Skip to content

Commit 0b29316

Browse files
committed
fix(cloudflare): Import types explicitly from worker-types
1 parent 29d35b4 commit 0b29316

File tree

10 files changed

+134
-17
lines changed

10 files changed

+134
-17
lines changed

dev-packages/e2e-tests/test-applications/cloudflare-hono/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
},
1717
"devDependencies": {
1818
"@cloudflare/vitest-pool-workers": "^0.8.31",
19-
"@cloudflare/workers-types": "^4.20250521.0",
19+
"@cloudflare/workers-types": "^4.20250620.0",
2020
"vitest": "3.1.0",
2121
"wrangler": "^4.16.0"
2222
},

dev-packages/e2e-tests/test-applications/cloudflare-hono/src/index.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,19 @@ app.notFound(ctx => {
2525
return ctx.json({ message: 'Not Found' }, 404);
2626
});
2727

28+
class MyDurableObjectBase extends DurableObject<Env> {
29+
// impl
30+
}
31+
32+
// Typecheck that the instrumented durable object is valid
33+
export const MyDurableObject = Sentry.instrumentDurableObjectWithSentry(
34+
(env: Env) => ({
35+
dsn: env?.E2E_TEST_DSN,
36+
tracesSampleRate: 1.0,
37+
}),
38+
MyDurableObjectBase,
39+
);
40+
2841
export default Sentry.withSentry(
2942
(env: Env) => ({
3043
dsn: env?.E2E_TEST_DSN,

packages/cloudflare/src/durableobject.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* eslint-disable @typescript-eslint/unbound-method */
1+
import type { DurableObject, DurableObjectState, ExecutionContext } from '@cloudflare/workers-types';
22
import {
33
captureException,
44
flush,
@@ -9,7 +9,6 @@ import {
99
withIsolationScope,
1010
withScope,
1111
} from '@sentry/core';
12-
import type { DurableObject } from 'cloudflare:workers';
1312
import { setAsyncLocalStorageAsyncContextStrategy } from './async';
1413
import type { CloudflareOptions } from './client';
1514
import { isInstrumented, markAsInstrumented } from './instrument';
@@ -135,7 +134,7 @@ function wrapMethodWithSentry<T extends (...args: any[]) => any>(
135134
*/
136135
export function instrumentDurableObjectWithSentry<
137136
E,
138-
T extends DurableObject<E>,
137+
T extends Partial<DurableObject>,
139138
C extends new (state: DurableObjectState, env: E) => T,
140139
>(optionsCallback: (env: E) => CloudflareOptions, DurableObjectClass: C): C {
141140
return new Proxy(DurableObjectClass, {

packages/cloudflare/src/handler.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
import type {
2+
EmailExportedHandler,
3+
ExportedHandler,
4+
ExportedHandlerFetchHandler,
5+
ExportedHandlerQueueHandler,
6+
ExportedHandlerScheduledHandler,
7+
ExportedHandlerTailHandler,
8+
} from '@cloudflare/workers-types';
19
import {
210
captureException,
311
flush,

packages/cloudflare/src/pages-plugin.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { EventPluginContext, PagesPluginFunction } from '@cloudflare/workers-types';
12
import { setAsyncLocalStorageAsyncContextStrategy } from './async';
23
import type { CloudflareOptions } from './client';
34
import { wrapRequestHandler } from './request';
@@ -49,8 +50,12 @@ export function sentryPagesPlugin<
4950
setAsyncLocalStorageAsyncContextStrategy();
5051
return context => {
5152
const options = typeof handlerOrOptions === 'function' ? handlerOrOptions(context) : handlerOrOptions;
52-
return wrapRequestHandler({ options, request: context.request, context: { ...context, props: {} } }, () =>
53-
context.next(),
54-
);
53+
return wrapRequestHandler(
54+
{ options, request: context.request, context: { ...context, props: {} } },
55+
() => context.next() as unknown as Promise<Response>,
56+
// Need to use `any` here because the return type does not work with Cloudflare's Response type.
57+
// Returning `PagesPluginFunction` in the wrapper function should take care of type safety.
58+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
59+
) as any;
5560
};
5661
}

packages/cloudflare/src/request.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
import type { ExecutionContext, IncomingRequestCfProperties } from '@cloudflare/workers-types';
1+
import type {
2+
ExecutionContext,
3+
IncomingRequestCfProperties,
4+
Request as CloudflareRequest,
5+
} from '@cloudflare/workers-types';
26
import {
37
captureException,
48
continueTrace,
@@ -16,7 +20,7 @@ import { init } from './sdk';
1620

1721
interface RequestHandlerWrapperOptions {
1822
options: CloudflareOptions;
19-
request: Request<unknown, IncomingRequestCfProperties<unknown>>;
23+
request: CloudflareRequest<unknown, IncomingRequestCfProperties<unknown>>;
2024
context: ExecutionContext;
2125
}
2226

packages/cloudflare/src/scope-utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { IncomingRequestCfProperties } from '@cloudflare/workers-types';
1+
import type { IncomingRequestCfProperties, Request as CloudflareRequest } from '@cloudflare/workers-types';
22
import type { Scope } from '@sentry/core';
33
import { winterCGRequestToRequestData } from '@sentry/core';
44

@@ -23,6 +23,6 @@ export function addCultureContext(scope: Scope, cf: IncomingRequestCfProperties)
2323
/**
2424
* Set request data on scope
2525
*/
26-
export function addRequest(scope: Scope, request: Request): void {
26+
export function addRequest(scope: Scope, request: CloudflareRequest): void {
2727
scope.setSDKProcessingMetadata({ normalizedRequest: winterCGRequestToRequestData(request) });
2828
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/* eslint-disable @typescript-eslint/naming-convention */
2+
/* eslint-disable @typescript-eslint/member-ordering */
3+
/* eslint-disable jsdoc/require-jsdoc */
4+
/* eslint-disable @typescript-eslint/explicit-member-accessibility */
5+
// This file vendors in worker types in `cloudflare:workers` because they are not
6+
// exported from `@cloudflare/workers-types` yet.
7+
8+
/* ! *****************************************************************************
9+
Copyright (c) Cloudflare. All rights reserved.
10+
Copyright (c) Microsoft Corporation. All rights reserved.
11+
12+
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
13+
this file except in compliance with the License. You may obtain a copy of the
14+
License at http://www.apache.org/licenses/LICENSE-2.0
15+
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
17+
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
18+
MERCHANTABLITY OR NON-INFRINGEMENT.
19+
See the Apache Version 2.0 License for specific language governing permissions
20+
and limitations under the License.
21+
***************************************************************************** */
22+
23+
import type { ExecutionContext, Rpc } from '@cloudflare/workers-types';
24+
25+
const __WORKFLOW_ENTRYPOINT_BRAND = '__WORKFLOW_ENTRYPOINT_BRAND' as const;
26+
27+
export type WorkflowEvent<T> = {
28+
payload: Readonly<T>;
29+
timestamp: Date;
30+
instanceId: string;
31+
};
32+
33+
export type WorkflowStepEvent<T> = {
34+
payload: Readonly<T>;
35+
timestamp: Date;
36+
type: string;
37+
};
38+
39+
export type WorkflowDurationLabel = 'second' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'year';
40+
export type WorkflowSleepDuration = `${number} ${WorkflowDurationLabel}${'s' | ''}` | number;
41+
export type WorkflowDelayDuration = WorkflowSleepDuration;
42+
export type WorkflowTimeoutDuration = WorkflowSleepDuration;
43+
export type WorkflowRetentionDuration = WorkflowSleepDuration;
44+
45+
export type WorkflowBackoff = 'constant' | 'linear' | 'exponential';
46+
47+
export type WorkflowStepConfig = {
48+
retries?: {
49+
limit: number;
50+
delay: WorkflowDelayDuration | number;
51+
backoff?: WorkflowBackoff;
52+
};
53+
timeout?: WorkflowTimeoutDuration | number;
54+
};
55+
56+
export abstract class WorkflowStep {
57+
do<T extends Rpc.Serializable<T>>(name: string, callback: () => Promise<T>): Promise<T>;
58+
// @ts-expect-error - This is a vendor file, so we don't need to implement the method.
59+
do<T extends Rpc.Serializable<T>>(name: string, config: WorkflowStepConfig, callback: () => Promise<T>): Promise<T>;
60+
// @ts-expect-error - This is a vendor file, so we don't need to implement the method.
61+
sleep: (name: string, duration: WorkflowSleepDuration) => Promise<void>;
62+
// @ts-expect-error - This is a vendor file, so we don't need to implement the method.
63+
sleepUntil: (name: string, timestamp: Date | number) => Promise<void>;
64+
// @ts-expect-error - This is a vendor file, so we don't need to implement the method.
65+
waitForEvent<T extends Rpc.Serializable<T>>(
66+
name: string,
67+
options: {
68+
type: string;
69+
timeout?: WorkflowTimeoutDuration | number;
70+
},
71+
): Promise<WorkflowStepEvent<T>>;
72+
}
73+
74+
export abstract class WorkflowEntrypoint<Env = unknown, T extends Rpc.Serializable<T> | unknown = unknown>
75+
implements Rpc.WorkflowEntrypointBranded
76+
{
77+
// @ts-expect-error - This is a vendor file, so we don't need to implement the property.
78+
[__WORKFLOW_ENTRYPOINT_BRAND]: never;
79+
// @ts-expect-error - This is a vendor file, so we don't need to implement the property.
80+
protected ctx: ExecutionContext;
81+
// @ts-expect-error - This is a vendor file, so we don't need to implement the property.
82+
protected env: Env;
83+
// @ts-expect-error - This is a vendor file, so we don't need to implement the constructor.
84+
constructor(ctx: ExecutionContext, env: Env);
85+
// @ts-expect-error - This is a vendor file, so we don't need to implement the method.
86+
run(event: Readonly<WorkflowEvent<T>>, step: WorkflowStep): Promise<unknown>;
87+
}

packages/cloudflare/src/workflows.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { ExecutionContext, Rpc } from '@cloudflare/workers-types';
12
import type { PropagationContext } from '@sentry/core';
23
import {
34
captureException,
@@ -8,6 +9,10 @@ import {
89
withIsolationScope,
910
withScope,
1011
} from '@sentry/core';
12+
import { setAsyncLocalStorageAsyncContextStrategy } from './async';
13+
import type { CloudflareOptions } from './client';
14+
import { addCloudResourceContext } from './scope-utils';
15+
import { init } from './sdk';
1116
import type {
1217
WorkflowEntrypoint,
1318
WorkflowEvent,
@@ -16,11 +21,7 @@ import type {
1621
WorkflowStepConfig,
1722
WorkflowStepEvent,
1823
WorkflowTimeoutDuration,
19-
} from 'cloudflare:workers';
20-
import { setAsyncLocalStorageAsyncContextStrategy } from './async';
21-
import type { CloudflareOptions } from './client';
22-
import { addCloudResourceContext } from './scope-utils';
23-
import { init } from './sdk';
24+
} from './vendor/workflow';
2425

2526
const UUID_REGEX = /^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$/i;
2627

packages/cloudflare/tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55

66
"compilerOptions": {
77
"module": "esnext",
8-
"types": ["node", "@cloudflare/workers-types"]
8+
"types": ["node"]
99
}
1010
}

0 commit comments

Comments
 (0)