autotel-cloudflare 2.13.0 → 2.14.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.
@@ -228,17 +228,16 @@ function instrumentWorkflowRun(runFn, workflowName, workflowClass) {
228
228
  kind: SpanKind.INTERNAL,
229
229
  attributes: {
230
230
  "workflow.name": workflowName,
231
+ "workflow.instance_id": event.instanceId,
231
232
  "faas.trigger": "workflow",
232
- "faas.coldstart": isColdStart2(workflowClass),
233
- // Add workflow event attributes if available
234
- ...event?.workflowId && { "workflow.id": event.workflowId },
235
- ...event?.runId && { "workflow.run_id": event.runId }
233
+ "faas.coldstart": isColdStart2(workflowClass)
236
234
  }
237
235
  },
238
236
  async (span) => {
239
237
  try {
240
- await runFn.call(this, event, instrumentedStep);
238
+ const result = await runFn.call(this, event, instrumentedStep);
241
239
  span.setStatus({ code: SpanStatusCode.OK });
240
+ return result;
242
241
  } catch (error) {
243
242
  span.recordException(error);
244
243
  span.setStatus({
@@ -277,7 +276,7 @@ function instrumentWorkflow(workflowClass, workflowName, config) {
277
276
  const classHandler = {
278
277
  construct(target, args) {
279
278
  const env = args[args.length - 1] || {};
280
- const trigger = new Request("https://workflow.local/run");
279
+ const trigger = { type: "workflow", name: workflowName };
281
280
  const workflowConfig = initialiser(env, trigger);
282
281
  const context$1 = setConfig(workflowConfig);
283
282
  const workflowInstance = context.with(context$1, () => {
@@ -294,5 +293,5 @@ function instrumentWorkflow(workflowClass, workflowName, config) {
294
293
  }
295
294
 
296
295
  export { instrumentDO, instrumentWorkflow };
297
- //# sourceMappingURL=chunk-ZJPX4N7S.js.map
298
- //# sourceMappingURL=chunk-ZJPX4N7S.js.map
296
+ //# sourceMappingURL=chunk-WDNZVVRW.js.map
297
+ //# sourceMappingURL=chunk-WDNZVVRW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/handlers/durable-objects.ts","../src/handlers/workflows.ts"],"names":["api_context","context","coldStarts","isColdStart","trace","SpanKind","SpanStatusCode","createInitialiser","setConfig"],"mappings":"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","file":"chunk-WDNZVVRW.js","sourcesContent":["/**\n * Durable Objects instrumentation for Cloudflare Workers\n * \n * Note: This file uses Cloudflare Workers types (DurableObjectId, DurableObjectState, etc.)\n * which are globally available via @cloudflare/workers-types when listed in tsconfig.json.\n * These types are devDependencies only - they're not runtime dependencies.\n * At runtime, Cloudflare Workers runtime provides the actual implementations.\n */\n\nimport {\n trace,\n context as api_context,\n propagation,\n SpanStatusCode,\n SpanKind,\n} from '@opentelemetry/api';\nimport type { ConfigurationOption } from 'autotel-edge';\nimport { createInitialiser, setConfig, WorkerTracer } from 'autotel-edge';\nimport { wrap } from '../bindings/common';\n\n// Durable Object types\ntype DOFetchFn = (request: Request) => Response | Promise<Response>;\ntype DOAlarmFn = () => void | Promise<void>;\n\n/**\n * Track cold starts per DO class\n */\nconst coldStarts = new WeakMap<any, boolean>();\n\nfunction isColdStart(doClass: any): boolean {\n if (!coldStarts.has(doClass)) {\n coldStarts.set(doClass, true);\n return true;\n }\n return false;\n}\n\n/**\n * Instrument a Durable Object fetch method\n */\nfunction instrumentDOFetch(\n fetchFn: DOFetchFn,\n id: DurableObjectId,\n doClass: any,\n): DOFetchFn {\n return async function instrumentedFetch(\n this: any,\n request: Request,\n ): Promise<Response> {\n const tracer = trace.getTracer('autotel-edge') as WorkerTracer;\n\n // Extract parent context from request headers\n const parentContext = propagation.extract(\n api_context.active(),\n request.headers,\n );\n\n const url = new URL(request.url);\n const spanName = `DO ${id.name || id.toString()}: ${request.method} ${url.pathname}`;\n\n return tracer.startActiveSpan(\n spanName,\n {\n kind: SpanKind.SERVER,\n attributes: {\n 'http.request.method': request.method,\n 'url.full': request.url,\n 'do.id': id.toString(),\n 'do.id.name': id.name || '',\n 'faas.trigger': 'http',\n 'faas.coldstart': isColdStart(doClass),\n },\n },\n parentContext,\n async (span) => {\n try {\n const response = await fetchFn.call(this, request);\n\n span.setAttributes({\n 'http.response.status_code': response.status,\n });\n\n if (response.ok) {\n span.setStatus({ code: SpanStatusCode.OK });\n } else {\n span.setStatus({ code: SpanStatusCode.ERROR });\n }\n\n return response;\n } catch (error) {\n span.recordException(error as Error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : String(error),\n });\n throw error;\n } finally {\n span.end();\n }\n },\n );\n };\n}\n\n/**\n * Instrument a Durable Object alarm method\n */\nfunction instrumentDOAlarm(\n alarmFn: DOAlarmFn,\n id: DurableObjectId,\n doClass: any,\n): DOAlarmFn {\n return async function instrumentedAlarm(this: any): Promise<void> {\n const tracer = trace.getTracer('autotel-edge') as WorkerTracer;\n\n const spanName = `DO ${id.name || id.toString()}: alarm`;\n\n return tracer.startActiveSpan(\n spanName,\n {\n kind: SpanKind.INTERNAL,\n attributes: {\n 'do.id': id.toString(),\n 'do.id.name': id.name || '',\n 'faas.trigger': 'timer',\n 'faas.coldstart': isColdStart(doClass),\n },\n },\n async (span) => {\n try {\n await alarmFn.call(this);\n span.setStatus({ code: SpanStatusCode.OK });\n } catch (error) {\n span.recordException(error as Error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : String(error),\n });\n throw error;\n } finally {\n span.end();\n }\n },\n );\n };\n}\n\n/**\n * Instrument a Durable Object instance\n */\nfunction instrumentDOInstance(\n doInstance: any,\n state: DurableObjectState,\n _env: any,\n doClass: any,\n): any {\n const instanceHandler: ProxyHandler<any> = {\n get(target, prop) {\n const value = Reflect.get(target, prop);\n\n if (prop === 'fetch' && typeof value === 'function') {\n return instrumentDOFetch(value.bind(target), state.id, doClass);\n }\n\n if (prop === 'alarm' && typeof value === 'function') {\n return instrumentDOAlarm(value.bind(target), state.id, doClass);\n }\n\n // Bind other methods to the target\n if (typeof value === 'function') {\n return value.bind(target);\n }\n\n return value;\n },\n };\n\n return wrap(doInstance, instanceHandler);\n}\n\n/**\n * Instrument a Durable Object class\n *\n * This wraps the DO class to automatically trace all fetch and alarm calls,\n * as well as initialize the telemetry configuration.\n *\n * **Usage:**\n * ```typescript\n * import { DurableObject } from 'cloudflare:workers'\n * import { instrumentDO } from 'autotel-edge'\n *\n * export class Counter extends DurableObject<Env> {\n * async fetch(request: Request) {\n * // Your DO logic here\n * return new Response('OK')\n * }\n * }\n *\n * // Wrap the class before exporting\n * export const CounterDO = instrumentDO(Counter, (env: Env) => ({\n * exporter: {\n * url: env.OTLP_ENDPOINT,\n * headers: { 'x-api-key': env.API_KEY }\n * },\n * service: {\n * name: 'my-durable-object',\n * version: '1.0.0'\n * }\n * }))\n * ```\n *\n * **What you get:**\n * - 🎯 Automatic spans for fetch() calls with HTTP attributes\n * - ⏰ Automatic spans for alarm() calls\n * - 🥶 Cold start tracking\n * - 🔗 Context propagation from incoming requests\n * - ⚡ Automatic span lifecycle management\n *\n * @param doClass - The Durable Object class to instrument\n * @param config - Configuration or configuration function\n * @returns Instrumented Durable Object class\n */\nexport function instrumentDO<C extends new (state: DurableObjectState, env: any) => any>(\n doClass: C,\n config: ConfigurationOption,\n): C {\n const initialiser = createInitialiser(config);\n\n const classHandler: ProxyHandler<C> = {\n construct(target, [state, env]: [DurableObjectState, any]) {\n // Initialize config for this DO instance\n const trigger = {\n id: state.id.toString(),\n name: state.id.name,\n };\n const doConfig = initialiser(env, trigger);\n const context = setConfig(doConfig);\n\n // Create the DO instance within the config context\n const doInstance = api_context.with(context, () => {\n return new target(state, env);\n });\n\n // Instrument the instance\n return instrumentDOInstance(doInstance, state, env, doClass);\n },\n };\n\n return wrap(doClass, classHandler);\n}\n","/**\n * Cloudflare Workflows instrumentation for autotel-edge\n *\n * Instruments WorkflowEntrypoint classes to automatically trace workflow execution,\n * step operations, retries, and sleeps.\n *\n * Based on Cloudflare Workflows API:\n * https://developers.cloudflare.com/workflows/\n */\n\nimport {\n trace,\n context as api_context,\n SpanStatusCode,\n SpanKind,\n} from '@opentelemetry/api';\nimport type { ConfigurationOption, WorkflowTrigger } from 'autotel-edge';\nimport { createInitialiser, setConfig, WorkerTracer } from 'autotel-edge';\nimport { wrap } from '../bindings/common';\n\n/**\n * Workflow types matching the Cloudflare Workers Workflows API.\n * @see https://developers.cloudflare.com/workflows/\n */\n\ninterface WorkflowEvent<T = unknown> {\n payload: Readonly<T>;\n timestamp: Date;\n instanceId: string;\n}\n\ninterface WorkflowStepConfig {\n retries?: {\n limit: number;\n delay?: string | number;\n backoff?: 'constant' | 'linear' | 'exponential';\n };\n timeout?: string | number;\n}\n\ninterface WorkflowStep {\n do<T>(name: string, callback: () => Promise<T>): Promise<T>;\n do<T>(name: string, config: WorkflowStepConfig, callback: () => Promise<T>): Promise<T>;\n sleep(name: string, duration: string | number): Promise<void>;\n sleepUntil(name: string, timestamp: Date | number): Promise<void>;\n}\n\ntype WorkflowRunFn = (\n event: Readonly<WorkflowEvent>,\n step: WorkflowStep,\n) => Promise<unknown> | void;\n\n/**\n * Track cold starts per Workflow class\n */\nconst coldStarts = new WeakMap<object, boolean>();\n\nfunction isColdStart(workflowClass: object): boolean {\n if (!coldStarts.has(workflowClass)) {\n coldStarts.set(workflowClass, true);\n return true;\n }\n return false;\n}\n\n/**\n * Proxy the step object to instrument step.do() and step.sleep() calls\n */\nfunction instrumentWorkflowStep(\n step: WorkflowStep,\n workflowName: string,\n): WorkflowStep {\n const stepHandler: ProxyHandler<WorkflowStep> = {\n get(target, prop) {\n const value = Reflect.get(target, prop);\n\n // Instrument step.do() to create spans for each workflow step\n if (prop === 'do' && typeof value === 'function') {\n return new Proxy(value, {\n apply: (fnTarget, thisArg, args) => {\n const [stepName] = args as [string, ...unknown[]];\n\n const tracer = trace.getTracer('autotel-edge') as WorkerTracer;\n\n return tracer.startActiveSpan(\n `Workflow ${workflowName}: ${stepName}`,\n {\n kind: SpanKind.INTERNAL,\n attributes: {\n 'workflow.step.name': stepName,\n 'workflow.name': workflowName,\n },\n },\n async (span) => {\n try {\n const result = await Reflect.apply(fnTarget, thisArg, args);\n span.setStatus({ code: SpanStatusCode.OK });\n return result;\n } catch (error) {\n span.recordException(error as Error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message:\n error instanceof Error ? error.message : String(error),\n });\n throw error;\n } finally {\n span.end();\n }\n },\n );\n },\n });\n }\n\n // Instrument step.sleep() to track workflow delays\n if (prop === 'sleep' && typeof value === 'function') {\n return new Proxy(value, {\n apply: (fnTarget, thisArg, args) => {\n const [sleepName, duration] = args as [string, string | number];\n\n const tracer = trace.getTracer('autotel-edge') as WorkerTracer;\n\n return tracer.startActiveSpan(\n `Workflow ${workflowName}: sleep ${sleepName}`,\n {\n kind: SpanKind.INTERNAL,\n attributes: {\n 'workflow.sleep.name': sleepName,\n 'workflow.sleep.duration': String(duration),\n 'workflow.name': workflowName,\n },\n },\n async (span) => {\n try {\n const result = await Reflect.apply(fnTarget, thisArg, args);\n span.setStatus({ code: SpanStatusCode.OK });\n return result;\n } catch (error) {\n span.recordException(error as Error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message:\n error instanceof Error ? error.message : String(error),\n });\n throw error;\n } finally {\n span.end();\n }\n },\n );\n },\n });\n }\n\n // Pass through other step methods\n if (typeof value === 'function') {\n return value.bind(target);\n }\n\n return value;\n },\n };\n\n return wrap(step, stepHandler);\n}\n\n/**\n * Instrument a Workflow run method\n */\nfunction instrumentWorkflowRun(\n runFn: WorkflowRunFn,\n workflowName: string,\n workflowClass: object,\n): WorkflowRunFn {\n return async function instrumentedRun(\n this: unknown,\n event: Readonly<WorkflowEvent>,\n step: WorkflowStep,\n ): Promise<unknown> {\n const tracer = trace.getTracer('autotel-edge') as WorkerTracer;\n\n // Instrument the step object to track individual operations\n const instrumentedStep = instrumentWorkflowStep(step, workflowName);\n\n const spanName = `Workflow ${workflowName}: run`;\n\n return tracer.startActiveSpan(\n spanName,\n {\n kind: SpanKind.INTERNAL,\n attributes: {\n 'workflow.name': workflowName,\n 'workflow.instance_id': event.instanceId,\n 'faas.trigger': 'workflow',\n 'faas.coldstart': isColdStart(workflowClass),\n },\n },\n async (span) => {\n try {\n const result = await runFn.call(this, event, instrumentedStep);\n span.setStatus({ code: SpanStatusCode.OK });\n return result;\n } catch (error) {\n span.recordException(error as Error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : String(error),\n });\n throw error;\n } finally {\n span.end();\n }\n },\n );\n };\n}\n\n/**\n * Instrument a Workflow instance\n */\nfunction instrumentWorkflowInstance(\n workflowInstance: Record<string, unknown>,\n workflowName: string,\n workflowClass: object,\n): Record<string, unknown> {\n const instanceHandler: ProxyHandler<Record<string, unknown>> = {\n get(target, prop) {\n const value = Reflect.get(target, prop);\n\n if (prop === 'run' && typeof value === 'function') {\n return instrumentWorkflowRun(\n value.bind(target) as WorkflowRunFn,\n workflowName,\n workflowClass,\n );\n }\n\n // Bind other methods to the target\n if (typeof value === 'function') {\n return value.bind(target);\n }\n\n return value;\n },\n };\n\n return wrap(workflowInstance, instanceHandler);\n}\n\n/**\n * Instrument a Cloudflare Workflow class\n *\n * This wraps the WorkflowEntrypoint class to automatically trace workflow execution,\n * step operations, retries, and sleeps.\n *\n * **Usage:**\n * ```typescript\n * import { WorkflowEntrypoint } from 'cloudflare:workers'\n * import { instrumentWorkflow } from 'autotel-cloudflare/handlers'\n *\n * class MyWorkflow extends WorkflowEntrypoint {\n * async run(event, step) {\n * await step.do('submit payment', async () => {\n * return await submitToPaymentProcessor(event.payload.payment)\n * })\n *\n * await step.sleep('wait for feedback', '2 days')\n *\n * await step.do('send feedback email', sendFeedbackEmail)\n * }\n * }\n *\n * export const CheckoutWorkflow = instrumentWorkflow(\n * MyWorkflow,\n * 'checkout-workflow',\n * (env: Env) => ({\n * exporter: {\n * url: env.OTLP_ENDPOINT,\n * headers: { 'x-api-key': env.API_KEY }\n * },\n * service: {\n * name: 'checkout-workflow',\n * version: '1.0.0'\n * }\n * })\n * )\n * ```\n *\n * @param workflowClass - The WorkflowEntrypoint class to instrument\n * @param workflowName - The name of the workflow (used in span names)\n * @param config - Configuration or configuration function\n * @returns Instrumented Workflow class\n */\nexport function instrumentWorkflow<\n C extends new (...args: any[]) => any,\n>(\n workflowClass: C,\n workflowName: string,\n config: ConfigurationOption,\n): C {\n const initialiser = createInitialiser(config);\n\n const classHandler: ProxyHandler<C> = {\n construct(target, args: any[]) {\n // Extract env from constructor args (typically last arg)\n const env = args[args.length - 1] || {};\n\n const trigger: WorkflowTrigger = { type: 'workflow', name: workflowName };\n const workflowConfig = initialiser(env, trigger);\n const context = setConfig(workflowConfig);\n\n // Create the workflow instance within the config context\n const workflowInstance = api_context.with(context, () => {\n return new target(...args);\n });\n\n // Instrument the instance\n return instrumentWorkflowInstance(\n workflowInstance,\n workflowName,\n workflowClass,\n );\n },\n };\n\n return wrap(workflowClass, classHandler);\n}\n"]}
@@ -72,12 +72,12 @@ declare function instrumentDO<C extends new (state: DurableObjectState, env: any
72
72
  * **Usage:**
73
73
  * ```typescript
74
74
  * import { WorkflowEntrypoint } from 'cloudflare:workers'
75
- * import { instrumentWorkflow } from 'autotel-edge'
75
+ * import { instrumentWorkflow } from 'autotel-cloudflare/handlers'
76
76
  *
77
- * export class CheckoutWorkflow extends WorkflowEntrypoint {
77
+ * class MyWorkflow extends WorkflowEntrypoint {
78
78
  * async run(event, step) {
79
79
  * await step.do('submit payment', async () => {
80
- * return await submitToPaymentProcessor(event.params.payment)
80
+ * return await submitToPaymentProcessor(event.payload.payment)
81
81
  * })
82
82
  *
83
83
  * await step.sleep('wait for feedback', '2 days')
@@ -86,9 +86,8 @@ declare function instrumentDO<C extends new (state: DurableObjectState, env: any
86
86
  * }
87
87
  * }
88
88
  *
89
- * // Wrap the class before exporting
90
- * export const CheckoutWorkflowInstrumented = instrumentWorkflow(
91
- * CheckoutWorkflow,
89
+ * export const CheckoutWorkflow = instrumentWorkflow(
90
+ * MyWorkflow,
92
91
  * 'checkout-workflow',
93
92
  * (env: Env) => ({
94
93
  * exporter: {
@@ -103,14 +102,6 @@ declare function instrumentDO<C extends new (state: DurableObjectState, env: any
103
102
  * )
104
103
  * ```
105
104
  *
106
- * **What you get:**
107
- * - 🎯 Automatic spans for workflow.run() execution
108
- * - 📋 Automatic spans for each step.do() operation
109
- * - ⏸️ Automatic spans for step.sleep() operations
110
- * - 🔄 Automatic retry tracking (via step.do retries)
111
- * - 🥶 Cold start tracking
112
- * - ⚡ Automatic span lifecycle management
113
- *
114
105
  * @param workflowClass - The WorkflowEntrypoint class to instrument
115
106
  * @param workflowName - The name of the workflow (used in span names)
116
107
  * @param config - Configuration or configuration function
package/dist/handlers.js CHANGED
@@ -1,4 +1,4 @@
1
- export { instrumentDO, instrumentWorkflow } from './chunk-ZJPX4N7S.js';
1
+ export { instrumentDO, instrumentWorkflow } from './chunk-WDNZVVRW.js';
2
2
  import './chunk-O4IYKWPJ.js';
3
3
  //# sourceMappingURL=handlers.js.map
4
4
  //# sourceMappingURL=handlers.js.map
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { instrumentBindings } from './chunk-4UG2QCPQ.js';
2
2
  export { instrumentAI, instrumentAnalyticsEngine, instrumentBindings, instrumentBrowserRendering, instrumentD1, instrumentHyperdrive, instrumentImages, instrumentKV, instrumentQueueProducer, instrumentR2, instrumentRateLimiter, instrumentServiceBinding, instrumentVectorize } from './chunk-4UG2QCPQ.js';
3
- import { instrumentDO } from './chunk-ZJPX4N7S.js';
4
- export { instrumentDO, instrumentWorkflow } from './chunk-ZJPX4N7S.js';
3
+ import { instrumentDO } from './chunk-WDNZVVRW.js';
4
+ export { instrumentDO, instrumentWorkflow } from './chunk-WDNZVVRW.js';
5
5
  import { wrap, unwrap, proxyExecutionContext } from './chunk-O4IYKWPJ.js';
6
6
  import { createInitialiser, getActiveConfig, setConfig, WorkerTracerProvider, WorkerTracer } from 'autotel-edge';
7
7
  export * from 'autotel-edge';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autotel-cloudflare",
3
- "version": "2.13.0",
3
+ "version": "2.14.0",
4
4
  "description": "The #1 OpenTelemetry package for Cloudflare Workers - complete bindings coverage, native CF OTel integration, advanced sampling",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -69,7 +69,7 @@
69
69
  "dependencies": {
70
70
  "@opentelemetry/api": "^1.9.0",
71
71
  "@opentelemetry/resources": "^2.5.1",
72
- "autotel-edge": "3.11.0"
72
+ "autotel-edge": "3.12.0"
73
73
  },
74
74
  "peerDependencies": {
75
75
  "@cloudflare/workers-types": "^4.20260302.0"
@@ -0,0 +1,325 @@
1
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
+ import { instrumentWorkflow } from './workflows';
3
+ import { trace, SpanStatusCode, SpanKind } from '@opentelemetry/api';
4
+
5
+ describe('Workflow Instrumentation', () => {
6
+ let mockTracer: any;
7
+ let mockSpan: any;
8
+ let getTracerSpy: any;
9
+
10
+ beforeEach(() => {
11
+ mockSpan = {
12
+ spanContext: () => ({
13
+ traceId: 'test-trace-id',
14
+ spanId: 'test-span-id',
15
+ traceFlags: 1,
16
+ }),
17
+ setAttribute: vi.fn(),
18
+ setAttributes: vi.fn(),
19
+ setStatus: vi.fn(),
20
+ recordException: vi.fn(),
21
+ end: vi.fn(),
22
+ isRecording: () => true,
23
+ updateName: vi.fn(),
24
+ addEvent: vi.fn(),
25
+ };
26
+
27
+ mockTracer = {
28
+ startActiveSpan: vi.fn((name, options, context, fn) => {
29
+ if (typeof options === 'function') return options(mockSpan);
30
+ if (typeof context === 'function') return context(mockSpan);
31
+ if (typeof fn === 'function') return fn(mockSpan);
32
+ return Promise.resolve();
33
+ }),
34
+ };
35
+
36
+ getTracerSpy = vi.spyOn(trace, 'getTracer').mockReturnValue(mockTracer as any);
37
+ });
38
+
39
+ afterEach(() => {
40
+ getTracerSpy.mockRestore();
41
+ });
42
+
43
+ describe('instrumentWorkflow()', () => {
44
+ it('should wrap workflow class constructor', () => {
45
+ class TestWorkflow {
46
+ constructor(public ctx: any, public env: any) {}
47
+ async run() {}
48
+ }
49
+
50
+ const Instrumented = instrumentWorkflow(TestWorkflow, 'test-workflow', {
51
+ service: { name: 'test' },
52
+ });
53
+
54
+ expect(Instrumented).toBeDefined();
55
+ expect(typeof Instrumented).toBe('function');
56
+ });
57
+
58
+ it('should create workflow instance with instrumented run()', () => {
59
+ class TestWorkflow {
60
+ constructor(public ctx: any, public env: any) {}
61
+ async run() { return 'done'; }
62
+ }
63
+
64
+ const Instrumented = instrumentWorkflow(TestWorkflow, 'test-workflow', {
65
+ service: { name: 'test' },
66
+ });
67
+
68
+ const instance = new Instrumented({}, {});
69
+
70
+ expect(instance).toBeDefined();
71
+ expect(typeof instance.run).toBe('function');
72
+ });
73
+
74
+ it('should accept static config', () => {
75
+ class TestWorkflow {
76
+ constructor(public ctx: any, public env: any) {}
77
+ async run() {}
78
+ }
79
+
80
+ const Instrumented = instrumentWorkflow(TestWorkflow, 'test-workflow', {
81
+ service: { name: 'test', version: '1.0.0' },
82
+ exporter: { url: 'http://localhost:4318/v1/traces' },
83
+ });
84
+
85
+ expect(Instrumented).toBeDefined();
86
+ });
87
+
88
+ it('should accept config function', () => {
89
+ class TestWorkflow {
90
+ constructor(public ctx: any, public env: any) {}
91
+ async run() {}
92
+ }
93
+
94
+ interface Env {
95
+ OTLP_ENDPOINT: string;
96
+ }
97
+
98
+ const Instrumented = instrumentWorkflow(TestWorkflow, 'test-workflow', (env: Env) => ({
99
+ service: { name: 'test' },
100
+ exporter: { url: env.OTLP_ENDPOINT },
101
+ }));
102
+
103
+ expect(Instrumented).toBeDefined();
104
+ });
105
+ });
106
+
107
+ describe('run() instrumentation', () => {
108
+ it('should preserve run() return value', async () => {
109
+ const output = { status: 'ok', orderId: 'ord-123' };
110
+
111
+ class TestWorkflow {
112
+ constructor(public ctx: any, public env: any) {}
113
+ async run(event: any, step: any) {
114
+ return output;
115
+ }
116
+ }
117
+
118
+ const Instrumented = instrumentWorkflow(TestWorkflow, 'return-test', {
119
+ service: { name: 'test' },
120
+ });
121
+
122
+ const instance = new Instrumented({}, {});
123
+ const event = { payload: {}, timestamp: new Date(), instanceId: 'wf-return' };
124
+ const step = { do: vi.fn(), sleep: vi.fn(), sleepUntil: vi.fn() };
125
+
126
+ await expect(instance.run(event, step)).resolves.toEqual(output);
127
+ });
128
+
129
+ it('should create span for run() with workflow attributes', async () => {
130
+ class TestWorkflow {
131
+ constructor(public ctx: any, public env: any) {}
132
+ async run(event: any, step: any) {}
133
+ }
134
+
135
+ const Instrumented = instrumentWorkflow(TestWorkflow, 'test-workflow', {
136
+ service: { name: 'test' },
137
+ });
138
+
139
+ const instance = new Instrumented({}, {});
140
+ const event = { payload: { foo: 'bar' }, timestamp: new Date(), instanceId: 'wf-123' };
141
+ const step = { do: vi.fn(), sleep: vi.fn(), sleepUntil: vi.fn() };
142
+
143
+ await instance.run(event, step);
144
+
145
+ expect(mockTracer.startActiveSpan).toHaveBeenCalled();
146
+
147
+ const spanName = mockTracer.startActiveSpan.mock.calls[0][0];
148
+ expect(spanName).toBe('Workflow test-workflow: run');
149
+
150
+ const options = mockTracer.startActiveSpan.mock.calls[0][1];
151
+ expect(options.kind).toBe(SpanKind.INTERNAL);
152
+ expect(options.attributes['workflow.name']).toBe('test-workflow');
153
+ expect(options.attributes['workflow.instance_id']).toBe('wf-123');
154
+ expect(options.attributes['faas.trigger']).toBe('workflow');
155
+ });
156
+
157
+ it('should track cold starts', async () => {
158
+ class TestWorkflow {
159
+ constructor(public ctx: any, public env: any) {}
160
+ async run(event: any, step: any) {}
161
+ }
162
+
163
+ const Instrumented = instrumentWorkflow(TestWorkflow, 'cold-test', {
164
+ service: { name: 'test' },
165
+ });
166
+
167
+ const event = { payload: {}, timestamp: new Date(), instanceId: 'wf-1' };
168
+ const step = { do: vi.fn(), sleep: vi.fn(), sleepUntil: vi.fn() };
169
+
170
+ const instance1 = new Instrumented({}, {});
171
+ await instance1.run(event, step);
172
+ const firstOptions = mockTracer.startActiveSpan.mock.calls[0][1];
173
+ expect(firstOptions.attributes['faas.coldstart']).toBe(true);
174
+
175
+ const instance2 = new Instrumented({}, {});
176
+ await instance2.run(event, step);
177
+ const secondOptions = mockTracer.startActiveSpan.mock.calls[1][1];
178
+ expect(secondOptions.attributes['faas.coldstart']).toBe(false);
179
+ });
180
+
181
+ it('should handle run() errors', async () => {
182
+ class TestWorkflow {
183
+ constructor(public ctx: any, public env: any) {}
184
+ async run() {
185
+ throw new Error('Workflow failed');
186
+ }
187
+ }
188
+
189
+ const Instrumented = instrumentWorkflow(TestWorkflow, 'error-test', {
190
+ service: { name: 'test' },
191
+ });
192
+
193
+ const instance = new Instrumented({}, {});
194
+ const event = { payload: {}, timestamp: new Date(), instanceId: 'wf-err' };
195
+ const step = { do: vi.fn(), sleep: vi.fn(), sleepUntil: vi.fn() };
196
+
197
+ await expect(instance.run(event, step)).rejects.toThrow('Workflow failed');
198
+
199
+ expect(mockSpan.recordException).toHaveBeenCalled();
200
+ expect(mockSpan.setStatus).toHaveBeenCalledWith({
201
+ code: SpanStatusCode.ERROR,
202
+ message: 'Workflow failed',
203
+ });
204
+ expect(mockSpan.end).toHaveBeenCalled();
205
+ });
206
+ });
207
+
208
+ describe('step.do() instrumentation', () => {
209
+ it('should create span for step.do() calls', async () => {
210
+ const stepDoResult = { paymentId: 'pay_123' };
211
+ const mockStepDo = vi.fn().mockResolvedValue(stepDoResult);
212
+
213
+ class TestWorkflow {
214
+ constructor(public ctx: any, public env: any) {}
215
+ async run(event: any, step: any) {
216
+ return await step.do('process payment', async () => stepDoResult);
217
+ }
218
+ }
219
+
220
+ const Instrumented = instrumentWorkflow(TestWorkflow, 'step-test', {
221
+ service: { name: 'test' },
222
+ });
223
+
224
+ const instance = new Instrumented({}, {});
225
+ const event = { payload: {}, timestamp: new Date(), instanceId: 'wf-step' };
226
+ const step = {
227
+ do: vi.fn(async (_name: string, cb: () => Promise<any>) => cb()),
228
+ sleep: vi.fn(),
229
+ sleepUntil: vi.fn(),
230
+ };
231
+
232
+ await instance.run(event, step);
233
+
234
+ // Should have spans for both run() and step.do()
235
+ expect(mockTracer.startActiveSpan.mock.calls.length).toBeGreaterThanOrEqual(2);
236
+
237
+ const stepSpanCall = mockTracer.startActiveSpan.mock.calls[1];
238
+ expect(stepSpanCall[0]).toBe('Workflow step-test: process payment');
239
+ expect(stepSpanCall[1].attributes['workflow.step.name']).toBe('process payment');
240
+ expect(stepSpanCall[1].attributes['workflow.name']).toBe('step-test');
241
+ });
242
+
243
+ it('should handle step.do() errors', async () => {
244
+ class TestWorkflow {
245
+ constructor(public ctx: any, public env: any) {}
246
+ async run(event: any, step: any) {
247
+ await step.do('failing step', async () => {
248
+ throw new Error('Step failed');
249
+ });
250
+ }
251
+ }
252
+
253
+ const Instrumented = instrumentWorkflow(TestWorkflow, 'step-err', {
254
+ service: { name: 'test' },
255
+ });
256
+
257
+ const instance = new Instrumented({}, {});
258
+ const event = { payload: {}, timestamp: new Date(), instanceId: 'wf-step-err' };
259
+ const step = {
260
+ do: vi.fn(async (_name: string, cb: () => Promise<any>) => cb()),
261
+ sleep: vi.fn(),
262
+ sleepUntil: vi.fn(),
263
+ };
264
+
265
+ await expect(instance.run(event, step)).rejects.toThrow('Step failed');
266
+
267
+ expect(mockSpan.recordException).toHaveBeenCalled();
268
+ expect(mockSpan.end).toHaveBeenCalled();
269
+ });
270
+ });
271
+
272
+ describe('step.sleep() instrumentation', () => {
273
+ it('should create span for step.sleep() calls', async () => {
274
+ class TestWorkflow {
275
+ constructor(public ctx: any, public env: any) {}
276
+ async run(event: any, step: any) {
277
+ await step.sleep('wait for settlement', '2 hours');
278
+ }
279
+ }
280
+
281
+ const Instrumented = instrumentWorkflow(TestWorkflow, 'sleep-test', {
282
+ service: { name: 'test' },
283
+ });
284
+
285
+ const instance = new Instrumented({}, {});
286
+ const event = { payload: {}, timestamp: new Date(), instanceId: 'wf-sleep' };
287
+ const step = {
288
+ do: vi.fn(),
289
+ sleep: vi.fn().mockResolvedValue(undefined),
290
+ sleepUntil: vi.fn(),
291
+ };
292
+
293
+ await instance.run(event, step);
294
+
295
+ const sleepSpanCall = mockTracer.startActiveSpan.mock.calls[1];
296
+ expect(sleepSpanCall[0]).toBe('Workflow sleep-test: sleep wait for settlement');
297
+ expect(sleepSpanCall[1].attributes['workflow.sleep.name']).toBe('wait for settlement');
298
+ expect(sleepSpanCall[1].attributes['workflow.sleep.duration']).toBe('2 hours');
299
+ expect(sleepSpanCall[1].attributes['workflow.name']).toBe('sleep-test');
300
+ });
301
+ });
302
+
303
+ describe('this binding', () => {
304
+ it('should preserve this context in run()', async () => {
305
+ class TestWorkflow {
306
+ private value = 42;
307
+ constructor(public ctx: any, public env: any) {}
308
+ async run(event: any, step: any) {
309
+ return this.value;
310
+ }
311
+ }
312
+
313
+ const Instrumented = instrumentWorkflow(TestWorkflow, 'this-test', {
314
+ service: { name: 'test' },
315
+ });
316
+
317
+ const instance = new Instrumented({}, {});
318
+ const event = { payload: {}, timestamp: new Date(), instanceId: 'wf-this' };
319
+ const step = { do: vi.fn(), sleep: vi.fn(), sleepUntil: vi.fn() };
320
+
321
+ // Should not throw — this.value should be accessible
322
+ await expect(instance.run(event, step)).resolves.not.toThrow();
323
+ });
324
+ });
325
+ });
@@ -14,25 +14,48 @@ import {
14
14
  SpanStatusCode,
15
15
  SpanKind,
16
16
  } from '@opentelemetry/api';
17
- import type { ConfigurationOption } from 'autotel-edge';
17
+ import type { ConfigurationOption, WorkflowTrigger } from 'autotel-edge';
18
18
  import { createInitialiser, setConfig, WorkerTracer } from 'autotel-edge';
19
19
  import { wrap } from '../bindings/common';
20
20
 
21
- // Workflow types (these would come from @cloudflare/workers-types when available)
22
- type WorkflowEvent = any;
23
- type WorkflowStep = any;
21
+ /**
22
+ * Workflow types matching the Cloudflare Workers Workflows API.
23
+ * @see https://developers.cloudflare.com/workflows/
24
+ */
25
+
26
+ interface WorkflowEvent<T = unknown> {
27
+ payload: Readonly<T>;
28
+ timestamp: Date;
29
+ instanceId: string;
30
+ }
31
+
32
+ interface WorkflowStepConfig {
33
+ retries?: {
34
+ limit: number;
35
+ delay?: string | number;
36
+ backoff?: 'constant' | 'linear' | 'exponential';
37
+ };
38
+ timeout?: string | number;
39
+ }
40
+
41
+ interface WorkflowStep {
42
+ do<T>(name: string, callback: () => Promise<T>): Promise<T>;
43
+ do<T>(name: string, config: WorkflowStepConfig, callback: () => Promise<T>): Promise<T>;
44
+ sleep(name: string, duration: string | number): Promise<void>;
45
+ sleepUntil(name: string, timestamp: Date | number): Promise<void>;
46
+ }
24
47
 
25
48
  type WorkflowRunFn = (
26
- event: WorkflowEvent,
49
+ event: Readonly<WorkflowEvent>,
27
50
  step: WorkflowStep,
28
- ) => Promise<void> | void;
51
+ ) => Promise<unknown> | void;
29
52
 
30
53
  /**
31
54
  * Track cold starts per Workflow class
32
55
  */
33
- const coldStarts = new WeakMap<any, boolean>();
56
+ const coldStarts = new WeakMap<object, boolean>();
34
57
 
35
- function isColdStart(workflowClass: any): boolean {
58
+ function isColdStart(workflowClass: object): boolean {
36
59
  if (!coldStarts.has(workflowClass)) {
37
60
  coldStarts.set(workflowClass, true);
38
61
  return true;
@@ -41,7 +64,7 @@ function isColdStart(workflowClass: any): boolean {
41
64
  }
42
65
 
43
66
  /**
44
- * Proxy the step object to instrument step.do() calls
67
+ * Proxy the step object to instrument step.do() and step.sleep() calls
45
68
  */
46
69
  function instrumentWorkflowStep(
47
70
  step: WorkflowStep,
@@ -55,7 +78,7 @@ function instrumentWorkflowStep(
55
78
  if (prop === 'do' && typeof value === 'function') {
56
79
  return new Proxy(value, {
57
80
  apply: (fnTarget, thisArg, args) => {
58
- const [stepName] = args as [string, () => Promise<any>];
81
+ const [stepName] = args as [string, ...unknown[]];
59
82
 
60
83
  const tracer = trace.getTracer('autotel-edge') as WorkerTracer;
61
84
 
@@ -148,13 +171,13 @@ function instrumentWorkflowStep(
148
171
  function instrumentWorkflowRun(
149
172
  runFn: WorkflowRunFn,
150
173
  workflowName: string,
151
- workflowClass: any,
174
+ workflowClass: object,
152
175
  ): WorkflowRunFn {
153
176
  return async function instrumentedRun(
154
- this: any,
155
- event: WorkflowEvent,
177
+ this: unknown,
178
+ event: Readonly<WorkflowEvent>,
156
179
  step: WorkflowStep,
157
- ): Promise<void> {
180
+ ): Promise<unknown> {
158
181
  const tracer = trace.getTracer('autotel-edge') as WorkerTracer;
159
182
 
160
183
  // Instrument the step object to track individual operations
@@ -168,17 +191,16 @@ function instrumentWorkflowRun(
168
191
  kind: SpanKind.INTERNAL,
169
192
  attributes: {
170
193
  'workflow.name': workflowName,
194
+ 'workflow.instance_id': event.instanceId,
171
195
  'faas.trigger': 'workflow',
172
196
  'faas.coldstart': isColdStart(workflowClass),
173
- // Add workflow event attributes if available
174
- ...(event?.workflowId && { 'workflow.id': event.workflowId }),
175
- ...(event?.runId && { 'workflow.run_id': event.runId }),
176
197
  },
177
198
  },
178
199
  async (span) => {
179
200
  try {
180
- await runFn.call(this, event, instrumentedStep);
201
+ const result = await runFn.call(this, event, instrumentedStep);
181
202
  span.setStatus({ code: SpanStatusCode.OK });
203
+ return result;
182
204
  } catch (error) {
183
205
  span.recordException(error as Error);
184
206
  span.setStatus({
@@ -198,17 +220,17 @@ function instrumentWorkflowRun(
198
220
  * Instrument a Workflow instance
199
221
  */
200
222
  function instrumentWorkflowInstance(
201
- workflowInstance: any,
223
+ workflowInstance: Record<string, unknown>,
202
224
  workflowName: string,
203
- workflowClass: any,
204
- ): any {
205
- const instanceHandler: ProxyHandler<any> = {
225
+ workflowClass: object,
226
+ ): Record<string, unknown> {
227
+ const instanceHandler: ProxyHandler<Record<string, unknown>> = {
206
228
  get(target, prop) {
207
229
  const value = Reflect.get(target, prop);
208
230
 
209
231
  if (prop === 'run' && typeof value === 'function') {
210
232
  return instrumentWorkflowRun(
211
- value.bind(target),
233
+ value.bind(target) as WorkflowRunFn,
212
234
  workflowName,
213
235
  workflowClass,
214
236
  );
@@ -235,12 +257,12 @@ function instrumentWorkflowInstance(
235
257
  * **Usage:**
236
258
  * ```typescript
237
259
  * import { WorkflowEntrypoint } from 'cloudflare:workers'
238
- * import { instrumentWorkflow } from 'autotel-edge'
260
+ * import { instrumentWorkflow } from 'autotel-cloudflare/handlers'
239
261
  *
240
- * export class CheckoutWorkflow extends WorkflowEntrypoint {
262
+ * class MyWorkflow extends WorkflowEntrypoint {
241
263
  * async run(event, step) {
242
264
  * await step.do('submit payment', async () => {
243
- * return await submitToPaymentProcessor(event.params.payment)
265
+ * return await submitToPaymentProcessor(event.payload.payment)
244
266
  * })
245
267
  *
246
268
  * await step.sleep('wait for feedback', '2 days')
@@ -249,9 +271,8 @@ function instrumentWorkflowInstance(
249
271
  * }
250
272
  * }
251
273
  *
252
- * // Wrap the class before exporting
253
- * export const CheckoutWorkflowInstrumented = instrumentWorkflow(
254
- * CheckoutWorkflow,
274
+ * export const CheckoutWorkflow = instrumentWorkflow(
275
+ * MyWorkflow,
255
276
  * 'checkout-workflow',
256
277
  * (env: Env) => ({
257
278
  * exporter: {
@@ -266,14 +287,6 @@ function instrumentWorkflowInstance(
266
287
  * )
267
288
  * ```
268
289
  *
269
- * **What you get:**
270
- * - 🎯 Automatic spans for workflow.run() execution
271
- * - 📋 Automatic spans for each step.do() operation
272
- * - ⏸️ Automatic spans for step.sleep() operations
273
- * - 🔄 Automatic retry tracking (via step.do retries)
274
- * - 🥶 Cold start tracking
275
- * - ⚡ Automatic span lifecycle management
276
- *
277
290
  * @param workflowClass - The WorkflowEntrypoint class to instrument
278
291
  * @param workflowName - The name of the workflow (used in span names)
279
292
  * @param config - Configuration or configuration function
@@ -293,9 +306,7 @@ export function instrumentWorkflow<
293
306
  // Extract env from constructor args (typically last arg)
294
307
  const env = args[args.length - 1] || {};
295
308
 
296
- // Initialize config for this workflow instance
297
- // Use Request as trigger type since workflows don't have a standard Trigger type yet
298
- const trigger = new Request('https://workflow.local/run');
309
+ const trigger: WorkflowTrigger = { type: 'workflow', name: workflowName };
299
310
  const workflowConfig = initialiser(env, trigger);
300
311
  const context = setConfig(workflowConfig);
301
312
 
@@ -315,4 +326,3 @@ export function instrumentWorkflow<
315
326
 
316
327
  return wrap(workflowClass, classHandler);
317
328
  }
318
-
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/handlers/durable-objects.ts","../src/handlers/workflows.ts"],"names":["api_context","context","coldStarts","isColdStart","trace","SpanKind","SpanStatusCode","createInitialiser","setConfig"],"mappings":"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","file":"chunk-ZJPX4N7S.js","sourcesContent":["/**\n * Durable Objects instrumentation for Cloudflare Workers\n * \n * Note: This file uses Cloudflare Workers types (DurableObjectId, DurableObjectState, etc.)\n * which are globally available via @cloudflare/workers-types when listed in tsconfig.json.\n * These types are devDependencies only - they're not runtime dependencies.\n * At runtime, Cloudflare Workers runtime provides the actual implementations.\n */\n\nimport {\n trace,\n context as api_context,\n propagation,\n SpanStatusCode,\n SpanKind,\n} from '@opentelemetry/api';\nimport type { ConfigurationOption } from 'autotel-edge';\nimport { createInitialiser, setConfig, WorkerTracer } from 'autotel-edge';\nimport { wrap } from '../bindings/common';\n\n// Durable Object types\ntype DOFetchFn = (request: Request) => Response | Promise<Response>;\ntype DOAlarmFn = () => void | Promise<void>;\n\n/**\n * Track cold starts per DO class\n */\nconst coldStarts = new WeakMap<any, boolean>();\n\nfunction isColdStart(doClass: any): boolean {\n if (!coldStarts.has(doClass)) {\n coldStarts.set(doClass, true);\n return true;\n }\n return false;\n}\n\n/**\n * Instrument a Durable Object fetch method\n */\nfunction instrumentDOFetch(\n fetchFn: DOFetchFn,\n id: DurableObjectId,\n doClass: any,\n): DOFetchFn {\n return async function instrumentedFetch(\n this: any,\n request: Request,\n ): Promise<Response> {\n const tracer = trace.getTracer('autotel-edge') as WorkerTracer;\n\n // Extract parent context from request headers\n const parentContext = propagation.extract(\n api_context.active(),\n request.headers,\n );\n\n const url = new URL(request.url);\n const spanName = `DO ${id.name || id.toString()}: ${request.method} ${url.pathname}`;\n\n return tracer.startActiveSpan(\n spanName,\n {\n kind: SpanKind.SERVER,\n attributes: {\n 'http.request.method': request.method,\n 'url.full': request.url,\n 'do.id': id.toString(),\n 'do.id.name': id.name || '',\n 'faas.trigger': 'http',\n 'faas.coldstart': isColdStart(doClass),\n },\n },\n parentContext,\n async (span) => {\n try {\n const response = await fetchFn.call(this, request);\n\n span.setAttributes({\n 'http.response.status_code': response.status,\n });\n\n if (response.ok) {\n span.setStatus({ code: SpanStatusCode.OK });\n } else {\n span.setStatus({ code: SpanStatusCode.ERROR });\n }\n\n return response;\n } catch (error) {\n span.recordException(error as Error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : String(error),\n });\n throw error;\n } finally {\n span.end();\n }\n },\n );\n };\n}\n\n/**\n * Instrument a Durable Object alarm method\n */\nfunction instrumentDOAlarm(\n alarmFn: DOAlarmFn,\n id: DurableObjectId,\n doClass: any,\n): DOAlarmFn {\n return async function instrumentedAlarm(this: any): Promise<void> {\n const tracer = trace.getTracer('autotel-edge') as WorkerTracer;\n\n const spanName = `DO ${id.name || id.toString()}: alarm`;\n\n return tracer.startActiveSpan(\n spanName,\n {\n kind: SpanKind.INTERNAL,\n attributes: {\n 'do.id': id.toString(),\n 'do.id.name': id.name || '',\n 'faas.trigger': 'timer',\n 'faas.coldstart': isColdStart(doClass),\n },\n },\n async (span) => {\n try {\n await alarmFn.call(this);\n span.setStatus({ code: SpanStatusCode.OK });\n } catch (error) {\n span.recordException(error as Error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : String(error),\n });\n throw error;\n } finally {\n span.end();\n }\n },\n );\n };\n}\n\n/**\n * Instrument a Durable Object instance\n */\nfunction instrumentDOInstance(\n doInstance: any,\n state: DurableObjectState,\n _env: any,\n doClass: any,\n): any {\n const instanceHandler: ProxyHandler<any> = {\n get(target, prop) {\n const value = Reflect.get(target, prop);\n\n if (prop === 'fetch' && typeof value === 'function') {\n return instrumentDOFetch(value.bind(target), state.id, doClass);\n }\n\n if (prop === 'alarm' && typeof value === 'function') {\n return instrumentDOAlarm(value.bind(target), state.id, doClass);\n }\n\n // Bind other methods to the target\n if (typeof value === 'function') {\n return value.bind(target);\n }\n\n return value;\n },\n };\n\n return wrap(doInstance, instanceHandler);\n}\n\n/**\n * Instrument a Durable Object class\n *\n * This wraps the DO class to automatically trace all fetch and alarm calls,\n * as well as initialize the telemetry configuration.\n *\n * **Usage:**\n * ```typescript\n * import { DurableObject } from 'cloudflare:workers'\n * import { instrumentDO } from 'autotel-edge'\n *\n * export class Counter extends DurableObject<Env> {\n * async fetch(request: Request) {\n * // Your DO logic here\n * return new Response('OK')\n * }\n * }\n *\n * // Wrap the class before exporting\n * export const CounterDO = instrumentDO(Counter, (env: Env) => ({\n * exporter: {\n * url: env.OTLP_ENDPOINT,\n * headers: { 'x-api-key': env.API_KEY }\n * },\n * service: {\n * name: 'my-durable-object',\n * version: '1.0.0'\n * }\n * }))\n * ```\n *\n * **What you get:**\n * - 🎯 Automatic spans for fetch() calls with HTTP attributes\n * - ⏰ Automatic spans for alarm() calls\n * - 🥶 Cold start tracking\n * - 🔗 Context propagation from incoming requests\n * - ⚡ Automatic span lifecycle management\n *\n * @param doClass - The Durable Object class to instrument\n * @param config - Configuration or configuration function\n * @returns Instrumented Durable Object class\n */\nexport function instrumentDO<C extends new (state: DurableObjectState, env: any) => any>(\n doClass: C,\n config: ConfigurationOption,\n): C {\n const initialiser = createInitialiser(config);\n\n const classHandler: ProxyHandler<C> = {\n construct(target, [state, env]: [DurableObjectState, any]) {\n // Initialize config for this DO instance\n const trigger = {\n id: state.id.toString(),\n name: state.id.name,\n };\n const doConfig = initialiser(env, trigger);\n const context = setConfig(doConfig);\n\n // Create the DO instance within the config context\n const doInstance = api_context.with(context, () => {\n return new target(state, env);\n });\n\n // Instrument the instance\n return instrumentDOInstance(doInstance, state, env, doClass);\n },\n };\n\n return wrap(doClass, classHandler);\n}\n","/**\n * Cloudflare Workflows instrumentation for autotel-edge\n *\n * Instruments WorkflowEntrypoint classes to automatically trace workflow execution,\n * step operations, retries, and sleeps.\n *\n * Based on Cloudflare Workflows API:\n * https://developers.cloudflare.com/workflows/\n */\n\nimport {\n trace,\n context as api_context,\n SpanStatusCode,\n SpanKind,\n} from '@opentelemetry/api';\nimport type { ConfigurationOption } from 'autotel-edge';\nimport { createInitialiser, setConfig, WorkerTracer } from 'autotel-edge';\nimport { wrap } from '../bindings/common';\n\n// Workflow types (these would come from @cloudflare/workers-types when available)\ntype WorkflowEvent = any;\ntype WorkflowStep = any;\n\ntype WorkflowRunFn = (\n event: WorkflowEvent,\n step: WorkflowStep,\n) => Promise<void> | void;\n\n/**\n * Track cold starts per Workflow class\n */\nconst coldStarts = new WeakMap<any, boolean>();\n\nfunction isColdStart(workflowClass: any): boolean {\n if (!coldStarts.has(workflowClass)) {\n coldStarts.set(workflowClass, true);\n return true;\n }\n return false;\n}\n\n/**\n * Proxy the step object to instrument step.do() calls\n */\nfunction instrumentWorkflowStep(\n step: WorkflowStep,\n workflowName: string,\n): WorkflowStep {\n const stepHandler: ProxyHandler<WorkflowStep> = {\n get(target, prop) {\n const value = Reflect.get(target, prop);\n\n // Instrument step.do() to create spans for each workflow step\n if (prop === 'do' && typeof value === 'function') {\n return new Proxy(value, {\n apply: (fnTarget, thisArg, args) => {\n const [stepName] = args as [string, () => Promise<any>];\n\n const tracer = trace.getTracer('autotel-edge') as WorkerTracer;\n\n return tracer.startActiveSpan(\n `Workflow ${workflowName}: ${stepName}`,\n {\n kind: SpanKind.INTERNAL,\n attributes: {\n 'workflow.step.name': stepName,\n 'workflow.name': workflowName,\n },\n },\n async (span) => {\n try {\n const result = await Reflect.apply(fnTarget, thisArg, args);\n span.setStatus({ code: SpanStatusCode.OK });\n return result;\n } catch (error) {\n span.recordException(error as Error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message:\n error instanceof Error ? error.message : String(error),\n });\n throw error;\n } finally {\n span.end();\n }\n },\n );\n },\n });\n }\n\n // Instrument step.sleep() to track workflow delays\n if (prop === 'sleep' && typeof value === 'function') {\n return new Proxy(value, {\n apply: (fnTarget, thisArg, args) => {\n const [sleepName, duration] = args as [string, string | number];\n\n const tracer = trace.getTracer('autotel-edge') as WorkerTracer;\n\n return tracer.startActiveSpan(\n `Workflow ${workflowName}: sleep ${sleepName}`,\n {\n kind: SpanKind.INTERNAL,\n attributes: {\n 'workflow.sleep.name': sleepName,\n 'workflow.sleep.duration': String(duration),\n 'workflow.name': workflowName,\n },\n },\n async (span) => {\n try {\n const result = await Reflect.apply(fnTarget, thisArg, args);\n span.setStatus({ code: SpanStatusCode.OK });\n return result;\n } catch (error) {\n span.recordException(error as Error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message:\n error instanceof Error ? error.message : String(error),\n });\n throw error;\n } finally {\n span.end();\n }\n },\n );\n },\n });\n }\n\n // Pass through other step methods\n if (typeof value === 'function') {\n return value.bind(target);\n }\n\n return value;\n },\n };\n\n return wrap(step, stepHandler);\n}\n\n/**\n * Instrument a Workflow run method\n */\nfunction instrumentWorkflowRun(\n runFn: WorkflowRunFn,\n workflowName: string,\n workflowClass: any,\n): WorkflowRunFn {\n return async function instrumentedRun(\n this: any,\n event: WorkflowEvent,\n step: WorkflowStep,\n ): Promise<void> {\n const tracer = trace.getTracer('autotel-edge') as WorkerTracer;\n\n // Instrument the step object to track individual operations\n const instrumentedStep = instrumentWorkflowStep(step, workflowName);\n\n const spanName = `Workflow ${workflowName}: run`;\n\n return tracer.startActiveSpan(\n spanName,\n {\n kind: SpanKind.INTERNAL,\n attributes: {\n 'workflow.name': workflowName,\n 'faas.trigger': 'workflow',\n 'faas.coldstart': isColdStart(workflowClass),\n // Add workflow event attributes if available\n ...(event?.workflowId && { 'workflow.id': event.workflowId }),\n ...(event?.runId && { 'workflow.run_id': event.runId }),\n },\n },\n async (span) => {\n try {\n await runFn.call(this, event, instrumentedStep);\n span.setStatus({ code: SpanStatusCode.OK });\n } catch (error) {\n span.recordException(error as Error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : String(error),\n });\n throw error;\n } finally {\n span.end();\n }\n },\n );\n };\n}\n\n/**\n * Instrument a Workflow instance\n */\nfunction instrumentWorkflowInstance(\n workflowInstance: any,\n workflowName: string,\n workflowClass: any,\n): any {\n const instanceHandler: ProxyHandler<any> = {\n get(target, prop) {\n const value = Reflect.get(target, prop);\n\n if (prop === 'run' && typeof value === 'function') {\n return instrumentWorkflowRun(\n value.bind(target),\n workflowName,\n workflowClass,\n );\n }\n\n // Bind other methods to the target\n if (typeof value === 'function') {\n return value.bind(target);\n }\n\n return value;\n },\n };\n\n return wrap(workflowInstance, instanceHandler);\n}\n\n/**\n * Instrument a Cloudflare Workflow class\n *\n * This wraps the WorkflowEntrypoint class to automatically trace workflow execution,\n * step operations, retries, and sleeps.\n *\n * **Usage:**\n * ```typescript\n * import { WorkflowEntrypoint } from 'cloudflare:workers'\n * import { instrumentWorkflow } from 'autotel-edge'\n *\n * export class CheckoutWorkflow extends WorkflowEntrypoint {\n * async run(event, step) {\n * await step.do('submit payment', async () => {\n * return await submitToPaymentProcessor(event.params.payment)\n * })\n *\n * await step.sleep('wait for feedback', '2 days')\n *\n * await step.do('send feedback email', sendFeedbackEmail)\n * }\n * }\n *\n * // Wrap the class before exporting\n * export const CheckoutWorkflowInstrumented = instrumentWorkflow(\n * CheckoutWorkflow,\n * 'checkout-workflow',\n * (env: Env) => ({\n * exporter: {\n * url: env.OTLP_ENDPOINT,\n * headers: { 'x-api-key': env.API_KEY }\n * },\n * service: {\n * name: 'checkout-workflow',\n * version: '1.0.0'\n * }\n * })\n * )\n * ```\n *\n * **What you get:**\n * - 🎯 Automatic spans for workflow.run() execution\n * - 📋 Automatic spans for each step.do() operation\n * - ⏸️ Automatic spans for step.sleep() operations\n * - 🔄 Automatic retry tracking (via step.do retries)\n * - 🥶 Cold start tracking\n * - ⚡ Automatic span lifecycle management\n *\n * @param workflowClass - The WorkflowEntrypoint class to instrument\n * @param workflowName - The name of the workflow (used in span names)\n * @param config - Configuration or configuration function\n * @returns Instrumented Workflow class\n */\nexport function instrumentWorkflow<\n C extends new (...args: any[]) => any,\n>(\n workflowClass: C,\n workflowName: string,\n config: ConfigurationOption,\n): C {\n const initialiser = createInitialiser(config);\n\n const classHandler: ProxyHandler<C> = {\n construct(target, args: any[]) {\n // Extract env from constructor args (typically last arg)\n const env = args[args.length - 1] || {};\n\n // Initialize config for this workflow instance\n // Use Request as trigger type since workflows don't have a standard Trigger type yet\n const trigger = new Request('https://workflow.local/run');\n const workflowConfig = initialiser(env, trigger);\n const context = setConfig(workflowConfig);\n\n // Create the workflow instance within the config context\n const workflowInstance = api_context.with(context, () => {\n return new target(...args);\n });\n\n // Instrument the instance\n return instrumentWorkflowInstance(\n workflowInstance,\n workflowName,\n workflowClass,\n );\n },\n };\n\n return wrap(workflowClass, classHandler);\n}\n\n"]}