@sentry/cloudflare 10.64.0 → 10.66.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.
Files changed (73) hide show
  1. package/build/cjs/client.js.map +1 -1
  2. package/build/cjs/durableobject.js +2 -2
  3. package/build/cjs/durableobject.js.map +1 -1
  4. package/build/cjs/flush.js.map +1 -1
  5. package/build/cjs/instrument.js +3 -1
  6. package/build/cjs/instrument.js.map +1 -1
  7. package/build/cjs/instrumentations/worker/instrumentEnv.js +2 -1
  8. package/build/cjs/instrumentations/worker/instrumentEnv.js.map +1 -1
  9. package/build/cjs/instrumentations/worker/instrumentQueueProducer.js.map +1 -1
  10. package/build/cjs/instrumentations/worker/instrumentR2.js +1 -1
  11. package/build/cjs/instrumentations/worker/instrumentR2.js.map +1 -1
  12. package/build/cjs/integrations/hono.js +1 -1
  13. package/build/cjs/integrations/hono.js.map +1 -1
  14. package/build/cjs/options.js +2 -2
  15. package/build/cjs/options.js.map +1 -1
  16. package/build/cjs/pages-plugin.js +2 -4
  17. package/build/cjs/pages-plugin.js.map +1 -1
  18. package/build/cjs/request.js.map +1 -1
  19. package/build/cjs/utils/rpcMeta.js +2 -3
  20. package/build/cjs/utils/rpcMeta.js.map +1 -1
  21. package/build/cjs/workflows.js +11 -5
  22. package/build/cjs/workflows.js.map +1 -1
  23. package/build/cjs/wrapMethodWithSentry.js +1 -1
  24. package/build/cjs/wrapMethodWithSentry.js.map +1 -1
  25. package/build/esm/client.js.map +1 -1
  26. package/build/esm/durableobject.js +2 -2
  27. package/build/esm/durableobject.js.map +1 -1
  28. package/build/esm/flush.js.map +1 -1
  29. package/build/esm/instrument.js +3 -1
  30. package/build/esm/instrument.js.map +1 -1
  31. package/build/esm/instrumentations/worker/instrumentEnv.js +2 -1
  32. package/build/esm/instrumentations/worker/instrumentEnv.js.map +1 -1
  33. package/build/esm/instrumentations/worker/instrumentQueueProducer.js.map +1 -1
  34. package/build/esm/instrumentations/worker/instrumentR2.js +2 -2
  35. package/build/esm/instrumentations/worker/instrumentR2.js.map +1 -1
  36. package/build/esm/integrations/hono.js +2 -2
  37. package/build/esm/integrations/hono.js.map +1 -1
  38. package/build/esm/options.js +3 -3
  39. package/build/esm/options.js.map +1 -1
  40. package/build/esm/package.json +1 -1
  41. package/build/esm/pages-plugin.js +2 -4
  42. package/build/esm/pages-plugin.js.map +1 -1
  43. package/build/esm/request.js.map +1 -1
  44. package/build/esm/utils/rpcMeta.js +3 -4
  45. package/build/esm/utils/rpcMeta.js.map +1 -1
  46. package/build/esm/workflows.js +11 -5
  47. package/build/esm/workflows.js.map +1 -1
  48. package/build/esm/wrapMethodWithSentry.js +2 -2
  49. package/build/esm/wrapMethodWithSentry.js.map +1 -1
  50. package/build/types/client.d.ts +2 -1
  51. package/build/types/client.d.ts.map +1 -1
  52. package/build/types/durableobject.d.ts.map +1 -1
  53. package/build/types/executionContext.d.ts +13 -0
  54. package/build/types/executionContext.d.ts.map +1 -0
  55. package/build/types/flush.d.ts +3 -2
  56. package/build/types/flush.d.ts.map +1 -1
  57. package/build/types/instrument.d.ts.map +1 -1
  58. package/build/types/instrumentations/worker/instrumentEnv.d.ts.map +1 -1
  59. package/build/types/integrations/hono.d.ts.map +1 -1
  60. package/build/types/pages-plugin.d.ts.map +1 -1
  61. package/build/types/request.d.ts +3 -2
  62. package/build/types/request.d.ts.map +1 -1
  63. package/build/types/utils/rpcMeta.d.ts.map +1 -1
  64. package/build/types/workflows.d.ts.map +1 -1
  65. package/build/types/wrapMethodWithSentry.d.ts.map +1 -1
  66. package/build/types-ts3.8/client.d.ts +2 -1
  67. package/build/types-ts3.8/executionContext.d.ts +13 -0
  68. package/build/types-ts3.8/flush.d.ts +3 -2
  69. package/build/types-ts3.8/request.d.ts +3 -2
  70. package/package.json +6 -6
  71. package/build/types/utils/addOriginToSpan.d.ts +0 -5
  72. package/build/types/utils/addOriginToSpan.d.ts.map +0 -1
  73. package/build/types-ts3.8/utils/addOriginToSpan.d.ts +0 -5
@@ -28,10 +28,12 @@ class WrappedWorkflowStep {
28
28
  this._step = _step;
29
29
  this._waitUntil = _waitUntil;
30
30
  }
31
- async do(name, configOrCallback, maybeCallback) {
31
+ async do(name, configOrCallback, callbackOrRollback, maybeRollback) {
32
32
  const scopeForStep = core.getCurrentScope();
33
- const userCallback = maybeCallback || configOrCallback;
34
- const config = typeof configOrCallback === "function" ? void 0 : configOrCallback;
33
+ const hasConfig = typeof configOrCallback !== "function";
34
+ const config = hasConfig ? configOrCallback : void 0;
35
+ const userCallback = hasConfig ? callbackOrRollback : configOrCallback;
36
+ const rollbackOptions = hasConfig ? maybeRollback : callbackOrRollback;
35
37
  const instrumentedCallback = async (...args) => {
36
38
  const stepContext = args[0];
37
39
  const attempt = stepContext?.attempt;
@@ -46,7 +48,8 @@ class WrappedWorkflowStep {
46
48
  attributes: {
47
49
  "cloudflare.workflow.timeout": config?.timeout,
48
50
  "cloudflare.workflow.retries.backoff": config?.retries?.backoff,
49
- "cloudflare.workflow.retries.delay": config?.retries?.delay,
51
+ // In workers-types v5, `delay` may be a `WorkflowDelayFunction`, which isn't a valid span attribute value.
52
+ "cloudflare.workflow.retries.delay": typeof config?.retries?.delay === "function" ? void 0 : config?.retries?.delay,
50
53
  "cloudflare.workflow.retries.limit": config?.retries?.limit,
51
54
  "cloudflare.workflow.attempt": attempt,
52
55
  [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.faas.cloudflare.workflow",
@@ -69,7 +72,10 @@ class WrappedWorkflowStep {
69
72
  }
70
73
  );
71
74
  };
72
- return config ? this._step.do(name, config, instrumentedCallback) : this._step.do(name, instrumentedCallback);
75
+ if (config) {
76
+ return rollbackOptions ? this._step.do(name, config, instrumentedCallback, rollbackOptions) : this._step.do(name, config, instrumentedCallback);
77
+ }
78
+ return rollbackOptions ? this._step.do(name, instrumentedCallback, rollbackOptions) : this._step.do(name, instrumentedCallback);
73
79
  }
74
80
  async sleep(name, duration) {
75
81
  return this._step.sleep(name, duration);
@@ -1 +1 @@
1
- {"version":3,"file":"workflows.js","sources":["../../src/workflows.ts"],"sourcesContent":["import type { PropagationContext } from '@sentry/core';\nimport {\n captureException,\n flush,\n getCurrentScope,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n startSpan,\n withIsolationScope,\n withScope,\n} from '@sentry/core';\nimport type {\n WorkflowEntrypoint,\n WorkflowEvent,\n WorkflowSleepDuration,\n WorkflowStep,\n WorkflowStepConfig,\n WorkflowStepEvent,\n WorkflowTimeoutDuration,\n} from 'cloudflare:workers';\nimport { setAsyncLocalStorageAsyncContextStrategy } from './async';\nimport type { CloudflareOptions } from './client';\nimport { flushAndDispose } from './flush';\nimport { instrumentEnv } from './instrumentations/worker/instrumentEnv';\nimport { addCloudResourceContext } from './scope-utils';\nimport { init } from './sdk';\nimport { instrumentContext } from './utils/instrumentContext';\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 ) {}\n\n public async do<T extends Rpc.Serializable<T>>(\n name: string,\n callback: (...args: unknown[]) => Promise<T>,\n ): Promise<T>;\n public async do<T extends Rpc.Serializable<T>>(\n name: string,\n config: WorkflowStepConfig,\n callback: (...args: unknown[]) => Promise<T>,\n ): Promise<T>;\n public async do<T extends Rpc.Serializable<T>>(\n name: string,\n configOrCallback: WorkflowStepConfig | (() => Promise<T>),\n maybeCallback?: (...args: unknown[]) => Promise<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 userCallback = (maybeCallback || configOrCallback) as (...args: unknown[]) => Promise<T>;\n const config = typeof configOrCallback === 'function' ? undefined : configOrCallback;\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 return startSpan(\n {\n op: 'function.step.do',\n name,\n scope: scopeForStep,\n attributes: {\n 'cloudflare.workflow.timeout': config?.timeout,\n 'cloudflare.workflow.retries.backoff': config?.retries?.backoff,\n 'cloudflare.workflow.retries.delay': 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 [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'task',\n },\n },\n async span => {\n try {\n const result = await userCallback(...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 } finally {\n this._waitUntil(flush(2000));\n }\n },\n );\n };\n\n return config ? this._step.do(name, config, instrumentedCallback) : 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, // Environment type\n P, // Payload type\n T extends WorkflowEntrypoint<E, P>, // WorkflowEntrypoint type\n C extends new (ctx: ExecutionContext, env: E) => T, // Constructor type of the WorkflowEntrypoint class\n>(optionsCallback: (env: E) => CloudflareOptions, WorkFlowClass: C): C {\n return new Proxy(WorkFlowClass, {\n construct(target: C, args: [ctx: ExecutionContext, env: E], 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 withIsolationScope(async isolationScope => {\n const waitUntil = context.waitUntil.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),\n );\n } finally {\n waitUntil(flushAndDispose(client));\n }\n });\n });\n };\n }\n return Reflect.get(obj, prop, receiver);\n },\n });\n },\n });\n}\n"],"names":["getCurrentScope","startSpan","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","SEMANTIC_ATTRIBUTE_SENTRY_SOURCE","captureException","flush","instrumentContext","instrumentEnv","setAsyncLocalStorageAsyncContextStrategy","withIsolationScope","init","addCloudResourceContext","withScope","flushAndDispose"],"mappings":"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"}
1
+ {"version":3,"file":"workflows.js","sources":["../../src/workflows.ts"],"sourcesContent":["import type { PropagationContext } from '@sentry/core';\nimport {\n captureException,\n flush,\n getCurrentScope,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\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 './async';\nimport type { CloudflareOptions } from './client';\nimport { flushAndDispose } from './flush';\nimport { instrumentEnv } from './instrumentations/worker/instrumentEnv';\nimport { addCloudResourceContext } from './scope-utils';\nimport { init } from './sdk';\nimport { instrumentContext } from './utils/instrumentContext';\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 ) {}\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 return startSpan(\n {\n op: 'function.step.do',\n name,\n scope: scopeForStep,\n attributes: {\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 [SEMANTIC_ATTRIBUTE_SENTRY_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 } finally {\n this._waitUntil(flush(2000));\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, // Environment type\n P, // Payload type\n T extends WorkflowEntrypoint<E, P>, // WorkflowEntrypoint type\n C extends new (ctx: ExecutionContext, env: E) => T, // Constructor type of the WorkflowEntrypoint class\n>(optionsCallback: (env: E) => CloudflareOptions, WorkFlowClass: C): C {\n return new Proxy(WorkFlowClass, {\n construct(target: C, args: [ctx: ExecutionContext, env: E], 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 withIsolationScope(async isolationScope => {\n const waitUntil = context.waitUntil.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),\n );\n } finally {\n waitUntil(flushAndDispose(client));\n }\n });\n });\n };\n }\n return Reflect.get(obj, prop, receiver);\n },\n });\n },\n });\n}\n"],"names":["getCurrentScope","startSpan","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","SEMANTIC_ATTRIBUTE_SENTRY_SOURCE","captureException","flush","instrumentContext","instrumentEnv","setAsyncLocalStorageAsyncContextStrategy","withIsolationScope","init","addCloudResourceContext","withScope","flushAndDispose"],"mappings":"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"}
@@ -8,7 +8,7 @@ const rpcMeta = require('./utils/rpcMeta.js');
8
8
  const traceLinks = require('./utils/traceLinks.js');
9
9
 
10
10
  function resolveOriginalStorage(context, thisArg) {
11
- if (thisArg && typeof thisArg === "object" && "ctx" in thisArg) {
11
+ if (core.isObjectLike(thisArg) && "ctx" in thisArg) {
12
12
  const doCtx = thisArg.ctx;
13
13
  if (doCtx?.originalStorage) {
14
14
  return doCtx.originalStorage;
@@ -1 +1 @@
1
- {"version":3,"file":"wrapMethodWithSentry.js","sources":["../../src/wrapMethodWithSentry.ts"],"sourcesContent":["import type { DurableObjectStorage } from '@cloudflare/workers-types';\nimport type { SerializedTraceData } from '@sentry/core';\nimport {\n captureException,\n continueTrace,\n getClient,\n isThenable,\n type Scope,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n startNewTrace as startNewTraceCore,\n startSpan,\n withIsolationScope,\n withScope,\n} from '@sentry/core';\nimport type { CloudflareOptions } from './client';\nimport { flushAndDispose } from './flush';\nimport { ensureInstrumented } from './instrument';\nimport { init } from './sdk';\nimport { extractRpcMeta } from './utils/rpcMeta';\nimport { buildSpanLinks, getStoredSpanContext, storeSpanContext } from './utils/traceLinks';\n\n/** Extended DurableObjectState with originalStorage exposed by instrumentContext */\ninterface InstrumentedDurableObjectState extends DurableObjectState {\n originalStorage?: DurableObjectStorage;\n}\n\n/**\n * Resolves uninstrumented DO storage for the current invocation.\n * Prefer `thisArg.ctx` (the live Durable Object instance) over the context captured at\n * construction time to avoid cross-DO I/O errors in the same isolate.\n */\nfunction resolveOriginalStorage(\n context: ExecutionContext | InstrumentedDurableObjectState | undefined,\n thisArg: unknown,\n): DurableObjectStorage | undefined {\n if (thisArg && typeof thisArg === 'object' && 'ctx' in thisArg) {\n const doCtx = (thisArg as { ctx: InstrumentedDurableObjectState }).ctx;\n if (doCtx?.originalStorage) {\n return doCtx.originalStorage;\n }\n }\n\n if (context && 'originalStorage' in context && context.originalStorage) {\n return context.originalStorage;\n }\n\n return undefined;\n}\n\ntype MethodWrapperOptions = {\n spanName?: string;\n spanOp?: string;\n options: CloudflareOptions;\n context: ExecutionContext | InstrumentedDurableObjectState;\n /**\n * If true, starts a fresh trace instead of inheriting from a parent trace.\n * Useful for scheduled/independent invocations like alarms.\n *\n * If true, it also stores the current span context and links to the previous invocation's span.\n * Uses Durable Object storage to persist the link. The link is set asynchronously via `span.addLinks()`\n * in a `waitUntil` to avoid blocking.\n *\n * @default false\n */\n startNewTrace?: boolean;\n};\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type UncheckedMethod = (...args: any[]) => any;\ntype OriginalMethod = UncheckedMethod;\n\n/**\n * Wraps a method with Sentry error tracking and optional tracing.\n * Supports starting new traces and linking to previous invocations via Durable Object storage.\n *\n * @param wrapperOptions - The options for the wrapper.\n * @param handler - The method to wrap.\n * @param callback - The callback to call.\n * @param noMark - Whether to mark the method as instrumented.\n * @returns The wrapped method.\n */\nexport function wrapMethodWithSentry<T extends OriginalMethod>(\n wrapperOptions: MethodWrapperOptions,\n handler: T,\n callback?: (...args: Parameters<T>) => void,\n noMark?: true,\n): T {\n return ensureInstrumented(\n handler,\n original =>\n new Proxy(original, {\n apply(target, thisArg, rawArgs: Parameters<T>) {\n const { startNewTrace } = wrapperOptions;\n\n // For RPC methods, extract Sentry trace context from the trailing argument.\n // The caller side (instrumentDurableObjectStub / JSRPC proxy) appends it;\n // we strip it here so the user's method never sees it.\n let args = rawArgs;\n let rpcMeta: SerializedTraceData | undefined;\n\n if (wrapperOptions.spanOp === 'rpc') {\n const extracted = extractRpcMeta(rawArgs);\n args = extracted.args;\n rpcMeta = extracted.rpcMeta;\n }\n\n // For startNewTrace, always use withIsolationScope to ensure a fresh scope\n // Otherwise, use existing client's scope or isolation scope\n const currentClient = getClient();\n const sentryWithScope = startNewTrace ? withIsolationScope : currentClient ? withScope : withIsolationScope;\n\n const wrappedFunction = (scope: Scope): unknown | Promise<unknown> => {\n // In certain situations, the passed context can become undefined.\n // For example, for Astro while prerendering pages at build time.\n // see: https://github.com/getsentry/sentry-javascript/issues/13217\n const context: typeof wrapperOptions.context | undefined = wrapperOptions.context;\n\n const waitUntil = context?.waitUntil?.bind?.(context);\n const storage = resolveOriginalStorage(context, thisArg);\n\n let scopeClient = scope.getClient();\n // Check if client exists AND is still usable (transport not disposed)\n // This handles the case where a previous handler disposed the client\n // but the scope still holds a reference to it (e.g., alarm handlers in Durable Objects)\n // For startNewTrace, always create a fresh client\n if (startNewTrace || !scopeClient?.getTransport()) {\n const client = init({\n ...wrapperOptions.options,\n ctx: context as unknown as ExecutionContext | undefined,\n });\n scope.setClient(client);\n scopeClient = client;\n }\n\n const clientToDispose = scopeClient;\n const methodName = wrapperOptions.spanName || 'unknown';\n\n const teardown = async (): Promise<void> => {\n if (startNewTrace && storage) {\n storeSpanContext(storage, methodName);\n }\n await flushAndDispose(clientToDispose);\n };\n\n const onFulfilled = (res: unknown) => {\n waitUntil?.(teardown());\n return res;\n };\n\n const onRejected = (e: unknown) => {\n captureException(e, {\n mechanism: {\n type: 'auto.faas.cloudflare.durable_object',\n handled: false,\n },\n });\n waitUntil?.(teardown());\n throw e;\n };\n\n if (!wrapperOptions.spanName) {\n try {\n if (callback) {\n callback(...args);\n }\n\n const result = Reflect.apply(target, thisArg, args);\n\n if (isThenable(result)) {\n return result.then(onFulfilled, onRejected);\n } else {\n return onFulfilled(result);\n }\n } catch (e) {\n return onRejected(e);\n }\n }\n\n const attributes = wrapperOptions.spanOp\n ? {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: wrapperOptions.spanOp,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.faas.cloudflare.durable_object',\n }\n : {};\n\n const executeSpan = (): unknown => {\n return startSpan({ name: methodName, attributes }, span => {\n if (startNewTrace && storage) {\n const storedContext = getStoredSpanContext(storage, methodName);\n\n if (storedContext) {\n span.addLinks(buildSpanLinks(storedContext));\n // TODO: Remove this once EAP can store span links. We currently only set this attribute so that we\n // can obtain the previous trace information from the EAP store. Long-term, EAP will handle\n // span links and then we should remove this again. Also throwing in a TODO(v11), to remind us\n // to check this at v11 time :)\n const sampledFlag = storedContext.sampled ? '1' : '0';\n span.setAttribute(\n 'sentry.previous_trace',\n `${storedContext.traceId}-${storedContext.spanId}-${sampledFlag}`,\n );\n }\n }\n\n try {\n const result = Reflect.apply(target, thisArg, args);\n\n if (isThenable(result)) {\n return result.then(onFulfilled, onRejected);\n } else {\n return onFulfilled(result);\n }\n } catch (e) {\n return onRejected(e);\n }\n });\n };\n\n if (rpcMeta) {\n return continueTrace(\n { sentryTrace: rpcMeta['sentry-trace'] || '', baggage: rpcMeta.baggage || '' },\n executeSpan,\n );\n }\n\n if (startNewTrace) {\n return startNewTraceCore(() => executeSpan());\n }\n\n return executeSpan();\n };\n\n return sentryWithScope(wrappedFunction);\n },\n }),\n noMark,\n );\n}\n"],"names":["ensureInstrumented","rpcMeta","extractRpcMeta","getClient","withIsolationScope","withScope","init","storeSpanContext","flushAndDispose","captureException","isThenable","SEMANTIC_ATTRIBUTE_SENTRY_OP","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","startSpan","getStoredSpanContext","buildSpanLinks","continueTrace","startNewTraceCore"],"mappings":"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"}
1
+ {"version":3,"file":"wrapMethodWithSentry.js","sources":["../../src/wrapMethodWithSentry.ts"],"sourcesContent":["import type { DurableObjectStorage } from '@cloudflare/workers-types';\nimport type { SerializedTraceData } from '@sentry/core';\nimport {\n isObjectLike,\n captureException,\n continueTrace,\n getClient,\n isThenable,\n type Scope,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n startNewTrace as startNewTraceCore,\n startSpan,\n withIsolationScope,\n withScope,\n} from '@sentry/core';\nimport type { CloudflareOptions } from './client';\nimport { flushAndDispose } from './flush';\nimport { ensureInstrumented } from './instrument';\nimport { init } from './sdk';\nimport { extractRpcMeta } from './utils/rpcMeta';\nimport { buildSpanLinks, getStoredSpanContext, storeSpanContext } from './utils/traceLinks';\n\n/** Extended DurableObjectState with originalStorage exposed by instrumentContext */\ninterface InstrumentedDurableObjectState extends DurableObjectState {\n originalStorage?: DurableObjectStorage;\n}\n\n/**\n * Resolves uninstrumented DO storage for the current invocation.\n * Prefer `thisArg.ctx` (the live Durable Object instance) over the context captured at\n * construction time to avoid cross-DO I/O errors in the same isolate.\n */\nfunction resolveOriginalStorage(\n context: ExecutionContext | InstrumentedDurableObjectState | undefined,\n thisArg: unknown,\n): DurableObjectStorage | undefined {\n if (isObjectLike(thisArg) && 'ctx' in thisArg) {\n const doCtx = (thisArg as { ctx: InstrumentedDurableObjectState }).ctx;\n if (doCtx?.originalStorage) {\n return doCtx.originalStorage;\n }\n }\n\n if (context && 'originalStorage' in context && context.originalStorage) {\n return context.originalStorage;\n }\n\n return undefined;\n}\n\ntype MethodWrapperOptions = {\n spanName?: string;\n spanOp?: string;\n options: CloudflareOptions;\n context: ExecutionContext | InstrumentedDurableObjectState;\n /**\n * If true, starts a fresh trace instead of inheriting from a parent trace.\n * Useful for scheduled/independent invocations like alarms.\n *\n * If true, it also stores the current span context and links to the previous invocation's span.\n * Uses Durable Object storage to persist the link. The link is set asynchronously via `span.addLinks()`\n * in a `waitUntil` to avoid blocking.\n *\n * @default false\n */\n startNewTrace?: boolean;\n};\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type UncheckedMethod = (...args: any[]) => any;\ntype OriginalMethod = UncheckedMethod;\n\n/**\n * Wraps a method with Sentry error tracking and optional tracing.\n * Supports starting new traces and linking to previous invocations via Durable Object storage.\n *\n * @param wrapperOptions - The options for the wrapper.\n * @param handler - The method to wrap.\n * @param callback - The callback to call.\n * @param noMark - Whether to mark the method as instrumented.\n * @returns The wrapped method.\n */\nexport function wrapMethodWithSentry<T extends OriginalMethod>(\n wrapperOptions: MethodWrapperOptions,\n handler: T,\n callback?: (...args: Parameters<T>) => void,\n noMark?: true,\n): T {\n return ensureInstrumented(\n handler,\n original =>\n new Proxy(original, {\n apply(target, thisArg, rawArgs: Parameters<T>) {\n const { startNewTrace } = wrapperOptions;\n\n // For RPC methods, extract Sentry trace context from the trailing argument.\n // The caller side (instrumentDurableObjectStub / JSRPC proxy) appends it;\n // we strip it here so the user's method never sees it.\n let args = rawArgs;\n let rpcMeta: SerializedTraceData | undefined;\n\n if (wrapperOptions.spanOp === 'rpc') {\n const extracted = extractRpcMeta(rawArgs);\n args = extracted.args;\n rpcMeta = extracted.rpcMeta;\n }\n\n // For startNewTrace, always use withIsolationScope to ensure a fresh scope\n // Otherwise, use existing client's scope or isolation scope\n const currentClient = getClient();\n const sentryWithScope = startNewTrace ? withIsolationScope : currentClient ? withScope : withIsolationScope;\n\n const wrappedFunction = (scope: Scope): unknown | Promise<unknown> => {\n // In certain situations, the passed context can become undefined.\n // For example, for Astro while prerendering pages at build time.\n // see: https://github.com/getsentry/sentry-javascript/issues/13217\n const context: typeof wrapperOptions.context | undefined = wrapperOptions.context;\n\n const waitUntil = context?.waitUntil?.bind?.(context);\n const storage = resolveOriginalStorage(context, thisArg);\n\n let scopeClient = scope.getClient();\n // Check if client exists AND is still usable (transport not disposed)\n // This handles the case where a previous handler disposed the client\n // but the scope still holds a reference to it (e.g., alarm handlers in Durable Objects)\n // For startNewTrace, always create a fresh client\n if (startNewTrace || !scopeClient?.getTransport()) {\n const client = init({\n ...wrapperOptions.options,\n ctx: context as unknown as ExecutionContext | undefined,\n });\n scope.setClient(client);\n scopeClient = client;\n }\n\n const clientToDispose = scopeClient;\n const methodName = wrapperOptions.spanName || 'unknown';\n\n const teardown = async (): Promise<void> => {\n if (startNewTrace && storage) {\n storeSpanContext(storage, methodName);\n }\n await flushAndDispose(clientToDispose);\n };\n\n const onFulfilled = (res: unknown) => {\n waitUntil?.(teardown());\n return res;\n };\n\n const onRejected = (e: unknown) => {\n captureException(e, {\n mechanism: {\n type: 'auto.faas.cloudflare.durable_object',\n handled: false,\n },\n });\n waitUntil?.(teardown());\n throw e;\n };\n\n if (!wrapperOptions.spanName) {\n try {\n if (callback) {\n callback(...args);\n }\n\n const result = Reflect.apply(target, thisArg, args);\n\n if (isThenable(result)) {\n return result.then(onFulfilled, onRejected);\n } else {\n return onFulfilled(result);\n }\n } catch (e) {\n return onRejected(e);\n }\n }\n\n const attributes = wrapperOptions.spanOp\n ? {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: wrapperOptions.spanOp,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.faas.cloudflare.durable_object',\n }\n : {};\n\n const executeSpan = (): unknown => {\n return startSpan({ name: methodName, attributes }, span => {\n if (startNewTrace && storage) {\n const storedContext = getStoredSpanContext(storage, methodName);\n\n if (storedContext) {\n span.addLinks(buildSpanLinks(storedContext));\n // TODO: Remove this once EAP can store span links. We currently only set this attribute so that we\n // can obtain the previous trace information from the EAP store. Long-term, EAP will handle\n // span links and then we should remove this again. Also throwing in a TODO(v11), to remind us\n // to check this at v11 time :)\n const sampledFlag = storedContext.sampled ? '1' : '0';\n span.setAttribute(\n 'sentry.previous_trace',\n `${storedContext.traceId}-${storedContext.spanId}-${sampledFlag}`,\n );\n }\n }\n\n try {\n const result = Reflect.apply(target, thisArg, args);\n\n if (isThenable(result)) {\n return result.then(onFulfilled, onRejected);\n } else {\n return onFulfilled(result);\n }\n } catch (e) {\n return onRejected(e);\n }\n });\n };\n\n if (rpcMeta) {\n return continueTrace(\n { sentryTrace: rpcMeta['sentry-trace'] || '', baggage: rpcMeta.baggage || '' },\n executeSpan,\n );\n }\n\n if (startNewTrace) {\n return startNewTraceCore(() => executeSpan());\n }\n\n return executeSpan();\n };\n\n return sentryWithScope(wrappedFunction);\n },\n }),\n noMark,\n );\n}\n"],"names":["isObjectLike","ensureInstrumented","rpcMeta","extractRpcMeta","getClient","withIsolationScope","withScope","init","storeSpanContext","flushAndDispose","captureException","isThenable","SEMANTIC_ATTRIBUTE_SENTRY_OP","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","startSpan","getStoredSpanContext","buildSpanLinks","continueTrace","startNewTraceCore"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sources":["../../src/client.ts"],"sourcesContent":["import type { ClientOptions, Options, ServerRuntimeClientOptions } from '@sentry/core';\nimport { applySdkMetadata, debug, ServerRuntimeClient, spanIsSampled } from '@sentry/core';\nimport { DEBUG_BUILD } from './debug-build';\nimport type { makeFlushLock } from './flush';\nimport type { CloudflareTransportOptions } from './transport';\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 /**\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\n // Track span lifecycle to know when to flush\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, resolving promise');\n this._resolveSpanCompletion();\n this._resetSpanCompletionPromise();\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 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 return super.flush(timeout);\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 /**\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\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, however, we set up some OpenTelemetry compatibility\n * via a custom trace provider.\n * This ensures that any spans emitted via `@opentelemetry/api` will be captured by Sentry.\n * HOWEVER, big caveat: This does not handle custom context handling, it will always work off the current scope.\n * This should be good enough for many, but not all integrations.\n *\n * If you want to opt-out of setting up the OpenTelemetry compatibility tracer, set this to `true`.\n *\n * @default false\n */\n skipOpenTelemetrySetup?: boolean;\n\n /**\n * Enable trace propagation for RPC calls between Workers, Durable Objects, and Service Bindings.\n *\n * When enabled, trace context (sentry-trace + baggage) is propagated across:\n * - `stub.fetch()` calls to Durable Objects (via HTTP headers)\n * - Service binding `fetch()` calls (via HTTP headers)\n * - RPC method calls to Durable Objects (via trailing argument)\n *\n * When enabled on the **receiver side** (DurableObject), the SDK will also:\n * - Extract and continue traces from incoming RPC calls\n * - Create spans for each RPC method invocation\n * - Capture errors thrown by RPC methods\n *\n * **Important:** This option should be enabled on **both sides** for full trace propagation.\n *\n * @default false\n * @example\n * ```ts\n * // Worker side (caller)\n * export default Sentry.withSentry(\n * (env) => ({\n * dsn: env.SENTRY_DSN,\n * enableRpcTracePropagation: true,\n * }),\n * handler,\n * );\n *\n * // Durable Object side (receiver)\n * export const MyDO = Sentry.instrumentDurableObjectWithSentry(\n * (env) => ({\n * dsn: env.SENTRY_DSN,\n * enableRpcTracePropagation: true,\n * }),\n * MyDOBase,\n * );\n * ```\n */\n enableRpcTracePropagation?: boolean;\n\n /**\n * @deprecated Use `enableRpcTracePropagation` instead. This option will be removed in a future major version.\n *\n * Enable instrumentation of prototype methods for DurableObjects.\n *\n * When `true`, the SDK will wrap all methods on the DurableObject prototype chain\n * to automatically create spans and capture errors for RPC method calls.\n *\n * When an array of strings is provided, only the specified method names will be instrumented.\n *\n * @default false\n */\n instrumentPrototypeMethods?: boolean | string[];\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?: ExecutionContext;\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, ServerRuntimeClientOptions } from '@sentry/core';\nimport { applySdkMetadata, debug, ServerRuntimeClient, spanIsSampled } from '@sentry/core';\nimport { DEBUG_BUILD } from './debug-build';\nimport type { ExecutionContextCompat } from './executionContext';\nimport type { makeFlushLock } from './flush';\nimport type { CloudflareTransportOptions } from './transport';\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 /**\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\n // Track span lifecycle to know when to flush\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, resolving promise');\n this._resolveSpanCompletion();\n this._resetSpanCompletionPromise();\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 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 return super.flush(timeout);\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 /**\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\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, however, we set up some OpenTelemetry compatibility\n * via a custom trace provider.\n * This ensures that any spans emitted via `@opentelemetry/api` will be captured by Sentry.\n * HOWEVER, big caveat: This does not handle custom context handling, it will always work off the current scope.\n * This should be good enough for many, but not all integrations.\n *\n * If you want to opt-out of setting up the OpenTelemetry compatibility tracer, set this to `true`.\n *\n * @default false\n */\n skipOpenTelemetrySetup?: boolean;\n\n /**\n * Enable trace propagation for RPC calls between Workers, Durable Objects, and Service Bindings.\n *\n * When enabled, trace context (sentry-trace + baggage) is propagated across:\n * - `stub.fetch()` calls to Durable Objects (via HTTP headers)\n * - Service binding `fetch()` calls (via HTTP headers)\n * - RPC method calls to Durable Objects (via trailing argument)\n *\n * When enabled on the **receiver side** (DurableObject), the SDK will also:\n * - Extract and continue traces from incoming RPC calls\n * - Create spans for each RPC method invocation\n * - Capture errors thrown by RPC methods\n *\n * **Important:** This option should be enabled on **both sides** for full trace propagation.\n *\n * @default false\n * @example\n * ```ts\n * // Worker side (caller)\n * export default Sentry.withSentry(\n * (env) => ({\n * dsn: env.SENTRY_DSN,\n * enableRpcTracePropagation: true,\n * }),\n * handler,\n * );\n *\n * // Durable Object side (receiver)\n * export const MyDO = Sentry.instrumentDurableObjectWithSentry(\n * (env) => ({\n * dsn: env.SENTRY_DSN,\n * enableRpcTracePropagation: true,\n * }),\n * MyDOBase,\n * );\n * ```\n */\n enableRpcTracePropagation?: boolean;\n\n /**\n * @deprecated Use `enableRpcTracePropagation` instead. This option will be removed in a future major version.\n *\n * Enable instrumentation of prototype methods for DurableObjects.\n *\n * When `true`, the SDK will wrap all methods on the DurableObject prototype chain\n * to automatically create spans and capture errors for RPC method calls.\n *\n * When an array of strings is provided, only the specified method names will be instrumented.\n *\n * @default false\n */\n instrumentPrototypeMethods?: boolean | string[];\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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"}
@@ -11,12 +11,12 @@ import { wrapMethodWithSentry } from './wrapMethodWithSentry.js';
11
11
 
12
12
  function instrumentDurableObjectWithSentry(optionsCallback, DurableObjectClass) {
13
13
  return new Proxy(DurableObjectClass, {
14
- construct(target, [ctx, env]) {
14
+ construct(target, [ctx, env], newTarget) {
15
15
  setAsyncLocalStorageAsyncContextStrategy();
16
16
  const context = instrumentContext(ctx);
17
17
  const options = getFinalOptions(optionsCallback(env), env);
18
18
  const instrumentedEnv = instrumentEnv(env, options);
19
- const obj = new target(context, instrumentedEnv);
19
+ const obj = Reflect.construct(target, [context, instrumentedEnv], newTarget);
20
20
  if (obj.fetch && typeof obj.fetch === "function") {
21
21
  obj.fetch = ensureInstrumented(
22
22
  obj.fetch,
@@ -1 +1 @@
1
- {"version":3,"file":"durableobject.js","sources":["../../src/durableobject.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/unbound-method */\nimport { captureException } from '@sentry/core';\nimport type { DurableObject } from 'cloudflare:workers';\nimport { setAsyncLocalStorageAsyncContextStrategy } from './async';\nimport type { CloudflareOptions } from './client';\nimport { ensureInstrumented } from './instrument';\nimport { instrumentEnv } from './instrumentations/worker/instrumentEnv';\nimport { getFinalOptions } from './options';\nimport { wrapRequestHandler } from './request';\nimport { instrumentContext } from './utils/instrumentContext';\nimport { extractRpcMeta } from './utils/rpcMeta';\nimport { getEffectiveRpcPropagation } from './utils/rpcOptions';\nimport { type UncheckedMethod, wrapMethodWithSentry } from './wrapMethodWithSentry';\n\n/**\n * Instruments a Durable Object class to capture errors and performance data.\n *\n * Instruments the following methods by default:\n * - fetch\n * - alarm\n * - webSocketMessage\n * - webSocketClose\n * - webSocketError\n *\n * To instrument RPC methods (prototype methods), enable the `enableRpcTracePropagation` option.\n *\n * @param optionsCallback Function that returns the options for the SDK initialization.\n * @param DurableObjectClass The Durable Object class to instrument.\n * @returns The instrumented Durable Object class.\n *\n * @example\n * ```ts\n * class MyDurableObjectBase extends DurableObject {\n * constructor(ctx: DurableObjectState, env: Env) {\n * super(ctx, env);\n * }\n * }\n *\n * export const MyDurableObject = instrumentDurableObjectWithSentry(\n * env => ({\n * dsn: env.SENTRY_DSN,\n * tracesSampleRate: 1.0,\n * }),\n * MyDurableObjectBase,\n * );\n * ```\n */\nexport function instrumentDurableObjectWithSentry<\n E,\n T extends DurableObject<E>,\n C extends new (state: DurableObjectState, env: E) => T,\n>(optionsCallback: (env: E) => CloudflareOptions, DurableObjectClass: C): C {\n return new Proxy(DurableObjectClass, {\n construct(target, [ctx, env]) {\n setAsyncLocalStorageAsyncContextStrategy();\n const context = instrumentContext(ctx);\n const options = getFinalOptions(optionsCallback(env), env);\n const instrumentedEnv = instrumentEnv(env, options);\n\n const obj = new target(context, instrumentedEnv);\n\n // These are the methods that are available on a Durable Object\n // ref: https://developers.cloudflare.com/durable-objects/api/base/\n // obj.alarm\n // obj.fetch\n // obj.webSocketError\n // obj.webSocketClose\n // obj.webSocketMessage\n\n // Any other public methods on the Durable Object instance are RPC calls.\n\n if (obj.fetch && typeof obj.fetch === 'function') {\n obj.fetch = ensureInstrumented(\n obj.fetch,\n original =>\n new Proxy(original, {\n apply(target, thisArg, args) {\n return wrapRequestHandler({ options, request: args[0], context }, () => {\n return Reflect.apply(target, thisArg, args);\n });\n },\n }),\n );\n }\n\n if (obj.alarm && typeof obj.alarm === 'function') {\n // Alarms are independent invocations, so we start a new trace and link to the previous alarm\n obj.alarm = wrapMethodWithSentry(\n { options, context, spanName: 'alarm', spanOp: 'function', startNewTrace: true },\n obj.alarm,\n );\n }\n\n if (obj.webSocketMessage && typeof obj.webSocketMessage === 'function') {\n obj.webSocketMessage = wrapMethodWithSentry(\n { options, context, spanName: 'webSocketMessage' },\n obj.webSocketMessage,\n );\n }\n\n if (obj.webSocketClose && typeof obj.webSocketClose === 'function') {\n obj.webSocketClose = wrapMethodWithSentry({ options, context, spanName: 'webSocketClose' }, obj.webSocketClose);\n }\n\n if (obj.webSocketError && typeof obj.webSocketError === 'function') {\n obj.webSocketError = wrapMethodWithSentry(\n { options, context, spanName: 'webSocketError' },\n obj.webSocketError,\n (_, error) =>\n captureException(error, {\n mechanism: {\n type: 'auto.faas.cloudflare.durable_object_websocket',\n handled: false,\n },\n }),\n );\n }\n\n // Get effective RPC propagation setting (handles deprecation of instrumentPrototypeMethods)\n const rpcPropagation = getEffectiveRpcPropagation(options);\n\n // Skip RPC instrumentation if not enabled\n if (!rpcPropagation) {\n return obj;\n }\n\n // If `instrumentPrototypeMethods` was passed as an array (deprecated),\n // only the listed method names should be instrumented.\n // eslint-disable-next-line typescript/no-deprecated\n const instrumentPrototypeMethods = Array.isArray(options.instrumentPrototypeMethods)\n ? // eslint-disable-next-line typescript/no-deprecated\n options.instrumentPrototypeMethods\n : undefined;\n const allowSet = instrumentPrototypeMethods ? new Set(instrumentPrototypeMethods) : null;\n\n // When using the deprecated `instrumentPrototypeMethods` option, always create spans.\n // When using the new `enableRpcTracePropagation`, only create spans when RPC metadata is present.\n const alwaysTrace = options.enableRpcTracePropagation === undefined;\n\n // Return a Proxy that binds all methods to the original object and creates spans\n // for RPC calls that have Sentry trace context propagated.\n // Binding is required because frameworks may use private fields (babel WeakMap pattern),\n // which fail if `this` is the Proxy instead of the original object.\n const methodCache = new Map<string, UncheckedMethod>();\n\n return new Proxy(obj, {\n get(proxyTarget, prop, receiver) {\n const value = Reflect.get(proxyTarget, prop, receiver);\n\n if (typeof prop !== 'string' || typeof value !== 'function' || prop === 'constructor') {\n return value;\n }\n\n const cached = methodCache.get(prop);\n\n if (cached) {\n return cached;\n }\n\n const boundMethod = (value as UncheckedMethod).bind(proxyTarget);\n\n if (\n prop in Object.prototype ||\n Object.prototype.hasOwnProperty.call(proxyTarget, prop) ||\n (allowSet && !allowSet.has(prop))\n ) {\n methodCache.set(prop, boundMethod);\n\n return boundMethod;\n }\n\n // Pre-create the traced version\n const tracedMethod = wrapMethodWithSentry(\n { options, context, spanName: prop, spanOp: 'rpc' },\n boundMethod,\n undefined,\n true,\n );\n\n // For deprecated `instrumentPrototypeMethods`, always trace.\n // For new `enableRpcTracePropagation`, only trace when RPC metadata is present.\n if (alwaysTrace) {\n methodCache.set(prop, tracedMethod);\n\n return tracedMethod;\n }\n\n // Wrapper that checks for Sentry RPC metadata at call time\n const wrappedMethod = ((...args: unknown[]) => {\n const { rpcMeta } = extractRpcMeta(args);\n\n // If Sentry RPC metadata is present, use the traced version (creates span)\n // Otherwise, call the bound method directly (no span)\n return rpcMeta ? tracedMethod(...args) : boundMethod(...args);\n }) as UncheckedMethod;\n\n methodCache.set(prop, wrappedMethod);\n\n return wrappedMethod;\n },\n });\n },\n });\n}\n"],"names":["target"],"mappings":"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"}
1
+ {"version":3,"file":"durableobject.js","sources":["../../src/durableobject.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/unbound-method */\nimport { captureException } from '@sentry/core';\nimport type { DurableObject } from 'cloudflare:workers';\nimport { setAsyncLocalStorageAsyncContextStrategy } from './async';\nimport type { CloudflareOptions } from './client';\nimport { ensureInstrumented } from './instrument';\nimport { instrumentEnv } from './instrumentations/worker/instrumentEnv';\nimport { getFinalOptions } from './options';\nimport { wrapRequestHandler } from './request';\nimport { instrumentContext } from './utils/instrumentContext';\nimport { extractRpcMeta } from './utils/rpcMeta';\nimport { getEffectiveRpcPropagation } from './utils/rpcOptions';\nimport { type UncheckedMethod, wrapMethodWithSentry } from './wrapMethodWithSentry';\n\n/**\n * Instruments a Durable Object class to capture errors and performance data.\n *\n * Instruments the following methods by default:\n * - fetch\n * - alarm\n * - webSocketMessage\n * - webSocketClose\n * - webSocketError\n *\n * To instrument RPC methods (prototype methods), enable the `enableRpcTracePropagation` option.\n *\n * @param optionsCallback Function that returns the options for the SDK initialization.\n * @param DurableObjectClass The Durable Object class to instrument.\n * @returns The instrumented Durable Object class.\n *\n * @example\n * ```ts\n * class MyDurableObjectBase extends DurableObject {\n * constructor(ctx: DurableObjectState, env: Env) {\n * super(ctx, env);\n * }\n * }\n *\n * export const MyDurableObject = instrumentDurableObjectWithSentry(\n * env => ({\n * dsn: env.SENTRY_DSN,\n * tracesSampleRate: 1.0,\n * }),\n * MyDurableObjectBase,\n * );\n * ```\n */\nexport function instrumentDurableObjectWithSentry<\n E,\n T extends DurableObject<E>,\n C extends new (state: DurableObjectState, env: E) => T,\n>(optionsCallback: (env: E) => CloudflareOptions, DurableObjectClass: C): C {\n return new Proxy(DurableObjectClass, {\n construct(target, [ctx, env], newTarget) {\n setAsyncLocalStorageAsyncContextStrategy();\n const context = instrumentContext(ctx);\n const options = getFinalOptions(optionsCallback(env), env);\n const instrumentedEnv = instrumentEnv(env, options);\n\n // Pass `newTarget` so that subclasses of the instrumented class (e.g. the wrapper classes\n // created by wrangler's local dev tooling or `@cloudflare/vitest-pool-workers`) keep their\n // own prototype — otherwise subclass methods disappear and `instanceof` checks break.\n const obj = Reflect.construct(target, [context, instrumentedEnv], newTarget) as T;\n\n // These are the methods that are available on a Durable Object\n // ref: https://developers.cloudflare.com/durable-objects/api/base/\n // obj.alarm\n // obj.fetch\n // obj.webSocketError\n // obj.webSocketClose\n // obj.webSocketMessage\n\n // Any other public methods on the Durable Object instance are RPC calls.\n\n if (obj.fetch && typeof obj.fetch === 'function') {\n obj.fetch = ensureInstrumented(\n obj.fetch,\n original =>\n new Proxy(original, {\n apply(target, thisArg, args) {\n return wrapRequestHandler({ options, request: args[0], context }, () => {\n return Reflect.apply(target, thisArg, args);\n });\n },\n }),\n );\n }\n\n if (obj.alarm && typeof obj.alarm === 'function') {\n // Alarms are independent invocations, so we start a new trace and link to the previous alarm\n obj.alarm = wrapMethodWithSentry(\n { options, context, spanName: 'alarm', spanOp: 'function', startNewTrace: true },\n obj.alarm,\n );\n }\n\n if (obj.webSocketMessage && typeof obj.webSocketMessage === 'function') {\n obj.webSocketMessage = wrapMethodWithSentry(\n { options, context, spanName: 'webSocketMessage' },\n obj.webSocketMessage,\n );\n }\n\n if (obj.webSocketClose && typeof obj.webSocketClose === 'function') {\n obj.webSocketClose = wrapMethodWithSentry({ options, context, spanName: 'webSocketClose' }, obj.webSocketClose);\n }\n\n if (obj.webSocketError && typeof obj.webSocketError === 'function') {\n obj.webSocketError = wrapMethodWithSentry(\n { options, context, spanName: 'webSocketError' },\n obj.webSocketError,\n (_, error) =>\n captureException(error, {\n mechanism: {\n type: 'auto.faas.cloudflare.durable_object_websocket',\n handled: false,\n },\n }),\n );\n }\n\n // Get effective RPC propagation setting (handles deprecation of instrumentPrototypeMethods)\n const rpcPropagation = getEffectiveRpcPropagation(options);\n\n // Skip RPC instrumentation if not enabled\n if (!rpcPropagation) {\n return obj;\n }\n\n // If `instrumentPrototypeMethods` was passed as an array (deprecated),\n // only the listed method names should be instrumented.\n // eslint-disable-next-line typescript/no-deprecated\n const instrumentPrototypeMethods = Array.isArray(options.instrumentPrototypeMethods)\n ? // eslint-disable-next-line typescript/no-deprecated\n options.instrumentPrototypeMethods\n : undefined;\n const allowSet = instrumentPrototypeMethods ? new Set(instrumentPrototypeMethods) : null;\n\n // When using the deprecated `instrumentPrototypeMethods` option, always create spans.\n // When using the new `enableRpcTracePropagation`, only create spans when RPC metadata is present.\n const alwaysTrace = options.enableRpcTracePropagation === undefined;\n\n // Return a Proxy that binds all methods to the original object and creates spans\n // for RPC calls that have Sentry trace context propagated.\n // Binding is required because frameworks may use private fields (babel WeakMap pattern),\n // which fail if `this` is the Proxy instead of the original object.\n const methodCache = new Map<string, UncheckedMethod>();\n\n return new Proxy(obj, {\n get(proxyTarget, prop, receiver) {\n const value = Reflect.get(proxyTarget, prop, receiver);\n\n if (typeof prop !== 'string' || typeof value !== 'function' || prop === 'constructor') {\n return value;\n }\n\n const cached = methodCache.get(prop);\n\n if (cached) {\n return cached;\n }\n\n const boundMethod = (value as UncheckedMethod).bind(proxyTarget);\n\n if (\n prop in Object.prototype ||\n Object.prototype.hasOwnProperty.call(proxyTarget, prop) ||\n (allowSet && !allowSet.has(prop))\n ) {\n methodCache.set(prop, boundMethod);\n\n return boundMethod;\n }\n\n // Pre-create the traced version\n const tracedMethod = wrapMethodWithSentry(\n { options, context, spanName: prop, spanOp: 'rpc' },\n boundMethod,\n undefined,\n true,\n );\n\n // For deprecated `instrumentPrototypeMethods`, always trace.\n // For new `enableRpcTracePropagation`, only trace when RPC metadata is present.\n if (alwaysTrace) {\n methodCache.set(prop, tracedMethod);\n\n return tracedMethod;\n }\n\n // Wrapper that checks for Sentry RPC metadata at call time\n const wrappedMethod = ((...args: unknown[]) => {\n const { rpcMeta } = extractRpcMeta(args);\n\n // If Sentry RPC metadata is present, use the traced version (creates span)\n // Otherwise, call the bound method directly (no span)\n return rpcMeta ? tracedMethod(...args) : boundMethod(...args);\n }) as UncheckedMethod;\n\n methodCache.set(prop, wrappedMethod);\n\n return wrappedMethod;\n },\n });\n },\n });\n}\n"],"names":["target"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"flush.js","sources":["../../src/flush.ts"],"sourcesContent":["import type { ExecutionContext } from '@cloudflare/workers-types';\nimport type { Client } from '@sentry/core';\nimport { debug, flush } from '@sentry/core';\nimport { DEBUG_BUILD } from './debug-build';\n\ntype FlushLock = {\n readonly ready: Promise<void>;\n readonly finalize: () => Promise<void>;\n};\n\ntype FlushLockRegistry = {\n readonly locks: Set<FlushLockInternal>;\n readonly originalWaitUntil: ExecutionContext['waitUntil'];\n};\n\ntype FlushLockInternal = FlushLock & {\n readonly acquire: () => void;\n readonly release: () => void;\n};\n\nconst flushLockRegistries = new WeakMap<ExecutionContext['waitUntil'], FlushLockRegistry>();\n\n/**\n * Returns the original (un-instrumented) waitUntil function for a context.\n * This should be used when calling waitUntil with flushAndDispose to avoid deadlock.\n *\n * The flush lock mechanism wraps context.waitUntil to track pending tasks.\n * If we call waitUntil(flushAndDispose(client)) through the instrumented version,\n * it creates a deadlock because:\n * 1. The instrumented waitUntil acquires the flush lock\n * 2. flushAndDispose calls client.flush() which waits for the lock to be released\n * 3. The lock won't be released until the waitUntil promise completes\n * 4. The waitUntil promise won't complete until flush() returns\n *\n * By using the original waitUntil for flush operations, we bypass this issue.\n */\nexport function getOriginalWaitUntil(context: ExecutionContext): ExecutionContext['waitUntil'] | undefined {\n // eslint-disable-next-line @typescript-eslint/unbound-method\n const currentWaitUntil = context.waitUntil;\n const original = flushLockRegistries.get(currentWaitUntil)?.originalWaitUntil;\n return original ?? currentWaitUntil;\n}\n\n/**\n * Enhances the given execution context by wrapping its `waitUntil` method with a proxy\n * to monitor pending tasks, and provides a flusher function to ensure all tasks\n * have been completed before executing any subsequent logic.\n *\n * @param {ExecutionContext} context - The execution context to be enhanced. If no context is provided, the function returns undefined.\n * @return {FlushLock} Returns a flusher function if a valid context is provided, otherwise undefined.\n */\nexport function makeFlushLock(context: ExecutionContext): FlushLock {\n const registry = getOrCreateFlushLockRegistry(context);\n let resolveAllDone: () => void = () => undefined;\n const allDone = new Promise<void>(res => {\n resolveAllDone = res;\n });\n let pending = 0;\n\n const lock: FlushLockInternal = {\n ready: allDone,\n acquire: () => {\n pending++;\n },\n release: () => {\n if (--pending === 0) {\n registry.locks.delete(lock);\n resolveAllDone();\n }\n },\n finalize: () => {\n if (pending === 0) {\n registry.locks.delete(lock);\n resolveAllDone();\n }\n return allDone;\n },\n };\n\n registry.locks.add(lock);\n return Object.freeze(lock);\n}\n\nfunction getOrCreateFlushLockRegistry(context: ExecutionContext): FlushLockRegistry {\n // eslint-disable-next-line @typescript-eslint/unbound-method\n const waitUntil = context.waitUntil;\n const existingRegistry = flushLockRegistries.get(waitUntil);\n\n if (existingRegistry) {\n return existingRegistry;\n }\n\n const originalWaitUntil = context.waitUntil.bind(context) as typeof context.waitUntil;\n const registry: FlushLockRegistry = { locks: new Set(), originalWaitUntil };\n const instrumentedWaitUntil: typeof context.waitUntil = promise => {\n // Snapshot active locks so locks created after this call do not wait for earlier waitUntil work.\n const locks = [...registry.locks];\n\n for (const lock of locks) {\n lock.acquire();\n }\n\n return originalWaitUntil(\n promise.finally(() => {\n for (const lock of locks) {\n lock.release();\n }\n }),\n );\n };\n\n flushLockRegistries.set(instrumentedWaitUntil, registry);\n context.waitUntil = instrumentedWaitUntil;\n\n return registry;\n}\n\n/**\n * Flushes the client and then disposes of it to allow garbage collection.\n * This should be called at the end of each request to prevent memory leaks.\n *\n * This function never rejects. On Workers, a rejected promise passed to\n * `ctx.waitUntil` marks the whole invocation as `outcome: exception` even when\n * the handler itself completed successfully. Since flush/dispose is internal\n * SDK housekeeping, a failure here must not fail the user's invocation.\n *\n * @param client - The CloudflareClient instance to flush and dispose\n * @param timeout - Timeout in milliseconds for the flush operation\n * @returns A promise that resolves when flush and dispose are complete\n */\nexport async function flushAndDispose(client: Client | undefined, timeout = 2000): Promise<void> {\n try {\n if (!client) {\n await flush(timeout);\n return;\n }\n await client.flush(timeout);\n } catch (e) {\n DEBUG_BUILD && debug.warn('Failed to flush client', e);\n } finally {\n try {\n client?.dispose();\n } catch (e) {\n DEBUG_BUILD && debug.warn('Failed to dispose client', e);\n }\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"flush.js","sources":["../../src/flush.ts"],"sourcesContent":["import type { ExecutionContext } from '@cloudflare/workers-types';\nimport type { Client } from '@sentry/core';\nimport { debug, flush } from '@sentry/core';\nimport { DEBUG_BUILD } from './debug-build';\nimport type { ExecutionContextCompat } from './executionContext';\n\ntype FlushLock = {\n readonly ready: Promise<void>;\n readonly finalize: () => Promise<void>;\n};\n\ntype FlushLockRegistry = {\n readonly locks: Set<FlushLockInternal>;\n readonly originalWaitUntil: ExecutionContext['waitUntil'];\n};\n\ntype FlushLockInternal = FlushLock & {\n readonly acquire: () => void;\n readonly release: () => void;\n};\n\nconst flushLockRegistries = new WeakMap<ExecutionContext['waitUntil'], FlushLockRegistry>();\n\n/**\n * Returns the original (un-instrumented) waitUntil function for a context.\n * This should be used when calling waitUntil with flushAndDispose to avoid deadlock.\n *\n * The flush lock mechanism wraps context.waitUntil to track pending tasks.\n * If we call waitUntil(flushAndDispose(client)) through the instrumented version,\n * it creates a deadlock because:\n * 1. The instrumented waitUntil acquires the flush lock\n * 2. flushAndDispose calls client.flush() which waits for the lock to be released\n * 3. The lock won't be released until the waitUntil promise completes\n * 4. The waitUntil promise won't complete until flush() returns\n *\n * By using the original waitUntil for flush operations, we bypass this issue.\n */\nexport function getOriginalWaitUntil(context: ExecutionContextCompat): ExecutionContext['waitUntil'] | undefined {\n // eslint-disable-next-line @typescript-eslint/unbound-method\n const currentWaitUntil = context.waitUntil;\n const original = flushLockRegistries.get(currentWaitUntil)?.originalWaitUntil;\n return original ?? currentWaitUntil;\n}\n\n/**\n * Enhances the given execution context by wrapping its `waitUntil` method with a proxy\n * to monitor pending tasks, and provides a flusher function to ensure all tasks\n * have been completed before executing any subsequent logic.\n *\n * @param {ExecutionContext} context - The execution context to be enhanced. If no context is provided, the function returns undefined.\n * @return {FlushLock} Returns a flusher function if a valid context is provided, otherwise undefined.\n */\nexport function makeFlushLock(context: ExecutionContextCompat): FlushLock {\n const registry = getOrCreateFlushLockRegistry(context);\n let resolveAllDone: () => void = () => undefined;\n const allDone = new Promise<void>(res => {\n resolveAllDone = res;\n });\n let pending = 0;\n\n const lock: FlushLockInternal = {\n ready: allDone,\n acquire: () => {\n pending++;\n },\n release: () => {\n if (--pending === 0) {\n registry.locks.delete(lock);\n resolveAllDone();\n }\n },\n finalize: () => {\n if (pending === 0) {\n registry.locks.delete(lock);\n resolveAllDone();\n }\n return allDone;\n },\n };\n\n registry.locks.add(lock);\n return Object.freeze(lock);\n}\n\nfunction getOrCreateFlushLockRegistry(context: ExecutionContextCompat): FlushLockRegistry {\n // eslint-disable-next-line @typescript-eslint/unbound-method\n const waitUntil = context.waitUntil;\n const existingRegistry = flushLockRegistries.get(waitUntil);\n\n if (existingRegistry) {\n return existingRegistry;\n }\n\n const originalWaitUntil = context.waitUntil.bind(context) as typeof context.waitUntil;\n const registry: FlushLockRegistry = { locks: new Set(), originalWaitUntil };\n const instrumentedWaitUntil: typeof context.waitUntil = promise => {\n // Snapshot active locks so locks created after this call do not wait for earlier waitUntil work.\n const locks = [...registry.locks];\n\n for (const lock of locks) {\n lock.acquire();\n }\n\n return originalWaitUntil(\n promise.finally(() => {\n for (const lock of locks) {\n lock.release();\n }\n }),\n );\n };\n\n flushLockRegistries.set(instrumentedWaitUntil, registry);\n context.waitUntil = instrumentedWaitUntil;\n\n return registry;\n}\n\n/**\n * Flushes the client and then disposes of it to allow garbage collection.\n * This should be called at the end of each request to prevent memory leaks.\n *\n * This function never rejects. On Workers, a rejected promise passed to\n * `ctx.waitUntil` marks the whole invocation as `outcome: exception` even when\n * the handler itself completed successfully. Since flush/dispose is internal\n * SDK housekeeping, a failure here must not fail the user's invocation.\n *\n * @param client - The CloudflareClient instance to flush and dispose\n * @param timeout - Timeout in milliseconds for the flush operation\n * @returns A promise that resolves when flush and dispose are complete\n */\nexport async function flushAndDispose(client: Client | undefined, timeout = 2000): Promise<void> {\n try {\n if (!client) {\n await flush(timeout);\n return;\n }\n await client.flush(timeout);\n } catch (e) {\n DEBUG_BUILD && debug.warn('Failed to flush client', e);\n } finally {\n try {\n client?.dispose();\n } catch (e) {\n DEBUG_BUILD && debug.warn('Failed to dispose client', e);\n }\n }\n}\n"],"names":[],"mappings":"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"}
@@ -1,3 +1,5 @@
1
+ import { isObjectLike } from '@sentry/core';
2
+
1
3
  const GLOBAL_KEY = "__SENTRY_INSTRUMENTED_MAP__";
2
4
  function getInstrumentedMap() {
3
5
  const globalObj = globalThis;
@@ -7,7 +9,7 @@ function getInstrumentedMap() {
7
9
  return globalObj[GLOBAL_KEY];
8
10
  }
9
11
  function isWeakMapKey(value) {
10
- return typeof value === "object" && value !== null || typeof value === "function";
12
+ return isObjectLike(value) || typeof value === "function";
11
13
  }
12
14
  function markAsInstrumented(original, instrumented) {
13
15
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"instrument.js","sources":["../../src/instrument.ts"],"sourcesContent":["// Use a global WeakMap to track instrumented objects across module instances.\n// This is important for Cloudflare Workers where the module may be bundled\n// separately for workers and Durable Objects, but they share the same global scope.\n// The WeakMap stores original -> instrumented mappings so we can retrieve the\n// instrumented version even if we only have a reference to the original.\nconst GLOBAL_KEY = '__SENTRY_INSTRUMENTED_MAP__' as const;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction getInstrumentedMap(): WeakMap<any, any> {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const globalObj = globalThis as typeof globalThis & { [GLOBAL_KEY]?: WeakMap<any, any> };\n if (!globalObj[GLOBAL_KEY]) {\n globalObj[GLOBAL_KEY] = new WeakMap();\n }\n return globalObj[GLOBAL_KEY];\n}\n\n/**\n * Check if a value can be used as a WeakMap key.\n * WeakMap keys must be objects or non-registered symbols.\n */\nfunction isWeakMapKey(value: unknown): value is object {\n return (typeof value === 'object' && value !== null) || typeof value === 'function';\n}\n\n/**\n * Mark an object as instrumented, storing the instrumented version.\n * @param original The original uninstrumented object\n * @param instrumented The instrumented version (defaults to original if not provided)\n */\nexport function markAsInstrumented<T>(original: T, instrumented?: T): void {\n try {\n if (isWeakMapKey(original)) {\n // Store mapping from original to instrumented version\n // If instrumented is not provided, store original (for backwards compat)\n getInstrumentedMap().set(original, instrumented ?? original);\n }\n // Also mark the instrumented version itself so we recognize it\n if (isWeakMapKey(instrumented) && instrumented !== original) {\n getInstrumentedMap().set(instrumented, instrumented);\n }\n } catch {\n // ignore errors here\n }\n}\n\n/**\n * Get the instrumented version of an object, if available.\n * Returns the instrumented version if the object was previously instrumented,\n * or undefined if not found.\n */\nexport function getInstrumented<T>(obj: T): T | undefined {\n try {\n if (isWeakMapKey(obj)) {\n return getInstrumentedMap().get(obj) as T | undefined;\n }\n\n return undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Returns the already-instrumented version of `original` if one exists,\n * otherwise calls `instrumentFn` to create it, marks the mapping, and returns it.\n *\n * @param noMark - If true, skips storing the original→instrumented mapping.\n */\nexport function ensureInstrumented<T>(original: T, instrumentFn: (original: T) => T, noMark?: boolean): T {\n const existing = getInstrumented(original);\n\n if (existing) {\n return existing;\n }\n\n const instrumented = instrumentFn(original);\n\n if (!noMark) {\n markAsInstrumented(original, instrumented);\n }\n\n return instrumented;\n}\n"],"names":[],"mappings":"AAKA,MAAM,UAAA,GAAa,6BAAA;AAGnB,SAAS,kBAAA,GAAwC;AAE/C,EAAA,MAAM,SAAA,GAAY,UAAA;AAClB,EAAA,IAAI,CAAC,SAAA,CAAU,UAAU,CAAA,EAAG;AAC1B,IAAA,SAAA,CAAU,UAAU,CAAA,mBAAI,IAAI,OAAA,EAAQ;AAAA,EACtC;AACA,EAAA,OAAO,UAAU,UAAU,CAAA;AAC7B;AAMA,SAAS,aAAa,KAAA,EAAiC;AACrD,EAAA,OAAQ,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,KAAU,IAAA,IAAS,OAAO,KAAA,KAAU,UAAA;AAC3E;AAOO,SAAS,kBAAA,CAAsB,UAAa,YAAA,EAAwB;AACzE,EAAA,IAAI;AACF,IAAA,IAAI,YAAA,CAAa,QAAQ,CAAA,EAAG;AAG1B,MAAA,kBAAA,EAAmB,CAAE,GAAA,CAAI,QAAA,EAAU,YAAA,IAAgB,QAAQ,CAAA;AAAA,IAC7D;AAEA,IAAA,IAAI,YAAA,CAAa,YAAY,CAAA,IAAK,YAAA,KAAiB,QAAA,EAAU;AAC3D,MAAA,kBAAA,EAAmB,CAAE,GAAA,CAAI,YAAA,EAAc,YAAY,CAAA;AAAA,IACrD;AAAA,EACF,CAAA,CAAA,MAAQ;AAAA,EAER;AACF;AAOO,SAAS,gBAAmB,GAAA,EAAuB;AACxD,EAAA,IAAI;AACF,IAAA,IAAI,YAAA,CAAa,GAAG,CAAA,EAAG;AACrB,MAAA,OAAO,kBAAA,EAAmB,CAAE,GAAA,CAAI,GAAG,CAAA;AAAA,IACrC;AAEA,IAAA,OAAO,KAAA,CAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,MAAA;AAAA,EACT;AACF;AAQO,SAAS,kBAAA,CAAsB,QAAA,EAAa,YAAA,EAAkC,MAAA,EAAqB;AACxG,EAAA,MAAM,QAAA,GAAW,gBAAgB,QAAQ,CAAA;AAEzC,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,OAAO,QAAA;AAAA,EACT;AAEA,EAAA,MAAM,YAAA,GAAe,aAAa,QAAQ,CAAA;AAE1C,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,kBAAA,CAAmB,UAAU,YAAY,CAAA;AAAA,EAC3C;AAEA,EAAA,OAAO,YAAA;AACT;;;;"}
1
+ {"version":3,"file":"instrument.js","sources":["../../src/instrument.ts"],"sourcesContent":["// Use a global WeakMap to track instrumented objects across module instances.\n// This is important for Cloudflare Workers where the module may be bundled\n// separately for workers and Durable Objects, but they share the same global scope.\n// The WeakMap stores original -> instrumented mappings so we can retrieve the\n// instrumented version even if we only have a reference to the original.\nimport { isObjectLike } from '@sentry/core';\n\nconst GLOBAL_KEY = '__SENTRY_INSTRUMENTED_MAP__' as const;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction getInstrumentedMap(): WeakMap<any, any> {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const globalObj = globalThis as typeof globalThis & { [GLOBAL_KEY]?: WeakMap<any, any> };\n if (!globalObj[GLOBAL_KEY]) {\n globalObj[GLOBAL_KEY] = new WeakMap();\n }\n return globalObj[GLOBAL_KEY];\n}\n\n/**\n * Check if a value can be used as a WeakMap key.\n * WeakMap keys must be objects or non-registered symbols.\n */\nfunction isWeakMapKey(value: unknown): value is object {\n return isObjectLike(value) || typeof value === 'function';\n}\n\n/**\n * Mark an object as instrumented, storing the instrumented version.\n * @param original The original uninstrumented object\n * @param instrumented The instrumented version (defaults to original if not provided)\n */\nexport function markAsInstrumented<T>(original: T, instrumented?: T): void {\n try {\n if (isWeakMapKey(original)) {\n // Store mapping from original to instrumented version\n // If instrumented is not provided, store original (for backwards compat)\n getInstrumentedMap().set(original, instrumented ?? original);\n }\n // Also mark the instrumented version itself so we recognize it\n if (isWeakMapKey(instrumented) && instrumented !== original) {\n getInstrumentedMap().set(instrumented, instrumented);\n }\n } catch {\n // ignore errors here\n }\n}\n\n/**\n * Get the instrumented version of an object, if available.\n * Returns the instrumented version if the object was previously instrumented,\n * or undefined if not found.\n */\nexport function getInstrumented<T>(obj: T): T | undefined {\n try {\n if (isWeakMapKey(obj)) {\n return getInstrumentedMap().get(obj) as T | undefined;\n }\n\n return undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Returns the already-instrumented version of `original` if one exists,\n * otherwise calls `instrumentFn` to create it, marks the mapping, and returns it.\n *\n * @param noMark - If true, skips storing the original→instrumented mapping.\n */\nexport function ensureInstrumented<T>(original: T, instrumentFn: (original: T) => T, noMark?: boolean): T {\n const existing = getInstrumented(original);\n\n if (existing) {\n return existing;\n }\n\n const instrumented = instrumentFn(original);\n\n if (!noMark) {\n markAsInstrumented(original, instrumented);\n }\n\n return instrumented;\n}\n"],"names":[],"mappings":";;AAOA,MAAM,UAAA,GAAa,6BAAA;AAGnB,SAAS,kBAAA,GAAwC;AAE/C,EAAA,MAAM,SAAA,GAAY,UAAA;AAClB,EAAA,IAAI,CAAC,SAAA,CAAU,UAAU,CAAA,EAAG;AAC1B,IAAA,SAAA,CAAU,UAAU,CAAA,mBAAI,IAAI,OAAA,EAAQ;AAAA,EACtC;AACA,EAAA,OAAO,UAAU,UAAU,CAAA;AAC7B;AAMA,SAAS,aAAa,KAAA,EAAiC;AACrD,EAAA,OAAO,YAAA,CAAa,KAAK,CAAA,IAAK,OAAO,KAAA,KAAU,UAAA;AACjD;AAOO,SAAS,kBAAA,CAAsB,UAAa,YAAA,EAAwB;AACzE,EAAA,IAAI;AACF,IAAA,IAAI,YAAA,CAAa,QAAQ,CAAA,EAAG;AAG1B,MAAA,kBAAA,EAAmB,CAAE,GAAA,CAAI,QAAA,EAAU,YAAA,IAAgB,QAAQ,CAAA;AAAA,IAC7D;AAEA,IAAA,IAAI,YAAA,CAAa,YAAY,CAAA,IAAK,YAAA,KAAiB,QAAA,EAAU;AAC3D,MAAA,kBAAA,EAAmB,CAAE,GAAA,CAAI,YAAA,EAAc,YAAY,CAAA;AAAA,IACrD;AAAA,EACF,CAAA,CAAA,MAAQ;AAAA,EAER;AACF;AAOO,SAAS,gBAAmB,GAAA,EAAuB;AACxD,EAAA,IAAI;AACF,IAAA,IAAI,YAAA,CAAa,GAAG,CAAA,EAAG;AACrB,MAAA,OAAO,kBAAA,EAAmB,CAAE,GAAA,CAAI,GAAG,CAAA;AAAA,IACrC;AAEA,IAAA,OAAO,KAAA,CAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,MAAA;AAAA,EACT;AACF;AAQO,SAAS,kBAAA,CAAsB,QAAA,EAAa,YAAA,EAAkC,MAAA,EAAqB;AACxG,EAAA,MAAM,QAAA,GAAW,gBAAgB,QAAQ,CAAA;AAEzC,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,OAAO,QAAA;AAAA,EACT;AAEA,EAAA,MAAM,YAAA,GAAe,aAAa,QAAQ,CAAA;AAE1C,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,kBAAA,CAAmB,UAAU,YAAY,CAAA;AAAA,EAC3C;AAEA,EAAA,OAAO,YAAA;AACT;;;;"}
@@ -1,3 +1,4 @@
1
+ import { isObjectLike } from '@sentry/core';
1
2
  import { isD1Database, isQueue, isR2Bucket, isDurableObjectNamespace, isJSRPC } from '../../utils/isBinding.js';
2
3
  import { instrumentD1 } from './instrumentD1.js';
3
4
  import { appendRpcMeta } from '../../utils/rpcMeta.js';
@@ -8,7 +9,7 @@ import { instrumentQueueProducer } from './instrumentQueueProducer.js';
8
9
  import { instrumentR2Bucket } from './instrumentR2.js';
9
10
 
10
11
  function isProxyable(item) {
11
- return item !== null && (typeof item === "object" || typeof item === "function");
12
+ return isObjectLike(item) || typeof item === "function";
12
13
  }
13
14
  const instrumentedBindings = /* @__PURE__ */ new WeakMap();
14
15
  function instrumentEnv(env, options) {
@@ -1 +1 @@
1
- {"version":3,"file":"instrumentEnv.js","sources":["../../../../src/instrumentations/worker/instrumentEnv.ts"],"sourcesContent":["import type { CloudflareOptions } from '../../client';\nimport { isD1Database, isDurableObjectNamespace, isJSRPC, isQueue, isR2Bucket } from '../../utils/isBinding';\nimport { instrumentD1 } from './instrumentD1';\nimport { appendRpcMeta } from '../../utils/rpcMeta';\nimport { getEffectiveRpcPropagation } from '../../utils/rpcOptions';\nimport { instrumentDurableObjectNamespace, STUB_NON_RPC_METHODS } from '../instrumentDurableObjectNamespace';\nimport { instrumentFetcher } from './instrumentFetcher';\nimport { instrumentQueueProducer } from './instrumentQueueProducer';\nimport { instrumentR2Bucket } from './instrumentR2';\n\nfunction isProxyable(item: unknown): item is object {\n return item !== null && (typeof item === 'object' || typeof item === 'function');\n}\n\nconst instrumentedBindings = new WeakMap<object, unknown>();\n\n/**\n * Wraps the Cloudflare `env` object in a Proxy that detects binding types\n * on property access and returns instrumented versions.\n *\n * Currently detects:\n * - DurableObjectNamespace (via `idFromName` duck-typing)\n * - Service bindings / JSRPC proxies\n * - Queue producers (via `send` + `sendBatch` duck-typing)\n * - R2 Buckets (via `head` + `put` + `createMultipartUpload` duck-typing)\n *\n * @param env - The Cloudflare env object to instrument\n * @param options - Optional CloudflareOptions to control RPC trace propagation\n */\nexport function instrumentEnv<Env extends Record<string, unknown>>(env: Env, options?: CloudflareOptions): Env {\n if (!env || typeof env !== 'object') {\n return env;\n }\n\n const rpcPropagation = options ? getEffectiveRpcPropagation(options) : false;\n\n return new Proxy(env, {\n get(target, prop, receiver) {\n const item = Reflect.get(target, prop, receiver);\n\n if (!isProxyable(item)) {\n return item;\n }\n\n const cached = instrumentedBindings.get(item);\n\n if (cached) {\n return cached;\n }\n\n if (isD1Database(item)) {\n const instrumented = instrumentD1(item);\n instrumentedBindings.set(item, instrumented);\n return instrumented;\n }\n\n if (isQueue(item)) {\n const bindingName = typeof prop === 'string' ? prop : String(prop);\n const instrumented = instrumentQueueProducer(item, bindingName);\n instrumentedBindings.set(item, instrumented);\n return instrumented;\n }\n\n if (isR2Bucket(item)) {\n const bindingName = typeof prop === 'string' ? prop : String(prop);\n const instrumented = instrumentR2Bucket(item, bindingName);\n instrumentedBindings.set(item, instrumented);\n return instrumented;\n }\n\n if (!rpcPropagation) {\n return item;\n }\n\n if (isDurableObjectNamespace(item)) {\n const instrumented = instrumentDurableObjectNamespace(item);\n instrumentedBindings.set(item, instrumented);\n return instrumented;\n }\n\n if (isJSRPC(item)) {\n const instrumented = new Proxy(item, {\n get(target, p) {\n const value = Reflect.get(target, p);\n\n if (p === 'fetch' && typeof value === 'function') {\n return instrumentFetcher((...args) => Reflect.apply(value, target, args));\n }\n\n if (typeof value === 'function' && typeof p === 'string' && !STUB_NON_RPC_METHODS.has(p)) {\n return (...args: unknown[]) => Reflect.apply(value, target, appendRpcMeta(args));\n }\n\n return value;\n },\n });\n\n instrumentedBindings.set(item, instrumented);\n return instrumented;\n }\n\n return item;\n },\n });\n}\n"],"names":["target"],"mappings":"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"}
1
+ {"version":3,"file":"instrumentEnv.js","sources":["../../../../src/instrumentations/worker/instrumentEnv.ts"],"sourcesContent":["import { isObjectLike } from '@sentry/core';\nimport type { CloudflareOptions } from '../../client';\nimport { isD1Database, isDurableObjectNamespace, isJSRPC, isQueue, isR2Bucket } from '../../utils/isBinding';\nimport { instrumentD1 } from './instrumentD1';\nimport { appendRpcMeta } from '../../utils/rpcMeta';\nimport { getEffectiveRpcPropagation } from '../../utils/rpcOptions';\nimport { instrumentDurableObjectNamespace, STUB_NON_RPC_METHODS } from '../instrumentDurableObjectNamespace';\nimport { instrumentFetcher } from './instrumentFetcher';\nimport { instrumentQueueProducer } from './instrumentQueueProducer';\nimport { instrumentR2Bucket } from './instrumentR2';\n\nfunction isProxyable(item: unknown): item is object {\n return isObjectLike(item) || typeof item === 'function';\n}\n\nconst instrumentedBindings = new WeakMap<object, unknown>();\n\n/**\n * Wraps the Cloudflare `env` object in a Proxy that detects binding types\n * on property access and returns instrumented versions.\n *\n * Currently detects:\n * - DurableObjectNamespace (via `idFromName` duck-typing)\n * - Service bindings / JSRPC proxies\n * - Queue producers (via `send` + `sendBatch` duck-typing)\n * - R2 Buckets (via `head` + `put` + `createMultipartUpload` duck-typing)\n *\n * @param env - The Cloudflare env object to instrument\n * @param options - Optional CloudflareOptions to control RPC trace propagation\n */\nexport function instrumentEnv<Env extends Record<string, unknown>>(env: Env, options?: CloudflareOptions): Env {\n if (!env || typeof env !== 'object') {\n return env;\n }\n\n const rpcPropagation = options ? getEffectiveRpcPropagation(options) : false;\n\n return new Proxy(env, {\n get(target, prop, receiver) {\n const item = Reflect.get(target, prop, receiver);\n\n if (!isProxyable(item)) {\n return item;\n }\n\n const cached = instrumentedBindings.get(item);\n\n if (cached) {\n return cached;\n }\n\n if (isD1Database(item)) {\n const instrumented = instrumentD1(item);\n instrumentedBindings.set(item, instrumented);\n return instrumented;\n }\n\n if (isQueue(item)) {\n const bindingName = typeof prop === 'string' ? prop : String(prop);\n const instrumented = instrumentQueueProducer(item, bindingName);\n instrumentedBindings.set(item, instrumented);\n return instrumented;\n }\n\n if (isR2Bucket(item)) {\n const bindingName = typeof prop === 'string' ? prop : String(prop);\n const instrumented = instrumentR2Bucket(item, bindingName);\n instrumentedBindings.set(item, instrumented);\n return instrumented;\n }\n\n if (!rpcPropagation) {\n return item;\n }\n\n if (isDurableObjectNamespace(item)) {\n const instrumented = instrumentDurableObjectNamespace(item);\n instrumentedBindings.set(item, instrumented);\n return instrumented;\n }\n\n if (isJSRPC(item)) {\n const instrumented = new Proxy(item, {\n get(target, p) {\n const value = Reflect.get(target, p);\n\n if (p === 'fetch' && typeof value === 'function') {\n return instrumentFetcher((...args) => Reflect.apply(value, target, args));\n }\n\n if (typeof value === 'function' && typeof p === 'string' && !STUB_NON_RPC_METHODS.has(p)) {\n return (...args: unknown[]) => Reflect.apply(value, target, appendRpcMeta(args));\n }\n\n return value;\n },\n });\n\n instrumentedBindings.set(item, instrumented);\n return instrumented;\n }\n\n return item;\n },\n });\n}\n"],"names":["target"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"instrumentQueueProducer.js","sources":["../../../../src/instrumentations/worker/instrumentQueueProducer.ts"],"sourcesContent":["import type { MessageSendRequest, Queue, QueueSendBatchOptions, QueueSendOptions } from '@cloudflare/workers-types';\nimport { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, startSpan } from '@sentry/core';\n\nconst ORIGIN = 'auto.faas.cloudflare.queue';\n\nfunction startPublishSpan<T>(\n options: {\n bindingName: string;\n bodySize: number | undefined;\n messageCount?: number;\n },\n callback: () => T,\n): T {\n const { bindingName, bodySize, messageCount } = options;\n\n return startSpan(\n {\n op: 'queue.publish',\n name: `send ${bindingName}`,\n attributes: {\n 'messaging.system': 'cloudflare',\n 'messaging.destination.name': bindingName,\n 'messaging.operation.type': 'send',\n 'messaging.operation.name': 'send',\n ...(messageCount !== undefined && { 'messaging.batch.message_count': messageCount }),\n 'messaging.message.body.size': bodySize,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'queue.publish',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,\n },\n },\n callback,\n );\n}\n\nfunction getBodySize(body: unknown): number | undefined {\n if (body == null) {\n return undefined;\n }\n\n if (typeof body === 'string') {\n return new TextEncoder().encode(body).byteLength;\n }\n\n if (body instanceof ArrayBuffer) {\n return body.byteLength;\n }\n\n if (ArrayBuffer.isView(body)) {\n return body.byteLength;\n }\n\n try {\n return new TextEncoder().encode(JSON.stringify(body)).byteLength;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Wraps a Queue producer binding to create `queue.publish` spans on\n * `send` and `sendBatch` calls.\n *\n * The queue's own name is not available on the binding object, so we use\n * the env binding key (e.g. `MY_QUEUE`) as `messaging.destination.name`.\n */\nexport function instrumentQueueProducer<T extends Queue>(queue: T, bindingName: string): T {\n return new Proxy(queue, {\n get(target, prop, receiver) {\n if (prop === 'send') {\n const original = Reflect.get(target, prop, receiver) as Queue['send'];\n\n return function (this: unknown, message: unknown, options?: QueueSendOptions): Promise<void> {\n return startPublishSpan({ bindingName, bodySize: getBodySize(message) }, () =>\n Reflect.apply(original, target, [message, options]),\n );\n };\n }\n\n if (prop === 'sendBatch') {\n const original = Reflect.get(target, prop, receiver) as Queue['sendBatch'];\n return function (\n this: unknown,\n messages: Iterable<MessageSendRequest>,\n options?: QueueSendBatchOptions,\n ): Promise<void> {\n const messageArray = Array.from(messages);\n const totalBodySize = messageArray.reduce<number | undefined>((acc, m) => {\n const size = getBodySize(m.body);\n if (size === undefined) {\n return acc;\n }\n return (acc ?? 0) + size;\n }, undefined);\n\n return startPublishSpan({ bindingName, bodySize: totalBodySize, messageCount: messageArray.length }, () =>\n Reflect.apply(original, target, [messageArray, options]),\n );\n };\n }\n\n return Reflect.get(target, prop, receiver);\n },\n });\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"instrumentQueueProducer.js","sources":["../../../../src/instrumentations/worker/instrumentQueueProducer.ts"],"sourcesContent":["import type { MessageSendRequest, Queue, QueueSendBatchOptions, QueueSendOptions } from '@cloudflare/workers-types';\nimport { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, startSpan } from '@sentry/core';\n\nconst ORIGIN = 'auto.faas.cloudflare.queue';\n\nfunction startPublishSpan<T>(\n options: {\n bindingName: string;\n bodySize: number | undefined;\n messageCount?: number;\n },\n callback: () => T,\n): T {\n const { bindingName, bodySize, messageCount } = options;\n\n return startSpan(\n {\n op: 'queue.publish',\n name: `send ${bindingName}`,\n attributes: {\n 'messaging.system': 'cloudflare',\n 'messaging.destination.name': bindingName,\n 'messaging.operation.type': 'send',\n 'messaging.operation.name': 'send',\n ...(messageCount !== undefined && { 'messaging.batch.message_count': messageCount }),\n 'messaging.message.body.size': bodySize,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'queue.publish',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,\n },\n },\n callback,\n );\n}\n\nfunction getBodySize(body: unknown): number | undefined {\n if (body == null) {\n return undefined;\n }\n\n if (typeof body === 'string') {\n return new TextEncoder().encode(body).byteLength;\n }\n\n if (body instanceof ArrayBuffer) {\n return body.byteLength;\n }\n\n if (ArrayBuffer.isView(body)) {\n return body.byteLength;\n }\n\n try {\n return new TextEncoder().encode(JSON.stringify(body)).byteLength;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Wraps a Queue producer binding to create `queue.publish` spans on\n * `send` and `sendBatch` calls.\n *\n * The queue's own name is not available on the binding object, so we use\n * the env binding key (e.g. `MY_QUEUE`) as `messaging.destination.name`.\n */\nexport function instrumentQueueProducer<T extends Queue>(queue: T, bindingName: string): T {\n return new Proxy(queue, {\n get(target, prop, receiver) {\n if (prop === 'send') {\n const original = Reflect.get(target, prop, receiver) as Queue['send'];\n\n return function (this: unknown, message: unknown, options?: QueueSendOptions): ReturnType<Queue['send']> {\n return startPublishSpan({ bindingName, bodySize: getBodySize(message) }, () =>\n Reflect.apply(original, target, [message, options]),\n );\n };\n }\n\n if (prop === 'sendBatch') {\n const original = Reflect.get(target, prop, receiver) as Queue['sendBatch'];\n return function (\n this: unknown,\n messages: Iterable<MessageSendRequest>,\n options?: QueueSendBatchOptions,\n ): ReturnType<Queue['sendBatch']> {\n const messageArray = Array.from(messages);\n const totalBodySize = messageArray.reduce<number | undefined>((acc, m) => {\n const size = getBodySize(m.body);\n if (size === undefined) {\n return acc;\n }\n return (acc ?? 0) + size;\n }, undefined);\n\n return startPublishSpan({ bindingName, bodySize: totalBodySize, messageCount: messageArray.length }, () =>\n Reflect.apply(original, target, [messageArray, options]),\n );\n };\n }\n\n return Reflect.get(target, prop, receiver);\n },\n });\n}\n"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { startSpan, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_OP } from '@sentry/core';
1
+ import { startSpan, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_OP, isObjectLike } from '@sentry/core';
2
2
 
3
3
  const ORIGIN = "auto.faas.cloudflare.r2";
4
4
  const R2_OPERATIONS = {
@@ -25,7 +25,7 @@ const R2_OPERATIONS = {
25
25
  }
26
26
  };
27
27
  function isR2ListOptions(key) {
28
- return typeof key === "object" && key !== null && !Array.isArray(key);
28
+ return isObjectLike(key) && !Array.isArray(key);
29
29
  }
30
30
  function createSpanOptions(bindingName, r2Op, key) {
31
31
  const { spanName, op, operation } = R2_OPERATIONS[r2Op];
@@ -1 +1 @@
1
- {"version":3,"file":"instrumentR2.js","sources":["../../../../src/instrumentations/worker/instrumentR2.ts"],"sourcesContent":["import type { R2Bucket, R2ListOptions, R2MultipartUpload } from '@cloudflare/workers-types';\nimport { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, startSpan } from '@sentry/core';\n\nconst ORIGIN = 'auto.faas.cloudflare.r2';\n\nconst R2_OPERATIONS = {\n get: { spanName: 'r2_get', op: 'object.get', operation: 'GetObject' },\n head: { spanName: 'r2_head', op: 'object.head', operation: 'HeadObject' },\n put: { spanName: 'r2_put', op: 'object.put', operation: 'PutObject' },\n delete: { spanName: 'r2_delete', op: 'object.delete', operation: 'DeleteObject' },\n list: { spanName: 'r2_list', op: 'object.list', operation: 'ListObjects' },\n uploadPart: { spanName: 'r2_uploadPart', op: 'object.upload_part', operation: 'UploadPart' },\n abortMultipartUpload: {\n spanName: 'r2_abortMultipartUpload',\n op: 'object.multipart_upload.abort',\n operation: 'AbortMultipartUpload',\n },\n createMultipartUpload: {\n spanName: 'r2_createMultipartUpload',\n op: 'object.multipart_upload.create',\n operation: 'CreateMultipartUpload',\n },\n completeMultipartUpload: {\n spanName: 'r2_completeMultipartUpload',\n op: 'object.multipart_upload.complete',\n operation: 'CompleteMultipartUpload',\n },\n} as const;\n\ntype R2OperationKey = keyof typeof R2_OPERATIONS;\n\nfunction isR2ListOptions(key: unknown): key is R2ListOptions {\n return typeof key === 'object' && key !== null && !Array.isArray(key);\n}\n\nfunction createSpanOptions(bindingName: string, r2Op: R2OperationKey, key?: string | string[] | R2ListOptions) {\n const { spanName, op, operation } = R2_OPERATIONS[r2Op];\n const requestKey = Array.isArray(key) ? key.join(', ') : typeof key === 'string' ? key : undefined;\n\n return {\n op,\n name: spanName,\n attributes: {\n 'cloudflare.r2.operation': operation,\n 'cloudflare.r2.bucket': bindingName,\n ...(requestKey !== undefined && { 'cloudflare.r2.request.key': requestKey }),\n ...(isR2ListOptions(key) && key.prefix !== undefined && { 'cloudflare.r2.request.prefix': key.prefix }),\n ...(isR2ListOptions(key) && key.delimiter !== undefined && { 'cloudflare.r2.request.delimiter': key.delimiter }),\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,\n },\n };\n}\n\nfunction instrumentR2MultipartUpload(upload: R2MultipartUpload, bindingName: string): R2MultipartUpload {\n const { key } = upload;\n\n return new Proxy(upload, {\n get(target, prop, receiver) {\n if (prop === 'uploadPart') {\n const original = Reflect.get(target, prop, receiver);\n\n return function (this: unknown, ...args: Parameters<R2MultipartUpload['uploadPart']>) {\n const [partNumber] = args;\n\n return startSpan(\n {\n ...createSpanOptions(bindingName, 'uploadPart', key),\n attributes: {\n ...createSpanOptions(bindingName, 'uploadPart', key).attributes,\n 'cloudflare.r2.request.part_number': partNumber,\n },\n },\n () => Reflect.apply(original, target, args),\n );\n };\n }\n\n if (prop === 'abort') {\n const original = Reflect.get(target, prop, receiver);\n\n return function (this: unknown) {\n return startSpan(createSpanOptions(bindingName, 'abortMultipartUpload', key), () =>\n Reflect.apply(original, target, []),\n );\n };\n }\n\n if (prop === 'complete') {\n const original = Reflect.get(target, prop, receiver);\n\n return function (this: unknown, ...args: Parameters<R2MultipartUpload['complete']>) {\n return startSpan(createSpanOptions(bindingName, 'completeMultipartUpload', key), () =>\n Reflect.apply(original, target, args),\n );\n };\n }\n\n return Reflect.get(target, prop, receiver);\n },\n });\n}\n\n/**\n * Wraps a Cloudflare R2 Bucket binding to create spans on bucket operations.\n *\n * Instrumented methods: get, head, put, delete, list, createMultipartUpload,\n * resumeMultipartUpload (and the resulting multipart upload operations).\n */\nexport function instrumentR2Bucket<T extends R2Bucket>(bucket: T, bindingName: string): T {\n return new Proxy(bucket, {\n get(target, prop, receiver) {\n if (prop === 'get' || prop === 'head' || prop === 'put' || prop === 'delete' || prop === 'list') {\n const original = Reflect.get(target, prop, receiver);\n\n return function (this: unknown, ...args: Parameters<R2Bucket[typeof prop]>) {\n const [key] = args;\n\n return startSpan(createSpanOptions(bindingName, prop, key), () => Reflect.apply(original, target, args));\n };\n }\n\n if (prop === 'createMultipartUpload') {\n const original = Reflect.get(target, prop, receiver) as R2Bucket['createMultipartUpload'];\n\n return function (this: unknown, ...args: Parameters<R2Bucket['createMultipartUpload']>) {\n const [key] = args;\n\n return startSpan(createSpanOptions(bindingName, 'createMultipartUpload', key), async () => {\n const upload = await Reflect.apply(original, target, args);\n return instrumentR2MultipartUpload(upload, bindingName);\n });\n };\n }\n\n if (prop === 'resumeMultipartUpload') {\n const original = Reflect.get(target, prop, receiver);\n\n return function (this: unknown, ...args: Parameters<R2Bucket['resumeMultipartUpload']>) {\n const upload = Reflect.apply(original, target, args);\n\n return instrumentR2MultipartUpload(upload, bindingName);\n };\n }\n\n return Reflect.get(target, prop, receiver);\n },\n });\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"instrumentR2.js","sources":["../../../../src/instrumentations/worker/instrumentR2.ts"],"sourcesContent":["import type { R2Bucket, R2ListOptions, R2MultipartUpload } from '@cloudflare/workers-types';\nimport { isObjectLike, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, startSpan } from '@sentry/core';\n\nconst ORIGIN = 'auto.faas.cloudflare.r2';\n\nconst R2_OPERATIONS = {\n get: { spanName: 'r2_get', op: 'object.get', operation: 'GetObject' },\n head: { spanName: 'r2_head', op: 'object.head', operation: 'HeadObject' },\n put: { spanName: 'r2_put', op: 'object.put', operation: 'PutObject' },\n delete: { spanName: 'r2_delete', op: 'object.delete', operation: 'DeleteObject' },\n list: { spanName: 'r2_list', op: 'object.list', operation: 'ListObjects' },\n uploadPart: { spanName: 'r2_uploadPart', op: 'object.upload_part', operation: 'UploadPart' },\n abortMultipartUpload: {\n spanName: 'r2_abortMultipartUpload',\n op: 'object.multipart_upload.abort',\n operation: 'AbortMultipartUpload',\n },\n createMultipartUpload: {\n spanName: 'r2_createMultipartUpload',\n op: 'object.multipart_upload.create',\n operation: 'CreateMultipartUpload',\n },\n completeMultipartUpload: {\n spanName: 'r2_completeMultipartUpload',\n op: 'object.multipart_upload.complete',\n operation: 'CompleteMultipartUpload',\n },\n} as const;\n\ntype R2OperationKey = keyof typeof R2_OPERATIONS;\n\nfunction isR2ListOptions(key: unknown): key is R2ListOptions {\n return isObjectLike(key) && !Array.isArray(key);\n}\n\nfunction createSpanOptions(bindingName: string, r2Op: R2OperationKey, key?: string | string[] | R2ListOptions) {\n const { spanName, op, operation } = R2_OPERATIONS[r2Op];\n const requestKey = Array.isArray(key) ? key.join(', ') : typeof key === 'string' ? key : undefined;\n\n return {\n op,\n name: spanName,\n attributes: {\n 'cloudflare.r2.operation': operation,\n 'cloudflare.r2.bucket': bindingName,\n ...(requestKey !== undefined && { 'cloudflare.r2.request.key': requestKey }),\n ...(isR2ListOptions(key) && key.prefix !== undefined && { 'cloudflare.r2.request.prefix': key.prefix }),\n ...(isR2ListOptions(key) && key.delimiter !== undefined && { 'cloudflare.r2.request.delimiter': key.delimiter }),\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,\n },\n };\n}\n\nfunction instrumentR2MultipartUpload(upload: R2MultipartUpload, bindingName: string): R2MultipartUpload {\n const { key } = upload;\n\n return new Proxy(upload, {\n get(target, prop, receiver) {\n if (prop === 'uploadPart') {\n const original = Reflect.get(target, prop, receiver);\n\n return function (this: unknown, ...args: Parameters<R2MultipartUpload['uploadPart']>) {\n const [partNumber] = args;\n\n return startSpan(\n {\n ...createSpanOptions(bindingName, 'uploadPart', key),\n attributes: {\n ...createSpanOptions(bindingName, 'uploadPart', key).attributes,\n 'cloudflare.r2.request.part_number': partNumber,\n },\n },\n () => Reflect.apply(original, target, args),\n );\n };\n }\n\n if (prop === 'abort') {\n const original = Reflect.get(target, prop, receiver);\n\n return function (this: unknown) {\n return startSpan(createSpanOptions(bindingName, 'abortMultipartUpload', key), () =>\n Reflect.apply(original, target, []),\n );\n };\n }\n\n if (prop === 'complete') {\n const original = Reflect.get(target, prop, receiver);\n\n return function (this: unknown, ...args: Parameters<R2MultipartUpload['complete']>) {\n return startSpan(createSpanOptions(bindingName, 'completeMultipartUpload', key), () =>\n Reflect.apply(original, target, args),\n );\n };\n }\n\n return Reflect.get(target, prop, receiver);\n },\n });\n}\n\n/**\n * Wraps a Cloudflare R2 Bucket binding to create spans on bucket operations.\n *\n * Instrumented methods: get, head, put, delete, list, createMultipartUpload,\n * resumeMultipartUpload (and the resulting multipart upload operations).\n */\nexport function instrumentR2Bucket<T extends R2Bucket>(bucket: T, bindingName: string): T {\n return new Proxy(bucket, {\n get(target, prop, receiver) {\n if (prop === 'get' || prop === 'head' || prop === 'put' || prop === 'delete' || prop === 'list') {\n const original = Reflect.get(target, prop, receiver);\n\n return function (this: unknown, ...args: Parameters<R2Bucket[typeof prop]>) {\n const [key] = args;\n\n return startSpan(createSpanOptions(bindingName, prop, key), () => Reflect.apply(original, target, args));\n };\n }\n\n if (prop === 'createMultipartUpload') {\n const original = Reflect.get(target, prop, receiver) as R2Bucket['createMultipartUpload'];\n\n return function (this: unknown, ...args: Parameters<R2Bucket['createMultipartUpload']>) {\n const [key] = args;\n\n return startSpan(createSpanOptions(bindingName, 'createMultipartUpload', key), async () => {\n const upload = await Reflect.apply(original, target, args);\n return instrumentR2MultipartUpload(upload, bindingName);\n });\n };\n }\n\n if (prop === 'resumeMultipartUpload') {\n const original = Reflect.get(target, prop, receiver);\n\n return function (this: unknown, ...args: Parameters<R2Bucket['resumeMultipartUpload']>) {\n const upload = Reflect.apply(original, target, args);\n\n return instrumentR2MultipartUpload(upload, bindingName);\n };\n }\n\n return Reflect.get(target, prop, receiver);\n },\n });\n}\n"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { defineIntegration, debug, getActiveSpan, updateSpanName, getRootSpan, getIsolationScope, captureException, getClient } from '@sentry/core';
1
+ import { defineIntegration, debug, getActiveSpan, updateSpanName, getRootSpan, getIsolationScope, captureException, isObjectLike, getClient } from '@sentry/core';
2
2
  import { DEBUG_BUILD } from '../debug-build.js';
3
3
 
4
4
  const INTEGRATION_NAME = "Hono";
@@ -9,7 +9,7 @@ function isHonoError(err) {
9
9
  if (err instanceof Error) {
10
10
  return true;
11
11
  }
12
- return typeof err === "object" && err !== null && "status" in err;
12
+ return isObjectLike(err) && "status" in err;
13
13
  }
14
14
  const routePath = (c) => c.req?.path ?? "";
15
15
  const _honoIntegration = ((options = {}) => {