autotel-cloudflare 3.0.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/dist/agents.d.ts +626 -123
  2. package/dist/agents.d.ts.map +1 -1
  3. package/dist/agents.js +260 -171
  4. package/dist/agents.js.map +1 -1
  5. package/package.json +8 -4
  6. package/src/actors/alarms.ts +0 -225
  7. package/src/actors/index.ts +0 -36
  8. package/src/actors/instrument-actor.test.ts +0 -179
  9. package/src/actors/instrument-actor.ts +0 -574
  10. package/src/actors/sockets.ts +0 -217
  11. package/src/actors/storage.ts +0 -263
  12. package/src/actors/traced-handler.ts +0 -300
  13. package/src/actors/types.ts +0 -98
  14. package/src/actors.ts +0 -50
  15. package/src/agents/index.ts +0 -42
  16. package/src/agents/otel-observability.test.ts +0 -336
  17. package/src/agents/otel-observability.ts +0 -474
  18. package/src/agents/types.ts +0 -167
  19. package/src/agents.ts +0 -76
  20. package/src/bindings/ai.test.ts +0 -170
  21. package/src/bindings/ai.ts +0 -73
  22. package/src/bindings/analytics-engine.test.ts +0 -175
  23. package/src/bindings/analytics-engine.ts +0 -78
  24. package/src/bindings/bindings-cache.test.ts +0 -80
  25. package/src/bindings/bindings-detection.test.ts +0 -235
  26. package/src/bindings/bindings-this-binding.test.ts +0 -294
  27. package/src/bindings/bindings.ts +0 -720
  28. package/src/bindings/browser-rendering.test.ts +0 -160
  29. package/src/bindings/browser-rendering.ts +0 -70
  30. package/src/bindings/common.ts +0 -84
  31. package/src/bindings/hyperdrive.test.ts +0 -176
  32. package/src/bindings/hyperdrive.ts +0 -74
  33. package/src/bindings/images.test.ts +0 -262
  34. package/src/bindings/images.ts +0 -182
  35. package/src/bindings/index.ts +0 -20
  36. package/src/bindings/queue-producer.test.ts +0 -224
  37. package/src/bindings/queue-producer.ts +0 -105
  38. package/src/bindings/rate-limiter.test.ts +0 -140
  39. package/src/bindings/rate-limiter.ts +0 -69
  40. package/src/bindings/vectorize.test.ts +0 -362
  41. package/src/bindings/vectorize.ts +0 -86
  42. package/src/bindings.ts +0 -6
  43. package/src/events.ts +0 -6
  44. package/src/execution-logger.test.ts +0 -127
  45. package/src/execution-logger.ts +0 -112
  46. package/src/global/cache.test.ts +0 -292
  47. package/src/global/cache.ts +0 -164
  48. package/src/global/fetch.test.ts +0 -399
  49. package/src/global/fetch.ts +0 -136
  50. package/src/global/index.ts +0 -7
  51. package/src/handlers/durable-objects.test.ts +0 -524
  52. package/src/handlers/durable-objects.ts +0 -250
  53. package/src/handlers/index.ts +0 -6
  54. package/src/handlers/workflows.test.ts +0 -411
  55. package/src/handlers/workflows.ts +0 -345
  56. package/src/handlers.ts +0 -6
  57. package/src/index.ts +0 -91
  58. package/src/logger.ts +0 -15
  59. package/src/native/native-tracing.test.ts +0 -54
  60. package/src/native/native-tracing.ts +0 -83
  61. package/src/native.ts +0 -12
  62. package/src/parse-error.ts +0 -1
  63. package/src/sampling.ts +0 -6
  64. package/src/testing.ts +0 -6
  65. package/src/wrappers/cf-attributes.test.ts +0 -334
  66. package/src/wrappers/define-worker-fetch.test.ts +0 -102
  67. package/src/wrappers/define-worker-fetch.ts +0 -71
  68. package/src/wrappers/index.ts +0 -13
  69. package/src/wrappers/instrument.integration.test.ts +0 -578
  70. package/src/wrappers/instrument.ts +0 -806
  71. package/src/wrappers/native-instrument.test.ts +0 -153
  72. package/src/wrappers/wrap-do.ts +0 -34
  73. 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
- });