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.
- package/dist/agents.d.ts.map +1 -1
- package/dist/agents.js +7 -0
- package/dist/agents.js.map +1 -1
- package/package.json +8 -4
- package/src/actors/alarms.ts +0 -225
- package/src/actors/index.ts +0 -36
- package/src/actors/instrument-actor.test.ts +0 -179
- package/src/actors/instrument-actor.ts +0 -574
- package/src/actors/sockets.ts +0 -217
- package/src/actors/storage.ts +0 -263
- package/src/actors/traced-handler.ts +0 -300
- package/src/actors/types.ts +0 -98
- package/src/actors.ts +0 -50
- package/src/agents/agent.ts +0 -327
- package/src/agents/base.ts +0 -26
- package/src/agents/index.ts +0 -46
- package/src/agents/mcp.ts +0 -38
- package/src/agents/observability.ts +0 -145
- package/src/agents/otel-observability.test.ts +0 -269
- package/src/agents/otel-observability.ts +0 -557
- package/src/agents/types.ts +0 -61
- package/src/agents.ts +0 -87
- package/src/bindings/ai.test.ts +0 -170
- package/src/bindings/ai.ts +0 -73
- package/src/bindings/analytics-engine.test.ts +0 -175
- package/src/bindings/analytics-engine.ts +0 -78
- package/src/bindings/bindings-cache.test.ts +0 -80
- package/src/bindings/bindings-detection.test.ts +0 -235
- package/src/bindings/bindings-this-binding.test.ts +0 -294
- package/src/bindings/bindings.ts +0 -720
- package/src/bindings/browser-rendering.test.ts +0 -160
- package/src/bindings/browser-rendering.ts +0 -70
- package/src/bindings/common.ts +0 -84
- package/src/bindings/hyperdrive.test.ts +0 -176
- package/src/bindings/hyperdrive.ts +0 -74
- package/src/bindings/images.test.ts +0 -262
- package/src/bindings/images.ts +0 -182
- package/src/bindings/index.ts +0 -20
- package/src/bindings/queue-producer.test.ts +0 -224
- package/src/bindings/queue-producer.ts +0 -105
- package/src/bindings/rate-limiter.test.ts +0 -140
- package/src/bindings/rate-limiter.ts +0 -69
- package/src/bindings/vectorize.test.ts +0 -362
- package/src/bindings/vectorize.ts +0 -86
- package/src/bindings.ts +0 -6
- package/src/events.ts +0 -6
- package/src/execution-logger.test.ts +0 -127
- package/src/execution-logger.ts +0 -112
- package/src/global/cache.test.ts +0 -292
- package/src/global/cache.ts +0 -164
- package/src/global/fetch.test.ts +0 -399
- package/src/global/fetch.ts +0 -136
- package/src/global/index.ts +0 -7
- package/src/handlers/durable-objects.test.ts +0 -524
- package/src/handlers/durable-objects.ts +0 -250
- package/src/handlers/index.ts +0 -6
- package/src/handlers/workflows.test.ts +0 -411
- package/src/handlers/workflows.ts +0 -345
- package/src/handlers.ts +0 -6
- package/src/index.ts +0 -91
- package/src/logger.ts +0 -15
- package/src/native/native-tracing.test.ts +0 -54
- package/src/native/native-tracing.ts +0 -83
- package/src/native.ts +0 -12
- package/src/parse-error.ts +0 -1
- package/src/sampling.ts +0 -6
- package/src/testing.ts +0 -6
- package/src/wrappers/cf-attributes.test.ts +0 -334
- package/src/wrappers/define-worker-fetch.test.ts +0 -102
- package/src/wrappers/define-worker-fetch.ts +0 -71
- package/src/wrappers/index.ts +0 -13
- package/src/wrappers/instrument.integration.test.ts +0 -578
- package/src/wrappers/instrument.ts +0 -806
- package/src/wrappers/native-instrument.test.ts +0 -153
- package/src/wrappers/wrap-do.ts +0 -34
- 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
|
-
});
|