ai-evaluate 2.1.6 → 2.1.8
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/README.md +90 -3
- package/dist/capnweb-bundle.d.ts +10 -0
- package/dist/capnweb-bundle.d.ts.map +1 -0
- package/dist/capnweb-bundle.js +2596 -0
- package/dist/capnweb-bundle.js.map +1 -0
- package/dist/evaluate.d.ts +1 -1
- package/dist/evaluate.d.ts.map +1 -1
- package/dist/evaluate.js +186 -7
- package/dist/evaluate.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/miniflare-pool.d.ts +109 -0
- package/dist/miniflare-pool.d.ts.map +1 -0
- package/dist/miniflare-pool.js +308 -0
- package/dist/miniflare-pool.js.map +1 -0
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +42 -10
- package/dist/node.js.map +1 -1
- package/dist/shared.d.ts +66 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +169 -0
- package/dist/shared.js.map +1 -0
- package/dist/type-guards.d.ts +21 -0
- package/dist/type-guards.d.ts.map +1 -0
- package/dist/type-guards.js +216 -0
- package/dist/type-guards.js.map +1 -0
- package/dist/types.d.ts +17 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/validation.d.ts +26 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +104 -0
- package/dist/validation.js.map +1 -0
- package/dist/worker-template/code-transforms.d.ts +9 -0
- package/dist/worker-template/code-transforms.d.ts.map +1 -0
- package/dist/worker-template/code-transforms.js +28 -0
- package/dist/worker-template/code-transforms.js.map +1 -0
- package/{src/worker-template.d.ts → dist/worker-template/core.d.ts} +7 -15
- package/dist/worker-template/core.d.ts.map +1 -0
- package/dist/worker-template/core.js +502 -0
- package/dist/worker-template/core.js.map +1 -0
- package/dist/worker-template/helpers.d.ts +14 -0
- package/dist/worker-template/helpers.d.ts.map +1 -0
- package/dist/worker-template/helpers.js +79 -0
- package/dist/worker-template/helpers.js.map +1 -0
- package/dist/worker-template/index.d.ts +14 -0
- package/dist/worker-template/index.d.ts.map +1 -0
- package/dist/worker-template/index.js +19 -0
- package/dist/worker-template/index.js.map +1 -0
- package/dist/worker-template/sdk-generator.d.ts +17 -0
- package/dist/worker-template/sdk-generator.d.ts.map +1 -0
- package/{src/worker-template.js → dist/worker-template/sdk-generator.js} +377 -1506
- package/dist/worker-template/sdk-generator.js.map +1 -0
- package/dist/worker-template/test-generator.d.ts +16 -0
- package/dist/worker-template/test-generator.d.ts.map +1 -0
- package/dist/worker-template/test-generator.js +357 -0
- package/dist/worker-template/test-generator.js.map +1 -0
- package/dist/worker-template.d.ts +2 -2
- package/dist/worker-template.d.ts.map +1 -1
- package/dist/worker-template.js +64 -31
- package/dist/worker-template.js.map +1 -1
- package/example/package.json +7 -3
- package/example/src/index.ts +194 -40
- package/example/wrangler.jsonc +18 -2
- package/package.json +1 -3
- package/src/capnweb-bundle.ts +2596 -0
- package/src/evaluate.ts +216 -7
- package/src/index.ts +3 -1
- package/src/miniflare-pool.ts +395 -0
- package/src/node.ts +56 -11
- package/src/shared.ts +186 -0
- package/src/type-guards.ts +323 -0
- package/src/types.ts +18 -2
- package/src/validation.ts +120 -0
- package/src/worker-template/code-transforms.ts +32 -0
- package/src/worker-template/core.ts +557 -0
- package/src/worker-template/helpers.ts +90 -0
- package/src/worker-template/index.ts +23 -0
- package/src/{worker-template.ts → worker-template/sdk-generator.ts} +322 -1566
- package/src/worker-template/test-generator.ts +358 -0
- package/test/miniflare-pool.test.ts +246 -0
- package/test/node.test.ts +467 -0
- package/test/security.test.ts +1009 -0
- package/test/shared.test.ts +105 -0
- package/test/type-guards.test.ts +303 -0
- package/test/validation.test.ts +240 -0
- package/test/worker-template.test.ts +21 -19
- package/src/evaluate.js +0 -187
- package/src/index.js +0 -10
- package/src/node.d.ts +0 -17
- package/src/node.d.ts.map +0 -1
- package/src/node.js +0 -168
- package/src/node.js.map +0 -1
- package/src/types.d.ts +0 -172
- package/src/types.d.ts.map +0 -1
- package/src/types.js +0 -4
- package/src/types.js.map +0 -1
- package/src/worker-template.d.ts.map +0 -1
- package/src/worker-template.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sdk-generator.js","sourceRoot":"","sources":["../../src/worker-template/sdk-generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test framework embedding for worker templates
|
|
3
|
+
*
|
|
4
|
+
* Generates the embedded test framework code used in dev mode
|
|
5
|
+
* (vitest-compatible API without external dependencies)
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Generate the embedded test framework code
|
|
9
|
+
* This creates a vitest-compatible testing API that runs in the sandbox
|
|
10
|
+
*/
|
|
11
|
+
export declare function generateTestFrameworkCode(): string;
|
|
12
|
+
/**
|
|
13
|
+
* Generate the test runner code that executes pending tests
|
|
14
|
+
*/
|
|
15
|
+
export declare function generateTestRunnerCode(): string;
|
|
16
|
+
//# sourceMappingURL=test-generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-generator.d.ts","sourceRoot":"","sources":["../../src/worker-template/test-generator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;GAGG;AACH,wBAAgB,yBAAyB,IAAI,MAAM,CA0RlD;AAED;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CA2D/C"}
|
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test framework embedding for worker templates
|
|
3
|
+
*
|
|
4
|
+
* Generates the embedded test framework code used in dev mode
|
|
5
|
+
* (vitest-compatible API without external dependencies)
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Generate the embedded test framework code
|
|
9
|
+
* This creates a vitest-compatible testing API that runs in the sandbox
|
|
10
|
+
*/
|
|
11
|
+
export function generateTestFrameworkCode() {
|
|
12
|
+
return `
|
|
13
|
+
// Test framework (vitest-compatible API)
|
|
14
|
+
let currentDescribe = '';
|
|
15
|
+
let beforeEachFns = [];
|
|
16
|
+
let afterEachFns = [];
|
|
17
|
+
|
|
18
|
+
const describe = (name, fn) => {
|
|
19
|
+
const prev = currentDescribe;
|
|
20
|
+
const prevBeforeEach = [...beforeEachFns];
|
|
21
|
+
const prevAfterEach = [...afterEachFns];
|
|
22
|
+
currentDescribe = currentDescribe ? currentDescribe + ' > ' + name : name;
|
|
23
|
+
try { fn(); } finally {
|
|
24
|
+
currentDescribe = prev;
|
|
25
|
+
beforeEachFns = prevBeforeEach;
|
|
26
|
+
afterEachFns = prevAfterEach;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// Hooks
|
|
31
|
+
const beforeEach = (fn) => { beforeEachFns.push(fn); };
|
|
32
|
+
const afterEach = (fn) => { afterEachFns.push(fn); };
|
|
33
|
+
|
|
34
|
+
const it = (name, fn) => {
|
|
35
|
+
const fullName = currentDescribe ? currentDescribe + ' > ' + name : name;
|
|
36
|
+
const hooks = { before: [...beforeEachFns], after: [...afterEachFns] };
|
|
37
|
+
pendingTests.push({ name: fullName, fn, hooks });
|
|
38
|
+
};
|
|
39
|
+
const test = it;
|
|
40
|
+
|
|
41
|
+
it.skip = (name, fn) => {
|
|
42
|
+
const fullName = currentDescribe ? currentDescribe + ' > ' + name : name;
|
|
43
|
+
pendingTests.push({ name: fullName, fn: null, skip: true });
|
|
44
|
+
};
|
|
45
|
+
test.skip = it.skip;
|
|
46
|
+
|
|
47
|
+
it.only = (name, fn) => {
|
|
48
|
+
const fullName = currentDescribe ? currentDescribe + ' > ' + name : name;
|
|
49
|
+
const hooks = { before: [...beforeEachFns], after: [...afterEachFns] };
|
|
50
|
+
pendingTests.push({ name: fullName, fn, hooks, only: true });
|
|
51
|
+
};
|
|
52
|
+
test.only = it.only;
|
|
53
|
+
|
|
54
|
+
// Deep equality check
|
|
55
|
+
const deepEqual = (a, b) => {
|
|
56
|
+
if (a === b) return true;
|
|
57
|
+
if (a == null || b == null) return false;
|
|
58
|
+
if (typeof a !== typeof b) return false;
|
|
59
|
+
if (typeof a !== 'object') return false;
|
|
60
|
+
if (Array.isArray(a) !== Array.isArray(b)) return false;
|
|
61
|
+
if (Array.isArray(a)) {
|
|
62
|
+
if (a.length !== b.length) return false;
|
|
63
|
+
return a.every((v, i) => deepEqual(v, b[i]));
|
|
64
|
+
}
|
|
65
|
+
const keysA = Object.keys(a);
|
|
66
|
+
const keysB = Object.keys(b);
|
|
67
|
+
if (keysA.length !== keysB.length) return false;
|
|
68
|
+
return keysA.every(k => deepEqual(a[k], b[k]));
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// Expect implementation with vitest-compatible matchers
|
|
72
|
+
const expect = (actual) => {
|
|
73
|
+
const matchers = {
|
|
74
|
+
toBe: (expected) => {
|
|
75
|
+
if (actual !== expected) {
|
|
76
|
+
throw new Error(\`Expected \${JSON.stringify(expected)} but got \${JSON.stringify(actual)}\`);
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
toEqual: (expected) => {
|
|
80
|
+
if (!deepEqual(actual, expected)) {
|
|
81
|
+
throw new Error(\`Expected \${JSON.stringify(expected)} but got \${JSON.stringify(actual)}\`);
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
toStrictEqual: (expected) => {
|
|
85
|
+
if (!deepEqual(actual, expected)) {
|
|
86
|
+
throw new Error(\`Expected \${JSON.stringify(expected)} but got \${JSON.stringify(actual)}\`);
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
toBeTruthy: () => {
|
|
90
|
+
if (!actual) throw new Error(\`Expected truthy but got \${JSON.stringify(actual)}\`);
|
|
91
|
+
},
|
|
92
|
+
toBeFalsy: () => {
|
|
93
|
+
if (actual) throw new Error(\`Expected falsy but got \${JSON.stringify(actual)}\`);
|
|
94
|
+
},
|
|
95
|
+
toBeNull: () => {
|
|
96
|
+
if (actual !== null) throw new Error(\`Expected null but got \${JSON.stringify(actual)}\`);
|
|
97
|
+
},
|
|
98
|
+
toBeUndefined: () => {
|
|
99
|
+
if (actual !== undefined) throw new Error(\`Expected undefined but got \${JSON.stringify(actual)}\`);
|
|
100
|
+
},
|
|
101
|
+
toBeDefined: () => {
|
|
102
|
+
if (actual === undefined) throw new Error('Expected defined but got undefined');
|
|
103
|
+
},
|
|
104
|
+
toBeNaN: () => {
|
|
105
|
+
if (!Number.isNaN(actual)) throw new Error(\`Expected NaN but got \${actual}\`);
|
|
106
|
+
},
|
|
107
|
+
toContain: (item) => {
|
|
108
|
+
if (Array.isArray(actual)) {
|
|
109
|
+
if (!actual.includes(item)) throw new Error(\`Expected array to contain \${JSON.stringify(item)}\`);
|
|
110
|
+
} else if (typeof actual === 'string') {
|
|
111
|
+
if (!actual.includes(item)) throw new Error(\`Expected string to contain "\${item}"\`);
|
|
112
|
+
} else {
|
|
113
|
+
throw new Error('toContain only works on arrays and strings');
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
toContainEqual: (item) => {
|
|
117
|
+
if (!Array.isArray(actual)) throw new Error('toContainEqual only works on arrays');
|
|
118
|
+
if (!actual.some(v => deepEqual(v, item))) {
|
|
119
|
+
throw new Error(\`Expected array to contain \${JSON.stringify(item)}\`);
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
toHaveLength: (length) => {
|
|
123
|
+
if (actual?.length !== length) {
|
|
124
|
+
throw new Error(\`Expected length \${length} but got \${actual?.length}\`);
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
toHaveProperty: function(path, value) {
|
|
128
|
+
const parts = typeof path === 'string' ? path.split('.') : [path];
|
|
129
|
+
let obj = actual;
|
|
130
|
+
for (const part of parts) {
|
|
131
|
+
if (obj == null || !(part in obj)) {
|
|
132
|
+
throw new Error(\`Expected object to have property "\${path}"\`);
|
|
133
|
+
}
|
|
134
|
+
obj = obj[part];
|
|
135
|
+
}
|
|
136
|
+
if (arguments.length > 1 && !deepEqual(obj, value)) {
|
|
137
|
+
throw new Error(\`Expected property "\${path}" to be \${JSON.stringify(value)} but got \${JSON.stringify(obj)}\`);
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
toMatchObject: (expected) => {
|
|
141
|
+
if (typeof actual !== 'object' || actual === null) {
|
|
142
|
+
throw new Error('toMatchObject expects an object');
|
|
143
|
+
}
|
|
144
|
+
for (const key of Object.keys(expected)) {
|
|
145
|
+
if (!deepEqual(actual[key], expected[key])) {
|
|
146
|
+
throw new Error(\`Expected property "\${key}" to be \${JSON.stringify(expected[key])} but got \${JSON.stringify(actual[key])}\`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
toThrow: (expected) => {
|
|
151
|
+
if (typeof actual !== 'function') throw new Error('toThrow expects a function');
|
|
152
|
+
let threw = false;
|
|
153
|
+
let error;
|
|
154
|
+
try {
|
|
155
|
+
actual();
|
|
156
|
+
} catch (e) {
|
|
157
|
+
threw = true;
|
|
158
|
+
error = e;
|
|
159
|
+
}
|
|
160
|
+
if (!threw) throw new Error('Expected function to throw');
|
|
161
|
+
if (expected !== undefined) {
|
|
162
|
+
if (typeof expected === 'string' && !error.message.includes(expected)) {
|
|
163
|
+
throw new Error(\`Expected error message to contain "\${expected}" but got "\${error.message}"\`);
|
|
164
|
+
}
|
|
165
|
+
if (expected instanceof RegExp && !expected.test(error.message)) {
|
|
166
|
+
throw new Error(\`Expected error message to match \${expected} but got "\${error.message}"\`);
|
|
167
|
+
}
|
|
168
|
+
if (typeof expected === 'function' && !(error instanceof expected)) {
|
|
169
|
+
throw new Error(\`Expected error to be instance of \${expected.name}\`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
toBeGreaterThan: (n) => {
|
|
174
|
+
if (!(actual > n)) throw new Error(\`Expected \${actual} to be greater than \${n}\`);
|
|
175
|
+
},
|
|
176
|
+
toBeLessThan: (n) => {
|
|
177
|
+
if (!(actual < n)) throw new Error(\`Expected \${actual} to be less than \${n}\`);
|
|
178
|
+
},
|
|
179
|
+
toBeGreaterThanOrEqual: (n) => {
|
|
180
|
+
if (!(actual >= n)) throw new Error(\`Expected \${actual} to be >= \${n}\`);
|
|
181
|
+
},
|
|
182
|
+
toBeLessThanOrEqual: (n) => {
|
|
183
|
+
if (!(actual <= n)) throw new Error(\`Expected \${actual} to be <= \${n}\`);
|
|
184
|
+
},
|
|
185
|
+
toBeCloseTo: (n, digits = 2) => {
|
|
186
|
+
const diff = Math.abs(actual - n);
|
|
187
|
+
const threshold = Math.pow(10, -digits) / 2;
|
|
188
|
+
if (diff > threshold) {
|
|
189
|
+
throw new Error(\`Expected \${actual} to be close to \${n}\`);
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
toMatch: (pattern) => {
|
|
193
|
+
if (typeof actual !== 'string') throw new Error('toMatch expects a string');
|
|
194
|
+
const regex = typeof pattern === 'string' ? new RegExp(pattern) : pattern;
|
|
195
|
+
if (!regex.test(actual)) {
|
|
196
|
+
throw new Error(\`Expected "\${actual}" to match \${pattern}\`);
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
toBeInstanceOf: (cls) => {
|
|
200
|
+
if (!(actual instanceof cls)) {
|
|
201
|
+
throw new Error(\`Expected instance of \${cls.name}\`);
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
toBeTypeOf: (type) => {
|
|
205
|
+
if (typeof actual !== type) {
|
|
206
|
+
throw new Error(\`Expected typeof to be "\${type}" but got "\${typeof actual}"\`);
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
matchers.not = {
|
|
212
|
+
toBe: (expected) => {
|
|
213
|
+
if (actual === expected) throw new Error(\`Expected not \${JSON.stringify(expected)}\`);
|
|
214
|
+
},
|
|
215
|
+
toEqual: (expected) => {
|
|
216
|
+
if (deepEqual(actual, expected)) {
|
|
217
|
+
throw new Error(\`Expected not equal to \${JSON.stringify(expected)}\`);
|
|
218
|
+
}
|
|
219
|
+
},
|
|
220
|
+
toBeTruthy: () => {
|
|
221
|
+
if (actual) throw new Error('Expected not truthy');
|
|
222
|
+
},
|
|
223
|
+
toBeFalsy: () => {
|
|
224
|
+
if (!actual) throw new Error('Expected not falsy');
|
|
225
|
+
},
|
|
226
|
+
toBeNull: () => {
|
|
227
|
+
if (actual === null) throw new Error('Expected not null');
|
|
228
|
+
},
|
|
229
|
+
toBeUndefined: () => {
|
|
230
|
+
if (actual === undefined) throw new Error('Expected not undefined');
|
|
231
|
+
},
|
|
232
|
+
toBeDefined: () => {
|
|
233
|
+
if (actual !== undefined) throw new Error('Expected undefined');
|
|
234
|
+
},
|
|
235
|
+
toContain: (item) => {
|
|
236
|
+
if (Array.isArray(actual) && actual.includes(item)) {
|
|
237
|
+
throw new Error(\`Expected array not to contain \${JSON.stringify(item)}\`);
|
|
238
|
+
}
|
|
239
|
+
if (typeof actual === 'string' && actual.includes(item)) {
|
|
240
|
+
throw new Error(\`Expected string not to contain "\${item}"\`);
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
toHaveProperty: (path) => {
|
|
244
|
+
const parts = typeof path === 'string' ? path.split('.') : [path];
|
|
245
|
+
let obj = actual;
|
|
246
|
+
try {
|
|
247
|
+
for (const part of parts) {
|
|
248
|
+
if (obj == null || !(part in obj)) return;
|
|
249
|
+
obj = obj[part];
|
|
250
|
+
}
|
|
251
|
+
throw new Error(\`Expected object not to have property "\${path}"\`);
|
|
252
|
+
} catch {}
|
|
253
|
+
},
|
|
254
|
+
toThrow: () => {
|
|
255
|
+
if (typeof actual !== 'function') throw new Error('toThrow expects a function');
|
|
256
|
+
try {
|
|
257
|
+
actual();
|
|
258
|
+
} catch (e) {
|
|
259
|
+
throw new Error('Expected function not to throw');
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
toMatch: (pattern) => {
|
|
263
|
+
if (typeof actual !== 'string') throw new Error('toMatch expects a string');
|
|
264
|
+
const regex = typeof pattern === 'string' ? new RegExp(pattern) : pattern;
|
|
265
|
+
if (regex.test(actual)) {
|
|
266
|
+
throw new Error(\`Expected "\${actual}" not to match \${pattern}\`);
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
matchers.resolves = new Proxy({}, {
|
|
272
|
+
get: (_, prop) => async (...args) => {
|
|
273
|
+
const resolved = await actual;
|
|
274
|
+
return expect(resolved)[prop](...args);
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
matchers.rejects = new Proxy({}, {
|
|
279
|
+
get: (_, prop) => async (...args) => {
|
|
280
|
+
try {
|
|
281
|
+
await actual;
|
|
282
|
+
throw new Error('Expected promise to reject');
|
|
283
|
+
} catch (e) {
|
|
284
|
+
if (e.message === 'Expected promise to reject') throw e;
|
|
285
|
+
return expect(e)[prop](...args);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
return matchers;
|
|
291
|
+
};
|
|
292
|
+
`;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Generate the test runner code that executes pending tests
|
|
296
|
+
*/
|
|
297
|
+
export function generateTestRunnerCode() {
|
|
298
|
+
return `
|
|
299
|
+
// Run all pending tests
|
|
300
|
+
const testStart = Date.now();
|
|
301
|
+
const hasOnly = pendingTests.some(t => t.only);
|
|
302
|
+
const testsToRun = hasOnly ? pendingTests.filter(t => t.only || t.skip) : pendingTests;
|
|
303
|
+
|
|
304
|
+
for (const { name, fn, hooks, skip } of testsToRun) {
|
|
305
|
+
testResults.total++;
|
|
306
|
+
|
|
307
|
+
if (skip) {
|
|
308
|
+
testResults.skipped++;
|
|
309
|
+
testResults.tests.push({ name, passed: true, skipped: true, duration: 0 });
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const start = Date.now();
|
|
314
|
+
try {
|
|
315
|
+
// Run beforeEach hooks
|
|
316
|
+
if (hooks?.before) {
|
|
317
|
+
for (const hook of hooks.before) {
|
|
318
|
+
const hookResult = hook();
|
|
319
|
+
if (hookResult && typeof hookResult.then === 'function') {
|
|
320
|
+
await hookResult;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Run the test
|
|
326
|
+
const result = fn();
|
|
327
|
+
if (result && typeof result.then === 'function') {
|
|
328
|
+
await result;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Run afterEach hooks
|
|
332
|
+
if (hooks?.after) {
|
|
333
|
+
for (const hook of hooks.after) {
|
|
334
|
+
const hookResult = hook();
|
|
335
|
+
if (hookResult && typeof hookResult.then === 'function') {
|
|
336
|
+
await hookResult;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
testResults.passed++;
|
|
342
|
+
testResults.tests.push({ name, passed: true, duration: Date.now() - start });
|
|
343
|
+
} catch (e) {
|
|
344
|
+
testResults.failed++;
|
|
345
|
+
testResults.tests.push({
|
|
346
|
+
name,
|
|
347
|
+
passed: false,
|
|
348
|
+
error: e.message || String(e),
|
|
349
|
+
duration: Date.now() - start
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
testResults.duration = Date.now() - testStart;
|
|
355
|
+
`;
|
|
356
|
+
}
|
|
357
|
+
//# sourceMappingURL=test-generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-generator.js","sourceRoot":"","sources":["../../src/worker-template/test-generator.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;GAGG;AACH,MAAM,UAAU,yBAAyB;IACvC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwRR,CAAA;AACD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,sBAAsB;IACpC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyDR,CAAA;AACD,CAAC"}
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* - POST /rpc or WebSocket upgrade - capnweb RPC to module exports
|
|
14
14
|
* - GET / - Return info about available exports
|
|
15
15
|
*/
|
|
16
|
-
import type { SDKConfig } from './types.js';
|
|
16
|
+
import type { SDKConfig, FetchConfig } from './types.js';
|
|
17
17
|
/**
|
|
18
18
|
* Generate worker code for production (uses RPC to ai-tests)
|
|
19
19
|
*/
|
|
@@ -36,6 +36,6 @@ export declare function generateDevWorkerCode(options: {
|
|
|
36
36
|
script?: string | undefined;
|
|
37
37
|
sdk?: SDKConfig | boolean | undefined;
|
|
38
38
|
imports?: string[] | undefined;
|
|
39
|
-
fetch?: null | undefined;
|
|
39
|
+
fetch?: null | FetchConfig | undefined;
|
|
40
40
|
}): string;
|
|
41
41
|
//# sourceMappingURL=worker-template.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker-template.d.ts","sourceRoot":"","sources":["../src/worker-template.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"worker-template.d.ts","sourceRoot":"","sources":["../src/worker-template.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AA23FxD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE;IAC1C,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,GAAG,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,CAAA;IACrC,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAA;CAC/B,GAAG,MAAM,CAoQT;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE;IAC7C,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,GAAG,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,CAAA;IACrC,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAA;IAC9B,KAAK,CAAC,EAAE,IAAI,GAAG,WAAW,GAAG,SAAS,CAAA;CACvC,GAAG,MAAM,CAikBT"}
|
package/dist/worker-template.js
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* - POST /rpc or WebSocket upgrade - capnweb RPC to module exports
|
|
14
14
|
* - GET / - Return info about available exports
|
|
15
15
|
*/
|
|
16
|
+
import { generateDomainCheckCode } from './shared.js';
|
|
16
17
|
/**
|
|
17
18
|
* Generate SDK code for injection into sandbox
|
|
18
19
|
*
|
|
@@ -2919,7 +2920,8 @@ function wrapScriptForReturn(script) {
|
|
|
2919
2920
|
return script;
|
|
2920
2921
|
const lastLine = lastLineRaw.trim();
|
|
2921
2922
|
// If last line is an expression (not a declaration, control flow, or throw)
|
|
2922
|
-
if (lastLine &&
|
|
2923
|
+
if (lastLine &&
|
|
2924
|
+
!/^\s*(const|let|var|if|for|while|switch|try|class|function|return|throw)\b/.test(lastLine)) {
|
|
2923
2925
|
lines[lines.length - 1] = `return ${lastLine.replace(/;?\s*$/, '')}`;
|
|
2924
2926
|
return lines.join('\n');
|
|
2925
2927
|
}
|
|
@@ -2930,7 +2932,7 @@ function wrapScriptForReturn(script) {
|
|
|
2930
2932
|
*/
|
|
2931
2933
|
export function generateWorkerCode(options) {
|
|
2932
2934
|
const { module: rawModule = '', tests = '', script: rawScript = '', sdk, imports = [] } = options;
|
|
2933
|
-
const sdkConfig = sdk === true ? {} :
|
|
2935
|
+
const sdkConfig = sdk === true ? {} : sdk || null;
|
|
2934
2936
|
const module = rawModule ? transformModuleCode(rawModule) : '';
|
|
2935
2937
|
const script = rawScript ? wrapScriptForReturn(rawScript) : '';
|
|
2936
2938
|
const exportNames = getExportNames(rawModule);
|
|
@@ -2938,7 +2940,7 @@ export function generateWorkerCode(options) {
|
|
|
2938
2940
|
const hoistedImports = imports.length > 0 ? imports.join('\n') + '\n' : '';
|
|
2939
2941
|
return `
|
|
2940
2942
|
// Sandbox Worker Entry Point
|
|
2941
|
-
import { RpcTarget, newWorkersRpcResponse } from 'capnweb';
|
|
2943
|
+
import { RpcTarget, newWorkersRpcResponse } from 'capnweb.js';
|
|
2942
2944
|
${hoistedImports}
|
|
2943
2945
|
const logs = [];
|
|
2944
2946
|
|
|
@@ -2968,20 +2970,24 @@ console.debug = captureConsole('debug');
|
|
|
2968
2970
|
// Module exports object - exports become top-level variables
|
|
2969
2971
|
const exports = {};
|
|
2970
2972
|
|
|
2971
|
-
${module
|
|
2973
|
+
${module
|
|
2974
|
+
? `
|
|
2972
2975
|
// Execute module code
|
|
2973
2976
|
try {
|
|
2974
2977
|
${module}
|
|
2975
2978
|
} catch (e) {
|
|
2976
2979
|
console.error('Module error:', e.message);
|
|
2977
2980
|
}
|
|
2978
|
-
`
|
|
2981
|
+
`
|
|
2982
|
+
: '// No module code provided'}
|
|
2979
2983
|
|
|
2980
2984
|
// Expose all exports as top-level variables for tests and scripts
|
|
2981
2985
|
// This allows: export const add = (a, b) => a + b; then later: add(1, 2)
|
|
2982
|
-
${rawModule
|
|
2986
|
+
${rawModule
|
|
2987
|
+
? `
|
|
2983
2988
|
const { ${exportNames} } = exports;
|
|
2984
|
-
`.trim()
|
|
2989
|
+
`.trim()
|
|
2990
|
+
: ''}
|
|
2985
2991
|
|
|
2986
2992
|
// ============================================================
|
|
2987
2993
|
// RPC SERVER - Expose exports via capnweb
|
|
@@ -3121,17 +3127,20 @@ export default {
|
|
|
3121
3127
|
// USER TEST CODE (embedded at generation time)
|
|
3122
3128
|
// ============================================================
|
|
3123
3129
|
|
|
3124
|
-
${tests
|
|
3130
|
+
${tests
|
|
3131
|
+
? `
|
|
3125
3132
|
// Register tests
|
|
3126
3133
|
try {
|
|
3127
3134
|
${tests}
|
|
3128
3135
|
} catch (e) {
|
|
3129
3136
|
console.error('Test registration error:', e.message);
|
|
3130
3137
|
}
|
|
3131
|
-
`
|
|
3138
|
+
`
|
|
3139
|
+
: '// No test code provided'}
|
|
3132
3140
|
|
|
3133
3141
|
// Execute user script
|
|
3134
|
-
${script
|
|
3142
|
+
${script
|
|
3143
|
+
? `
|
|
3135
3144
|
try {
|
|
3136
3145
|
scriptResult = await (async () => {
|
|
3137
3146
|
${script}
|
|
@@ -3140,17 +3149,20 @@ ${script}
|
|
|
3140
3149
|
console.error('Script error:', e.message);
|
|
3141
3150
|
scriptError = e.message;
|
|
3142
3151
|
}
|
|
3143
|
-
`
|
|
3152
|
+
`
|
|
3153
|
+
: '// No script code provided'}
|
|
3144
3154
|
|
|
3145
3155
|
// Run tests if any were registered
|
|
3146
|
-
${tests
|
|
3156
|
+
${tests
|
|
3157
|
+
? `
|
|
3147
3158
|
try {
|
|
3148
3159
|
testResults = await testService.run();
|
|
3149
3160
|
} catch (e) {
|
|
3150
3161
|
console.error('Test run error:', e.message);
|
|
3151
3162
|
testResults = { total: 0, passed: 0, failed: 1, skipped: 0, tests: [], duration: 0, error: e.message };
|
|
3152
3163
|
}
|
|
3153
|
-
`
|
|
3164
|
+
`
|
|
3165
|
+
: ''}
|
|
3154
3166
|
|
|
3155
3167
|
const hasTests = ${tests ? 'true' : 'false'};
|
|
3156
3168
|
const success = scriptError === null && (!hasTests || (testResults && testResults.failed === 0));
|
|
@@ -3174,14 +3186,33 @@ ${script}
|
|
|
3174
3186
|
* avoiding the need for RPC service bindings in local development.
|
|
3175
3187
|
*/
|
|
3176
3188
|
export function generateDevWorkerCode(options) {
|
|
3177
|
-
const { module: rawModule = '', tests = '', script: rawScript = '', sdk, imports = [], fetch: fetchOption } = options;
|
|
3178
|
-
const sdkConfig = sdk === true ? {} :
|
|
3189
|
+
const { module: rawModule = '', tests = '', script: rawScript = '', sdk, imports = [], fetch: fetchOption, } = options;
|
|
3190
|
+
const sdkConfig = sdk === true ? {} : sdk || null;
|
|
3179
3191
|
const module = rawModule ? transformModuleCode(rawModule) : '';
|
|
3180
3192
|
const script = rawScript ? wrapScriptForReturn(rawScript) : '';
|
|
3181
3193
|
const exportNames = getExportNames(rawModule);
|
|
3182
|
-
|
|
3194
|
+
// Determine fetch handling mode
|
|
3195
|
+
// - null or { mode: 'block' } -> block all network
|
|
3196
|
+
// - { mode: 'allowlist', allowedDomains: [...] } -> domain filtering
|
|
3197
|
+
// - undefined or { mode: 'allow' } -> allow all (no wrapper needed)
|
|
3198
|
+
const blockFetch = fetchOption === null || (fetchOption && fetchOption.mode === 'block');
|
|
3199
|
+
const useAllowlist = fetchOption && fetchOption.mode === 'allowlist' && fetchOption.allowedDomains;
|
|
3183
3200
|
// Hoisted imports (from MDX test files) - placed at true module top level
|
|
3184
3201
|
const hoistedImports = imports.length > 0 ? imports.join('\n') + '\n' : '';
|
|
3202
|
+
// Generate fetch control code based on mode
|
|
3203
|
+
let fetchControlCode = '';
|
|
3204
|
+
if (blockFetch) {
|
|
3205
|
+
fetchControlCode = `
|
|
3206
|
+
// Block fetch when fetch: null or mode: 'block' is specified
|
|
3207
|
+
const __originalFetch__ = globalThis.fetch;
|
|
3208
|
+
globalThis.fetch = async (...args) => {
|
|
3209
|
+
throw new Error('Network access blocked: fetch is disabled in this sandbox');
|
|
3210
|
+
};
|
|
3211
|
+
`;
|
|
3212
|
+
}
|
|
3213
|
+
else if (useAllowlist) {
|
|
3214
|
+
fetchControlCode = generateDomainCheckCode(fetchOption.allowedDomains);
|
|
3215
|
+
}
|
|
3185
3216
|
return `
|
|
3186
3217
|
// Sandbox Worker Entry Point (Dev Mode - embedded test framework)
|
|
3187
3218
|
${hoistedImports}
|
|
@@ -3189,13 +3220,7 @@ const logs = [];
|
|
|
3189
3220
|
const testResults = { total: 0, passed: 0, failed: 0, skipped: 0, tests: [], duration: 0 };
|
|
3190
3221
|
const pendingTests = [];
|
|
3191
3222
|
|
|
3192
|
-
${
|
|
3193
|
-
// Block fetch when fetch: null is specified
|
|
3194
|
-
const __originalFetch__ = globalThis.fetch;
|
|
3195
|
-
globalThis.fetch = async (...args) => {
|
|
3196
|
-
throw new Error('Network access blocked: fetch is disabled in this sandbox');
|
|
3197
|
-
};
|
|
3198
|
-
` : ''}
|
|
3223
|
+
${fetchControlCode}
|
|
3199
3224
|
|
|
3200
3225
|
${sdkConfig ? generateShouldCode() : ''}
|
|
3201
3226
|
|
|
@@ -3503,32 +3528,38 @@ const expect = (actual) => {
|
|
|
3503
3528
|
// Module exports object - exports become top-level variables
|
|
3504
3529
|
const exports = {};
|
|
3505
3530
|
|
|
3506
|
-
${module
|
|
3531
|
+
${module
|
|
3532
|
+
? `
|
|
3507
3533
|
// Execute module code
|
|
3508
3534
|
try {
|
|
3509
3535
|
${module}
|
|
3510
3536
|
} catch (e) {
|
|
3511
3537
|
console.error('Module error:', e.message);
|
|
3512
3538
|
}
|
|
3513
|
-
`
|
|
3539
|
+
`
|
|
3540
|
+
: '// No module code provided'}
|
|
3514
3541
|
|
|
3515
3542
|
// Expose all exports as top-level variables for tests and scripts
|
|
3516
3543
|
// This allows: export const add = (a, b) => a + b; then later: add(1, 2)
|
|
3517
|
-
${rawModule
|
|
3544
|
+
${rawModule
|
|
3545
|
+
? `
|
|
3518
3546
|
const { ${exportNames} } = exports;
|
|
3519
|
-
`.trim()
|
|
3547
|
+
`.trim()
|
|
3548
|
+
: ''}
|
|
3520
3549
|
|
|
3521
3550
|
// ============================================================
|
|
3522
3551
|
// USER TEST CODE (embedded at generation time)
|
|
3523
3552
|
// ============================================================
|
|
3524
|
-
${tests
|
|
3553
|
+
${tests
|
|
3554
|
+
? `
|
|
3525
3555
|
// Register tests
|
|
3526
3556
|
try {
|
|
3527
3557
|
${tests}
|
|
3528
3558
|
} catch (e) {
|
|
3529
3559
|
console.error('Test registration error:', e.message);
|
|
3530
3560
|
}
|
|
3531
|
-
`
|
|
3561
|
+
`
|
|
3562
|
+
: '// No test code provided'}
|
|
3532
3563
|
|
|
3533
3564
|
// ============================================================
|
|
3534
3565
|
// SIMPLE RPC HANDLER (dev mode - no capnweb dependency)
|
|
@@ -3629,7 +3660,8 @@ export default {
|
|
|
3629
3660
|
let scriptError = null;
|
|
3630
3661
|
|
|
3631
3662
|
// Execute user script
|
|
3632
|
-
${script
|
|
3663
|
+
${script
|
|
3664
|
+
? `
|
|
3633
3665
|
try {
|
|
3634
3666
|
scriptResult = await (async () => {
|
|
3635
3667
|
${script}
|
|
@@ -3638,7 +3670,8 @@ ${script}
|
|
|
3638
3670
|
console.error('Script error:', e.message);
|
|
3639
3671
|
scriptError = e.message;
|
|
3640
3672
|
}
|
|
3641
|
-
`
|
|
3673
|
+
`
|
|
3674
|
+
: '// No script code provided'}
|
|
3642
3675
|
|
|
3643
3676
|
// Run all pending tests
|
|
3644
3677
|
const testStart = Date.now();
|