autotel-cloudflare 3.1.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 (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,235 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
- import { trace, SpanStatusCode, SpanKind } from '@opentelemetry/api';
3
- import { instrumentBindings } from './bindings';
4
- import { isWrapped, wrap } from './common';
5
-
6
- describe('instrumentBindings() detection logic', () => {
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 detect R2 (object with get, put, delete, list, head methods)', () => {
42
- const mockR2 = {
43
- get: vi.fn(),
44
- put: vi.fn(),
45
- delete: vi.fn(),
46
- list: vi.fn(),
47
- head: vi.fn(),
48
- };
49
-
50
- const result = instrumentBindings({ MY_R2: mockR2 });
51
-
52
- expect(result.MY_R2).not.toBe(mockR2);
53
- expect(isWrapped(result.MY_R2)).toBe(true);
54
- });
55
-
56
- it('should detect KV (object with get, put, delete, list but NOT head)', () => {
57
- const mockKV = {
58
- get: vi.fn(),
59
- put: vi.fn(),
60
- delete: vi.fn(),
61
- list: vi.fn(),
62
- };
63
-
64
- const result = instrumentBindings({ MY_KV: mockKV });
65
-
66
- expect(result.MY_KV).not.toBe(mockKV);
67
- expect(isWrapped(result.MY_KV)).toBe(true);
68
- });
69
-
70
- it('should detect D1 (object with prepare, exec methods)', () => {
71
- const mockD1 = {
72
- prepare: vi.fn(),
73
- exec: vi.fn(),
74
- };
75
-
76
- const result = instrumentBindings({ MY_DB: mockD1 });
77
-
78
- expect(result.MY_DB).not.toBe(mockD1);
79
- expect(isWrapped(result.MY_DB)).toBe(true);
80
- });
81
-
82
- it('should detect Vectorize (object with query, insert, upsert, describe methods)', () => {
83
- const mockVectorize = {
84
- query: vi.fn(),
85
- insert: vi.fn(),
86
- upsert: vi.fn(),
87
- describe: vi.fn(),
88
- };
89
-
90
- const result = instrumentBindings({ MY_INDEX: mockVectorize });
91
-
92
- expect(result.MY_INDEX).not.toBe(mockVectorize);
93
- expect(isWrapped(result.MY_INDEX)).toBe(true);
94
- });
95
-
96
- it('should detect AI (object with run method AND gateway property)', () => {
97
- const mockAI = {
98
- run: vi.fn(),
99
- gateway: {},
100
- };
101
-
102
- const result = instrumentBindings({ AI: mockAI });
103
-
104
- expect(result.AI).not.toBe(mockAI);
105
- expect(isWrapped(result.AI)).toBe(true);
106
- });
107
-
108
- it('should detect Hyperdrive (object with connect method AND connectionString, host properties)', () => {
109
- const mockHyperdrive = {
110
- connect: vi.fn(),
111
- connectionString: 'postgresql://user:pass@host:5432/db',
112
- host: 'db.example.com',
113
- port: 5432,
114
- user: 'user',
115
- password: 'pass',
116
- database: 'db',
117
- };
118
-
119
- const result = instrumentBindings({ HYPERDRIVE: mockHyperdrive });
120
-
121
- expect(result.HYPERDRIVE).not.toBe(mockHyperdrive);
122
- expect(isWrapped(result.HYPERDRIVE)).toBe(true);
123
- });
124
-
125
- it('should detect Queue Producer (object with send, sendBatch but NOT get)', () => {
126
- const mockQueue = {
127
- send: vi.fn(),
128
- sendBatch: vi.fn(),
129
- };
130
-
131
- const result = instrumentBindings({ MY_QUEUE: mockQueue });
132
-
133
- expect(result.MY_QUEUE).not.toBe(mockQueue);
134
- expect(isWrapped(result.MY_QUEUE)).toBe(true);
135
- });
136
-
137
- it('should detect Analytics Engine (object with writeDataPoint method)', () => {
138
- const mockAE = {
139
- writeDataPoint: vi.fn(),
140
- };
141
-
142
- const result = instrumentBindings({ ANALYTICS: mockAE });
143
-
144
- expect(result.ANALYTICS).not.toBe(mockAE);
145
- expect(isWrapped(result.ANALYTICS)).toBe(true);
146
- });
147
-
148
- it('should detect Images (object with info, input methods)', () => {
149
- const mockImages = {
150
- info: vi.fn(),
151
- input: vi.fn(),
152
- };
153
-
154
- const result = instrumentBindings({ IMAGES: mockImages });
155
-
156
- expect(result.IMAGES).not.toBe(mockImages);
157
- expect(isWrapped(result.IMAGES)).toBe(true);
158
- });
159
-
160
- it('should detect Service Binding (object with fetch method) - last', () => {
161
- const mockService = {
162
- fetch: vi.fn(),
163
- };
164
-
165
- const result = instrumentBindings({ MY_SERVICE: mockService });
166
-
167
- expect(result.MY_SERVICE).not.toBe(mockService);
168
- expect(isWrapped(result.MY_SERVICE)).toBe(true);
169
- });
170
-
171
- it('should detect R2 before KV (object with head gets R2, without head gets KV)', () => {
172
- const withHead = {
173
- get: vi.fn(),
174
- put: vi.fn(),
175
- delete: vi.fn(),
176
- list: vi.fn(),
177
- head: vi.fn(),
178
- };
179
- const withoutHead = {
180
- get: vi.fn(),
181
- put: vi.fn(),
182
- delete: vi.fn(),
183
- list: vi.fn(),
184
- };
185
-
186
- const result = instrumentBindings({
187
- R2_BUCKET: withHead,
188
- KV_STORE: withoutHead,
189
- });
190
-
191
- // Both should be wrapped but detected as different types
192
- expect(isWrapped(result.R2_BUCKET)).toBe(true);
193
- expect(isWrapped(result.KV_STORE)).toBe(true);
194
- expect(result.R2_BUCKET).not.toBe(withHead);
195
- expect(result.KV_STORE).not.toBe(withoutHead);
196
- });
197
-
198
- it('should skip already-wrapped bindings', () => {
199
- const mockKV = {
200
- get: vi.fn(),
201
- put: vi.fn(),
202
- delete: vi.fn(),
203
- list: vi.fn(),
204
- };
205
-
206
- // Pre-wrap the binding using the wrap helper
207
- const preWrapped = wrap(mockKV, {
208
- get(target, prop) {
209
- return Reflect.get(target, prop);
210
- },
211
- });
212
-
213
- const result = instrumentBindings({ MY_KV: preWrapped });
214
-
215
- // Should be the same already-wrapped object, not double-wrapped
216
- expect(result.MY_KV).toBe(preWrapped);
217
- expect(isWrapped(result.MY_KV)).toBe(true);
218
- });
219
-
220
- it('should pass through non-object values (strings, numbers)', () => {
221
- const result = instrumentBindings({
222
- API_KEY: 'my-secret-key',
223
- TIMEOUT: 5000,
224
- ENABLED: true,
225
- EMPTY: null,
226
- UNDEF: undefined,
227
- });
228
-
229
- expect(result.API_KEY).toBe('my-secret-key');
230
- expect(result.TIMEOUT).toBe(5000);
231
- expect(result.ENABLED).toBe(true);
232
- expect(result.EMPTY).toBe(null);
233
- expect(result.UNDEF).toBe(undefined);
234
- });
235
- });
@@ -1,294 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
- import { trace, SpanStatusCode, SpanKind } from '@opentelemetry/api';
3
- import { instrumentKV, instrumentR2, instrumentD1, instrumentServiceBinding } from './bindings';
4
-
5
- describe('Bindings this-binding tests', () => {
6
- let mockTracer: any;
7
- let mockSpan: any;
8
- let getTracerSpy: any;
9
-
10
- beforeEach(() => {
11
- mockSpan = {
12
- spanContext: () => ({
13
- traceId: 'test-trace-id',
14
- spanId: 'test-span-id',
15
- traceFlags: 1,
16
- }),
17
- setAttribute: vi.fn(),
18
- setAttributes: vi.fn(),
19
- setStatus: vi.fn(),
20
- recordException: vi.fn(),
21
- end: vi.fn(),
22
- isRecording: () => true,
23
- updateName: vi.fn(),
24
- addEvent: vi.fn(),
25
- };
26
-
27
- mockTracer = {
28
- startActiveSpan: vi.fn((name, options, fn) => {
29
- return fn(mockSpan);
30
- }),
31
- };
32
-
33
- getTracerSpy = vi.spyOn(trace, 'getTracer').mockReturnValue(mockTracer as any);
34
- });
35
-
36
- afterEach(() => {
37
- getTracerSpy.mockRestore();
38
- });
39
-
40
- describe('KV this-binding', () => {
41
- it('should invoke get() with original object as this, not the proxy', async () => {
42
- let receivedThis: any;
43
- const mockKV = {
44
- get: vi.fn(async function(this: any) {
45
- // eslint-disable-next-line unicorn/no-this-assignment, @typescript-eslint/no-this-alias
46
- receivedThis = this;
47
- return 'value';
48
- }),
49
- put: vi.fn(async () => undefined),
50
- delete: vi.fn(async () => undefined),
51
- list: vi.fn(async () => ({ keys: [], list_complete: true, cacheStatus: null })),
52
- } as unknown as KVNamespace;
53
- const instrumented = instrumentKV(mockKV, 'test');
54
- await instrumented.get('key');
55
- expect(receivedThis).toBe(mockKV);
56
- });
57
-
58
- it('should invoke put() with original object as this, not the proxy', async () => {
59
- let receivedThis: any;
60
- const mockKV = {
61
- get: vi.fn(async () => null),
62
- put: vi.fn(async function(this: any) {
63
- // eslint-disable-next-line unicorn/no-this-assignment, @typescript-eslint/no-this-alias
64
- receivedThis = this;
65
- }),
66
- delete: vi.fn(async () => undefined),
67
- list: vi.fn(async () => ({ keys: [], list_complete: true, cacheStatus: null })),
68
- } as unknown as KVNamespace;
69
- const instrumented = instrumentKV(mockKV, 'test');
70
- await instrumented.put('key', 'value');
71
- expect(receivedThis).toBe(mockKV);
72
- });
73
-
74
- it('should invoke delete() with original object as this, not the proxy', async () => {
75
- let receivedThis: any;
76
- const mockKV = {
77
- get: vi.fn(async () => null),
78
- put: vi.fn(async () => undefined),
79
- delete: vi.fn(async function(this: any) {
80
- // eslint-disable-next-line unicorn/no-this-assignment, @typescript-eslint/no-this-alias
81
- receivedThis = this;
82
- }),
83
- list: vi.fn(async () => ({ keys: [], list_complete: true, cacheStatus: null })),
84
- } as unknown as KVNamespace;
85
- const instrumented = instrumentKV(mockKV, 'test');
86
- await instrumented.delete('key');
87
- expect(receivedThis).toBe(mockKV);
88
- });
89
-
90
- it('should invoke list() with original object as this, not the proxy', async () => {
91
- let receivedThis: any;
92
- const mockKV = {
93
- get: vi.fn(async () => null),
94
- put: vi.fn(async () => undefined),
95
- delete: vi.fn(async () => undefined),
96
- list: vi.fn(async function(this: any) {
97
- // eslint-disable-next-line unicorn/no-this-assignment, @typescript-eslint/no-this-alias
98
- receivedThis = this;
99
- return { keys: [], list_complete: true, cacheStatus: null };
100
- }),
101
- } as unknown as KVNamespace;
102
- const instrumented = instrumentKV(mockKV, 'test');
103
- await instrumented.list();
104
- expect(receivedThis).toBe(mockKV);
105
- });
106
- });
107
-
108
- describe('R2 this-binding', () => {
109
- it('should invoke get() with original object as this, not the proxy', async () => {
110
- let receivedThis: any;
111
- const mockR2 = {
112
- get: vi.fn(async function(this: any) {
113
- // eslint-disable-next-line unicorn/no-this-assignment, @typescript-eslint/no-this-alias
114
- receivedThis = this;
115
- return { size: 100, etag: 'abc', httpMetadata: {} };
116
- }),
117
- put: vi.fn(async () => ({ etag: 'abc', uploaded: new Date() })),
118
- delete: vi.fn(async () => undefined),
119
- list: vi.fn(async () => ({ objects: [], truncated: false })),
120
- head: vi.fn(async () => null),
121
- } as unknown as R2Bucket;
122
- const instrumented = instrumentR2(mockR2, 'test');
123
- await instrumented.get('key');
124
- expect(receivedThis).toBe(mockR2);
125
- });
126
-
127
- it('should invoke put() with original object as this, not the proxy', async () => {
128
- let receivedThis: any;
129
- const mockR2 = {
130
- get: vi.fn(async () => null),
131
- put: vi.fn(async function(this: any) {
132
- // eslint-disable-next-line unicorn/no-this-assignment, @typescript-eslint/no-this-alias
133
- receivedThis = this;
134
- return { etag: 'abc', uploaded: new Date() };
135
- }),
136
- delete: vi.fn(async () => undefined),
137
- list: vi.fn(async () => ({ objects: [], truncated: false })),
138
- head: vi.fn(async () => null),
139
- } as unknown as R2Bucket;
140
- const instrumented = instrumentR2(mockR2, 'test');
141
- await instrumented.put('key', 'value');
142
- expect(receivedThis).toBe(mockR2);
143
- });
144
-
145
- it('should invoke delete() with original object as this, not the proxy', async () => {
146
- let receivedThis: any;
147
- const mockR2 = {
148
- get: vi.fn(async () => null),
149
- put: vi.fn(async () => ({ etag: 'abc', uploaded: new Date() })),
150
- delete: vi.fn(async function(this: any) {
151
- // eslint-disable-next-line unicorn/no-this-assignment, @typescript-eslint/no-this-alias
152
- receivedThis = this;
153
- }),
154
- list: vi.fn(async () => ({ objects: [], truncated: false })),
155
- head: vi.fn(async () => null),
156
- } as unknown as R2Bucket;
157
- const instrumented = instrumentR2(mockR2, 'test');
158
- await instrumented.delete('key');
159
- expect(receivedThis).toBe(mockR2);
160
- });
161
-
162
- it('should invoke list() with original object as this, not the proxy', async () => {
163
- let receivedThis: any;
164
- const mockR2 = {
165
- get: vi.fn(async () => null),
166
- put: vi.fn(async () => ({ etag: 'abc', uploaded: new Date() })),
167
- delete: vi.fn(async () => undefined),
168
- list: vi.fn(async function(this: any) {
169
- // eslint-disable-next-line unicorn/no-this-assignment, @typescript-eslint/no-this-alias
170
- receivedThis = this;
171
- return { objects: [], truncated: false };
172
- }),
173
- head: vi.fn(async () => null),
174
- } as unknown as R2Bucket;
175
- const instrumented = instrumentR2(mockR2, 'test');
176
- await instrumented.list();
177
- expect(receivedThis).toBe(mockR2);
178
- });
179
- });
180
-
181
- describe('D1 this-binding', () => {
182
- it('should invoke prepare() with original object as this, not the proxy', () => {
183
- let receivedThis: any;
184
- const mockPrepared = {
185
- first: vi.fn(async () => null),
186
- run: vi.fn(async () => ({})),
187
- all: vi.fn(async () => []),
188
- raw: vi.fn(async () => []),
189
- bind: vi.fn(function() { return mockPrepared; }),
190
- };
191
- const mockD1 = {
192
- prepare: vi.fn(function(this: any) {
193
- // eslint-disable-next-line unicorn/no-this-assignment, @typescript-eslint/no-this-alias
194
- receivedThis = this;
195
- return mockPrepared;
196
- }),
197
- exec: vi.fn(async () => ({ count: 0 })),
198
- } as unknown as D1Database;
199
- const instrumented = instrumentD1(mockD1, 'test');
200
- instrumented.prepare('SELECT 1');
201
- expect(receivedThis).toBe(mockD1);
202
- });
203
-
204
- it('should invoke prepared statement methods with original prepared object as this, not the proxy', async () => {
205
- let receivedThis: any;
206
- const mockPrepared = {
207
- first: vi.fn(async function(this: any) {
208
- // eslint-disable-next-line unicorn/no-this-assignment, @typescript-eslint/no-this-alias
209
- receivedThis = this;
210
- return { id: 1 };
211
- }),
212
- run: vi.fn(async () => ({})),
213
- all: vi.fn(async () => []),
214
- raw: vi.fn(async () => []),
215
- bind: vi.fn(function() { return mockPrepared; }),
216
- };
217
- const mockD1 = {
218
- prepare: vi.fn(() => mockPrepared),
219
- exec: vi.fn(async () => ({ count: 0 })),
220
- } as unknown as D1Database;
221
- const instrumented = instrumentD1(mockD1, 'test');
222
- const stmt = instrumented.prepare('SELECT * FROM users WHERE id = ?');
223
- await stmt.first();
224
- expect(receivedThis).toBe(mockPrepared);
225
- });
226
-
227
- it('should invoke exec() with original object as this, not the proxy', async () => {
228
- let receivedThis: any;
229
- const mockD1 = {
230
- prepare: vi.fn(() => ({ first: vi.fn(), run: vi.fn(), all: vi.fn(), raw: vi.fn() })),
231
- exec: vi.fn(async function(this: any) {
232
- // eslint-disable-next-line unicorn/no-this-assignment, @typescript-eslint/no-this-alias
233
- receivedThis = this;
234
- return { count: 1 };
235
- }),
236
- } as unknown as D1Database;
237
- const instrumented = instrumentD1(mockD1, 'test');
238
- await instrumented.exec('CREATE TABLE test (id INTEGER PRIMARY KEY)');
239
- expect(receivedThis).toBe(mockD1);
240
- });
241
- });
242
-
243
- describe('Service Binding this-binding', () => {
244
- it('should invoke fetch() with original object as this, not the proxy', async () => {
245
- let receivedThis: any;
246
- const mockFetcher = {
247
- fetch: vi.fn(async function(this: any) {
248
- // eslint-disable-next-line unicorn/no-this-assignment, @typescript-eslint/no-this-alias
249
- receivedThis = this;
250
- return new Response('ok', { status: 200 });
251
- }),
252
- } as unknown as Fetcher;
253
- const instrumented = instrumentServiceBinding(mockFetcher, 'test');
254
- await instrumented.fetch('https://example.com');
255
- expect(receivedThis).toBe(mockFetcher);
256
- });
257
-
258
- it('should not throw "Illegal invocation" for native-like bindings that check this', async () => {
259
- // Simulate a native Cloudflare Fetcher that throws when `this` is wrong.
260
- // Native bindings use C++ checks that reject proxied `this` references.
261
- class NativeFetcher {
262
- async fetch(input: RequestInfo | URL, _init?: RequestInit): Promise<Response> {
263
- // Native bindings validate `this` — throw if it's not the exact instance
264
- if (!(this instanceof NativeFetcher)) {
265
- throw new TypeError('Illegal invocation: function called with incorrect `this` reference');
266
- }
267
- return new Response('ok', { status: 200 });
268
- }
269
- }
270
-
271
- const nativeFetcher = new NativeFetcher() as unknown as Fetcher;
272
- const instrumented = instrumentServiceBinding(nativeFetcher, 'native-service');
273
-
274
- // This should NOT throw — the fix ensures fetch() is called on the
275
- // original target, preserving the native `this` binding
276
- await expect(instrumented.fetch('https://example.com')).resolves.toBeInstanceOf(Response);
277
- });
278
-
279
- it('should bind non-fetch methods to the original target', () => {
280
- let receivedThis: any;
281
- const mockFetcher = {
282
- fetch: vi.fn(async () => new Response('ok', { status: 200 })),
283
- connect: vi.fn(function(this: any) {
284
- // eslint-disable-next-line unicorn/no-this-assignment, @typescript-eslint/no-this-alias
285
- receivedThis = this;
286
- return {};
287
- }),
288
- } as unknown as Fetcher;
289
- const instrumented = instrumentServiceBinding(mockFetcher, 'test');
290
- (instrumented as any).connect('https://example.com');
291
- expect(receivedThis).toBe(mockFetcher);
292
- });
293
- });
294
- });