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,105 +0,0 @@
1
- /**
2
- * Queue producer 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 Queue producer binding
15
- */
16
- export function instrumentQueueProducer<T extends Queue>(queue: T, queueName?: string): T {
17
- const name = queueName || 'queue';
18
-
19
- const handler: ProxyHandler<T> = {
20
- get(target, prop) {
21
- const value = Reflect.get(target, prop);
22
-
23
- if (prop === 'send' && typeof value === 'function') {
24
- return new Proxy(value, {
25
- apply: (fnTarget, _thisArg, args) => {
26
- const tracer = trace.getTracer('autotel-edge') as WorkerTracer;
27
-
28
- return tracer.startActiveSpan(
29
- `Queue ${name}: send`,
30
- {
31
- kind: SpanKind.PRODUCER,
32
- attributes: {
33
- 'messaging.system': 'cloudflare-queues',
34
- 'messaging.operation.type': 'publish',
35
- 'messaging.operation': 'send',
36
- 'messaging.destination.name': name,
37
- },
38
- },
39
- async (span) => {
40
- try {
41
- const result = await Reflect.apply(fnTarget, target, args);
42
- setAttr(span, 'messaging.message.id', (result as any)?.messageId);
43
- span.setStatus({ code: SpanStatusCode.OK });
44
- return result;
45
- } catch (error) {
46
- span.recordException(error as Error);
47
- span.setStatus({
48
- code: SpanStatusCode.ERROR,
49
- message: error instanceof Error ? error.message : String(error),
50
- });
51
- throw error;
52
- } finally {
53
- span.end();
54
- }
55
- },
56
- );
57
- },
58
- });
59
- }
60
-
61
- if (prop === 'sendBatch' && typeof value === 'function') {
62
- return new Proxy(value, {
63
- apply: (fnTarget, _thisArg, args) => {
64
- const [messages] = args as [{ body: unknown }[]];
65
- const tracer = trace.getTracer('autotel-edge') as WorkerTracer;
66
-
67
- return tracer.startActiveSpan(
68
- `Queue ${name}: sendBatch`,
69
- {
70
- kind: SpanKind.PRODUCER,
71
- attributes: {
72
- 'messaging.system': 'cloudflare-queues',
73
- 'messaging.operation.type': 'publish',
74
- 'messaging.operation': 'sendBatch',
75
- 'messaging.destination.name': name,
76
- 'messaging.batch.message_count': Array.isArray(messages) ? messages.length : 0,
77
- },
78
- },
79
- async (span) => {
80
- try {
81
- const result = await Reflect.apply(fnTarget, target, args);
82
- span.setStatus({ code: SpanStatusCode.OK });
83
- return result;
84
- } catch (error) {
85
- span.recordException(error as Error);
86
- span.setStatus({
87
- code: SpanStatusCode.ERROR,
88
- message: error instanceof Error ? error.message : String(error),
89
- });
90
- throw error;
91
- } finally {
92
- span.end();
93
- }
94
- },
95
- );
96
- },
97
- });
98
- }
99
-
100
- return value;
101
- },
102
- };
103
-
104
- return wrap(queue, handler);
105
- }
@@ -1,140 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
- import { instrumentRateLimiter } from './rate-limiter';
3
- import { trace, SpanStatusCode, SpanKind } from '@opentelemetry/api';
4
-
5
- describe('Rate Limiter Instrumentation', () => {
6
- let mockTracer: any;
7
- let mockSpan: any;
8
- let getTracerSpy: any;
9
- let mockLimiter: 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
- mockLimiter = {
37
- limit: vi.fn(async () => ({ success: true })),
38
- someOtherMethod: vi.fn(() => 'passthrough-value'),
39
- };
40
- });
41
-
42
- afterEach(() => {
43
- getTracerSpy.mockRestore();
44
- });
45
-
46
- describe('limit()', () => {
47
- it('should create span with correct attributes', async () => {
48
- const instrumented = instrumentRateLimiter(mockLimiter, 'my-limiter');
49
-
50
- await instrumented.limit({ key: 'user-123' });
51
-
52
- expect(mockTracer.startActiveSpan).toHaveBeenCalledTimes(1);
53
-
54
- const [spanName, spanOptions] = mockTracer.startActiveSpan.mock.calls[0];
55
- expect(spanName).toBe('RateLimiter my-limiter: limit');
56
- expect(spanOptions.kind).toBe(SpanKind.CLIENT);
57
- expect(spanOptions.attributes['rate_limiter.system']).toBe('cloudflare-rate-limiter');
58
- expect(spanOptions.attributes['rate_limiter.key']).toBe('user-123');
59
- });
60
-
61
- it('should record success from result', async () => {
62
- const instrumented = instrumentRateLimiter(mockLimiter, 'my-limiter');
63
-
64
- await instrumented.limit({ key: 'user-123' });
65
-
66
- expect(mockSpan.setAttribute).toHaveBeenCalledWith('rate_limiter.success', true);
67
- expect(mockSpan.setStatus).toHaveBeenCalledWith({ code: SpanStatusCode.OK });
68
- expect(mockSpan.end).toHaveBeenCalled();
69
- });
70
-
71
- it('should record success=false when rate limited', async () => {
72
- mockLimiter.limit = vi.fn(async () => ({ success: false }));
73
-
74
- const instrumented = instrumentRateLimiter(mockLimiter, 'my-limiter');
75
-
76
- const result = await instrumented.limit({ key: 'user-456' });
77
-
78
- expect(result.success).toBe(false);
79
- expect(mockSpan.setAttribute).toHaveBeenCalledWith('rate_limiter.success', false);
80
- expect(mockSpan.setStatus).toHaveBeenCalledWith({ code: SpanStatusCode.OK });
81
- expect(mockSpan.end).toHaveBeenCalled();
82
- });
83
-
84
- it('should handle errors by recording exception and rethrowing', async () => {
85
- const error = new Error('Rate limiter unavailable');
86
- mockLimiter.limit = vi.fn(async () => {
87
- throw error;
88
- });
89
-
90
- const instrumented = instrumentRateLimiter(mockLimiter, 'my-limiter');
91
-
92
- await expect(instrumented.limit({ key: 'user-789' })).rejects.toThrow('Rate limiter unavailable');
93
-
94
- expect(mockSpan.recordException).toHaveBeenCalledWith(error);
95
- expect(mockSpan.setStatus).toHaveBeenCalledWith({
96
- code: SpanStatusCode.ERROR,
97
- message: 'Rate limiter unavailable',
98
- });
99
- expect(mockSpan.end).toHaveBeenCalled();
100
- });
101
-
102
- it('should use default binding name when none provided', async () => {
103
- const instrumented = instrumentRateLimiter(mockLimiter);
104
-
105
- await instrumented.limit({ key: 'user-123' });
106
-
107
- const spanName = mockTracer.startActiveSpan.mock.calls[0][0];
108
- expect(spanName).toBe('RateLimiter rate-limiter: limit');
109
- });
110
- });
111
-
112
- describe('this-binding', () => {
113
- it('should invoke limit() with original object as this, not the proxy', async () => {
114
- let receivedThis: any;
115
- const mockLim = {
116
- limit: vi.fn(async function(this: any) {
117
- // eslint-disable-next-line unicorn/no-this-assignment, @typescript-eslint/no-this-alias
118
- receivedThis = this;
119
- return { success: true };
120
- }),
121
- };
122
- const instrumented = instrumentRateLimiter(mockLim, 'test');
123
- await instrumented.limit({ key: 'user-123' });
124
- expect(receivedThis).toBe(mockLim);
125
- });
126
- });
127
-
128
- describe('Non-instrumented methods', () => {
129
- it('should pass through non-instrumented methods unchanged', () => {
130
- const instrumented = instrumentRateLimiter(mockLimiter, 'my-limiter');
131
-
132
- const result = instrumented.someOtherMethod();
133
-
134
- expect(result).toBe('passthrough-value');
135
- expect(mockLimiter.someOtherMethod).toHaveBeenCalled();
136
- // No span should be created for non-instrumented methods
137
- expect(mockTracer.startActiveSpan).not.toHaveBeenCalled();
138
- });
139
- });
140
- });
@@ -1,69 +0,0 @@
1
- /**
2
- * Rate Limiter 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
- interface RateLimiterLike {
14
- limit(options: { key: string }): Promise<{ success: boolean }>;
15
- }
16
-
17
- /**
18
- * Instrument Rate Limiter binding (manual only — not auto-detected)
19
- */
20
- export function instrumentRateLimiter<T extends RateLimiterLike>(limiter: T, bindingName?: string): T {
21
- const name = bindingName || 'rate-limiter';
22
-
23
- const handler: ProxyHandler<T> = {
24
- get(target, prop) {
25
- const value = Reflect.get(target, prop);
26
-
27
- if (prop === 'limit' && typeof value === 'function') {
28
- return new Proxy(value, {
29
- apply: (fnTarget, _thisArg, args) => {
30
- const [options] = args as [{ key: string }];
31
- const tracer = trace.getTracer('autotel-edge') as WorkerTracer;
32
-
33
- return tracer.startActiveSpan(
34
- `RateLimiter ${name}: limit`,
35
- {
36
- kind: SpanKind.CLIENT,
37
- attributes: {
38
- 'rate_limiter.system': 'cloudflare-rate-limiter',
39
- 'rate_limiter.key': options?.key,
40
- },
41
- },
42
- async (span) => {
43
- try {
44
- const result = await Reflect.apply(fnTarget, target, args);
45
- setAttr(span, 'rate_limiter.success', result?.success);
46
- span.setStatus({ code: SpanStatusCode.OK });
47
- return result;
48
- } catch (error) {
49
- span.recordException(error as Error);
50
- span.setStatus({
51
- code: SpanStatusCode.ERROR,
52
- message: error instanceof Error ? error.message : String(error),
53
- });
54
- throw error;
55
- } finally {
56
- span.end();
57
- }
58
- },
59
- );
60
- },
61
- });
62
- }
63
-
64
- return value;
65
- },
66
- };
67
-
68
- return wrap(limiter, handler);
69
- }
@@ -1,362 +0,0 @@
1
- import { describe, it, expect, beforeEach, vi } from 'vitest';
2
- import { trace, SpanStatusCode, SpanKind } from '@opentelemetry/api';
3
- import { instrumentVectorize } from './vectorize';
4
-
5
- describe('Vectorize Binding Instrumentation', () => {
6
- let mockTracer: any;
7
- let mockSpan: any;
8
- let getTracerSpy: any;
9
- let mockVectorize: 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
- mockVectorize = {
37
- query: vi.fn(async () => ({
38
- matches: [
39
- { id: 'vec-1', score: 0.95 },
40
- { id: 'vec-2', score: 0.87 },
41
- { id: 'vec-3', score: 0.72 },
42
- ],
43
- count: 3,
44
- })),
45
- insert: vi.fn(async () => ({ mutationId: 'mut-1', count: 2 })),
46
- upsert: vi.fn(async () => ({ mutationId: 'mut-2', count: 3 })),
47
- deleteByIds: vi.fn(async () => ({ mutationId: 'mut-3', count: 1 })),
48
- getByIds: vi.fn(async () => [{ id: 'vec-1', values: [0.1, 0.2] }]),
49
- describe: vi.fn(async () => ({
50
- dimensions: 128,
51
- vectorCount: 1000,
52
- processedUpTo: 'ts-123',
53
- })),
54
- // Non-instrumented method
55
- toString: vi.fn(() => 'VectorizeIndex'),
56
- } as unknown as VectorizeIndex;
57
- });
58
-
59
- describe('query()', () => {
60
- it('should create span with correct attributes', async () => {
61
- const instrumented = instrumentVectorize(mockVectorize, 'my-index');
62
-
63
- // The source reads topK from args[0], so we pass a query object as the first argument
64
- await instrumented.query({ topK: 5 } as any, {} as any);
65
-
66
- expect(mockTracer.startActiveSpan).toHaveBeenCalledWith(
67
- 'Vectorize my-index: query',
68
- expect.objectContaining({
69
- kind: SpanKind.CLIENT,
70
- attributes: expect.objectContaining({
71
- 'db.system': 'cloudflare-vectorize',
72
- 'db.operation': 'query',
73
- 'db.collection.name': 'my-index',
74
- 'db.vectorize.top_k': 5,
75
- }),
76
- }),
77
- expect.any(Function),
78
- );
79
- });
80
-
81
- it('should record matches_count from result', async () => {
82
- const instrumented = instrumentVectorize(mockVectorize, 'my-index');
83
-
84
- await instrumented.query([0.1, 0.2, 0.3] as any, {} as any);
85
-
86
- expect(mockSpan.setAttribute).toHaveBeenCalledWith('db.vectorize.matches_count', 3);
87
- expect(mockSpan.setStatus).toHaveBeenCalledWith({ code: SpanStatusCode.OK });
88
- expect(mockSpan.end).toHaveBeenCalled();
89
- });
90
-
91
- it('should handle query without topK in first argument', async () => {
92
- const instrumented = instrumentVectorize(mockVectorize, 'my-index');
93
-
94
- await instrumented.query([0.1, 0.2, 0.3] as any, {} as any);
95
-
96
- const attributes = mockTracer.startActiveSpan.mock.calls[0][1].attributes;
97
- expect(attributes['db.vectorize.top_k']).toBeUndefined();
98
- });
99
- });
100
-
101
- describe('insert()', () => {
102
- it('should set vectors_count from input array length', async () => {
103
- const instrumented = instrumentVectorize(mockVectorize, 'my-index');
104
-
105
- const vectors = [
106
- { id: 'vec-1', values: [0.1, 0.2] },
107
- { id: 'vec-2', values: [0.3, 0.4] },
108
- ];
109
- await instrumented.insert(vectors as any);
110
-
111
- expect(mockTracer.startActiveSpan).toHaveBeenCalledWith(
112
- 'Vectorize my-index: insert',
113
- expect.objectContaining({
114
- kind: SpanKind.CLIENT,
115
- attributes: expect.objectContaining({
116
- 'db.system': 'cloudflare-vectorize',
117
- 'db.operation': 'insert',
118
- 'db.collection.name': 'my-index',
119
- 'db.vectorize.vectors_count': 2,
120
- }),
121
- }),
122
- expect.any(Function),
123
- );
124
-
125
- expect(mockSpan.setStatus).toHaveBeenCalledWith({ code: SpanStatusCode.OK });
126
- expect(mockSpan.end).toHaveBeenCalled();
127
- });
128
- });
129
-
130
- describe('upsert()', () => {
131
- it('should set vectors_count from input array length', async () => {
132
- const instrumented = instrumentVectorize(mockVectorize, 'my-index');
133
-
134
- const vectors = [
135
- { id: 'vec-1', values: [0.1, 0.2] },
136
- { id: 'vec-2', values: [0.3, 0.4] },
137
- { id: 'vec-3', values: [0.5, 0.6] },
138
- ];
139
- await instrumented.upsert(vectors as any);
140
-
141
- expect(mockTracer.startActiveSpan).toHaveBeenCalledWith(
142
- 'Vectorize my-index: upsert',
143
- expect.objectContaining({
144
- kind: SpanKind.CLIENT,
145
- attributes: expect.objectContaining({
146
- 'db.system': 'cloudflare-vectorize',
147
- 'db.operation': 'upsert',
148
- 'db.collection.name': 'my-index',
149
- 'db.vectorize.vectors_count': 3,
150
- }),
151
- }),
152
- expect.any(Function),
153
- );
154
-
155
- expect(mockSpan.setStatus).toHaveBeenCalledWith({ code: SpanStatusCode.OK });
156
- expect(mockSpan.end).toHaveBeenCalled();
157
- });
158
- });
159
-
160
- describe('deleteByIds()', () => {
161
- it('should create correct span', async () => {
162
- const instrumented = instrumentVectorize(mockVectorize, 'my-index');
163
-
164
- await instrumented.deleteByIds(['vec-1', 'vec-2']);
165
-
166
- expect(mockTracer.startActiveSpan).toHaveBeenCalledWith(
167
- 'Vectorize my-index: deleteByIds',
168
- expect.objectContaining({
169
- kind: SpanKind.CLIENT,
170
- attributes: expect.objectContaining({
171
- 'db.system': 'cloudflare-vectorize',
172
- 'db.operation': 'deleteByIds',
173
- 'db.collection.name': 'my-index',
174
- }),
175
- }),
176
- expect.any(Function),
177
- );
178
-
179
- expect(mockSpan.setStatus).toHaveBeenCalledWith({ code: SpanStatusCode.OK });
180
- expect(mockSpan.end).toHaveBeenCalled();
181
- });
182
- });
183
-
184
- describe('describe()', () => {
185
- it('should create correct span', async () => {
186
- const instrumented = instrumentVectorize(mockVectorize, 'my-index');
187
-
188
- await instrumented.describe();
189
-
190
- expect(mockTracer.startActiveSpan).toHaveBeenCalledWith(
191
- 'Vectorize my-index: describe',
192
- expect.objectContaining({
193
- kind: SpanKind.CLIENT,
194
- attributes: expect.objectContaining({
195
- 'db.system': 'cloudflare-vectorize',
196
- 'db.operation': 'describe',
197
- 'db.collection.name': 'my-index',
198
- }),
199
- }),
200
- expect.any(Function),
201
- );
202
-
203
- expect(mockSpan.setStatus).toHaveBeenCalledWith({ code: SpanStatusCode.OK });
204
- expect(mockSpan.end).toHaveBeenCalled();
205
- });
206
- });
207
-
208
- describe('this-binding', () => {
209
- it('should invoke methods with original object as this, not the proxy', async () => {
210
- let receivedThis: any;
211
- const mockVec = {
212
- query: vi.fn(async function(this: any) {
213
- // eslint-disable-next-line unicorn/no-this-assignment, @typescript-eslint/no-this-alias
214
- receivedThis = this;
215
- return { matches: [], count: 0 };
216
- }),
217
- insert: vi.fn(async () => ({ mutationId: 'mut-1', count: 0 })),
218
- upsert: vi.fn(async () => ({ mutationId: 'mut-2', count: 0 })),
219
- deleteByIds: vi.fn(async () => ({ mutationId: 'mut-3', count: 0 })),
220
- getByIds: vi.fn(async () => []),
221
- describe: vi.fn(async () => ({ dimensions: 128, vectorCount: 0, processedUpTo: '' })),
222
- } as unknown as VectorizeIndex;
223
-
224
- const instrumented = instrumentVectorize(mockVec, 'test');
225
- await instrumented.query([0.1, 0.2] as any, {} as any);
226
- expect(receivedThis).toBe(mockVec);
227
- });
228
- });
229
-
230
- describe('Error handling', () => {
231
- it('should record exception and set error status on query() failure', async () => {
232
- mockVectorize.query = vi.fn(async () => {
233
- throw new Error('Vectorize query failed');
234
- });
235
-
236
- const instrumented = instrumentVectorize(mockVectorize, 'my-index');
237
-
238
- await expect(instrumented.query([0.1, 0.2] as any, {} as any)).rejects.toThrow('Vectorize query failed');
239
-
240
- expect(mockSpan.recordException).toHaveBeenCalled();
241
- expect(mockSpan.setStatus).toHaveBeenCalledWith({
242
- code: SpanStatusCode.ERROR,
243
- message: 'Vectorize query failed',
244
- });
245
- expect(mockSpan.end).toHaveBeenCalled();
246
- });
247
-
248
- it('should record exception and set error status on insert() failure', async () => {
249
- mockVectorize.insert = vi.fn(async () => {
250
- throw new Error('Insert failed');
251
- });
252
-
253
- const instrumented = instrumentVectorize(mockVectorize, 'my-index');
254
-
255
- await expect(instrumented.insert([{ id: 'v1', values: [0.1] }] as any)).rejects.toThrow('Insert failed');
256
-
257
- expect(mockSpan.recordException).toHaveBeenCalled();
258
- expect(mockSpan.setStatus).toHaveBeenCalledWith({
259
- code: SpanStatusCode.ERROR,
260
- message: 'Insert failed',
261
- });
262
- expect(mockSpan.end).toHaveBeenCalled();
263
- });
264
-
265
- it('should record exception and set error status on upsert() failure', async () => {
266
- mockVectorize.upsert = vi.fn(async () => {
267
- throw new Error('Upsert failed');
268
- });
269
-
270
- const instrumented = instrumentVectorize(mockVectorize, 'my-index');
271
-
272
- await expect(instrumented.upsert([{ id: 'v1', values: [0.1] }] as any)).rejects.toThrow('Upsert failed');
273
-
274
- expect(mockSpan.recordException).toHaveBeenCalled();
275
- expect(mockSpan.setStatus).toHaveBeenCalledWith({
276
- code: SpanStatusCode.ERROR,
277
- message: 'Upsert failed',
278
- });
279
- expect(mockSpan.end).toHaveBeenCalled();
280
- });
281
-
282
- it('should record exception and set error status on deleteByIds() failure', async () => {
283
- mockVectorize.deleteByIds = vi.fn(async () => {
284
- throw new Error('Delete failed');
285
- });
286
-
287
- const instrumented = instrumentVectorize(mockVectorize, 'my-index');
288
-
289
- await expect(instrumented.deleteByIds(['vec-1'])).rejects.toThrow('Delete failed');
290
-
291
- expect(mockSpan.recordException).toHaveBeenCalled();
292
- expect(mockSpan.setStatus).toHaveBeenCalledWith({
293
- code: SpanStatusCode.ERROR,
294
- message: 'Delete failed',
295
- });
296
- expect(mockSpan.end).toHaveBeenCalled();
297
- });
298
-
299
- it('should record exception and set error status on describe() failure', async () => {
300
- mockVectorize.describe = vi.fn(async () => {
301
- throw new Error('Describe failed');
302
- });
303
-
304
- const instrumented = instrumentVectorize(mockVectorize, 'my-index');
305
-
306
- await expect(instrumented.describe()).rejects.toThrow('Describe failed');
307
-
308
- expect(mockSpan.recordException).toHaveBeenCalled();
309
- expect(mockSpan.setStatus).toHaveBeenCalledWith({
310
- code: SpanStatusCode.ERROR,
311
- message: 'Describe failed',
312
- });
313
- expect(mockSpan.end).toHaveBeenCalled();
314
- });
315
-
316
- it('should handle non-Error exceptions', async () => {
317
- mockVectorize.query = vi.fn(async () => {
318
- throw 'string error';
319
- });
320
-
321
- const instrumented = instrumentVectorize(mockVectorize, 'my-index');
322
-
323
- await expect(instrumented.query([0.1] as any, {} as any)).rejects.toThrow('string error');
324
-
325
- expect(mockSpan.recordException).toHaveBeenCalled();
326
- expect(mockSpan.setStatus).toHaveBeenCalledWith({
327
- code: SpanStatusCode.ERROR,
328
- message: 'string error',
329
- });
330
- expect(mockSpan.end).toHaveBeenCalled();
331
- });
332
- });
333
-
334
- describe('Non-instrumented methods', () => {
335
- it('should pass through non-traced methods without creating spans', () => {
336
- const instrumented = instrumentVectorize(mockVectorize, 'my-index');
337
-
338
- const result = instrumented.toString();
339
-
340
- expect(result).toBe('VectorizeIndex');
341
- expect(mockTracer.startActiveSpan).not.toHaveBeenCalled();
342
- });
343
- });
344
-
345
- describe('Default index name', () => {
346
- it('should use "vectorize" as default index name when none provided', async () => {
347
- const instrumented = instrumentVectorize(mockVectorize);
348
-
349
- await instrumented.query([0.1, 0.2] as any, {} as any);
350
-
351
- expect(mockTracer.startActiveSpan).toHaveBeenCalledWith(
352
- 'Vectorize vectorize: query',
353
- expect.objectContaining({
354
- attributes: expect.objectContaining({
355
- 'db.collection.name': 'vectorize',
356
- }),
357
- }),
358
- expect.any(Function),
359
- );
360
- });
361
- });
362
- });