@sentry/cloudflare 9.41.0 → 10.0.0-alpha.1

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.
@@ -7,24 +7,14 @@ const sdk = require('./sdk.js');
7
7
 
8
8
  const UUID_REGEX = /^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$/i;
9
9
 
10
- /**
11
- * Hashes a string to a UUID using SHA-1.
12
- */
13
- async function deterministicTraceIdFromInstanceId(instanceId) {
14
- const buf = await crypto.subtle.digest('SHA-1', new TextEncoder().encode(instanceId));
15
- return (
16
- Array.from(new Uint8Array(buf))
17
- // We only need the first 16 bytes for the 32 characters
18
- .slice(0, 16)
19
- .map(b => b.toString(16).padStart(2, '0'))
20
- .join('')
21
- );
22
- }
10
+ function propagationContextFromInstanceId(instanceId) {
11
+ // Validate and normalize traceId - should be a valid UUID with or without hyphens
12
+ if (!UUID_REGEX.test(instanceId)) {
13
+ throw new Error("Invalid 'instanceId' for workflow: Sentry requires random UUIDs for instanceId.");
14
+ }
23
15
 
24
- async function propagationContextFromInstanceId(instanceId) {
25
- const traceId = UUID_REGEX.test(instanceId)
26
- ? instanceId.replace(/-/g, '')
27
- : await deterministicTraceIdFromInstanceId(instanceId);
16
+ // Remove hyphens to get UUID without hyphens
17
+ const traceId = instanceId.replace(/-/g, '');
28
18
 
29
19
  // Derive sampleRand from last 4 characters of the random UUID
30
20
  //
@@ -53,7 +43,7 @@ async function workflowStepWithSentry(
53
43
  scopeUtils.addCloudResourceContext(isolationScope);
54
44
 
55
45
  return core.withScope(async scope => {
56
- const propagationContext = await propagationContextFromInstanceId(instanceId);
46
+ const propagationContext = propagationContextFromInstanceId(instanceId);
57
47
  scope.setPropagationContext(propagationContext);
58
48
 
59
49
  // eslint-disable-next-line no-return-await
@@ -167,6 +157,5 @@ function instrumentWorkflowWithSentry
167
157
  }) ;
168
158
  }
169
159
 
170
- exports.deterministicTraceIdFromInstanceId = deterministicTraceIdFromInstanceId;
171
160
  exports.instrumentWorkflowWithSentry = instrumentWorkflowWithSentry;
172
161
  //# sourceMappingURL=workflows.js.map
@@ -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 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 { addCloudResourceContext } from './scope-utils';\nimport { init } from './sdk';\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\nasync function workflowStepWithSentry<V>(\n instanceId: string,\n options: CloudflareOptions,\n callback: () => V,\n): Promise<V> {\n setAsyncLocalStorageAsyncContextStrategy();\n\n return withIsolationScope(async isolationScope => {\n const client = init({ ...options, enableDedupe: false });\n isolationScope.setClient(client);\n\n addCloudResourceContext(isolationScope);\n\n return withScope(async scope => {\n const propagationContext = await propagationContextFromInstanceId(instanceId);\n scope.setPropagationContext(propagationContext);\n\n // eslint-disable-next-line no-return-await\n return await callback();\n });\n });\n}\n\nclass WrappedWorkflowStep implements WorkflowStep {\n public constructor(\n private _instanceId: string,\n private _ctx: ExecutionContext,\n private _options: CloudflareOptions,\n private _step: WorkflowStep,\n ) {}\n\n public async do<T extends Rpc.Serializable<T>>(name: string, callback: () => Promise<T>): Promise<T>;\n public async do<T extends Rpc.Serializable<T>>(\n name: string,\n config: WorkflowStepConfig,\n callback: () => Promise<T>,\n ): Promise<T>;\n public async do<T extends Rpc.Serializable<T>>(\n name: string,\n configOrCallback: WorkflowStepConfig | (() => Promise<T>),\n maybeCallback?: () => Promise<T>,\n ): Promise<T> {\n const userCallback = (maybeCallback || configOrCallback) as () => Promise<T>;\n const config = typeof configOrCallback === 'function' ? undefined : configOrCallback;\n\n const instrumentedCallback: () => Promise<T> = async () => {\n return workflowStepWithSentry(this._instanceId, this._options, async () => {\n return startSpan(\n {\n op: 'function.step.do',\n name,\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 [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();\n span.setStatus({ code: 1 });\n return result;\n } catch (error) {\n captureException(error, { mechanism: { handled: true, type: 'cloudflare' } });\n throw error;\n } finally {\n this._ctx.waitUntil(flush(2000));\n }\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 options = optionsCallback(env);\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 return obj.run.call(obj, event, new WrappedWorkflowStep(event.instanceId, ctx, options, step));\n };\n }\n return Reflect.get(obj, prop, receiver);\n },\n });\n },\n }) as C;\n}\n"],"names":["setAsyncLocalStorageAsyncContextStrategy","withIsolationScope","init","addCloudResourceContext","withScope","startSpan","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","SEMANTIC_ATTRIBUTE_SENTRY_SOURCE","captureException","flush"],"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 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 { addCloudResourceContext } from './scope-utils';\nimport { init } from './sdk';\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\nfunction propagationContextFromInstanceId(instanceId: string): PropagationContext {\n // Validate and normalize traceId - should be a valid UUID with or without hyphens\n if (!UUID_REGEX.test(instanceId)) {\n throw new Error(\"Invalid 'instanceId' for workflow: Sentry requires random UUIDs for instanceId.\");\n }\n\n // Remove hyphens to get UUID without hyphens\n const traceId = instanceId.replace(/-/g, '');\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\nasync function workflowStepWithSentry<V>(\n instanceId: string,\n options: CloudflareOptions,\n callback: () => V,\n): Promise<V> {\n setAsyncLocalStorageAsyncContextStrategy();\n\n return withIsolationScope(async isolationScope => {\n const client = init({ ...options, enableDedupe: false });\n isolationScope.setClient(client);\n\n addCloudResourceContext(isolationScope);\n\n return withScope(async scope => {\n const propagationContext = propagationContextFromInstanceId(instanceId);\n scope.setPropagationContext(propagationContext);\n\n // eslint-disable-next-line no-return-await\n return await callback();\n });\n });\n}\n\nclass WrappedWorkflowStep implements WorkflowStep {\n public constructor(\n private _instanceId: string,\n private _ctx: ExecutionContext,\n private _options: CloudflareOptions,\n private _step: WorkflowStep,\n ) {}\n\n public async do<T extends Rpc.Serializable<T>>(name: string, callback: () => Promise<T>): Promise<T>;\n public async do<T extends Rpc.Serializable<T>>(\n name: string,\n config: WorkflowStepConfig,\n callback: () => Promise<T>,\n ): Promise<T>;\n public async do<T extends Rpc.Serializable<T>>(\n name: string,\n configOrCallback: WorkflowStepConfig | (() => Promise<T>),\n maybeCallback?: () => Promise<T>,\n ): Promise<T> {\n const userCallback = (maybeCallback || configOrCallback) as () => Promise<T>;\n const config = typeof configOrCallback === 'function' ? undefined : configOrCallback;\n\n const instrumentedCallback: () => Promise<T> = async () => {\n return workflowStepWithSentry(this._instanceId, this._options, async () => {\n return startSpan(\n {\n op: 'function.step.do',\n name,\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 [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();\n span.setStatus({ code: 1 });\n return result;\n } catch (error) {\n captureException(error, { mechanism: { handled: true, type: 'cloudflare' } });\n throw error;\n } finally {\n this._ctx.waitUntil(flush(2000));\n }\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 options = optionsCallback(env);\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 return obj.run.call(obj, event, new WrappedWorkflowStep(event.instanceId, ctx, options, step));\n };\n }\n return Reflect.get(obj, prop, receiver);\n },\n });\n },\n }) as C;\n}\n"],"names":["setAsyncLocalStorageAsyncContextStrategy","withIsolationScope","init","addCloudResourceContext","withScope","startSpan","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","SEMANTIC_ATTRIBUTE_SENTRY_SOURCE","captureException","flush"],"mappings":"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"}
@@ -1 +1 @@
1
- {"type":"module","version":"9.41.0","sideEffects":false}
1
+ {"type":"module","version":"10.0.0-alpha.1","sideEffects":false}
@@ -5,24 +5,14 @@ import { init } from './sdk.js';
5
5
 
6
6
  const UUID_REGEX = /^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$/i;
7
7
 
8
- /**
9
- * Hashes a string to a UUID using SHA-1.
10
- */
11
- async function deterministicTraceIdFromInstanceId(instanceId) {
12
- const buf = await crypto.subtle.digest('SHA-1', new TextEncoder().encode(instanceId));
13
- return (
14
- Array.from(new Uint8Array(buf))
15
- // We only need the first 16 bytes for the 32 characters
16
- .slice(0, 16)
17
- .map(b => b.toString(16).padStart(2, '0'))
18
- .join('')
19
- );
20
- }
8
+ function propagationContextFromInstanceId(instanceId) {
9
+ // Validate and normalize traceId - should be a valid UUID with or without hyphens
10
+ if (!UUID_REGEX.test(instanceId)) {
11
+ throw new Error("Invalid 'instanceId' for workflow: Sentry requires random UUIDs for instanceId.");
12
+ }
21
13
 
22
- async function propagationContextFromInstanceId(instanceId) {
23
- const traceId = UUID_REGEX.test(instanceId)
24
- ? instanceId.replace(/-/g, '')
25
- : await deterministicTraceIdFromInstanceId(instanceId);
14
+ // Remove hyphens to get UUID without hyphens
15
+ const traceId = instanceId.replace(/-/g, '');
26
16
 
27
17
  // Derive sampleRand from last 4 characters of the random UUID
28
18
  //
@@ -51,7 +41,7 @@ async function workflowStepWithSentry(
51
41
  addCloudResourceContext(isolationScope);
52
42
 
53
43
  return withScope(async scope => {
54
- const propagationContext = await propagationContextFromInstanceId(instanceId);
44
+ const propagationContext = propagationContextFromInstanceId(instanceId);
55
45
  scope.setPropagationContext(propagationContext);
56
46
 
57
47
  // eslint-disable-next-line no-return-await
@@ -165,5 +155,5 @@ function instrumentWorkflowWithSentry
165
155
  }) ;
166
156
  }
167
157
 
168
- export { deterministicTraceIdFromInstanceId, instrumentWorkflowWithSentry };
158
+ export { instrumentWorkflowWithSentry };
169
159
  //# sourceMappingURL=workflows.js.map
@@ -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 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 { addCloudResourceContext } from './scope-utils';\nimport { init } from './sdk';\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\nasync function workflowStepWithSentry<V>(\n instanceId: string,\n options: CloudflareOptions,\n callback: () => V,\n): Promise<V> {\n setAsyncLocalStorageAsyncContextStrategy();\n\n return withIsolationScope(async isolationScope => {\n const client = init({ ...options, enableDedupe: false });\n isolationScope.setClient(client);\n\n addCloudResourceContext(isolationScope);\n\n return withScope(async scope => {\n const propagationContext = await propagationContextFromInstanceId(instanceId);\n scope.setPropagationContext(propagationContext);\n\n // eslint-disable-next-line no-return-await\n return await callback();\n });\n });\n}\n\nclass WrappedWorkflowStep implements WorkflowStep {\n public constructor(\n private _instanceId: string,\n private _ctx: ExecutionContext,\n private _options: CloudflareOptions,\n private _step: WorkflowStep,\n ) {}\n\n public async do<T extends Rpc.Serializable<T>>(name: string, callback: () => Promise<T>): Promise<T>;\n public async do<T extends Rpc.Serializable<T>>(\n name: string,\n config: WorkflowStepConfig,\n callback: () => Promise<T>,\n ): Promise<T>;\n public async do<T extends Rpc.Serializable<T>>(\n name: string,\n configOrCallback: WorkflowStepConfig | (() => Promise<T>),\n maybeCallback?: () => Promise<T>,\n ): Promise<T> {\n const userCallback = (maybeCallback || configOrCallback) as () => Promise<T>;\n const config = typeof configOrCallback === 'function' ? undefined : configOrCallback;\n\n const instrumentedCallback: () => Promise<T> = async () => {\n return workflowStepWithSentry(this._instanceId, this._options, async () => {\n return startSpan(\n {\n op: 'function.step.do',\n name,\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 [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();\n span.setStatus({ code: 1 });\n return result;\n } catch (error) {\n captureException(error, { mechanism: { handled: true, type: 'cloudflare' } });\n throw error;\n } finally {\n this._ctx.waitUntil(flush(2000));\n }\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 options = optionsCallback(env);\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 return obj.run.call(obj, event, new WrappedWorkflowStep(event.instanceId, ctx, options, step));\n };\n }\n return Reflect.get(obj, prop, receiver);\n },\n });\n },\n }) as C;\n}\n"],"names":[],"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 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 { addCloudResourceContext } from './scope-utils';\nimport { init } from './sdk';\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\nfunction propagationContextFromInstanceId(instanceId: string): PropagationContext {\n // Validate and normalize traceId - should be a valid UUID with or without hyphens\n if (!UUID_REGEX.test(instanceId)) {\n throw new Error(\"Invalid 'instanceId' for workflow: Sentry requires random UUIDs for instanceId.\");\n }\n\n // Remove hyphens to get UUID without hyphens\n const traceId = instanceId.replace(/-/g, '');\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\nasync function workflowStepWithSentry<V>(\n instanceId: string,\n options: CloudflareOptions,\n callback: () => V,\n): Promise<V> {\n setAsyncLocalStorageAsyncContextStrategy();\n\n return withIsolationScope(async isolationScope => {\n const client = init({ ...options, enableDedupe: false });\n isolationScope.setClient(client);\n\n addCloudResourceContext(isolationScope);\n\n return withScope(async scope => {\n const propagationContext = propagationContextFromInstanceId(instanceId);\n scope.setPropagationContext(propagationContext);\n\n // eslint-disable-next-line no-return-await\n return await callback();\n });\n });\n}\n\nclass WrappedWorkflowStep implements WorkflowStep {\n public constructor(\n private _instanceId: string,\n private _ctx: ExecutionContext,\n private _options: CloudflareOptions,\n private _step: WorkflowStep,\n ) {}\n\n public async do<T extends Rpc.Serializable<T>>(name: string, callback: () => Promise<T>): Promise<T>;\n public async do<T extends Rpc.Serializable<T>>(\n name: string,\n config: WorkflowStepConfig,\n callback: () => Promise<T>,\n ): Promise<T>;\n public async do<T extends Rpc.Serializable<T>>(\n name: string,\n configOrCallback: WorkflowStepConfig | (() => Promise<T>),\n maybeCallback?: () => Promise<T>,\n ): Promise<T> {\n const userCallback = (maybeCallback || configOrCallback) as () => Promise<T>;\n const config = typeof configOrCallback === 'function' ? undefined : configOrCallback;\n\n const instrumentedCallback: () => Promise<T> = async () => {\n return workflowStepWithSentry(this._instanceId, this._options, async () => {\n return startSpan(\n {\n op: 'function.step.do',\n name,\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 [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();\n span.setStatus({ code: 1 });\n return result;\n } catch (error) {\n captureException(error, { mechanism: { handled: true, type: 'cloudflare' } });\n throw error;\n } finally {\n this._ctx.waitUntil(flush(2000));\n }\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 options = optionsCallback(env);\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 return obj.run.call(obj, event, new WrappedWorkflowStep(event.instanceId, ctx, options, step));\n };\n }\n return Reflect.get(obj, prop, receiver);\n },\n });\n },\n }) as C;\n}\n"],"names":[],"mappings":"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"}
@@ -1,10 +1,6 @@
1
1
  /// <reference types="@cloudflare/workers-types" />
2
2
  import type { WorkflowEntrypoint } from 'cloudflare:workers';
3
3
  import type { CloudflareOptions } from './client';
4
- /**
5
- * Hashes a string to a UUID using SHA-1.
6
- */
7
- export declare function deterministicTraceIdFromInstanceId(instanceId: string): Promise<string>;
8
4
  /**
9
5
  * Instruments a Cloudflare Workflow class with Sentry.
10
6
  *
@@ -1 +1 @@
1
- {"version":3,"file":"workflows.d.ts","sourceRoot":"","sources":["../../src/workflows.ts"],"names":[],"mappings":";AAUA,OAAO,KAAK,EACV,kBAAkB,EAOnB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAMlD;;GAEG;AACH,wBAAsB,kCAAkC,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAS5F;AAmHD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,4BAA4B,CAC1C,CAAC,EAAE,mBAAmB;AACtB,CAAC,EAAE,eAAe;AAClB,CAAC,SAAS,kBAAkB,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,0BAA0B;AAC9D,CAAC,SAAS,KAAK,GAAG,EAAE,gBAAgB,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,EAClD,eAAe,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,iBAAiB,EAAE,aAAa,EAAE,CAAC,GAAG,CAAC,CAkBrE"}
1
+ {"version":3,"file":"workflows.d.ts","sourceRoot":"","sources":["../../src/workflows.ts"],"names":[],"mappings":";AAUA,OAAO,KAAK,EACV,kBAAkB,EAOnB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AA2HlD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,4BAA4B,CAC1C,CAAC,EAAE,mBAAmB;AACtB,CAAC,EAAE,eAAe;AAClB,CAAC,SAAS,kBAAkB,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,0BAA0B;AAC9D,CAAC,SAAS,KAAK,GAAG,EAAE,gBAAgB,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,EAClD,eAAe,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,iBAAiB,EAAE,aAAa,EAAE,CAAC,GAAG,CAAC,CAkBrE"}
@@ -1,10 +1,6 @@
1
1
  /// <reference types="@cloudflare/workers-types" />
2
2
  import { WorkflowEntrypoint } from 'cloudflare:workers';
3
3
  import { CloudflareOptions } from './client';
4
- /**
5
- * Hashes a string to a UUID using SHA-1.
6
- */
7
- export declare function deterministicTraceIdFromInstanceId(instanceId: string): Promise<string>;
8
4
  /**
9
5
  * Instruments a Cloudflare Workflow class with Sentry.
10
6
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sentry/cloudflare",
3
- "version": "9.41.0",
3
+ "version": "10.0.0-alpha.1",
4
4
  "description": "Official Sentry SDK for Cloudflare Workers and Pages",
5
5
  "repository": "git://github.com/getsentry/sentry-javascript.git",
6
6
  "homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/cloudflare",
@@ -50,7 +50,7 @@
50
50
  },
51
51
  "dependencies": {
52
52
  "@opentelemetry/api": "^1.9.0",
53
- "@sentry/core": "9.41.0"
53
+ "@sentry/core": "10.0.0-alpha.1"
54
54
  },
55
55
  "peerDependencies": {
56
56
  "@cloudflare/workers-types": "^4.x"