@sentry/cloudflare 11.0.0-rc.1 → 11.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -200
- package/build/cjs/dev/client.js +11 -4
- package/build/cjs/dev/client.js.map +1 -1
- package/build/cjs/dev/index.js +1 -0
- package/build/cjs/dev/index.js.map +1 -1
- package/build/cjs/dev/instrumentations/instrumentDurableObjectNamespace.js +3 -0
- package/build/cjs/dev/instrumentations/instrumentDurableObjectNamespace.js.map +1 -1
- package/build/cjs/dev/instrumentations/worker/instrumentEnv.js +3 -0
- package/build/cjs/dev/instrumentations/worker/instrumentEnv.js.map +1 -1
- package/build/cjs/dev/instrumentations/worker/instrumentQueueProducer.js +2 -1
- package/build/cjs/dev/instrumentations/worker/instrumentQueueProducer.js.map +1 -1
- package/build/cjs/dev/request.js +2 -0
- package/build/cjs/dev/request.js.map +1 -1
- package/build/cjs/dev/transport.js +18 -4
- package/build/cjs/dev/transport.js.map +1 -1
- package/build/cjs/dev/vite/flueRuntime.js +6 -35
- package/build/cjs/dev/vite/flueRuntime.js.map +1 -1
- package/build/cjs/dev/vite/mastraObservability.js +6 -30
- package/build/cjs/dev/vite/mastraObservability.js.map +1 -1
- package/build/cjs/dev/vite/providedModulePlugin.js +53 -0
- package/build/cjs/dev/vite/providedModulePlugin.js.map +1 -0
- package/build/cjs/dev/vite/transform.js +26 -29
- package/build/cjs/dev/vite/transform.js.map +1 -1
- package/build/cjs/dev/workflows.js +7 -2
- package/build/cjs/dev/workflows.js.map +1 -1
- package/build/cjs/prod/client.js +11 -4
- package/build/cjs/prod/client.js.map +1 -1
- package/build/cjs/prod/index.js +1 -0
- package/build/cjs/prod/index.js.map +1 -1
- package/build/cjs/prod/instrumentations/instrumentDurableObjectNamespace.js +3 -0
- package/build/cjs/prod/instrumentations/instrumentDurableObjectNamespace.js.map +1 -1
- package/build/cjs/prod/instrumentations/worker/instrumentEnv.js +3 -0
- package/build/cjs/prod/instrumentations/worker/instrumentEnv.js.map +1 -1
- package/build/cjs/prod/instrumentations/worker/instrumentQueueProducer.js +2 -1
- package/build/cjs/prod/instrumentations/worker/instrumentQueueProducer.js.map +1 -1
- package/build/cjs/prod/request.js +2 -0
- package/build/cjs/prod/request.js.map +1 -1
- package/build/cjs/prod/transport.js +18 -4
- package/build/cjs/prod/transport.js.map +1 -1
- package/build/cjs/prod/vite/flueRuntime.js +6 -35
- package/build/cjs/prod/vite/flueRuntime.js.map +1 -1
- package/build/cjs/prod/vite/mastraObservability.js +6 -30
- package/build/cjs/prod/vite/mastraObservability.js.map +1 -1
- package/build/cjs/prod/vite/providedModulePlugin.js +53 -0
- package/build/cjs/prod/vite/providedModulePlugin.js.map +1 -0
- package/build/cjs/prod/vite/transform.js +26 -29
- package/build/cjs/prod/vite/transform.js.map +1 -1
- package/build/cjs/prod/workflows.js +7 -2
- package/build/cjs/prod/workflows.js.map +1 -1
- package/build/esm/dev/client.js +11 -4
- package/build/esm/dev/client.js.map +1 -1
- package/build/esm/dev/index.js +1 -1
- package/build/esm/dev/instrumentations/instrumentDurableObjectNamespace.js +3 -0
- package/build/esm/dev/instrumentations/instrumentDurableObjectNamespace.js.map +1 -1
- package/build/esm/dev/instrumentations/worker/instrumentEnv.js +3 -0
- package/build/esm/dev/instrumentations/worker/instrumentEnv.js.map +1 -1
- package/build/esm/dev/instrumentations/worker/instrumentQueueProducer.js +2 -1
- package/build/esm/dev/instrumentations/worker/instrumentQueueProducer.js.map +1 -1
- package/build/esm/dev/package.json +1 -1
- package/build/esm/dev/request.js +1 -0
- package/build/esm/dev/request.js.map +1 -1
- package/build/esm/dev/transport.js +19 -5
- package/build/esm/dev/transport.js.map +1 -1
- package/build/esm/dev/vite/flueRuntime.js +7 -35
- package/build/esm/dev/vite/flueRuntime.js.map +1 -1
- package/build/esm/dev/vite/mastraObservability.js +7 -30
- package/build/esm/dev/vite/mastraObservability.js.map +1 -1
- package/build/esm/dev/vite/providedModulePlugin.js +50 -0
- package/build/esm/dev/vite/providedModulePlugin.js.map +1 -0
- package/build/esm/dev/vite/transform.js +26 -29
- package/build/esm/dev/vite/transform.js.map +1 -1
- package/build/esm/dev/workflows.js +7 -2
- package/build/esm/dev/workflows.js.map +1 -1
- package/build/esm/prod/client.js +11 -4
- package/build/esm/prod/client.js.map +1 -1
- package/build/esm/prod/index.js +1 -1
- package/build/esm/prod/instrumentations/instrumentDurableObjectNamespace.js +3 -0
- package/build/esm/prod/instrumentations/instrumentDurableObjectNamespace.js.map +1 -1
- package/build/esm/prod/instrumentations/worker/instrumentEnv.js +3 -0
- package/build/esm/prod/instrumentations/worker/instrumentEnv.js.map +1 -1
- package/build/esm/prod/instrumentations/worker/instrumentQueueProducer.js +2 -1
- package/build/esm/prod/instrumentations/worker/instrumentQueueProducer.js.map +1 -1
- package/build/esm/prod/package.json +1 -1
- package/build/esm/prod/request.js +1 -0
- package/build/esm/prod/request.js.map +1 -1
- package/build/esm/prod/transport.js +19 -5
- package/build/esm/prod/transport.js.map +1 -1
- package/build/esm/prod/vite/flueRuntime.js +7 -35
- package/build/esm/prod/vite/flueRuntime.js.map +1 -1
- package/build/esm/prod/vite/mastraObservability.js +7 -30
- package/build/esm/prod/vite/mastraObservability.js.map +1 -1
- package/build/esm/prod/vite/providedModulePlugin.js +50 -0
- package/build/esm/prod/vite/providedModulePlugin.js.map +1 -0
- package/build/esm/prod/vite/transform.js +26 -29
- package/build/esm/prod/vite/transform.js.map +1 -1
- package/build/esm/prod/workflows.js +7 -2
- package/build/esm/prod/workflows.js.map +1 -1
- package/build/types/client.d.ts +5 -3
- package/build/types/client.d.ts.map +1 -1
- package/build/types/index.d.ts +1 -1
- package/build/types/index.d.ts.map +1 -1
- package/build/types/instrumentations/worker/instrumentEnv.d.ts.map +1 -1
- package/build/types/instrumentations/worker/instrumentQueueProducer.d.ts.map +1 -1
- package/build/types/request.d.ts +1 -0
- package/build/types/request.d.ts.map +1 -1
- package/build/types/transport.d.ts +5 -0
- package/build/types/transport.d.ts.map +1 -1
- package/build/types/vite/flueRuntime.d.ts +2 -13
- package/build/types/vite/flueRuntime.d.ts.map +1 -1
- package/build/types/vite/mastraObservability.d.ts +8 -23
- package/build/types/vite/mastraObservability.d.ts.map +1 -1
- package/build/types/vite/providedModulePlugin.d.ts +62 -0
- package/build/types/vite/providedModulePlugin.d.ts.map +1 -0
- package/build/types/workflows.d.ts.map +1 -1
- package/package.json +5 -5
|
@@ -26,7 +26,7 @@ function applyAutoInstrumentTransforms(code, ast, ctx) {
|
|
|
26
26
|
needsImport: false,
|
|
27
27
|
wrappedClasses: /* @__PURE__ */ new Set(),
|
|
28
28
|
topLevelClasses,
|
|
29
|
-
|
|
29
|
+
wrappedLocals: /* @__PURE__ */ new Map(),
|
|
30
30
|
classWrappers: ctx.classWrappers,
|
|
31
31
|
agentClasses: ctx.agentClasses ?? /* @__PURE__ */ new Set(),
|
|
32
32
|
workerEntrypointClasses: detectWorkerEntrypointClasses(ast),
|
|
@@ -107,9 +107,13 @@ function collectTopLevelClasses(ast) {
|
|
|
107
107
|
function wrapDefaultExport(node, ctx, state) {
|
|
108
108
|
const decl = node.declaration;
|
|
109
109
|
if (isCallToMethod(decl, "withSentry")) return;
|
|
110
|
-
if (decl.type === "Identifier"
|
|
111
|
-
state.
|
|
112
|
-
|
|
110
|
+
if (decl.type === "Identifier") {
|
|
111
|
+
const wrappedName = state.wrappedLocals.get(decl.name);
|
|
112
|
+
if (wrappedName) {
|
|
113
|
+
state.ms.overwrite(decl.start, decl.end, wrappedName);
|
|
114
|
+
state.autoWrapped.add(DEFAULT_EXPORT);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
113
117
|
}
|
|
114
118
|
state.ms.overwrite(node.start, decl.start, "const __SENTRY_DEFAULT_EXPORT__ = ");
|
|
115
119
|
state.ms.append(`
|
|
@@ -146,19 +150,26 @@ function wrapInlineClassExport(exportNode, classDecl, ctx, state) {
|
|
|
146
150
|
const kind = classId ? resolveWrapperKind(classId.name, classId.name, state) : void 0;
|
|
147
151
|
if (!classId || !kind) return;
|
|
148
152
|
const className = classId.name;
|
|
149
|
-
const renamedClass = `__SENTRY_ORIGINAL_${className}__`;
|
|
150
153
|
state.ms.overwrite(exportNode.start, classDecl.start, "");
|
|
151
|
-
|
|
154
|
+
const wrappedName = wrapLocalClass(className, classDecl, kind, state);
|
|
155
|
+
state.ms.appendLeft(exportNode.end, `export { ${wrappedName} as ${className} };
|
|
156
|
+
`);
|
|
157
|
+
state.wrappedClasses.add(className);
|
|
158
|
+
state.autoWrapped.add(className);
|
|
159
|
+
}
|
|
160
|
+
function wrapLocalClass(localName, localClass, kind, state) {
|
|
161
|
+
const existing = state.wrappedLocals.get(localName);
|
|
162
|
+
if (existing) return existing;
|
|
163
|
+
const wrappedName = `__SENTRY_WRAPPED_${localName}__`;
|
|
164
|
+
state.wrappedLocals.set(localName, wrappedName);
|
|
152
165
|
state.ms.appendLeft(
|
|
153
|
-
|
|
166
|
+
localClass.end,
|
|
154
167
|
`
|
|
155
|
-
|
|
168
|
+
const ${wrappedName} = __SENTRY__.${WRAPPER_METHODS[kind]}(${state.optionsFn}, ${localName});
|
|
156
169
|
`
|
|
157
170
|
);
|
|
158
|
-
state.wrappedClasses.add(className);
|
|
159
|
-
state.autoWrapped.add(className);
|
|
160
|
-
state.renamedLocals.add(className);
|
|
161
171
|
state.needsImport = true;
|
|
172
|
+
return wrappedName;
|
|
162
173
|
}
|
|
163
174
|
function wrapSpecifierExports(node, ctx, state) {
|
|
164
175
|
const specifiers = node.specifiers ?? [];
|
|
@@ -168,7 +179,7 @@ function wrapSpecifierExports(node, ctx, state) {
|
|
|
168
179
|
const wrappedPairs = [];
|
|
169
180
|
const kept = [];
|
|
170
181
|
for (const specifier of specifiers) {
|
|
171
|
-
const pair =
|
|
182
|
+
const pair = wrapSpecifier(specifier, sourceLiteral, ctx, state, prelude);
|
|
172
183
|
if (pair) {
|
|
173
184
|
wrappedPairs.push(pair);
|
|
174
185
|
} else {
|
|
@@ -183,7 +194,7 @@ function wrapSpecifierExports(node, ctx, state) {
|
|
|
183
194
|
}
|
|
184
195
|
state.ms.overwrite(node.start, node.end, statements.join("\n"));
|
|
185
196
|
}
|
|
186
|
-
function
|
|
197
|
+
function wrapSpecifier(specifier, sourceLiteral, ctx, state, prelude) {
|
|
187
198
|
const exportedName = specifier.type === "ExportSpecifier" && specifier.exported?.type === "Identifier" ? specifier.exported.name : void 0;
|
|
188
199
|
const localName = specifier.local?.type === "Identifier" ? specifier.local.name : void 0;
|
|
189
200
|
const kind = exportedName ? resolveWrapperKind(exportedName, sourceLiteral ? void 0 : localName, state) : void 0;
|
|
@@ -191,10 +202,9 @@ function wrapCrossModuleSpecifier(specifier, sourceLiteral, ctx, state, prelude)
|
|
|
191
202
|
if (!sourceLiteral) {
|
|
192
203
|
const localClass = state.topLevelClasses.get(localName);
|
|
193
204
|
if (localClass?.id) {
|
|
194
|
-
|
|
205
|
+
const wrappedName2 = wrapLocalClass(localName, localClass, kind, state);
|
|
195
206
|
state.wrappedClasses.add(exportedName);
|
|
196
|
-
|
|
197
|
-
return void 0;
|
|
207
|
+
return `${wrappedName2} as ${exportedName}`;
|
|
198
208
|
}
|
|
199
209
|
if (state.manuallyWrappedLocals.has(localName)) {
|
|
200
210
|
state.wrappedClasses.add(exportedName);
|
|
@@ -217,19 +227,6 @@ function wrapCrossModuleSpecifier(specifier, sourceLiteral, ctx, state, prelude)
|
|
|
217
227
|
state.needsImport = true;
|
|
218
228
|
return `${wrappedName} as ${exportedName}`;
|
|
219
229
|
}
|
|
220
|
-
function wrapLocalClassExport(localName, localClass, kind, ctx, state) {
|
|
221
|
-
const classId = localClass.id;
|
|
222
|
-
if (!classId || state.renamedLocals.has(localName)) return;
|
|
223
|
-
state.renamedLocals.add(localName);
|
|
224
|
-
const renamedClass = `__SENTRY_ORIGINAL_${localName}__`;
|
|
225
|
-
state.ms.overwrite(classId.start, classId.end, renamedClass);
|
|
226
|
-
state.ms.appendLeft(
|
|
227
|
-
localClass.end,
|
|
228
|
-
`
|
|
229
|
-
const ${localName} = __SENTRY__.${WRAPPER_METHODS[kind]}(${state.optionsFn}, ${renamedClass});
|
|
230
|
-
`
|
|
231
|
-
);
|
|
232
|
-
}
|
|
233
230
|
|
|
234
231
|
export { applyAutoInstrumentTransforms };
|
|
235
232
|
//# sourceMappingURL=transform.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transform.js","sources":["../../../../src/vite/transform.ts"],"sourcesContent":["/* eslint-disable max-lines */\nimport MagicString from 'magic-string';\nimport { DEFAULT_EXPORT, type ExportName, type SameWorkerBinding } from './wranglerConfig';\nimport { detectWorkerEntrypointClasses } from './workerEntrypoint';\n\nconst MERGED_OPTIONS_IDENTIFIER = '__SENTRY_OPTIONS__';\n\n// ---------------------------------------------------------------------------\n// Minimal ESTree node types for the AST nodes we inspect.\n// ---------------------------------------------------------------------------\n\nexport interface BaseNode {\n type: string;\n start: number;\n end: number;\n}\n\nexport interface ProgramBody {\n body: BaseNode[];\n}\n\ninterface IdentifierNode extends BaseNode {\n name: string;\n}\n\ninterface CalleeNode {\n type: string;\n name?: string;\n property?: { type: string; name?: string };\n}\n\ninterface CallExpressionNode extends BaseNode {\n callee?: CalleeNode;\n}\n\ninterface ClassDeclarationNode extends BaseNode {\n id?: IdentifierNode | null;\n}\n\ninterface ExportDefaultNode extends BaseNode {\n declaration: BaseNode;\n}\n\ninterface ExportSpecifierNode extends BaseNode {\n local?: { type: string; name?: string };\n exported?: { type: string; name?: string };\n}\n\ninterface ExportNamedNode extends BaseNode {\n declaration?: BaseNode | null;\n source?: BaseNode | null;\n specifiers?: ExportSpecifierNode[];\n}\n\ninterface VariableDeclaratorNode {\n id?: { type: string; name?: string };\n init?: BaseNode | null;\n}\n\ninterface VariableDeclarationNode extends BaseNode {\n declarations?: VariableDeclaratorNode[];\n}\n\nfunction isCallToMethod(node: BaseNode, methodName: string): boolean {\n if (node.type !== 'CallExpression') return false;\n const callee = (node as CallExpressionNode).callee;\n if (!callee) return false;\n if (callee.type === 'Identifier' && callee.name === methodName) return true;\n return (\n callee.type === 'MemberExpression' && callee.property?.type === 'Identifier' && callee.property.name === methodName\n );\n}\n\n/**\n * The kind of Sentry wrapper to apply to an exported class.\n *\n * `durableObject` and `workflow` are keyed by name from the wrangler config\n * (`durable_objects.bindings`, `workflows`), since those class names are\n * authoritative there. `workerEntrypoint` is different: a worker's own\n * entrypoints aren't enumerated in its config, so they're detected structurally\n * (a class extending `WorkerEntrypoint` from `cloudflare:workers`), with the\n * config providing only a fallback for self-bound entrypoints whose base class\n * lives in another module.\n */\nexport type ClassWrapperKind = 'durableObject' | 'agent' | 'workflow' | 'workerEntrypoint';\n\n/** Specifier name a `export { default as X } from '...'` re-export uses for the source's default. */\nconst DEFAULT_IMPORT = 'default';\n\n/**\n * The `@sentry/cloudflare` helper each wrapper kind emits. All share the same\n * `(optionsCallback, Class)` signature. `WorkerEntrypoint` classes use\n * `withSentry`, which runtime-detects the class type and routes accordingly.\n */\nconst WRAPPER_METHODS: Record<ClassWrapperKind, string> = {\n durableObject: 'instrumentDurableObjectWithSentry',\n agent: 'instrumentAgentWithSentry',\n workflow: 'instrumentWorkflowWithSentry',\n workerEntrypoint: 'withSentry',\n};\n\nexport interface TransformContext {\n /**\n * Exported class name → the kind of Sentry wrapper to apply. Populated from\n * the wrangler config, so the transform can wrap by name without resolving\n * each class's base type.\n */\n classWrappers: Map<string, ClassWrapperKind>;\n /**\n * Local class names detected as `agents` Agents. An Agent is configured as a Durable Object in\n * wrangler, so this upgrades those entries from `durableObject` to `agent`.\n */\n agentClasses?: ReadonlySet<string>;\n optionsFn: string;\n /** Import statement prepended when `optionsFn` references a separate module. */\n optionsImport?: string;\n /** @see {@link import('./wranglerConfig').WranglerConfig.sameWorkerBindings} */\n sameWorkerBindings?: readonly SameWorkerBinding[];\n}\n\nexport interface TransformResult {\n code: string;\n map: ReturnType<MagicString['generateMap']>;\n /**\n * The configured class names that were actually wrapped. Lets the plugin warn\n * about configured classes it could not find, instead of silently leaving\n * them uninstrumented.\n */\n wrappedClasses: Set<string>;\n}\n\n/**\n * Rewrite the worker entry source to wrap its default export with `withSentry`\n * and any configured class export with its matching Sentry wrapper (see\n * {@link TransformContext.classWrappers}, e.g. Durable Object classes with\n * `instrumentDurableObjectWithSentry`).\n *\n * Handles `export class MyDO {}`, the specifier form (`class MyDO {}` …\n * `export { MyDO }` / `export { Foo as MyDO }`), and classes that live in\n * another module (`import { MyDO } from './do'; export { MyDO }` or\n * `export { MyDO } from './do'`). Only star re-exports (`export * from './do'`)\n * are left alone — the plugin warns about those via\n * {@link TransformResult.wrappedClasses}.\n *\n * Exported (rather than inlined into the plugin) so it can be unit-tested with a\n * plain AST and no Vite context. Returns `undefined` when nothing was wrapped and\n * there are no already-manually-wrapped classes to report.\n */\nexport function applyAutoInstrumentTransforms(\n code: string,\n ast: ProgramBody,\n ctx: TransformContext,\n): TransformResult | undefined {\n const ms = new MagicString(code);\n const topLevelClasses = collectTopLevelClasses(ast);\n const sameWorkerBindings = ctx.sameWorkerBindings ?? [];\n const state: TransformState = {\n ms,\n needsImport: false,\n wrappedClasses: new Set<string>(),\n topLevelClasses,\n renamedLocals: new Set<string>(),\n classWrappers: ctx.classWrappers,\n agentClasses: ctx.agentClasses ?? new Set<string>(),\n workerEntrypointClasses: detectWorkerEntrypointClasses(ast),\n // The identifier must be chosen before wrapping, which bindings survive is only known after.\n optionsFn: sameWorkerBindings.length > 0 ? MERGED_OPTIONS_IDENTIFIER : ctx.optionsFn,\n autoWrapped: new Set<ExportName>(),\n manuallyWrappedLocals: collectManuallyWrappedLocals(ast),\n };\n const { wrappedClasses } = state;\n\n // Named exports first, regardless of source order: the default-export handler\n // needs to know which local bindings a named export already wrapped, so it can\n // skip a class that is both exported by name and re-exported as default (which\n // would otherwise wrap it twice).\n for (const node of ast.body) {\n if (node.type === 'ExportNamedDeclaration') {\n handleNamedExport(node, ctx, state);\n }\n }\n for (const node of ast.body) {\n if (node.type === 'ExportDefaultDeclaration') {\n wrapDefaultExport(node as ExportDefaultNode, ctx, state);\n }\n }\n\n if (!state.needsImport) {\n // Nothing was rewritten. Still surface any classes found already wrapped\n // manually (via `wrappedClasses`) so the caller doesn't warn about them;\n // return undefined only when there was nothing to report either.\n if (wrappedClasses.size === 0) return undefined;\n return { code, map: ms.generateMap({ hires: true }), wrappedClasses };\n }\n\n // `prepend` inserts before earlier prepends, yielding: Sentry import, options import, declaration.\n if (sameWorkerBindings.length > 0) {\n ms.prepend(buildMergedOptionsDeclaration(sameWorkerBindings, ctx.optionsFn, state));\n }\n if (ctx.optionsImport) ms.prepend(ctx.optionsImport);\n ms.prepend(\"import * as __SENTRY__ from '@sentry/cloudflare';\\n\");\n\n return {\n code: ms.toString(),\n map: ms.generateMap({ hires: true }),\n wrappedClasses,\n };\n}\n\ninterface TransformState {\n ms: MagicString;\n needsImport: boolean;\n wrappedClasses: Set<string>;\n /**\n * Top-level (non-exported) class declarations, so specifier exports like\n * `export { MyDO }` can locate the class they refer to.\n */\n topLevelClasses: Map<string, ClassDeclarationNode>;\n /**\n * Local class names already renamed + wrapped, so two specifiers pointing at\n * the same class don't produce duplicate bindings.\n */\n renamedLocals: Set<string>;\n /** Class name → wrapper kind, keyed by the *exported* name (from config). */\n classWrappers: Map<string, ClassWrapperKind>;\n /** Local class names detected as `agents` Agents (see {@link TransformContext.agentClasses}). */\n agentClasses: ReadonlySet<string>;\n /**\n * Local class names detected as `WorkerEntrypoint` subclasses in this module,\n * so they can be wrapped without a config entry.\n */\n workerEntrypointClasses: Set<string>;\n optionsFn: string;\n /**\n * Export names wrapped by this transform, so their options can be extended with\n * `rpcTracePropagationBindings`. Hand-wrapped exports stay out, they keep the options they were\n * wrapped with. `wrappedClasses` counts both.\n */\n autoWrapped: Set<ExportName>;\n /**\n * Top-level bindings already assigned an `instrument*WithSentry(...)` result\n * (`const MyDO = instrumentDurableObjectWithSentry(...)`). Exporting one by\n * specifier must report it as wrapped rather than wrap it a second time.\n */\n manuallyWrappedLocals: Set<string>;\n}\n\n/**\n * Builds the callback that merges same-worker binding names into `rpcTracePropagationBindings` at\n * runtime, the options object only exists once the callback runs with `env`. Only bindings whose\n * class this transform wrapped survive, a hand-wrapped class runs on its own options.\n */\nfunction buildMergedOptionsDeclaration(\n sameWorkerBindings: readonly SameWorkerBinding[],\n optionsFn: string,\n state: TransformState,\n): string {\n const bindingNames = sameWorkerBindings\n .filter(({ className }) => state.autoWrapped.has(className))\n .map(({ bindingName }) => bindingName);\n\n if (!bindingNames.length) {\n return `const ${MERGED_OPTIONS_IDENTIFIER} = ${optionsFn};\\n`;\n }\n\n const names = bindingNames.map(name => JSON.stringify(name)).join(', ');\n return (\n `const ${MERGED_OPTIONS_IDENTIFIER} = (env) => { ` +\n `const opts = (${optionsFn})(env); ` +\n `return { ...opts, rpcTracePropagationBindings: [${names}, ...(opts?.rpcTracePropagationBindings ?? [])] }; };\\n`\n );\n}\n\n/**\n * Resolve the wrapper kind for a class export.\n *\n * Config (`classWrappers`) wins — it's authoritative for Durable Objects and\n * Workflows, and provides the self-binding fallback for WorkerEntrypoints whose\n * base class this module can't see. Otherwise a structurally-detected\n * `WorkerEntrypoint` subclass (matched by its *local* name) gets wrapped with\n * `withSentry`.\n *\n * `localName` is the binding **in this module** the export refers to, and must be\n * left undefined for `export { X } from '...'`: there the specifier's name belongs\n * to the source module, so matching it against anything detected here would wrap a\n * class that merely shares a name.\n *\n * The one case where config is refined rather than obeyed is an `agents` Agent:\n * it *is* a Durable Object, so wrangler can only ever describe it as one, and\n * only the detected base chain distinguishes the two.\n */\nfunction resolveWrapperKind(\n exportedName: string,\n localName: string | undefined,\n state: TransformState,\n): ClassWrapperKind | undefined {\n const configured = state.classWrappers.get(exportedName);\n\n if (\n configured === 'durableObject' &&\n ((localName && state.agentClasses.has(localName)) || state.agentClasses.has(exportedName))\n ) {\n return 'agent';\n }\n\n if (configured) return configured;\n if (localName && state.workerEntrypointClasses.has(localName)) return 'workerEntrypoint';\n return undefined;\n}\n\n/**\n * Top-level `const X = instrument*WithSentry(...)` bindings — a hand-wrapped class that is exported\n * separately (`export { X }`) rather than inline.\n */\nfunction collectManuallyWrappedLocals(ast: ProgramBody): Set<string> {\n const wrapperMethods = Object.values(WRAPPER_METHODS);\n const locals = new Set<string>();\n\n for (const node of ast.body) {\n if (node.type !== 'VariableDeclaration') continue;\n for (const declarator of (node as VariableDeclarationNode).declarations ?? []) {\n const name = declarator.id?.type === 'Identifier' ? declarator.id.name : undefined;\n const init = declarator.init;\n if (name && init && wrapperMethods.some(method => isCallToMethod(init, method))) {\n locals.add(name);\n }\n }\n }\n\n return locals;\n}\n\nfunction collectTopLevelClasses(ast: ProgramBody): Map<string, ClassDeclarationNode> {\n const classes = new Map<string, ClassDeclarationNode>();\n for (const node of ast.body) {\n if (node.type !== 'ClassDeclaration') continue;\n const classNode = node as ClassDeclarationNode;\n if (classNode.id?.name) classes.set(classNode.id.name, classNode);\n }\n return classes;\n}\n\nfunction wrapDefaultExport(node: ExportDefaultNode, ctx: TransformContext, state: TransformState): void {\n const decl = node.declaration;\n\n // Already wrapped — leave it alone\n if (isCallToMethod(decl, 'withSentry')) return;\n\n // `export default Foo` where `Foo` is a local class already wrapped by a named\n // export (e.g. a self-bound WorkerEntrypoint also used as the default handler).\n // Wrapping again would produce `withSentry(withSentry(...))`. The binding still\n // points at the wrapped class, so the default export counts as auto-wrapped.\n if (decl.type === 'Identifier' && state.renamedLocals.has((decl as IdentifierNode).name)) {\n state.autoWrapped.add(DEFAULT_EXPORT);\n return;\n }\n\n // `export default <expr>` → `const __SENTRY_DEFAULT_EXPORT__ = <expr>`\n // MagicString positions are always relative to the original source.\n state.ms.overwrite(node.start, decl.start, 'const __SENTRY_DEFAULT_EXPORT__ = ');\n state.ms.append(`\\nexport default __SENTRY__.withSentry(${state.optionsFn}, __SENTRY_DEFAULT_EXPORT__);\\n`);\n state.needsImport = true;\n state.autoWrapped.add(DEFAULT_EXPORT);\n}\n\nfunction handleNamedExport(node: ExportNamedNode, ctx: TransformContext, state: TransformState): void {\n const decl = node.declaration;\n\n // ---- Manually wrapped class export ----\n // `export const MyDO = instrumentDurableObjectWithSentry(...)` — count it\n // as wrapped so the plugin doesn't warn about it, but leave it alone.\n if (decl?.type === 'VariableDeclaration') {\n collectManuallyWrappedClassExports(decl, ctx, state);\n return;\n }\n\n // ---- Named class export matching a configured binding ----\n if (decl?.type === 'ClassDeclaration') {\n wrapInlineClassExport(node, decl, ctx, state);\n return;\n }\n\n // ---- Specifier export (`export { Foo as MyDO }`, `export { MyDO } from './do'`) ----\n wrapSpecifierExports(node, ctx, state);\n}\n\nfunction collectManuallyWrappedClassExports(\n varDecl: VariableDeclarationNode,\n ctx: TransformContext,\n state: TransformState,\n): void {\n for (const declarator of varDecl.declarations ?? []) {\n const name = declarator.id?.type === 'Identifier' ? declarator.id.name : undefined;\n const kind = name ? ctx.classWrappers.get(name) : undefined;\n if (!name || !kind || !declarator.init) continue;\n\n // A hand-wrapped Agent is configured as a Durable Object, so accept either helper there —\n // otherwise an already-instrumented Agent would be reported as unwrapped.\n const accepted =\n kind === 'durableObject' ? [WRAPPER_METHODS.durableObject, WRAPPER_METHODS.agent] : [WRAPPER_METHODS[kind]];\n\n if (accepted.some(method => isCallToMethod(declarator.init as BaseNode, method))) {\n state.wrappedClasses.add(name);\n }\n }\n}\n\nfunction wrapInlineClassExport(\n exportNode: ExportNamedNode,\n classDecl: ClassDeclarationNode,\n ctx: TransformContext,\n state: TransformState,\n): void {\n const classId = classDecl.id;\n // Inline export: the exported name and the local class name are the same.\n const kind = classId ? resolveWrapperKind(classId.name, classId.name, state) : undefined;\n if (!classId || !kind) return;\n\n const className = classId.name;\n const renamedClass = `__SENTRY_ORIGINAL_${className}__`;\n\n // Strip the `export ` keyword\n state.ms.overwrite(exportNode.start, classDecl.start, '');\n\n // Rename the class to avoid a duplicate binding\n state.ms.overwrite(classId.start, classId.end, renamedClass);\n\n // Insert the wrapped re-export after the class body\n state.ms.appendLeft(\n exportNode.end,\n `\\nexport const ${className} = __SENTRY__.${WRAPPER_METHODS[kind]}(${state.optionsFn}, ${renamedClass});\\n`,\n );\n\n state.wrappedClasses.add(className);\n state.autoWrapped.add(className);\n state.renamedLocals.add(className);\n state.needsImport = true;\n}\n\n/**\n * Wrap the configured classes an `export { ... }` statement names.\n *\n * A class *declared* in this module keeps the statement intact: the declaration is renamed and the\n * wrapper takes over its binding, so the untouched specifier now exports the wrapped class.\n *\n * A class that lives in **another** module — imported and re-exported, or re-exported directly — has\n * no local binding to overwrite (import bindings are immutable). Those specifiers are re-pointed at\n * a fresh wrapper binding instead, which means rebuilding the statement; specifiers this plugin has\n * no business touching are carried over verbatim.\n */\nfunction wrapSpecifierExports(node: ExportNamedNode, ctx: TransformContext, state: TransformState): void {\n const specifiers = node.specifiers ?? [];\n if (specifiers.length === 0) return;\n\n const sourceLiteral = node.source ? state.ms.original.slice(node.source.start, node.source.end) : undefined;\n\n const prelude: string[] = [];\n const wrappedPairs: string[] = [];\n const kept: string[] = [];\n\n for (const specifier of specifiers) {\n const pair = wrapCrossModuleSpecifier(specifier, sourceLiteral, ctx, state, prelude);\n if (pair) {\n wrappedPairs.push(pair);\n } else {\n kept.push(state.ms.original.slice(specifier.start, specifier.end));\n }\n }\n\n if (wrappedPairs.length === 0) return;\n\n const statements = [...prelude, `export { ${wrappedPairs.join(', ')} };`];\n if (kept.length > 0) {\n const clause = `export { ${kept.join(', ')} }`;\n statements.push(sourceLiteral ? `${clause} from ${sourceLiteral};` : `${clause};`);\n }\n state.ms.overwrite(node.start, node.end, statements.join('\\n'));\n}\n\n/**\n * Handle one export specifier, returning the `Wrapped as Exported` pair to emit when its class has\n * to be wrapped through a fresh binding — the cross-module case. The import/wrapper statements that\n * pair depends on are pushed onto `prelude`.\n *\n * Returns `undefined` when the specifier can stay exactly as written: it doesn't name a configured\n * class, its class is declared locally (wrapped in place via {@link wrapLocalClassExport}, which\n * takes over the binding the specifier already exports), or the binding is already hand-wrapped.\n */\nfunction wrapCrossModuleSpecifier(\n specifier: ExportSpecifierNode,\n sourceLiteral: string | undefined,\n ctx: TransformContext,\n state: TransformState,\n prelude: string[],\n): string | undefined {\n const exportedName =\n specifier.type === 'ExportSpecifier' && specifier.exported?.type === 'Identifier'\n ? specifier.exported.name\n : undefined;\n const localName = specifier.local?.type === 'Identifier' ? specifier.local.name : undefined;\n // With a `from` clause the specifier names an export of the *source* module, not a binding here.\n const kind = exportedName\n ? resolveWrapperKind(exportedName, sourceLiteral ? undefined : localName, state)\n : undefined;\n\n if (!exportedName || !localName || !kind) return undefined;\n\n // Without a `from` clause the specifier points at a module-local binding, which may already be\n // (or become) the wrapped class without touching the export statement itself.\n if (!sourceLiteral) {\n const localClass = state.topLevelClasses.get(localName);\n\n if (localClass?.id) {\n wrapLocalClassExport(localName, localClass, kind, ctx, state);\n state.wrappedClasses.add(exportedName);\n state.needsImport = true;\n return undefined;\n }\n\n if (state.manuallyWrappedLocals.has(localName)) {\n state.wrappedClasses.add(exportedName);\n return undefined;\n }\n }\n\n // The class comes from another module: bind it under a private name (for the `from` form, which\n // has no local binding at all), wrap that, and export the wrapper under the configured name.\n let target = localName;\n\n if (sourceLiteral) {\n target = `__SENTRY_REEXPORT_${exportedName}__`;\n prelude.push(\n localName === DEFAULT_IMPORT\n ? `import ${target} from ${sourceLiteral};`\n : `import { ${localName} as ${target} } from ${sourceLiteral};`,\n );\n }\n\n const wrappedName = `__SENTRY_WRAPPED_${exportedName}__`;\n\n // The class may already be hand-wrapped in its own module, which this transform cannot see. The\n // emitted guard returns such a class as-is instead of nesting a second wrapper around it.\n prelude.push(\n `const ${wrappedName} = __SENTRY__._INTERNAL_wrapUnlessInstrumented(__SENTRY__.${WRAPPER_METHODS[kind]}, ${state.optionsFn}, ${target});`,\n );\n state.wrappedClasses.add(exportedName);\n state.autoWrapped.add(exportedName);\n state.needsImport = true;\n\n return `${wrappedName} as ${exportedName}`;\n}\n\n/** Rename a locally declared class and rebind its original name to the wrapper. */\nfunction wrapLocalClassExport(\n localName: string,\n localClass: ClassDeclarationNode,\n kind: ClassWrapperKind,\n ctx: TransformContext,\n state: TransformState,\n): void {\n const classId = localClass.id;\n if (!classId || state.renamedLocals.has(localName)) return;\n state.renamedLocals.add(localName);\n\n const renamedClass = `__SENTRY_ORIGINAL_${localName}__`;\n state.ms.overwrite(classId.start, classId.end, renamedClass);\n state.ms.appendLeft(\n localClass.end,\n `\\nconst ${localName} = __SENTRY__.${WRAPPER_METHODS[kind]}(${state.optionsFn}, ${renamedClass});\\n`,\n );\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"transform.js","sources":["../../../../src/vite/transform.ts"],"sourcesContent":["/* eslint-disable max-lines */\nimport MagicString from 'magic-string';\nimport { DEFAULT_EXPORT, type ExportName, type SameWorkerBinding } from './wranglerConfig';\nimport { detectWorkerEntrypointClasses } from './workerEntrypoint';\n\nconst MERGED_OPTIONS_IDENTIFIER = '__SENTRY_OPTIONS__';\n\n// ---------------------------------------------------------------------------\n// Minimal ESTree node types for the AST nodes we inspect.\n// ---------------------------------------------------------------------------\n\nexport interface BaseNode {\n type: string;\n start: number;\n end: number;\n}\n\nexport interface ProgramBody {\n body: BaseNode[];\n}\n\ninterface IdentifierNode extends BaseNode {\n name: string;\n}\n\ninterface CalleeNode {\n type: string;\n name?: string;\n property?: { type: string; name?: string };\n}\n\ninterface CallExpressionNode extends BaseNode {\n callee?: CalleeNode;\n}\n\ninterface ClassDeclarationNode extends BaseNode {\n id?: IdentifierNode | null;\n}\n\ninterface ExportDefaultNode extends BaseNode {\n declaration: BaseNode;\n}\n\ninterface ExportSpecifierNode extends BaseNode {\n local?: { type: string; name?: string };\n exported?: { type: string; name?: string };\n}\n\ninterface ExportNamedNode extends BaseNode {\n declaration?: BaseNode | null;\n source?: BaseNode | null;\n specifiers?: ExportSpecifierNode[];\n}\n\ninterface VariableDeclaratorNode {\n id?: { type: string; name?: string };\n init?: BaseNode | null;\n}\n\ninterface VariableDeclarationNode extends BaseNode {\n declarations?: VariableDeclaratorNode[];\n}\n\nfunction isCallToMethod(node: BaseNode, methodName: string): boolean {\n if (node.type !== 'CallExpression') return false;\n const callee = (node as CallExpressionNode).callee;\n if (!callee) return false;\n if (callee.type === 'Identifier' && callee.name === methodName) return true;\n return (\n callee.type === 'MemberExpression' && callee.property?.type === 'Identifier' && callee.property.name === methodName\n );\n}\n\n/**\n * The kind of Sentry wrapper to apply to an exported class.\n *\n * `durableObject` and `workflow` are keyed by name from the wrangler config\n * (`durable_objects.bindings`, `workflows`), since those class names are\n * authoritative there. `workerEntrypoint` is different: a worker's own\n * entrypoints aren't enumerated in its config, so they're detected structurally\n * (a class extending `WorkerEntrypoint` from `cloudflare:workers`), with the\n * config providing only a fallback for self-bound entrypoints whose base class\n * lives in another module.\n */\nexport type ClassWrapperKind = 'durableObject' | 'agent' | 'workflow' | 'workerEntrypoint';\n\n/** Specifier name a `export { default as X } from '...'` re-export uses for the source's default. */\nconst DEFAULT_IMPORT = 'default';\n\n/**\n * The `@sentry/cloudflare` helper each wrapper kind emits. All share the same\n * `(optionsCallback, Class)` signature. `WorkerEntrypoint` classes use\n * `withSentry`, which runtime-detects the class type and routes accordingly.\n */\nconst WRAPPER_METHODS: Record<ClassWrapperKind, string> = {\n durableObject: 'instrumentDurableObjectWithSentry',\n agent: 'instrumentAgentWithSentry',\n workflow: 'instrumentWorkflowWithSentry',\n workerEntrypoint: 'withSentry',\n};\n\nexport interface TransformContext {\n /**\n * Exported class name → the kind of Sentry wrapper to apply. Populated from\n * the wrangler config, so the transform can wrap by name without resolving\n * each class's base type.\n */\n classWrappers: Map<string, ClassWrapperKind>;\n /**\n * Local class names detected as `agents` Agents. An Agent is configured as a Durable Object in\n * wrangler, so this upgrades those entries from `durableObject` to `agent`.\n */\n agentClasses?: ReadonlySet<string>;\n optionsFn: string;\n /** Import statement prepended when `optionsFn` references a separate module. */\n optionsImport?: string;\n /** @see {@link import('./wranglerConfig').WranglerConfig.sameWorkerBindings} */\n sameWorkerBindings?: readonly SameWorkerBinding[];\n}\n\nexport interface TransformResult {\n code: string;\n map: ReturnType<MagicString['generateMap']>;\n /**\n * The configured class names that were actually wrapped. Lets the plugin warn\n * about configured classes it could not find, instead of silently leaving\n * them uninstrumented.\n */\n wrappedClasses: Set<string>;\n}\n\n/**\n * Rewrite the worker entry source to wrap its default export with `withSentry`\n * and any configured class export with its matching Sentry wrapper (see\n * {@link TransformContext.classWrappers}, e.g. Durable Object classes with\n * `instrumentDurableObjectWithSentry`).\n *\n * Handles `export class MyDO {}`, the specifier form (`class MyDO {}` …\n * `export { MyDO }` / `export { Foo as MyDO }`), and classes that live in\n * another module (`import { MyDO } from './do'; export { MyDO }` or\n * `export { MyDO } from './do'`). Only star re-exports (`export * from './do'`)\n * are left alone — the plugin warns about those via\n * {@link TransformResult.wrappedClasses}.\n *\n * Exported (rather than inlined into the plugin) so it can be unit-tested with a\n * plain AST and no Vite context. Returns `undefined` when nothing was wrapped and\n * there are no already-manually-wrapped classes to report.\n */\nexport function applyAutoInstrumentTransforms(\n code: string,\n ast: ProgramBody,\n ctx: TransformContext,\n): TransformResult | undefined {\n const ms = new MagicString(code);\n const topLevelClasses = collectTopLevelClasses(ast);\n const sameWorkerBindings = ctx.sameWorkerBindings ?? [];\n const state: TransformState = {\n ms,\n needsImport: false,\n wrappedClasses: new Set<string>(),\n topLevelClasses,\n wrappedLocals: new Map<string, string>(),\n classWrappers: ctx.classWrappers,\n agentClasses: ctx.agentClasses ?? new Set<string>(),\n workerEntrypointClasses: detectWorkerEntrypointClasses(ast),\n // The identifier must be chosen before wrapping, which bindings survive is only known after.\n optionsFn: sameWorkerBindings.length > 0 ? MERGED_OPTIONS_IDENTIFIER : ctx.optionsFn,\n autoWrapped: new Set<ExportName>(),\n manuallyWrappedLocals: collectManuallyWrappedLocals(ast),\n };\n const { wrappedClasses } = state;\n\n // Named exports first, regardless of source order: the default-export handler\n // needs to know which local bindings a named export already wrapped, so it can\n // skip a class that is both exported by name and re-exported as default (which\n // would otherwise wrap it twice).\n for (const node of ast.body) {\n if (node.type === 'ExportNamedDeclaration') {\n handleNamedExport(node, ctx, state);\n }\n }\n for (const node of ast.body) {\n if (node.type === 'ExportDefaultDeclaration') {\n wrapDefaultExport(node as ExportDefaultNode, ctx, state);\n }\n }\n\n if (!state.needsImport) {\n // Nothing was rewritten. Still surface any classes found already wrapped\n // manually (via `wrappedClasses`) so the caller doesn't warn about them;\n // return undefined only when there was nothing to report either.\n if (wrappedClasses.size === 0) return undefined;\n return { code, map: ms.generateMap({ hires: true }), wrappedClasses };\n }\n\n // `prepend` inserts before earlier prepends, yielding: Sentry import, options import, declaration.\n if (sameWorkerBindings.length > 0) {\n ms.prepend(buildMergedOptionsDeclaration(sameWorkerBindings, ctx.optionsFn, state));\n }\n if (ctx.optionsImport) ms.prepend(ctx.optionsImport);\n ms.prepend(\"import * as __SENTRY__ from '@sentry/cloudflare';\\n\");\n\n return {\n code: ms.toString(),\n map: ms.generateMap({ hires: true }),\n wrappedClasses,\n };\n}\n\ninterface TransformState {\n ms: MagicString;\n needsImport: boolean;\n wrappedClasses: Set<string>;\n /**\n * Top-level (non-exported) class declarations, so specifier exports like\n * `export { MyDO }` can locate the class they refer to.\n */\n topLevelClasses: Map<string, ClassDeclarationNode>;\n /**\n * Local class name → the binding holding its wrapper, so two exports of the same class share one\n * wrapper and a default export of it can be re-pointed.\n */\n wrappedLocals: Map<string, string>;\n /** Class name → wrapper kind, keyed by the *exported* name (from config). */\n classWrappers: Map<string, ClassWrapperKind>;\n /** Local class names detected as `agents` Agents (see {@link TransformContext.agentClasses}). */\n agentClasses: ReadonlySet<string>;\n /**\n * Local class names detected as `WorkerEntrypoint` subclasses in this module,\n * so they can be wrapped without a config entry.\n */\n workerEntrypointClasses: Set<string>;\n optionsFn: string;\n /**\n * Export names wrapped by this transform, so their options can be extended with\n * `rpcTracePropagationBindings`. Hand-wrapped exports stay out, they keep the options they were\n * wrapped with. `wrappedClasses` counts both.\n */\n autoWrapped: Set<ExportName>;\n /**\n * Top-level bindings already assigned an `instrument*WithSentry(...)` result\n * (`const MyDO = instrumentDurableObjectWithSentry(...)`). Exporting one by\n * specifier must report it as wrapped rather than wrap it a second time.\n */\n manuallyWrappedLocals: Set<string>;\n}\n\n/**\n * Builds the callback that merges same-worker binding names into `rpcTracePropagationBindings` at\n * runtime, the options object only exists once the callback runs with `env`. Only bindings whose\n * class this transform wrapped survive, a hand-wrapped class runs on its own options.\n */\nfunction buildMergedOptionsDeclaration(\n sameWorkerBindings: readonly SameWorkerBinding[],\n optionsFn: string,\n state: TransformState,\n): string {\n const bindingNames = sameWorkerBindings\n .filter(({ className }) => state.autoWrapped.has(className))\n .map(({ bindingName }) => bindingName);\n\n if (!bindingNames.length) {\n return `const ${MERGED_OPTIONS_IDENTIFIER} = ${optionsFn};\\n`;\n }\n\n const names = bindingNames.map(name => JSON.stringify(name)).join(', ');\n return (\n `const ${MERGED_OPTIONS_IDENTIFIER} = (env) => { ` +\n `const opts = (${optionsFn})(env); ` +\n `return { ...opts, rpcTracePropagationBindings: [${names}, ...(opts?.rpcTracePropagationBindings ?? [])] }; };\\n`\n );\n}\n\n/**\n * Resolve the wrapper kind for a class export.\n *\n * Config (`classWrappers`) wins — it's authoritative for Durable Objects and\n * Workflows, and provides the self-binding fallback for WorkerEntrypoints whose\n * base class this module can't see. Otherwise a structurally-detected\n * `WorkerEntrypoint` subclass (matched by its *local* name) gets wrapped with\n * `withSentry`.\n *\n * `localName` is the binding **in this module** the export refers to, and must be\n * left undefined for `export { X } from '...'`: there the specifier's name belongs\n * to the source module, so matching it against anything detected here would wrap a\n * class that merely shares a name.\n *\n * The one case where config is refined rather than obeyed is an `agents` Agent:\n * it *is* a Durable Object, so wrangler can only ever describe it as one, and\n * only the detected base chain distinguishes the two.\n */\nfunction resolveWrapperKind(\n exportedName: string,\n localName: string | undefined,\n state: TransformState,\n): ClassWrapperKind | undefined {\n const configured = state.classWrappers.get(exportedName);\n\n if (\n configured === 'durableObject' &&\n ((localName && state.agentClasses.has(localName)) || state.agentClasses.has(exportedName))\n ) {\n return 'agent';\n }\n\n if (configured) return configured;\n if (localName && state.workerEntrypointClasses.has(localName)) return 'workerEntrypoint';\n return undefined;\n}\n\n/**\n * Top-level `const X = instrument*WithSentry(...)` bindings — a hand-wrapped class that is exported\n * separately (`export { X }`) rather than inline.\n */\nfunction collectManuallyWrappedLocals(ast: ProgramBody): Set<string> {\n const wrapperMethods = Object.values(WRAPPER_METHODS);\n const locals = new Set<string>();\n\n for (const node of ast.body) {\n if (node.type !== 'VariableDeclaration') continue;\n for (const declarator of (node as VariableDeclarationNode).declarations ?? []) {\n const name = declarator.id?.type === 'Identifier' ? declarator.id.name : undefined;\n const init = declarator.init;\n if (name && init && wrapperMethods.some(method => isCallToMethod(init, method))) {\n locals.add(name);\n }\n }\n }\n\n return locals;\n}\n\nfunction collectTopLevelClasses(ast: ProgramBody): Map<string, ClassDeclarationNode> {\n const classes = new Map<string, ClassDeclarationNode>();\n for (const node of ast.body) {\n if (node.type !== 'ClassDeclaration') continue;\n const classNode = node as ClassDeclarationNode;\n if (classNode.id?.name) classes.set(classNode.id.name, classNode);\n }\n return classes;\n}\n\nfunction wrapDefaultExport(node: ExportDefaultNode, ctx: TransformContext, state: TransformState): void {\n const decl = node.declaration;\n\n // Already wrapped — leave it alone\n if (isCallToMethod(decl, 'withSentry')) return;\n\n // `export default Foo` where `Foo` is a local class already wrapped by a named\n // export (e.g. a self-bound WorkerEntrypoint also used as the default handler).\n // Wrapping again would produce `withSentry(withSentry(...))`, so the default\n // export is re-pointed at the wrapper binding the named export created.\n if (decl.type === 'Identifier') {\n const wrappedName = state.wrappedLocals.get((decl as IdentifierNode).name);\n if (wrappedName) {\n state.ms.overwrite(decl.start, decl.end, wrappedName);\n state.autoWrapped.add(DEFAULT_EXPORT);\n return;\n }\n }\n\n // `export default <expr>` → `const __SENTRY_DEFAULT_EXPORT__ = <expr>`\n // MagicString positions are always relative to the original source.\n state.ms.overwrite(node.start, decl.start, 'const __SENTRY_DEFAULT_EXPORT__ = ');\n state.ms.append(`\\nexport default __SENTRY__.withSentry(${state.optionsFn}, __SENTRY_DEFAULT_EXPORT__);\\n`);\n state.needsImport = true;\n state.autoWrapped.add(DEFAULT_EXPORT);\n}\n\nfunction handleNamedExport(node: ExportNamedNode, ctx: TransformContext, state: TransformState): void {\n const decl = node.declaration;\n\n // ---- Manually wrapped class export ----\n // `export const MyDO = instrumentDurableObjectWithSentry(...)` — count it\n // as wrapped so the plugin doesn't warn about it, but leave it alone.\n if (decl?.type === 'VariableDeclaration') {\n collectManuallyWrappedClassExports(decl, ctx, state);\n return;\n }\n\n // ---- Named class export matching a configured binding ----\n if (decl?.type === 'ClassDeclaration') {\n wrapInlineClassExport(node, decl, ctx, state);\n return;\n }\n\n // ---- Specifier export (`export { Foo as MyDO }`, `export { MyDO } from './do'`) ----\n wrapSpecifierExports(node, ctx, state);\n}\n\nfunction collectManuallyWrappedClassExports(\n varDecl: VariableDeclarationNode,\n ctx: TransformContext,\n state: TransformState,\n): void {\n for (const declarator of varDecl.declarations ?? []) {\n const name = declarator.id?.type === 'Identifier' ? declarator.id.name : undefined;\n const kind = name ? ctx.classWrappers.get(name) : undefined;\n if (!name || !kind || !declarator.init) continue;\n\n // A hand-wrapped Agent is configured as a Durable Object, so accept either helper there —\n // otherwise an already-instrumented Agent would be reported as unwrapped.\n const accepted =\n kind === 'durableObject' ? [WRAPPER_METHODS.durableObject, WRAPPER_METHODS.agent] : [WRAPPER_METHODS[kind]];\n\n if (accepted.some(method => isCallToMethod(declarator.init as BaseNode, method))) {\n state.wrappedClasses.add(name);\n }\n }\n}\n\nfunction wrapInlineClassExport(\n exportNode: ExportNamedNode,\n classDecl: ClassDeclarationNode,\n ctx: TransformContext,\n state: TransformState,\n): void {\n const classId = classDecl.id;\n // Inline export: the exported name and the local class name are the same.\n const kind = classId ? resolveWrapperKind(classId.name, classId.name, state) : undefined;\n if (!classId || !kind) return;\n\n const className = classId.name;\n\n // Strip the `export ` keyword\n state.ms.overwrite(exportNode.start, classDecl.start, '');\n\n const wrappedName = wrapLocalClass(className, classDecl, kind, state);\n state.ms.appendLeft(exportNode.end, `export { ${wrappedName} as ${className} };\\n`);\n\n state.wrappedClasses.add(className);\n state.autoWrapped.add(className);\n}\n\n/**\n * Wrap a class declared in this module and return the binding that holds the wrapper.\n *\n * The declaration is left exactly as written. Only the *export* has to become the wrapper, so the\n * wrapper gets its own binding and the export is aliased to it, the same shape as the documented\n * manual `instrument*WithSentry` pattern and the cross-module re-export path below. Renaming the\n * declaration instead (`class __SENTRY_ORIGINAL_MyAgent__`) would also rename what the class reports\n * as `Function.prototype.name`, which libraries read to identify the user's class: `@cloudflare/think`\n * hands `this.constructor.name` to the AI SDK as the telemetry `functionId`, and that surfaced as a\n * `gen_ai.invoke_agent __SENTRY_ORIGINAL_MyAgent__` span.\n */\nfunction wrapLocalClass(\n localName: string,\n localClass: ClassDeclarationNode,\n kind: ClassWrapperKind,\n state: TransformState,\n): string {\n const existing = state.wrappedLocals.get(localName);\n if (existing) return existing;\n\n const wrappedName = `__SENTRY_WRAPPED_${localName}__`;\n state.wrappedLocals.set(localName, wrappedName);\n state.ms.appendLeft(\n localClass.end,\n `\\nconst ${wrappedName} = __SENTRY__.${WRAPPER_METHODS[kind]}(${state.optionsFn}, ${localName});\\n`,\n );\n state.needsImport = true;\n return wrappedName;\n}\n\n/**\n * Wrap the configured classes an `export { ... }` statement names.\n *\n * Each such specifier is re-pointed at a binding holding the wrapper, which means rebuilding the\n * statement; specifiers this plugin has no business touching are carried over verbatim. For a class\n * declared in this module the wrapper binding follows the declaration (see {@link wrapLocalClass}).\n * A class that lives in **another** module — imported and re-exported, or re-exported directly — is\n * first bound under a private name, since an import binding cannot be reassigned and the `from` form\n * has no local binding at all.\n */\nfunction wrapSpecifierExports(node: ExportNamedNode, ctx: TransformContext, state: TransformState): void {\n const specifiers = node.specifiers ?? [];\n if (specifiers.length === 0) return;\n\n const sourceLiteral = node.source ? state.ms.original.slice(node.source.start, node.source.end) : undefined;\n\n const prelude: string[] = [];\n const wrappedPairs: string[] = [];\n const kept: string[] = [];\n\n for (const specifier of specifiers) {\n const pair = wrapSpecifier(specifier, sourceLiteral, ctx, state, prelude);\n if (pair) {\n wrappedPairs.push(pair);\n } else {\n kept.push(state.ms.original.slice(specifier.start, specifier.end));\n }\n }\n\n if (wrappedPairs.length === 0) return;\n\n const statements = [...prelude, `export { ${wrappedPairs.join(', ')} };`];\n if (kept.length > 0) {\n const clause = `export { ${kept.join(', ')} }`;\n statements.push(sourceLiteral ? `${clause} from ${sourceLiteral};` : `${clause};`);\n }\n state.ms.overwrite(node.start, node.end, statements.join('\\n'));\n}\n\n/**\n * Handle one export specifier, returning the `Wrapped as Exported` pair to emit for a class that\n * gets wrapped. The import/wrapper statements a cross-module pair depends on are pushed onto\n * `prelude`; a local class's wrapper binding is emitted after its declaration instead.\n *\n * Returns `undefined` when the specifier can stay exactly as written: it doesn't name a configured\n * class, or the binding is already hand-wrapped.\n */\nfunction wrapSpecifier(\n specifier: ExportSpecifierNode,\n sourceLiteral: string | undefined,\n ctx: TransformContext,\n state: TransformState,\n prelude: string[],\n): string | undefined {\n const exportedName =\n specifier.type === 'ExportSpecifier' && specifier.exported?.type === 'Identifier'\n ? specifier.exported.name\n : undefined;\n const localName = specifier.local?.type === 'Identifier' ? specifier.local.name : undefined;\n // With a `from` clause the specifier names an export of the *source* module, not a binding here.\n const kind = exportedName\n ? resolveWrapperKind(exportedName, sourceLiteral ? undefined : localName, state)\n : undefined;\n\n if (!exportedName || !localName || !kind) return undefined;\n\n // Without a `from` clause the specifier points at a module-local binding.\n if (!sourceLiteral) {\n const localClass = state.topLevelClasses.get(localName);\n\n if (localClass?.id) {\n const wrappedName = wrapLocalClass(localName, localClass, kind, state);\n state.wrappedClasses.add(exportedName);\n return `${wrappedName} as ${exportedName}`;\n }\n\n if (state.manuallyWrappedLocals.has(localName)) {\n state.wrappedClasses.add(exportedName);\n return undefined;\n }\n }\n\n // The class comes from another module: bind it under a private name (for the `from` form, which\n // has no local binding at all), wrap that, and export the wrapper under the configured name.\n let target = localName;\n\n if (sourceLiteral) {\n target = `__SENTRY_REEXPORT_${exportedName}__`;\n prelude.push(\n localName === DEFAULT_IMPORT\n ? `import ${target} from ${sourceLiteral};`\n : `import { ${localName} as ${target} } from ${sourceLiteral};`,\n );\n }\n\n const wrappedName = `__SENTRY_WRAPPED_${exportedName}__`;\n\n // The class may already be hand-wrapped in its own module, which this transform cannot see. The\n // emitted guard returns such a class as-is instead of nesting a second wrapper around it.\n prelude.push(\n `const ${wrappedName} = __SENTRY__._INTERNAL_wrapUnlessInstrumented(__SENTRY__.${WRAPPER_METHODS[kind]}, ${state.optionsFn}, ${target});`,\n );\n state.wrappedClasses.add(exportedName);\n state.autoWrapped.add(exportedName);\n state.needsImport = true;\n\n return `${wrappedName} as ${exportedName}`;\n}\n"],"names":["wrappedName"],"mappings":";;;;AAKA,MAAM,yBAAA,GAA4B,oBAAA;AA0DlC,SAAS,cAAA,CAAe,MAAgB,UAAA,EAA6B;AACnE,EAAA,IAAI,IAAA,CAAK,IAAA,KAAS,gBAAA,EAAkB,OAAO,KAAA;AAC3C,EAAA,MAAM,SAAU,IAAA,CAA4B,MAAA;AAC5C,EAAA,IAAI,CAAC,QAAQ,OAAO,KAAA;AACpB,EAAA,IAAI,OAAO,IAAA,KAAS,YAAA,IAAgB,MAAA,CAAO,IAAA,KAAS,YAAY,OAAO,IAAA;AACvE,EAAA,OACE,MAAA,CAAO,SAAS,kBAAA,IAAsB,MAAA,CAAO,UAAU,IAAA,KAAS,YAAA,IAAgB,MAAA,CAAO,QAAA,CAAS,IAAA,KAAS,UAAA;AAE7G;AAgBA,MAAM,cAAA,GAAiB,SAAA;AAOvB,MAAM,eAAA,GAAoD;AAAA,EACxD,aAAA,EAAe,mCAAA;AAAA,EACf,KAAA,EAAO,2BAAA;AAAA,EACP,QAAA,EAAU,8BAAA;AAAA,EACV,gBAAA,EAAkB;AACpB,CAAA;AAiDO,SAAS,6BAAA,CACd,IAAA,EACA,GAAA,EACA,GAAA,EAC6B;AAC7B,EAAA,MAAM,EAAA,GAAK,IAAI,WAAA,CAAY,IAAI,CAAA;AAC/B,EAAA,MAAM,eAAA,GAAkB,uBAAuB,GAAG,CAAA;AAClD,EAAA,MAAM,kBAAA,GAAqB,GAAA,CAAI,kBAAA,IAAsB,EAAC;AACtD,EAAA,MAAM,KAAA,GAAwB;AAAA,IAC5B,EAAA;AAAA,IACA,WAAA,EAAa,KAAA;AAAA,IACb,cAAA,sBAAoB,GAAA,EAAY;AAAA,IAChC,eAAA;AAAA,IACA,aAAA,sBAAmB,GAAA,EAAoB;AAAA,IACvC,eAAe,GAAA,CAAI,aAAA;AAAA,IACnB,YAAA,EAAc,GAAA,CAAI,YAAA,oBAAgB,IAAI,GAAA,EAAY;AAAA,IAClD,uBAAA,EAAyB,8BAA8B,GAAG,CAAA;AAAA;AAAA,IAE1D,SAAA,EAAW,kBAAA,CAAmB,MAAA,GAAS,CAAA,GAAI,4BAA4B,GAAA,CAAI,SAAA;AAAA,IAC3E,WAAA,sBAAiB,GAAA,EAAgB;AAAA,IACjC,qBAAA,EAAuB,6BAA6B,GAAG;AAAA,GACzD;AACA,EAAA,MAAM,EAAE,gBAAe,GAAI,KAAA;AAM3B,EAAA,KAAA,MAAW,IAAA,IAAQ,IAAI,IAAA,EAAM;AAC3B,IAAA,IAAI,IAAA,CAAK,SAAS,wBAAA,EAA0B;AAC1C,MAAA,iBAAA,CAAkB,IAAA,EAAM,KAAK,KAAK,CAAA;AAAA,IACpC;AAAA,EACF;AACA,EAAA,KAAA,MAAW,IAAA,IAAQ,IAAI,IAAA,EAAM;AAC3B,IAAA,IAAI,IAAA,CAAK,SAAS,0BAAA,EAA4B;AAC5C,MAAA,iBAAA,CAAkB,IAAA,EAA2B,KAAK,KAAK,CAAA;AAAA,IACzD;AAAA,EACF;AAEA,EAAA,IAAI,CAAC,MAAM,WAAA,EAAa;AAItB,IAAA,IAAI,cAAA,CAAe,IAAA,KAAS,CAAA,EAAG,OAAO,MAAA;AACtC,IAAA,OAAO,EAAE,IAAA,EAAM,GAAA,EAAK,EAAA,CAAG,WAAA,CAAY,EAAE,KAAA,EAAO,IAAA,EAAM,CAAA,EAAG,cAAA,EAAe;AAAA,EACtE;AAGA,EAAA,IAAI,kBAAA,CAAmB,SAAS,CAAA,EAAG;AACjC,IAAA,EAAA,CAAG,QAAQ,6BAAA,CAA8B,kBAAA,EAAoB,GAAA,CAAI,SAAA,EAAW,KAAK,CAAC,CAAA;AAAA,EACpF;AACA,EAAA,IAAI,GAAA,CAAI,aAAA,EAAe,EAAA,CAAG,OAAA,CAAQ,IAAI,aAAa,CAAA;AACnD,EAAA,EAAA,CAAG,QAAQ,qDAAqD,CAAA;AAEhE,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,GAAG,QAAA,EAAS;AAAA,IAClB,KAAK,EAAA,CAAG,WAAA,CAAY,EAAE,KAAA,EAAO,MAAM,CAAA;AAAA,IACnC;AAAA,GACF;AACF;AA6CA,SAAS,6BAAA,CACP,kBAAA,EACA,SAAA,EACA,KAAA,EACQ;AACR,EAAA,MAAM,eAAe,kBAAA,CAClB,MAAA,CAAO,CAAC,EAAE,SAAA,OAAgB,KAAA,CAAM,WAAA,CAAY,GAAA,CAAI,SAAS,CAAC,CAAA,CAC1D,GAAA,CAAI,CAAC,EAAE,WAAA,OAAkB,WAAW,CAAA;AAEvC,EAAA,IAAI,CAAC,aAAa,MAAA,EAAQ;AACxB,IAAA,OAAO,CAAA,MAAA,EAAS,yBAAyB,CAAA,GAAA,EAAM,SAAS,CAAA;AAAA,CAAA;AAAA,EAC1D;AAEA,EAAA,MAAM,KAAA,GAAQ,YAAA,CAAa,GAAA,CAAI,CAAA,IAAA,KAAQ,IAAA,CAAK,UAAU,IAAI,CAAC,CAAA,CAAE,IAAA,CAAK,IAAI,CAAA;AACtE,EAAA,OACE,CAAA,MAAA,EAAS,yBAAyB,CAAA,4BAAA,EACjB,SAAS,2DACyB,KAAK,CAAA;AAAA,CAAA;AAE5D;AAoBA,SAAS,kBAAA,CACP,YAAA,EACA,SAAA,EACA,KAAA,EAC8B;AAC9B,EAAA,MAAM,UAAA,GAAa,KAAA,CAAM,aAAA,CAAc,GAAA,CAAI,YAAY,CAAA;AAEvD,EAAA,IACE,UAAA,KAAe,eAAA,KACb,SAAA,IAAa,KAAA,CAAM,YAAA,CAAa,GAAA,CAAI,SAAS,CAAA,IAAM,KAAA,CAAM,YAAA,CAAa,GAAA,CAAI,YAAY,CAAA,CAAA,EACxF;AACA,IAAA,OAAO,OAAA;AAAA,EACT;AAEA,EAAA,IAAI,YAAY,OAAO,UAAA;AACvB,EAAA,IAAI,aAAa,KAAA,CAAM,uBAAA,CAAwB,GAAA,CAAI,SAAS,GAAG,OAAO,kBAAA;AACtE,EAAA,OAAO,MAAA;AACT;AAMA,SAAS,6BAA6B,GAAA,EAA+B;AACnE,EAAA,MAAM,cAAA,GAAiB,MAAA,CAAO,MAAA,CAAO,eAAe,CAAA;AACpD,EAAA,MAAM,MAAA,uBAAa,GAAA,EAAY;AAE/B,EAAA,KAAA,MAAW,IAAA,IAAQ,IAAI,IAAA,EAAM;AAC3B,IAAA,IAAI,IAAA,CAAK,SAAS,qBAAA,EAAuB;AACzC,IAAA,KAAA,MAAW,UAAA,IAAe,IAAA,CAAiC,YAAA,IAAgB,EAAC,EAAG;AAC7E,MAAA,MAAM,OAAO,UAAA,CAAW,EAAA,EAAI,SAAS,YAAA,GAAe,UAAA,CAAW,GAAG,IAAA,GAAO,MAAA;AACzE,MAAA,MAAM,OAAO,UAAA,CAAW,IAAA;AACxB,MAAA,IAAI,IAAA,IAAQ,QAAQ,cAAA,CAAe,IAAA,CAAK,YAAU,cAAA,CAAe,IAAA,EAAM,MAAM,CAAC,CAAA,EAAG;AAC/E,QAAA,MAAA,CAAO,IAAI,IAAI,CAAA;AAAA,MACjB;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO,MAAA;AACT;AAEA,SAAS,uBAAuB,GAAA,EAAqD;AACnF,EAAA,MAAM,OAAA,uBAAc,GAAA,EAAkC;AACtD,EAAA,KAAA,MAAW,IAAA,IAAQ,IAAI,IAAA,EAAM;AAC3B,IAAA,IAAI,IAAA,CAAK,SAAS,kBAAA,EAAoB;AACtC,IAAA,MAAM,SAAA,GAAY,IAAA;AAClB,IAAA,IAAI,SAAA,CAAU,IAAI,IAAA,EAAM,OAAA,CAAQ,IAAI,SAAA,CAAU,EAAA,CAAG,MAAM,SAAS,CAAA;AAAA,EAClE;AACA,EAAA,OAAO,OAAA;AACT;AAEA,SAAS,iBAAA,CAAkB,IAAA,EAAyB,GAAA,EAAuB,KAAA,EAA6B;AACtG,EAAA,MAAM,OAAO,IAAA,CAAK,WAAA;AAGlB,EAAA,IAAI,cAAA,CAAe,IAAA,EAAM,YAAY,CAAA,EAAG;AAMxC,EAAA,IAAI,IAAA,CAAK,SAAS,YAAA,EAAc;AAC9B,IAAA,MAAM,WAAA,GAAc,KAAA,CAAM,aAAA,CAAc,GAAA,CAAK,KAAwB,IAAI,CAAA;AACzE,IAAA,IAAI,WAAA,EAAa;AACf,MAAA,KAAA,CAAM,GAAG,SAAA,CAAU,IAAA,CAAK,KAAA,EAAO,IAAA,CAAK,KAAK,WAAW,CAAA;AACpD,MAAA,KAAA,CAAM,WAAA,CAAY,IAAI,cAAc,CAAA;AACpC,MAAA;AAAA,IACF;AAAA,EACF;AAIA,EAAA,KAAA,CAAM,GAAG,SAAA,CAAU,IAAA,CAAK,KAAA,EAAO,IAAA,CAAK,OAAO,oCAAoC,CAAA;AAC/E,EAAA,KAAA,CAAM,GAAG,MAAA,CAAO;AAAA,qCAAA,EAA0C,MAAM,SAAS,CAAA;AAAA,CAAiC,CAAA;AAC1G,EAAA,KAAA,CAAM,WAAA,GAAc,IAAA;AACpB,EAAA,KAAA,CAAM,WAAA,CAAY,IAAI,cAAc,CAAA;AACtC;AAEA,SAAS,iBAAA,CAAkB,IAAA,EAAuB,GAAA,EAAuB,KAAA,EAA6B;AACpG,EAAA,MAAM,OAAO,IAAA,CAAK,WAAA;AAKlB,EAAA,IAAI,IAAA,EAAM,SAAS,qBAAA,EAAuB;AACxC,IAAA,kCAAA,CAAmC,IAAA,EAAM,KAAK,KAAK,CAAA;AACnD,IAAA;AAAA,EACF;AAGA,EAAA,IAAI,IAAA,EAAM,SAAS,kBAAA,EAAoB;AACrC,IAAA,qBAAA,CAAsB,IAAA,EAAM,IAAA,EAAM,GAAA,EAAK,KAAK,CAAA;AAC5C,IAAA;AAAA,EACF;AAGA,EAAA,oBAAA,CAAqB,IAAA,EAAM,KAAK,KAAK,CAAA;AACvC;AAEA,SAAS,kCAAA,CACP,OAAA,EACA,GAAA,EACA,KAAA,EACM;AACN,EAAA,KAAA,MAAW,UAAA,IAAc,OAAA,CAAQ,YAAA,IAAgB,EAAC,EAAG;AACnD,IAAA,MAAM,OAAO,UAAA,CAAW,EAAA,EAAI,SAAS,YAAA,GAAe,UAAA,CAAW,GAAG,IAAA,GAAO,MAAA;AACzE,IAAA,MAAM,OAAO,IAAA,GAAO,GAAA,CAAI,aAAA,CAAc,GAAA,CAAI,IAAI,CAAA,GAAI,MAAA;AAClD,IAAA,IAAI,CAAC,IAAA,IAAQ,CAAC,IAAA,IAAQ,CAAC,WAAW,IAAA,EAAM;AAIxC,IAAA,MAAM,QAAA,GACJ,IAAA,KAAS,eAAA,GAAkB,CAAC,eAAA,CAAgB,aAAA,EAAe,eAAA,CAAgB,KAAK,CAAA,GAAI,CAAC,eAAA,CAAgB,IAAI,CAAC,CAAA;AAE5G,IAAA,IAAI,QAAA,CAAS,KAAK,CAAA,MAAA,KAAU,cAAA,CAAe,WAAW,IAAA,EAAkB,MAAM,CAAC,CAAA,EAAG;AAChF,MAAA,KAAA,CAAM,cAAA,CAAe,IAAI,IAAI,CAAA;AAAA,IAC/B;AAAA,EACF;AACF;AAEA,SAAS,qBAAA,CACP,UAAA,EACA,SAAA,EACA,GAAA,EACA,KAAA,EACM;AACN,EAAA,MAAM,UAAU,SAAA,CAAU,EAAA;AAE1B,EAAA,MAAM,IAAA,GAAO,UAAU,kBAAA,CAAmB,OAAA,CAAQ,MAAM,OAAA,CAAQ,IAAA,EAAM,KAAK,CAAA,GAAI,MAAA;AAC/E,EAAA,IAAI,CAAC,OAAA,IAAW,CAAC,IAAA,EAAM;AAEvB,EAAA,MAAM,YAAY,OAAA,CAAQ,IAAA;AAG1B,EAAA,KAAA,CAAM,GAAG,SAAA,CAAU,UAAA,CAAW,KAAA,EAAO,SAAA,CAAU,OAAO,EAAE,CAAA;AAExD,EAAA,MAAM,WAAA,GAAc,cAAA,CAAe,SAAA,EAAW,SAAA,EAAW,MAAM,KAAK,CAAA;AACpE,EAAA,KAAA,CAAM,GAAG,UAAA,CAAW,UAAA,CAAW,KAAK,CAAA,SAAA,EAAY,WAAW,OAAO,SAAS,CAAA;AAAA,CAAO,CAAA;AAElF,EAAA,KAAA,CAAM,cAAA,CAAe,IAAI,SAAS,CAAA;AAClC,EAAA,KAAA,CAAM,WAAA,CAAY,IAAI,SAAS,CAAA;AACjC;AAaA,SAAS,cAAA,CACP,SAAA,EACA,UAAA,EACA,IAAA,EACA,KAAA,EACQ;AACR,EAAA,MAAM,QAAA,GAAW,KAAA,CAAM,aAAA,CAAc,GAAA,CAAI,SAAS,CAAA;AAClD,EAAA,IAAI,UAAU,OAAO,QAAA;AAErB,EAAA,MAAM,WAAA,GAAc,oBAAoB,SAAS,CAAA,EAAA,CAAA;AACjD,EAAA,KAAA,CAAM,aAAA,CAAc,GAAA,CAAI,SAAA,EAAW,WAAW,CAAA;AAC9C,EAAA,KAAA,CAAM,EAAA,CAAG,UAAA;AAAA,IACP,UAAA,CAAW,GAAA;AAAA,IACX;AAAA,MAAA,EAAW,WAAW,iBAAiB,eAAA,CAAgB,IAAI,CAAC,CAAA,CAAA,EAAI,KAAA,CAAM,SAAS,CAAA,EAAA,EAAK,SAAS,CAAA;AAAA;AAAA,GAC/F;AACA,EAAA,KAAA,CAAM,WAAA,GAAc,IAAA;AACpB,EAAA,OAAO,WAAA;AACT;AAYA,SAAS,oBAAA,CAAqB,IAAA,EAAuB,GAAA,EAAuB,KAAA,EAA6B;AACvG,EAAA,MAAM,UAAA,GAAa,IAAA,CAAK,UAAA,IAAc,EAAC;AACvC,EAAA,IAAI,UAAA,CAAW,WAAW,CAAA,EAAG;AAE7B,EAAA,MAAM,aAAA,GAAgB,IAAA,CAAK,MAAA,GAAS,KAAA,CAAM,EAAA,CAAG,QAAA,CAAS,KAAA,CAAM,IAAA,CAAK,MAAA,CAAO,KAAA,EAAO,IAAA,CAAK,MAAA,CAAO,GAAG,CAAA,GAAI,MAAA;AAElG,EAAA,MAAM,UAAoB,EAAC;AAC3B,EAAA,MAAM,eAAyB,EAAC;AAChC,EAAA,MAAM,OAAiB,EAAC;AAExB,EAAA,KAAA,MAAW,aAAa,UAAA,EAAY;AAClC,IAAA,MAAM,OAAO,aAAA,CAAc,SAAA,EAAW,aAAA,EAAe,GAAA,EAAK,OAAO,OAAO,CAAA;AACxE,IAAA,IAAI,IAAA,EAAM;AACR,MAAA,YAAA,CAAa,KAAK,IAAI,CAAA;AAAA,IACxB,CAAA,MAAO;AACL,MAAA,IAAA,CAAK,IAAA,CAAK,MAAM,EAAA,CAAG,QAAA,CAAS,MAAM,SAAA,CAAU,KAAA,EAAO,SAAA,CAAU,GAAG,CAAC,CAAA;AAAA,IACnE;AAAA,EACF;AAEA,EAAA,IAAI,YAAA,CAAa,WAAW,CAAA,EAAG;AAE/B,EAAA,MAAM,UAAA,GAAa,CAAC,GAAG,OAAA,EAAS,YAAY,YAAA,CAAa,IAAA,CAAK,IAAI,CAAC,CAAA,GAAA,CAAK,CAAA;AACxE,EAAA,IAAI,IAAA,CAAK,SAAS,CAAA,EAAG;AACnB,IAAA,MAAM,MAAA,GAAS,CAAA,SAAA,EAAY,IAAA,CAAK,IAAA,CAAK,IAAI,CAAC,CAAA,EAAA,CAAA;AAC1C,IAAA,UAAA,CAAW,IAAA,CAAK,gBAAgB,CAAA,EAAG,MAAM,SAAS,aAAa,CAAA,CAAA,CAAA,GAAM,CAAA,EAAG,MAAM,CAAA,CAAA,CAAG,CAAA;AAAA,EACnF;AACA,EAAA,KAAA,CAAM,EAAA,CAAG,UAAU,IAAA,CAAK,KAAA,EAAO,KAAK,GAAA,EAAK,UAAA,CAAW,IAAA,CAAK,IAAI,CAAC,CAAA;AAChE;AAUA,SAAS,aAAA,CACP,SAAA,EACA,aAAA,EACA,GAAA,EACA,OACA,OAAA,EACoB;AACpB,EAAA,MAAM,YAAA,GACJ,SAAA,CAAU,IAAA,KAAS,iBAAA,IAAqB,SAAA,CAAU,UAAU,IAAA,KAAS,YAAA,GACjE,SAAA,CAAU,QAAA,CAAS,IAAA,GACnB,MAAA;AACN,EAAA,MAAM,YAAY,SAAA,CAAU,KAAA,EAAO,SAAS,YAAA,GAAe,SAAA,CAAU,MAAM,IAAA,GAAO,MAAA;AAElF,EAAA,MAAM,IAAA,GAAO,eACT,kBAAA,CAAmB,YAAA,EAAc,gBAAgB,MAAA,GAAY,SAAA,EAAW,KAAK,CAAA,GAC7E,MAAA;AAEJ,EAAA,IAAI,CAAC,YAAA,IAAgB,CAAC,SAAA,IAAa,CAAC,MAAM,OAAO,MAAA;AAGjD,EAAA,IAAI,CAAC,aAAA,EAAe;AAClB,IAAA,MAAM,UAAA,GAAa,KAAA,CAAM,eAAA,CAAgB,GAAA,CAAI,SAAS,CAAA;AAEtD,IAAA,IAAI,YAAY,EAAA,EAAI;AAClB,MAAA,MAAMA,YAAAA,GAAc,cAAA,CAAe,SAAA,EAAW,UAAA,EAAY,MAAM,KAAK,CAAA;AACrE,MAAA,KAAA,CAAM,cAAA,CAAe,IAAI,YAAY,CAAA;AACrC,MAAA,OAAO,CAAA,EAAGA,YAAW,CAAA,IAAA,EAAO,YAAY,CAAA,CAAA;AAAA,IAC1C;AAEA,IAAA,IAAI,KAAA,CAAM,qBAAA,CAAsB,GAAA,CAAI,SAAS,CAAA,EAAG;AAC9C,MAAA,KAAA,CAAM,cAAA,CAAe,IAAI,YAAY,CAAA;AACrC,MAAA,OAAO,MAAA;AAAA,IACT;AAAA,EACF;AAIA,EAAA,IAAI,MAAA,GAAS,SAAA;AAEb,EAAA,IAAI,aAAA,EAAe;AACjB,IAAA,MAAA,GAAS,qBAAqB,YAAY,CAAA,EAAA,CAAA;AAC1C,IAAA,OAAA,CAAQ,IAAA;AAAA,MACN,SAAA,KAAc,cAAA,GACV,CAAA,OAAA,EAAU,MAAM,CAAA,MAAA,EAAS,aAAa,CAAA,CAAA,CAAA,GACtC,CAAA,SAAA,EAAY,SAAS,CAAA,IAAA,EAAO,MAAM,CAAA,QAAA,EAAW,aAAa,CAAA,CAAA;AAAA,KAChE;AAAA,EACF;AAEA,EAAA,MAAM,WAAA,GAAc,oBAAoB,YAAY,CAAA,EAAA,CAAA;AAIpD,EAAA,OAAA,CAAQ,IAAA;AAAA,IACN,CAAA,MAAA,EAAS,WAAW,CAAA,0DAAA,EAA6D,eAAA,CAAgB,IAAI,CAAC,CAAA,EAAA,EAAK,KAAA,CAAM,SAAS,CAAA,EAAA,EAAK,MAAM,CAAA,EAAA;AAAA,GACvI;AACA,EAAA,KAAA,CAAM,cAAA,CAAe,IAAI,YAAY,CAAA;AACrC,EAAA,KAAA,CAAM,WAAA,CAAY,IAAI,YAAY,CAAA;AAClC,EAAA,KAAA,CAAM,WAAA,GAAc,IAAA;AAEpB,EAAA,OAAO,CAAA,EAAG,WAAW,CAAA,IAAA,EAAO,YAAY,CAAA,CAAA;AAC1C;;;;"}
|
|
@@ -8,6 +8,7 @@ import { instrumentEnv } from './instrumentations/worker/instrumentEnv.js';
|
|
|
8
8
|
import { addCloudResourceContext } from './scope-utils.js';
|
|
9
9
|
import { init } from './sdk.js';
|
|
10
10
|
import { instrumentContext } from './utils/instrumentContext.js';
|
|
11
|
+
import { getInvocationState } from './utils/invocationContext.js';
|
|
11
12
|
import { withInvocationIsolationScope } from './utils/invocationScope.js';
|
|
12
13
|
|
|
13
14
|
const UUID_REGEX = /^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$/i;
|
|
@@ -44,6 +45,10 @@ class WrappedWorkflowStep {
|
|
|
44
45
|
const hasStepContext = typeof attempt === "number" && typeof retryLimit === "number";
|
|
45
46
|
const isFinalAttempt = !hasStepContext || attempt > retryLimit;
|
|
46
47
|
return withIsolationScope(this._isolationScope, () => {
|
|
48
|
+
const invocationState = getInvocationState();
|
|
49
|
+
if (invocationState) {
|
|
50
|
+
invocationState.flushPointReached = false;
|
|
51
|
+
}
|
|
47
52
|
const stepResult = startSpan(
|
|
48
53
|
{
|
|
49
54
|
name,
|
|
@@ -77,11 +82,11 @@ class WrappedWorkflowStep {
|
|
|
77
82
|
);
|
|
78
83
|
return stepResult.then(
|
|
79
84
|
(result) => {
|
|
80
|
-
this._waitUntil(flush(2e3));
|
|
85
|
+
this._waitUntil(withScope(scopeForStep, () => flush(2e3)));
|
|
81
86
|
return result;
|
|
82
87
|
},
|
|
83
88
|
(error) => {
|
|
84
|
-
this._waitUntil(flush(2e3));
|
|
89
|
+
this._waitUntil(withScope(scopeForStep, () => flush(2e3)));
|
|
85
90
|
throw error;
|
|
86
91
|
}
|
|
87
92
|
);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflows.js","sources":["../../../src/workflows.ts"],"sourcesContent":["import { SENTRY_SEGMENT_NAME_SOURCE, CODE_FUNCTION_NAME, SENTRY_OP } from '@sentry/conventions/attributes';\nimport { FUNCTION } from '@sentry/conventions/op';\nimport type { PropagationContext, Scope } from '@sentry/core';\nimport {\n captureException,\n flush,\n getCurrentScope,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n startSpan,\n withIsolationScope,\n withScope,\n} from '@sentry/core';\nimport type {\n WorkflowDelayDuration,\n WorkflowEntrypoint,\n WorkflowEvent,\n WorkflowSleepDuration,\n WorkflowStep,\n WorkflowStepConfig,\n WorkflowStepContext,\n WorkflowStepEvent,\n WorkflowStepRollbackOptions,\n WorkflowTimeoutDuration,\n} from 'cloudflare:workers';\nimport { setAsyncLocalStorageAsyncContextStrategy } from '@sentry/server-utils/no-diagnostic-channels';\nimport type { CloudflareOptions } from './client';\nimport { flushAndDispose, getOriginalWaitUntil } from './flush';\nimport { markAsInstrumented } from './instrument';\nimport { instrumentEnv } from './instrumentations/worker/instrumentEnv';\nimport { addCloudResourceContext } from './scope-utils';\nimport { init } from './sdk';\nimport { instrumentContext } from './utils/instrumentContext';\nimport type { DefaultEnv, ResolveEnv, StrictCloudflareOptions } from './types';\nimport { withInvocationIsolationScope } from './utils/invocationScope';\n\nconst UUID_REGEX = /^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$/i;\n\n/**\n * Hashes a string to a UUID using SHA-1.\n */\nexport async function deterministicTraceIdFromInstanceId(instanceId: string): Promise<string> {\n const buf = await crypto.subtle.digest('SHA-1', new TextEncoder().encode(instanceId));\n return (\n Array.from(new Uint8Array(buf))\n // We only need the first 16 bytes for the 32 characters\n .slice(0, 16)\n .map(b => b.toString(16).padStart(2, '0'))\n .join('')\n );\n}\n\nasync function propagationContextFromInstanceId(instanceId: string): Promise<PropagationContext> {\n const traceId = UUID_REGEX.test(instanceId)\n ? instanceId.replace(/-/g, '')\n : await deterministicTraceIdFromInstanceId(instanceId);\n\n // Derive sampleRand from last 4 characters of the random UUID\n //\n // We cannot store any state between workflow steps, so we derive the\n // sampleRand from the traceId itself. This ensures that the sampling is\n // consistent across all steps in the same workflow instance.\n const sampleRand = parseInt(traceId.slice(-4), 16) / 0xffff;\n\n return {\n traceId,\n sampleRand,\n };\n}\n\nclass WrappedWorkflowStep implements WorkflowStep {\n public constructor(\n private _instanceId: string,\n private _options: CloudflareOptions,\n private _step: WorkflowStep,\n private _waitUntil: ExecutionContext['waitUntil'],\n private _isolationScope: Scope,\n ) {}\n\n public async do<T extends Rpc.Serializable<T>>(\n name: string,\n callback: (ctx: WorkflowStepContext) => Promise<T>,\n rollbackOptions?: WorkflowStepRollbackOptions<T>,\n ): Promise<T>;\n public async do<T extends Rpc.Serializable<T>, const C extends WorkflowStepConfig>(\n name: string,\n config: C,\n callback: (\n ctx: WorkflowStepContext<C['retries'] extends { delay: infer D } ? D : WorkflowDelayDuration | number>,\n ) => Promise<T>,\n rollbackOptions?: WorkflowStepRollbackOptions<T>,\n ): Promise<T>;\n public async do<T extends Rpc.Serializable<T>>(\n name: string,\n configOrCallback: WorkflowStepConfig | ((ctx: WorkflowStepContext) => Promise<T>),\n callbackOrRollback?: ((ctx: WorkflowStepContext) => Promise<T>) | WorkflowStepRollbackOptions<T>,\n maybeRollback?: WorkflowStepRollbackOptions<T>,\n ): Promise<T> {\n // Capture the current scope, so parent span (e.g., a startSpan surrounding step.do) is preserved\n const scopeForStep = getCurrentScope();\n\n const hasConfig = typeof configOrCallback !== 'function';\n const config = hasConfig ? configOrCallback : undefined;\n const userCallback = (hasConfig ? callbackOrRollback : configOrCallback) as (\n ctx: WorkflowStepContext,\n ) => Promise<T>;\n const rollbackOptions = (hasConfig ? maybeRollback : callbackOrRollback) as\n | WorkflowStepRollbackOptions<T>\n | undefined;\n\n const instrumentedCallback = async (...args: unknown[]): Promise<T> => {\n // Feature detection: Cloudflare Workflows (April 2026+) pass a step context\n // with `attempt` and `config.retries.limit`. When available, we only capture\n // errors on the final attempt to avoid duplicates during retries.\n const stepContext = args[0] as { attempt?: number; config?: { retries?: { limit?: number } } } | undefined;\n const attempt = stepContext?.attempt;\n const retryLimit = stepContext?.config?.retries?.limit;\n const hasStepContext = typeof attempt === 'number' && typeof retryLimit === 'number';\n\n // Only capture error on final attempt (attempt > retryLimit means no more retries left)\n // or when step context is unavailable (legacy behavior - capture all errors)\n const isFinalAttempt = !hasStepContext || attempt > retryLimit;\n\n // The engine invokes step callbacks outside the async context of `run`, so the\n // run's isolation scope (and with it the invocation state that ties eager sends\n // to this invocation's `waitUntil`) has to be restored explicitly.\n return withIsolationScope(this._isolationScope, () => {\n const stepResult = startSpan(\n {\n name,\n scope: scopeForStep,\n attributes: {\n [SENTRY_OP]: FUNCTION,\n [CODE_FUNCTION_NAME]: name,\n 'workflow.step.name': name,\n 'cloudflare.workflow.timeout': config?.timeout,\n 'cloudflare.workflow.retries.backoff': config?.retries?.backoff,\n // In workers-types v5, `delay` may be a `WorkflowDelayFunction`, which isn't a valid span attribute value.\n 'cloudflare.workflow.retries.delay':\n typeof config?.retries?.delay === 'function' ? undefined : config?.retries?.delay,\n 'cloudflare.workflow.retries.limit': config?.retries?.limit,\n 'cloudflare.workflow.attempt': attempt,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.faas.cloudflare.workflow',\n [SENTRY_SEGMENT_NAME_SOURCE]: 'task',\n },\n },\n async span => {\n try {\n const result = await (userCallback as (...args: unknown[]) => Promise<T>)(...args);\n span.setStatus({ code: 1 });\n return result;\n } catch (error) {\n if (isFinalAttempt) {\n captureException(error, { mechanism: { handled: true, type: 'auto.faas.cloudflare.workflow' } });\n }\n throw error;\n }\n },\n );\n // Deliver after the step span has ended, so the span rides this flush instead of\n // starting an eager drain (same ordering as `wrapMethodWithSentry`'s teardown).\n return stepResult.then(\n result => {\n this._waitUntil(flush(2000));\n return result;\n },\n error => {\n this._waitUntil(flush(2000));\n throw error;\n },\n );\n });\n };\n\n if (config) {\n return rollbackOptions\n ? this._step.do(name, config, instrumentedCallback, rollbackOptions)\n : this._step.do(name, config, instrumentedCallback);\n }\n\n return rollbackOptions\n ? this._step.do(name, instrumentedCallback, rollbackOptions)\n : this._step.do(name, instrumentedCallback);\n }\n\n public async sleep(name: string, duration: WorkflowSleepDuration): Promise<void> {\n return this._step.sleep(name, duration);\n }\n\n public async sleepUntil(name: string, timestamp: Date | number): Promise<void> {\n return this._step.sleepUntil(name, timestamp);\n }\n\n public async waitForEvent<T extends Rpc.Serializable<T>>(\n name: string,\n options: { type: string; timeout?: WorkflowTimeoutDuration | number },\n ): Promise<WorkflowStepEvent<T>> {\n return this._step.waitForEvent<T>(name, options);\n }\n}\n\n/**\n * Instruments a Cloudflare Workflow class with Sentry.\n *\n * @example\n * ```typescript\n * const InstrumentedWorkflow = instrumentWorkflowWithSentry(\n * (env) => ({ dsn: env.SENTRY_DSN }),\n * MyWorkflowClass\n * );\n *\n * export default InstrumentedWorkflow;\n * ```\n *\n * @param optionsCallback - Function that returns Sentry options to initialize Sentry\n * @param WorkflowClass - The workflow class to instrument\n * @returns Instrumented workflow class with the same interface\n */\nexport function instrumentWorkflowWithSentry<\n E = DefaultEnv, // Environment type\n P = unknown, // Payload type\n // oxlint-disable-next-line typescript/no-explicit-any\n T extends WorkflowEntrypoint<any, any> = WorkflowEntrypoint<E, P>, // WorkflowEntrypoint type\n // The constraint must not route through `T`: workers-types defaults `WorkflowEntrypoint`'s\n // `Env` to `unknown` (unlike `WorkerEntrypoint`/`DurableObject`, which default to\n // `Cloudflare.Env`), so a bare subclass would be rejected in a `wrangler types` project.\n // The callback env is resolved from the inferred constructor via `ResolveEnv` instead.\n // oxlint-disable-next-line typescript/no-explicit-any\n C extends new (ctx: ExecutionContext, env: any) => WorkflowEntrypoint<any, any> = new (\n ctx: ExecutionContext,\n // oxlint-disable-next-line typescript/no-explicit-any\n env: any,\n ) => T, // Constructor type of the WorkflowEntrypoint class\n O = unknown,\n>(optionsCallback: (env: ResolveEnv<C, E>) => StrictCloudflareOptions<O>, WorkFlowClass: C): C {\n const InstrumentedClass = new Proxy(WorkFlowClass, {\n // oxlint-disable-next-line typescript/no-explicit-any\n construct(target: C, args: [ctx: ExecutionContext, env: any], newTarget) {\n const [ctx, env] = args;\n const context = instrumentContext(ctx);\n const options = optionsCallback(env);\n args[0] = context;\n args[1] = instrumentEnv(env as Record<string, unknown>, options) as E;\n const instance = Reflect.construct(target, args, newTarget) as T;\n return new Proxy(instance, {\n get(obj, prop, receiver) {\n if (prop === 'run') {\n return async function (event: WorkflowEvent<P>, step: WorkflowStep): Promise<unknown> {\n setAsyncLocalStorageAsyncContextStrategy();\n\n return withInvocationIsolationScope(async isolationScope => {\n const waitUntil = getOriginalWaitUntil(context).bind(context);\n const client = init({ ...options, ctx: context, enableDedupe: false });\n isolationScope.setClient(client);\n\n addCloudResourceContext(isolationScope);\n\n return withScope(async scope => {\n const propagationContext = await propagationContextFromInstanceId(event.instanceId);\n scope.setPropagationContext(propagationContext);\n\n try {\n return await obj.run.call(\n obj,\n event,\n new WrappedWorkflowStep(event.instanceId, options, step, waitUntil, isolationScope),\n );\n } finally {\n waitUntil(flushAndDispose(client));\n }\n });\n }, context);\n };\n }\n return Reflect.get(obj, prop, receiver);\n },\n });\n },\n });\n // Recognizable for `_INTERNAL_wrapUnlessInstrumented`, so auto-instrumentation never nests wrappers.\n markAsInstrumented(InstrumentedClass);\n return InstrumentedClass;\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"workflows.js","sources":["../../../src/workflows.ts"],"sourcesContent":["import { SENTRY_SEGMENT_NAME_SOURCE, CODE_FUNCTION_NAME, SENTRY_OP } from '@sentry/conventions/attributes';\nimport { FUNCTION } from '@sentry/conventions/op';\nimport type { PropagationContext, Scope } from '@sentry/core';\nimport {\n captureException,\n flush,\n getCurrentScope,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n startSpan,\n withIsolationScope,\n withScope,\n} from '@sentry/core';\nimport type {\n WorkflowDelayDuration,\n WorkflowEntrypoint,\n WorkflowEvent,\n WorkflowSleepDuration,\n WorkflowStep,\n WorkflowStepConfig,\n WorkflowStepContext,\n WorkflowStepEvent,\n WorkflowStepRollbackOptions,\n WorkflowTimeoutDuration,\n} from 'cloudflare:workers';\nimport { setAsyncLocalStorageAsyncContextStrategy } from '@sentry/server-utils/no-diagnostic-channels';\nimport type { CloudflareOptions } from './client';\nimport { flushAndDispose, getOriginalWaitUntil } from './flush';\nimport { markAsInstrumented } from './instrument';\nimport { instrumentEnv } from './instrumentations/worker/instrumentEnv';\nimport { addCloudResourceContext } from './scope-utils';\nimport { init } from './sdk';\nimport { instrumentContext } from './utils/instrumentContext';\nimport type { DefaultEnv, ResolveEnv, StrictCloudflareOptions } from './types';\nimport { getInvocationState } from './utils/invocationContext';\nimport { withInvocationIsolationScope } from './utils/invocationScope';\n\nconst UUID_REGEX = /^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$/i;\n\n/**\n * Hashes a string to a UUID using SHA-1.\n */\nexport async function deterministicTraceIdFromInstanceId(instanceId: string): Promise<string> {\n const buf = await crypto.subtle.digest('SHA-1', new TextEncoder().encode(instanceId));\n return (\n Array.from(new Uint8Array(buf))\n // We only need the first 16 bytes for the 32 characters\n .slice(0, 16)\n .map(b => b.toString(16).padStart(2, '0'))\n .join('')\n );\n}\n\nasync function propagationContextFromInstanceId(instanceId: string): Promise<PropagationContext> {\n const traceId = UUID_REGEX.test(instanceId)\n ? instanceId.replace(/-/g, '')\n : await deterministicTraceIdFromInstanceId(instanceId);\n\n // Derive sampleRand from last 4 characters of the random UUID\n //\n // We cannot store any state between workflow steps, so we derive the\n // sampleRand from the traceId itself. This ensures that the sampling is\n // consistent across all steps in the same workflow instance.\n const sampleRand = parseInt(traceId.slice(-4), 16) / 0xffff;\n\n return {\n traceId,\n sampleRand,\n };\n}\n\nclass WrappedWorkflowStep implements WorkflowStep {\n public constructor(\n private _instanceId: string,\n private _options: CloudflareOptions,\n private _step: WorkflowStep,\n private _waitUntil: ExecutionContext['waitUntil'],\n private _isolationScope: Scope,\n ) {}\n\n public async do<T extends Rpc.Serializable<T>>(\n name: string,\n callback: (ctx: WorkflowStepContext) => Promise<T>,\n rollbackOptions?: WorkflowStepRollbackOptions<T>,\n ): Promise<T>;\n public async do<T extends Rpc.Serializable<T>, const C extends WorkflowStepConfig>(\n name: string,\n config: C,\n callback: (\n ctx: WorkflowStepContext<C['retries'] extends { delay: infer D } ? D : WorkflowDelayDuration | number>,\n ) => Promise<T>,\n rollbackOptions?: WorkflowStepRollbackOptions<T>,\n ): Promise<T>;\n public async do<T extends Rpc.Serializable<T>>(\n name: string,\n configOrCallback: WorkflowStepConfig | ((ctx: WorkflowStepContext) => Promise<T>),\n callbackOrRollback?: ((ctx: WorkflowStepContext) => Promise<T>) | WorkflowStepRollbackOptions<T>,\n maybeRollback?: WorkflowStepRollbackOptions<T>,\n ): Promise<T> {\n // Capture the current scope, so parent span (e.g., a startSpan surrounding step.do) is preserved\n const scopeForStep = getCurrentScope();\n\n const hasConfig = typeof configOrCallback !== 'function';\n const config = hasConfig ? configOrCallback : undefined;\n const userCallback = (hasConfig ? callbackOrRollback : configOrCallback) as (\n ctx: WorkflowStepContext,\n ) => Promise<T>;\n const rollbackOptions = (hasConfig ? maybeRollback : callbackOrRollback) as\n | WorkflowStepRollbackOptions<T>\n | undefined;\n\n const instrumentedCallback = async (...args: unknown[]): Promise<T> => {\n // Feature detection: Cloudflare Workflows (April 2026+) pass a step context\n // with `attempt` and `config.retries.limit`. When available, we only capture\n // errors on the final attempt to avoid duplicates during retries.\n const stepContext = args[0] as { attempt?: number; config?: { retries?: { limit?: number } } } | undefined;\n const attempt = stepContext?.attempt;\n const retryLimit = stepContext?.config?.retries?.limit;\n const hasStepContext = typeof attempt === 'number' && typeof retryLimit === 'number';\n\n // Only capture error on final attempt (attempt > retryLimit means no more retries left)\n // or when step context is unavailable (legacy behavior - capture all errors)\n const isFinalAttempt = !hasStepContext || attempt > retryLimit;\n\n // The engine invokes step callbacks outside the async context of `run`, so the\n // run's isolation scope (and with it the invocation state that ties eager sends\n // to this invocation's `waitUntil`) has to be restored explicitly.\n return withIsolationScope(this._isolationScope, () => {\n const invocationState = getInvocationState();\n\n if (invocationState) {\n invocationState.flushPointReached = false;\n }\n\n const stepResult = startSpan(\n {\n name,\n scope: scopeForStep,\n attributes: {\n [SENTRY_OP]: FUNCTION,\n [CODE_FUNCTION_NAME]: name,\n 'workflow.step.name': name,\n 'cloudflare.workflow.timeout': config?.timeout,\n 'cloudflare.workflow.retries.backoff': config?.retries?.backoff,\n // In workers-types v5, `delay` may be a `WorkflowDelayFunction`, which isn't a valid span attribute value.\n 'cloudflare.workflow.retries.delay':\n typeof config?.retries?.delay === 'function' ? undefined : config?.retries?.delay,\n 'cloudflare.workflow.retries.limit': config?.retries?.limit,\n 'cloudflare.workflow.attempt': attempt,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.faas.cloudflare.workflow',\n [SENTRY_SEGMENT_NAME_SOURCE]: 'task',\n },\n },\n async span => {\n try {\n const result = await (userCallback as (...args: unknown[]) => Promise<T>)(...args);\n span.setStatus({ code: 1 });\n return result;\n } catch (error) {\n if (isFinalAttempt) {\n captureException(error, { mechanism: { handled: true, type: 'auto.faas.cloudflare.workflow' } });\n }\n throw error;\n }\n },\n );\n // Deliver after the step span has ended, so the span rides this flush instead of\n // starting an eager drain (same ordering as `wrapMethodWithSentry`'s teardown). The flush runs on the\n // step's scope: the engine calls the step callback outside of `run()`, so the current scope here has\n // neither the client nor the run's trace, and envelopes without a DSC are dropped by Relay.\n return stepResult.then(\n result => {\n this._waitUntil(withScope(scopeForStep, () => flush(2000)));\n return result;\n },\n error => {\n this._waitUntil(withScope(scopeForStep, () => flush(2000)));\n throw error;\n },\n );\n });\n };\n\n if (config) {\n return rollbackOptions\n ? this._step.do(name, config, instrumentedCallback, rollbackOptions)\n : this._step.do(name, config, instrumentedCallback);\n }\n\n return rollbackOptions\n ? this._step.do(name, instrumentedCallback, rollbackOptions)\n : this._step.do(name, instrumentedCallback);\n }\n\n public async sleep(name: string, duration: WorkflowSleepDuration): Promise<void> {\n return this._step.sleep(name, duration);\n }\n\n public async sleepUntil(name: string, timestamp: Date | number): Promise<void> {\n return this._step.sleepUntil(name, timestamp);\n }\n\n public async waitForEvent<T extends Rpc.Serializable<T>>(\n name: string,\n options: { type: string; timeout?: WorkflowTimeoutDuration | number },\n ): Promise<WorkflowStepEvent<T>> {\n return this._step.waitForEvent<T>(name, options);\n }\n}\n\n/**\n * Instruments a Cloudflare Workflow class with Sentry.\n *\n * @example\n * ```typescript\n * const InstrumentedWorkflow = instrumentWorkflowWithSentry(\n * (env) => ({ dsn: env.SENTRY_DSN }),\n * MyWorkflowClass\n * );\n *\n * export default InstrumentedWorkflow;\n * ```\n *\n * @param optionsCallback - Function that returns Sentry options to initialize Sentry\n * @param WorkflowClass - The workflow class to instrument\n * @returns Instrumented workflow class with the same interface\n */\nexport function instrumentWorkflowWithSentry<\n E = DefaultEnv, // Environment type\n P = unknown, // Payload type\n // oxlint-disable-next-line typescript/no-explicit-any\n T extends WorkflowEntrypoint<any, any> = WorkflowEntrypoint<E, P>, // WorkflowEntrypoint type\n // The constraint must not route through `T`: workers-types defaults `WorkflowEntrypoint`'s\n // `Env` to `unknown` (unlike `WorkerEntrypoint`/`DurableObject`, which default to\n // `Cloudflare.Env`), so a bare subclass would be rejected in a `wrangler types` project.\n // The callback env is resolved from the inferred constructor via `ResolveEnv` instead.\n // oxlint-disable-next-line typescript/no-explicit-any\n C extends new (ctx: ExecutionContext, env: any) => WorkflowEntrypoint<any, any> = new (\n ctx: ExecutionContext,\n // oxlint-disable-next-line typescript/no-explicit-any\n env: any,\n ) => T, // Constructor type of the WorkflowEntrypoint class\n O = unknown,\n>(optionsCallback: (env: ResolveEnv<C, E>) => StrictCloudflareOptions<O>, WorkFlowClass: C): C {\n const InstrumentedClass = new Proxy(WorkFlowClass, {\n // oxlint-disable-next-line typescript/no-explicit-any\n construct(target: C, args: [ctx: ExecutionContext, env: any], newTarget) {\n const [ctx, env] = args;\n const context = instrumentContext(ctx);\n const options = optionsCallback(env);\n args[0] = context;\n args[1] = instrumentEnv(env as Record<string, unknown>, options) as E;\n const instance = Reflect.construct(target, args, newTarget) as T;\n return new Proxy(instance, {\n get(obj, prop, receiver) {\n if (prop === 'run') {\n return async function (event: WorkflowEvent<P>, step: WorkflowStep): Promise<unknown> {\n setAsyncLocalStorageAsyncContextStrategy();\n\n return withInvocationIsolationScope(async isolationScope => {\n const waitUntil = getOriginalWaitUntil(context).bind(context);\n const client = init({ ...options, ctx: context, enableDedupe: false });\n isolationScope.setClient(client);\n\n addCloudResourceContext(isolationScope);\n\n return withScope(async scope => {\n const propagationContext = await propagationContextFromInstanceId(event.instanceId);\n scope.setPropagationContext(propagationContext);\n\n try {\n return await obj.run.call(\n obj,\n event,\n new WrappedWorkflowStep(event.instanceId, options, step, waitUntil, isolationScope),\n );\n } finally {\n waitUntil(flushAndDispose(client));\n }\n });\n }, context);\n };\n }\n return Reflect.get(obj, prop, receiver);\n },\n });\n },\n });\n // Recognizable for `_INTERNAL_wrapUnlessInstrumented`, so auto-instrumentation never nests wrappers.\n markAsInstrumented(InstrumentedClass);\n return InstrumentedClass;\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;AAoCA,MAAM,UAAA,GAAa,qEAAA;AAKnB,eAAsB,mCAAmC,UAAA,EAAqC;AAC5F,EAAA,MAAM,GAAA,GAAM,MAAM,MAAA,CAAO,MAAA,CAAO,MAAA,CAAO,OAAA,EAAS,IAAI,WAAA,EAAY,CAAE,MAAA,CAAO,UAAU,CAAC,CAAA;AACpF,EAAA,OACE,KAAA,CAAM,KAAK,IAAI,UAAA,CAAW,GAAG,CAAC,CAAA,CAE3B,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA,CACX,IAAI,CAAA,CAAA,KAAK,CAAA,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,QAAA,CAAS,GAAG,GAAG,CAAC,CAAA,CACxC,IAAA,CAAK,EAAE,CAAA;AAEd;AAEA,eAAe,iCAAiC,UAAA,EAAiD;AAC/F,EAAA,MAAM,OAAA,GAAU,UAAA,CAAW,IAAA,CAAK,UAAU,CAAA,GACtC,UAAA,CAAW,OAAA,CAAQ,IAAA,EAAM,EAAE,CAAA,GAC3B,MAAM,kCAAA,CAAmC,UAAU,CAAA;AAOvD,EAAA,MAAM,aAAa,QAAA,CAAS,OAAA,CAAQ,MAAM,EAAE,CAAA,EAAG,EAAE,CAAA,GAAI,KAAA;AAErD,EAAA,OAAO;AAAA,IACL,OAAA;AAAA,IACA;AAAA,GACF;AACF;AAEA,MAAM,mBAAA,CAA4C;AAAA,EACzC,WAAA,CACG,WAAA,EACA,QAAA,EACA,KAAA,EACA,YACA,eAAA,EACR;AALQ,IAAA,IAAA,CAAA,WAAA,GAAA,WAAA;AACA,IAAA,IAAA,CAAA,QAAA,GAAA,QAAA;AACA,IAAA,IAAA,CAAA,KAAA,GAAA,KAAA;AACA,IAAA,IAAA,CAAA,UAAA,GAAA,UAAA;AACA,IAAA,IAAA,CAAA,eAAA,GAAA,eAAA;AAAA,EACP;AAAA,EAeH,MAAa,EAAA,CACX,IAAA,EACA,gBAAA,EACA,oBACA,aAAA,EACY;AAEZ,IAAA,MAAM,eAAe,eAAA,EAAgB;AAErC,IAAA,MAAM,SAAA,GAAY,OAAO,gBAAA,KAAqB,UAAA;AAC9C,IAAA,MAAM,MAAA,GAAS,YAAY,gBAAA,GAAmB,MAAA;AAC9C,IAAA,MAAM,YAAA,GAAgB,YAAY,kBAAA,GAAqB,gBAAA;AAGvD,IAAA,MAAM,eAAA,GAAmB,YAAY,aAAA,GAAgB,kBAAA;AAIrD,IAAA,MAAM,oBAAA,GAAuB,UAAU,IAAA,KAAgC;AAIrE,MAAA,MAAM,WAAA,GAAc,KAAK,CAAC,CAAA;AAC1B,MAAA,MAAM,UAAU,WAAA,EAAa,OAAA;AAC7B,MAAA,MAAM,UAAA,GAAa,WAAA,EAAa,MAAA,EAAQ,OAAA,EAAS,KAAA;AACjD,MAAA,MAAM,cAAA,GAAiB,OAAO,OAAA,KAAY,QAAA,IAAY,OAAO,UAAA,KAAe,QAAA;AAI5E,MAAA,MAAM,cAAA,GAAiB,CAAC,cAAA,IAAkB,OAAA,GAAU,UAAA;AAKpD,MAAA,OAAO,kBAAA,CAAmB,IAAA,CAAK,eAAA,EAAiB,MAAM;AACpD,QAAA,MAAM,kBAAkB,kBAAA,EAAmB;AAE3C,QAAA,IAAI,eAAA,EAAiB;AACnB,UAAA,eAAA,CAAgB,iBAAA,GAAoB,KAAA;AAAA,QACtC;AAEA,QAAA,MAAM,UAAA,GAAa,SAAA;AAAA,UACjB;AAAA,YACE,IAAA;AAAA,YACA,KAAA,EAAO,YAAA;AAAA,YACP,UAAA,EAAY;AAAA,cACV,CAAC,SAAS,GAAG,QAAA;AAAA,cACb,CAAC,kBAAkB,GAAG,IAAA;AAAA,cACtB,oBAAA,EAAsB,IAAA;AAAA,cACtB,+BAA+B,MAAA,EAAQ,OAAA;AAAA,cACvC,qCAAA,EAAuC,QAAQ,OAAA,EAAS,OAAA;AAAA;AAAA,cAExD,mCAAA,EACE,OAAO,MAAA,EAAQ,OAAA,EAAS,UAAU,UAAA,GAAa,MAAA,GAAY,QAAQ,OAAA,EAAS,KAAA;AAAA,cAC9E,mCAAA,EAAqC,QAAQ,OAAA,EAAS,KAAA;AAAA,cACtD,6BAAA,EAA+B,OAAA;AAAA,cAC/B,CAAC,gCAAgC,GAAG,+BAAA;AAAA,cACpC,CAAC,0BAA0B,GAAG;AAAA;AAChC,WACF;AAAA,UACA,OAAM,IAAA,KAAQ;AACZ,YAAA,IAAI;AACF,cAAA,MAAM,MAAA,GAAS,MAAO,YAAA,CAAoD,GAAG,IAAI,CAAA;AACjF,cAAA,IAAA,CAAK,SAAA,CAAU,EAAE,IAAA,EAAM,CAAA,EAAG,CAAA;AAC1B,cAAA,OAAO,MAAA;AAAA,YACT,SAAS,KAAA,EAAO;AACd,cAAA,IAAI,cAAA,EAAgB;AAClB,gBAAA,gBAAA,CAAiB,KAAA,EAAO,EAAE,SAAA,EAAW,EAAE,SAAS,IAAA,EAAM,IAAA,EAAM,+BAAA,EAAgC,EAAG,CAAA;AAAA,cACjG;AACA,cAAA,MAAM,KAAA;AAAA,YACR;AAAA,UACF;AAAA,SACF;AAKA,QAAA,OAAO,UAAA,CAAW,IAAA;AAAA,UAChB,CAAA,MAAA,KAAU;AACR,YAAA,IAAA,CAAK,WAAW,SAAA,CAAU,YAAA,EAAc,MAAM,KAAA,CAAM,GAAI,CAAC,CAAC,CAAA;AAC1D,YAAA,OAAO,MAAA;AAAA,UACT,CAAA;AAAA,UACA,CAAA,KAAA,KAAS;AACP,YAAA,IAAA,CAAK,WAAW,SAAA,CAAU,YAAA,EAAc,MAAM,KAAA,CAAM,GAAI,CAAC,CAAC,CAAA;AAC1D,YAAA,MAAM,KAAA;AAAA,UACR;AAAA,SACF;AAAA,MACF,CAAC,CAAA;AAAA,IACH,CAAA;AAEA,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,OAAO,eAAA,GACH,IAAA,CAAK,KAAA,CAAM,EAAA,CAAG,MAAM,MAAA,EAAQ,oBAAA,EAAsB,eAAe,CAAA,GACjE,IAAA,CAAK,KAAA,CAAM,EAAA,CAAG,IAAA,EAAM,QAAQ,oBAAoB,CAAA;AAAA,IACtD;AAEA,IAAA,OAAO,eAAA,GACH,IAAA,CAAK,KAAA,CAAM,EAAA,CAAG,IAAA,EAAM,oBAAA,EAAsB,eAAe,CAAA,GACzD,IAAA,CAAK,KAAA,CAAM,EAAA,CAAG,IAAA,EAAM,oBAAoB,CAAA;AAAA,EAC9C;AAAA,EAEA,MAAa,KAAA,CAAM,IAAA,EAAc,QAAA,EAAgD;AAC/E,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,KAAA,CAAM,IAAA,EAAM,QAAQ,CAAA;AAAA,EACxC;AAAA,EAEA,MAAa,UAAA,CAAW,IAAA,EAAc,SAAA,EAAyC;AAC7E,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,UAAA,CAAW,IAAA,EAAM,SAAS,CAAA;AAAA,EAC9C;AAAA,EAEA,MAAa,YAAA,CACX,IAAA,EACA,OAAA,EAC+B;AAC/B,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,YAAA,CAAgB,IAAA,EAAM,OAAO,CAAA;AAAA,EACjD;AACF;AAmBO,SAAS,4BAAA,CAgBd,iBAAwE,aAAA,EAAqB;AAC7F,EAAA,MAAM,iBAAA,GAAoB,IAAI,KAAA,CAAM,aAAA,EAAe;AAAA;AAAA,IAEjD,SAAA,CAAU,MAAA,EAAW,IAAA,EAAyC,SAAA,EAAW;AACvE,MAAA,MAAM,CAAC,GAAA,EAAK,GAAG,CAAA,GAAI,IAAA;AACnB,MAAA,MAAM,OAAA,GAAU,kBAAkB,GAAG,CAAA;AACrC,MAAA,MAAM,OAAA,GAAU,gBAAgB,GAAG,CAAA;AACnC,MAAA,IAAA,CAAK,CAAC,CAAA,GAAI,OAAA;AACV,MAAA,IAAA,CAAK,CAAC,CAAA,GAAI,aAAA,CAAc,GAAA,EAAgC,OAAO,CAAA;AAC/D,MAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,SAAA,CAAU,MAAA,EAAQ,MAAM,SAAS,CAAA;AAC1D,MAAA,OAAO,IAAI,MAAM,QAAA,EAAU;AAAA,QACzB,GAAA,CAAI,GAAA,EAAK,IAAA,EAAM,QAAA,EAAU;AACvB,UAAA,IAAI,SAAS,KAAA,EAAO;AAClB,YAAA,OAAO,eAAgB,OAAyB,IAAA,EAAsC;AACpF,cAAA,wCAAA,EAAyC;AAEzC,cAAA,OAAO,4BAAA,CAA6B,OAAM,cAAA,KAAkB;AAC1D,gBAAA,MAAM,SAAA,GAAY,oBAAA,CAAqB,OAAO,CAAA,CAAE,KAAK,OAAO,CAAA;AAC5D,gBAAA,MAAM,MAAA,GAAS,KAAK,EAAE,GAAG,SAAS,GAAA,EAAK,OAAA,EAAS,YAAA,EAAc,KAAA,EAAO,CAAA;AACrE,gBAAA,cAAA,CAAe,UAAU,MAAM,CAAA;AAE/B,gBAAA,uBAAA,CAAwB,cAAc,CAAA;AAEtC,gBAAA,OAAO,SAAA,CAAU,OAAM,KAAA,KAAS;AAC9B,kBAAA,MAAM,kBAAA,GAAqB,MAAM,gCAAA,CAAiC,KAAA,CAAM,UAAU,CAAA;AAClF,kBAAA,KAAA,CAAM,sBAAsB,kBAAkB,CAAA;AAE9C,kBAAA,IAAI;AACF,oBAAA,OAAO,MAAM,IAAI,GAAA,CAAI,IAAA;AAAA,sBACnB,GAAA;AAAA,sBACA,KAAA;AAAA,sBACA,IAAI,mBAAA,CAAoB,KAAA,CAAM,YAAY,OAAA,EAAS,IAAA,EAAM,WAAW,cAAc;AAAA,qBACpF;AAAA,kBACF,CAAA,SAAE;AACA,oBAAA,SAAA,CAAU,eAAA,CAAgB,MAAM,CAAC,CAAA;AAAA,kBACnC;AAAA,gBACF,CAAC,CAAA;AAAA,cACH,GAAG,OAAO,CAAA;AAAA,YACZ,CAAA;AAAA,UACF;AACA,UAAA,OAAO,OAAA,CAAQ,GAAA,CAAI,GAAA,EAAK,IAAA,EAAM,QAAQ,CAAA;AAAA,QACxC;AAAA,OACD,CAAA;AAAA,IACH;AAAA,GACD,CAAA;AAED,EAAA,kBAAA,CAAmB,iBAAiB,CAAA;AACpC,EAAA,OAAO,iBAAA;AACT;;;;"}
|
package/build/esm/prod/client.js
CHANGED
|
@@ -59,16 +59,23 @@ class CloudflareClient extends ServerRuntimeClient {
|
|
|
59
59
|
}
|
|
60
60
|
/**
|
|
61
61
|
* Flushes pending operations and ensures all data is processed.
|
|
62
|
-
* If a timeout is provided, the operation will be completed within the specified time limit.
|
|
63
62
|
*
|
|
64
|
-
*
|
|
63
|
+
* Each phase waits at most `timeout`: the flush lock of a per-invocation client, pending spans, event
|
|
64
|
+
* processing and the transport drain. So a flush can take a small multiple of `timeout`, which stays well
|
|
65
|
+
* below Cloudflare's 30 second `waitUntil` limit for the timeouts the SDK uses. Sends still pending when
|
|
66
|
+
* the drain times out are aborted.
|
|
65
67
|
*
|
|
66
|
-
* @param {number} [timeout] -
|
|
68
|
+
* @param {number} [timeout] - Maximum time in milliseconds for each phase of the flush.
|
|
67
69
|
* @return {Promise<boolean>} A promise that resolves to a boolean indicating whether the flush operation was successful.
|
|
68
70
|
*/
|
|
69
71
|
async flush(timeout) {
|
|
70
72
|
if (this._flushLock) {
|
|
71
|
-
|
|
73
|
+
let timer;
|
|
74
|
+
await Promise.race([
|
|
75
|
+
this._flushLock.finalize(),
|
|
76
|
+
...timeout ? [new Promise((resolve) => timer = setTimeout(resolve, timeout))] : []
|
|
77
|
+
]);
|
|
78
|
+
clearTimeout(timer);
|
|
72
79
|
}
|
|
73
80
|
if (this._pendingSpans.size > 0 && this._spanCompletionPromise) {
|
|
74
81
|
DEBUG_BUILD && debug.log("[CloudflareClient] Waiting for", this._pendingSpans.size, "pending spans to complete...");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sources":["../../../src/client.ts"],"sourcesContent":["import type { ClientOptions, Options, TracePropagationTargets } from '@sentry/core';\nimport {\n _INTERNAL_clearAiProviderSkips,\n _INTERNAL_flushLogsBuffer,\n _INTERNAL_flushMetricsBuffer,\n applySdkMetadata,\n debug,\n spanIsSampled,\n} from '@sentry/core';\nimport type { ServerRuntimeClientOptions } from '@sentry/core/server';\nimport { ServerRuntimeClient } from '@sentry/core/server';\nimport { DEBUG_BUILD } from './debug-build';\nimport type { ExecutionContextCompat } from './executionContext';\nimport type { makeFlushLock } from './flush';\nimport type { CloudflareTransportOptions } from './transport';\nimport { getInvocationState, getInvocationWaitUntil } from './utils/invocationContext';\n\n/**\n * The Sentry Cloudflare SDK Client.\n *\n * @see CloudflareClientOptions for documentation on configuration options.\n * @see ServerRuntimeClient for usage documentation.\n */\nexport class CloudflareClient extends ServerRuntimeClient {\n private readonly _flushLock: ReturnType<typeof makeFlushLock> | void;\n private _pendingSpans: Set<string> = new Set();\n private _spanCompletionPromise: Promise<void> | null = null;\n private _resolveSpanCompletion: (() => void) | null = null;\n\n private _unsubscribeSpanStart: (() => void) | null = null;\n private _unsubscribeSpanEnd: (() => void) | null = null;\n\n // True while a boundary `flush()` is draining; envelopes created by that drain ride it\n // and must not each start their own eager transport flush.\n private _inBoundaryFlush = false;\n\n /**\n * Whether this client is a cached, cross-invocation client (`cacheClient`).\n * Cached clients are never disposed at an invocation boundary, so their spans/events\n * are delivered eagerly instead of waiting for a per-invocation flush.\n */\n public readonly isCachedClient: boolean;\n\n /**\n * Creates a new Cloudflare SDK instance.\n * @param options Configuration options for this SDK.\n */\n public constructor(options: CloudflareClientOptions) {\n applySdkMetadata(options, 'cloudflare');\n options._metadata = options._metadata || {};\n const { flushLock, ...serverOptions } = options;\n\n const clientOptions: ServerRuntimeClientOptions = {\n ...serverOptions,\n platform: 'javascript',\n // TODO: Grab version information\n runtime: { name: 'cloudflare' },\n // TODO: Add server name\n _flushInterval: 0,\n };\n\n super(clientOptions);\n this._flushLock = flushLock;\n this.isCachedClient = options.cacheClient === true;\n\n // Track span lifecycle to know when to flush. Skipped for cached clients\n // (`cacheClient`): they are never disposed, so spans that end after\n // a flush are still delivered. Per-invocation clients are disposed right after\n // the boundary flush, so the flush must wait for open spans to end otherwise\n // their transaction never gets emitted.\n if (!this.isCachedClient) {\n this._unsubscribeSpanStart = this.on('spanStart', span => {\n const spanId = span.spanContext().spanId;\n DEBUG_BUILD && debug.log('[CloudflareClient] Span started:', spanId);\n\n // Negatively sampled spans never emit spanEnd,\n // so tracking them would cause _pendingSpans to grow unboundedly.\n // We should fix the inconsistent behavior for NonRecordingSpans in the future but\n // for now, we just ignore them.\n if (!spanIsSampled(span)) {\n return;\n }\n\n this._pendingSpans.add(spanId);\n\n if (!this._spanCompletionPromise) {\n this._spanCompletionPromise = new Promise(resolve => {\n this._resolveSpanCompletion = resolve;\n });\n }\n });\n\n this._unsubscribeSpanEnd = this.on('spanEnd', span => {\n const spanId = span.spanContext().spanId;\n DEBUG_BUILD && debug.log('[CloudflareClient] Span ended:', spanId);\n this._pendingSpans.delete(spanId);\n\n // If no more pending spans, resolve the completion promise\n if (this._pendingSpans.size === 0 && this._resolveSpanCompletion) {\n DEBUG_BUILD && debug.log('[CloudflareClient] All spans completed, preparing to flush');\n this._resolveSpanCompletion();\n this._resetSpanCompletionPromise();\n }\n });\n }\n }\n\n /**\n * Flushes pending operations and ensures all data is processed.\n * If a timeout is provided, the operation will be completed within the specified time limit.\n *\n * It will wait for all pending spans to complete before flushing.\n *\n * @param {number} [timeout] - Optional timeout in milliseconds to force the completion of the flush operation.\n * @return {Promise<boolean>} A promise that resolves to a boolean indicating whether the flush operation was successful.\n */\n public async flush(timeout?: number): Promise<boolean> {\n // Wait for user waitUntil-registered work to settle before draining, so events\n // captured in that work are still in the buffer. Without this the final flush\n // can drain (and the client be disposed) before background captures land.\n if (this._flushLock) {\n await this._flushLock.finalize();\n }\n\n if (this._pendingSpans.size > 0 && this._spanCompletionPromise) {\n DEBUG_BUILD &&\n debug.log('[CloudflareClient] Waiting for', this._pendingSpans.size, 'pending spans to complete...');\n\n const timeoutMs = timeout ?? 5000;\n const spanCompletionRace = Promise.race([\n this._spanCompletionPromise,\n new Promise(resolve =>\n setTimeout(() => {\n DEBUG_BUILD &&\n debug.log('[CloudflareClient] Span completion timeout after', timeoutMs, 'ms, flushing anyway');\n resolve(undefined);\n }, timeoutMs),\n ),\n ]);\n\n await spanCompletionRace;\n }\n\n // Envelopes created while this flush drains (log/metric/span buffers turning into\n // envelopes on the `flush` emit) ride its own transport drain; without the flag each\n // of them would also start an eager drain and a `waitUntil` registration.\n this._inBoundaryFlush = true;\n try {\n return await super.flush(timeout);\n } finally {\n this._inBoundaryFlush = false;\n }\n }\n\n /**\n * Disposes of the client and releases all resources.\n *\n * This method clears all Cloudflare-specific state in addition to the base client cleanup.\n * It unsubscribes from span lifecycle events and clears pending span tracking.\n *\n * Call this method after flushing to allow the client to be garbage collected.\n * After calling dispose(), the client should not be used anymore.\n */\n public override dispose(): void {\n DEBUG_BUILD && debug.log('[CloudflareClient] Disposing client...');\n\n super.dispose();\n\n if (this._unsubscribeSpanStart) {\n this._unsubscribeSpanStart();\n this._unsubscribeSpanStart = null;\n }\n if (this._unsubscribeSpanEnd) {\n this._unsubscribeSpanEnd();\n this._unsubscribeSpanEnd = null;\n }\n\n this._resetSpanCompletionPromise();\n (this as unknown as { _flushLock: ReturnType<typeof makeFlushLock> | void })._flushLock = undefined;\n }\n\n /** @inheritDoc */\n protected override _setupIntegrations(): void {\n // Clear AI provider skip registrations before setting up integrations.\n // The registry is module-global and Cloudflare calls `init()` per request, so without this a\n // single `ai` SDK call would suppress direct `env.AI.run` spans for the rest of the isolate's\n // life. Mirrors the same reset in the Node client.\n _INTERNAL_clearAiProviderSkips();\n super._setupIntegrations();\n\n // Registered after the integrations on purpose: the flush-point marker must run\n // after core and the span buffer have turned their buffers into envelopes on the\n // same `flush` emit (so those envelopes ride the boundary drain instead of starting\n // eager ones), and the eager span handler relies on `spanStreamingIntegration`\n // having already buffered the span that triggers it.\n if (this.isCachedClient) {\n // Marks the invocation's natural flush point: anything captured from now on\n // (post-response `waitUntil` work, detached continuations) has no later flush\n // to ride and is delivered eagerly by the hooks below.\n this.on('flush', () => {\n const invocationState = getInvocationState();\n if (invocationState) {\n invocationState.flushPointReached = true;\n }\n });\n this._setupEagerEnvelopeDelivery();\n this._setupEagerBufferDelivery();\n }\n }\n\n /**\n * Resets the span completion promise and resolve function.\n */\n private _resetSpanCompletionPromise(): void {\n this._pendingSpans.clear();\n this._spanCompletionPromise = null;\n this._resolveSpanCompletion = null;\n }\n\n /**\n * Drains the transport after an envelope has been accepted past the invocation's\n * flush point. The transport queues request producers until `flush()`; before the\n * flush point the boundary `flush()` drains everything, but envelopes created after\n * it (post-response `waitUntil` work, detached continuations) have no later flush to\n * ride. The drain is registered with the invocation's `waitUntil` to keep the fetch\n * alive; outside any instrumented invocation it always runs.\n */\n private _setupEagerEnvelopeDelivery(): void {\n this.on('afterEnvelope', () => {\n const transport = this.getTransport();\n const invocationState = getInvocationState();\n\n if (!transport || this._inBoundaryFlush || (invocationState && !invocationState.flushPointReached)) {\n return;\n }\n\n this._registerWithInvocationWaitUntil(transport.flush(2000));\n });\n }\n\n /**\n * Turns spans, logs and metrics captured past the invocation's flush point into\n * envelopes. Before the flush point the boundary `flush()` drains their buffers; after\n * it (or outside any instrumented invocation) nothing else would: the log/metric idle\n * timer is disabled for this runtime (`_flushInterval: 0`) and the span buffer's own 5s\n * timer fires outside any invocation, where the runtime suspends the send. Each capture\n * drains only its own bucket (the ended span's trace, the log buffer, the metric\n * buffer), so a fan-out of concurrent traces stays one envelope per trace. RPC method\n * spans never reach this path: `wrapMethodWithSentry` runs the boundary flush after the\n * method span has ended, so only work past that (e.g. detached continuations) lands here.\n */\n private _setupEagerBufferDelivery(): void {\n this.on('afterSpanEnd', span => {\n // The trace id must come from the span, not the current scope: `continueTrace`\n // writes the propagation context to the *current* scope, so the forked\n // isolation scope's propagation context carries a different trace id and\n // flushing by it silently no-ops.\n const traceId = span.spanContext().traceId;\n this._eagerDrain(() => this.emit('flushTraceSpans', traceId));\n });\n this.on('afterCaptureLog', () => this._eagerDrain(() => _INTERNAL_flushLogsBuffer(this)));\n this.on('afterCaptureMetric', () => this._eagerDrain(() => _INTERNAL_flushMetricsBuffer(this)));\n }\n\n /**\n * Runs `drain` unless the owning invocation has not reached its flush point yet\n * (before it the boundary `flush()` delivers the buffers).\n */\n private _eagerDrain(drain: () => void): void {\n const invocationState = getInvocationState();\n\n if (invocationState && !invocationState.flushPointReached) {\n return;\n }\n\n drain();\n }\n\n /**\n * Attaches a promise to the `waitUntil` of the invocation that owns the current\n * async context, so the runtime keeps the send alive after the response is returned.\n * Outside any instrumented invocation (or where the context has no `waitUntil`,\n * e.g. Astro prerendering) the send is fire-and-forget.\n */\n private _registerWithInvocationWaitUntil(promise: PromiseLike<unknown>): void {\n const invocationState = getInvocationState();\n const waitUntil = invocationState && getInvocationWaitUntil(invocationState);\n if (!waitUntil) {\n return;\n }\n\n try {\n waitUntil(\n Promise.resolve(promise).then(\n () => undefined,\n () => undefined,\n ),\n );\n } catch {\n // The owning invocation already ended; the send races isolate teardown either way.\n }\n }\n}\n\ninterface BaseCloudflareOptions {\n /**\n * @ignore Used internally to disable the deDupeIntegration for workflows.\n * @hidden Used internally to disable the deDupeIntegration for workflows.\n * @default true\n */\n enableDedupe?: boolean;\n\n /**\n * The Cloudflare SDK is not OpenTelemetry native. By default (`false`) it does not set up a tracer\n * provider; spans are emitted via the SDK's own instrumentation and scopes are isolated with\n * AsyncLocalStorage.\n *\n * Set this to `true` to opt into the OpenTelemetry compatibility tracer, which captures spans\n * emitted via `@opentelemetry/api`. Big caveat: it does not handle custom context, always working\n * off the current scope. This is good enough for many, but not all, integrations.\n *\n * @default false\n */\n enableOpenTelemetrySetup?: boolean;\n\n /**\n * The bindings on `env` that outgoing RPC calls propagate trace context to.\n *\n * Strings match a binding name exactly, regular expressions match by pattern. An empty array\n * (the default) propagates to nothing.\n *\n * RPC has no headers to carry trace context, so the SDK appends it as a trailing argument to\n * every RPC method call on a matching binding. Only a Sentry-instrumented receiver strips that\n * argument again. Anywhere else it arrives as a real argument and changes what the method was\n * called with, so list only the bindings whose receiver you know runs Sentry.\n *\n * Propagation over `stub.fetch()` and service binding `fetch()` uses HTTP headers and is not\n * affected by this option.\n *\n * Strings match a binding name exactly, regular expressions match by pattern. Both match\n * case-insensitively.\n *\n * When you build with the Sentry Cloudflare Vite plugin, bindings that resolve to *this* worker\n * (its own Durable Objects, its self service bindings) are added for you, because the plugin\n * instruments those receivers itself. Whatever you list here is added on top of them.\n *\n * @default []\n * @example\n * ```ts\n * // Propagate to `env.ORDERS` and every `env.SVC_*` binding\n * export default Sentry.withSentry(\n * env => ({\n * dsn: env.SENTRY_DSN,\n * rpcTracePropagationBindings: ['ORDERS', /^SVC_/],\n * }),\n * handler,\n * );\n * ```\n */\n rpcTracePropagationBindings?: TracePropagationTargets;\n\n /**\n * Table names that should stay instrumented even though they match the reserved `cf_` prefix used\n * by Durable Object frameworks (`agents`, `partyserver`, ...) for their internal SQLite tables.\n *\n * By default, `exec` queries against `cf_`-prefixed tables are treated as framework noise and no\n * `db.query` span is created for them. If one of your own tables happens to use this prefix, add it\n * here to opt it back into instrumentation. Entries are matched against each table name in the\n * query summary — strings must match exactly, while regular expressions give you prefix/pattern\n * matching.\n *\n * @default []\n * @example\n * ```ts\n * export default Sentry.withSentry(\n * (env) => ({\n * dsn: env.SENTRY_DSN,\n * durableObjectSqlSpanAllowlist: ['cf_my_table', /^cf_reports_/],\n * }),\n * handler,\n * );\n * ```\n */\n durableObjectSqlSpanAllowlist?: Array<string | RegExp>;\n\n /**\n * KV keys that should stay instrumented even though they match a reserved prefix used by Durable\n * Object frameworks (`agents`, `partyserver`, ...) for their internal storage entries.\n *\n * By default, KV reads/writes (`get`, `put`, `delete`, `list`) of `cf_`- or `__ps_`-prefixed keys\n * are treated as framework noise and no `durable_object_storage_*` span is created for them,\n * mirroring how `cf_`-prefixed SQL tables are handled (see {@link durableObjectSqlSpanAllowlist}).\n * If one of your own keys happens to use such a prefix, add it here to opt it back into\n * instrumentation. Strings must match exactly, while regular expressions give you prefix/pattern\n * matching.\n *\n * @default []\n * @example\n * ```ts\n * export default Sentry.withSentry(\n * (env) => ({\n * dsn: env.SENTRY_DSN,\n * durableObjectStorageSpanAllowlist: ['cf_my_key', /^cf_reports_/],\n * }),\n * handler,\n * );\n * ```\n */\n durableObjectStorageSpanAllowlist?: Array<string | RegExp>;\n\n /**\n * Sets an optional server name (device name).\n *\n * This is useful for identifying which server or instance is sending events.\n */\n serverName?: string;\n\n /**\n * If you use Spotlight by Sentry during development, use\n * this option to forward captured Sentry events to Spotlight.\n *\n * Either set it to true, or provide a specific Spotlight Sidecar URL.\n *\n * More details: https://spotlightjs.com/\n *\n * IMPORTANT: Only set this option to `true` while developing, not in production!\n */\n spotlight?: boolean | string;\n\n /**\n * Cache the client and reuse it across invocations within the same isolate.\n *\n * The SDK creates one client per isolate and reuses it for all requests/DO\n * handlers in that isolate. This avoids the per-invocation cost of\n * constructing a new client.\n *\n * Since a cached client outlives any single invocation, data captured after an\n * invocation's flush point (post-response `waitUntil` work, detached background\n * work) is delivered eagerly instead of waiting for a flush that never comes.\n *\n * The first `init()` in an isolate decides the cached client's options; later\n * `init()` calls with different options (e.g. another DSN) reuse the cached client\n * unchanged (a debug warning is logged for a DSN change). Use `cacheClient: false`\n * when options must differ per invocation.\n *\n * When disabled, a new client is created per invocation and disposed after the\n * handler completes.\n *\n * @default true\n */\n cacheClient?: boolean;\n}\n\n/**\n * Configuration options for the Sentry Cloudflare SDK\n *\n * @see @sentry/core Options for more information.\n */\nexport interface CloudflareOptions extends Options<CloudflareTransportOptions>, BaseCloudflareOptions {\n ctx?: ExecutionContextCompat;\n}\n\n/**\n * Configuration options for the Sentry Cloudflare SDK Client class\n *\n * @see CloudflareClient for more information.\n */\nexport interface CloudflareClientOptions extends ClientOptions<CloudflareTransportOptions>, BaseCloudflareOptions {\n flushLock?: ReturnType<typeof makeFlushLock>;\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","sources":["../../../src/client.ts"],"sourcesContent":["import type { ClientOptions, Options, TracePropagationTargets } from '@sentry/core';\nimport {\n _INTERNAL_clearAiProviderSkips,\n _INTERNAL_flushLogsBuffer,\n _INTERNAL_flushMetricsBuffer,\n applySdkMetadata,\n debug,\n spanIsSampled,\n} from '@sentry/core';\nimport type { ServerRuntimeClientOptions } from '@sentry/core/server';\nimport { ServerRuntimeClient } from '@sentry/core/server';\nimport { DEBUG_BUILD } from './debug-build';\nimport type { ExecutionContextCompat } from './executionContext';\nimport type { makeFlushLock } from './flush';\nimport type { CloudflareTransportOptions } from './transport';\nimport { getInvocationState, getInvocationWaitUntil } from './utils/invocationContext';\n\n/**\n * The Sentry Cloudflare SDK Client.\n *\n * @see CloudflareClientOptions for documentation on configuration options.\n * @see ServerRuntimeClient for usage documentation.\n */\nexport class CloudflareClient extends ServerRuntimeClient {\n private readonly _flushLock: ReturnType<typeof makeFlushLock> | void;\n private _pendingSpans: Set<string> = new Set();\n private _spanCompletionPromise: Promise<void> | null = null;\n private _resolveSpanCompletion: (() => void) | null = null;\n\n private _unsubscribeSpanStart: (() => void) | null = null;\n private _unsubscribeSpanEnd: (() => void) | null = null;\n\n // True while a boundary `flush()` is draining; envelopes created by that drain ride it\n // and must not each start their own eager transport flush.\n private _inBoundaryFlush = false;\n\n /**\n * Whether this client is a cached, cross-invocation client (`cacheClient`).\n * Cached clients are never disposed at an invocation boundary, so their spans/events\n * are delivered eagerly instead of waiting for a per-invocation flush.\n */\n public readonly isCachedClient: boolean;\n\n /**\n * Creates a new Cloudflare SDK instance.\n * @param options Configuration options for this SDK.\n */\n public constructor(options: CloudflareClientOptions) {\n applySdkMetadata(options, 'cloudflare');\n options._metadata = options._metadata || {};\n const { flushLock, ...serverOptions } = options;\n\n const clientOptions: ServerRuntimeClientOptions = {\n ...serverOptions,\n platform: 'javascript',\n // TODO: Grab version information\n runtime: { name: 'cloudflare' },\n // TODO: Add server name\n _flushInterval: 0,\n };\n\n super(clientOptions);\n this._flushLock = flushLock;\n this.isCachedClient = options.cacheClient === true;\n\n // Track span lifecycle to know when to flush. Skipped for cached clients\n // (`cacheClient`): they are never disposed, so spans that end after\n // a flush are still delivered. Per-invocation clients are disposed right after\n // the boundary flush, so the flush must wait for open spans to end otherwise\n // their transaction never gets emitted.\n if (!this.isCachedClient) {\n this._unsubscribeSpanStart = this.on('spanStart', span => {\n const spanId = span.spanContext().spanId;\n DEBUG_BUILD && debug.log('[CloudflareClient] Span started:', spanId);\n\n // Negatively sampled spans never emit spanEnd,\n // so tracking them would cause _pendingSpans to grow unboundedly.\n // We should fix the inconsistent behavior for NonRecordingSpans in the future but\n // for now, we just ignore them.\n if (!spanIsSampled(span)) {\n return;\n }\n\n this._pendingSpans.add(spanId);\n\n if (!this._spanCompletionPromise) {\n this._spanCompletionPromise = new Promise(resolve => {\n this._resolveSpanCompletion = resolve;\n });\n }\n });\n\n this._unsubscribeSpanEnd = this.on('spanEnd', span => {\n const spanId = span.spanContext().spanId;\n DEBUG_BUILD && debug.log('[CloudflareClient] Span ended:', spanId);\n this._pendingSpans.delete(spanId);\n\n // If no more pending spans, resolve the completion promise\n if (this._pendingSpans.size === 0 && this._resolveSpanCompletion) {\n DEBUG_BUILD && debug.log('[CloudflareClient] All spans completed, preparing to flush');\n this._resolveSpanCompletion();\n this._resetSpanCompletionPromise();\n }\n });\n }\n }\n\n /**\n * Flushes pending operations and ensures all data is processed.\n *\n * Each phase waits at most `timeout`: the flush lock of a per-invocation client, pending spans, event\n * processing and the transport drain. So a flush can take a small multiple of `timeout`, which stays well\n * below Cloudflare's 30 second `waitUntil` limit for the timeouts the SDK uses. Sends still pending when\n * the drain times out are aborted.\n *\n * @param {number} [timeout] - Maximum time in milliseconds for each phase of the flush.\n * @return {Promise<boolean>} A promise that resolves to a boolean indicating whether the flush operation was successful.\n */\n public async flush(timeout?: number): Promise<boolean> {\n // Wait for user waitUntil-registered work to settle before draining, so events\n // captured in that work are still in the buffer. Without this the final flush\n // can drain (and the client be disposed) before background captures land.\n //\n // Only per-invocation clients (`cacheClient: false`) have a flush lock; remove this with them in v12.\n // The wait is bounded by `timeout` because a user `waitUntil` task that outlives the invocation\n // would otherwise keep the flush from draining until the runtime cancels it.\n if (this._flushLock) {\n let timer: ReturnType<typeof setTimeout> | undefined;\n await Promise.race([\n this._flushLock.finalize(),\n ...(timeout ? [new Promise<void>(resolve => (timer = setTimeout(resolve, timeout)))] : []),\n ]);\n clearTimeout(timer);\n }\n\n if (this._pendingSpans.size > 0 && this._spanCompletionPromise) {\n DEBUG_BUILD &&\n debug.log('[CloudflareClient] Waiting for', this._pendingSpans.size, 'pending spans to complete...');\n\n const timeoutMs = timeout ?? 5000;\n const spanCompletionRace = Promise.race([\n this._spanCompletionPromise,\n new Promise(resolve =>\n setTimeout(() => {\n DEBUG_BUILD &&\n debug.log('[CloudflareClient] Span completion timeout after', timeoutMs, 'ms, flushing anyway');\n resolve(undefined);\n }, timeoutMs),\n ),\n ]);\n\n await spanCompletionRace;\n }\n\n // Envelopes created while this flush drains (log/metric/span buffers turning into\n // envelopes on the `flush` emit) ride its own transport drain; without the flag each\n // of them would also start an eager drain and a `waitUntil` registration.\n this._inBoundaryFlush = true;\n try {\n return await super.flush(timeout);\n } finally {\n this._inBoundaryFlush = false;\n }\n }\n\n /**\n * Disposes of the client and releases all resources.\n *\n * This method clears all Cloudflare-specific state in addition to the base client cleanup.\n * It unsubscribes from span lifecycle events and clears pending span tracking.\n *\n * Call this method after flushing to allow the client to be garbage collected.\n * After calling dispose(), the client should not be used anymore.\n */\n public override dispose(): void {\n DEBUG_BUILD && debug.log('[CloudflareClient] Disposing client...');\n\n super.dispose();\n\n if (this._unsubscribeSpanStart) {\n this._unsubscribeSpanStart();\n this._unsubscribeSpanStart = null;\n }\n if (this._unsubscribeSpanEnd) {\n this._unsubscribeSpanEnd();\n this._unsubscribeSpanEnd = null;\n }\n\n this._resetSpanCompletionPromise();\n (this as unknown as { _flushLock: ReturnType<typeof makeFlushLock> | void })._flushLock = undefined;\n }\n\n /** @inheritDoc */\n protected override _setupIntegrations(): void {\n // Clear AI provider skip registrations before setting up integrations.\n // The registry is module-global and Cloudflare calls `init()` per request, so without this a\n // single `ai` SDK call would suppress direct `env.AI.run` spans for the rest of the isolate's\n // life. Mirrors the same reset in the Node client.\n _INTERNAL_clearAiProviderSkips();\n super._setupIntegrations();\n\n // Registered after the integrations on purpose: the flush-point marker must run\n // after core and the span buffer have turned their buffers into envelopes on the\n // same `flush` emit (so those envelopes ride the boundary drain instead of starting\n // eager ones), and the eager span handler relies on `spanStreamingIntegration`\n // having already buffered the span that triggers it.\n if (this.isCachedClient) {\n // Marks the invocation's natural flush point: anything captured from now on\n // (post-response `waitUntil` work, detached continuations) has no later flush\n // to ride and is delivered eagerly by the hooks below.\n this.on('flush', () => {\n const invocationState = getInvocationState();\n if (invocationState) {\n invocationState.flushPointReached = true;\n }\n });\n this._setupEagerEnvelopeDelivery();\n this._setupEagerBufferDelivery();\n }\n }\n\n /**\n * Resets the span completion promise and resolve function.\n */\n private _resetSpanCompletionPromise(): void {\n this._pendingSpans.clear();\n this._spanCompletionPromise = null;\n this._resolveSpanCompletion = null;\n }\n\n /**\n * Drains the transport after an envelope has been accepted past the invocation's\n * flush point. The transport queues request producers until `flush()`; before the\n * flush point the boundary `flush()` drains everything, but envelopes created after\n * it (post-response `waitUntil` work, detached continuations) have no later flush to\n * ride. The drain is registered with the invocation's `waitUntil` to keep the fetch\n * alive; outside any instrumented invocation it always runs.\n */\n private _setupEagerEnvelopeDelivery(): void {\n this.on('afterEnvelope', () => {\n const transport = this.getTransport();\n const invocationState = getInvocationState();\n\n if (!transport || this._inBoundaryFlush || (invocationState && !invocationState.flushPointReached)) {\n return;\n }\n\n this._registerWithInvocationWaitUntil(transport.flush(2000));\n });\n }\n\n /**\n * Turns spans, logs and metrics captured past the invocation's flush point into\n * envelopes. Before the flush point the boundary `flush()` drains their buffers; after\n * it (or outside any instrumented invocation) nothing else would: the log/metric idle\n * timer is disabled for this runtime (`_flushInterval: 0`) and the span buffer's own 5s\n * timer fires outside any invocation, where the runtime suspends the send. Each capture\n * drains only its own bucket (the ended span's trace, the log buffer, the metric\n * buffer), so a fan-out of concurrent traces stays one envelope per trace. RPC method\n * spans never reach this path: `wrapMethodWithSentry` runs the boundary flush after the\n * method span has ended, so only work past that (e.g. detached continuations) lands here.\n */\n private _setupEagerBufferDelivery(): void {\n this.on('afterSpanEnd', span => {\n // The trace id must come from the span, not the current scope: `continueTrace`\n // writes the propagation context to the *current* scope, so the forked\n // isolation scope's propagation context carries a different trace id and\n // flushing by it silently no-ops.\n const traceId = span.spanContext().traceId;\n this._eagerDrain(() => this.emit('flushTraceSpans', traceId));\n });\n this.on('afterCaptureLog', () => this._eagerDrain(() => _INTERNAL_flushLogsBuffer(this)));\n this.on('afterCaptureMetric', () => this._eagerDrain(() => _INTERNAL_flushMetricsBuffer(this)));\n }\n\n /**\n * Runs `drain` unless the owning invocation has not reached its flush point yet\n * (before it the boundary `flush()` delivers the buffers).\n */\n private _eagerDrain(drain: () => void): void {\n const invocationState = getInvocationState();\n\n if (invocationState && !invocationState.flushPointReached) {\n return;\n }\n\n drain();\n }\n\n /**\n * Attaches a promise to the `waitUntil` of the invocation that owns the current\n * async context, so the runtime keeps the send alive after the response is returned.\n * Outside any instrumented invocation (or where the context has no `waitUntil`,\n * e.g. Astro prerendering) the send is fire-and-forget.\n */\n private _registerWithInvocationWaitUntil(promise: PromiseLike<unknown>): void {\n const invocationState = getInvocationState();\n const waitUntil = invocationState && getInvocationWaitUntil(invocationState);\n if (!waitUntil) {\n return;\n }\n\n try {\n waitUntil(\n Promise.resolve(promise).then(\n () => undefined,\n () => undefined,\n ),\n );\n } catch {\n // The owning invocation already ended; the send races isolate teardown either way.\n }\n }\n}\n\ninterface BaseCloudflareOptions {\n /**\n * @ignore Used internally to disable the deDupeIntegration for workflows.\n * @hidden Used internally to disable the deDupeIntegration for workflows.\n * @default true\n */\n enableDedupe?: boolean;\n\n /**\n * The Cloudflare SDK is not OpenTelemetry native. By default (`false`) it does not set up a tracer\n * provider; spans are emitted via the SDK's own instrumentation and scopes are isolated with\n * AsyncLocalStorage.\n *\n * Set this to `true` to opt into the OpenTelemetry compatibility tracer, which captures spans\n * emitted via `@opentelemetry/api`. Big caveat: it does not handle custom context, always working\n * off the current scope. This is good enough for many, but not all, integrations.\n *\n * @default false\n */\n enableOpenTelemetrySetup?: boolean;\n\n /**\n * The bindings on `env` that outgoing RPC calls propagate trace context to.\n *\n * Strings match a binding name exactly, regular expressions match by pattern. An empty array\n * (the default) propagates to nothing.\n *\n * RPC has no headers to carry trace context, so the SDK appends it as a trailing argument to\n * every RPC method call on a matching binding. Only a Sentry-instrumented receiver strips that\n * argument again. Anywhere else it arrives as a real argument and changes what the method was\n * called with, so list only the bindings whose receiver you know runs Sentry.\n *\n * Propagation over `stub.fetch()` and service binding `fetch()` uses HTTP headers and is not\n * affected by this option.\n *\n * Strings match a binding name exactly, regular expressions match by pattern. Both match\n * case-insensitively.\n *\n * When you build with the Sentry Cloudflare Vite plugin, bindings that resolve to *this* worker\n * (its own Durable Objects, its self service bindings) are added for you, because the plugin\n * instruments those receivers itself. Whatever you list here is added on top of them.\n *\n * @default []\n * @example\n * ```ts\n * // Propagate to `env.ORDERS` and every `env.SVC_*` binding\n * export default Sentry.withSentry(\n * env => ({\n * dsn: env.SENTRY_DSN,\n * rpcTracePropagationBindings: ['ORDERS', /^SVC_/],\n * }),\n * handler,\n * );\n * ```\n */\n rpcTracePropagationBindings?: TracePropagationTargets;\n\n /**\n * Table names that should stay instrumented even though they match the reserved `cf_` prefix used\n * by Durable Object frameworks (`agents`, `partyserver`, ...) for their internal SQLite tables.\n *\n * By default, `exec` queries against `cf_`-prefixed tables are treated as framework noise and no\n * `db.query` span is created for them. If one of your own tables happens to use this prefix, add it\n * here to opt it back into instrumentation. Entries are matched against each table name in the\n * query summary — strings must match exactly, while regular expressions give you prefix/pattern\n * matching.\n *\n * @default []\n * @example\n * ```ts\n * export default Sentry.withSentry(\n * (env) => ({\n * dsn: env.SENTRY_DSN,\n * durableObjectSqlSpanAllowlist: ['cf_my_table', /^cf_reports_/],\n * }),\n * handler,\n * );\n * ```\n */\n durableObjectSqlSpanAllowlist?: Array<string | RegExp>;\n\n /**\n * KV keys that should stay instrumented even though they match a reserved prefix used by Durable\n * Object frameworks (`agents`, `partyserver`, ...) for their internal storage entries.\n *\n * By default, KV reads/writes (`get`, `put`, `delete`, `list`) of `cf_`- or `__ps_`-prefixed keys\n * are treated as framework noise and no `durable_object_storage_*` span is created for them,\n * mirroring how `cf_`-prefixed SQL tables are handled (see {@link durableObjectSqlSpanAllowlist}).\n * If one of your own keys happens to use such a prefix, add it here to opt it back into\n * instrumentation. Strings must match exactly, while regular expressions give you prefix/pattern\n * matching.\n *\n * @default []\n * @example\n * ```ts\n * export default Sentry.withSentry(\n * (env) => ({\n * dsn: env.SENTRY_DSN,\n * durableObjectStorageSpanAllowlist: ['cf_my_key', /^cf_reports_/],\n * }),\n * handler,\n * );\n * ```\n */\n durableObjectStorageSpanAllowlist?: Array<string | RegExp>;\n\n /**\n * Sets an optional server name (device name).\n *\n * This is useful for identifying which server or instance is sending events.\n */\n serverName?: string;\n\n /**\n * If you use Spotlight by Sentry during development, use\n * this option to forward captured Sentry events to Spotlight.\n *\n * Either set it to true, or provide a specific Spotlight Sidecar URL.\n *\n * More details: https://spotlightjs.com/\n *\n * IMPORTANT: Only set this option to `true` while developing, not in production!\n */\n spotlight?: boolean | string;\n\n /**\n * Cache the client and reuse it across invocations within the same isolate.\n *\n * The SDK creates one client per isolate and reuses it for all requests/DO\n * handlers in that isolate. This avoids the per-invocation cost of\n * constructing a new client.\n *\n * Since a cached client outlives any single invocation, data captured after an\n * invocation's flush point (post-response `waitUntil` work, detached background\n * work) is delivered eagerly instead of waiting for a flush that never comes.\n *\n * The first `init()` in an isolate decides the cached client's options; later\n * `init()` calls with different options (e.g. another DSN) reuse the cached client\n * unchanged (a debug warning is logged for a DSN change). Use `cacheClient: false`\n * when options must differ per invocation.\n *\n * When disabled, a new client is created per invocation and disposed after the\n * handler completes.\n *\n * @default true\n */\n cacheClient?: boolean;\n}\n\n/**\n * Configuration options for the Sentry Cloudflare SDK\n *\n * @see @sentry/core Options for more information.\n */\nexport interface CloudflareOptions extends Options<CloudflareTransportOptions>, BaseCloudflareOptions {\n ctx?: ExecutionContextCompat;\n}\n\n/**\n * Configuration options for the Sentry Cloudflare SDK Client class\n *\n * @see CloudflareClient for more information.\n */\nexport interface CloudflareClientOptions extends ClientOptions<CloudflareTransportOptions>, BaseCloudflareOptions {\n flushLock?: ReturnType<typeof makeFlushLock>;\n}\n"],"names":[],"mappings":";;;;;AAuBO,MAAM,yBAAyB,mBAAA,CAAoB;AAAA;AAAA;AAAA;AAAA;AAAA,EAwBjD,YAAY,OAAA,EAAkC;AACnD,IAAA,gBAAA,CAAiB,SAAS,YAAY,CAAA;AACtC,IAAA,OAAA,CAAQ,SAAA,GAAY,OAAA,CAAQ,SAAA,IAAa,EAAC;AAC1C,IAAA,MAAM,EAAE,SAAA,EAAW,GAAG,aAAA,EAAc,GAAI,OAAA;AAExC,IAAA,MAAM,aAAA,GAA4C;AAAA,MAChD,GAAG,aAAA;AAAA,MACH,QAAA,EAAU,YAAA;AAAA;AAAA,MAEV,OAAA,EAAS,EAAE,IAAA,EAAM,YAAA,EAAa;AAAA;AAAA,MAE9B,cAAA,EAAgB;AAAA,KAClB;AAEA,IAAA,KAAA,CAAM,aAAa,CAAA;AApCrB,IAAA,IAAA,CAAQ,aAAA,uBAAiC,GAAA,EAAI;AAC7C,IAAA,IAAA,CAAQ,sBAAA,GAA+C,IAAA;AACvD,IAAA,IAAA,CAAQ,sBAAA,GAA8C,IAAA;AAEtD,IAAA,IAAA,CAAQ,qBAAA,GAA6C,IAAA;AACrD,IAAA,IAAA,CAAQ,mBAAA,GAA2C,IAAA;AAInD;AAAA;AAAA,IAAA,IAAA,CAAQ,gBAAA,GAAmB,KAAA;AA4BzB,IAAA,IAAA,CAAK,UAAA,GAAa,SAAA;AAClB,IAAA,IAAA,CAAK,cAAA,GAAiB,QAAQ,WAAA,KAAgB,IAAA;AAO9C,IAAA,IAAI,CAAC,KAAK,cAAA,EAAgB;AACxB,MAAA,IAAA,CAAK,qBAAA,GAAwB,IAAA,CAAK,EAAA,CAAG,WAAA,EAAa,CAAA,IAAA,KAAQ;AACxD,QAAA,MAAM,MAAA,GAAS,IAAA,CAAK,WAAA,EAAY,CAAE,MAAA;AAClC,QAAA,WAAA,IAAe,KAAA,CAAM,GAAA,CAAI,kCAAA,EAAoC,MAAM,CAAA;AAMnE,QAAA,IAAI,CAAC,aAAA,CAAc,IAAI,CAAA,EAAG;AACxB,UAAA;AAAA,QACF;AAEA,QAAA,IAAA,CAAK,aAAA,CAAc,IAAI,MAAM,CAAA;AAE7B,QAAA,IAAI,CAAC,KAAK,sBAAA,EAAwB;AAChC,UAAA,IAAA,CAAK,sBAAA,GAAyB,IAAI,OAAA,CAAQ,CAAA,OAAA,KAAW;AACnD,YAAA,IAAA,CAAK,sBAAA,GAAyB,OAAA;AAAA,UAChC,CAAC,CAAA;AAAA,QACH;AAAA,MACF,CAAC,CAAA;AAED,MAAA,IAAA,CAAK,mBAAA,GAAsB,IAAA,CAAK,EAAA,CAAG,SAAA,EAAW,CAAA,IAAA,KAAQ;AACpD,QAAA,MAAM,MAAA,GAAS,IAAA,CAAK,WAAA,EAAY,CAAE,MAAA;AAClC,QAAA,WAAA,IAAe,KAAA,CAAM,GAAA,CAAI,gCAAA,EAAkC,MAAM,CAAA;AACjE,QAAA,IAAA,CAAK,aAAA,CAAc,OAAO,MAAM,CAAA;AAGhC,QAAA,IAAI,IAAA,CAAK,aAAA,CAAc,IAAA,KAAS,CAAA,IAAK,KAAK,sBAAA,EAAwB;AAChE,UAAA,WAAA,IAAe,KAAA,CAAM,IAAI,4DAA4D,CAAA;AACrF,UAAA,IAAA,CAAK,sBAAA,EAAuB;AAC5B,UAAA,IAAA,CAAK,2BAAA,EAA4B;AAAA,QACnC;AAAA,MACF,CAAC,CAAA;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,MAAa,MAAM,OAAA,EAAoC;AAQrD,IAAA,IAAI,KAAK,UAAA,EAAY;AACnB,MAAA,IAAI,KAAA;AACJ,MAAA,MAAM,QAAQ,IAAA,CAAK;AAAA,QACjB,IAAA,CAAK,WAAW,QAAA,EAAS;AAAA,QACzB,GAAI,OAAA,GAAU,CAAC,IAAI,OAAA,CAAc,CAAA,OAAA,KAAY,KAAA,GAAQ,UAAA,CAAW,OAAA,EAAS,OAAO,CAAE,CAAC,IAAI;AAAC,OACzF,CAAA;AACD,MAAA,YAAA,CAAa,KAAK,CAAA;AAAA,IACpB;AAEA,IAAA,IAAI,IAAA,CAAK,aAAA,CAAc,IAAA,GAAO,CAAA,IAAK,KAAK,sBAAA,EAAwB;AAC9D,MAAA,WAAA,IACE,MAAM,GAAA,CAAI,gCAAA,EAAkC,IAAA,CAAK,aAAA,CAAc,MAAM,8BAA8B,CAAA;AAErG,MAAA,MAAM,YAAY,OAAA,IAAW,GAAA;AAC7B,MAAA,MAAM,kBAAA,GAAqB,QAAQ,IAAA,CAAK;AAAA,QACtC,IAAA,CAAK,sBAAA;AAAA,QACL,IAAI,OAAA;AAAA,UAAQ,CAAA,OAAA,KACV,WAAW,MAAM;AACf,YAAA,WAAA,IACE,KAAA,CAAM,GAAA,CAAI,kDAAA,EAAoD,SAAA,EAAW,qBAAqB,CAAA;AAChG,YAAA,OAAA,CAAQ,MAAS,CAAA;AAAA,UACnB,GAAG,SAAS;AAAA;AACd,OACD,CAAA;AAED,MAAA,MAAM,kBAAA;AAAA,IACR;AAKA,IAAA,IAAA,CAAK,gBAAA,GAAmB,IAAA;AACxB,IAAA,IAAI;AACF,MAAA,OAAO,MAAM,KAAA,CAAM,KAAA,CAAM,OAAO,CAAA;AAAA,IAClC,CAAA,SAAE;AACA,MAAA,IAAA,CAAK,gBAAA,GAAmB,KAAA;AAAA,IAC1B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWgB,OAAA,GAAgB;AAC9B,IAAA,WAAA,IAAe,KAAA,CAAM,IAAI,wCAAwC,CAAA;AAEjE,IAAA,KAAA,CAAM,OAAA,EAAQ;AAEd,IAAA,IAAI,KAAK,qBAAA,EAAuB;AAC9B,MAAA,IAAA,CAAK,qBAAA,EAAsB;AAC3B,MAAA,IAAA,CAAK,qBAAA,GAAwB,IAAA;AAAA,IAC/B;AACA,IAAA,IAAI,KAAK,mBAAA,EAAqB;AAC5B,MAAA,IAAA,CAAK,mBAAA,EAAoB;AACzB,MAAA,IAAA,CAAK,mBAAA,GAAsB,IAAA;AAAA,IAC7B;AAEA,IAAA,IAAA,CAAK,2BAAA,EAA4B;AACjC,IAAC,KAA4E,UAAA,GAAa,MAAA;AAAA,EAC5F;AAAA;AAAA,EAGmB,kBAAA,GAA2B;AAK5C,IAAA,8BAAA,EAA+B;AAC/B,IAAA,KAAA,CAAM,kBAAA,EAAmB;AAOzB,IAAA,IAAI,KAAK,cAAA,EAAgB;AAIvB,MAAA,IAAA,CAAK,EAAA,CAAG,SAAS,MAAM;AACrB,QAAA,MAAM,kBAAkB,kBAAA,EAAmB;AAC3C,QAAA,IAAI,eAAA,EAAiB;AACnB,UAAA,eAAA,CAAgB,iBAAA,GAAoB,IAAA;AAAA,QACtC;AAAA,MACF,CAAC,CAAA;AACD,MAAA,IAAA,CAAK,2BAAA,EAA4B;AACjC,MAAA,IAAA,CAAK,yBAAA,EAA0B;AAAA,IACjC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,2BAAA,GAAoC;AAC1C,IAAA,IAAA,CAAK,cAAc,KAAA,EAAM;AACzB,IAAA,IAAA,CAAK,sBAAA,GAAyB,IAAA;AAC9B,IAAA,IAAA,CAAK,sBAAA,GAAyB,IAAA;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUQ,2BAAA,GAAoC;AAC1C,IAAA,IAAA,CAAK,EAAA,CAAG,iBAAiB,MAAM;AAC7B,MAAA,MAAM,SAAA,GAAY,KAAK,YAAA,EAAa;AACpC,MAAA,MAAM,kBAAkB,kBAAA,EAAmB;AAE3C,MAAA,IAAI,CAAC,SAAA,IAAa,IAAA,CAAK,oBAAqB,eAAA,IAAmB,CAAC,gBAAgB,iBAAA,EAAoB;AAClG,QAAA;AAAA,MACF;AAEA,MAAA,IAAA,CAAK,gCAAA,CAAiC,SAAA,CAAU,KAAA,CAAM,GAAI,CAAC,CAAA;AAAA,IAC7D,CAAC,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaQ,yBAAA,GAAkC;AACxC,IAAA,IAAA,CAAK,EAAA,CAAG,gBAAgB,CAAA,IAAA,KAAQ;AAK9B,MAAA,MAAM,OAAA,GAAU,IAAA,CAAK,WAAA,EAAY,CAAE,OAAA;AACnC,MAAA,IAAA,CAAK,YAAY,MAAM,IAAA,CAAK,IAAA,CAAK,iBAAA,EAAmB,OAAO,CAAC,CAAA;AAAA,IAC9D,CAAC,CAAA;AACD,IAAA,IAAA,CAAK,EAAA,CAAG,mBAAmB,MAAM,IAAA,CAAK,YAAY,MAAM,yBAAA,CAA0B,IAAI,CAAC,CAAC,CAAA;AACxF,IAAA,IAAA,CAAK,EAAA,CAAG,sBAAsB,MAAM,IAAA,CAAK,YAAY,MAAM,4BAAA,CAA6B,IAAI,CAAC,CAAC,CAAA;AAAA,EAChG;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,YAAY,KAAA,EAAyB;AAC3C,IAAA,MAAM,kBAAkB,kBAAA,EAAmB;AAE3C,IAAA,IAAI,eAAA,IAAmB,CAAC,eAAA,CAAgB,iBAAA,EAAmB;AACzD,MAAA;AAAA,IACF;AAEA,IAAA,KAAA,EAAM;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,iCAAiC,OAAA,EAAqC;AAC5E,IAAA,MAAM,kBAAkB,kBAAA,EAAmB;AAC3C,IAAA,MAAM,SAAA,GAAY,eAAA,IAAmB,sBAAA,CAAuB,eAAe,CAAA;AAC3E,IAAA,IAAI,CAAC,SAAA,EAAW;AACd,MAAA;AAAA,IACF;AAEA,IAAA,IAAI;AACF,MAAA,SAAA;AAAA,QACE,OAAA,CAAQ,OAAA,CAAQ,OAAO,CAAA,CAAE,IAAA;AAAA,UACvB,MAAM,KAAA,CAAA;AAAA,UACN,MAAM,KAAA;AAAA;AACR,OACF;AAAA,IACF,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF;AACF;;;;"}
|
package/build/esm/prod/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { SDK_VERSION, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, Scope, addBreadcrumb, addEventProcessor, addIntegration, bindScopeToEmitter, captureCheckIn, captureConsoleIntegration, captureEvent, captureException, captureFeedback, captureMessage, close, consoleIntegration, consoleLoggingIntegration, continueTrace, createConsolaReporter, createTransport, dedupeIntegration, eventFiltersIntegration, extraErrorDataIntegration, featureFlagsIntegration, flush, functionToStringIntegration, getActiveSpan, getClient, getCurrentScope, getGlobalScope, getIsolationScope, getRootSpan, getSpanDescendants, getSpanStatusFromHttpCode, getTraceData, getTraceMetaTags, growthbookIntegration, instrumentSupabaseClient, isEnabled, isInitialized, lastEventId, linkedErrorsIntegration, logger, metrics, moduleMetadataIntegration, requestDataIntegration, rewriteFramesIntegration, setAttribute, setAttributes, setContext, setConversationId, setCurrentClient, setExtra, setExtras, setHttpStatus, setMeasurement, setTag, setTags, setUser, spanStreamingIntegration, spanToBaggageHeader, spanToJSON, spanToStaticSpanJSON, spanToTraceHeader, startInactiveSpan, startNewTrace, startSpan, startSpanManual, supabaseIntegration, suppressTracing, updateSpanName, withActiveSpan, withIsolationScope, withMonitor, withScope, withStaticSpan, withStreamedSpan, zodErrorsIntegration } from '@sentry/core';
|
|
2
2
|
export { trpcMiddleware, wrapMcpServerWithSentry } from '@sentry/core/server';
|
|
3
|
-
export { createFlueInstrumentation, createLangChainCallbackHandler, eveConversationHook, eveIntegration, getInstrumentedModuleNames, getOtlpTracesEndpoint, instrumentAnthropicAiClient, instrumentCreateReactAgent, instrumentGoogleGenAIClient, instrumentLangChainEmbeddings, instrumentMistralAiClient, instrumentOpenAiClient, instrumentPostgresJsSql, instrumentStateGraph, instrumentWorkersAiClient, openTelemetryIntegration, prismaIntegration, vercelAIIntegration } from '@sentry/server-utils';
|
|
3
|
+
export { createFlueInstrumentation, createLangChainCallbackHandler, eveConversationHook, eveIntegration, getInstrumentedModuleNames, getOtlpTracesEndpoint, instrumentAnthropicAiClient, instrumentCreateReactAgent, instrumentGoogleGenAIClient, instrumentLangChainEmbeddings, instrumentMistralAiClient, instrumentOpenAiClient, instrumentPostgresJsSql, instrumentStateGraph, instrumentTypeSafeClient, instrumentWorkersAiClient, openTelemetryIntegration, prismaIntegration, vercelAIIntegration } from '@sentry/server-utils';
|
|
4
4
|
export { withSentry } from './withSentry.js';
|
|
5
5
|
export { defineCloudflareOptions } from './defineCloudflareOptions.js';
|
|
6
6
|
export { instrumentAgentWithSentry, instrumentDurableObjectWithSentry } from './durableobject.js';
|
|
@@ -32,6 +32,9 @@ function instrumentDurableObjectStub(stub, propagateRpcTrace) {
|
|
|
32
32
|
if (prop === "fetch" && typeof value === "function") {
|
|
33
33
|
return instrumentFetcher((...args) => Reflect.apply(value, target, args));
|
|
34
34
|
}
|
|
35
|
+
if (prop === "connect" && typeof value === "function") {
|
|
36
|
+
return (...args) => Reflect.apply(value, target, args);
|
|
37
|
+
}
|
|
35
38
|
if (propagateRpcTrace && typeof value === "function" && typeof prop === "string" && !STUB_NON_RPC_METHODS.has(prop)) {
|
|
36
39
|
return (...args) => Reflect.apply(value, target, appendRpcMeta(args));
|
|
37
40
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instrumentDurableObjectNamespace.js","sources":["../../../../src/instrumentations/instrumentDurableObjectNamespace.ts"],"sourcesContent":["import type { DurableObjectNamespace, DurableObjectStub } from '@cloudflare/workers-types';\nimport { appendRpcMeta } from '../utils/rpcMeta';\nimport { instrumentFetcher } from './worker/instrumentFetcher';\n\n// Built-in DurableObjectStub methods that are not RPC calls.\nexport const STUB_NON_RPC_METHODS = new Set(['fetch', 'connect', 'dup']);\n\n/**\n * Instruments a DurableObjectNamespace binding to create spans for DO interactions.\n *\n * Wraps:\n * - `namespace.get(id)` / `namespace.getByName(name)` with a span + instruments returned stub\n * - `namespace.jurisdiction(name)` by instrumenting the returned namespace the same way\n * - `namespace.idFromName(name)` / `namespace.idFromString(id)` / `namespace.newUniqueId()` with breadcrumbs\n *\n * @param namespace - The DurableObjectNamespace to instrument\n * @param propagateRpcTrace - Whether RPC method calls on the returned stubs carry trace context\n */\nexport function instrumentDurableObjectNamespace(\n namespace: DurableObjectNamespace,\n propagateRpcTrace = false,\n): DurableObjectNamespace {\n return new Proxy(namespace, {\n get(target, prop, _receiver) {\n const value = Reflect.get(target, prop) as unknown;\n\n if (typeof value !== 'function') {\n return value;\n }\n\n if (prop === 'get' || prop === 'getByName') {\n return function (this: unknown, ...args: unknown[]) {\n const stub = Reflect.apply(value, target, args);\n\n return instrumentDurableObjectStub(stub, propagateRpcTrace);\n };\n }\n\n if (prop === 'jurisdiction') {\n return function (this: unknown, ...args: unknown[]) {\n const subnamespace = Reflect.apply(value, target, args);\n\n return instrumentDurableObjectNamespace(subnamespace, propagateRpcTrace);\n };\n }\n\n return value.bind(target);\n },\n });\n}\n\n/**\n * Instruments a DurableObjectStub to create spans for outgoing fetch calls\n * and propagate trace context across RPC calls.\n *\n * @param stub - The DurableObjectStub to instrument\n * @param propagateRpcTrace - Whether RPC method calls carry trace context\n */\nfunction instrumentDurableObjectStub(stub: DurableObjectStub, propagateRpcTrace: boolean): DurableObjectStub {\n return new Proxy(stub, {\n get(target, prop) {\n const value = Reflect.get(target, prop);\n\n if (prop === 'fetch' && typeof value === 'function') {\n return instrumentFetcher((...args) => Reflect.apply(value, target, args));\n }\n\n if (\n propagateRpcTrace &&\n typeof value === 'function' &&\n typeof prop === 'string' &&\n !STUB_NON_RPC_METHODS.has(prop)\n ) {\n return (...args: unknown[]) => Reflect.apply(value, target, appendRpcMeta(args));\n }\n\n return value;\n },\n });\n}\n"],"names":[],"mappings":";;;AAKO,MAAM,uCAAuB,IAAI,GAAA,CAAI,CAAC,OAAA,EAAS,SAAA,EAAW,KAAK,CAAC;AAahE,SAAS,gCAAA,CACd,SAAA,EACA,iBAAA,GAAoB,KAAA,EACI;AACxB,EAAA,OAAO,IAAI,MAAM,SAAA,EAAW;AAAA,IAC1B,GAAA,CAAI,MAAA,EAAQ,IAAA,EAAM,SAAA,EAAW;AAC3B,MAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,GAAA,CAAI,MAAA,EAAQ,IAAI,CAAA;AAEtC,MAAA,IAAI,OAAO,UAAU,UAAA,EAAY;AAC/B,QAAA,OAAO,KAAA;AAAA,MACT;AAEA,MAAA,IAAI,IAAA,KAAS,KAAA,IAAS,IAAA,KAAS,WAAA,EAAa;AAC1C,QAAA,OAAO,YAA4B,IAAA,EAAiB;AAClD,UAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,KAAA,CAAM,KAAA,EAAO,QAAQ,IAAI,CAAA;AAE9C,UAAA,OAAO,2BAAA,CAA4B,MAAM,iBAAiB,CAAA;AAAA,QAC5D,CAAA;AAAA,MACF;AAEA,MAAA,IAAI,SAAS,cAAA,EAAgB;AAC3B,QAAA,OAAO,YAA4B,IAAA,EAAiB;AAClD,UAAA,MAAM,YAAA,GAAe,OAAA,CAAQ,KAAA,CAAM,KAAA,EAAO,QAAQ,IAAI,CAAA;AAEtD,UAAA,OAAO,gCAAA,CAAiC,cAAc,iBAAiB,CAAA;AAAA,QACzE,CAAA;AAAA,MACF;AAEA,MAAA,OAAO,KAAA,CAAM,KAAK,MAAM,CAAA;AAAA,IAC1B;AAAA,GACD,CAAA;AACH;AASA,SAAS,2BAAA,CAA4B,MAAyB,iBAAA,EAA+C;AAC3G,EAAA,OAAO,IAAI,MAAM,IAAA,EAAM;AAAA,IACrB,GAAA,CAAI,QAAQ,IAAA,EAAM;AAChB,MAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,GAAA,CAAI,MAAA,EAAQ,IAAI,CAAA;AAEtC,MAAA,IAAI,IAAA,KAAS,OAAA,IAAW,OAAO,KAAA,KAAU,UAAA,EAAY;AACnD,QAAA,OAAO,iBAAA,CAAkB,IAAI,IAAA,KAAS,OAAA,CAAQ,MAAM,KAAA,EAAO,MAAA,EAAQ,IAAI,CAAC,CAAA;AAAA,MAC1E;AAEA,MAAA,IACE,iBAAA,IACA,OAAO,KAAA,KAAU,UAAA,IACjB,OAAO,IAAA,KAAS,QAAA,IAChB,CAAC,oBAAA,CAAqB,GAAA,CAAI,IAAI,CAAA,EAC9B;AACA,QAAA,OAAO,CAAA,GAAI,SAAoB,OAAA,CAAQ,KAAA,CAAM,OAAO,MAAA,EAAQ,aAAA,CAAc,IAAI,CAAC,CAAA;AAAA,MACjF;AAEA,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,GACD,CAAA;AACH;;;;"}
|
|
1
|
+
{"version":3,"file":"instrumentDurableObjectNamespace.js","sources":["../../../../src/instrumentations/instrumentDurableObjectNamespace.ts"],"sourcesContent":["import type { DurableObjectNamespace, DurableObjectStub } from '@cloudflare/workers-types';\nimport { appendRpcMeta } from '../utils/rpcMeta';\nimport { instrumentFetcher } from './worker/instrumentFetcher';\n\n// Built-in DurableObjectStub methods that are not RPC calls.\nexport const STUB_NON_RPC_METHODS = new Set(['fetch', 'connect', 'dup']);\n\n/**\n * Instruments a DurableObjectNamespace binding to create spans for DO interactions.\n *\n * Wraps:\n * - `namespace.get(id)` / `namespace.getByName(name)` with a span + instruments returned stub\n * - `namespace.jurisdiction(name)` by instrumenting the returned namespace the same way\n * - `namespace.idFromName(name)` / `namespace.idFromString(id)` / `namespace.newUniqueId()` with breadcrumbs\n *\n * @param namespace - The DurableObjectNamespace to instrument\n * @param propagateRpcTrace - Whether RPC method calls on the returned stubs carry trace context\n */\nexport function instrumentDurableObjectNamespace(\n namespace: DurableObjectNamespace,\n propagateRpcTrace = false,\n): DurableObjectNamespace {\n return new Proxy(namespace, {\n get(target, prop, _receiver) {\n const value = Reflect.get(target, prop) as unknown;\n\n if (typeof value !== 'function') {\n return value;\n }\n\n if (prop === 'get' || prop === 'getByName') {\n return function (this: unknown, ...args: unknown[]) {\n const stub = Reflect.apply(value, target, args);\n\n return instrumentDurableObjectStub(stub, propagateRpcTrace);\n };\n }\n\n if (prop === 'jurisdiction') {\n return function (this: unknown, ...args: unknown[]) {\n const subnamespace = Reflect.apply(value, target, args);\n\n return instrumentDurableObjectNamespace(subnamespace, propagateRpcTrace);\n };\n }\n\n return value.bind(target);\n },\n });\n}\n\n/**\n * Instruments a DurableObjectStub to create spans for outgoing fetch calls\n * and propagate trace context across RPC calls.\n *\n * @param stub - The DurableObjectStub to instrument\n * @param propagateRpcTrace - Whether RPC method calls carry trace context\n */\nfunction instrumentDurableObjectStub(stub: DurableObjectStub, propagateRpcTrace: boolean): DurableObjectStub {\n return new Proxy(stub, {\n get(target, prop) {\n const value = Reflect.get(target, prop);\n\n if (prop === 'fetch' && typeof value === 'function') {\n return instrumentFetcher((...args) => Reflect.apply(value, target, args));\n }\n\n if (prop === 'connect' && typeof value === 'function') {\n return (...args: unknown[]) => Reflect.apply(value, target, args);\n }\n\n if (\n propagateRpcTrace &&\n typeof value === 'function' &&\n typeof prop === 'string' &&\n !STUB_NON_RPC_METHODS.has(prop)\n ) {\n return (...args: unknown[]) => Reflect.apply(value, target, appendRpcMeta(args));\n }\n\n return value;\n },\n });\n}\n"],"names":[],"mappings":";;;AAKO,MAAM,uCAAuB,IAAI,GAAA,CAAI,CAAC,OAAA,EAAS,SAAA,EAAW,KAAK,CAAC;AAahE,SAAS,gCAAA,CACd,SAAA,EACA,iBAAA,GAAoB,KAAA,EACI;AACxB,EAAA,OAAO,IAAI,MAAM,SAAA,EAAW;AAAA,IAC1B,GAAA,CAAI,MAAA,EAAQ,IAAA,EAAM,SAAA,EAAW;AAC3B,MAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,GAAA,CAAI,MAAA,EAAQ,IAAI,CAAA;AAEtC,MAAA,IAAI,OAAO,UAAU,UAAA,EAAY;AAC/B,QAAA,OAAO,KAAA;AAAA,MACT;AAEA,MAAA,IAAI,IAAA,KAAS,KAAA,IAAS,IAAA,KAAS,WAAA,EAAa;AAC1C,QAAA,OAAO,YAA4B,IAAA,EAAiB;AAClD,UAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,KAAA,CAAM,KAAA,EAAO,QAAQ,IAAI,CAAA;AAE9C,UAAA,OAAO,2BAAA,CAA4B,MAAM,iBAAiB,CAAA;AAAA,QAC5D,CAAA;AAAA,MACF;AAEA,MAAA,IAAI,SAAS,cAAA,EAAgB;AAC3B,QAAA,OAAO,YAA4B,IAAA,EAAiB;AAClD,UAAA,MAAM,YAAA,GAAe,OAAA,CAAQ,KAAA,CAAM,KAAA,EAAO,QAAQ,IAAI,CAAA;AAEtD,UAAA,OAAO,gCAAA,CAAiC,cAAc,iBAAiB,CAAA;AAAA,QACzE,CAAA;AAAA,MACF;AAEA,MAAA,OAAO,KAAA,CAAM,KAAK,MAAM,CAAA;AAAA,IAC1B;AAAA,GACD,CAAA;AACH;AASA,SAAS,2BAAA,CAA4B,MAAyB,iBAAA,EAA+C;AAC3G,EAAA,OAAO,IAAI,MAAM,IAAA,EAAM;AAAA,IACrB,GAAA,CAAI,QAAQ,IAAA,EAAM;AAChB,MAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,GAAA,CAAI,MAAA,EAAQ,IAAI,CAAA;AAEtC,MAAA,IAAI,IAAA,KAAS,OAAA,IAAW,OAAO,KAAA,KAAU,UAAA,EAAY;AACnD,QAAA,OAAO,iBAAA,CAAkB,IAAI,IAAA,KAAS,OAAA,CAAQ,MAAM,KAAA,EAAO,MAAA,EAAQ,IAAI,CAAC,CAAA;AAAA,MAC1E;AAEA,MAAA,IAAI,IAAA,KAAS,SAAA,IAAa,OAAO,KAAA,KAAU,UAAA,EAAY;AACrD,QAAA,OAAO,IAAI,IAAA,KAAoB,OAAA,CAAQ,KAAA,CAAM,KAAA,EAAO,QAAQ,IAAI,CAAA;AAAA,MAClE;AAEA,MAAA,IACE,iBAAA,IACA,OAAO,KAAA,KAAU,UAAA,IACjB,OAAO,IAAA,KAAS,QAAA,IAChB,CAAC,oBAAA,CAAqB,GAAA,CAAI,IAAI,CAAA,EAC9B;AACA,QAAA,OAAO,CAAA,GAAI,SAAoB,OAAA,CAAQ,KAAA,CAAM,OAAO,MAAA,EAAQ,aAAA,CAAc,IAAI,CAAC,CAAA;AAAA,MACjF;AAEA,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,GACD,CAAA;AACH;;;;"}
|
|
@@ -63,6 +63,9 @@ function instrumentEnv(env, options) {
|
|
|
63
63
|
if (p === "fetch" && typeof value === "function") {
|
|
64
64
|
return instrumentFetcher((...args) => Reflect.apply(value, target2, args));
|
|
65
65
|
}
|
|
66
|
+
if (p === "connect" && typeof value === "function") {
|
|
67
|
+
return (...args) => Reflect.apply(value, target2, args);
|
|
68
|
+
}
|
|
66
69
|
if (propagateRpcTrace && typeof value === "function" && typeof p === "string" && !STUB_NON_RPC_METHODS.has(p)) {
|
|
67
70
|
return (...args) => Reflect.apply(value, target2, appendRpcMeta(args));
|
|
68
71
|
}
|