autotel-cloudflare 2.18.18 → 2.19.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 (58) hide show
  1. package/dist/actors.d.ts +54 -89
  2. package/dist/actors.d.ts.map +1 -0
  3. package/dist/actors.js +990 -986
  4. package/dist/actors.js.map +1 -1
  5. package/dist/agents.d.ts +102 -128
  6. package/dist/agents.d.ts.map +1 -0
  7. package/dist/agents.js +275 -259
  8. package/dist/agents.js.map +1 -1
  9. package/dist/bindings-C10RI6Il.js +975 -0
  10. package/dist/bindings-C10RI6Il.js.map +1 -0
  11. package/dist/bindings-xEZcXo5r.d.ts +149 -0
  12. package/dist/bindings-xEZcXo5r.d.ts.map +1 -0
  13. package/dist/bindings.d.ts +2 -139
  14. package/dist/bindings.js +3 -4
  15. package/dist/common-DiWH6nmG.js +63 -0
  16. package/dist/common-DiWH6nmG.js.map +1 -0
  17. package/dist/events.d.ts +1 -1
  18. package/dist/events.js +3 -3
  19. package/dist/execution-logger-BxmgP8jF.js +65 -0
  20. package/dist/execution-logger-BxmgP8jF.js.map +1 -0
  21. package/dist/{logger-Cm_73k3-.d.ts → execution-logger-tgQmJeeU.d.ts} +9 -7
  22. package/dist/execution-logger-tgQmJeeU.d.ts.map +1 -0
  23. package/dist/handlers-CMg9l_T-.js +378 -0
  24. package/dist/handlers-CMg9l_T-.js.map +1 -0
  25. package/dist/handlers-C_VojUeA.d.ts +96 -0
  26. package/dist/handlers-C_VojUeA.d.ts.map +1 -0
  27. package/dist/handlers.d.ts +2 -112
  28. package/dist/handlers.js +3 -4
  29. package/dist/index.d.ts +20 -99
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +644 -600
  32. package/dist/index.js.map +1 -1
  33. package/dist/logger.d.ts +3 -3
  34. package/dist/logger.js +5 -4
  35. package/dist/parse-error.d.ts +2 -1
  36. package/dist/parse-error.js +3 -3
  37. package/dist/sampling.d.ts +1 -4
  38. package/dist/sampling.js +3 -3
  39. package/dist/testing.d.ts +1 -1
  40. package/dist/testing.js +3 -3
  41. package/package.json +6 -6
  42. package/src/bindings/ai.test.ts +1 -1
  43. package/src/bindings/ai.ts +3 -1
  44. package/dist/bindings.js.map +0 -1
  45. package/dist/chunk-KAUHT25H.js +0 -1084
  46. package/dist/chunk-KAUHT25H.js.map +0 -1
  47. package/dist/chunk-MIDMNKDC.js +0 -333
  48. package/dist/chunk-MIDMNKDC.js.map +0 -1
  49. package/dist/chunk-O4IYKWPJ.js +0 -55
  50. package/dist/chunk-O4IYKWPJ.js.map +0 -1
  51. package/dist/chunk-RVVMMPWN.js +0 -63
  52. package/dist/chunk-RVVMMPWN.js.map +0 -1
  53. package/dist/events.js.map +0 -1
  54. package/dist/handlers.js.map +0 -1
  55. package/dist/logger.js.map +0 -1
  56. package/dist/parse-error.js.map +0 -1
  57. package/dist/sampling.js.map +0 -1
  58. package/dist/testing.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,658 +1,702 @@
1
- import { instrumentBindings } from './chunk-KAUHT25H.js';
2
- export { instrumentAI, instrumentAnalyticsEngine, instrumentBindings, instrumentBrowserRendering, instrumentD1, instrumentHyperdrive, instrumentImages, instrumentKV, instrumentQueueProducer, instrumentR2, instrumentRateLimiter, instrumentServiceBinding, instrumentVectorize } from './chunk-KAUHT25H.js';
3
- import { instrumentDO } from './chunk-MIDMNKDC.js';
4
- export { instrumentDO, instrumentWorkflow } from './chunk-MIDMNKDC.js';
5
- import { createWorkersLogger } from './chunk-RVVMMPWN.js';
6
- export { createWorkersLogger, getActorLogger, getQueueLogger, getRequestLogger, getWorkflowLogger } from './chunk-RVVMMPWN.js';
7
- import { wrap, unwrap, proxyExecutionContext } from './chunk-O4IYKWPJ.js';
8
- import { createInitialiser, getActiveConfig, shouldInstrumentPath, setConfig, WorkerTracerProvider, WorkerTracer, getServiceForPath } from 'autotel-edge';
9
- export * from 'autotel-edge';
10
- import { trace, SpanKind, propagation, context, SpanStatusCode } from '@opentelemetry/api';
11
- import { resourceFromAttributes } from '@opentelemetry/resources';
1
+ import { a as getWorkflowLogger, i as getRequestLogger, n as getActorLogger, r as getQueueLogger, t as createWorkersLogger } from "./execution-logger-BxmgP8jF.js";
2
+ import { a as wrap, i as unwrap, n as proxyExecutionContext } from "./common-DiWH6nmG.js";
3
+ import { a as instrumentKV, c as instrumentImages, d as instrumentHyperdrive, f as instrumentVectorize, i as instrumentD1, l as instrumentAnalyticsEngine, n as instrumentRateLimiter, o as instrumentR2, p as instrumentAI, r as instrumentBindings, s as instrumentServiceBinding, t as instrumentBrowserRendering, u as instrumentQueueProducer } from "./bindings-C10RI6Il.js";
4
+ import { n as instrumentDO, t as instrumentWorkflow } from "./handlers-CMg9l_T-.js";
5
+ import { WorkerTracer, WorkerTracerProvider, createInitialiser, getActiveConfig, getServiceForPath, setConfig, shouldInstrumentPath } from "autotel-edge";
6
+ import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
7
+ import { resourceFromAttributes } from "@opentelemetry/resources";
12
8
 
9
+ export * from "autotel-edge"
10
+
11
+ //#region src/global/fetch.ts
12
+ /**
13
+ * Global fetch() instrumentation for autotel-edge
14
+ *
15
+ * Automatically traces all outgoing fetch() calls with:
16
+ * - HTTP method, URL, status code
17
+ * - Request/response headers
18
+ * - Automatic context propagation
19
+ * - Error tracking
20
+ */
21
+ /**
22
+ * Gather HTTP request attributes following OpenTelemetry semantic conventions
23
+ */
13
24
  function gatherRequestAttributes(request) {
14
- const url = new URL(request.url);
15
- const config = getActiveConfig();
16
- const redactQuery = config?.dataSafety?.redactQueryParams === true;
17
- return {
18
- "http.request.method": request.method.toUpperCase(),
19
- "url.full": redactQuery ? `${url.origin}${url.pathname}` : request.url,
20
- "url.scheme": url.protocol.replace(":", ""),
21
- "server.address": url.host,
22
- "url.path": url.pathname,
23
- "url.query": redactQuery ? url.search ? "[REDACTED]" : "" : url.search,
24
- "network.protocol.name": "http",
25
- "user_agent.original": request.headers.get("user-agent") || void 0
26
- };
25
+ const url = new URL(request.url);
26
+ const redactQuery = getActiveConfig()?.dataSafety?.redactQueryParams === true;
27
+ return {
28
+ "http.request.method": request.method.toUpperCase(),
29
+ "url.full": redactQuery ? `${url.origin}${url.pathname}` : request.url,
30
+ "url.scheme": url.protocol.replace(":", ""),
31
+ "server.address": url.host,
32
+ "url.path": url.pathname,
33
+ "url.query": redactQuery ? url.search ? "[REDACTED]" : "" : url.search,
34
+ "network.protocol.name": "http",
35
+ "user_agent.original": request.headers.get("user-agent") || void 0
36
+ };
27
37
  }
38
+ /**
39
+ * Gather HTTP response attributes
40
+ */
28
41
  function gatherResponseAttributes(response) {
29
- return {
30
- "http.response.status_code": response.status,
31
- "http.response.body.size": response.headers.get("content-length") || void 0
32
- };
42
+ return {
43
+ "http.response.status_code": response.status,
44
+ "http.response.body.size": response.headers.get("content-length") || void 0
45
+ };
33
46
  }
47
+ /**
48
+ * Instrument the global fetch function
49
+ *
50
+ * This wraps globalThis.fetch to automatically create spans for all outgoing HTTP requests.
51
+ *
52
+ * **Note:** This is called automatically when the library is initialized with
53
+ * `instrumentation.instrumentGlobalFetch: true` (default).
54
+ */
34
55
  function instrumentGlobalFetch() {
35
- const originalFetch = globalThis.fetch;
36
- const instrumentedFetch = function fetch(input, init) {
37
- const request = new Request(input, init);
38
- if (!request.url.startsWith("http")) {
39
- return originalFetch(input, init);
40
- }
41
- const config = getActiveConfig();
42
- if (!config) {
43
- return originalFetch(input, init);
44
- }
45
- const tracer = trace.getTracer("autotel-edge");
46
- const url = new URL(request.url);
47
- const spanName = `${request.method} ${url.host}`;
48
- return tracer.startActiveSpan(
49
- spanName,
50
- {
51
- kind: SpanKind.CLIENT,
52
- attributes: gatherRequestAttributes(request)
53
- },
54
- async (span) => {
55
- try {
56
- const shouldIncludeContext = typeof config.fetch?.includeTraceContext === "function" ? config.fetch.includeTraceContext(request) : config.fetch?.includeTraceContext ?? true;
57
- if (shouldIncludeContext) {
58
- propagation.inject(context.active(), request.headers, {
59
- set: (headers, key, value) => {
60
- if (typeof value === "string") {
61
- headers.set(key, value);
62
- }
63
- }
64
- });
65
- }
66
- const response = await originalFetch(request);
67
- span.setAttributes(gatherResponseAttributes(response));
68
- if (response.ok) {
69
- span.setStatus({ code: SpanStatusCode.OK });
70
- } else {
71
- span.setStatus({ code: SpanStatusCode.ERROR });
72
- }
73
- return response;
74
- } catch (error) {
75
- span.recordException(error);
76
- span.setStatus({
77
- code: SpanStatusCode.ERROR,
78
- message: error instanceof Error ? error.message : String(error)
79
- });
80
- throw error;
81
- } finally {
82
- span.end();
83
- }
84
- }
85
- );
86
- };
87
- globalThis.fetch = instrumentedFetch;
56
+ const originalFetch = globalThis.fetch;
57
+ globalThis.fetch = function fetch(input, init) {
58
+ const request = new Request(input, init);
59
+ if (!request.url.startsWith("http")) return originalFetch(input, init);
60
+ const config = getActiveConfig();
61
+ if (!config) return originalFetch(input, init);
62
+ const tracer = trace.getTracer("autotel-edge");
63
+ const url = new URL(request.url);
64
+ const spanName = `${request.method} ${url.host}`;
65
+ return tracer.startActiveSpan(spanName, {
66
+ kind: SpanKind.CLIENT,
67
+ attributes: gatherRequestAttributes(request)
68
+ }, async (span) => {
69
+ try {
70
+ if (typeof config.fetch?.includeTraceContext === "function" ? config.fetch.includeTraceContext(request) : config.fetch?.includeTraceContext ?? true) propagation.inject(context.active(), request.headers, { set: (headers, key, value) => {
71
+ if (typeof value === "string") headers.set(key, value);
72
+ } });
73
+ const response = await originalFetch(request);
74
+ span.setAttributes(gatherResponseAttributes(response));
75
+ if (response.ok) span.setStatus({ code: SpanStatusCode.OK });
76
+ else span.setStatus({ code: SpanStatusCode.ERROR });
77
+ return response;
78
+ } catch (error) {
79
+ span.recordException(error);
80
+ span.setStatus({
81
+ code: SpanStatusCode.ERROR,
82
+ message: error instanceof Error ? error.message : String(error)
83
+ });
84
+ throw error;
85
+ } finally {
86
+ span.end();
87
+ }
88
+ });
89
+ };
88
90
  }
91
+
92
+ //#endregion
93
+ //#region src/global/cache.ts
94
+ /**
95
+ * Global Cache API instrumentation for Cloudflare Workers
96
+ *
97
+ * Automatically traces cache operations:
98
+ * - cache.match() - Read from cache
99
+ * - cache.put() - Write to cache
100
+ * - cache.delete() - Delete from cache
101
+ */
102
+ /**
103
+ * Sanitize URL for span attributes (remove query params that might contain sensitive data)
104
+ */
89
105
  function sanitizeURL(url) {
90
- const u = new URL(url);
91
- return `${u.protocol}//${u.host}${u.pathname}`;
106
+ const u = new URL(url);
107
+ return `${u.protocol}//${u.host}${u.pathname}`;
92
108
  }
109
+ /**
110
+ * Instrument a cache method (match, put, delete)
111
+ */
93
112
  function instrumentCacheMethod(fn, cacheName, operation) {
94
- const handler = {
95
- async apply(target, thisArg, argArray) {
96
- const tracer = trace.getTracer("autotel-edge");
97
- const firstArg = argArray[0];
98
- const url = firstArg instanceof Request ? firstArg.url : typeof firstArg === "string" ? firstArg : void 0;
99
- const spanName = `Cache ${cacheName}.${operation}`;
100
- return tracer.startActiveSpan(
101
- spanName,
102
- {
103
- kind: SpanKind.CLIENT,
104
- attributes: {
105
- "cache.name": cacheName,
106
- "cache.operation": operation,
107
- "cache.key": url ? sanitizeURL(url) : void 0
108
- }
109
- },
110
- async (span) => {
111
- try {
112
- const result = await Reflect.apply(target, thisArg, argArray);
113
- if (operation === "match") {
114
- span.setAttribute("cache.hit", !!result);
115
- }
116
- span.setStatus({ code: SpanStatusCode.OK });
117
- return result;
118
- } catch (error) {
119
- span.recordException(error);
120
- span.setStatus({
121
- code: SpanStatusCode.ERROR,
122
- message: error instanceof Error ? error.message : String(error)
123
- });
124
- throw error;
125
- } finally {
126
- span.end();
127
- }
128
- }
129
- );
130
- }
131
- };
132
- return wrap(fn, handler);
113
+ return wrap(fn, { async apply(target, thisArg, argArray) {
114
+ const tracer = trace.getTracer("autotel-edge");
115
+ const firstArg = argArray[0];
116
+ const url = firstArg instanceof Request ? firstArg.url : typeof firstArg === "string" ? firstArg : void 0;
117
+ const spanName = `Cache ${cacheName}.${operation}`;
118
+ return tracer.startActiveSpan(spanName, {
119
+ kind: SpanKind.CLIENT,
120
+ attributes: {
121
+ "cache.name": cacheName,
122
+ "cache.operation": operation,
123
+ "cache.key": url ? sanitizeURL(url) : void 0
124
+ }
125
+ }, async (span) => {
126
+ try {
127
+ const result = await Reflect.apply(target, thisArg, argArray);
128
+ if (operation === "match") span.setAttribute("cache.hit", !!result);
129
+ span.setStatus({ code: SpanStatusCode.OK });
130
+ return result;
131
+ } catch (error) {
132
+ span.recordException(error);
133
+ span.setStatus({
134
+ code: SpanStatusCode.ERROR,
135
+ message: error instanceof Error ? error.message : String(error)
136
+ });
137
+ throw error;
138
+ } finally {
139
+ span.end();
140
+ }
141
+ });
142
+ } });
133
143
  }
144
+ /**
145
+ * Instrument a Cache instance
146
+ */
134
147
  function instrumentCache(cache, cacheName) {
135
- const handler = {
136
- get(target, prop) {
137
- const value = Reflect.get(target, prop);
138
- if ((prop === "match" || prop === "put" || prop === "delete") && typeof value === "function") {
139
- return instrumentCacheMethod(
140
- value.bind(target),
141
- cacheName,
142
- prop
143
- );
144
- }
145
- if (typeof value === "function") {
146
- return value.bind(target);
147
- }
148
- return value;
149
- }
150
- };
151
- return wrap(cache, handler);
148
+ return wrap(cache, { get(target, prop) {
149
+ const value = Reflect.get(target, prop);
150
+ if ((prop === "match" || prop === "put" || prop === "delete") && typeof value === "function") return instrumentCacheMethod(value.bind(target), cacheName, prop);
151
+ if (typeof value === "function") return value.bind(target);
152
+ return value;
153
+ } });
152
154
  }
155
+ /**
156
+ * Instrument caches.open()
157
+ */
153
158
  function instrumentCachesOpen(openFn) {
154
- const handler = {
155
- async apply(target, thisArg, argArray) {
156
- const cacheName = argArray[0];
157
- const cache = await Reflect.apply(target, thisArg, argArray);
158
- return instrumentCache(cache, cacheName);
159
- }
160
- };
161
- return wrap(openFn, handler);
159
+ return wrap(openFn, { async apply(target, thisArg, argArray) {
160
+ const cacheName = argArray[0];
161
+ return instrumentCache(await Reflect.apply(target, thisArg, argArray), cacheName);
162
+ } });
162
163
  }
164
+ /**
165
+ * Instrument the global caches API
166
+ *
167
+ * This wraps globalThis.caches to automatically create spans for all cache operations.
168
+ *
169
+ * **Note:** This is called automatically when the library is initialized with
170
+ * `instrumentation.instrumentGlobalCache: true` (default).
171
+ */
163
172
  function instrumentGlobalCache() {
164
- const handler = {
165
- get(target, prop) {
166
- if (prop === "default") {
167
- return instrumentCache(target.default, "default");
168
- } else if (prop === "open") {
169
- const openFn = Reflect.get(target, prop);
170
- if (typeof openFn === "function") {
171
- return instrumentCachesOpen(openFn.bind(target));
172
- }
173
- }
174
- return Reflect.get(target, prop);
175
- }
176
- };
177
- globalThis.caches = wrap(caches, handler);
173
+ globalThis.caches = wrap(caches, { get(target, prop) {
174
+ if (prop === "default") return instrumentCache(target.default, "default");
175
+ else if (prop === "open") {
176
+ const openFn = Reflect.get(target, prop);
177
+ if (typeof openFn === "function") return instrumentCachesOpen(openFn.bind(target));
178
+ }
179
+ return Reflect.get(target, prop);
180
+ } });
178
181
  }
179
182
 
180
- // src/wrappers/instrument.ts
181
- var headersGetter = {
182
- get: (carrier, key) => carrier.get(key) ?? void 0,
183
- keys: (carrier) => [...carrier.keys()]
183
+ //#endregion
184
+ //#region src/wrappers/instrument.ts
185
+ /**
186
+ * Handler instrumentation for Cloudflare Workers
187
+ *
188
+ * Note: This file uses Cloudflare Workers types (ExportedHandler, Request, Response, etc.)
189
+ * which are globally available via @cloudflare/workers-types when listed in tsconfig.json.
190
+ * These types are devDependencies only - they're not runtime dependencies.
191
+ * At runtime, Cloudflare Workers runtime provides the actual implementations.
192
+ *
193
+ * Provides automatic OpenTelemetry tracing for:
194
+ * - HTTP handlers (fetch)
195
+ * - Scheduled/cron handlers
196
+ * - Queue handlers (with message tracking)
197
+ * - Email handlers
198
+ * - Auto-instrumentation of Cloudflare bindings (KV, R2, D1, Service Bindings)
199
+ * - Global fetch and cache instrumentation
200
+ * - Post-processor support for span customization
201
+ * - Tail sampling support
202
+ * - Cold start tracking
203
+ */
204
+ const headersGetter = {
205
+ get: (carrier, key) => carrier.get(key) ?? void 0,
206
+ keys: (carrier) => [...carrier.keys()]
184
207
  };
208
+ /**
209
+ * Create fetch handler instrumentation with config support for postProcess
210
+ */
211
+ /**
212
+ * Extract Cloudflare-specific attributes from a request
213
+ */
185
214
  function extractCfAttributes(request) {
186
- const cf = request.cf;
187
- if (!cf) return {};
188
- const attrs = {};
189
- const set = (key, value) => {
190
- if (value !== void 0 && value !== null) {
191
- attrs[key] = value;
192
- }
193
- };
194
- set("cloudflare.colo", cf.colo);
195
- const ray = request.headers.get("cf-ray");
196
- if (ray) attrs["cloudflare.ray_id"] = ray;
197
- set("cloudflare.country", cf.country);
198
- set("cloudflare.city", cf.city);
199
- set("cloudflare.region", cf.region);
200
- set("cloudflare.continent", cf.continent);
201
- set("cloudflare.timezone", cf.timezone);
202
- set("cloudflare.latitude", cf.latitude);
203
- set("cloudflare.longitude", cf.longitude);
204
- set("cloudflare.asn", cf.asn);
205
- set("cloudflare.as_organization", cf.asOrganization);
206
- set("cloudflare.http_protocol", cf.httpProtocol);
207
- set("cloudflare.tls_version", cf.tlsVersion);
208
- set("cloudflare.client_tcp_rtt", cf.clientTcpRtt);
209
- return attrs;
215
+ const cf = request.cf;
216
+ if (!cf) return {};
217
+ const attrs = {};
218
+ const set = (key, value) => {
219
+ if (value !== void 0 && value !== null) attrs[key] = value;
220
+ };
221
+ set("cloudflare.colo", cf.colo);
222
+ const ray = request.headers.get("cf-ray");
223
+ if (ray) attrs["cloudflare.ray_id"] = ray;
224
+ set("cloudflare.country", cf.country);
225
+ set("cloudflare.city", cf.city);
226
+ set("cloudflare.region", cf.region);
227
+ set("cloudflare.continent", cf.continent);
228
+ set("cloudflare.timezone", cf.timezone);
229
+ set("cloudflare.latitude", cf.latitude);
230
+ set("cloudflare.longitude", cf.longitude);
231
+ set("cloudflare.asn", cf.asn);
232
+ set("cloudflare.as_organization", cf.asOrganization);
233
+ set("cloudflare.http_protocol", cf.httpProtocol);
234
+ set("cloudflare.tls_version", cf.tlsVersion);
235
+ set("cloudflare.client_tcp_rtt", cf.clientTcpRtt);
236
+ return attrs;
210
237
  }
211
238
  function createFetchInstrumentation(config) {
212
- return {
213
- getInitialSpanInfo: (request) => {
214
- const url = new URL(request.url);
215
- const routeService = getServiceForPath(
216
- url.pathname,
217
- config.handlers.fetch.routes
218
- );
219
- const cfAttrs = config.extractCfAttributes === false ? {} : extractCfAttributes(request);
220
- return {
221
- name: `${request.method} ${url.pathname}`,
222
- options: {
223
- kind: SpanKind.SERVER,
224
- attributes: {
225
- "http.request.method": request.method,
226
- "url.full": request.url,
227
- ...routeService ? { "service.name": routeService, "autotel.route.service": routeService } : {},
228
- ...cfAttrs
229
- }
230
- },
231
- context: propagation.extract(context.active(), request.headers, headersGetter)
232
- };
233
- },
234
- getAttributesFromResult: (response) => ({
235
- "http.response.status_code": response.status
236
- }),
237
- executionSucces: (span, trigger, result) => {
238
- if (result.status >= 500) {
239
- span.setStatus({ code: SpanStatusCode.ERROR });
240
- }
241
- if (config.handlers.fetch.postProcess) {
242
- const readableSpan = span;
243
- config.handlers.fetch.postProcess(span, {
244
- request: trigger,
245
- response: result,
246
- readable: readableSpan
247
- });
248
- }
249
- }
250
- };
239
+ return {
240
+ getInitialSpanInfo: (request) => {
241
+ const url = new URL(request.url);
242
+ const routeService = getServiceForPath(url.pathname, config.handlers.fetch.routes);
243
+ const cfAttrs = config.extractCfAttributes === false ? {} : extractCfAttributes(request);
244
+ return {
245
+ name: `${request.method} ${url.pathname}`,
246
+ options: {
247
+ kind: SpanKind.SERVER,
248
+ attributes: {
249
+ "http.request.method": request.method,
250
+ "url.full": request.url,
251
+ ...routeService ? {
252
+ "service.name": routeService,
253
+ "autotel.route.service": routeService
254
+ } : {},
255
+ ...cfAttrs
256
+ }
257
+ },
258
+ context: propagation.extract(context.active(), request.headers, headersGetter)
259
+ };
260
+ },
261
+ getAttributesFromResult: (response) => ({ "http.response.status_code": response.status }),
262
+ executionSucces: (span, trigger, result) => {
263
+ if (result.status >= 500) span.setStatus({ code: SpanStatusCode.ERROR });
264
+ if (config.handlers.fetch.postProcess) {
265
+ const readableSpan = span;
266
+ config.handlers.fetch.postProcess(span, {
267
+ request: trigger,
268
+ response: result,
269
+ readable: readableSpan
270
+ });
271
+ }
272
+ }
273
+ };
251
274
  }
252
- var scheduledInstrumentation = {
253
- getInitialSpanInfo: (event) => {
254
- return {
255
- name: `scheduledHandler ${event.cron || "unknown"}`,
256
- options: {
257
- kind: SpanKind.INTERNAL,
258
- attributes: {
259
- "faas.trigger": "timer",
260
- "faas.cron": event.cron || "unknown",
261
- "faas.scheduled_time": new Date(event.scheduledTime).toISOString()
262
- }
263
- }
264
- };
265
- }
266
- };
275
+ /**
276
+ * Scheduled handler instrumentation
277
+ */
278
+ const scheduledInstrumentation = { getInitialSpanInfo: (event) => {
279
+ return {
280
+ name: `scheduledHandler ${event.cron || "unknown"}`,
281
+ options: {
282
+ kind: SpanKind.INTERNAL,
283
+ attributes: {
284
+ "faas.trigger": "timer",
285
+ "faas.cron": event.cron || "unknown",
286
+ "faas.scheduled_time": new Date(event.scheduledTime).toISOString()
287
+ }
288
+ }
289
+ };
290
+ } };
291
+ /**
292
+ * Tracks message status counts for queue processing
293
+ */
267
294
  var MessageStatusCount = class {
268
- succeeded = 0;
269
- failed = 0;
270
- implicitly_acked = 0;
271
- implicitly_retried = 0;
272
- total;
273
- constructor(total) {
274
- this.total = total;
275
- }
276
- ack() {
277
- this.succeeded = this.succeeded + 1;
278
- }
279
- ackRemaining() {
280
- this.implicitly_acked = this.total - this.succeeded - this.failed;
281
- this.succeeded = this.total - this.failed;
282
- }
283
- retry() {
284
- this.failed = this.failed + 1;
285
- }
286
- retryRemaining() {
287
- this.implicitly_retried = this.total - this.succeeded - this.failed;
288
- this.failed = this.total - this.succeeded;
289
- }
290
- toAttributes() {
291
- return {
292
- "queue.messages_count": this.total,
293
- "queue.messages_success": this.succeeded,
294
- "queue.messages_failed": this.failed,
295
- "queue.batch_success": this.succeeded === this.total,
296
- "queue.implicitly_acked": this.implicitly_acked,
297
- "queue.implicitly_retried": this.implicitly_retried
298
- };
299
- }
295
+ succeeded = 0;
296
+ failed = 0;
297
+ implicitly_acked = 0;
298
+ implicitly_retried = 0;
299
+ total;
300
+ constructor(total) {
301
+ this.total = total;
302
+ }
303
+ ack() {
304
+ this.succeeded = this.succeeded + 1;
305
+ }
306
+ ackRemaining() {
307
+ this.implicitly_acked = this.total - this.succeeded - this.failed;
308
+ this.succeeded = this.total - this.failed;
309
+ }
310
+ retry() {
311
+ this.failed = this.failed + 1;
312
+ }
313
+ retryRemaining() {
314
+ this.implicitly_retried = this.total - this.succeeded - this.failed;
315
+ this.failed = this.total - this.succeeded;
316
+ }
317
+ toAttributes() {
318
+ return {
319
+ "queue.messages_count": this.total,
320
+ "queue.messages_success": this.succeeded,
321
+ "queue.messages_failed": this.failed,
322
+ "queue.batch_success": this.succeeded === this.total,
323
+ "queue.implicitly_acked": this.implicitly_acked,
324
+ "queue.implicitly_retried": this.implicitly_retried
325
+ };
326
+ }
300
327
  };
328
+ /**
329
+ * Add event to active span
330
+ */
301
331
  function addQueueEvent(name, msg, delaySeconds) {
302
- const attrs = {};
303
- if (msg) {
304
- attrs["queue.message_id"] = msg.id;
305
- attrs["queue.message_timestamp"] = msg.timestamp.toISOString();
306
- if ("attempts" in msg && typeof msg.attempts === "number") {
307
- attrs["queue.message_attempts"] = msg.attempts;
308
- }
309
- }
310
- if (delaySeconds !== void 0) {
311
- attrs["queue.retry_delay_seconds"] = delaySeconds;
312
- }
313
- trace.getActiveSpan()?.addEvent(name, attrs);
332
+ const attrs = {};
333
+ if (msg) {
334
+ attrs["queue.message_id"] = msg.id;
335
+ attrs["queue.message_timestamp"] = msg.timestamp.toISOString();
336
+ if ("attempts" in msg && typeof msg.attempts === "number") attrs["queue.message_attempts"] = msg.attempts;
337
+ }
338
+ if (delaySeconds !== void 0) attrs["queue.retry_delay_seconds"] = delaySeconds;
339
+ trace.getActiveSpan()?.addEvent(name, attrs);
314
340
  }
341
+ /**
342
+ * Proxy a queue message to track ack/retry operations
343
+ */
315
344
  function proxyQueueMessage(msg, count) {
316
- const msgHandler = {
317
- get: (target, prop) => {
318
- if (prop === "ack") {
319
- const ackFn = Reflect.get(target, prop);
320
- return new Proxy(ackFn, {
321
- apply: (fnTarget) => {
322
- addQueueEvent("messageAck", msg);
323
- count.ack();
324
- Reflect.apply(fnTarget, msg, []);
325
- }
326
- });
327
- } else if (prop === "retry") {
328
- const retryFn = Reflect.get(target, prop);
329
- return new Proxy(retryFn, {
330
- apply: (fnTarget, _thisArg, args) => {
331
- const retryOptions = args[0];
332
- const delaySeconds = retryOptions?.delaySeconds;
333
- addQueueEvent("messageRetry", msg, delaySeconds);
334
- if (retryOptions?.contentType) {
335
- const span = trace.getActiveSpan();
336
- if (span) {
337
- span.setAttribute("queue.message.content_type", retryOptions.contentType);
338
- }
339
- }
340
- count.retry();
341
- const result = Reflect.apply(fnTarget, msg, args);
342
- return result;
343
- }
344
- });
345
- } else {
346
- return Reflect.get(target, prop, msg);
347
- }
348
- }
349
- };
350
- return wrap(msg, msgHandler);
345
+ return wrap(msg, { get: (target, prop) => {
346
+ if (prop === "ack") {
347
+ const ackFn = Reflect.get(target, prop);
348
+ return new Proxy(ackFn, { apply: (fnTarget) => {
349
+ addQueueEvent("messageAck", msg);
350
+ count.ack();
351
+ Reflect.apply(fnTarget, msg, []);
352
+ } });
353
+ } else if (prop === "retry") {
354
+ const retryFn = Reflect.get(target, prop);
355
+ return new Proxy(retryFn, { apply: (fnTarget, _thisArg, args) => {
356
+ const retryOptions = args[0];
357
+ const delaySeconds = retryOptions?.delaySeconds;
358
+ addQueueEvent("messageRetry", msg, delaySeconds);
359
+ if (retryOptions?.contentType) {
360
+ const span = trace.getActiveSpan();
361
+ if (span) span.setAttribute("queue.message.content_type", retryOptions.contentType);
362
+ }
363
+ count.retry();
364
+ return Reflect.apply(fnTarget, msg, args);
365
+ } });
366
+ } else return Reflect.get(target, prop, msg);
367
+ } });
351
368
  }
369
+ /**
370
+ * Proxy MessageBatch to track ackAll/retryAll operations
371
+ */
352
372
  function proxyMessageBatch(batch, count) {
353
- const batchHandler = {
354
- get: (target, prop) => {
355
- if (prop === "messages") {
356
- const messages = Reflect.get(target, prop);
357
- const messagesHandler = {
358
- get: (target2, prop2) => {
359
- if (typeof prop2 === "string" && !isNaN(parseInt(prop2))) {
360
- const message = Reflect.get(target2, prop2);
361
- return proxyQueueMessage(message, count);
362
- } else {
363
- return Reflect.get(target2, prop2);
364
- }
365
- }
366
- };
367
- return wrap(messages, messagesHandler);
368
- } else if (prop === "ackAll") {
369
- const ackFn = Reflect.get(target, prop);
370
- return new Proxy(ackFn, {
371
- apply: (fnTarget) => {
372
- addQueueEvent("ackAll");
373
- count.ackRemaining();
374
- Reflect.apply(fnTarget, batch, []);
375
- }
376
- });
377
- } else if (prop === "retryAll") {
378
- const retryFn = Reflect.get(target, prop);
379
- return new Proxy(retryFn, {
380
- apply: (fnTarget, _thisArg, args) => {
381
- const retryOptions = args[0];
382
- const delaySeconds = retryOptions?.delaySeconds;
383
- addQueueEvent("retryAll", void 0, delaySeconds);
384
- count.retryRemaining();
385
- Reflect.apply(fnTarget, batch, args);
386
- }
387
- });
388
- }
389
- return Reflect.get(target, prop);
390
- }
391
- };
392
- return wrap(batch, batchHandler);
373
+ return wrap(batch, { get: (target, prop) => {
374
+ if (prop === "messages") return wrap(Reflect.get(target, prop), { get: (target, prop) => {
375
+ if (typeof prop === "string" && !isNaN(parseInt(prop))) return proxyQueueMessage(Reflect.get(target, prop), count);
376
+ else return Reflect.get(target, prop);
377
+ } });
378
+ else if (prop === "ackAll") {
379
+ const ackFn = Reflect.get(target, prop);
380
+ return new Proxy(ackFn, { apply: (fnTarget) => {
381
+ addQueueEvent("ackAll");
382
+ count.ackRemaining();
383
+ Reflect.apply(fnTarget, batch, []);
384
+ } });
385
+ } else if (prop === "retryAll") {
386
+ const retryFn = Reflect.get(target, prop);
387
+ return new Proxy(retryFn, { apply: (fnTarget, _thisArg, args) => {
388
+ const delaySeconds = args[0]?.delaySeconds;
389
+ addQueueEvent("retryAll", void 0, delaySeconds);
390
+ count.retryRemaining();
391
+ Reflect.apply(fnTarget, batch, args);
392
+ } });
393
+ }
394
+ return Reflect.get(target, prop);
395
+ } });
393
396
  }
397
+ /**
398
+ * Queue handler instrumentation with message tracking
399
+ */
394
400
  var QueueInstrumentation = class {
395
- count;
396
- getInitialSpanInfo(batch) {
397
- return {
398
- name: `queueHandler ${batch.queue || "unknown"}`,
399
- options: {
400
- kind: SpanKind.CONSUMER,
401
- attributes: {
402
- "faas.trigger": "pubsub",
403
- "queue.name": batch.queue || "unknown"
404
- }
405
- }
406
- };
407
- }
408
- instrumentTrigger(batch) {
409
- this.count = new MessageStatusCount(batch.messages.length);
410
- return proxyMessageBatch(batch, this.count);
411
- }
412
- executionSucces(span, _trigger, _result) {
413
- if (this.count) {
414
- this.count.ackRemaining();
415
- span.setAttributes(this.count.toAttributes());
416
- }
417
- }
418
- executionFailed(span, _trigger, _error) {
419
- if (this.count) {
420
- this.count.retryRemaining();
421
- span.setAttributes(this.count.toAttributes());
422
- }
423
- }
401
+ count;
402
+ getInitialSpanInfo(batch) {
403
+ return {
404
+ name: `queueHandler ${batch.queue || "unknown"}`,
405
+ options: {
406
+ kind: SpanKind.CONSUMER,
407
+ attributes: {
408
+ "faas.trigger": "pubsub",
409
+ "queue.name": batch.queue || "unknown"
410
+ }
411
+ }
412
+ };
413
+ }
414
+ instrumentTrigger(batch) {
415
+ this.count = new MessageStatusCount(batch.messages.length);
416
+ return proxyMessageBatch(batch, this.count);
417
+ }
418
+ executionSucces(span, _trigger, _result) {
419
+ if (this.count) {
420
+ this.count.ackRemaining();
421
+ span.setAttributes(this.count.toAttributes());
422
+ }
423
+ }
424
+ executionFailed(span, _trigger, _error) {
425
+ if (this.count) {
426
+ this.count.retryRemaining();
427
+ span.setAttributes(this.count.toAttributes());
428
+ }
429
+ }
424
430
  };
431
+ /**
432
+ * Converts email headers into OpenTelemetry attributes.
433
+ * When dataSafety.emailHeaderAllowlist is configured, only allowed headers are captured.
434
+ */
425
435
  function headerAttributes(message) {
426
- const attrs = {};
427
- if (message.headers instanceof Headers) {
428
- const config = getActiveConfig();
429
- const allowlist = config?.dataSafety?.emailHeaderAllowlist;
430
- for (const [key, value] of message.headers.entries()) {
431
- if (allowlist && !allowlist.includes(key.toLowerCase())) {
432
- continue;
433
- }
434
- attrs[`email.header.${key}`] = value;
435
- }
436
- }
437
- return attrs;
436
+ const attrs = {};
437
+ if (message.headers instanceof Headers) {
438
+ const allowlist = getActiveConfig()?.dataSafety?.emailHeaderAllowlist;
439
+ for (const [key, value] of message.headers.entries()) {
440
+ if (allowlist && !allowlist.includes(key.toLowerCase())) continue;
441
+ attrs[`email.header.${key}`] = value;
442
+ }
443
+ }
444
+ return attrs;
438
445
  }
439
- var emailInstrumentation = {
440
- getInitialSpanInfo: (message) => {
441
- const attributes = {
442
- "faas.trigger": "other",
443
- "messaging.destination.name": message.to || "unknown"
444
- };
445
- if ("headers" in message && message.headers instanceof Headers) {
446
- const messageId = message.headers.get("Message-Id");
447
- if (messageId) {
448
- attributes["rpc.message.id"] = messageId;
449
- }
450
- Object.assign(attributes, headerAttributes(message));
451
- }
452
- return {
453
- name: `emailHandler ${message.to || "unknown"}`,
454
- options: {
455
- kind: SpanKind.CONSUMER,
456
- attributes
457
- }
458
- };
459
- }
460
- };
446
+ /**
447
+ * Email handler instrumentation
448
+ */
449
+ const emailInstrumentation = { getInitialSpanInfo: (message) => {
450
+ const attributes = {
451
+ "faas.trigger": "other",
452
+ "messaging.destination.name": message.to || "unknown"
453
+ };
454
+ if ("headers" in message && message.headers instanceof Headers) {
455
+ const messageId = message.headers.get("Message-Id");
456
+ if (messageId) attributes["rpc.message.id"] = messageId;
457
+ Object.assign(attributes, headerAttributes(message));
458
+ }
459
+ return {
460
+ name: `emailHandler ${message.to || "unknown"}`,
461
+ options: {
462
+ kind: SpanKind.CONSUMER,
463
+ attributes
464
+ }
465
+ };
466
+ } };
467
+ /**
468
+ * Export spans after request completes
469
+ */
461
470
  async function exportSpans(traceId, tracker, ctx) {
462
- const tracer = trace.getTracer("autotel-edge");
463
- if (tracer instanceof WorkerTracer) {
464
- try {
465
- const ctxWithScheduler = ctx;
466
- if (ctxWithScheduler.scheduler) {
467
- await ctxWithScheduler.scheduler.wait(1);
468
- }
469
- await tracker?.wait();
470
- await tracer.forceFlush(traceId);
471
- } catch (error) {
472
- console.error("[autotel-edge] Failed to export spans:", error);
473
- }
474
- }
471
+ const tracer = trace.getTracer("autotel-edge");
472
+ if (tracer instanceof WorkerTracer) try {
473
+ const ctxWithScheduler = ctx;
474
+ if (ctxWithScheduler.scheduler) await ctxWithScheduler.scheduler.wait(1);
475
+ await tracker?.wait();
476
+ await tracer.forceFlush(traceId);
477
+ } catch (error) {
478
+ console.error("[autotel-edge] Failed to export spans:", error);
479
+ }
475
480
  }
481
+ /**
482
+ * Create handler flow with instrumentation
483
+ */
476
484
  function createHandlerFlow(instrumentation) {
477
- return (handlerFn, [trigger, env, context$1]) => {
478
- const { ctx: proxiedCtx, tracker } = proxyExecutionContext(context$1);
479
- const tracer = trace.getTracer("autotel-edge");
480
- const { name, options, context: spanContext } = instrumentation.getInitialSpanInfo(trigger);
481
- if (options.attributes) {
482
- options.attributes["faas.coldstart"] = coldStart;
483
- } else {
484
- options.attributes = { "faas.coldstart": coldStart };
485
- }
486
- coldStart = false;
487
- const parentContext = spanContext || context.active();
488
- const instrumentedTrigger = instrumentation.instrumentTrigger ? instrumentation.instrumentTrigger(trigger) : trigger;
489
- return tracer.startActiveSpan(name, options, parentContext, async (span) => {
490
- try {
491
- const result = await handlerFn(instrumentedTrigger, env, proxiedCtx);
492
- if (instrumentation.getAttributesFromResult) {
493
- const attributes = instrumentation.getAttributesFromResult(result);
494
- span.setAttributes(attributes);
495
- }
496
- span.setStatus({ code: SpanStatusCode.OK });
497
- if (instrumentation.executionSucces) {
498
- instrumentation.executionSucces(span, trigger, result);
499
- }
500
- return result;
501
- } catch (error) {
502
- span.recordException(error);
503
- span.setStatus({
504
- code: SpanStatusCode.ERROR,
505
- message: error instanceof Error ? error.message : String(error)
506
- });
507
- if (instrumentation.executionFailed) {
508
- instrumentation.executionFailed(span, trigger, error);
509
- }
510
- throw error;
511
- } finally {
512
- span.end();
513
- context$1.waitUntil(exportSpans(span.spanContext().traceId, tracker, context$1));
514
- }
515
- });
516
- };
485
+ return (handlerFn, [trigger, env, context$1]) => {
486
+ const { ctx: proxiedCtx, tracker } = proxyExecutionContext(context$1);
487
+ const tracer = trace.getTracer("autotel-edge");
488
+ const { name, options, context: spanContext } = instrumentation.getInitialSpanInfo(trigger);
489
+ if (options.attributes) options.attributes["faas.coldstart"] = coldStart;
490
+ else options.attributes = { "faas.coldstart": coldStart };
491
+ coldStart = false;
492
+ const parentContext = spanContext || context.active();
493
+ const instrumentedTrigger = instrumentation.instrumentTrigger ? instrumentation.instrumentTrigger(trigger) : trigger;
494
+ return tracer.startActiveSpan(name, options, parentContext, async (span) => {
495
+ try {
496
+ const result = await handlerFn(instrumentedTrigger, env, proxiedCtx);
497
+ if (instrumentation.getAttributesFromResult) {
498
+ const attributes = instrumentation.getAttributesFromResult(result);
499
+ span.setAttributes(attributes);
500
+ }
501
+ span.setStatus({ code: SpanStatusCode.OK });
502
+ if (instrumentation.executionSucces) instrumentation.executionSucces(span, trigger, result);
503
+ return result;
504
+ } catch (error) {
505
+ span.recordException(error);
506
+ span.setStatus({
507
+ code: SpanStatusCode.ERROR,
508
+ message: error instanceof Error ? error.message : String(error)
509
+ });
510
+ if (instrumentation.executionFailed) instrumentation.executionFailed(span, trigger, error);
511
+ throw error;
512
+ } finally {
513
+ span.end();
514
+ context$1.waitUntil(exportSpans(span.spanContext().traceId, tracker, context$1));
515
+ }
516
+ });
517
+ };
517
518
  }
519
+ /**
520
+ * Create handler proxy
521
+ */
518
522
  function createHandlerProxy(_handler, handlerFn, initialiser, instrumentation) {
519
- return (trigger, env, ctx) => {
520
- const config = initialiser(env, trigger);
521
- if (config.instrumentation.disabled) {
522
- return handlerFn(trigger, env, ctx);
523
- }
524
- const instrumentedEnv = instrumentBindings(env);
525
- const configContext = setConfig(config);
526
- initProvider(config);
527
- const flowFn = createHandlerFlow(instrumentation);
528
- return context.with(configContext, () => {
529
- return flowFn(handlerFn, [trigger, instrumentedEnv, ctx]);
530
- });
531
- };
523
+ return (trigger, env, ctx) => {
524
+ const config = initialiser(env, trigger);
525
+ if (config.instrumentation.disabled) return handlerFn(trigger, env, ctx);
526
+ const instrumentedEnv = instrumentBindings(env);
527
+ const configContext = setConfig(config);
528
+ initProvider(config);
529
+ const flowFn = createHandlerFlow(instrumentation);
530
+ return context.with(configContext, () => {
531
+ return flowFn(handlerFn, [
532
+ trigger,
533
+ instrumentedEnv,
534
+ ctx
535
+ ]);
536
+ });
537
+ };
532
538
  }
539
+ /**
540
+ * Create handler proxy with dynamic instrumentation (for fetch with postProcess)
541
+ */
533
542
  function createHandlerProxyWithConfig(_handler, handlerFn, initialiser, createInstrumentation) {
534
- return (trigger, env, ctx) => {
535
- const config = initialiser(env, trigger);
536
- if (config.instrumentation.disabled) {
537
- return handlerFn(trigger, env, ctx);
538
- }
539
- if (trigger instanceof Request) {
540
- const pathname = new URL(trigger.url).pathname;
541
- const fetchCfg = config.handlers.fetch;
542
- if (!shouldInstrumentPath(pathname, {
543
- include: fetchCfg.include,
544
- exclude: fetchCfg.exclude
545
- })) {
546
- return handlerFn(trigger, env, ctx);
547
- }
548
- }
549
- const instrumentedEnv = instrumentBindings(env);
550
- const configContext = setConfig(config);
551
- initProvider(config);
552
- const instrumentation = createInstrumentation(config);
553
- const flowFn = createHandlerFlow(instrumentation);
554
- return context.with(configContext, () => {
555
- return flowFn(handlerFn, [trigger, instrumentedEnv, ctx]);
556
- });
557
- };
543
+ return (trigger, env, ctx) => {
544
+ const config = initialiser(env, trigger);
545
+ if (config.instrumentation.disabled) return handlerFn(trigger, env, ctx);
546
+ if (trigger instanceof Request) {
547
+ const pathname = new URL(trigger.url).pathname;
548
+ const fetchCfg = config.handlers.fetch;
549
+ if (!shouldInstrumentPath(pathname, {
550
+ include: fetchCfg.include,
551
+ exclude: fetchCfg.exclude
552
+ })) return handlerFn(trigger, env, ctx);
553
+ }
554
+ const instrumentedEnv = instrumentBindings(env);
555
+ const configContext = setConfig(config);
556
+ initProvider(config);
557
+ const flowFn = createHandlerFlow(createInstrumentation(config));
558
+ return context.with(configContext, () => {
559
+ return flowFn(handlerFn, [
560
+ trigger,
561
+ instrumentedEnv,
562
+ ctx
563
+ ]);
564
+ });
565
+ };
558
566
  }
559
- var providerInitialized = false;
560
- var coldStart = true;
567
+ let providerInitialized = false;
568
+ let coldStart = true;
569
+ /**
570
+ * Initialize the tracer provider
571
+ */
561
572
  function initProvider(config) {
562
- if (providerInitialized) return;
563
- if (config.instrumentation.instrumentGlobalFetch) {
564
- instrumentGlobalFetch();
565
- }
566
- if (config.instrumentation.instrumentGlobalCache) {
567
- instrumentGlobalCache();
568
- }
569
- propagation.setGlobalPropagator(config.propagator);
570
- const resource = resourceFromAttributes({
571
- "service.name": config.service.name,
572
- "service.version": config.service.version,
573
- "service.namespace": config.service.namespace,
574
- "cloud.provider": "cloudflare",
575
- "cloud.platform": "cloudflare.workers",
576
- "telemetry.sdk.name": "autotel-edge",
577
- "telemetry.sdk.language": "js"
578
- });
579
- const provider = new WorkerTracerProvider(config.spanProcessors, resource);
580
- provider.register();
581
- const tracer = trace.getTracer("autotel-edge");
582
- tracer.setHeadSampler(config.sampling.headSampler);
583
- providerInitialized = true;
573
+ if (providerInitialized) return;
574
+ if (config.instrumentation.instrumentGlobalFetch) instrumentGlobalFetch();
575
+ if (config.instrumentation.instrumentGlobalCache) instrumentGlobalCache();
576
+ propagation.setGlobalPropagator(config.propagator);
577
+ const resource = resourceFromAttributes({
578
+ "service.name": config.service.name,
579
+ "service.version": config.service.version,
580
+ "service.namespace": config.service.namespace,
581
+ "cloud.provider": "cloudflare",
582
+ "cloud.platform": "cloudflare.workers",
583
+ "telemetry.sdk.name": "autotel-edge",
584
+ "telemetry.sdk.language": "js"
585
+ });
586
+ new WorkerTracerProvider(config.spanProcessors, resource).register();
587
+ trace.getTracer("autotel-edge").setHeadSampler(config.sampling.headSampler);
588
+ providerInitialized = true;
584
589
  }
590
+ /**
591
+ * Instrument a Cloudflare Workers handler
592
+ *
593
+ * @example
594
+ * ```typescript
595
+ * import { instrument } from 'autotel-edge'
596
+ *
597
+ * const handler = {
598
+ * async fetch(request, env, ctx) {
599
+ * return new Response('Hello World')
600
+ * }
601
+ * }
602
+ *
603
+ * export default instrument(handler, {
604
+ * exporter: {
605
+ * url: env.OTLP_ENDPOINT,
606
+ * headers: { 'x-api-key': env.API_KEY }
607
+ * },
608
+ * service: { name: 'my-worker' }
609
+ * })
610
+ * ```
611
+ */
585
612
  function instrument(handler, config) {
586
- const initialiser = createInitialiser(config);
587
- if (handler.fetch) {
588
- const fetcher = unwrap(handler.fetch);
589
- handler.fetch = createHandlerProxyWithConfig(
590
- handler,
591
- fetcher,
592
- initialiser,
593
- createFetchInstrumentation
594
- );
595
- }
596
- if (handler.scheduled) {
597
- const scheduled = unwrap(handler.scheduled);
598
- handler.scheduled = createHandlerProxy(
599
- handler,
600
- scheduled,
601
- initialiser,
602
- scheduledInstrumentation
603
- );
604
- }
605
- if (handler.queue) {
606
- const queue = unwrap(handler.queue);
607
- handler.queue = createHandlerProxy(
608
- handler,
609
- queue,
610
- initialiser,
611
- new QueueInstrumentation()
612
- );
613
- }
614
- if (handler.email) {
615
- const email = unwrap(handler.email);
616
- handler.email = createHandlerProxy(
617
- handler,
618
- email,
619
- initialiser,
620
- emailInstrumentation
621
- );
622
- }
623
- return handler;
613
+ const initialiser = createInitialiser(config);
614
+ if (handler.fetch) handler.fetch = createHandlerProxyWithConfig(handler, unwrap(handler.fetch), initialiser, createFetchInstrumentation);
615
+ if (handler.scheduled) handler.scheduled = createHandlerProxy(handler, unwrap(handler.scheduled), initialiser, scheduledInstrumentation);
616
+ if (handler.queue) handler.queue = createHandlerProxy(handler, unwrap(handler.queue), initialiser, new QueueInstrumentation());
617
+ if (handler.email) handler.email = createHandlerProxy(handler, unwrap(handler.email), initialiser, emailInstrumentation);
618
+ return handler;
624
619
  }
625
620
 
626
- // src/wrappers/wrap-module.ts
621
+ //#endregion
622
+ //#region src/wrappers/wrap-module.ts
623
+ /**
624
+ * workers-honeycomb-logger style wrapper API
625
+ *
626
+ * @example
627
+ * ```typescript
628
+ * import { wrapModule } from 'autotel-cloudflare'
629
+ *
630
+ * const handler = {
631
+ * async fetch(req, env, ctx) {
632
+ * return new Response('Hello')
633
+ * }
634
+ * }
635
+ *
636
+ * export default wrapModule(
637
+ * { service: { name: 'my-worker' } },
638
+ * handler
639
+ * )
640
+ * ```
641
+ */
642
+ /**
643
+ * Wrap a Cloudflare Workers module-style handler
644
+ * Alternative API style inspired by workers-honeycomb-logger
645
+ *
646
+ * @param config Configuration (can be static object or function)
647
+ * @param handler The worker handler to wrap
648
+ * @returns Instrumented handler
649
+ */
627
650
  function wrapModule(config, handler) {
628
- return instrument(handler, config);
651
+ return instrument(handler, config);
629
652
  }
630
653
 
631
- // src/wrappers/wrap-do.ts
654
+ //#endregion
655
+ //#region src/wrappers/wrap-do.ts
656
+ /**
657
+ * Durable Object wrapper
658
+ *
659
+ * @example
660
+ * ```typescript
661
+ * import { wrapDurableObject } from 'autotel-cloudflare'
662
+ *
663
+ * class Counter implements DurableObject {
664
+ * async fetch(request: Request) {
665
+ * return new Response('count')
666
+ * }
667
+ * }
668
+ *
669
+ * export default wrapDurableObject({ service: { name: 'counter-do' } }, Counter)
670
+ * ```
671
+ */
672
+ /**
673
+ * Wrap a Durable Object class with instrumentation
674
+ * Alternative API style inspired by workers-honeycomb-logger
675
+ *
676
+ * @param config Configuration (can be static object or function)
677
+ * @param doClass The Durable Object class to wrap
678
+ * @returns Instrumented Durable Object class
679
+ */
632
680
  function wrapDurableObject(config, doClass) {
633
- return instrumentDO(doClass, config);
681
+ return instrumentDO(doClass, config);
634
682
  }
635
683
 
636
- // src/wrappers/define-worker-fetch.ts
684
+ //#endregion
685
+ //#region src/wrappers/define-worker-fetch.ts
686
+ /**
687
+ * Wrap a Workers fetch handler so:
688
+ * - the handler is instrumented (spans, propagation, waitUntil export flush)
689
+ * - the handler receives a request-scoped logger as its fourth argument
690
+ */
637
691
  function defineWorkerFetch(config, handler, loggerOptions = {}) {
638
- const wrapped = instrument(
639
- {
640
- fetch(request, env, ctx) {
641
- const log = createWorkersLogger(request, loggerOptions);
642
- return handler(request, env, ctx, log);
643
- }
644
- },
645
- config
646
- );
647
- return {
648
- fetch(request, env, ctx) {
649
- return Promise.resolve(
650
- wrapped.fetch(request, env, ctx)
651
- );
652
- }
653
- };
692
+ const wrapped = instrument({ fetch(request, env, ctx) {
693
+ return handler(request, env, ctx, createWorkersLogger(request, loggerOptions));
694
+ } }, config);
695
+ return { fetch(request, env, ctx) {
696
+ return Promise.resolve(wrapped.fetch(request, env, ctx));
697
+ } };
654
698
  }
655
699
 
656
- export { defineWorkerFetch, instrument, instrumentGlobalCache, instrumentGlobalFetch, wrapDurableObject, wrapModule };
657
- //# sourceMappingURL=index.js.map
700
+ //#endregion
701
+ export { createWorkersLogger, defineWorkerFetch, getActorLogger, getQueueLogger, getRequestLogger, getWorkflowLogger, instrument, instrumentAI, instrumentAnalyticsEngine, instrumentBindings, instrumentBrowserRendering, instrumentD1, instrumentDO, instrumentGlobalCache, instrumentGlobalFetch, instrumentHyperdrive, instrumentImages, instrumentKV, instrumentQueueProducer, instrumentR2, instrumentRateLimiter, instrumentServiceBinding, instrumentVectorize, instrumentWorkflow, wrapDurableObject, wrapModule };
658
702
  //# sourceMappingURL=index.js.map