Skip to content

Commit 6b77f35

Browse files
committed
fixup! feat(cloudflare): Support Cloudflare types v5 & newer wrangler versions
1 parent 95dce26 commit 6b77f35

5 files changed

Lines changed: 27 additions & 11 deletions

File tree

packages/cloudflare/src/client.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { ClientOptions, Options, ServerRuntimeClientOptions } from '@sentry/core';
22
import { applySdkMetadata, debug, ServerRuntimeClient, spanIsSampled } from '@sentry/core';
33
import { DEBUG_BUILD } from './debug-build';
4+
import type { ExecutionContextCompat } from './executionContext';
45
import type { makeFlushLock } from './flush';
56
import type { CloudflareTransportOptions } from './transport';
67

@@ -230,7 +231,7 @@ interface BaseCloudflareOptions {
230231
* @see @sentry/core Options for more information.
231232
*/
232233
export interface CloudflareOptions extends Options<CloudflareTransportOptions>, BaseCloudflareOptions {
233-
ctx?: ExecutionContext;
234+
ctx?: ExecutionContextCompat;
234235
}
235236

236237
/**
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import type { ExecutionContext } from '@cloudflare/workers-types';
2+
3+
/**
4+
* A structural subset of `ExecutionContext` that is compatible with both `@cloudflare/workers-types`
5+
* v4 and v5.
6+
*
7+
* v5 added `exports` and `tracing` as required members. Referencing the full `ExecutionContext` in
8+
* public input positions would force consumers on v4 (still allowed by our `peerDependencies` range)
9+
* to provide members their types don't have. We only ever use `waitUntil` (plus a runtime
10+
* `'storage' in ctx` check), so picking the members that exist in both majors keeps a context
11+
* constructed against either version assignable here.
12+
*/
13+
export type ExecutionContextCompat = Pick<ExecutionContext, 'waitUntil' | 'passThroughOnException'> | ExecutionContext;

packages/cloudflare/src/flush.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { ExecutionContext } from '@cloudflare/workers-types';
22
import type { Client } from '@sentry/core';
33
import { debug, flush } from '@sentry/core';
44
import { DEBUG_BUILD } from './debug-build';
5+
import type { ExecutionContextCompat } from './executionContext';
56

67
type FlushLock = {
78
readonly ready: Promise<void>;
@@ -34,7 +35,7 @@ const flushLockRegistries = new WeakMap<ExecutionContext['waitUntil'], FlushLock
3435
*
3536
* By using the original waitUntil for flush operations, we bypass this issue.
3637
*/
37-
export function getOriginalWaitUntil(context: ExecutionContext): ExecutionContext['waitUntil'] | undefined {
38+
export function getOriginalWaitUntil(context: ExecutionContextCompat): ExecutionContext['waitUntil'] | undefined {
3839
// eslint-disable-next-line @typescript-eslint/unbound-method
3940
const currentWaitUntil = context.waitUntil;
4041
const original = flushLockRegistries.get(currentWaitUntil)?.originalWaitUntil;
@@ -49,7 +50,7 @@ export function getOriginalWaitUntil(context: ExecutionContext): ExecutionContex
4950
* @param {ExecutionContext} context - The execution context to be enhanced. If no context is provided, the function returns undefined.
5051
* @return {FlushLock} Returns a flusher function if a valid context is provided, otherwise undefined.
5152
*/
52-
export function makeFlushLock(context: ExecutionContext): FlushLock {
53+
export function makeFlushLock(context: ExecutionContextCompat): FlushLock {
5354
const registry = getOrCreateFlushLockRegistry(context);
5455
let resolveAllDone: () => void = () => undefined;
5556
const allDone = new Promise<void>(res => {
@@ -81,7 +82,7 @@ export function makeFlushLock(context: ExecutionContext): FlushLock {
8182
return Object.freeze(lock);
8283
}
8384

84-
function getOrCreateFlushLockRegistry(context: ExecutionContext): FlushLockRegistry {
85+
function getOrCreateFlushLockRegistry(context: ExecutionContextCompat): FlushLockRegistry {
8586
// eslint-disable-next-line @typescript-eslint/unbound-method
8687
const waitUntil = context.waitUntil;
8788
const existingRegistry = flushLockRegistries.get(waitUntil);

packages/cloudflare/src/pages-plugin.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import type { ExecutionContext } from '@cloudflare/workers-types';
21
import { setAsyncLocalStorageAsyncContextStrategy } from './async';
32
import type { CloudflareOptions } from './client';
3+
import type { ExecutionContextCompat } from './executionContext';
44
import { wrapRequestHandler } from './request';
55

66
/**
@@ -54,9 +54,9 @@ export function sentryPagesPlugin<
5454
}
5555

5656
const options = typeof handlerOrOptions === 'function' ? handlerOrOptions(context) : handlerOrOptions;
57-
// A Pages `EventPluginContext` is not a Workers `ExecutionContext` (it lacks `exports`/`tracing`),
58-
// but `wrapRequestHandler` only reads `waitUntil` off it, so a structural cast is safe here.
59-
const executionContext = { ...context, props: {} } as unknown as ExecutionContext;
57+
// A Pages `EventPluginContext` is not a Workers `ExecutionContext`, but `wrapRequestHandler` only
58+
// uses `waitUntil` and a `'storage' in context` check, both of which this satisfies.
59+
const executionContext = { ...context, props: {} } as unknown as ExecutionContextCompat;
6060
return wrapRequestHandler({ options, request: context.request, context: executionContext }, () => context.next());
6161
};
6262
}

packages/cloudflare/src/request.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { CfProperties, ExecutionContext, IncomingRequestCfProperties } from '@cloudflare/workers-types';
1+
import type { CfProperties, IncomingRequestCfProperties } from '@cloudflare/workers-types';
22
import {
33
captureException,
44
continueTrace,
@@ -14,20 +14,21 @@ import {
1414
} from '@sentry/core';
1515
import { captureIncomingRequestBody } from './integrations/httpServer';
1616
import type { CloudflareOptions } from './client';
17+
import type { ExecutionContextCompat } from './executionContext';
1718
import { flushAndDispose, getOriginalWaitUntil } from './flush';
1819
import { addCloudResourceContext, addCultureContext, addRequest } from './scope-utils';
1920
import { init } from './sdk';
2021
import { classifyResponseStreaming } from './utils/streaming';
2122

22-
function getRequestErrorMechanismType(context: ExecutionContext | undefined): string {
23+
function getRequestErrorMechanismType(context: ExecutionContextCompat | undefined): string {
2324
// Durable Object fetch handlers use DO state as context (see instrumentDurableObjectWithSentry)
2425
return context && 'storage' in context ? 'auto.faas.cloudflare.durable_object' : 'auto.http.cloudflare';
2526
}
2627

2728
interface RequestHandlerWrapperOptions {
2829
options: CloudflareOptions;
2930
request: Request<unknown, IncomingRequestCfProperties<unknown> | CfProperties<unknown>>;
30-
context: ExecutionContext | undefined;
31+
context: ExecutionContextCompat | undefined;
3132
/**
3233
* If true, errors will be captured, rethrown and sent to Sentry.
3334
* Otherwise, errors are rethrown but not captured.

0 commit comments

Comments
 (0)