autotel-cloudflare 3.1.0 → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/dist/agents.d.ts.map +1 -1
  2. package/dist/agents.js +7 -0
  3. package/dist/agents.js.map +1 -1
  4. package/package.json +8 -4
  5. package/src/actors/alarms.ts +0 -225
  6. package/src/actors/index.ts +0 -36
  7. package/src/actors/instrument-actor.test.ts +0 -179
  8. package/src/actors/instrument-actor.ts +0 -574
  9. package/src/actors/sockets.ts +0 -217
  10. package/src/actors/storage.ts +0 -263
  11. package/src/actors/traced-handler.ts +0 -300
  12. package/src/actors/types.ts +0 -98
  13. package/src/actors.ts +0 -50
  14. package/src/agents/agent.ts +0 -327
  15. package/src/agents/base.ts +0 -26
  16. package/src/agents/index.ts +0 -46
  17. package/src/agents/mcp.ts +0 -38
  18. package/src/agents/observability.ts +0 -145
  19. package/src/agents/otel-observability.test.ts +0 -269
  20. package/src/agents/otel-observability.ts +0 -557
  21. package/src/agents/types.ts +0 -61
  22. package/src/agents.ts +0 -87
  23. package/src/bindings/ai.test.ts +0 -170
  24. package/src/bindings/ai.ts +0 -73
  25. package/src/bindings/analytics-engine.test.ts +0 -175
  26. package/src/bindings/analytics-engine.ts +0 -78
  27. package/src/bindings/bindings-cache.test.ts +0 -80
  28. package/src/bindings/bindings-detection.test.ts +0 -235
  29. package/src/bindings/bindings-this-binding.test.ts +0 -294
  30. package/src/bindings/bindings.ts +0 -720
  31. package/src/bindings/browser-rendering.test.ts +0 -160
  32. package/src/bindings/browser-rendering.ts +0 -70
  33. package/src/bindings/common.ts +0 -84
  34. package/src/bindings/hyperdrive.test.ts +0 -176
  35. package/src/bindings/hyperdrive.ts +0 -74
  36. package/src/bindings/images.test.ts +0 -262
  37. package/src/bindings/images.ts +0 -182
  38. package/src/bindings/index.ts +0 -20
  39. package/src/bindings/queue-producer.test.ts +0 -224
  40. package/src/bindings/queue-producer.ts +0 -105
  41. package/src/bindings/rate-limiter.test.ts +0 -140
  42. package/src/bindings/rate-limiter.ts +0 -69
  43. package/src/bindings/vectorize.test.ts +0 -362
  44. package/src/bindings/vectorize.ts +0 -86
  45. package/src/bindings.ts +0 -6
  46. package/src/events.ts +0 -6
  47. package/src/execution-logger.test.ts +0 -127
  48. package/src/execution-logger.ts +0 -112
  49. package/src/global/cache.test.ts +0 -292
  50. package/src/global/cache.ts +0 -164
  51. package/src/global/fetch.test.ts +0 -399
  52. package/src/global/fetch.ts +0 -136
  53. package/src/global/index.ts +0 -7
  54. package/src/handlers/durable-objects.test.ts +0 -524
  55. package/src/handlers/durable-objects.ts +0 -250
  56. package/src/handlers/index.ts +0 -6
  57. package/src/handlers/workflows.test.ts +0 -411
  58. package/src/handlers/workflows.ts +0 -345
  59. package/src/handlers.ts +0 -6
  60. package/src/index.ts +0 -91
  61. package/src/logger.ts +0 -15
  62. package/src/native/native-tracing.test.ts +0 -54
  63. package/src/native/native-tracing.ts +0 -83
  64. package/src/native.ts +0 -12
  65. package/src/parse-error.ts +0 -1
  66. package/src/sampling.ts +0 -6
  67. package/src/testing.ts +0 -6
  68. package/src/wrappers/cf-attributes.test.ts +0 -334
  69. package/src/wrappers/define-worker-fetch.test.ts +0 -102
  70. package/src/wrappers/define-worker-fetch.ts +0 -71
  71. package/src/wrappers/index.ts +0 -13
  72. package/src/wrappers/instrument.integration.test.ts +0 -578
  73. package/src/wrappers/instrument.ts +0 -806
  74. package/src/wrappers/native-instrument.test.ts +0 -153
  75. package/src/wrappers/wrap-do.ts +0 -34
  76. package/src/wrappers/wrap-module.ts +0 -37
@@ -1,86 +0,0 @@
1
- /**
2
- * Vectorize binding instrumentation
3
- */
4
-
5
- import {
6
- trace,
7
- SpanKind,
8
- SpanStatusCode,
9
- } from '@opentelemetry/api';
10
- import type { WorkerTracer } from 'autotel-edge';
11
- import { wrap, setAttr } from './common';
12
-
13
- const TRACED_METHODS = ['query', 'insert', 'upsert', 'deleteByIds', 'getByIds', 'describe'] as const;
14
-
15
- /**
16
- * Instrument Vectorize index binding
17
- */
18
- export function instrumentVectorize<T extends VectorizeIndex>(vectorize: T, indexName?: string): T {
19
- const name = indexName || 'vectorize';
20
-
21
- const handler: ProxyHandler<T> = {
22
- get(target, prop) {
23
- const value = Reflect.get(target, prop);
24
-
25
- if (typeof prop === 'string' && TRACED_METHODS.includes(prop as any) && typeof value === 'function') {
26
- return new Proxy(value, {
27
- apply: (fnTarget, _thisArg, args) => {
28
- const operation = prop as string;
29
- const tracer = trace.getTracer('autotel-edge') as WorkerTracer;
30
-
31
- const attributes: Record<string, string | number> = {
32
- 'db.system': 'cloudflare-vectorize',
33
- 'db.operation': operation,
34
- 'db.collection.name': name,
35
- };
36
-
37
- // Per-operation attributes
38
- if (operation === 'query') {
39
- const queryInput = args[0] as { topK?: number } | undefined;
40
- if (queryInput?.topK !== undefined) {
41
- attributes['db.vectorize.top_k'] = queryInput.topK;
42
- }
43
- }
44
-
45
- if ((operation === 'insert' || operation === 'upsert') && Array.isArray(args[0])) {
46
- attributes['db.vectorize.vectors_count'] = args[0].length;
47
- }
48
-
49
- return tracer.startActiveSpan(
50
- `Vectorize ${name}: ${operation}`,
51
- {
52
- kind: SpanKind.CLIENT,
53
- attributes,
54
- },
55
- async (span) => {
56
- try {
57
- const result = await Reflect.apply(fnTarget, target, args);
58
-
59
- if (operation === 'query' && result?.matches) {
60
- setAttr(span, 'db.vectorize.matches_count', result.matches.length);
61
- }
62
-
63
- span.setStatus({ code: SpanStatusCode.OK });
64
- return result;
65
- } catch (error) {
66
- span.recordException(error as Error);
67
- span.setStatus({
68
- code: SpanStatusCode.ERROR,
69
- message: error instanceof Error ? error.message : String(error),
70
- });
71
- throw error;
72
- } finally {
73
- span.end();
74
- }
75
- },
76
- );
77
- },
78
- });
79
- }
80
-
81
- return value;
82
- },
83
- };
84
-
85
- return wrap(vectorize, handler);
86
- }
package/src/bindings.ts DELETED
@@ -1,6 +0,0 @@
1
- /**
2
- * Bindings instrumentation entry point
3
- * Entry point: autotel-cloudflare/bindings
4
- */
5
-
6
- export * from './bindings/index';
package/src/events.ts DELETED
@@ -1,6 +0,0 @@
1
- /**
2
- * Events system entry point (re-export from autotel-edge)
3
- * Entry point: autotel-cloudflare/events
4
- */
5
-
6
- export * from 'autotel-edge/events';
@@ -1,127 +0,0 @@
1
- import { describe, expect, it, vi } from 'vitest';
2
- import {
3
- getRequestLogger,
4
- getQueueLogger,
5
- getWorkflowLogger,
6
- getActorLogger,
7
- createWorkersLogger,
8
- } from './execution-logger';
9
-
10
- const createMockContext = () => ({
11
- traceId: 'trace-id',
12
- spanId: 'span-id',
13
- correlationId: 'corr-id',
14
- setAttribute: vi.fn(),
15
- setAttributes: vi.fn(),
16
- setStatus: vi.fn(),
17
- recordException: vi.fn(),
18
- addEvent: vi.fn(),
19
- addLink: vi.fn(),
20
- addLinks: vi.fn(),
21
- updateName: vi.fn(),
22
- isRecording: vi.fn(() => true),
23
- });
24
-
25
- describe('cloudflare execution logger aliases', () => {
26
- it('getRequestLogger delegates to the shared execution logger', () => {
27
- const ctx = createMockContext();
28
- const log = getRequestLogger(ctx);
29
-
30
- log.set({ request: { id: 'req-123' } });
31
-
32
- expect(ctx.setAttributes).toHaveBeenCalledWith({
33
- 'request.id': 'req-123',
34
- });
35
- expect(typeof log.fork).toBe('function');
36
- });
37
-
38
- it('getQueueLogger delegates to the shared execution logger', () => {
39
- const ctx = createMockContext();
40
- const log = getQueueLogger(ctx);
41
-
42
- log.info('processing batch', { queue: { name: 'payments' } });
43
-
44
- expect(ctx.addEvent).toHaveBeenCalledWith('log.info', {
45
- message: 'processing batch',
46
- 'queue.name': 'payments',
47
- });
48
- });
49
-
50
- it('getWorkflowLogger delegates to the shared execution logger', () => {
51
- const ctx = createMockContext();
52
- const log = getWorkflowLogger(ctx);
53
- const first = log.emitNow({ workflow: { id: 'wf-123' } });
54
- const second = log.emitNow({ workflow: { id: 'wf-123' } });
55
-
56
- expect(first.traceId).toBe('trace-id');
57
- expect(second).toBe(first);
58
- expect(ctx.addEvent).toHaveBeenCalledWith('log.emit.manual', {
59
- 'workflow.id': 'wf-123',
60
- });
61
- });
62
-
63
- it('getActorLogger delegates to the shared execution logger', () => {
64
- const ctx = createMockContext();
65
- const log = getActorLogger(ctx);
66
-
67
- log.warn('alarm delayed', { actor: { class: 'Counter' } });
68
-
69
- expect(ctx.setAttribute).toHaveBeenCalledWith('autotel.log.level', 'warn');
70
- expect(ctx.addEvent).toHaveBeenCalledWith('log.warn', {
71
- message: 'alarm delayed',
72
- 'actor.class': 'Counter',
73
- });
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
- });
127
- });
@@ -1,112 +0,0 @@
1
- import {
2
- type ExecutionLogger,
3
- type ExecutionLoggerOptions,
4
- type ExecutionLogSnapshot,
5
- getExecutionLogger,
6
- type TraceContext,
7
- } from 'autotel-edge/logger';
8
-
9
- export type {
10
- ExecutionLogger,
11
- ExecutionLoggerOptions,
12
- ExecutionLogSnapshot,
13
- };
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
-
86
- export function getRequestLogger(
87
- ctx?: TraceContext,
88
- options?: ExecutionLoggerOptions,
89
- ): ExecutionLogger {
90
- return getExecutionLogger(ctx, options);
91
- }
92
-
93
- export function getQueueLogger(
94
- ctx?: TraceContext,
95
- options?: ExecutionLoggerOptions,
96
- ): ExecutionLogger {
97
- return getExecutionLogger(ctx, options);
98
- }
99
-
100
- export function getWorkflowLogger(
101
- ctx?: TraceContext,
102
- options?: ExecutionLoggerOptions,
103
- ): ExecutionLogger {
104
- return getExecutionLogger(ctx, options);
105
- }
106
-
107
- export function getActorLogger(
108
- ctx?: TraceContext,
109
- options?: ExecutionLoggerOptions,
110
- ): ExecutionLogger {
111
- return getExecutionLogger(ctx, options);
112
- }
@@ -1,292 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
- import { instrumentGlobalCache } from './cache';
3
- import { trace, SpanStatusCode, SpanKind } from '@opentelemetry/api';
4
-
5
- describe('Global Cache Instrumentation', () => {
6
- let mockTracer: any;
7
- let mockSpan: any;
8
- let getTracerSpy: any;
9
- let originalCaches: typeof globalThis.caches;
10
-
11
- beforeEach(() => {
12
- // Save original caches
13
- originalCaches = globalThis.caches;
14
-
15
- mockSpan = {
16
- spanContext: () => ({
17
- traceId: 'test-trace-id',
18
- spanId: 'test-span-id',
19
- traceFlags: 1,
20
- }),
21
- setAttribute: vi.fn(),
22
- setAttributes: vi.fn(),
23
- setStatus: vi.fn(),
24
- recordException: vi.fn(),
25
- end: vi.fn(),
26
- isRecording: () => true,
27
- updateName: vi.fn(),
28
- addEvent: vi.fn(),
29
- };
30
-
31
- mockTracer = {
32
- startActiveSpan: vi.fn((name, options, fn) => {
33
- return fn(mockSpan);
34
- }),
35
- };
36
-
37
- getTracerSpy = vi.spyOn(trace, 'getTracer').mockReturnValue(mockTracer as any);
38
-
39
- // Mock caches API
40
- const mockCache = {
41
- match: vi.fn(async (key) => {
42
- // Simulate cache hit/miss
43
- const url = key instanceof Request ? key.url : key;
44
- if (typeof url === 'string' && url.includes('cached')) {
45
- return new Response('cached data');
46
- }
47
- return undefined;
48
- }),
49
- put: vi.fn(async () => {}),
50
- delete: vi.fn(async () => true),
51
- keys: vi.fn(async () => []),
52
- add: vi.fn(async () => {}),
53
- addAll: vi.fn(async () => {}),
54
- };
55
-
56
- (globalThis as any).caches = {
57
- default: mockCache,
58
- open: vi.fn(async (name: string) => mockCache),
59
- };
60
- });
61
-
62
- afterEach(() => {
63
- // Restore original caches
64
- (globalThis as any).caches = originalCaches;
65
- getTracerSpy.mockRestore();
66
- });
67
-
68
- describe('instrumentGlobalCache()', () => {
69
- it('should wrap globalThis.caches', () => {
70
- const originalCaches = globalThis.caches;
71
- instrumentGlobalCache();
72
-
73
- expect(globalThis.caches).not.toBe(originalCaches);
74
- expect(globalThis.caches.default).toBeDefined();
75
- });
76
-
77
- it('should instrument caches.default', async () => {
78
- instrumentGlobalCache();
79
-
80
- const request = new Request('https://example.com/test');
81
- await caches.default.match(request);
82
-
83
- expect(mockTracer.startActiveSpan).toHaveBeenCalled();
84
-
85
- const spanName = mockTracer.startActiveSpan.mock.calls[0][0];
86
- expect(spanName).toContain('Cache');
87
- expect(spanName).toContain('default');
88
- expect(spanName).toContain('match');
89
- });
90
- });
91
-
92
- describe('cache.match() instrumentation', () => {
93
- it('should create span for cache.match()', async () => {
94
- instrumentGlobalCache();
95
-
96
- const request = new Request('https://example.com/api/data');
97
- await caches.default.match(request);
98
-
99
- expect(mockTracer.startActiveSpan).toHaveBeenCalled();
100
-
101
- const spanName = mockTracer.startActiveSpan.mock.calls[0][0];
102
- expect(spanName).toBe('Cache default.match');
103
- });
104
-
105
- it('should record cache hit (result found)', async () => {
106
- instrumentGlobalCache();
107
-
108
- const request = new Request('https://example.com/cached/data');
109
- const result = await caches.default.match(request);
110
-
111
- expect(result).toBeDefined();
112
- expect(mockSpan.setAttribute).toHaveBeenCalledWith('cache.hit', true);
113
- });
114
-
115
- it('should record cache miss (result not found)', async () => {
116
- // Create a mock that explicitly returns undefined
117
- const missCache = {
118
- match: vi.fn(async () => undefined),
119
- put: vi.fn(async () => {}),
120
- delete: vi.fn(async () => true),
121
- };
122
-
123
- (globalThis as any).caches = {
124
- default: missCache,
125
- open: vi.fn(),
126
- };
127
-
128
- instrumentGlobalCache();
129
-
130
- const request = new Request('https://example.com/uncached/data');
131
- const result = await caches.default.match(request);
132
-
133
- expect(result).toBeUndefined();
134
- expect(mockSpan.setAttribute).toHaveBeenCalledWith('cache.hit', false);
135
- });
136
-
137
- it('should sanitize URL in attributes', async () => {
138
- instrumentGlobalCache();
139
-
140
- const request = new Request('https://example.com/api/data?secret=123&token=abc');
141
- await caches.default.match(request);
142
-
143
- const options = mockTracer.startActiveSpan.mock.calls[0][1];
144
-
145
- // URL should be sanitized (query params removed)
146
- expect(options.attributes['cache.key']).toBe('https://example.com/api/data');
147
- expect(options.attributes['cache.key']).not.toContain('secret');
148
- expect(options.attributes['cache.key']).not.toContain('token');
149
- });
150
-
151
- it('should add cache operation attributes', async () => {
152
- instrumentGlobalCache();
153
-
154
- const request = new Request('https://example.com/test');
155
- await caches.default.match(request);
156
-
157
- const options = mockTracer.startActiveSpan.mock.calls[0][1];
158
- expect(options.kind).toBe(SpanKind.CLIENT);
159
- expect(options.attributes['cache.name']).toBe('default');
160
- expect(options.attributes['cache.operation']).toBe('match');
161
- });
162
- });
163
-
164
- describe('cache.put() instrumentation', () => {
165
- it('should create span for cache.put()', async () => {
166
- instrumentGlobalCache();
167
-
168
- const request = new Request('https://example.com/test');
169
- const response = new Response('data');
170
- await caches.default.put(request, response);
171
-
172
- expect(mockTracer.startActiveSpan).toHaveBeenCalled();
173
-
174
- const spanName = mockTracer.startActiveSpan.mock.calls[0][0];
175
- expect(spanName).toBe('Cache default.put');
176
- });
177
-
178
- it('should add cache name and operation attributes', async () => {
179
- instrumentGlobalCache();
180
-
181
- const request = new Request('https://example.com/test');
182
- const response = new Response('data');
183
- await caches.default.put(request, response);
184
-
185
- const options = mockTracer.startActiveSpan.mock.calls[0][1];
186
- expect(options.attributes['cache.name']).toBe('default');
187
- expect(options.attributes['cache.operation']).toBe('put');
188
- });
189
-
190
- it('should handle errors in cache.put()', async () => {
191
- const errorCache = {
192
- ...globalThis.caches.default,
193
- put: vi.fn(async () => {
194
- throw new Error('Cache error');
195
- }),
196
- };
197
-
198
- (globalThis as any).caches = {
199
- default: errorCache,
200
- open: vi.fn(),
201
- };
202
-
203
- instrumentGlobalCache();
204
-
205
- const request = new Request('https://example.com/test');
206
- const response = new Response('data');
207
-
208
- await expect(caches.default.put(request, response)).rejects.toThrow('Cache error');
209
-
210
- expect(mockSpan.recordException).toHaveBeenCalled();
211
- expect(mockSpan.setStatus).toHaveBeenCalledWith({
212
- code: SpanStatusCode.ERROR,
213
- message: 'Cache error',
214
- });
215
- });
216
- });
217
-
218
- describe('cache.delete() instrumentation', () => {
219
- it('should create span for cache.delete()', async () => {
220
- instrumentGlobalCache();
221
-
222
- const request = new Request('https://example.com/test');
223
- await caches.default.delete(request);
224
-
225
- expect(mockTracer.startActiveSpan).toHaveBeenCalled();
226
-
227
- const spanName = mockTracer.startActiveSpan.mock.calls[0][0];
228
- expect(spanName).toBe('Cache default.delete');
229
- });
230
-
231
- it('should add cache operation attributes for delete', async () => {
232
- instrumentGlobalCache();
233
-
234
- const request = new Request('https://example.com/test');
235
- await caches.default.delete(request);
236
-
237
- const options = mockTracer.startActiveSpan.mock.calls[0][1];
238
- expect(options.attributes['cache.name']).toBe('default');
239
- expect(options.attributes['cache.operation']).toBe('delete');
240
- });
241
- });
242
-
243
- describe('caches.open() instrumentation', () => {
244
- it('should wrap caches.open() to instrument named caches', async () => {
245
- instrumentGlobalCache();
246
-
247
- const namedCache = await caches.open('my-cache');
248
-
249
- // After instrumentation, caches.open is wrapped
250
- // The key is that we can still call it and get a cache back
251
- expect(namedCache).toBeDefined();
252
- expect(typeof namedCache.match).toBe('function');
253
- });
254
-
255
- it('should instrument operations on named caches', async () => {
256
- instrumentGlobalCache();
257
-
258
- const namedCache = await caches.open('my-custom-cache');
259
- const request = new Request('https://example.com/test');
260
- await namedCache.match(request);
261
-
262
- expect(mockTracer.startActiveSpan).toHaveBeenCalled();
263
-
264
- const spanName = mockTracer.startActiveSpan.mock.calls[0][0];
265
- expect(spanName).toBe('Cache my-custom-cache.match');
266
- });
267
- });
268
-
269
- describe('Edge cases', () => {
270
- it('should handle string keys for match()', async () => {
271
- instrumentGlobalCache();
272
-
273
- // Some implementations allow string keys
274
- await caches.default.match('https://example.com/test');
275
-
276
- expect(mockTracer.startActiveSpan).toHaveBeenCalled();
277
-
278
- const options = mockTracer.startActiveSpan.mock.calls[0][1];
279
- expect(options.attributes['cache.key']).toBe('https://example.com/test');
280
- });
281
-
282
- it('should set OK status on successful operations', async () => {
283
- instrumentGlobalCache();
284
-
285
- const request = new Request('https://example.com/test');
286
- await caches.default.match(request);
287
-
288
- expect(mockSpan.setStatus).toHaveBeenCalledWith({ code: SpanStatusCode.OK });
289
- expect(mockSpan.end).toHaveBeenCalled();
290
- });
291
- });
292
- });