autotel-cloudflare 2.18.4 → 2.18.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -0
- package/dist/chunk-C3QLNZRK.js +63 -0
- package/dist/chunk-C3QLNZRK.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +35 -1
- package/dist/index.js.map +1 -1
- package/dist/logger-DGS3kP-A.d.ts +20 -0
- package/dist/logger.d.ts +1 -8
- package/dist/logger.js +1 -1
- package/package.json +2 -2
- package/src/execution-logger.test.ts +58 -2
- package/src/execution-logger.ts +71 -0
- package/src/index.ts +2 -0
- package/src/wrappers/cf-attributes.test.ts +59 -0
- package/src/wrappers/instrument.ts +55 -0
- package/dist/chunk-EACMDVCB.js +0 -19
- package/dist/chunk-EACMDVCB.js.map +0 -1
package/README.md
CHANGED
|
@@ -109,6 +109,35 @@ export default instrument(
|
|
|
109
109
|
)
|
|
110
110
|
```
|
|
111
111
|
|
|
112
|
+
### Fetch Route Controls
|
|
113
|
+
|
|
114
|
+
Filter which fetch routes are instrumented and map route patterns to service names:
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
import { wrapModule } from 'autotel-cloudflare'
|
|
118
|
+
|
|
119
|
+
export default wrapModule(
|
|
120
|
+
{
|
|
121
|
+
service: { name: 'edge-gateway' },
|
|
122
|
+
handlers: {
|
|
123
|
+
fetch: {
|
|
124
|
+
include: ['/api/**'],
|
|
125
|
+
exclude: ['/api/internal/**', '/health'],
|
|
126
|
+
routes: {
|
|
127
|
+
'/api/auth/**': { service: 'auth-service' },
|
|
128
|
+
'/api/**': { service: 'api-service' },
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
async fetch(req) {
|
|
135
|
+
return new Response('ok')
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
)
|
|
139
|
+
```
|
|
140
|
+
|
|
112
141
|
### Style 3: Functional API (Unique)
|
|
113
142
|
|
|
114
143
|
Zero-boilerplate function tracing:
|
|
@@ -132,6 +161,31 @@ export const processPayment = trace(ctx => async (amount: number) => {
|
|
|
132
161
|
})
|
|
133
162
|
```
|
|
134
163
|
|
|
164
|
+
## Request Logger Bootstrap
|
|
165
|
+
|
|
166
|
+
Use `createWorkersLogger()` for request-scoped snapshots with Cloudflare context pre-filled.
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
import { wrapModule, createWorkersLogger } from 'autotel-cloudflare'
|
|
170
|
+
|
|
171
|
+
export default wrapModule(
|
|
172
|
+
{ service: { name: 'checkout-worker' } },
|
|
173
|
+
{
|
|
174
|
+
async fetch(request) {
|
|
175
|
+
const log = createWorkersLogger(request, {
|
|
176
|
+
headers: ['x-request-id'],
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
log.info('checkout.started')
|
|
180
|
+
log.set({ checkout: { stage: 'validated' } })
|
|
181
|
+
log.emitNow({ status: 200 })
|
|
182
|
+
|
|
183
|
+
return new Response('ok')
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
)
|
|
187
|
+
```
|
|
188
|
+
|
|
135
189
|
## Complete Bindings Coverage
|
|
136
190
|
|
|
137
191
|
### Auto-Instrumented Bindings
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { getExecutionLogger } from 'autotel-edge';
|
|
2
|
+
|
|
3
|
+
// src/execution-logger.ts
|
|
4
|
+
function isRecord(value) {
|
|
5
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6
|
+
}
|
|
7
|
+
function collectHeaders(headers, include) {
|
|
8
|
+
if (!include || include.length === 0) return void 0;
|
|
9
|
+
const allowlist = new Set(include.map((h) => h.toLowerCase()));
|
|
10
|
+
const out = {};
|
|
11
|
+
headers.forEach((value, key) => {
|
|
12
|
+
if (allowlist.has(key.toLowerCase())) {
|
|
13
|
+
out[key] = value;
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
17
|
+
}
|
|
18
|
+
function pickCfContext(request) {
|
|
19
|
+
const cf = Reflect.get(request, "cf");
|
|
20
|
+
if (!isRecord(cf)) return {};
|
|
21
|
+
const out = {};
|
|
22
|
+
if (typeof cf.colo === "string") out.colo = cf.colo;
|
|
23
|
+
if (typeof cf.country === "string") out.country = cf.country;
|
|
24
|
+
if (typeof cf.asn === "number") out.asn = cf.asn;
|
|
25
|
+
if (typeof cf.city === "string") out.city = cf.city;
|
|
26
|
+
if (typeof cf.region === "string") out.region = cf.region;
|
|
27
|
+
return out;
|
|
28
|
+
}
|
|
29
|
+
function createWorkersLogger(request, options = {}, ctx) {
|
|
30
|
+
const log = getExecutionLogger(ctx);
|
|
31
|
+
const url = new URL(request.url);
|
|
32
|
+
const cfRay = request.headers.get("cf-ray") ?? void 0;
|
|
33
|
+
const traceparent = request.headers.get("traceparent") ?? void 0;
|
|
34
|
+
log.set({
|
|
35
|
+
request: {
|
|
36
|
+
method: request.method,
|
|
37
|
+
path: url.pathname,
|
|
38
|
+
url: request.url,
|
|
39
|
+
requestId: options.requestId ?? cfRay,
|
|
40
|
+
headers: collectHeaders(request.headers, options.headers)
|
|
41
|
+
},
|
|
42
|
+
cfRay,
|
|
43
|
+
traceparent,
|
|
44
|
+
...pickCfContext(request)
|
|
45
|
+
});
|
|
46
|
+
return log;
|
|
47
|
+
}
|
|
48
|
+
function getRequestLogger(ctx, options) {
|
|
49
|
+
return getExecutionLogger(ctx, options);
|
|
50
|
+
}
|
|
51
|
+
function getQueueLogger(ctx, options) {
|
|
52
|
+
return getExecutionLogger(ctx, options);
|
|
53
|
+
}
|
|
54
|
+
function getWorkflowLogger(ctx, options) {
|
|
55
|
+
return getExecutionLogger(ctx, options);
|
|
56
|
+
}
|
|
57
|
+
function getActorLogger(ctx, options) {
|
|
58
|
+
return getExecutionLogger(ctx, options);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export { createWorkersLogger, getActorLogger, getQueueLogger, getRequestLogger, getWorkflowLogger };
|
|
62
|
+
//# sourceMappingURL=chunk-C3QLNZRK.js.map
|
|
63
|
+
//# sourceMappingURL=chunk-C3QLNZRK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/execution-logger.ts"],"names":[],"mappings":"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","file":"chunk-C3QLNZRK.js","sourcesContent":["import {\n type ExecutionLogger,\n type ExecutionLoggerOptions,\n type ExecutionLogSnapshot,\n getExecutionLogger,\n type TraceContext,\n} from 'autotel-edge';\n\nexport type {\n ExecutionLogger,\n ExecutionLoggerOptions,\n ExecutionLogSnapshot,\n};\n\nexport interface WorkersLoggerOptions {\n /** Override derived request id (default: cf-ray header value when present). */\n requestId?: string;\n /** Optional request header allowlist to include in logger context. */\n headers?: string[];\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction collectHeaders(\n headers: Headers,\n include: string[] | undefined,\n): Record<string, string> | undefined {\n if (!include || include.length === 0) return undefined;\n\n const allowlist = new Set(include.map((h) => h.toLowerCase()));\n const out: Record<string, string> = {};\n headers.forEach((value, key) => {\n if (allowlist.has(key.toLowerCase())) {\n out[key] = value;\n }\n });\n\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\nfunction pickCfContext(request: Request): Record<string, unknown> {\n const cf = Reflect.get(request, 'cf');\n if (!isRecord(cf)) return {};\n\n const out: Record<string, unknown> = {};\n if (typeof cf.colo === 'string') out.colo = cf.colo;\n if (typeof cf.country === 'string') out.country = cf.country;\n if (typeof cf.asn === 'number') out.asn = cf.asn;\n if (typeof cf.city === 'string') out.city = cf.city;\n if (typeof cf.region === 'string') out.region = cf.region;\n return out;\n}\n\n/**\n * Create an execution logger pre-populated with common request context.\n * Best used from fetch handlers that already run inside autotel span context.\n */\nexport function createWorkersLogger(\n request: Request,\n options: WorkersLoggerOptions = {},\n ctx?: TraceContext,\n): ExecutionLogger {\n const log = getExecutionLogger(ctx);\n const url = new URL(request.url);\n const cfRay = request.headers.get('cf-ray') ?? undefined;\n const traceparent = request.headers.get('traceparent') ?? undefined;\n\n log.set({\n request: {\n method: request.method,\n path: url.pathname,\n url: request.url,\n requestId: options.requestId ?? cfRay,\n headers: collectHeaders(request.headers, options.headers),\n },\n cfRay,\n traceparent,\n ...pickCfContext(request),\n });\n\n return log;\n}\n\nexport function getRequestLogger(\n ctx?: TraceContext,\n options?: ExecutionLoggerOptions,\n): ExecutionLogger {\n return getExecutionLogger(ctx, options);\n}\n\nexport function getQueueLogger(\n ctx?: TraceContext,\n options?: ExecutionLoggerOptions,\n): ExecutionLogger {\n return getExecutionLogger(ctx, options);\n}\n\nexport function getWorkflowLogger(\n ctx?: TraceContext,\n options?: ExecutionLoggerOptions,\n): ExecutionLogger {\n return getExecutionLogger(ctx, options);\n}\n\nexport function getActorLogger(\n ctx?: TraceContext,\n options?: ExecutionLoggerOptions,\n): ExecutionLogger {\n return getExecutionLogger(ctx, options);\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ConfigurationOption } from 'autotel-edge';
|
|
2
2
|
export * from 'autotel-edge';
|
|
3
3
|
export { ExecutionLogSnapshot, ExecutionLogger, ExecutionLoggerOptions } from 'autotel-edge';
|
|
4
|
-
export { getActorLogger, getQueueLogger, getRequestLogger, getWorkflowLogger } from './logger.js';
|
|
4
|
+
export { W as WorkersLoggerOptions, c as createWorkersLogger, g as getActorLogger, a as getQueueLogger, b as getRequestLogger, d as getWorkflowLogger } from './logger-DGS3kP-A.js';
|
|
5
5
|
export { instrumentDO, instrumentWorkflow } from './handlers.js';
|
|
6
6
|
export { instrumentAI, instrumentAnalyticsEngine, instrumentBindings, instrumentBrowserRendering, instrumentD1, instrumentHyperdrive, instrumentImages, instrumentKV, instrumentQueueProducer, instrumentR2, instrumentRateLimiter, instrumentServiceBinding, instrumentVectorize } from './bindings.js';
|
|
7
7
|
import 'autotel-edge/logger';
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { instrumentBindings } from './chunk-KAUHT25H.js';
|
|
|
2
2
|
export { instrumentAI, instrumentAnalyticsEngine, instrumentBindings, instrumentBrowserRendering, instrumentD1, instrumentHyperdrive, instrumentImages, instrumentKV, instrumentQueueProducer, instrumentR2, instrumentRateLimiter, instrumentServiceBinding, instrumentVectorize } from './chunk-KAUHT25H.js';
|
|
3
3
|
import { instrumentDO } from './chunk-MIDMNKDC.js';
|
|
4
4
|
export { instrumentDO, instrumentWorkflow } from './chunk-MIDMNKDC.js';
|
|
5
|
-
export { getActorLogger, getQueueLogger, getRequestLogger, getWorkflowLogger } from './chunk-
|
|
5
|
+
export { createWorkersLogger, getActorLogger, getQueueLogger, getRequestLogger, getWorkflowLogger } from './chunk-C3QLNZRK.js';
|
|
6
6
|
import { wrap, unwrap, proxyExecutionContext } from './chunk-O4IYKWPJ.js';
|
|
7
7
|
import { createInitialiser, getActiveConfig, setConfig, WorkerTracerProvider, WorkerTracer } from 'autotel-edge';
|
|
8
8
|
export * from 'autotel-edge';
|
|
@@ -177,6 +177,28 @@ function instrumentGlobalCache() {
|
|
|
177
177
|
}
|
|
178
178
|
|
|
179
179
|
// src/wrappers/instrument.ts
|
|
180
|
+
function matchesPattern(path, pattern) {
|
|
181
|
+
const regexPattern = pattern.replaceAll(/[.+^${}()|[\]\\]/g, String.raw`\$&`).replaceAll("**", "{{GLOBSTAR}}").replaceAll("*", "[^/]*").replaceAll("{{GLOBSTAR}}", ".*").replaceAll("?", "[^/]");
|
|
182
|
+
return new RegExp(`^${regexPattern}$`).test(path);
|
|
183
|
+
}
|
|
184
|
+
function shouldInstrumentPath(path, include, exclude) {
|
|
185
|
+
if (exclude && exclude.some((pattern) => matchesPattern(path, pattern))) {
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
if (!include || include.length === 0) {
|
|
189
|
+
return true;
|
|
190
|
+
}
|
|
191
|
+
return include.some((pattern) => matchesPattern(path, pattern));
|
|
192
|
+
}
|
|
193
|
+
function getServiceForPath(path, routes) {
|
|
194
|
+
if (!routes) return void 0;
|
|
195
|
+
for (const [pattern, config] of Object.entries(routes)) {
|
|
196
|
+
if (matchesPattern(path, pattern)) {
|
|
197
|
+
return config.service;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return void 0;
|
|
201
|
+
}
|
|
180
202
|
function extractCfAttributes(request) {
|
|
181
203
|
const cf = request.cf;
|
|
182
204
|
if (!cf) return {};
|
|
@@ -207,6 +229,10 @@ function createFetchInstrumentation(config) {
|
|
|
207
229
|
return {
|
|
208
230
|
getInitialSpanInfo: (request) => {
|
|
209
231
|
const url = new URL(request.url);
|
|
232
|
+
const routeService = getServiceForPath(
|
|
233
|
+
url.pathname,
|
|
234
|
+
config.handlers.fetch.routes
|
|
235
|
+
);
|
|
210
236
|
const cfAttrs = config.extractCfAttributes === false ? {} : extractCfAttributes(request);
|
|
211
237
|
return {
|
|
212
238
|
name: `${request.method} ${url.pathname}`,
|
|
@@ -215,6 +241,7 @@ function createFetchInstrumentation(config) {
|
|
|
215
241
|
attributes: {
|
|
216
242
|
"http.request.method": request.method,
|
|
217
243
|
"url.full": request.url,
|
|
244
|
+
...routeService ? { "service.name": routeService, "autotel.route.service": routeService } : {},
|
|
218
245
|
...cfAttrs
|
|
219
246
|
}
|
|
220
247
|
},
|
|
@@ -526,6 +553,13 @@ function createHandlerProxyWithConfig(_handler, handlerFn, initialiser, createIn
|
|
|
526
553
|
if (config.instrumentation.disabled) {
|
|
527
554
|
return handlerFn(trigger, env, ctx);
|
|
528
555
|
}
|
|
556
|
+
if (trigger instanceof Request) {
|
|
557
|
+
const pathname = new URL(trigger.url).pathname;
|
|
558
|
+
const fetchCfg = config.handlers.fetch;
|
|
559
|
+
if (!shouldInstrumentPath(pathname, fetchCfg.include, fetchCfg.exclude)) {
|
|
560
|
+
return handlerFn(trigger, env, ctx);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
529
563
|
const instrumentedEnv = instrumentBindings(env);
|
|
530
564
|
const configContext = setConfig(config);
|
|
531
565
|
initProvider(config);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/global/fetch.ts","../src/global/cache.ts","../src/wrappers/instrument.ts","../src/wrappers/wrap-module.ts","../src/wrappers/wrap-do.ts"],"names":["api_context","trace","SpanKind","SpanStatusCode","propagation","target","prop","getActiveConfig","WorkerTracer","context"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Global fetch() instrumentation for autotel-edge\n *\n * Automatically traces all outgoing fetch() calls with:\n * - HTTP method, URL, status code\n * - Request/response headers\n * - Automatic context propagation\n * - Error tracking\n */\n\nimport {\n trace,\n context as api_context,\n propagation,\n SpanStatusCode,\n SpanKind,\n} from '@opentelemetry/api';\nimport { getActiveConfig, WorkerTracer } from 'autotel-edge';\n\n/**\n * Gather HTTP request attributes following OpenTelemetry semantic conventions\n */\nfunction gatherRequestAttributes(request: Request): Record<string, any> {\n const url = new URL(request.url);\n const config = getActiveConfig();\n const redactQuery = config?.dataSafety?.redactQueryParams === true;\n\n return {\n 'http.request.method': request.method.toUpperCase(),\n 'url.full': redactQuery ? `${url.origin}${url.pathname}` : request.url,\n 'url.scheme': url.protocol.replace(':', ''),\n 'server.address': url.host,\n 'url.path': url.pathname,\n 'url.query': redactQuery ? (url.search ? '[REDACTED]' : '') : url.search,\n 'network.protocol.name': 'http',\n 'user_agent.original': request.headers.get('user-agent') || undefined,\n };\n}\n\n/**\n * Gather HTTP response attributes\n */\nfunction gatherResponseAttributes(response: Response): Record<string, any> {\n return {\n 'http.response.status_code': response.status,\n 'http.response.body.size': response.headers.get('content-length') || undefined,\n };\n}\n\n/**\n * Instrument the global fetch function\n *\n * This wraps globalThis.fetch to automatically create spans for all outgoing HTTP requests.\n *\n * **Note:** This is called automatically when the library is initialized with\n * `instrumentation.instrumentGlobalFetch: true` (default).\n */\nexport function instrumentGlobalFetch(): void {\n const originalFetch = globalThis.fetch;\n\n const instrumentedFetch = function fetch(\n input: RequestInfo | URL,\n init?: RequestInit,\n ): Promise<Response> {\n const request = new Request(input, init);\n\n // Skip non-HTTP requests\n if (!request.url.startsWith('http')) {\n return originalFetch(input, init);\n }\n\n // Skip if no active config (not initialized yet)\n const config = getActiveConfig();\n if (!config) {\n return originalFetch(input, init);\n }\n\n const tracer = trace.getTracer('autotel-edge') as WorkerTracer;\n const url = new URL(request.url);\n const spanName = `${request.method} ${url.host}`;\n\n return tracer.startActiveSpan(\n spanName,\n {\n kind: SpanKind.CLIENT,\n attributes: gatherRequestAttributes(request),\n },\n async (span) => {\n try {\n // Inject trace context into request headers for distributed tracing\n const shouldIncludeContext =\n typeof config.fetch?.includeTraceContext === 'function'\n ? config.fetch.includeTraceContext(request)\n : (config.fetch?.includeTraceContext ?? true);\n\n if (shouldIncludeContext) {\n propagation.inject(api_context.active(), request.headers, {\n set: (headers, key, value) => {\n if (typeof value === 'string') {\n headers.set(key, value);\n }\n },\n });\n }\n\n // Make the actual fetch call\n const response = await originalFetch(request);\n\n // Add response attributes\n span.setAttributes(gatherResponseAttributes(response));\n\n // Set span status based on response\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 // Replace global fetch\n globalThis.fetch = instrumentedFetch as typeof fetch;\n}\n","/**\n * Global Cache API instrumentation for Cloudflare Workers\n *\n * Automatically traces cache operations:\n * - cache.match() - Read from cache\n * - cache.put() - Write to cache\n * - cache.delete() - Delete from cache\n */\n\nimport { trace, SpanStatusCode, SpanKind } from '@opentelemetry/api';\nimport { wrap } from '../bindings/common';\nimport { WorkerTracer } from 'autotel-edge';\n\ntype CacheOperation = 'match' | 'put' | 'delete';\n\n/**\n * Sanitize URL for span attributes (remove query params that might contain sensitive data)\n */\nfunction sanitizeURL(url: string): string {\n const u = new URL(url);\n return `${u.protocol}//${u.host}${u.pathname}`;\n}\n\n/**\n * Instrument a cache method (match, put, delete)\n */\nfunction instrumentCacheMethod<T extends Function>(\n fn: T,\n cacheName: string,\n operation: CacheOperation,\n): T {\n const handler: ProxyHandler<T> = {\n async apply(target, thisArg, argArray) {\n const tracer = trace.getTracer('autotel-edge') as WorkerTracer;\n\n // Extract URL from first argument (Request or string)\n const firstArg = argArray[0];\n const url =\n firstArg instanceof Request\n ? firstArg.url\n : typeof firstArg === 'string'\n ? firstArg\n : undefined;\n\n const spanName = `Cache ${cacheName}.${operation}`;\n\n return tracer.startActiveSpan(\n spanName,\n {\n kind: SpanKind.CLIENT,\n attributes: {\n 'cache.name': cacheName,\n 'cache.operation': operation,\n 'cache.key': url ? sanitizeURL(url) : undefined,\n },\n },\n async (span) => {\n try {\n const result = await Reflect.apply(target, thisArg, argArray);\n\n // For match operations, record whether it was a hit or miss\n if (operation === 'match') {\n span.setAttribute('cache.hit', !!result);\n }\n\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 return wrap(fn, handler);\n}\n\n/**\n * Instrument a Cache instance\n */\nfunction instrumentCache(cache: Cache, cacheName: string): Cache {\n const handler: ProxyHandler<Cache> = {\n get(target, prop) {\n const value = Reflect.get(target, prop);\n\n // Instrument the cache operation methods\n if (\n (prop === 'match' || prop === 'put' || prop === 'delete') &&\n typeof value === 'function'\n ) {\n return instrumentCacheMethod(\n value.bind(target),\n cacheName,\n prop as CacheOperation,\n );\n }\n\n // Bind other methods to preserve `this` context\n if (typeof value === 'function') {\n return value.bind(target);\n }\n\n return value;\n },\n };\n\n return wrap(cache, handler);\n}\n\n/**\n * Instrument caches.open()\n */\nfunction instrumentCachesOpen(\n openFn: CacheStorage['open'],\n): CacheStorage['open'] {\n const handler: ProxyHandler<CacheStorage['open']> = {\n async apply(target, thisArg, argArray) {\n const cacheName = argArray[0];\n const cache = await Reflect.apply(target, thisArg, argArray);\n return instrumentCache(cache, cacheName);\n },\n };\n\n return wrap(openFn, handler);\n}\n\n/**\n * Instrument the global caches API\n *\n * This wraps globalThis.caches to automatically create spans for all cache operations.\n *\n * **Note:** This is called automatically when the library is initialized with\n * `instrumentation.instrumentGlobalCache: true` (default).\n */\nexport function instrumentGlobalCache(): void {\n const handler: ProxyHandler<typeof caches> = {\n get(target, prop) {\n if (prop === 'default') {\n // Wrap the default cache\n return instrumentCache(target.default, 'default');\n } else if (prop === 'open') {\n // Wrap the open method\n const openFn = Reflect.get(target, prop);\n if (typeof openFn === 'function') {\n return instrumentCachesOpen(openFn.bind(target));\n }\n }\n\n return Reflect.get(target, prop);\n },\n };\n\n // Replace global caches\n // @ts-ignore - TypeScript doesn't like reassigning globalThis.caches\n globalThis.caches = wrap(caches, handler);\n}\n","/**\n * Handler instrumentation for Cloudflare Workers\n * \n * Note: This file uses Cloudflare Workers types (ExportedHandler, Request, Response, 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 * Provides automatic OpenTelemetry tracing for:\n * - HTTP handlers (fetch)\n * - Scheduled/cron handlers\n * - Queue handlers (with message tracking)\n * - Email handlers\n * - Auto-instrumentation of Cloudflare bindings (KV, R2, D1, Service Bindings)\n * - Global fetch and cache instrumentation\n * - Post-processor support for span customization\n * - Tail sampling support\n * - Cold start tracking\n */\n\nimport {\n trace,\n context as api_context,\n propagation,\n SpanStatusCode,\n SpanKind,\n} from '@opentelemetry/api';\nimport { resourceFromAttributes } from '@opentelemetry/resources';\nimport type {\n ConfigurationOption,\n ResolvedEdgeConfig,\n Trigger,\n HandlerInstrumentation,\n InitialSpanInfo,\n ReadableSpan,\n} from 'autotel-edge';\nimport {\n createInitialiser,\n setConfig,\n getActiveConfig,\n type Initialiser,\n WorkerTracerProvider,\n WorkerTracer,\n} from 'autotel-edge';\nimport { proxyExecutionContext, unwrap, wrap, type PromiseTracker } from '../bindings/common';\nimport { instrumentGlobalFetch } from '../global/fetch';\nimport { instrumentGlobalCache } from '../global/cache';\nimport { instrumentBindings } from '../bindings/bindings';\nimport type { Attributes, Span } from '@opentelemetry/api';\n\ntype FetchHandler = (\n request: Request,\n env: any,\n ctx: ExecutionContext,\n) => Response | Promise<Response>;\n\ntype ScheduledHandler = (\n event: ScheduledController,\n env: any,\n ctx: ExecutionContext,\n) => void | Promise<void>;\n\ntype QueueHandler = (\n batch: MessageBatch,\n env: any,\n ctx: ExecutionContext,\n) => void | Promise<void>;\n\ntype EmailHandler = (\n message: ForwardableEmailMessage,\n env: any,\n ctx: ExecutionContext,\n) => void | Promise<void>;\n\n\n/**\n * Create fetch handler instrumentation with config support for postProcess\n */\n/**\n * Extract Cloudflare-specific attributes from a request\n */\nfunction extractCfAttributes(request: Request): Record<string, string | number | boolean> {\n const cf = (request as any).cf;\n if (!cf) return {};\n\n const attrs: Record<string, string | number | boolean> = {};\n const set = (key: string, value: unknown) => {\n if (value !== undefined && value !== null) {\n attrs[key] = value as string | number | boolean;\n }\n };\n\n set('cloudflare.colo', cf.colo);\n const ray = request.headers.get('cf-ray');\n if (ray) attrs['cloudflare.ray_id'] = ray;\n set('cloudflare.country', cf.country);\n set('cloudflare.city', cf.city);\n set('cloudflare.region', cf.region);\n set('cloudflare.continent', cf.continent);\n set('cloudflare.timezone', cf.timezone);\n set('cloudflare.latitude', cf.latitude);\n set('cloudflare.longitude', cf.longitude);\n set('cloudflare.asn', cf.asn);\n set('cloudflare.as_organization', cf.asOrganization);\n set('cloudflare.http_protocol', cf.httpProtocol);\n set('cloudflare.tls_version', cf.tlsVersion);\n set('cloudflare.client_tcp_rtt', cf.clientTcpRtt);\n\n return attrs;\n}\n\nfunction createFetchInstrumentation(\n config: ResolvedEdgeConfig,\n): HandlerInstrumentation<Request, Response> {\n return {\n getInitialSpanInfo: (request: Request): InitialSpanInfo => {\n const url = new URL(request.url);\n\n const cfAttrs = (config as any).extractCfAttributes === false\n ? {}\n : extractCfAttributes(request);\n\n return {\n name: `${request.method} ${url.pathname}`,\n options: {\n kind: SpanKind.SERVER,\n attributes: {\n 'http.request.method': request.method,\n 'url.full': request.url,\n ...cfAttrs,\n },\n },\n context: propagation.extract(api_context.active(), request.headers),\n };\n },\n getAttributesFromResult: (response: Response) => ({\n 'http.response.status_code': response.status,\n }),\n executionSucces: (span: Span, trigger: Request, result: Response) => {\n // Override span status for server errors (5xx)\n if (result.status >= 500) {\n span.setStatus({ code: SpanStatusCode.ERROR });\n }\n\n // Call postProcess callback if configured\n if (config.handlers.fetch.postProcess) {\n const readableSpan = span as unknown as ReadableSpan;\n config.handlers.fetch.postProcess(span, {\n request: trigger,\n response: result,\n readable: readableSpan,\n });\n }\n },\n };\n}\n\n/**\n * Scheduled handler instrumentation\n */\nconst scheduledInstrumentation: HandlerInstrumentation<ScheduledController, void> = {\n getInitialSpanInfo: (event: ScheduledController): InitialSpanInfo => {\n return {\n name: `scheduledHandler ${event.cron || 'unknown'}`,\n options: {\n kind: SpanKind.INTERNAL,\n attributes: {\n 'faas.trigger': 'timer',\n 'faas.cron': event.cron || 'unknown',\n 'faas.scheduled_time': new Date(event.scheduledTime).toISOString(),\n },\n },\n };\n },\n};\n\n/**\n * Tracks message status counts for queue processing\n */\nclass MessageStatusCount {\n succeeded = 0;\n failed = 0;\n implicitly_acked = 0;\n implicitly_retried = 0;\n readonly total: number;\n\n constructor(total: number) {\n this.total = total;\n }\n\n ack() {\n this.succeeded = this.succeeded + 1;\n }\n\n ackRemaining() {\n this.implicitly_acked = this.total - this.succeeded - this.failed;\n this.succeeded = this.total - this.failed;\n }\n\n retry() {\n this.failed = this.failed + 1;\n }\n\n retryRemaining() {\n this.implicitly_retried = this.total - this.succeeded - this.failed;\n this.failed = this.total - this.succeeded;\n }\n\n toAttributes(): Attributes {\n return {\n 'queue.messages_count': this.total,\n 'queue.messages_success': this.succeeded,\n 'queue.messages_failed': this.failed,\n 'queue.batch_success': this.succeeded === this.total,\n 'queue.implicitly_acked': this.implicitly_acked,\n 'queue.implicitly_retried': this.implicitly_retried,\n };\n }\n}\n\n/**\n * Add event to active span\n */\nfunction addQueueEvent(name: string, msg?: Message, delaySeconds?: number) {\n const attrs: Attributes = {};\n if (msg) {\n attrs['queue.message_id'] = msg.id;\n attrs['queue.message_timestamp'] = msg.timestamp.toISOString();\n // Add attempts if available (from Cloudflare Queues API)\n if ('attempts' in msg && typeof msg.attempts === 'number') {\n attrs['queue.message_attempts'] = msg.attempts;\n }\n }\n if (delaySeconds !== undefined) {\n attrs['queue.retry_delay_seconds'] = delaySeconds;\n }\n trace.getActiveSpan()?.addEvent(name, attrs);\n}\n\n/**\n * Proxy a queue message to track ack/retry operations\n */\nfunction proxyQueueMessage<Q>(msg: Message<Q>, count: MessageStatusCount): Message<Q> {\n const msgHandler: ProxyHandler<Message<Q>> = {\n get: (target, prop) => {\n if (prop === 'ack') {\n const ackFn = Reflect.get(target, prop);\n return new Proxy(ackFn, {\n apply: (fnTarget) => {\n addQueueEvent('messageAck', msg);\n count.ack();\n Reflect.apply(fnTarget, msg, []);\n },\n });\n } else if (prop === 'retry') {\n const retryFn = Reflect.get(target, prop);\n return new Proxy(retryFn, {\n apply: (fnTarget, _thisArg, args) => {\n // Extract delay and content type from retry options if provided\n const retryOptions = args[0] as\n | { delaySeconds?: number; contentType?: string }\n | undefined;\n const delaySeconds = retryOptions?.delaySeconds;\n\n addQueueEvent('messageRetry', msg, delaySeconds);\n\n // Add content type attribute if provided\n if (retryOptions?.contentType) {\n const span = trace.getActiveSpan();\n if (span) {\n span.setAttribute('queue.message.content_type', retryOptions.contentType);\n }\n }\n\n count.retry();\n const result = Reflect.apply(fnTarget, msg, args);\n return result;\n },\n });\n } else {\n return Reflect.get(target, prop, msg);\n }\n },\n };\n return wrap(msg, msgHandler);\n}\n\n/**\n * Proxy MessageBatch to track ackAll/retryAll operations\n */\nfunction proxyMessageBatch(batch: MessageBatch, count: MessageStatusCount): MessageBatch {\n const batchHandler: ProxyHandler<MessageBatch> = {\n get: (target, prop) => {\n if (prop === 'messages') {\n const messages = Reflect.get(target, prop);\n const messagesHandler: ProxyHandler<MessageBatch['messages']> = {\n get: (target, prop) => {\n if (typeof prop === 'string' && !isNaN(parseInt(prop))) {\n const message = Reflect.get(target, prop);\n return proxyQueueMessage(message, count);\n } else {\n return Reflect.get(target, prop);\n }\n },\n };\n return wrap(messages, messagesHandler);\n } else if (prop === 'ackAll') {\n const ackFn = Reflect.get(target, prop);\n return new Proxy(ackFn, {\n apply: (fnTarget) => {\n addQueueEvent('ackAll');\n count.ackRemaining();\n Reflect.apply(fnTarget, batch, []);\n },\n });\n } else if (prop === 'retryAll') {\n const retryFn = Reflect.get(target, prop);\n return new Proxy(retryFn, {\n apply: (fnTarget, _thisArg, args) => {\n // Extract delay from retryAll options if provided\n const retryOptions = args[0] as { delaySeconds?: number } | undefined;\n const delaySeconds = retryOptions?.delaySeconds;\n\n addQueueEvent('retryAll', undefined, delaySeconds);\n count.retryRemaining();\n Reflect.apply(fnTarget, batch, args);\n },\n });\n }\n return Reflect.get(target, prop);\n },\n };\n return wrap(batch, batchHandler);\n}\n\n/**\n * Queue handler instrumentation with message tracking\n */\nclass QueueInstrumentation implements HandlerInstrumentation<MessageBatch, void> {\n private count?: MessageStatusCount;\n\n getInitialSpanInfo(batch: MessageBatch): InitialSpanInfo {\n return {\n name: `queueHandler ${batch.queue || 'unknown'}`,\n options: {\n kind: SpanKind.CONSUMER,\n attributes: {\n 'faas.trigger': 'pubsub',\n 'queue.name': batch.queue || 'unknown',\n },\n },\n };\n }\n\n instrumentTrigger(batch: MessageBatch): MessageBatch {\n this.count = new MessageStatusCount(batch.messages.length);\n return proxyMessageBatch(batch, this.count);\n }\n\n executionSucces(span: Span, _trigger: MessageBatch, _result: void) {\n if (this.count) {\n this.count.ackRemaining();\n span.setAttributes(this.count.toAttributes());\n }\n }\n\n executionFailed(span: Span, _trigger: MessageBatch, _error?: any) {\n if (this.count) {\n this.count.retryRemaining();\n span.setAttributes(this.count.toAttributes());\n }\n }\n}\n\n/**\n * Converts email headers into OpenTelemetry attributes.\n * When dataSafety.emailHeaderAllowlist is configured, only allowed headers are captured.\n */\nfunction headerAttributes(message: { headers: Headers }): Record<string, string> {\n const attrs: Record<string, string> = {};\n if (message.headers instanceof Headers) {\n const config = getActiveConfig();\n const allowlist: string[] | undefined = config?.dataSafety?.emailHeaderAllowlist;\n for (const [key, value] of message.headers.entries()) {\n if (allowlist && !allowlist.includes(key.toLowerCase())) {\n continue;\n }\n attrs[`email.header.${key}`] = value;\n }\n }\n return attrs;\n}\n\n/**\n * Email handler instrumentation\n */\nconst emailInstrumentation: HandlerInstrumentation<ForwardableEmailMessage, void> = {\n getInitialSpanInfo: (message: ForwardableEmailMessage): InitialSpanInfo => {\n const attributes: Record<string, string> = {\n 'faas.trigger': 'other',\n 'messaging.destination.name': message.to || 'unknown',\n };\n\n // Add message ID if available\n if ('headers' in message && message.headers instanceof Headers) {\n const messageId = message.headers.get('Message-Id');\n if (messageId) {\n attributes['rpc.message.id'] = messageId;\n }\n // Add all headers as attributes\n Object.assign(attributes, headerAttributes(message));\n }\n\n return {\n name: `emailHandler ${message.to || 'unknown'}`,\n options: {\n kind: SpanKind.CONSUMER,\n attributes,\n },\n };\n },\n};\n\n\n/**\n * Export spans after request completes\n */\nasync function exportSpans(\n traceId: string,\n tracker: PromiseTracker | undefined,\n ctx: ExecutionContext,\n) {\n const tracer = trace.getTracer('autotel-edge');\n if (tracer instanceof WorkerTracer) {\n try {\n // scheduler is available on ExecutionContext at runtime\n const ctxWithScheduler = ctx as ExecutionContext & { scheduler?: { wait(ms: number): Promise<void> } };\n if (ctxWithScheduler.scheduler) {\n await ctxWithScheduler.scheduler.wait(1);\n }\n await tracker?.wait();\n await tracer.forceFlush(traceId);\n } catch (error) {\n // Silently handle exporter errors to prevent worker crashes\n // Exporter failures should not affect the worker's ability to process requests\n // In production, consider logging to a monitoring service\n console.error('[autotel-edge] Failed to export spans:', error);\n }\n }\n}\n\n/**\n * Create handler flow with instrumentation\n */\nfunction createHandlerFlow<T extends Trigger, E, R>(\n instrumentation: HandlerInstrumentation<T, R>,\n) {\n return (\n handlerFn: (trigger: T, env: E, ctx: ExecutionContext) => R | Promise<R>,\n [trigger, env, context]: [T, E, ExecutionContext],\n ) => {\n const { ctx: proxiedCtx, tracker } = proxyExecutionContext(context);\n\n const tracer = trace.getTracer('autotel-edge') as WorkerTracer;\n\n const { name, options, context: spanContext } =\n instrumentation.getInitialSpanInfo(trigger);\n\n // Add cold start tracking\n if (options.attributes) {\n options.attributes['faas.coldstart'] = coldStart;\n } else {\n options.attributes = { 'faas.coldstart': coldStart };\n }\n coldStart = false;\n\n const parentContext = spanContext || api_context.active();\n\n // Instrument trigger if supported (e.g., for queue handler)\n const instrumentedTrigger = instrumentation.instrumentTrigger\n ? instrumentation.instrumentTrigger(trigger)\n : trigger;\n\n return tracer.startActiveSpan(name, options, parentContext, async (span) => {\n try {\n const result = await handlerFn(instrumentedTrigger, env, proxiedCtx);\n\n if (instrumentation.getAttributesFromResult) {\n const attributes = instrumentation.getAttributesFromResult(result);\n span.setAttributes(attributes);\n }\n\n // Set default OK status; executionSucces may override (e.g. HTTP 5xx)\n span.setStatus({ code: SpanStatusCode.OK });\n\n if (instrumentation.executionSucces) {\n instrumentation.executionSucces(span, trigger, result);\n }\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 if (instrumentation.executionFailed) {\n instrumentation.executionFailed(span, trigger, error);\n }\n throw error;\n } finally {\n span.end();\n context.waitUntil(exportSpans(span.spanContext().traceId, tracker, context));\n }\n });\n };\n}\n\n/**\n * Create handler proxy\n */\nfunction createHandlerProxy<T extends Trigger, E, R>(\n _handler: unknown,\n handlerFn: (trigger: T, env: E, ctx: ExecutionContext) => R | Promise<R>,\n initialiser: Initialiser,\n instrumentation: HandlerInstrumentation<T, R>,\n): (trigger: T, env: E, ctx: ExecutionContext) => ReturnType<typeof handlerFn> {\n return (trigger: T, env: E, ctx: ExecutionContext) => {\n const config = initialiser(env, trigger);\n \n // Check if instrumentation is disabled (useful for local dev)\n if (config.instrumentation.disabled) {\n // Return handler as-is without instrumentation\n return handlerFn(trigger, env, ctx);\n }\n \n // Auto-instrument Cloudflare bindings in the environment\n const instrumentedEnv = instrumentBindings(env as Record<string, any>) as E;\n \n const configContext = setConfig(config);\n\n // Initialize provider on first call\n initProvider(config);\n\n const flowFn = createHandlerFlow<T, E, R>(instrumentation);\n\n // Execute the handler flow within the config context\n return api_context.with(configContext, () => {\n return flowFn(handlerFn, [trigger, instrumentedEnv, ctx]) as ReturnType<typeof handlerFn>;\n });\n };\n}\n\n/**\n * Create handler proxy with dynamic instrumentation (for fetch with postProcess)\n */\nfunction createHandlerProxyWithConfig<T extends Trigger, E, R>(\n _handler: unknown,\n handlerFn: (trigger: T, env: E, ctx: ExecutionContext) => R | Promise<R>,\n initialiser: Initialiser,\n createInstrumentation: (config: ResolvedEdgeConfig) => HandlerInstrumentation<T, R>,\n): (trigger: T, env: E, ctx: ExecutionContext) => ReturnType<typeof handlerFn> {\n return (trigger: T, env: E, ctx: ExecutionContext) => {\n const config = initialiser(env, trigger);\n \n // Check if instrumentation is disabled (useful for local dev)\n if (config.instrumentation.disabled) {\n // Return handler as-is without instrumentation\n return handlerFn(trigger, env, ctx);\n }\n \n // Auto-instrument Cloudflare bindings in the environment\n const instrumentedEnv = instrumentBindings(env as Record<string, any>) as E;\n \n const configContext = setConfig(config);\n\n // Initialize provider on first call\n initProvider(config);\n\n // Create instrumentation with config\n const instrumentation = createInstrumentation(config);\n const flowFn = createHandlerFlow<T, E, R>(instrumentation);\n\n // Execute the handler flow within the config context\n return api_context.with(configContext, () => {\n return flowFn(handlerFn, [trigger, instrumentedEnv, ctx]) as ReturnType<typeof handlerFn>;\n });\n };\n}\n\nlet providerInitialized = false;\nlet coldStart = true;\n\n/**\n * Initialize the tracer provider\n */\nfunction initProvider(config: ResolvedEdgeConfig): void {\n if (providerInitialized) return;\n\n // Install global instrumentations\n if (config.instrumentation.instrumentGlobalFetch) {\n instrumentGlobalFetch();\n }\n if (config.instrumentation.instrumentGlobalCache) {\n instrumentGlobalCache();\n }\n\n // Set up propagator\n propagation.setGlobalPropagator(config.propagator);\n\n // Create resource\n const resource = resourceFromAttributes({\n 'service.name': config.service.name,\n 'service.version': config.service.version,\n 'service.namespace': config.service.namespace,\n 'cloud.provider': 'cloudflare',\n 'cloud.platform': 'cloudflare.workers',\n 'telemetry.sdk.name': 'autotel-edge',\n 'telemetry.sdk.language': 'js',\n });\n\n // Create and register provider\n const provider = new WorkerTracerProvider(config.spanProcessors, resource);\n provider.register();\n\n // Set head sampler on tracer\n const tracer = trace.getTracer('autotel-edge') as WorkerTracer;\n tracer.setHeadSampler(config.sampling.headSampler);\n\n providerInitialized = true;\n}\n\n/**\n * Instrument a Cloudflare Workers handler\n *\n * @example\n * ```typescript\n * import { instrument } from 'autotel-edge'\n *\n * const handler = {\n * async fetch(request, env, ctx) {\n * return new Response('Hello World')\n * }\n * }\n *\n * export default instrument(handler, {\n * exporter: {\n * url: env.OTLP_ENDPOINT,\n * headers: { 'x-api-key': env.API_KEY }\n * },\n * service: { name: 'my-worker' }\n * })\n * ```\n */\nexport function instrument<E, Q = any, C = any>(\n handler: ExportedHandler<E, Q, C>,\n config: ConfigurationOption,\n): ExportedHandler<E, Q, C> {\n const initialiser = createInitialiser(config);\n\n if (handler.fetch) {\n const fetcher = unwrap(handler.fetch) as FetchHandler;\n // Create fetch instrumentation with config support\n handler.fetch = createHandlerProxyWithConfig(\n handler,\n fetcher,\n initialiser,\n createFetchInstrumentation,\n );\n }\n\n if (handler.scheduled) {\n const scheduled = unwrap(handler.scheduled) as ScheduledHandler;\n handler.scheduled = createHandlerProxy(\n handler,\n scheduled,\n initialiser,\n scheduledInstrumentation,\n );\n }\n\n if (handler.queue) {\n const queue = unwrap(handler.queue) as QueueHandler;\n handler.queue = createHandlerProxy(\n handler,\n queue,\n initialiser,\n new QueueInstrumentation(),\n );\n }\n\n if (handler.email) {\n const email = unwrap(handler.email) as EmailHandler;\n handler.email = createHandlerProxy(\n handler,\n email,\n initialiser,\n emailInstrumentation,\n );\n }\n\n return handler;\n}\n","/**\n * workers-honeycomb-logger style wrapper API\n *\n * @example\n * ```typescript\n * import { wrapModule } from 'autotel-cloudflare'\n *\n * const handler = {\n * async fetch(req, env, ctx) {\n * return new Response('Hello')\n * }\n * }\n *\n * export default wrapModule(\n * { service: { name: 'my-worker' } },\n * handler\n * )\n * ```\n */\n\nimport { instrument } from './instrument';\nimport type { ConfigurationOption } from 'autotel-edge';\n\n/**\n * Wrap a Cloudflare Workers module-style handler\n * Alternative API style inspired by workers-honeycomb-logger\n *\n * @param config Configuration (can be static object or function)\n * @param handler The worker handler to wrap\n * @returns Instrumented handler\n */\nexport function wrapModule<E, Q = any, C = any>(\n config: ConfigurationOption,\n handler: ExportedHandler<E, Q, C>,\n): ExportedHandler<E, Q, C> {\n return instrument(handler, config);\n}\n","/**\n * Durable Object wrapper\n *\n * @example\n * ```typescript\n * import { wrapDurableObject } from 'autotel-cloudflare'\n *\n * class Counter implements DurableObject {\n * async fetch(request: Request) {\n * return new Response('count')\n * }\n * }\n *\n * export default wrapDurableObject({ service: { name: 'counter-do' } }, Counter)\n * ```\n */\n\nimport { instrumentDO } from '../handlers/durable-objects';\nimport type { ConfigurationOption } from 'autotel-edge';\n\n/**\n * Wrap a Durable Object class with instrumentation\n * Alternative API style inspired by workers-honeycomb-logger\n *\n * @param config Configuration (can be static object or function)\n * @param doClass The Durable Object class to wrap\n * @returns Instrumented Durable Object class\n */\nexport function wrapDurableObject<T extends DurableObject>(\n config: ConfigurationOption,\n doClass: new (state: DurableObjectState, env: any) => T,\n): new (state: DurableObjectState, env: any) => T {\n return instrumentDO(doClass, config);\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/global/fetch.ts","../src/global/cache.ts","../src/wrappers/instrument.ts","../src/wrappers/wrap-module.ts","../src/wrappers/wrap-do.ts"],"names":["api_context","trace","SpanKind","SpanStatusCode","propagation","target","prop","getActiveConfig","WorkerTracer","context"],"mappings":";;;;;;;;;;;AAsBA,SAAS,wBAAwB,OAAA,EAAuC;AACtE,EAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,OAAA,CAAQ,GAAG,CAAA;AAC/B,EAAA,MAAM,SAAS,eAAA,EAAgB;AAC/B,EAAA,MAAM,WAAA,GAAc,MAAA,EAAQ,UAAA,EAAY,iBAAA,KAAsB,IAAA;AAE9D,EAAA,OAAO;AAAA,IACL,qBAAA,EAAuB,OAAA,CAAQ,MAAA,CAAO,WAAA,EAAY;AAAA,IAClD,UAAA,EAAY,cAAc,CAAA,EAAG,GAAA,CAAI,MAAM,CAAA,EAAG,GAAA,CAAI,QAAQ,CAAA,CAAA,GAAK,OAAA,CAAQ,GAAA;AAAA,IACnE,YAAA,EAAc,GAAA,CAAI,QAAA,CAAS,OAAA,CAAQ,KAAK,EAAE,CAAA;AAAA,IAC1C,kBAAkB,GAAA,CAAI,IAAA;AAAA,IACtB,YAAY,GAAA,CAAI,QAAA;AAAA,IAChB,aAAa,WAAA,GAAe,GAAA,CAAI,MAAA,GAAS,YAAA,GAAe,KAAM,GAAA,CAAI,MAAA;AAAA,IAClE,uBAAA,EAAyB,MAAA;AAAA,IACzB,qBAAA,EAAuB,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,YAAY,CAAA,IAAK;AAAA,GAC9D;AACF;AAKA,SAAS,yBAAyB,QAAA,EAAyC;AACzE,EAAA,OAAO;AAAA,IACL,6BAA6B,QAAA,CAAS,MAAA;AAAA,IACtC,yBAAA,EAA2B,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,gBAAgB,CAAA,IAAK;AAAA,GACvE;AACF;AAUO,SAAS,qBAAA,GAA8B;AAC5C,EAAA,MAAM,gBAAgB,UAAA,CAAW,KAAA;AAEjC,EAAA,MAAM,iBAAA,GAAoB,SAAS,KAAA,CACjC,KAAA,EACA,IAAA,EACmB;AACnB,IAAA,MAAM,OAAA,GAAU,IAAI,OAAA,CAAQ,KAAA,EAAO,IAAI,CAAA;AAGvC,IAAA,IAAI,CAAC,OAAA,CAAQ,GAAA,CAAI,UAAA,CAAW,MAAM,CAAA,EAAG;AACnC,MAAA,OAAO,aAAA,CAAc,OAAO,IAAI,CAAA;AAAA,IAClC;AAGA,IAAA,MAAM,SAAS,eAAA,EAAgB;AAC/B,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,OAAO,aAAA,CAAc,OAAO,IAAI,CAAA;AAAA,IAClC;AAEA,IAAA,MAAM,MAAA,GAAS,KAAA,CAAM,SAAA,CAAU,cAAc,CAAA;AAC7C,IAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,OAAA,CAAQ,GAAG,CAAA;AAC/B,IAAA,MAAM,WAAW,CAAA,EAAG,OAAA,CAAQ,MAAM,CAAA,CAAA,EAAI,IAAI,IAAI,CAAA,CAAA;AAE9C,IAAA,OAAO,MAAA,CAAO,eAAA;AAAA,MACZ,QAAA;AAAA,MACA;AAAA,QACE,MAAM,QAAA,CAAS,MAAA;AAAA,QACf,UAAA,EAAY,wBAAwB,OAAO;AAAA,OAC7C;AAAA,MACA,OAAO,IAAA,KAAS;AACd,QAAA,IAAI;AAEF,UAAA,MAAM,oBAAA,GACJ,OAAO,MAAA,CAAO,KAAA,EAAO,mBAAA,KAAwB,UAAA,GACzC,MAAA,CAAO,KAAA,CAAM,mBAAA,CAAoB,OAAO,CAAA,GACvC,MAAA,CAAO,OAAO,mBAAA,IAAuB,IAAA;AAE5C,UAAA,IAAI,oBAAA,EAAsB;AACxB,YAAA,WAAA,CAAY,MAAA,CAAOA,OAAA,CAAY,MAAA,EAAO,EAAG,QAAQ,OAAA,EAAS;AAAA,cACxD,GAAA,EAAK,CAAC,OAAA,EAAS,GAAA,EAAK,KAAA,KAAU;AAC5B,gBAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,kBAAA,OAAA,CAAQ,GAAA,CAAI,KAAK,KAAK,CAAA;AAAA,gBACxB;AAAA,cACF;AAAA,aACD,CAAA;AAAA,UACH;AAGA,UAAA,MAAM,QAAA,GAAW,MAAM,aAAA,CAAc,OAAO,CAAA;AAG5C,UAAA,IAAA,CAAK,aAAA,CAAc,wBAAA,CAAyB,QAAQ,CAAC,CAAA;AAGrD,UAAA,IAAI,SAAS,EAAA,EAAI;AACf,YAAA,IAAA,CAAK,SAAA,CAAU,EAAE,IAAA,EAAM,cAAA,CAAe,IAAI,CAAA;AAAA,UAC5C,CAAA,MAAO;AACL,YAAA,IAAA,CAAK,SAAA,CAAU,EAAE,IAAA,EAAM,cAAA,CAAe,OAAO,CAAA;AAAA,UAC/C;AAEA,UAAA,OAAO,QAAA;AAAA,QACT,SAAS,KAAA,EAAO;AACd,UAAA,IAAA,CAAK,gBAAgB,KAAc,CAAA;AACnC,UAAA,IAAA,CAAK,SAAA,CAAU;AAAA,YACb,MAAM,cAAA,CAAe,KAAA;AAAA,YACrB,SAAS,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK;AAAA,WAC/D,CAAA;AACD,UAAA,MAAM,KAAA;AAAA,QACR,CAAA,SAAE;AACA,UAAA,IAAA,CAAK,GAAA,EAAI;AAAA,QACX;AAAA,MACF;AAAA,KACF;AAAA,EACF,CAAA;AAGA,EAAA,UAAA,CAAW,KAAA,GAAQ,iBAAA;AACrB;ACrHA,SAAS,YAAY,GAAA,EAAqB;AACxC,EAAA,MAAM,CAAA,GAAI,IAAI,GAAA,CAAI,GAAG,CAAA;AACrB,EAAA,OAAO,CAAA,EAAG,EAAE,QAAQ,CAAA,EAAA,EAAK,EAAE,IAAI,CAAA,EAAG,EAAE,QAAQ,CAAA,CAAA;AAC9C;AAKA,SAAS,qBAAA,CACP,EAAA,EACA,SAAA,EACA,SAAA,EACG;AACH,EAAA,MAAM,OAAA,GAA2B;AAAA,IAC/B,MAAM,KAAA,CAAM,MAAA,EAAQ,OAAA,EAAS,QAAA,EAAU;AACrC,MAAA,MAAM,MAAA,GAASC,KAAAA,CAAM,SAAA,CAAU,cAAc,CAAA;AAG7C,MAAA,MAAM,QAAA,GAAW,SAAS,CAAC,CAAA;AAC3B,MAAA,MAAM,GAAA,GACJ,oBAAoB,OAAA,GAChB,QAAA,CAAS,MACT,OAAO,QAAA,KAAa,WAClB,QAAA,GACA,MAAA;AAER,MAAA,MAAM,QAAA,GAAW,CAAA,MAAA,EAAS,SAAS,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA;AAEhD,MAAA,OAAO,MAAA,CAAO,eAAA;AAAA,QACZ,QAAA;AAAA,QACA;AAAA,UACE,MAAMC,QAAAA,CAAS,MAAA;AAAA,UACf,UAAA,EAAY;AAAA,YACV,YAAA,EAAc,SAAA;AAAA,YACd,iBAAA,EAAmB,SAAA;AAAA,YACnB,WAAA,EAAa,GAAA,GAAM,WAAA,CAAY,GAAG,CAAA,GAAI;AAAA;AACxC,SACF;AAAA,QACA,OAAO,IAAA,KAAS;AACd,UAAA,IAAI;AACF,YAAA,MAAM,SAAS,MAAM,OAAA,CAAQ,KAAA,CAAM,MAAA,EAAQ,SAAS,QAAQ,CAAA;AAG5D,YAAA,IAAI,cAAc,OAAA,EAAS;AACzB,cAAA,IAAA,CAAK,YAAA,CAAa,WAAA,EAAa,CAAC,CAAC,MAAM,CAAA;AAAA,YACzC;AAEA,YAAA,IAAA,CAAK,SAAA,CAAU,EAAE,IAAA,EAAMC,cAAAA,CAAe,IAAI,CAAA;AAC1C,YAAA,OAAO,MAAA;AAAA,UACT,SAAS,KAAA,EAAO;AACd,YAAA,IAAA,CAAK,gBAAgB,KAAc,CAAA;AACnC,YAAA,IAAA,CAAK,SAAA,CAAU;AAAA,cACb,MAAMA,cAAAA,CAAe,KAAA;AAAA,cACrB,SAAS,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK;AAAA,aAC/D,CAAA;AACD,YAAA,MAAM,KAAA;AAAA,UACR,CAAA,SAAE;AACA,YAAA,IAAA,CAAK,GAAA,EAAI;AAAA,UACX;AAAA,QACF;AAAA,OACF;AAAA,IACF;AAAA,GACF;AAEA,EAAA,OAAO,IAAA,CAAK,IAAI,OAAO,CAAA;AACzB;AAKA,SAAS,eAAA,CAAgB,OAAc,SAAA,EAA0B;AAC/D,EAAA,MAAM,OAAA,GAA+B;AAAA,IACnC,GAAA,CAAI,QAAQ,IAAA,EAAM;AAChB,MAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,GAAA,CAAI,MAAA,EAAQ,IAAI,CAAA;AAGtC,MAAA,IAAA,CACG,IAAA,KAAS,WAAW,IAAA,KAAS,KAAA,IAAS,SAAS,QAAA,KAChD,OAAO,UAAU,UAAA,EACjB;AACA,QAAA,OAAO,qBAAA;AAAA,UACL,KAAA,CAAM,KAAK,MAAM,CAAA;AAAA,UACjB,SAAA;AAAA,UACA;AAAA,SACF;AAAA,MACF;AAGA,MAAA,IAAI,OAAO,UAAU,UAAA,EAAY;AAC/B,QAAA,OAAO,KAAA,CAAM,KAAK,MAAM,CAAA;AAAA,MAC1B;AAEA,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,GACF;AAEA,EAAA,OAAO,IAAA,CAAK,OAAO,OAAO,CAAA;AAC5B;AAKA,SAAS,qBACP,MAAA,EACsB;AACtB,EAAA,MAAM,OAAA,GAA8C;AAAA,IAClD,MAAM,KAAA,CAAM,MAAA,EAAQ,OAAA,EAAS,QAAA,EAAU;AACrC,MAAA,MAAM,SAAA,GAAY,SAAS,CAAC,CAAA;AAC5B,MAAA,MAAM,QAAQ,MAAM,OAAA,CAAQ,KAAA,CAAM,MAAA,EAAQ,SAAS,QAAQ,CAAA;AAC3D,MAAA,OAAO,eAAA,CAAgB,OAAO,SAAS,CAAA;AAAA,IACzC;AAAA,GACF;AAEA,EAAA,OAAO,IAAA,CAAK,QAAQ,OAAO,CAAA;AAC7B;AAUO,SAAS,qBAAA,GAA8B;AAC5C,EAAA,MAAM,OAAA,GAAuC;AAAA,IAC3C,GAAA,CAAI,QAAQ,IAAA,EAAM;AAChB,MAAA,IAAI,SAAS,SAAA,EAAW;AAEtB,QAAA,OAAO,eAAA,CAAgB,MAAA,CAAO,OAAA,EAAS,SAAS,CAAA;AAAA,MAClD,CAAA,MAAA,IAAW,SAAS,MAAA,EAAQ;AAE1B,QAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,GAAA,CAAI,MAAA,EAAQ,IAAI,CAAA;AACvC,QAAA,IAAI,OAAO,WAAW,UAAA,EAAY;AAChC,UAAA,OAAO,oBAAA,CAAqB,MAAA,CAAO,IAAA,CAAK,MAAM,CAAC,CAAA;AAAA,QACjD;AAAA,MACF;AAEA,MAAA,OAAO,OAAA,CAAQ,GAAA,CAAI,MAAA,EAAQ,IAAI,CAAA;AAAA,IACjC;AAAA,GACF;AAIA,EAAA,UAAA,CAAW,MAAA,GAAS,IAAA,CAAK,MAAA,EAAQ,OAAO,CAAA;AAC1C;;;ACvFA,SAAS,cAAA,CAAe,MAAc,OAAA,EAA0B;AAC9D,EAAA,MAAM,YAAA,GAAe,QAClB,UAAA,CAAW,mBAAA,EAAqB,OAAO,GAAA,CAAA,GAAA,CAAQ,CAAA,CAC/C,WAAW,IAAA,EAAM,cAAc,EAC/B,UAAA,CAAW,GAAA,EAAK,OAAO,CAAA,CACvB,UAAA,CAAW,gBAAgB,IAAI,CAAA,CAC/B,UAAA,CAAW,GAAA,EAAK,MAAM,CAAA;AACzB,EAAA,OAAO,IAAI,MAAA,CAAO,CAAA,CAAA,EAAI,YAAY,CAAA,CAAA,CAAG,CAAA,CAAE,KAAK,IAAI,CAAA;AAClD;AAEA,SAAS,oBAAA,CACP,IAAA,EACA,OAAA,EACA,OAAA,EACS;AACT,EAAA,IAAI,OAAA,IAAW,QAAQ,IAAA,CAAK,CAAC,YAAY,cAAA,CAAe,IAAA,EAAM,OAAO,CAAC,CAAA,EAAG;AACvE,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,IAAI,CAAC,OAAA,IAAW,OAAA,CAAQ,MAAA,KAAW,CAAA,EAAG;AACpC,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,OAAO,QAAQ,IAAA,CAAK,CAAC,YAAY,cAAA,CAAe,IAAA,EAAM,OAAO,CAAC,CAAA;AAChE;AAEA,SAAS,iBAAA,CACP,MACA,MAAA,EACoB;AACpB,EAAA,IAAI,CAAC,QAAQ,OAAO,MAAA;AACpB,EAAA,KAAA,MAAW,CAAC,OAAA,EAAS,MAAM,KAAK,MAAA,CAAO,OAAA,CAAQ,MAAM,CAAA,EAAG;AACtD,IAAA,IAAI,cAAA,CAAe,IAAA,EAAM,OAAO,CAAA,EAAG;AACjC,MAAA,OAAO,MAAA,CAAO,OAAA;AAAA,IAChB;AAAA,EACF;AACA,EAAA,OAAO,MAAA;AACT;AAQA,SAAS,oBAAoB,OAAA,EAA6D;AACxF,EAAA,MAAM,KAAM,OAAA,CAAgB,EAAA;AAC5B,EAAA,IAAI,CAAC,EAAA,EAAI,OAAO,EAAC;AAEjB,EAAA,MAAM,QAAmD,EAAC;AAC1D,EAAA,MAAM,GAAA,GAAM,CAAC,GAAA,EAAa,KAAA,KAAmB;AAC3C,IAAA,IAAI,KAAA,KAAU,MAAA,IAAa,KAAA,KAAU,IAAA,EAAM;AACzC,MAAA,KAAA,CAAM,GAAG,CAAA,GAAI,KAAA;AAAA,IACf;AAAA,EACF,CAAA;AAEA,EAAA,GAAA,CAAI,iBAAA,EAAmB,GAAG,IAAI,CAAA;AAC9B,EAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,QAAQ,CAAA;AACxC,EAAA,IAAI,GAAA,EAAK,KAAA,CAAM,mBAAmB,CAAA,GAAI,GAAA;AACtC,EAAA,GAAA,CAAI,oBAAA,EAAsB,GAAG,OAAO,CAAA;AACpC,EAAA,GAAA,CAAI,iBAAA,EAAmB,GAAG,IAAI,CAAA;AAC9B,EAAA,GAAA,CAAI,mBAAA,EAAqB,GAAG,MAAM,CAAA;AAClC,EAAA,GAAA,CAAI,sBAAA,EAAwB,GAAG,SAAS,CAAA;AACxC,EAAA,GAAA,CAAI,qBAAA,EAAuB,GAAG,QAAQ,CAAA;AACtC,EAAA,GAAA,CAAI,qBAAA,EAAuB,GAAG,QAAQ,CAAA;AACtC,EAAA,GAAA,CAAI,sBAAA,EAAwB,GAAG,SAAS,CAAA;AACxC,EAAA,GAAA,CAAI,gBAAA,EAAkB,GAAG,GAAG,CAAA;AAC5B,EAAA,GAAA,CAAI,4BAAA,EAA8B,GAAG,cAAc,CAAA;AACnD,EAAA,GAAA,CAAI,0BAAA,EAA4B,GAAG,YAAY,CAAA;AAC/C,EAAA,GAAA,CAAI,wBAAA,EAA0B,GAAG,UAAU,CAAA;AAC3C,EAAA,GAAA,CAAI,2BAAA,EAA6B,GAAG,YAAY,CAAA;AAEhD,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,2BACP,MAAA,EAC2C;AAC3C,EAAA,OAAO;AAAA,IACL,kBAAA,EAAoB,CAAC,OAAA,KAAsC;AACzD,MAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,OAAA,CAAQ,GAAG,CAAA;AAC/B,MAAA,MAAM,YAAA,GAAe,iBAAA;AAAA,QACnB,GAAA,CAAI,QAAA;AAAA,QACJ,MAAA,CAAO,SAAS,KAAA,CAAM;AAAA,OACxB;AAEA,MAAA,MAAM,UAAW,MAAA,CAAe,mBAAA,KAAwB,QACpD,EAAC,GACD,oBAAoB,OAAO,CAAA;AAE/B,MAAA,OAAO;AAAA,QACL,MAAM,CAAA,EAAG,OAAA,CAAQ,MAAM,CAAA,CAAA,EAAI,IAAI,QAAQ,CAAA,CAAA;AAAA,QACvC,OAAA,EAAS;AAAA,UACP,MAAMD,QAAAA,CAAS,MAAA;AAAA,UACf,UAAA,EAAY;AAAA,YACV,uBAAuB,OAAA,CAAQ,MAAA;AAAA,YAC/B,YAAY,OAAA,CAAQ,GAAA;AAAA,YACpB,GAAI,eAAe,EAAE,cAAA,EAAgB,cAAc,uBAAA,EAAyB,YAAA,KAAiB,EAAC;AAAA,YAC9F,GAAG;AAAA;AACL,SACF;AAAA,QACA,SAASE,WAAAA,CAAY,OAAA,CAAQJ,QAAY,MAAA,EAAO,EAAG,QAAQ,OAAO;AAAA,OACpE;AAAA,IACF,CAAA;AAAA,IACA,uBAAA,EAAyB,CAAC,QAAA,MAAwB;AAAA,MAChD,6BAA6B,QAAA,CAAS;AAAA,KACxC,CAAA;AAAA,IACA,eAAA,EAAiB,CAAC,IAAA,EAAY,OAAA,EAAkB,MAAA,KAAqB;AAEnE,MAAA,IAAI,MAAA,CAAO,UAAU,GAAA,EAAK;AACxB,QAAA,IAAA,CAAK,SAAA,CAAU,EAAE,IAAA,EAAMG,cAAAA,CAAe,OAAO,CAAA;AAAA,MAC/C;AAGA,MAAA,IAAI,MAAA,CAAO,QAAA,CAAS,KAAA,CAAM,WAAA,EAAa;AACrC,QAAA,MAAM,YAAA,GAAe,IAAA;AACrB,QAAA,MAAA,CAAO,QAAA,CAAS,KAAA,CAAM,WAAA,CAAY,IAAA,EAAM;AAAA,UACtC,OAAA,EAAS,OAAA;AAAA,UACT,QAAA,EAAU,MAAA;AAAA,UACV,QAAA,EAAU;AAAA,SACX,CAAA;AAAA,MACH;AAAA,IACF;AAAA,GACF;AACF;AAKA,IAAM,wBAAA,GAA8E;AAAA,EAClF,kBAAA,EAAoB,CAAC,KAAA,KAAgD;AACnE,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,CAAA,iBAAA,EAAoB,KAAA,CAAM,IAAA,IAAQ,SAAS,CAAA,CAAA;AAAA,MACjD,OAAA,EAAS;AAAA,QACP,MAAMD,QAAAA,CAAS,QAAA;AAAA,QACf,UAAA,EAAY;AAAA,UACV,cAAA,EAAgB,OAAA;AAAA,UAChB,WAAA,EAAa,MAAM,IAAA,IAAQ,SAAA;AAAA,UAC3B,uBAAuB,IAAI,IAAA,CAAK,KAAA,CAAM,aAAa,EAAE,WAAA;AAAY;AACnE;AACF,KACF;AAAA,EACF;AACF,CAAA;AAKA,IAAM,qBAAN,MAAyB;AAAA,EACvB,SAAA,GAAY,CAAA;AAAA,EACZ,MAAA,GAAS,CAAA;AAAA,EACT,gBAAA,GAAmB,CAAA;AAAA,EACnB,kBAAA,GAAqB,CAAA;AAAA,EACZ,KAAA;AAAA,EAET,YAAY,KAAA,EAAe;AACzB,IAAA,IAAA,CAAK,KAAA,GAAQ,KAAA;AAAA,EACf;AAAA,EAEA,GAAA,GAAM;AACJ,IAAA,IAAA,CAAK,SAAA,GAAY,KAAK,SAAA,GAAY,CAAA;AAAA,EACpC;AAAA,EAEA,YAAA,GAAe;AACb,IAAA,IAAA,CAAK,gBAAA,GAAmB,IAAA,CAAK,KAAA,GAAQ,IAAA,CAAK,YAAY,IAAA,CAAK,MAAA;AAC3D,IAAA,IAAA,CAAK,SAAA,GAAY,IAAA,CAAK,KAAA,GAAQ,IAAA,CAAK,MAAA;AAAA,EACrC;AAAA,EAEA,KAAA,GAAQ;AACN,IAAA,IAAA,CAAK,MAAA,GAAS,KAAK,MAAA,GAAS,CAAA;AAAA,EAC9B;AAAA,EAEA,cAAA,GAAiB;AACf,IAAA,IAAA,CAAK,kBAAA,GAAqB,IAAA,CAAK,KAAA,GAAQ,IAAA,CAAK,YAAY,IAAA,CAAK,MAAA;AAC7D,IAAA,IAAA,CAAK,MAAA,GAAS,IAAA,CAAK,KAAA,GAAQ,IAAA,CAAK,SAAA;AAAA,EAClC;AAAA,EAEA,YAAA,GAA2B;AACzB,IAAA,OAAO;AAAA,MACL,wBAAwB,IAAA,CAAK,KAAA;AAAA,MAC7B,0BAA0B,IAAA,CAAK,SAAA;AAAA,MAC/B,yBAAyB,IAAA,CAAK,MAAA;AAAA,MAC9B,qBAAA,EAAuB,IAAA,CAAK,SAAA,KAAc,IAAA,CAAK,KAAA;AAAA,MAC/C,0BAA0B,IAAA,CAAK,gBAAA;AAAA,MAC/B,4BAA4B,IAAA,CAAK;AAAA,KACnC;AAAA,EACF;AACF,CAAA;AAKA,SAAS,aAAA,CAAc,IAAA,EAAc,GAAA,EAAe,YAAA,EAAuB;AACzE,EAAA,MAAM,QAAoB,EAAC;AAC3B,EAAA,IAAI,GAAA,EAAK;AACP,IAAA,KAAA,CAAM,kBAAkB,IAAI,GAAA,CAAI,EAAA;AAChC,IAAA,KAAA,CAAM,yBAAyB,CAAA,GAAI,GAAA,CAAI,SAAA,CAAU,WAAA,EAAY;AAE7D,IAAA,IAAI,UAAA,IAAc,GAAA,IAAO,OAAO,GAAA,CAAI,aAAa,QAAA,EAAU;AACzD,MAAA,KAAA,CAAM,wBAAwB,IAAI,GAAA,CAAI,QAAA;AAAA,IACxC;AAAA,EACF;AACA,EAAA,IAAI,iBAAiB,MAAA,EAAW;AAC9B,IAAA,KAAA,CAAM,2BAA2B,CAAA,GAAI,YAAA;AAAA,EACvC;AACA,EAAAD,KAAAA,CAAM,aAAA,EAAc,EAAG,QAAA,CAAS,MAAM,KAAK,CAAA;AAC7C;AAKA,SAAS,iBAAA,CAAqB,KAAiB,KAAA,EAAuC;AACpF,EAAA,MAAM,UAAA,GAAuC;AAAA,IAC3C,GAAA,EAAK,CAAC,MAAA,EAAQ,IAAA,KAAS;AACrB,MAAA,IAAI,SAAS,KAAA,EAAO;AAClB,QAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,GAAA,CAAI,MAAA,EAAQ,IAAI,CAAA;AACtC,QAAA,OAAO,IAAI,MAAM,KAAA,EAAO;AAAA,UACtB,KAAA,EAAO,CAAC,QAAA,KAAa;AACnB,YAAA,aAAA,CAAc,cAAc,GAAG,CAAA;AAC/B,YAAA,KAAA,CAAM,GAAA,EAAI;AACV,YAAA,OAAA,CAAQ,KAAA,CAAM,QAAA,EAAU,GAAA,EAAK,EAAE,CAAA;AAAA,UACjC;AAAA,SACD,CAAA;AAAA,MACH,CAAA,MAAA,IAAW,SAAS,OAAA,EAAS;AAC3B,QAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,GAAA,CAAI,MAAA,EAAQ,IAAI,CAAA;AACxC,QAAA,OAAO,IAAI,MAAM,OAAA,EAAS;AAAA,UACxB,KAAA,EAAO,CAAC,QAAA,EAAU,QAAA,EAAU,IAAA,KAAS;AAEnC,YAAA,MAAM,YAAA,GAAe,KAAK,CAAC,CAAA;AAG3B,YAAA,MAAM,eAAe,YAAA,EAAc,YAAA;AAEnC,YAAA,aAAA,CAAc,cAAA,EAAgB,KAAK,YAAY,CAAA;AAG/C,YAAA,IAAI,cAAc,WAAA,EAAa;AAC7B,cAAA,MAAM,IAAA,GAAOA,MAAM,aAAA,EAAc;AACjC,cAAA,IAAI,IAAA,EAAM;AACR,gBAAA,IAAA,CAAK,YAAA,CAAa,4BAAA,EAA8B,YAAA,CAAa,WAAW,CAAA;AAAA,cAC1E;AAAA,YACF;AAEA,YAAA,KAAA,CAAM,KAAA,EAAM;AACZ,YAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,KAAA,CAAM,QAAA,EAAU,KAAK,IAAI,CAAA;AAChD,YAAA,OAAO,MAAA;AAAA,UACT;AAAA,SACD,CAAA;AAAA,MACH,CAAA,MAAO;AACL,QAAA,OAAO,OAAA,CAAQ,GAAA,CAAI,MAAA,EAAQ,IAAA,EAAM,GAAG,CAAA;AAAA,MACtC;AAAA,IACF;AAAA,GACF;AACA,EAAA,OAAO,IAAA,CAAK,KAAK,UAAU,CAAA;AAC7B;AAKA,SAAS,iBAAA,CAAkB,OAAqB,KAAA,EAAyC;AACvF,EAAA,MAAM,YAAA,GAA2C;AAAA,IAC/C,GAAA,EAAK,CAAC,MAAA,EAAQ,IAAA,KAAS;AACrB,MAAA,IAAI,SAAS,UAAA,EAAY;AACvB,QAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,GAAA,CAAI,MAAA,EAAQ,IAAI,CAAA;AACzC,QAAA,MAAM,eAAA,GAA0D;AAAA,UAC9D,GAAA,EAAK,CAACI,OAAAA,EAAQC,KAAAA,KAAS;AACrB,YAAA,IAAI,OAAOA,UAAS,QAAA,IAAY,CAAC,MAAM,QAAA,CAASA,KAAI,CAAC,CAAA,EAAG;AACtD,cAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,GAAA,CAAID,OAAAA,EAAQC,KAAI,CAAA;AACxC,cAAA,OAAO,iBAAA,CAAkB,SAAS,KAAK,CAAA;AAAA,YACzC,CAAA,MAAO;AACL,cAAA,OAAO,OAAA,CAAQ,GAAA,CAAID,OAAAA,EAAQC,KAAI,CAAA;AAAA,YACjC;AAAA,UACF;AAAA,SACF;AACA,QAAA,OAAO,IAAA,CAAK,UAAU,eAAe,CAAA;AAAA,MACvC,CAAA,MAAA,IAAW,SAAS,QAAA,EAAU;AAC5B,QAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,GAAA,CAAI,MAAA,EAAQ,IAAI,CAAA;AACtC,QAAA,OAAO,IAAI,MAAM,KAAA,EAAO;AAAA,UACtB,KAAA,EAAO,CAAC,QAAA,KAAa;AACnB,YAAA,aAAA,CAAc,QAAQ,CAAA;AACtB,YAAA,KAAA,CAAM,YAAA,EAAa;AACnB,YAAA,OAAA,CAAQ,KAAA,CAAM,QAAA,EAAU,KAAA,EAAO,EAAE,CAAA;AAAA,UACnC;AAAA,SACD,CAAA;AAAA,MACH,CAAA,MAAA,IAAW,SAAS,UAAA,EAAY;AAC9B,QAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,GAAA,CAAI,MAAA,EAAQ,IAAI,CAAA;AACxC,QAAA,OAAO,IAAI,MAAM,OAAA,EAAS;AAAA,UACxB,KAAA,EAAO,CAAC,QAAA,EAAU,QAAA,EAAU,IAAA,KAAS;AAEnC,YAAA,MAAM,YAAA,GAAe,KAAK,CAAC,CAAA;AAC3B,YAAA,MAAM,eAAe,YAAA,EAAc,YAAA;AAEnC,YAAA,aAAA,CAAc,UAAA,EAAY,QAAW,YAAY,CAAA;AACjD,YAAA,KAAA,CAAM,cAAA,EAAe;AACrB,YAAA,OAAA,CAAQ,KAAA,CAAM,QAAA,EAAU,KAAA,EAAO,IAAI,CAAA;AAAA,UACrC;AAAA,SACD,CAAA;AAAA,MACH;AACA,MAAA,OAAO,OAAA,CAAQ,GAAA,CAAI,MAAA,EAAQ,IAAI,CAAA;AAAA,IACjC;AAAA,GACF;AACA,EAAA,OAAO,IAAA,CAAK,OAAO,YAAY,CAAA;AACjC;AAKA,IAAM,uBAAN,MAAiF;AAAA,EACvE,KAAA;AAAA,EAER,mBAAmB,KAAA,EAAsC;AACvD,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,CAAA,aAAA,EAAgB,KAAA,CAAM,KAAA,IAAS,SAAS,CAAA,CAAA;AAAA,MAC9C,OAAA,EAAS;AAAA,QACP,MAAMJ,QAAAA,CAAS,QAAA;AAAA,QACf,UAAA,EAAY;AAAA,UACV,cAAA,EAAgB,QAAA;AAAA,UAChB,YAAA,EAAc,MAAM,KAAA,IAAS;AAAA;AAC/B;AACF,KACF;AAAA,EACF;AAAA,EAEA,kBAAkB,KAAA,EAAmC;AACnD,IAAA,IAAA,CAAK,KAAA,GAAQ,IAAI,kBAAA,CAAmB,KAAA,CAAM,SAAS,MAAM,CAAA;AACzD,IAAA,OAAO,iBAAA,CAAkB,KAAA,EAAO,IAAA,CAAK,KAAK,CAAA;AAAA,EAC5C;AAAA,EAEA,eAAA,CAAgB,IAAA,EAAY,QAAA,EAAwB,OAAA,EAAe;AACjE,IAAA,IAAI,KAAK,KAAA,EAAO;AACd,MAAA,IAAA,CAAK,MAAM,YAAA,EAAa;AACxB,MAAA,IAAA,CAAK,aAAA,CAAc,IAAA,CAAK,KAAA,CAAM,YAAA,EAAc,CAAA;AAAA,IAC9C;AAAA,EACF;AAAA,EAEA,eAAA,CAAgB,IAAA,EAAY,QAAA,EAAwB,MAAA,EAAc;AAChE,IAAA,IAAI,KAAK,KAAA,EAAO;AACd,MAAA,IAAA,CAAK,MAAM,cAAA,EAAe;AAC1B,MAAA,IAAA,CAAK,aAAA,CAAc,IAAA,CAAK,KAAA,CAAM,YAAA,EAAc,CAAA;AAAA,IAC9C;AAAA,EACF;AACF,CAAA;AAMA,SAAS,iBAAiB,OAAA,EAAuD;AAC/E,EAAA,MAAM,QAAgC,EAAC;AACvC,EAAA,IAAI,OAAA,CAAQ,mBAAmB,OAAA,EAAS;AACtC,IAAA,MAAM,SAASK,eAAAA,EAAgB;AAC/B,IAAA,MAAM,SAAA,GAAkC,QAAQ,UAAA,EAAY,oBAAA;AAC5D,IAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,KAAK,OAAA,CAAQ,OAAA,CAAQ,SAAQ,EAAG;AACpD,MAAA,IAAI,aAAa,CAAC,SAAA,CAAU,SAAS,GAAA,CAAI,WAAA,EAAa,CAAA,EAAG;AACvD,QAAA;AAAA,MACF;AACA,MAAA,KAAA,CAAM,CAAA,aAAA,EAAgB,GAAG,CAAA,CAAE,CAAA,GAAI,KAAA;AAAA,IACjC;AAAA,EACF;AACA,EAAA,OAAO,KAAA;AACT;AAKA,IAAM,oBAAA,GAA8E;AAAA,EAClF,kBAAA,EAAoB,CAAC,OAAA,KAAsD;AACzE,IAAA,MAAM,UAAA,GAAqC;AAAA,MACzC,cAAA,EAAgB,OAAA;AAAA,MAChB,4BAAA,EAA8B,QAAQ,EAAA,IAAM;AAAA,KAC9C;AAGA,IAAA,IAAI,SAAA,IAAa,OAAA,IAAW,OAAA,CAAQ,OAAA,YAAmB,OAAA,EAAS;AAC9D,MAAA,MAAM,SAAA,GAAY,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,YAAY,CAAA;AAClD,MAAA,IAAI,SAAA,EAAW;AACb,QAAA,UAAA,CAAW,gBAAgB,CAAA,GAAI,SAAA;AAAA,MACjC;AAEA,MAAA,MAAA,CAAO,MAAA,CAAO,UAAA,EAAY,gBAAA,CAAiB,OAAO,CAAC,CAAA;AAAA,IACrD;AAEA,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,CAAA,aAAA,EAAgB,OAAA,CAAQ,EAAA,IAAM,SAAS,CAAA,CAAA;AAAA,MAC7C,OAAA,EAAS;AAAA,QACP,MAAML,QAAAA,CAAS,QAAA;AAAA,QACf;AAAA;AACF,KACF;AAAA,EACF;AACF,CAAA;AAMA,eAAe,WAAA,CACb,OAAA,EACA,OAAA,EACA,GAAA,EACA;AACA,EAAA,MAAM,MAAA,GAASD,KAAAA,CAAM,SAAA,CAAU,cAAc,CAAA;AAC7C,EAAA,IAAI,kBAAkBO,YAAAA,EAAc;AAClC,IAAA,IAAI;AAEF,MAAA,MAAM,gBAAA,GAAmB,GAAA;AACzB,MAAA,IAAI,iBAAiB,SAAA,EAAW;AAC9B,QAAA,MAAM,gBAAA,CAAiB,SAAA,CAAU,IAAA,CAAK,CAAC,CAAA;AAAA,MACzC;AACA,MAAA,MAAM,SAAS,IAAA,EAAK;AACpB,MAAA,MAAM,MAAA,CAAO,WAAW,OAAO,CAAA;AAAA,IACjC,SAAS,KAAA,EAAO;AAId,MAAA,OAAA,CAAQ,KAAA,CAAM,0CAA0C,KAAK,CAAA;AAAA,IAC/D;AAAA,EACF;AACF;AAKA,SAAS,kBACP,eAAA,EACA;AACA,EAAA,OAAO,CACL,SAAA,EACA,CAAC,OAAA,EAAS,GAAA,EAAKC,SAAO,CAAA,KACnB;AACH,IAAA,MAAM,EAAE,GAAA,EAAK,UAAA,EAAY,OAAA,EAAQ,GAAI,sBAAsBA,SAAO,CAAA;AAElE,IAAA,MAAM,MAAA,GAASR,KAAAA,CAAM,SAAA,CAAU,cAAc,CAAA;AAE7C,IAAA,MAAM,EAAE,MAAM,OAAA,EAAS,OAAA,EAAS,aAAY,GAC1C,eAAA,CAAgB,mBAAmB,OAAO,CAAA;AAG5C,IAAA,IAAI,QAAQ,UAAA,EAAY;AACtB,MAAA,OAAA,CAAQ,UAAA,CAAW,gBAAgB,CAAA,GAAI,SAAA;AAAA,IACzC,CAAA,MAAO;AACL,MAAA,OAAA,CAAQ,UAAA,GAAa,EAAE,gBAAA,EAAkB,SAAA,EAAU;AAAA,IACrD;AACA,IAAA,SAAA,GAAY,KAAA;AAEZ,IAAA,MAAM,aAAA,GAAgB,WAAA,IAAeD,OAAAA,CAAY,MAAA,EAAO;AAGxD,IAAA,MAAM,sBAAsB,eAAA,CAAgB,iBAAA,GACxC,eAAA,CAAgB,iBAAA,CAAkB,OAAO,CAAA,GACzC,OAAA;AAEJ,IAAA,OAAO,OAAO,eAAA,CAAgB,IAAA,EAAM,OAAA,EAAS,aAAA,EAAe,OAAO,IAAA,KAAS;AAC1E,MAAA,IAAI;AACF,QAAA,MAAM,MAAA,GAAS,MAAM,SAAA,CAAU,mBAAA,EAAqB,KAAK,UAAU,CAAA;AAEnE,QAAA,IAAI,gBAAgB,uBAAA,EAAyB;AAC3C,UAAA,MAAM,UAAA,GAAa,eAAA,CAAgB,uBAAA,CAAwB,MAAM,CAAA;AACjE,UAAA,IAAA,CAAK,cAAc,UAAU,CAAA;AAAA,QAC/B;AAGA,QAAA,IAAA,CAAK,SAAA,CAAU,EAAE,IAAA,EAAMG,cAAAA,CAAe,IAAI,CAAA;AAE1C,QAAA,IAAI,gBAAgB,eAAA,EAAiB;AACnC,UAAA,eAAA,CAAgB,eAAA,CAAgB,IAAA,EAAM,OAAA,EAAS,MAAM,CAAA;AAAA,QACvD;AACA,QAAA,OAAO,MAAA;AAAA,MACT,SAAS,KAAA,EAAO;AACd,QAAA,IAAA,CAAK,gBAAgB,KAAc,CAAA;AACnC,QAAA,IAAA,CAAK,SAAA,CAAU;AAAA,UACb,MAAMA,cAAAA,CAAe,KAAA;AAAA,UACrB,SAAS,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK;AAAA,SAC/D,CAAA;AACD,QAAA,IAAI,gBAAgB,eAAA,EAAiB;AACnC,UAAA,eAAA,CAAgB,eAAA,CAAgB,IAAA,EAAM,OAAA,EAAS,KAAK,CAAA;AAAA,QACtD;AACA,QAAA,MAAM,KAAA;AAAA,MACR,CAAA,SAAE;AACA,QAAA,IAAA,CAAK,GAAA,EAAI;AACT,QAAAM,SAAA,CAAQ,SAAA,CAAU,YAAY,IAAA,CAAK,WAAA,GAAc,OAAA,EAAS,OAAA,EAASA,SAAO,CAAC,CAAA;AAAA,MAC7E;AAAA,IACF,CAAC,CAAA;AAAA,EACH,CAAA;AACF;AAKA,SAAS,kBAAA,CACP,QAAA,EACA,SAAA,EACA,WAAA,EACA,eAAA,EAC6E;AAC7E,EAAA,OAAO,CAAC,OAAA,EAAY,GAAA,EAAQ,GAAA,KAA0B;AACpD,IAAA,MAAM,MAAA,GAAS,WAAA,CAAY,GAAA,EAAK,OAAO,CAAA;AAGvC,IAAA,IAAI,MAAA,CAAO,gBAAgB,QAAA,EAAU;AAEnC,MAAA,OAAO,SAAA,CAAU,OAAA,EAAS,GAAA,EAAK,GAAG,CAAA;AAAA,IACpC;AAGA,IAAA,MAAM,eAAA,GAAkB,mBAAmB,GAA0B,CAAA;AAErE,IAAA,MAAM,aAAA,GAAgB,UAAU,MAAM,CAAA;AAGtC,IAAA,YAAA,CAAa,MAAM,CAAA;AAEnB,IAAA,MAAM,MAAA,GAAS,kBAA2B,eAAe,CAAA;AAGzD,IAAA,OAAOT,OAAAA,CAAY,IAAA,CAAK,aAAA,EAAe,MAAM;AAC3C,MAAA,OAAO,OAAO,SAAA,EAAW,CAAC,OAAA,EAAS,eAAA,EAAiB,GAAG,CAAC,CAAA;AAAA,IAC1D,CAAC,CAAA;AAAA,EACH,CAAA;AACF;AAKA,SAAS,4BAAA,CACP,QAAA,EACA,SAAA,EACA,WAAA,EACA,qBAAA,EAC6E;AAC7E,EAAA,OAAO,CAAC,OAAA,EAAY,GAAA,EAAQ,GAAA,KAA0B;AACpD,IAAA,MAAM,MAAA,GAAS,WAAA,CAAY,GAAA,EAAK,OAAO,CAAA;AAGvC,IAAA,IAAI,MAAA,CAAO,gBAAgB,QAAA,EAAU;AAEnC,MAAA,OAAO,SAAA,CAAU,OAAA,EAAS,GAAA,EAAK,GAAG,CAAA;AAAA,IACpC;AAEA,IAAA,IAAI,mBAAmB,OAAA,EAAS;AAC9B,MAAA,MAAM,QAAA,GAAW,IAAI,GAAA,CAAI,OAAA,CAAQ,GAAG,CAAA,CAAE,QAAA;AACtC,MAAA,MAAM,QAAA,GAAW,OAAO,QAAA,CAAS,KAAA;AACjC,MAAA,IACE,CAAC,oBAAA,CAAqB,QAAA,EAAU,SAAS,OAAA,EAAS,QAAA,CAAS,OAAO,CAAA,EAClE;AACA,QAAA,OAAO,SAAA,CAAU,OAAA,EAAS,GAAA,EAAK,GAAG,CAAA;AAAA,MACpC;AAAA,IACF;AAGA,IAAA,MAAM,eAAA,GAAkB,mBAAmB,GAA0B,CAAA;AAErE,IAAA,MAAM,aAAA,GAAgB,UAAU,MAAM,CAAA;AAGtC,IAAA,YAAA,CAAa,MAAM,CAAA;AAGnB,IAAA,MAAM,eAAA,GAAkB,sBAAsB,MAAM,CAAA;AACpD,IAAA,MAAM,MAAA,GAAS,kBAA2B,eAAe,CAAA;AAGzD,IAAA,OAAOA,OAAAA,CAAY,IAAA,CAAK,aAAA,EAAe,MAAM;AAC3C,MAAA,OAAO,OAAO,SAAA,EAAW,CAAC,OAAA,EAAS,eAAA,EAAiB,GAAG,CAAC,CAAA;AAAA,IAC1D,CAAC,CAAA;AAAA,EACH,CAAA;AACF;AAEA,IAAI,mBAAA,GAAsB,KAAA;AAC1B,IAAI,SAAA,GAAY,IAAA;AAKhB,SAAS,aAAa,MAAA,EAAkC;AACtD,EAAA,IAAI,mBAAA,EAAqB;AAGzB,EAAA,IAAI,MAAA,CAAO,gBAAgB,qBAAA,EAAuB;AAChD,IAAA,qBAAA,EAAsB;AAAA,EACxB;AACA,EAAA,IAAI,MAAA,CAAO,gBAAgB,qBAAA,EAAuB;AAChD,IAAA,qBAAA,EAAsB;AAAA,EACxB;AAGA,EAAAI,WAAAA,CAAY,mBAAA,CAAoB,MAAA,CAAO,UAAU,CAAA;AAGjD,EAAA,MAAM,WAAW,sBAAA,CAAuB;AAAA,IACtC,cAAA,EAAgB,OAAO,OAAA,CAAQ,IAAA;AAAA,IAC/B,iBAAA,EAAmB,OAAO,OAAA,CAAQ,OAAA;AAAA,IAClC,mBAAA,EAAqB,OAAO,OAAA,CAAQ,SAAA;AAAA,IACpC,gBAAA,EAAkB,YAAA;AAAA,IAClB,gBAAA,EAAkB,oBAAA;AAAA,IAClB,oBAAA,EAAsB,cAAA;AAAA,IACtB,wBAAA,EAA0B;AAAA,GAC3B,CAAA;AAGD,EAAA,MAAM,QAAA,GAAW,IAAI,oBAAA,CAAqB,MAAA,CAAO,gBAAgB,QAAQ,CAAA;AACzE,EAAA,QAAA,CAAS,QAAA,EAAS;AAGlB,EAAA,MAAM,MAAA,GAASH,KAAAA,CAAM,SAAA,CAAU,cAAc,CAAA;AAC7C,EAAA,MAAA,CAAO,cAAA,CAAe,MAAA,CAAO,QAAA,CAAS,WAAW,CAAA;AAEjD,EAAA,mBAAA,GAAsB,IAAA;AACxB;AAwBO,SAAS,UAAA,CACd,SACA,MAAA,EAC0B;AAC1B,EAAA,MAAM,WAAA,GAAc,kBAAkB,MAAM,CAAA;AAE5C,EAAA,IAAI,QAAQ,KAAA,EAAO;AACjB,IAAA,MAAM,OAAA,GAAU,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA;AAEpC,IAAA,OAAA,CAAQ,KAAA,GAAQ,4BAAA;AAAA,MACd,OAAA;AAAA,MACA,OAAA;AAAA,MACA,WAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AAEA,EAAA,IAAI,QAAQ,SAAA,EAAW;AACrB,IAAA,MAAM,SAAA,GAAY,MAAA,CAAO,OAAA,CAAQ,SAAS,CAAA;AAC1C,IAAA,OAAA,CAAQ,SAAA,GAAY,kBAAA;AAAA,MAClB,OAAA;AAAA,MACA,SAAA;AAAA,MACA,WAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AAEA,EAAA,IAAI,QAAQ,KAAA,EAAO;AACjB,IAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA;AAClC,IAAA,OAAA,CAAQ,KAAA,GAAQ,kBAAA;AAAA,MACd,OAAA;AAAA,MACA,KAAA;AAAA,MACA,WAAA;AAAA,MACA,IAAI,oBAAA;AAAqB,KAC3B;AAAA,EACF;AAEA,EAAA,IAAI,QAAQ,KAAA,EAAO;AACjB,IAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA;AAClC,IAAA,OAAA,CAAQ,KAAA,GAAQ,kBAAA;AAAA,MACd,OAAA;AAAA,MACA,KAAA;AAAA,MACA,WAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AAEA,EAAA,OAAO,OAAA;AACT;;;ACrtBO,SAAS,UAAA,CACd,QACA,OAAA,EAC0B;AAC1B,EAAA,OAAO,UAAA,CAAW,SAAS,MAAM,CAAA;AACnC;;;ACRO,SAAS,iBAAA,CACd,QACA,OAAA,EACgD;AAChD,EAAA,OAAO,YAAA,CAAa,SAAS,MAAM,CAAA;AACrC","file":"index.js","sourcesContent":["/**\n * Global fetch() instrumentation for autotel-edge\n *\n * Automatically traces all outgoing fetch() calls with:\n * - HTTP method, URL, status code\n * - Request/response headers\n * - Automatic context propagation\n * - Error tracking\n */\n\nimport {\n trace,\n context as api_context,\n propagation,\n SpanStatusCode,\n SpanKind,\n} from '@opentelemetry/api';\nimport { getActiveConfig, WorkerTracer } from 'autotel-edge';\n\n/**\n * Gather HTTP request attributes following OpenTelemetry semantic conventions\n */\nfunction gatherRequestAttributes(request: Request): Record<string, any> {\n const url = new URL(request.url);\n const config = getActiveConfig();\n const redactQuery = config?.dataSafety?.redactQueryParams === true;\n\n return {\n 'http.request.method': request.method.toUpperCase(),\n 'url.full': redactQuery ? `${url.origin}${url.pathname}` : request.url,\n 'url.scheme': url.protocol.replace(':', ''),\n 'server.address': url.host,\n 'url.path': url.pathname,\n 'url.query': redactQuery ? (url.search ? '[REDACTED]' : '') : url.search,\n 'network.protocol.name': 'http',\n 'user_agent.original': request.headers.get('user-agent') || undefined,\n };\n}\n\n/**\n * Gather HTTP response attributes\n */\nfunction gatherResponseAttributes(response: Response): Record<string, any> {\n return {\n 'http.response.status_code': response.status,\n 'http.response.body.size': response.headers.get('content-length') || undefined,\n };\n}\n\n/**\n * Instrument the global fetch function\n *\n * This wraps globalThis.fetch to automatically create spans for all outgoing HTTP requests.\n *\n * **Note:** This is called automatically when the library is initialized with\n * `instrumentation.instrumentGlobalFetch: true` (default).\n */\nexport function instrumentGlobalFetch(): void {\n const originalFetch = globalThis.fetch;\n\n const instrumentedFetch = function fetch(\n input: RequestInfo | URL,\n init?: RequestInit,\n ): Promise<Response> {\n const request = new Request(input, init);\n\n // Skip non-HTTP requests\n if (!request.url.startsWith('http')) {\n return originalFetch(input, init);\n }\n\n // Skip if no active config (not initialized yet)\n const config = getActiveConfig();\n if (!config) {\n return originalFetch(input, init);\n }\n\n const tracer = trace.getTracer('autotel-edge') as WorkerTracer;\n const url = new URL(request.url);\n const spanName = `${request.method} ${url.host}`;\n\n return tracer.startActiveSpan(\n spanName,\n {\n kind: SpanKind.CLIENT,\n attributes: gatherRequestAttributes(request),\n },\n async (span) => {\n try {\n // Inject trace context into request headers for distributed tracing\n const shouldIncludeContext =\n typeof config.fetch?.includeTraceContext === 'function'\n ? config.fetch.includeTraceContext(request)\n : (config.fetch?.includeTraceContext ?? true);\n\n if (shouldIncludeContext) {\n propagation.inject(api_context.active(), request.headers, {\n set: (headers, key, value) => {\n if (typeof value === 'string') {\n headers.set(key, value);\n }\n },\n });\n }\n\n // Make the actual fetch call\n const response = await originalFetch(request);\n\n // Add response attributes\n span.setAttributes(gatherResponseAttributes(response));\n\n // Set span status based on response\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 // Replace global fetch\n globalThis.fetch = instrumentedFetch as typeof fetch;\n}\n","/**\n * Global Cache API instrumentation for Cloudflare Workers\n *\n * Automatically traces cache operations:\n * - cache.match() - Read from cache\n * - cache.put() - Write to cache\n * - cache.delete() - Delete from cache\n */\n\nimport { trace, SpanStatusCode, SpanKind } from '@opentelemetry/api';\nimport { wrap } from '../bindings/common';\nimport { WorkerTracer } from 'autotel-edge';\n\ntype CacheOperation = 'match' | 'put' | 'delete';\n\n/**\n * Sanitize URL for span attributes (remove query params that might contain sensitive data)\n */\nfunction sanitizeURL(url: string): string {\n const u = new URL(url);\n return `${u.protocol}//${u.host}${u.pathname}`;\n}\n\n/**\n * Instrument a cache method (match, put, delete)\n */\nfunction instrumentCacheMethod<T extends Function>(\n fn: T,\n cacheName: string,\n operation: CacheOperation,\n): T {\n const handler: ProxyHandler<T> = {\n async apply(target, thisArg, argArray) {\n const tracer = trace.getTracer('autotel-edge') as WorkerTracer;\n\n // Extract URL from first argument (Request or string)\n const firstArg = argArray[0];\n const url =\n firstArg instanceof Request\n ? firstArg.url\n : typeof firstArg === 'string'\n ? firstArg\n : undefined;\n\n const spanName = `Cache ${cacheName}.${operation}`;\n\n return tracer.startActiveSpan(\n spanName,\n {\n kind: SpanKind.CLIENT,\n attributes: {\n 'cache.name': cacheName,\n 'cache.operation': operation,\n 'cache.key': url ? sanitizeURL(url) : undefined,\n },\n },\n async (span) => {\n try {\n const result = await Reflect.apply(target, thisArg, argArray);\n\n // For match operations, record whether it was a hit or miss\n if (operation === 'match') {\n span.setAttribute('cache.hit', !!result);\n }\n\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 return wrap(fn, handler);\n}\n\n/**\n * Instrument a Cache instance\n */\nfunction instrumentCache(cache: Cache, cacheName: string): Cache {\n const handler: ProxyHandler<Cache> = {\n get(target, prop) {\n const value = Reflect.get(target, prop);\n\n // Instrument the cache operation methods\n if (\n (prop === 'match' || prop === 'put' || prop === 'delete') &&\n typeof value === 'function'\n ) {\n return instrumentCacheMethod(\n value.bind(target),\n cacheName,\n prop as CacheOperation,\n );\n }\n\n // Bind other methods to preserve `this` context\n if (typeof value === 'function') {\n return value.bind(target);\n }\n\n return value;\n },\n };\n\n return wrap(cache, handler);\n}\n\n/**\n * Instrument caches.open()\n */\nfunction instrumentCachesOpen(\n openFn: CacheStorage['open'],\n): CacheStorage['open'] {\n const handler: ProxyHandler<CacheStorage['open']> = {\n async apply(target, thisArg, argArray) {\n const cacheName = argArray[0];\n const cache = await Reflect.apply(target, thisArg, argArray);\n return instrumentCache(cache, cacheName);\n },\n };\n\n return wrap(openFn, handler);\n}\n\n/**\n * Instrument the global caches API\n *\n * This wraps globalThis.caches to automatically create spans for all cache operations.\n *\n * **Note:** This is called automatically when the library is initialized with\n * `instrumentation.instrumentGlobalCache: true` (default).\n */\nexport function instrumentGlobalCache(): void {\n const handler: ProxyHandler<typeof caches> = {\n get(target, prop) {\n if (prop === 'default') {\n // Wrap the default cache\n return instrumentCache(target.default, 'default');\n } else if (prop === 'open') {\n // Wrap the open method\n const openFn = Reflect.get(target, prop);\n if (typeof openFn === 'function') {\n return instrumentCachesOpen(openFn.bind(target));\n }\n }\n\n return Reflect.get(target, prop);\n },\n };\n\n // Replace global caches\n // @ts-ignore - TypeScript doesn't like reassigning globalThis.caches\n globalThis.caches = wrap(caches, handler);\n}\n","/**\n * Handler instrumentation for Cloudflare Workers\n * \n * Note: This file uses Cloudflare Workers types (ExportedHandler, Request, Response, 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 * Provides automatic OpenTelemetry tracing for:\n * - HTTP handlers (fetch)\n * - Scheduled/cron handlers\n * - Queue handlers (with message tracking)\n * - Email handlers\n * - Auto-instrumentation of Cloudflare bindings (KV, R2, D1, Service Bindings)\n * - Global fetch and cache instrumentation\n * - Post-processor support for span customization\n * - Tail sampling support\n * - Cold start tracking\n */\n\nimport {\n trace,\n context as api_context,\n propagation,\n SpanStatusCode,\n SpanKind,\n} from '@opentelemetry/api';\nimport { resourceFromAttributes } from '@opentelemetry/resources';\nimport type {\n ConfigurationOption,\n ResolvedEdgeConfig,\n Trigger,\n HandlerInstrumentation,\n InitialSpanInfo,\n ReadableSpan,\n} from 'autotel-edge';\nimport {\n createInitialiser,\n setConfig,\n getActiveConfig,\n type Initialiser,\n WorkerTracerProvider,\n WorkerTracer,\n} from 'autotel-edge';\nimport { proxyExecutionContext, unwrap, wrap, type PromiseTracker } from '../bindings/common';\nimport { instrumentGlobalFetch } from '../global/fetch';\nimport { instrumentGlobalCache } from '../global/cache';\nimport { instrumentBindings } from '../bindings/bindings';\nimport type { Attributes, Span } from '@opentelemetry/api';\n\ntype FetchHandler = (\n request: Request,\n env: any,\n ctx: ExecutionContext,\n) => Response | Promise<Response>;\n\ntype ScheduledHandler = (\n event: ScheduledController,\n env: any,\n ctx: ExecutionContext,\n) => void | Promise<void>;\n\ntype QueueHandler = (\n batch: MessageBatch,\n env: any,\n ctx: ExecutionContext,\n) => void | Promise<void>;\n\ntype EmailHandler = (\n message: ForwardableEmailMessage,\n env: any,\n ctx: ExecutionContext,\n) => void | Promise<void>;\n\ntype RouteServiceConfig = { service: string };\n\nfunction matchesPattern(path: string, pattern: string): boolean {\n const regexPattern = pattern\n .replaceAll(/[.+^${}()|[\\]\\\\]/g, String.raw`\\$&`)\n .replaceAll('**', '{{GLOBSTAR}}')\n .replaceAll('*', '[^/]*')\n .replaceAll('{{GLOBSTAR}}', '.*')\n .replaceAll('?', '[^/]');\n return new RegExp(`^${regexPattern}$`).test(path);\n}\n\nfunction shouldInstrumentPath(\n path: string,\n include?: string[],\n exclude?: string[],\n): boolean {\n if (exclude && exclude.some((pattern) => matchesPattern(path, pattern))) {\n return false;\n }\n\n if (!include || include.length === 0) {\n return true;\n }\n\n return include.some((pattern) => matchesPattern(path, pattern));\n}\n\nfunction getServiceForPath(\n path: string,\n routes?: Record<string, RouteServiceConfig>,\n): string | undefined {\n if (!routes) return undefined;\n for (const [pattern, config] of Object.entries(routes)) {\n if (matchesPattern(path, pattern)) {\n return config.service;\n }\n }\n return undefined;\n}\n\n/**\n * Create fetch handler instrumentation with config support for postProcess\n */\n/**\n * Extract Cloudflare-specific attributes from a request\n */\nfunction extractCfAttributes(request: Request): Record<string, string | number | boolean> {\n const cf = (request as any).cf;\n if (!cf) return {};\n\n const attrs: Record<string, string | number | boolean> = {};\n const set = (key: string, value: unknown) => {\n if (value !== undefined && value !== null) {\n attrs[key] = value as string | number | boolean;\n }\n };\n\n set('cloudflare.colo', cf.colo);\n const ray = request.headers.get('cf-ray');\n if (ray) attrs['cloudflare.ray_id'] = ray;\n set('cloudflare.country', cf.country);\n set('cloudflare.city', cf.city);\n set('cloudflare.region', cf.region);\n set('cloudflare.continent', cf.continent);\n set('cloudflare.timezone', cf.timezone);\n set('cloudflare.latitude', cf.latitude);\n set('cloudflare.longitude', cf.longitude);\n set('cloudflare.asn', cf.asn);\n set('cloudflare.as_organization', cf.asOrganization);\n set('cloudflare.http_protocol', cf.httpProtocol);\n set('cloudflare.tls_version', cf.tlsVersion);\n set('cloudflare.client_tcp_rtt', cf.clientTcpRtt);\n\n return attrs;\n}\n\nfunction createFetchInstrumentation(\n config: ResolvedEdgeConfig,\n): HandlerInstrumentation<Request, Response> {\n return {\n getInitialSpanInfo: (request: Request): InitialSpanInfo => {\n const url = new URL(request.url);\n const routeService = getServiceForPath(\n url.pathname,\n config.handlers.fetch.routes as Record<string, RouteServiceConfig> | undefined,\n );\n\n const cfAttrs = (config as any).extractCfAttributes === false\n ? {}\n : extractCfAttributes(request);\n\n return {\n name: `${request.method} ${url.pathname}`,\n options: {\n kind: SpanKind.SERVER,\n attributes: {\n 'http.request.method': request.method,\n 'url.full': request.url,\n ...(routeService ? { 'service.name': routeService, 'autotel.route.service': routeService } : {}),\n ...cfAttrs,\n },\n },\n context: propagation.extract(api_context.active(), request.headers),\n };\n },\n getAttributesFromResult: (response: Response) => ({\n 'http.response.status_code': response.status,\n }),\n executionSucces: (span: Span, trigger: Request, result: Response) => {\n // Override span status for server errors (5xx)\n if (result.status >= 500) {\n span.setStatus({ code: SpanStatusCode.ERROR });\n }\n\n // Call postProcess callback if configured\n if (config.handlers.fetch.postProcess) {\n const readableSpan = span as unknown as ReadableSpan;\n config.handlers.fetch.postProcess(span, {\n request: trigger,\n response: result,\n readable: readableSpan,\n });\n }\n },\n };\n}\n\n/**\n * Scheduled handler instrumentation\n */\nconst scheduledInstrumentation: HandlerInstrumentation<ScheduledController, void> = {\n getInitialSpanInfo: (event: ScheduledController): InitialSpanInfo => {\n return {\n name: `scheduledHandler ${event.cron || 'unknown'}`,\n options: {\n kind: SpanKind.INTERNAL,\n attributes: {\n 'faas.trigger': 'timer',\n 'faas.cron': event.cron || 'unknown',\n 'faas.scheduled_time': new Date(event.scheduledTime).toISOString(),\n },\n },\n };\n },\n};\n\n/**\n * Tracks message status counts for queue processing\n */\nclass MessageStatusCount {\n succeeded = 0;\n failed = 0;\n implicitly_acked = 0;\n implicitly_retried = 0;\n readonly total: number;\n\n constructor(total: number) {\n this.total = total;\n }\n\n ack() {\n this.succeeded = this.succeeded + 1;\n }\n\n ackRemaining() {\n this.implicitly_acked = this.total - this.succeeded - this.failed;\n this.succeeded = this.total - this.failed;\n }\n\n retry() {\n this.failed = this.failed + 1;\n }\n\n retryRemaining() {\n this.implicitly_retried = this.total - this.succeeded - this.failed;\n this.failed = this.total - this.succeeded;\n }\n\n toAttributes(): Attributes {\n return {\n 'queue.messages_count': this.total,\n 'queue.messages_success': this.succeeded,\n 'queue.messages_failed': this.failed,\n 'queue.batch_success': this.succeeded === this.total,\n 'queue.implicitly_acked': this.implicitly_acked,\n 'queue.implicitly_retried': this.implicitly_retried,\n };\n }\n}\n\n/**\n * Add event to active span\n */\nfunction addQueueEvent(name: string, msg?: Message, delaySeconds?: number) {\n const attrs: Attributes = {};\n if (msg) {\n attrs['queue.message_id'] = msg.id;\n attrs['queue.message_timestamp'] = msg.timestamp.toISOString();\n // Add attempts if available (from Cloudflare Queues API)\n if ('attempts' in msg && typeof msg.attempts === 'number') {\n attrs['queue.message_attempts'] = msg.attempts;\n }\n }\n if (delaySeconds !== undefined) {\n attrs['queue.retry_delay_seconds'] = delaySeconds;\n }\n trace.getActiveSpan()?.addEvent(name, attrs);\n}\n\n/**\n * Proxy a queue message to track ack/retry operations\n */\nfunction proxyQueueMessage<Q>(msg: Message<Q>, count: MessageStatusCount): Message<Q> {\n const msgHandler: ProxyHandler<Message<Q>> = {\n get: (target, prop) => {\n if (prop === 'ack') {\n const ackFn = Reflect.get(target, prop);\n return new Proxy(ackFn, {\n apply: (fnTarget) => {\n addQueueEvent('messageAck', msg);\n count.ack();\n Reflect.apply(fnTarget, msg, []);\n },\n });\n } else if (prop === 'retry') {\n const retryFn = Reflect.get(target, prop);\n return new Proxy(retryFn, {\n apply: (fnTarget, _thisArg, args) => {\n // Extract delay and content type from retry options if provided\n const retryOptions = args[0] as\n | { delaySeconds?: number; contentType?: string }\n | undefined;\n const delaySeconds = retryOptions?.delaySeconds;\n\n addQueueEvent('messageRetry', msg, delaySeconds);\n\n // Add content type attribute if provided\n if (retryOptions?.contentType) {\n const span = trace.getActiveSpan();\n if (span) {\n span.setAttribute('queue.message.content_type', retryOptions.contentType);\n }\n }\n\n count.retry();\n const result = Reflect.apply(fnTarget, msg, args);\n return result;\n },\n });\n } else {\n return Reflect.get(target, prop, msg);\n }\n },\n };\n return wrap(msg, msgHandler);\n}\n\n/**\n * Proxy MessageBatch to track ackAll/retryAll operations\n */\nfunction proxyMessageBatch(batch: MessageBatch, count: MessageStatusCount): MessageBatch {\n const batchHandler: ProxyHandler<MessageBatch> = {\n get: (target, prop) => {\n if (prop === 'messages') {\n const messages = Reflect.get(target, prop);\n const messagesHandler: ProxyHandler<MessageBatch['messages']> = {\n get: (target, prop) => {\n if (typeof prop === 'string' && !isNaN(parseInt(prop))) {\n const message = Reflect.get(target, prop);\n return proxyQueueMessage(message, count);\n } else {\n return Reflect.get(target, prop);\n }\n },\n };\n return wrap(messages, messagesHandler);\n } else if (prop === 'ackAll') {\n const ackFn = Reflect.get(target, prop);\n return new Proxy(ackFn, {\n apply: (fnTarget) => {\n addQueueEvent('ackAll');\n count.ackRemaining();\n Reflect.apply(fnTarget, batch, []);\n },\n });\n } else if (prop === 'retryAll') {\n const retryFn = Reflect.get(target, prop);\n return new Proxy(retryFn, {\n apply: (fnTarget, _thisArg, args) => {\n // Extract delay from retryAll options if provided\n const retryOptions = args[0] as { delaySeconds?: number } | undefined;\n const delaySeconds = retryOptions?.delaySeconds;\n\n addQueueEvent('retryAll', undefined, delaySeconds);\n count.retryRemaining();\n Reflect.apply(fnTarget, batch, args);\n },\n });\n }\n return Reflect.get(target, prop);\n },\n };\n return wrap(batch, batchHandler);\n}\n\n/**\n * Queue handler instrumentation with message tracking\n */\nclass QueueInstrumentation implements HandlerInstrumentation<MessageBatch, void> {\n private count?: MessageStatusCount;\n\n getInitialSpanInfo(batch: MessageBatch): InitialSpanInfo {\n return {\n name: `queueHandler ${batch.queue || 'unknown'}`,\n options: {\n kind: SpanKind.CONSUMER,\n attributes: {\n 'faas.trigger': 'pubsub',\n 'queue.name': batch.queue || 'unknown',\n },\n },\n };\n }\n\n instrumentTrigger(batch: MessageBatch): MessageBatch {\n this.count = new MessageStatusCount(batch.messages.length);\n return proxyMessageBatch(batch, this.count);\n }\n\n executionSucces(span: Span, _trigger: MessageBatch, _result: void) {\n if (this.count) {\n this.count.ackRemaining();\n span.setAttributes(this.count.toAttributes());\n }\n }\n\n executionFailed(span: Span, _trigger: MessageBatch, _error?: any) {\n if (this.count) {\n this.count.retryRemaining();\n span.setAttributes(this.count.toAttributes());\n }\n }\n}\n\n/**\n * Converts email headers into OpenTelemetry attributes.\n * When dataSafety.emailHeaderAllowlist is configured, only allowed headers are captured.\n */\nfunction headerAttributes(message: { headers: Headers }): Record<string, string> {\n const attrs: Record<string, string> = {};\n if (message.headers instanceof Headers) {\n const config = getActiveConfig();\n const allowlist: string[] | undefined = config?.dataSafety?.emailHeaderAllowlist;\n for (const [key, value] of message.headers.entries()) {\n if (allowlist && !allowlist.includes(key.toLowerCase())) {\n continue;\n }\n attrs[`email.header.${key}`] = value;\n }\n }\n return attrs;\n}\n\n/**\n * Email handler instrumentation\n */\nconst emailInstrumentation: HandlerInstrumentation<ForwardableEmailMessage, void> = {\n getInitialSpanInfo: (message: ForwardableEmailMessage): InitialSpanInfo => {\n const attributes: Record<string, string> = {\n 'faas.trigger': 'other',\n 'messaging.destination.name': message.to || 'unknown',\n };\n\n // Add message ID if available\n if ('headers' in message && message.headers instanceof Headers) {\n const messageId = message.headers.get('Message-Id');\n if (messageId) {\n attributes['rpc.message.id'] = messageId;\n }\n // Add all headers as attributes\n Object.assign(attributes, headerAttributes(message));\n }\n\n return {\n name: `emailHandler ${message.to || 'unknown'}`,\n options: {\n kind: SpanKind.CONSUMER,\n attributes,\n },\n };\n },\n};\n\n\n/**\n * Export spans after request completes\n */\nasync function exportSpans(\n traceId: string,\n tracker: PromiseTracker | undefined,\n ctx: ExecutionContext,\n) {\n const tracer = trace.getTracer('autotel-edge');\n if (tracer instanceof WorkerTracer) {\n try {\n // scheduler is available on ExecutionContext at runtime\n const ctxWithScheduler = ctx as ExecutionContext & { scheduler?: { wait(ms: number): Promise<void> } };\n if (ctxWithScheduler.scheduler) {\n await ctxWithScheduler.scheduler.wait(1);\n }\n await tracker?.wait();\n await tracer.forceFlush(traceId);\n } catch (error) {\n // Silently handle exporter errors to prevent worker crashes\n // Exporter failures should not affect the worker's ability to process requests\n // In production, consider logging to a monitoring service\n console.error('[autotel-edge] Failed to export spans:', error);\n }\n }\n}\n\n/**\n * Create handler flow with instrumentation\n */\nfunction createHandlerFlow<T extends Trigger, E, R>(\n instrumentation: HandlerInstrumentation<T, R>,\n) {\n return (\n handlerFn: (trigger: T, env: E, ctx: ExecutionContext) => R | Promise<R>,\n [trigger, env, context]: [T, E, ExecutionContext],\n ) => {\n const { ctx: proxiedCtx, tracker } = proxyExecutionContext(context);\n\n const tracer = trace.getTracer('autotel-edge') as WorkerTracer;\n\n const { name, options, context: spanContext } =\n instrumentation.getInitialSpanInfo(trigger);\n\n // Add cold start tracking\n if (options.attributes) {\n options.attributes['faas.coldstart'] = coldStart;\n } else {\n options.attributes = { 'faas.coldstart': coldStart };\n }\n coldStart = false;\n\n const parentContext = spanContext || api_context.active();\n\n // Instrument trigger if supported (e.g., for queue handler)\n const instrumentedTrigger = instrumentation.instrumentTrigger\n ? instrumentation.instrumentTrigger(trigger)\n : trigger;\n\n return tracer.startActiveSpan(name, options, parentContext, async (span) => {\n try {\n const result = await handlerFn(instrumentedTrigger, env, proxiedCtx);\n\n if (instrumentation.getAttributesFromResult) {\n const attributes = instrumentation.getAttributesFromResult(result);\n span.setAttributes(attributes);\n }\n\n // Set default OK status; executionSucces may override (e.g. HTTP 5xx)\n span.setStatus({ code: SpanStatusCode.OK });\n\n if (instrumentation.executionSucces) {\n instrumentation.executionSucces(span, trigger, result);\n }\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 if (instrumentation.executionFailed) {\n instrumentation.executionFailed(span, trigger, error);\n }\n throw error;\n } finally {\n span.end();\n context.waitUntil(exportSpans(span.spanContext().traceId, tracker, context));\n }\n });\n };\n}\n\n/**\n * Create handler proxy\n */\nfunction createHandlerProxy<T extends Trigger, E, R>(\n _handler: unknown,\n handlerFn: (trigger: T, env: E, ctx: ExecutionContext) => R | Promise<R>,\n initialiser: Initialiser,\n instrumentation: HandlerInstrumentation<T, R>,\n): (trigger: T, env: E, ctx: ExecutionContext) => ReturnType<typeof handlerFn> {\n return (trigger: T, env: E, ctx: ExecutionContext) => {\n const config = initialiser(env, trigger);\n \n // Check if instrumentation is disabled (useful for local dev)\n if (config.instrumentation.disabled) {\n // Return handler as-is without instrumentation\n return handlerFn(trigger, env, ctx);\n }\n \n // Auto-instrument Cloudflare bindings in the environment\n const instrumentedEnv = instrumentBindings(env as Record<string, any>) as E;\n \n const configContext = setConfig(config);\n\n // Initialize provider on first call\n initProvider(config);\n\n const flowFn = createHandlerFlow<T, E, R>(instrumentation);\n\n // Execute the handler flow within the config context\n return api_context.with(configContext, () => {\n return flowFn(handlerFn, [trigger, instrumentedEnv, ctx]) as ReturnType<typeof handlerFn>;\n });\n };\n}\n\n/**\n * Create handler proxy with dynamic instrumentation (for fetch with postProcess)\n */\nfunction createHandlerProxyWithConfig<T extends Trigger, E, R>(\n _handler: unknown,\n handlerFn: (trigger: T, env: E, ctx: ExecutionContext) => R | Promise<R>,\n initialiser: Initialiser,\n createInstrumentation: (config: ResolvedEdgeConfig) => HandlerInstrumentation<T, R>,\n): (trigger: T, env: E, ctx: ExecutionContext) => ReturnType<typeof handlerFn> {\n return (trigger: T, env: E, ctx: ExecutionContext) => {\n const config = initialiser(env, trigger);\n \n // Check if instrumentation is disabled (useful for local dev)\n if (config.instrumentation.disabled) {\n // Return handler as-is without instrumentation\n return handlerFn(trigger, env, ctx);\n }\n\n if (trigger instanceof Request) {\n const pathname = new URL(trigger.url).pathname;\n const fetchCfg = config.handlers.fetch;\n if (\n !shouldInstrumentPath(pathname, fetchCfg.include, fetchCfg.exclude)\n ) {\n return handlerFn(trigger, env, ctx) as ReturnType<typeof handlerFn>;\n }\n }\n \n // Auto-instrument Cloudflare bindings in the environment\n const instrumentedEnv = instrumentBindings(env as Record<string, any>) as E;\n \n const configContext = setConfig(config);\n\n // Initialize provider on first call\n initProvider(config);\n\n // Create instrumentation with config\n const instrumentation = createInstrumentation(config);\n const flowFn = createHandlerFlow<T, E, R>(instrumentation);\n\n // Execute the handler flow within the config context\n return api_context.with(configContext, () => {\n return flowFn(handlerFn, [trigger, instrumentedEnv, ctx]) as ReturnType<typeof handlerFn>;\n });\n };\n}\n\nlet providerInitialized = false;\nlet coldStart = true;\n\n/**\n * Initialize the tracer provider\n */\nfunction initProvider(config: ResolvedEdgeConfig): void {\n if (providerInitialized) return;\n\n // Install global instrumentations\n if (config.instrumentation.instrumentGlobalFetch) {\n instrumentGlobalFetch();\n }\n if (config.instrumentation.instrumentGlobalCache) {\n instrumentGlobalCache();\n }\n\n // Set up propagator\n propagation.setGlobalPropagator(config.propagator);\n\n // Create resource\n const resource = resourceFromAttributes({\n 'service.name': config.service.name,\n 'service.version': config.service.version,\n 'service.namespace': config.service.namespace,\n 'cloud.provider': 'cloudflare',\n 'cloud.platform': 'cloudflare.workers',\n 'telemetry.sdk.name': 'autotel-edge',\n 'telemetry.sdk.language': 'js',\n });\n\n // Create and register provider\n const provider = new WorkerTracerProvider(config.spanProcessors, resource);\n provider.register();\n\n // Set head sampler on tracer\n const tracer = trace.getTracer('autotel-edge') as WorkerTracer;\n tracer.setHeadSampler(config.sampling.headSampler);\n\n providerInitialized = true;\n}\n\n/**\n * Instrument a Cloudflare Workers handler\n *\n * @example\n * ```typescript\n * import { instrument } from 'autotel-edge'\n *\n * const handler = {\n * async fetch(request, env, ctx) {\n * return new Response('Hello World')\n * }\n * }\n *\n * export default instrument(handler, {\n * exporter: {\n * url: env.OTLP_ENDPOINT,\n * headers: { 'x-api-key': env.API_KEY }\n * },\n * service: { name: 'my-worker' }\n * })\n * ```\n */\nexport function instrument<E, Q = any, C = any>(\n handler: ExportedHandler<E, Q, C>,\n config: ConfigurationOption,\n): ExportedHandler<E, Q, C> {\n const initialiser = createInitialiser(config);\n\n if (handler.fetch) {\n const fetcher = unwrap(handler.fetch) as FetchHandler;\n // Create fetch instrumentation with config support\n handler.fetch = createHandlerProxyWithConfig(\n handler,\n fetcher,\n initialiser,\n createFetchInstrumentation,\n );\n }\n\n if (handler.scheduled) {\n const scheduled = unwrap(handler.scheduled) as ScheduledHandler;\n handler.scheduled = createHandlerProxy(\n handler,\n scheduled,\n initialiser,\n scheduledInstrumentation,\n );\n }\n\n if (handler.queue) {\n const queue = unwrap(handler.queue) as QueueHandler;\n handler.queue = createHandlerProxy(\n handler,\n queue,\n initialiser,\n new QueueInstrumentation(),\n );\n }\n\n if (handler.email) {\n const email = unwrap(handler.email) as EmailHandler;\n handler.email = createHandlerProxy(\n handler,\n email,\n initialiser,\n emailInstrumentation,\n );\n }\n\n return handler;\n}\n","/**\n * workers-honeycomb-logger style wrapper API\n *\n * @example\n * ```typescript\n * import { wrapModule } from 'autotel-cloudflare'\n *\n * const handler = {\n * async fetch(req, env, ctx) {\n * return new Response('Hello')\n * }\n * }\n *\n * export default wrapModule(\n * { service: { name: 'my-worker' } },\n * handler\n * )\n * ```\n */\n\nimport { instrument } from './instrument';\nimport type { ConfigurationOption } from 'autotel-edge';\n\n/**\n * Wrap a Cloudflare Workers module-style handler\n * Alternative API style inspired by workers-honeycomb-logger\n *\n * @param config Configuration (can be static object or function)\n * @param handler The worker handler to wrap\n * @returns Instrumented handler\n */\nexport function wrapModule<E, Q = any, C = any>(\n config: ConfigurationOption,\n handler: ExportedHandler<E, Q, C>,\n): ExportedHandler<E, Q, C> {\n return instrument(handler, config);\n}\n","/**\n * Durable Object wrapper\n *\n * @example\n * ```typescript\n * import { wrapDurableObject } from 'autotel-cloudflare'\n *\n * class Counter implements DurableObject {\n * async fetch(request: Request) {\n * return new Response('count')\n * }\n * }\n *\n * export default wrapDurableObject({ service: { name: 'counter-do' } }, Counter)\n * ```\n */\n\nimport { instrumentDO } from '../handlers/durable-objects';\nimport type { ConfigurationOption } from 'autotel-edge';\n\n/**\n * Wrap a Durable Object class with instrumentation\n * Alternative API style inspired by workers-honeycomb-logger\n *\n * @param config Configuration (can be static object or function)\n * @param doClass The Durable Object class to wrap\n * @returns Instrumented Durable Object class\n */\nexport function wrapDurableObject<T extends DurableObject>(\n config: ConfigurationOption,\n doClass: new (state: DurableObjectState, env: any) => T,\n): new (state: DurableObjectState, env: any) => T {\n return instrumentDO(doClass, config);\n}\n"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import 'autotel-edge/logger';
|
|
2
|
+
import { TraceContext, ExecutionLogger, ExecutionLoggerOptions } from 'autotel-edge';
|
|
3
|
+
|
|
4
|
+
interface WorkersLoggerOptions {
|
|
5
|
+
/** Override derived request id (default: cf-ray header value when present). */
|
|
6
|
+
requestId?: string;
|
|
7
|
+
/** Optional request header allowlist to include in logger context. */
|
|
8
|
+
headers?: string[];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Create an execution logger pre-populated with common request context.
|
|
12
|
+
* Best used from fetch handlers that already run inside autotel span context.
|
|
13
|
+
*/
|
|
14
|
+
declare function createWorkersLogger(request: Request, options?: WorkersLoggerOptions, ctx?: TraceContext): ExecutionLogger;
|
|
15
|
+
declare function getRequestLogger(ctx?: TraceContext, options?: ExecutionLoggerOptions): ExecutionLogger;
|
|
16
|
+
declare function getQueueLogger(ctx?: TraceContext, options?: ExecutionLoggerOptions): ExecutionLogger;
|
|
17
|
+
declare function getWorkflowLogger(ctx?: TraceContext, options?: ExecutionLoggerOptions): ExecutionLogger;
|
|
18
|
+
declare function getActorLogger(ctx?: TraceContext, options?: ExecutionLoggerOptions): ExecutionLogger;
|
|
19
|
+
|
|
20
|
+
export { type WorkersLoggerOptions as W, getQueueLogger as a, getRequestLogger as b, createWorkersLogger as c, getWorkflowLogger as d, getActorLogger as g };
|
package/dist/logger.d.ts
CHANGED
|
@@ -1,10 +1,3 @@
|
|
|
1
1
|
export * from 'autotel-edge/logger';
|
|
2
|
-
|
|
2
|
+
export { g as getActorLogger, a as getQueueLogger, b as getRequestLogger, d as getWorkflowLogger } from './logger-DGS3kP-A.js';
|
|
3
3
|
export { ExecutionLogSnapshot, ExecutionLogger, ExecutionLoggerOptions } from 'autotel-edge';
|
|
4
|
-
|
|
5
|
-
declare function getRequestLogger(ctx?: TraceContext, options?: ExecutionLoggerOptions): ExecutionLogger;
|
|
6
|
-
declare function getQueueLogger(ctx?: TraceContext, options?: ExecutionLoggerOptions): ExecutionLogger;
|
|
7
|
-
declare function getWorkflowLogger(ctx?: TraceContext, options?: ExecutionLoggerOptions): ExecutionLogger;
|
|
8
|
-
declare function getActorLogger(ctx?: TraceContext, options?: ExecutionLoggerOptions): ExecutionLogger;
|
|
9
|
-
|
|
10
|
-
export { getActorLogger, getQueueLogger, getRequestLogger, getWorkflowLogger };
|
package/dist/logger.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { getActorLogger, getQueueLogger, getRequestLogger, getWorkflowLogger } from './chunk-
|
|
1
|
+
export { getActorLogger, getQueueLogger, getRequestLogger, getWorkflowLogger } from './chunk-C3QLNZRK.js';
|
|
2
2
|
export * from 'autotel-edge/logger';
|
|
3
3
|
//# sourceMappingURL=logger.js.map
|
|
4
4
|
//# sourceMappingURL=logger.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "autotel-cloudflare",
|
|
3
|
-
"version": "2.18.
|
|
3
|
+
"version": "2.18.5",
|
|
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",
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
"@opentelemetry/api": "^1.9.1",
|
|
78
78
|
"@opentelemetry/resources": "^2.6.1",
|
|
79
79
|
"@tanstack/intent": "^0.0.29",
|
|
80
|
-
"autotel-edge": "3.16.
|
|
80
|
+
"autotel-edge": "3.16.4"
|
|
81
81
|
},
|
|
82
82
|
"peerDependencies": {
|
|
83
83
|
"@cloudflare/workers-types": "^4.20260408.1"
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
getQueueLogger,
|
|
5
5
|
getWorkflowLogger,
|
|
6
6
|
getActorLogger,
|
|
7
|
+
createWorkersLogger,
|
|
7
8
|
} from './execution-logger';
|
|
8
9
|
|
|
9
10
|
const createMockContext = () => ({
|
|
@@ -31,6 +32,7 @@ describe('cloudflare execution logger aliases', () => {
|
|
|
31
32
|
expect(ctx.setAttributes).toHaveBeenCalledWith({
|
|
32
33
|
'request.id': 'req-123',
|
|
33
34
|
});
|
|
35
|
+
expect(typeof log.fork).toBe('function');
|
|
34
36
|
});
|
|
35
37
|
|
|
36
38
|
it('getQueueLogger delegates to the shared execution logger', () => {
|
|
@@ -48,9 +50,11 @@ describe('cloudflare execution logger aliases', () => {
|
|
|
48
50
|
it('getWorkflowLogger delegates to the shared execution logger', () => {
|
|
49
51
|
const ctx = createMockContext();
|
|
50
52
|
const log = getWorkflowLogger(ctx);
|
|
51
|
-
const
|
|
53
|
+
const first = log.emitNow({ workflow: { id: 'wf-123' } });
|
|
54
|
+
const second = log.emitNow({ workflow: { id: 'wf-123' } });
|
|
52
55
|
|
|
53
|
-
expect(
|
|
56
|
+
expect(first.traceId).toBe('trace-id');
|
|
57
|
+
expect(second).toBe(first);
|
|
54
58
|
expect(ctx.addEvent).toHaveBeenCalledWith('log.emit.manual', {
|
|
55
59
|
'workflow.id': 'wf-123',
|
|
56
60
|
});
|
|
@@ -68,4 +72,56 @@ describe('cloudflare execution logger aliases', () => {
|
|
|
68
72
|
'actor.class': 'Counter',
|
|
69
73
|
});
|
|
70
74
|
});
|
|
75
|
+
|
|
76
|
+
it('createWorkersLogger pre-populates request and cf context fields', () => {
|
|
77
|
+
const ctx = createMockContext();
|
|
78
|
+
const request = new Request('https://example.com/api/orders/123?expand=1', {
|
|
79
|
+
method: 'POST',
|
|
80
|
+
headers: {
|
|
81
|
+
'cf-ray': 'ray-123',
|
|
82
|
+
traceparent: '00-abc-def-01',
|
|
83
|
+
authorization: 'Bearer should-not-include-by-default',
|
|
84
|
+
'x-request-id': 'req-789',
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
Object.defineProperty(request, 'cf', {
|
|
89
|
+
value: {
|
|
90
|
+
colo: 'LHR',
|
|
91
|
+
country: 'GB',
|
|
92
|
+
asn: 13335,
|
|
93
|
+
city: 'London',
|
|
94
|
+
region: 'England',
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const log = createWorkersLogger(request, { headers: ['x-request-id'] }, ctx);
|
|
99
|
+
|
|
100
|
+
const fields = log.getContext();
|
|
101
|
+
expect(fields.request).toMatchObject({
|
|
102
|
+
method: 'POST',
|
|
103
|
+
path: '/api/orders/123',
|
|
104
|
+
url: 'https://example.com/api/orders/123?expand=1',
|
|
105
|
+
requestId: 'ray-123',
|
|
106
|
+
headers: { 'x-request-id': 'req-789' },
|
|
107
|
+
});
|
|
108
|
+
expect(fields.cfRay).toBe('ray-123');
|
|
109
|
+
expect(fields.traceparent).toBe('00-abc-def-01');
|
|
110
|
+
expect(fields.colo).toBe('LHR');
|
|
111
|
+
expect(fields.country).toBe('GB');
|
|
112
|
+
expect(fields.asn).toBe(13335);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('createWorkersLogger honors explicit requestId override', () => {
|
|
116
|
+
const ctx = createMockContext();
|
|
117
|
+
const request = new Request('https://example.com/health', {
|
|
118
|
+
headers: { 'cf-ray': 'ray-default' },
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
const log = createWorkersLogger(request, { requestId: 'manual-id' }, ctx);
|
|
122
|
+
|
|
123
|
+
expect(log.getContext().request).toMatchObject({
|
|
124
|
+
requestId: 'manual-id',
|
|
125
|
+
});
|
|
126
|
+
});
|
|
71
127
|
});
|
package/src/execution-logger.ts
CHANGED
|
@@ -12,6 +12,77 @@ export type {
|
|
|
12
12
|
ExecutionLogSnapshot,
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
+
export interface WorkersLoggerOptions {
|
|
16
|
+
/** Override derived request id (default: cf-ray header value when present). */
|
|
17
|
+
requestId?: string;
|
|
18
|
+
/** Optional request header allowlist to include in logger context. */
|
|
19
|
+
headers?: string[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
23
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function collectHeaders(
|
|
27
|
+
headers: Headers,
|
|
28
|
+
include: string[] | undefined,
|
|
29
|
+
): Record<string, string> | undefined {
|
|
30
|
+
if (!include || include.length === 0) return undefined;
|
|
31
|
+
|
|
32
|
+
const allowlist = new Set(include.map((h) => h.toLowerCase()));
|
|
33
|
+
const out: Record<string, string> = {};
|
|
34
|
+
headers.forEach((value, key) => {
|
|
35
|
+
if (allowlist.has(key.toLowerCase())) {
|
|
36
|
+
out[key] = value;
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
return Object.keys(out).length > 0 ? out : undefined;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function pickCfContext(request: Request): Record<string, unknown> {
|
|
44
|
+
const cf = Reflect.get(request, 'cf');
|
|
45
|
+
if (!isRecord(cf)) return {};
|
|
46
|
+
|
|
47
|
+
const out: Record<string, unknown> = {};
|
|
48
|
+
if (typeof cf.colo === 'string') out.colo = cf.colo;
|
|
49
|
+
if (typeof cf.country === 'string') out.country = cf.country;
|
|
50
|
+
if (typeof cf.asn === 'number') out.asn = cf.asn;
|
|
51
|
+
if (typeof cf.city === 'string') out.city = cf.city;
|
|
52
|
+
if (typeof cf.region === 'string') out.region = cf.region;
|
|
53
|
+
return out;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Create an execution logger pre-populated with common request context.
|
|
58
|
+
* Best used from fetch handlers that already run inside autotel span context.
|
|
59
|
+
*/
|
|
60
|
+
export function createWorkersLogger(
|
|
61
|
+
request: Request,
|
|
62
|
+
options: WorkersLoggerOptions = {},
|
|
63
|
+
ctx?: TraceContext,
|
|
64
|
+
): ExecutionLogger {
|
|
65
|
+
const log = getExecutionLogger(ctx);
|
|
66
|
+
const url = new URL(request.url);
|
|
67
|
+
const cfRay = request.headers.get('cf-ray') ?? undefined;
|
|
68
|
+
const traceparent = request.headers.get('traceparent') ?? undefined;
|
|
69
|
+
|
|
70
|
+
log.set({
|
|
71
|
+
request: {
|
|
72
|
+
method: request.method,
|
|
73
|
+
path: url.pathname,
|
|
74
|
+
url: request.url,
|
|
75
|
+
requestId: options.requestId ?? cfRay,
|
|
76
|
+
headers: collectHeaders(request.headers, options.headers),
|
|
77
|
+
},
|
|
78
|
+
cfRay,
|
|
79
|
+
traceparent,
|
|
80
|
+
...pickCfContext(request),
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
return log;
|
|
84
|
+
}
|
|
85
|
+
|
|
15
86
|
export function getRequestLogger(
|
|
16
87
|
ctx?: TraceContext,
|
|
17
88
|
options?: ExecutionLoggerOptions,
|
package/src/index.ts
CHANGED
|
@@ -42,9 +42,11 @@ export {
|
|
|
42
42
|
getQueueLogger,
|
|
43
43
|
getWorkflowLogger,
|
|
44
44
|
getActorLogger,
|
|
45
|
+
createWorkersLogger,
|
|
45
46
|
type ExecutionLogger,
|
|
46
47
|
type ExecutionLoggerOptions,
|
|
47
48
|
type ExecutionLogSnapshot,
|
|
49
|
+
type WorkersLoggerOptions,
|
|
48
50
|
} from './execution-logger';
|
|
49
51
|
|
|
50
52
|
// Cloudflare-specific wrappers
|
|
@@ -272,4 +272,63 @@ describe('CF Attributes extraction via instrument()', () => {
|
|
|
272
272
|
expect(attrs['cloudflare.asn']).toBe(0);
|
|
273
273
|
expect(attrs['cloudflare.client_tcp_rtt']).toBe(0);
|
|
274
274
|
});
|
|
275
|
+
|
|
276
|
+
it('should skip fetch instrumentation when route does not match include patterns', async () => {
|
|
277
|
+
const handler = {
|
|
278
|
+
async fetch(_request: Request) {
|
|
279
|
+
return new Response('OK', { status: 200 });
|
|
280
|
+
},
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
const instrumented = instrument(handler, {
|
|
284
|
+
service: { name: 'test-worker' },
|
|
285
|
+
handlers: {
|
|
286
|
+
fetch: {
|
|
287
|
+
include: ['/api/**'],
|
|
288
|
+
exclude: ['/api/internal/**'],
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
const request = new Request('http://example.com/health');
|
|
294
|
+
const env = {} as any;
|
|
295
|
+
const ctx = createMockCtx();
|
|
296
|
+
|
|
297
|
+
const response = await instrumented.fetch!(request, env, ctx);
|
|
298
|
+
|
|
299
|
+
expect(response.status).toBe(200);
|
|
300
|
+
expect(mockTracer.startActiveSpan).not.toHaveBeenCalled();
|
|
301
|
+
expect(capturedSpanOptions).toBeNull();
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
it('should apply per-route service mapping to fetch span attributes', async () => {
|
|
305
|
+
const handler = {
|
|
306
|
+
async fetch(_request: Request) {
|
|
307
|
+
return new Response('OK', { status: 200 });
|
|
308
|
+
},
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
const instrumented = instrument(handler, {
|
|
312
|
+
service: { name: 'default-worker' },
|
|
313
|
+
handlers: {
|
|
314
|
+
fetch: {
|
|
315
|
+
routes: {
|
|
316
|
+
'/api/auth/**': { service: 'auth-service' },
|
|
317
|
+
'/api/**': { service: 'api-service' },
|
|
318
|
+
},
|
|
319
|
+
},
|
|
320
|
+
},
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
const request = new Request('http://example.com/api/auth/login');
|
|
324
|
+
const env = {} as any;
|
|
325
|
+
const ctx = createMockCtx();
|
|
326
|
+
|
|
327
|
+
await instrumented.fetch!(request, env, ctx);
|
|
328
|
+
|
|
329
|
+
expect(capturedSpanOptions).toBeDefined();
|
|
330
|
+
const attrs = capturedSpanOptions.attributes;
|
|
331
|
+
expect(attrs['service.name']).toBe('auth-service');
|
|
332
|
+
expect(attrs['autotel.route.service']).toBe('auth-service');
|
|
333
|
+
});
|
|
275
334
|
});
|
|
@@ -72,6 +72,46 @@ type EmailHandler = (
|
|
|
72
72
|
ctx: ExecutionContext,
|
|
73
73
|
) => void | Promise<void>;
|
|
74
74
|
|
|
75
|
+
type RouteServiceConfig = { service: string };
|
|
76
|
+
|
|
77
|
+
function matchesPattern(path: string, pattern: string): boolean {
|
|
78
|
+
const regexPattern = pattern
|
|
79
|
+
.replaceAll(/[.+^${}()|[\]\\]/g, String.raw`\$&`)
|
|
80
|
+
.replaceAll('**', '{{GLOBSTAR}}')
|
|
81
|
+
.replaceAll('*', '[^/]*')
|
|
82
|
+
.replaceAll('{{GLOBSTAR}}', '.*')
|
|
83
|
+
.replaceAll('?', '[^/]');
|
|
84
|
+
return new RegExp(`^${regexPattern}$`).test(path);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function shouldInstrumentPath(
|
|
88
|
+
path: string,
|
|
89
|
+
include?: string[],
|
|
90
|
+
exclude?: string[],
|
|
91
|
+
): boolean {
|
|
92
|
+
if (exclude && exclude.some((pattern) => matchesPattern(path, pattern))) {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (!include || include.length === 0) {
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return include.some((pattern) => matchesPattern(path, pattern));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function getServiceForPath(
|
|
104
|
+
path: string,
|
|
105
|
+
routes?: Record<string, RouteServiceConfig>,
|
|
106
|
+
): string | undefined {
|
|
107
|
+
if (!routes) return undefined;
|
|
108
|
+
for (const [pattern, config] of Object.entries(routes)) {
|
|
109
|
+
if (matchesPattern(path, pattern)) {
|
|
110
|
+
return config.service;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
75
115
|
|
|
76
116
|
/**
|
|
77
117
|
* Create fetch handler instrumentation with config support for postProcess
|
|
@@ -115,6 +155,10 @@ function createFetchInstrumentation(
|
|
|
115
155
|
return {
|
|
116
156
|
getInitialSpanInfo: (request: Request): InitialSpanInfo => {
|
|
117
157
|
const url = new URL(request.url);
|
|
158
|
+
const routeService = getServiceForPath(
|
|
159
|
+
url.pathname,
|
|
160
|
+
config.handlers.fetch.routes as Record<string, RouteServiceConfig> | undefined,
|
|
161
|
+
);
|
|
118
162
|
|
|
119
163
|
const cfAttrs = (config as any).extractCfAttributes === false
|
|
120
164
|
? {}
|
|
@@ -127,6 +171,7 @@ function createFetchInstrumentation(
|
|
|
127
171
|
attributes: {
|
|
128
172
|
'http.request.method': request.method,
|
|
129
173
|
'url.full': request.url,
|
|
174
|
+
...(routeService ? { 'service.name': routeService, 'autotel.route.service': routeService } : {}),
|
|
130
175
|
...cfAttrs,
|
|
131
176
|
},
|
|
132
177
|
},
|
|
@@ -567,6 +612,16 @@ function createHandlerProxyWithConfig<T extends Trigger, E, R>(
|
|
|
567
612
|
// Return handler as-is without instrumentation
|
|
568
613
|
return handlerFn(trigger, env, ctx);
|
|
569
614
|
}
|
|
615
|
+
|
|
616
|
+
if (trigger instanceof Request) {
|
|
617
|
+
const pathname = new URL(trigger.url).pathname;
|
|
618
|
+
const fetchCfg = config.handlers.fetch;
|
|
619
|
+
if (
|
|
620
|
+
!shouldInstrumentPath(pathname, fetchCfg.include, fetchCfg.exclude)
|
|
621
|
+
) {
|
|
622
|
+
return handlerFn(trigger, env, ctx) as ReturnType<typeof handlerFn>;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
570
625
|
|
|
571
626
|
// Auto-instrument Cloudflare bindings in the environment
|
|
572
627
|
const instrumentedEnv = instrumentBindings(env as Record<string, any>) as E;
|
package/dist/chunk-EACMDVCB.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { getExecutionLogger } from 'autotel-edge';
|
|
2
|
-
|
|
3
|
-
// src/execution-logger.ts
|
|
4
|
-
function getRequestLogger(ctx, options) {
|
|
5
|
-
return getExecutionLogger(ctx, options);
|
|
6
|
-
}
|
|
7
|
-
function getQueueLogger(ctx, options) {
|
|
8
|
-
return getExecutionLogger(ctx, options);
|
|
9
|
-
}
|
|
10
|
-
function getWorkflowLogger(ctx, options) {
|
|
11
|
-
return getExecutionLogger(ctx, options);
|
|
12
|
-
}
|
|
13
|
-
function getActorLogger(ctx, options) {
|
|
14
|
-
return getExecutionLogger(ctx, options);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export { getActorLogger, getQueueLogger, getRequestLogger, getWorkflowLogger };
|
|
18
|
-
//# sourceMappingURL=chunk-EACMDVCB.js.map
|
|
19
|
-
//# sourceMappingURL=chunk-EACMDVCB.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/execution-logger.ts"],"names":[],"mappings":";;;AAcO,SAAS,gBAAA,CACd,KACA,OAAA,EACiB;AACjB,EAAA,OAAO,kBAAA,CAAmB,KAAK,OAAO,CAAA;AACxC;AAEO,SAAS,cAAA,CACd,KACA,OAAA,EACiB;AACjB,EAAA,OAAO,kBAAA,CAAmB,KAAK,OAAO,CAAA;AACxC;AAEO,SAAS,iBAAA,CACd,KACA,OAAA,EACiB;AACjB,EAAA,OAAO,kBAAA,CAAmB,KAAK,OAAO,CAAA;AACxC;AAEO,SAAS,cAAA,CACd,KACA,OAAA,EACiB;AACjB,EAAA,OAAO,kBAAA,CAAmB,KAAK,OAAO,CAAA;AACxC","file":"chunk-EACMDVCB.js","sourcesContent":["import {\n type ExecutionLogger,\n type ExecutionLoggerOptions,\n type ExecutionLogSnapshot,\n getExecutionLogger,\n type TraceContext,\n} from 'autotel-edge';\n\nexport type {\n ExecutionLogger,\n ExecutionLoggerOptions,\n ExecutionLogSnapshot,\n};\n\nexport function getRequestLogger(\n ctx?: TraceContext,\n options?: ExecutionLoggerOptions,\n): ExecutionLogger {\n return getExecutionLogger(ctx, options);\n}\n\nexport function getQueueLogger(\n ctx?: TraceContext,\n options?: ExecutionLoggerOptions,\n): ExecutionLogger {\n return getExecutionLogger(ctx, options);\n}\n\nexport function getWorkflowLogger(\n ctx?: TraceContext,\n options?: ExecutionLoggerOptions,\n): ExecutionLogger {\n return getExecutionLogger(ctx, options);\n}\n\nexport function getActorLogger(\n ctx?: TraceContext,\n options?: ExecutionLoggerOptions,\n): ExecutionLogger {\n return getExecutionLogger(ctx, options);\n}\n"]}
|