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,170 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
- import { trace, SpanStatusCode, SpanKind } from '@opentelemetry/api';
3
- import { instrumentAI } from './ai';
4
-
5
- describe('AI Binding Instrumentation', () => {
6
- let mockTracer: any;
7
- let mockSpan: any;
8
- let getTracerSpy: any;
9
- let mockAI: any;
10
-
11
- beforeEach(() => {
12
- mockSpan = {
13
- spanContext: () => ({
14
- traceId: 'test-trace-id',
15
- spanId: 'test-span-id',
16
- traceFlags: 1,
17
- }),
18
- setAttribute: vi.fn(),
19
- setAttributes: vi.fn(),
20
- setStatus: vi.fn(),
21
- recordException: vi.fn(),
22
- end: vi.fn(),
23
- isRecording: () => true,
24
- updateName: vi.fn(),
25
- addEvent: vi.fn(),
26
- };
27
-
28
- mockTracer = {
29
- startActiveSpan: vi.fn((name, options, fn) => {
30
- return fn(mockSpan);
31
- }),
32
- };
33
-
34
- getTracerSpy = vi.spyOn(trace, 'getTracer').mockReturnValue(mockTracer as any);
35
-
36
- mockAI = {
37
- run: vi.fn(async () => ({ response: 'Hello world' })),
38
- someOtherMethod: vi.fn(() => 'passthrough'),
39
- someProperty: 'test-value',
40
- };
41
- });
42
-
43
- afterEach(() => {
44
- getTracerSpy.mockRestore();
45
- });
46
-
47
- describe('instrumentAI()', () => {
48
- it('should wrap AI binding with proxy', () => {
49
- const instrumented = instrumentAI(mockAI);
50
-
51
- expect(instrumented).not.toBe(mockAI);
52
- expect(typeof instrumented.run).toBe('function');
53
- });
54
-
55
- it('should create span with correct name and attributes for run()', async () => {
56
- const instrumented = instrumentAI(mockAI, 'my-ai');
57
-
58
- await instrumented.run('@cf/meta/llama-2-7b-chat-int8', { prompt: 'Hello' });
59
-
60
- expect(mockTracer.startActiveSpan).toHaveBeenCalledTimes(1);
61
-
62
- const [spanName, options] = mockTracer.startActiveSpan.mock.calls[0];
63
- expect(spanName).toBe('AI my-ai: run @cf/meta/llama-2-7b-chat-int8');
64
- expect(options.kind).toBe(SpanKind.CLIENT);
65
- expect(options.attributes['gen_ai.provider.name']).toBe('cloudflare-workers-ai');
66
- expect(options.attributes['gen_ai.operation.name']).toBe('run');
67
- expect(options.attributes['gen_ai.request.model']).toBe('@cf/meta/llama-2-7b-chat-int8');
68
- });
69
-
70
- it('should use default binding name "ai" when no name is provided', async () => {
71
- const instrumented = instrumentAI(mockAI);
72
-
73
- await instrumented.run('@cf/meta/llama-2-7b-chat-int8', { prompt: 'Hello' });
74
-
75
- const spanName = mockTracer.startActiveSpan.mock.calls[0][0];
76
- expect(spanName).toBe('AI ai: run @cf/meta/llama-2-7b-chat-int8');
77
- });
78
-
79
- it('should record token usage when result has usage.prompt_tokens and usage.completion_tokens', async () => {
80
- mockAI.run = vi.fn(async () => ({
81
- response: 'Hello world',
82
- usage: {
83
- prompt_tokens: 10,
84
- completion_tokens: 25,
85
- },
86
- }));
87
-
88
- const instrumented = instrumentAI(mockAI);
89
-
90
- await instrumented.run('@cf/meta/llama-2-7b-chat-int8', { prompt: 'Hello' });
91
-
92
- expect(mockSpan.setAttribute).toHaveBeenCalledWith('gen_ai.usage.input_tokens', 10);
93
- expect(mockSpan.setAttribute).toHaveBeenCalledWith('gen_ai.usage.output_tokens', 25);
94
- expect(mockSpan.setStatus).toHaveBeenCalledWith({ code: SpanStatusCode.OK });
95
- expect(mockSpan.end).toHaveBeenCalled();
96
- });
97
-
98
- it('should NOT set token attributes when usage is not present', async () => {
99
- mockAI.run = vi.fn(async () => ({
100
- response: 'Hello world',
101
- }));
102
-
103
- const instrumented = instrumentAI(mockAI);
104
-
105
- await instrumented.run('@cf/meta/llama-2-7b-chat-int8', { prompt: 'Hello' });
106
-
107
- expect(mockSpan.setAttribute).not.toHaveBeenCalledWith(
108
- 'gen_ai.usage.input_tokens',
109
- expect.anything(),
110
- );
111
- expect(mockSpan.setAttribute).not.toHaveBeenCalledWith(
112
- 'gen_ai.usage.output_tokens',
113
- expect.anything(),
114
- );
115
- expect(mockSpan.setStatus).toHaveBeenCalledWith({ code: SpanStatusCode.OK });
116
- expect(mockSpan.end).toHaveBeenCalled();
117
- });
118
-
119
- it('should handle errors correctly', async () => {
120
- const testError = new Error('AI model failed');
121
- mockAI.run = vi.fn(async () => {
122
- throw testError;
123
- });
124
-
125
- const instrumented = instrumentAI(mockAI);
126
-
127
- await expect(
128
- instrumented.run('@cf/meta/llama-2-7b-chat-int8', { prompt: 'Hello' }),
129
- ).rejects.toThrow('AI model failed');
130
-
131
- expect(mockSpan.recordException).toHaveBeenCalledWith(testError);
132
- expect(mockSpan.setStatus).toHaveBeenCalledWith({
133
- code: SpanStatusCode.ERROR,
134
- message: 'AI model failed',
135
- });
136
- expect(mockSpan.end).toHaveBeenCalled();
137
- });
138
-
139
- it('should invoke run() with original object as this, not the proxy', async () => {
140
- let receivedThis: any;
141
- const mockAIObj = {
142
- run: vi.fn(async function(this: any) {
143
- // eslint-disable-next-line unicorn/no-this-assignment, @typescript-eslint/no-this-alias
144
- receivedThis = this;
145
- return { response: 'Hello' };
146
- }),
147
- };
148
- const instrumented = instrumentAI(mockAIObj as any, 'test');
149
- await instrumented.run('@cf/meta/llama-2-7b-chat-int8', { prompt: 'Hello' });
150
- expect(receivedThis).toBe(mockAIObj);
151
- });
152
-
153
- it('should pass through non-instrumented methods unchanged', () => {
154
- const instrumented = instrumentAI(mockAI);
155
-
156
- const result = instrumented.someOtherMethod();
157
-
158
- expect(result).toBe('passthrough');
159
- expect(mockAI.someOtherMethod).toHaveBeenCalled();
160
- expect(mockTracer.startActiveSpan).not.toHaveBeenCalled();
161
- });
162
-
163
- it('should pass through non-instrumented properties unchanged', () => {
164
- const instrumented = instrumentAI(mockAI);
165
-
166
- expect(instrumented.someProperty).toBe('test-value');
167
- expect(mockTracer.startActiveSpan).not.toHaveBeenCalled();
168
- });
169
- });
170
- });
@@ -1,73 +0,0 @@
1
- /**
2
- * Workers AI 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
- /**
14
- * Instrument Workers AI binding
15
- */
16
- export function instrumentAI<T extends Ai>(ai: T, bindingName?: string): T {
17
- const name = bindingName || 'ai';
18
-
19
- const handler: ProxyHandler<T> = {
20
- get(target, prop) {
21
- const value = Reflect.get(target, prop);
22
-
23
- if (prop === 'run' && typeof value === 'function') {
24
- return new Proxy(value, {
25
- apply: (fnTarget, _thisArg, args) => {
26
- const [model] = args as [string, unknown, unknown];
27
- const tracer = trace.getTracer('autotel-edge') as WorkerTracer;
28
-
29
- return tracer.startActiveSpan(
30
- `AI ${name}: run ${model}`,
31
- {
32
- kind: SpanKind.CLIENT,
33
- attributes: {
34
- // Canonical GenAI provider attribute (replaces deprecated
35
- // `gen_ai.system`).
36
- 'gen_ai.provider.name': 'cloudflare-workers-ai',
37
- 'gen_ai.operation.name': 'run',
38
- 'gen_ai.request.model': model,
39
- },
40
- },
41
- async (span) => {
42
- try {
43
- const result = await Reflect.apply(fnTarget, target, args);
44
- if (result?.usage?.prompt_tokens !== undefined) {
45
- setAttr(span, 'gen_ai.usage.input_tokens', Number(result.usage.prompt_tokens));
46
- }
47
- if (result?.usage?.completion_tokens !== undefined) {
48
- setAttr(span, 'gen_ai.usage.output_tokens', Number(result.usage.completion_tokens));
49
- }
50
- span.setStatus({ code: SpanStatusCode.OK });
51
- return result;
52
- } catch (error) {
53
- span.recordException(error as Error);
54
- span.setStatus({
55
- code: SpanStatusCode.ERROR,
56
- message: error instanceof Error ? error.message : String(error),
57
- });
58
- throw error;
59
- } finally {
60
- span.end();
61
- }
62
- },
63
- );
64
- },
65
- });
66
- }
67
-
68
- return value;
69
- },
70
- };
71
-
72
- return wrap(ai, handler);
73
- }
@@ -1,175 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
- import { instrumentAnalyticsEngine } from './analytics-engine';
3
- import { trace, SpanStatusCode, SpanKind } from '@opentelemetry/api';
4
-
5
- describe('Analytics Engine Instrumentation', () => {
6
- let mockTracer: any;
7
- let mockSpan: any;
8
- let getTracerSpy: any;
9
- let mockAE: any;
10
-
11
- beforeEach(() => {
12
- mockSpan = {
13
- spanContext: () => ({
14
- traceId: 'test-trace-id',
15
- spanId: 'test-span-id',
16
- traceFlags: 1,
17
- }),
18
- setAttribute: vi.fn(),
19
- setAttributes: vi.fn(),
20
- setStatus: vi.fn(),
21
- recordException: vi.fn(),
22
- end: vi.fn(),
23
- isRecording: () => true,
24
- updateName: vi.fn(),
25
- addEvent: vi.fn(),
26
- };
27
-
28
- mockTracer = {
29
- startActiveSpan: vi.fn((name, options, fn) => {
30
- return fn(mockSpan);
31
- }),
32
- };
33
-
34
- getTracerSpy = vi.spyOn(trace, 'getTracer').mockReturnValue(mockTracer as any);
35
-
36
- mockAE = {
37
- writeDataPoint: vi.fn(),
38
- someOtherMethod: vi.fn(() => 'passthrough-value'),
39
- };
40
- });
41
-
42
- afterEach(() => {
43
- getTracerSpy.mockRestore();
44
- });
45
-
46
- describe('writeDataPoint()', () => {
47
- it('should create span with correct attributes', () => {
48
- const instrumented = instrumentAnalyticsEngine(mockAE, 'my-dataset');
49
-
50
- instrumented.writeDataPoint({
51
- indexes: ['idx1'],
52
- doubles: [1, 2],
53
- blobs: ['blob1'],
54
- });
55
-
56
- expect(mockTracer.startActiveSpan).toHaveBeenCalledTimes(1);
57
-
58
- const [spanName, spanOptions] = mockTracer.startActiveSpan.mock.calls[0];
59
- expect(spanName).toBe('AnalyticsEngine my-dataset: writeDataPoint');
60
- expect(spanOptions.kind).toBe(SpanKind.CLIENT);
61
- expect(spanOptions.attributes['analytics.system']).toBe('cloudflare-analytics-engine');
62
- expect(spanOptions.attributes['analytics.operation']).toBe('writeDataPoint');
63
- });
64
-
65
- it('should record indexes_count, doubles_count, blobs_count', () => {
66
- const instrumented = instrumentAnalyticsEngine(mockAE, 'my-dataset');
67
-
68
- instrumented.writeDataPoint({
69
- indexes: ['idx1', 'idx2'],
70
- doubles: [1, 2, 3],
71
- blobs: ['blob1'],
72
- });
73
-
74
- const spanOptions = mockTracer.startActiveSpan.mock.calls[0][1];
75
- expect(spanOptions.attributes['analytics.indexes_count']).toBe(2);
76
- expect(spanOptions.attributes['analytics.doubles_count']).toBe(3);
77
- expect(spanOptions.attributes['analytics.blobs_count']).toBe(1);
78
- });
79
-
80
- it('should handle a single index (non-array) by recording indexes_count as 1', () => {
81
- const instrumented = instrumentAnalyticsEngine(mockAE, 'my-dataset');
82
-
83
- instrumented.writeDataPoint({
84
- indexes: 'single-index' as any,
85
- });
86
-
87
- const spanOptions = mockTracer.startActiveSpan.mock.calls[0][1];
88
- expect(spanOptions.attributes['analytics.indexes_count']).toBe(1);
89
- });
90
-
91
- it('should work with no datapoint argument', () => {
92
- const instrumented = instrumentAnalyticsEngine(mockAE);
93
-
94
- instrumented.writeDataPoint(undefined as any);
95
-
96
- expect(mockTracer.startActiveSpan).toHaveBeenCalledTimes(1);
97
-
98
- const spanOptions = mockTracer.startActiveSpan.mock.calls[0][1];
99
- expect(spanOptions.attributes['analytics.system']).toBe('cloudflare-analytics-engine');
100
- expect(spanOptions.attributes['analytics.operation']).toBe('writeDataPoint');
101
- // No count attributes should be set when no datapoint
102
- expect(spanOptions.attributes['analytics.indexes_count']).toBeUndefined();
103
- expect(spanOptions.attributes['analytics.doubles_count']).toBeUndefined();
104
- expect(spanOptions.attributes['analytics.blobs_count']).toBeUndefined();
105
-
106
- expect(mockSpan.setStatus).toHaveBeenCalledWith({ code: SpanStatusCode.OK });
107
- expect(mockSpan.end).toHaveBeenCalled();
108
- });
109
-
110
- it('should handle errors by recording exception and rethrowing', () => {
111
- const error = new Error('writeDataPoint failed');
112
- mockAE.writeDataPoint = vi.fn(() => {
113
- throw error;
114
- });
115
-
116
- const instrumented = instrumentAnalyticsEngine(mockAE, 'my-dataset');
117
-
118
- expect(() => instrumented.writeDataPoint({ indexes: ['idx1'] })).toThrow('writeDataPoint failed');
119
-
120
- expect(mockSpan.recordException).toHaveBeenCalledWith(error);
121
- expect(mockSpan.setStatus).toHaveBeenCalledWith({
122
- code: SpanStatusCode.ERROR,
123
- message: 'writeDataPoint failed',
124
- });
125
- expect(mockSpan.end).toHaveBeenCalled();
126
- });
127
-
128
- it('should use default dataset name when none provided', () => {
129
- const instrumented = instrumentAnalyticsEngine(mockAE);
130
-
131
- instrumented.writeDataPoint({ indexes: ['idx1'] });
132
-
133
- const spanName = mockTracer.startActiveSpan.mock.calls[0][0];
134
- expect(spanName).toBe('AnalyticsEngine analytics-engine: writeDataPoint');
135
- });
136
-
137
- it('should set OK status and end span on success', () => {
138
- const instrumented = instrumentAnalyticsEngine(mockAE, 'my-dataset');
139
-
140
- instrumented.writeDataPoint({ doubles: [42] });
141
-
142
- expect(mockSpan.setStatus).toHaveBeenCalledWith({ code: SpanStatusCode.OK });
143
- expect(mockSpan.end).toHaveBeenCalled();
144
- expect(mockAE.writeDataPoint).toHaveBeenCalledWith({ doubles: [42] });
145
- });
146
- });
147
-
148
- describe('this-binding', () => {
149
- it('should invoke writeDataPoint() with original object as this, not the proxy', () => {
150
- let receivedThis: any;
151
- const mockAEObj = {
152
- writeDataPoint: vi.fn(function(this: any) {
153
- // eslint-disable-next-line unicorn/no-this-assignment, @typescript-eslint/no-this-alias
154
- receivedThis = this;
155
- }),
156
- };
157
- const instrumented = instrumentAnalyticsEngine(mockAEObj as any, 'test');
158
- instrumented.writeDataPoint({ indexes: ['idx1'] });
159
- expect(receivedThis).toBe(mockAEObj);
160
- });
161
- });
162
-
163
- describe('Non-instrumented methods', () => {
164
- it('should pass through non-instrumented methods unchanged', () => {
165
- const instrumented = instrumentAnalyticsEngine(mockAE, 'my-dataset');
166
-
167
- const result = instrumented.someOtherMethod();
168
-
169
- expect(result).toBe('passthrough-value');
170
- expect(mockAE.someOtherMethod).toHaveBeenCalled();
171
- // No span should be created for non-instrumented methods
172
- expect(mockTracer.startActiveSpan).not.toHaveBeenCalled();
173
- });
174
- });
175
- });
@@ -1,78 +0,0 @@
1
- /**
2
- * Analytics Engine 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 } from './common';
12
-
13
- /**
14
- * Instrument Analytics Engine binding
15
- */
16
- export function instrumentAnalyticsEngine<T extends AnalyticsEngineDataset>(ae: T, datasetName?: string): T {
17
- const name = datasetName || 'analytics-engine';
18
-
19
- const handler: ProxyHandler<T> = {
20
- get(target, prop) {
21
- const value = Reflect.get(target, prop);
22
-
23
- if (prop === 'writeDataPoint' && typeof value === 'function') {
24
- return new Proxy(value, {
25
- apply: (fnTarget, _thisArg, args) => {
26
- const [dataPoint] = args as [AnalyticsEngineDataPoint | undefined];
27
- const tracer = trace.getTracer('autotel-edge') as WorkerTracer;
28
-
29
- const attributes: Record<string, string | number> = {
30
- 'analytics.system': 'cloudflare-analytics-engine',
31
- 'analytics.operation': 'writeDataPoint',
32
- };
33
-
34
- if (dataPoint) {
35
- if (dataPoint.indexes) {
36
- attributes['analytics.indexes_count'] = Array.isArray(dataPoint.indexes) ? dataPoint.indexes.length : 1;
37
- }
38
- if (dataPoint.doubles) {
39
- attributes['analytics.doubles_count'] = dataPoint.doubles.length;
40
- }
41
- if (dataPoint.blobs) {
42
- attributes['analytics.blobs_count'] = dataPoint.blobs.length;
43
- }
44
- }
45
-
46
- return tracer.startActiveSpan(
47
- `AnalyticsEngine ${name}: writeDataPoint`,
48
- {
49
- kind: SpanKind.CLIENT,
50
- attributes,
51
- },
52
- (span) => {
53
- try {
54
- // writeDataPoint is synchronous/void
55
- Reflect.apply(fnTarget, target, args);
56
- span.setStatus({ code: SpanStatusCode.OK });
57
- } catch (error) {
58
- span.recordException(error as Error);
59
- span.setStatus({
60
- code: SpanStatusCode.ERROR,
61
- message: error instanceof Error ? error.message : String(error),
62
- });
63
- throw error;
64
- } finally {
65
- span.end();
66
- }
67
- },
68
- );
69
- },
70
- });
71
- }
72
-
73
- return value;
74
- },
75
- };
76
-
77
- return wrap(ae, handler);
78
- }
@@ -1,80 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
- import { trace } from '@opentelemetry/api';
3
- import { instrumentBindings } from './bindings';
4
- import { isWrapped } from './common';
5
-
6
- describe('instrumentBindings() caching', () => {
7
- let mockTracer: any;
8
- let mockSpan: any;
9
- let getTracerSpy: any;
10
-
11
- beforeEach(() => {
12
- mockSpan = {
13
- spanContext: () => ({
14
- traceId: 'test-trace-id',
15
- spanId: 'test-span-id',
16
- traceFlags: 1,
17
- }),
18
- setAttribute: vi.fn(),
19
- setAttributes: vi.fn(),
20
- setStatus: vi.fn(),
21
- recordException: vi.fn(),
22
- end: vi.fn(),
23
- isRecording: () => true,
24
- updateName: vi.fn(),
25
- addEvent: vi.fn(),
26
- };
27
-
28
- mockTracer = {
29
- startActiveSpan: vi.fn((name, options, fn) => {
30
- return fn(mockSpan);
31
- }),
32
- };
33
-
34
- getTracerSpy = vi.spyOn(trace, 'getTracer').mockReturnValue(mockTracer as any);
35
- });
36
-
37
- afterEach(() => {
38
- getTracerSpy.mockRestore();
39
- });
40
-
41
- it('should return the same instrumented object for the same env reference', () => {
42
- const env = {
43
- MY_KV: { get: vi.fn(), put: vi.fn(), delete: vi.fn(), list: vi.fn() },
44
- };
45
-
46
- const first = instrumentBindings(env);
47
- const second = instrumentBindings(env);
48
-
49
- expect(first).toBe(second);
50
- });
51
-
52
- it('should return different instrumented objects for different env references', () => {
53
- const env1 = {
54
- MY_KV: { get: vi.fn(), put: vi.fn(), delete: vi.fn(), list: vi.fn() },
55
- };
56
- const env2 = {
57
- MY_KV: { get: vi.fn(), put: vi.fn(), delete: vi.fn(), list: vi.fn() },
58
- };
59
-
60
- const first = instrumentBindings(env1);
61
- const second = instrumentBindings(env2);
62
-
63
- expect(first).not.toBe(second);
64
- });
65
-
66
- it('should correctly instrument bindings even when returning from cache', () => {
67
- const env = {
68
- MY_KV: { get: vi.fn(), put: vi.fn(), delete: vi.fn(), list: vi.fn() },
69
- API_KEY: 'secret',
70
- };
71
-
72
- const first = instrumentBindings(env);
73
- const second = instrumentBindings(env);
74
-
75
- // Cached result should have instrumented bindings
76
- expect(isWrapped(second.MY_KV)).toBe(true);
77
- // Non-object values pass through
78
- expect(second.API_KEY).toBe('secret');
79
- });
80
- });