ai-evaluate 2.1.8 → 2.3.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/README.md +16 -0
- package/dist/evaluate.d.ts.map +1 -1
- package/dist/evaluate.js +10 -10
- package/dist/evaluate.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/miniflare-pool.d.ts.map +1 -1
- package/dist/miniflare-pool.js +1 -1
- package/dist/miniflare-pool.js.map +1 -1
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js.map +1 -1
- package/dist/repl.js +6 -6
- package/dist/repl.js.map +1 -1
- package/dist/shared.d.ts.map +1 -1
- package/dist/shared.js +5 -2
- package/dist/shared.js.map +1 -1
- package/dist/static/index.d.ts +111 -0
- package/dist/static/index.d.ts.map +1 -0
- package/dist/static/index.js +347 -0
- package/dist/static/index.js.map +1 -0
- package/dist/type-guards.d.ts.map +1 -1
- package/dist/type-guards.js +64 -62
- package/dist/type-guards.js.map +1 -1
- package/dist/worker-template/core.d.ts.map +1 -1
- package/dist/worker-template/core.js +1 -1
- package/dist/worker-template/core.js.map +1 -1
- package/package.json +19 -6
- package/public/capnweb.mjs +220 -0
- package/public/index.mjs +426 -0
- package/public/scaffold.mjs +198 -0
- package/.turbo/turbo-build.log +0 -4
- package/.turbo/turbo-test.log +0 -54
- package/.turbo/turbo-typecheck.log +0 -4
- package/CHANGELOG.md +0 -48
- package/dist/worker-template.d.ts +0 -41
- package/dist/worker-template.d.ts.map +0 -1
- package/dist/worker-template.js +0 -3748
- package/dist/worker-template.js.map +0 -1
- package/example/package.json +0 -20
- package/example/src/index.ts +0 -221
- package/example/wrangler.jsonc +0 -25
- package/src/capnweb-bundle.ts +0 -2596
- package/src/evaluate.ts +0 -329
- package/src/index.ts +0 -23
- package/src/miniflare-pool.ts +0 -395
- package/src/node.ts +0 -245
- package/src/repl.ts +0 -228
- package/src/shared.ts +0 -186
- package/src/type-guards.ts +0 -323
- package/src/types.ts +0 -196
- package/src/validation.ts +0 -120
- package/src/worker-template/code-transforms.ts +0 -32
- package/src/worker-template/core.ts +0 -557
- package/src/worker-template/helpers.ts +0 -90
- package/src/worker-template/index.ts +0 -23
- package/src/worker-template/sdk-generator.ts +0 -2515
- package/src/worker-template/test-generator.ts +0 -358
- package/test/evaluate-extended.test.js +0 -429
- package/test/evaluate-extended.test.ts +0 -469
- package/test/evaluate.test.js +0 -235
- package/test/evaluate.test.ts +0 -253
- package/test/index.test.js +0 -77
- package/test/index.test.ts +0 -95
- package/test/miniflare-pool.test.ts +0 -246
- package/test/node.test.ts +0 -467
- package/test/security.test.ts +0 -1009
- package/test/shared.test.ts +0 -105
- package/test/type-guards.test.ts +0 -303
- package/test/validation.test.ts +0 -240
- package/test/worker-template.test.js +0 -365
- package/test/worker-template.test.ts +0 -432
- package/tsconfig.json +0 -22
- package/vitest.config.js +0 -21
- package/vitest.config.ts +0 -28
package/public/index.mjs
ADDED
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ai-evaluate v2.2.0
|
|
3
|
+
* Static worker template for evaluate.workers.do
|
|
4
|
+
* Generated: 2026-05-26T11:50:49.389Z
|
|
5
|
+
*
|
|
6
|
+
* @license MIT
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// Full worker template with capnweb RPC support
|
|
10
|
+
// Import capnweb from the capnweb.js module
|
|
11
|
+
|
|
12
|
+
import { RpcTarget, newWorkersRpcResponse } from 'capnweb.js';
|
|
13
|
+
|
|
14
|
+
const logs = [];
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
// ============================================================
|
|
18
|
+
// Global .should Chainable Assertions
|
|
19
|
+
// ============================================================
|
|
20
|
+
|
|
21
|
+
const __createShouldChain__ = (actual, negated = false) => {
|
|
22
|
+
const check = (condition, message) => {
|
|
23
|
+
const passes = negated ? !condition : condition;
|
|
24
|
+
if (!passes) throw new Error(negated ? 'Expected NOT: ' + message : message);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const stringify = (val) => {
|
|
28
|
+
try {
|
|
29
|
+
return JSON.stringify(val);
|
|
30
|
+
} catch {
|
|
31
|
+
return String(val);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// Create a lazy chain getter - returns 'this' assertion for chaining
|
|
36
|
+
const assertion = {};
|
|
37
|
+
|
|
38
|
+
// Core assertion methods
|
|
39
|
+
assertion.equal = (expected) => {
|
|
40
|
+
check(actual === expected, 'Expected ' + stringify(actual) + ' to equal ' + stringify(expected));
|
|
41
|
+
return assertion;
|
|
42
|
+
};
|
|
43
|
+
assertion.deep = {
|
|
44
|
+
equal: (expected) => {
|
|
45
|
+
check(stringify(actual) === stringify(expected), 'Expected deep equal to ' + stringify(expected));
|
|
46
|
+
return assertion;
|
|
47
|
+
},
|
|
48
|
+
include: (expected) => {
|
|
49
|
+
const actualStr = stringify(actual);
|
|
50
|
+
const expectedStr = stringify(expected);
|
|
51
|
+
// Check if expected properties exist with same values
|
|
52
|
+
const matches = Object.entries(expected || {}).every(([k, v]) =>
|
|
53
|
+
actual && stringify(actual[k]) === stringify(v)
|
|
54
|
+
);
|
|
55
|
+
check(matches, 'Expected ' + actualStr + ' to deeply include ' + expectedStr);
|
|
56
|
+
return assertion;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
assertion.include = (value) => {
|
|
60
|
+
if (typeof actual === 'string') check(actual.includes(String(value)), 'Expected "' + actual + '" to include "' + value + '"');
|
|
61
|
+
else if (Array.isArray(actual)) check(actual.includes(value), 'Expected array to include ' + stringify(value));
|
|
62
|
+
return assertion;
|
|
63
|
+
};
|
|
64
|
+
assertion.contain = assertion.include;
|
|
65
|
+
assertion.lengthOf = (n) => {
|
|
66
|
+
check(actual?.length === n, 'Expected length ' + n + ', got ' + actual?.length);
|
|
67
|
+
return assertion;
|
|
68
|
+
};
|
|
69
|
+
assertion.match = (regex) => {
|
|
70
|
+
const str = String(actual);
|
|
71
|
+
check(regex.test(str), 'Expected "' + str + '" to match ' + regex);
|
|
72
|
+
return assertion;
|
|
73
|
+
};
|
|
74
|
+
assertion.matches = assertion.match;
|
|
75
|
+
|
|
76
|
+
// .be accessor with type checks
|
|
77
|
+
Object.defineProperty(assertion, 'be', {
|
|
78
|
+
get: () => {
|
|
79
|
+
const beObj = {
|
|
80
|
+
a: (type) => {
|
|
81
|
+
const actualType = actual === null ? 'null' : Array.isArray(actual) ? 'array' : actual instanceof Date ? 'date' : typeof actual;
|
|
82
|
+
check(actualType === type.toLowerCase(), 'Expected ' + stringify(actual) + ' to be a ' + type);
|
|
83
|
+
return assertion;
|
|
84
|
+
},
|
|
85
|
+
above: (n) => { check(actual > n, 'Expected ' + actual + ' to be above ' + n); return assertion; },
|
|
86
|
+
below: (n) => { check(actual < n, 'Expected ' + actual + ' to be below ' + n); return assertion; },
|
|
87
|
+
within: (min, max) => { check(actual >= min && actual <= max, 'Expected ' + actual + ' to be within ' + min + '..' + max); return assertion; },
|
|
88
|
+
oneOf: (arr) => { check(Array.isArray(arr) && arr.includes(actual), 'Expected ' + stringify(actual) + ' to be one of ' + stringify(arr)); return assertion; },
|
|
89
|
+
instanceOf: (cls) => { check(actual instanceof cls, 'Expected to be instance of ' + cls.name); return assertion; }
|
|
90
|
+
};
|
|
91
|
+
beObj.an = beObj.a;
|
|
92
|
+
Object.defineProperty(beObj, 'true', { get: () => { check(actual === true, 'Expected ' + stringify(actual) + ' to be true'); return assertion; } });
|
|
93
|
+
Object.defineProperty(beObj, 'false', { get: () => { check(actual === false, 'Expected ' + stringify(actual) + ' to be false'); return assertion; } });
|
|
94
|
+
Object.defineProperty(beObj, 'ok', { get: () => { check(!!actual, 'Expected ' + stringify(actual) + ' to be truthy'); return assertion; } });
|
|
95
|
+
Object.defineProperty(beObj, 'null', { get: () => { check(actual === null, 'Expected ' + stringify(actual) + ' to be null'); return assertion; } });
|
|
96
|
+
Object.defineProperty(beObj, 'undefined', { get: () => { check(actual === undefined, 'Expected ' + stringify(actual) + ' to be undefined'); return assertion; } });
|
|
97
|
+
Object.defineProperty(beObj, 'empty', { get: () => {
|
|
98
|
+
const isEmpty = actual === '' || (Array.isArray(actual) && actual.length === 0) || (actual && typeof actual === 'object' && Object.keys(actual).length === 0);
|
|
99
|
+
check(isEmpty, 'Expected ' + stringify(actual) + ' to be empty');
|
|
100
|
+
return assertion;
|
|
101
|
+
}});
|
|
102
|
+
return beObj;
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// .have accessor with property/keys/lengthOf/at checks
|
|
107
|
+
Object.defineProperty(assertion, 'have', {
|
|
108
|
+
get: () => ({
|
|
109
|
+
property: (name, value) => {
|
|
110
|
+
const hasIt = actual != null && Object.prototype.hasOwnProperty.call(actual, name);
|
|
111
|
+
if (value !== undefined) {
|
|
112
|
+
check(hasIt && actual[name] === value, "Expected property '" + name + "' = " + stringify(value) + ", got " + stringify(actual?.[name]));
|
|
113
|
+
} else {
|
|
114
|
+
check(hasIt, "Expected to have property '" + name + "'");
|
|
115
|
+
}
|
|
116
|
+
if (hasIt) return __createShouldChain__(actual[name], negated);
|
|
117
|
+
return assertion;
|
|
118
|
+
},
|
|
119
|
+
keys: (...keys) => {
|
|
120
|
+
const actualKeys = Object.keys(actual || {});
|
|
121
|
+
check(keys.every(k => actualKeys.includes(k)), 'Expected to have keys ' + stringify(keys));
|
|
122
|
+
return assertion;
|
|
123
|
+
},
|
|
124
|
+
lengthOf: (n) => {
|
|
125
|
+
check(actual?.length === n, 'Expected length ' + n + ', got ' + actual?.length);
|
|
126
|
+
return assertion;
|
|
127
|
+
},
|
|
128
|
+
at: {
|
|
129
|
+
least: (n) => {
|
|
130
|
+
check(actual?.length >= n, 'Expected length at least ' + n + ', got ' + actual?.length);
|
|
131
|
+
return assertion;
|
|
132
|
+
},
|
|
133
|
+
most: (n) => {
|
|
134
|
+
check(actual?.length <= n, 'Expected length at most ' + n + ', got ' + actual?.length);
|
|
135
|
+
return assertion;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
})
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// .not negation
|
|
142
|
+
Object.defineProperty(assertion, 'not', {
|
|
143
|
+
get: () => __createShouldChain__(actual, !negated)
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// .with passthrough for readability
|
|
147
|
+
Object.defineProperty(assertion, 'with', {
|
|
148
|
+
get: () => assertion
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// .that passthrough for chaining (e.g. .have.property('x').that.matches(/.../) )
|
|
152
|
+
Object.defineProperty(assertion, 'that', {
|
|
153
|
+
get: () => assertion
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// .and passthrough for chaining
|
|
157
|
+
Object.defineProperty(assertion, 'and', {
|
|
158
|
+
get: () => assertion
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
return assertion;
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
// Add .should to Object.prototype
|
|
165
|
+
Object.defineProperty(Object.prototype, 'should', {
|
|
166
|
+
get: function() { return __createShouldChain__(this); },
|
|
167
|
+
configurable: true,
|
|
168
|
+
enumerable: false
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
// Capture console output
|
|
173
|
+
const originalConsole = { ...console };
|
|
174
|
+
const captureConsole = (level) => (...args) => {
|
|
175
|
+
logs.push({
|
|
176
|
+
level,
|
|
177
|
+
message: args.map(a => typeof a === 'object' ? JSON.stringify(a) : String(a)).join(' '),
|
|
178
|
+
timestamp: Date.now()
|
|
179
|
+
});
|
|
180
|
+
originalConsole[level](...args);
|
|
181
|
+
};
|
|
182
|
+
console.log = captureConsole('log');
|
|
183
|
+
console.warn = captureConsole('warn');
|
|
184
|
+
console.error = captureConsole('error');
|
|
185
|
+
console.info = captureConsole('info');
|
|
186
|
+
console.debug = captureConsole('debug');
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
// Test framework (vitest-compatible API)
|
|
190
|
+
let currentDescribe = '';
|
|
191
|
+
let beforeEachFns = [];
|
|
192
|
+
let afterEachFns = [];
|
|
193
|
+
|
|
194
|
+
const describe = (name, fn) => {
|
|
195
|
+
const prev = currentDescribe;
|
|
196
|
+
const prevBeforeEach = [...beforeEachFns];
|
|
197
|
+
const prevAfterEach = [...afterEachFns];
|
|
198
|
+
currentDescribe = currentDescribe ? currentDescribe + ' > ' + name : name;
|
|
199
|
+
try { fn(); } finally {
|
|
200
|
+
currentDescribe = prev;
|
|
201
|
+
beforeEachFns = prevBeforeEach;
|
|
202
|
+
afterEachFns = prevAfterEach;
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
// Hooks
|
|
207
|
+
const beforeEach = (fn) => { beforeEachFns.push(fn); };
|
|
208
|
+
const afterEach = (fn) => { afterEachFns.push(fn); };
|
|
209
|
+
|
|
210
|
+
const it = (name, fn) => {
|
|
211
|
+
const fullName = currentDescribe ? currentDescribe + ' > ' + name : name;
|
|
212
|
+
const hooks = { before: [...beforeEachFns], after: [...afterEachFns] };
|
|
213
|
+
pendingTests.push({ name: fullName, fn, hooks });
|
|
214
|
+
};
|
|
215
|
+
const test = it;
|
|
216
|
+
|
|
217
|
+
it.skip = (name, fn) => {
|
|
218
|
+
const fullName = currentDescribe ? currentDescribe + ' > ' + name : name;
|
|
219
|
+
pendingTests.push({ name: fullName, fn: null, skip: true });
|
|
220
|
+
};
|
|
221
|
+
test.skip = it.skip;
|
|
222
|
+
|
|
223
|
+
it.only = (name, fn) => {
|
|
224
|
+
const fullName = currentDescribe ? currentDescribe + ' > ' + name : name;
|
|
225
|
+
const hooks = { before: [...beforeEachFns], after: [...afterEachFns] };
|
|
226
|
+
pendingTests.push({ name: fullName, fn, hooks, only: true });
|
|
227
|
+
};
|
|
228
|
+
test.only = it.only;
|
|
229
|
+
|
|
230
|
+
// Deep equality check
|
|
231
|
+
const deepEqual = (a, b) => {
|
|
232
|
+
if (a === b) return true;
|
|
233
|
+
if (a == null || b == null) return false;
|
|
234
|
+
if (typeof a !== typeof b) return false;
|
|
235
|
+
if (typeof a !== 'object') return false;
|
|
236
|
+
if (Array.isArray(a) !== Array.isArray(b)) return false;
|
|
237
|
+
if (Array.isArray(a)) {
|
|
238
|
+
if (a.length !== b.length) return false;
|
|
239
|
+
return a.every((v, i) => deepEqual(v, b[i]));
|
|
240
|
+
}
|
|
241
|
+
const keysA = Object.keys(a);
|
|
242
|
+
const keysB = Object.keys(b);
|
|
243
|
+
if (keysA.length !== keysB.length) return false;
|
|
244
|
+
return keysA.every(k => deepEqual(a[k], b[k]));
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
// Expect implementation with vitest-compatible matchers
|
|
248
|
+
const expect = (actual) => {
|
|
249
|
+
const matchers = {
|
|
250
|
+
toBe: (expected) => {
|
|
251
|
+
if (actual !== expected) {
|
|
252
|
+
throw new Error(\
|
|
253
|
+
|
|
254
|
+
// Module exports object
|
|
255
|
+
const exports = {};
|
|
256
|
+
const pendingTests = [];
|
|
257
|
+
const testResults = { total: 0, passed: 0, failed: 0, skipped: 0, tests: [], duration: 0 };
|
|
258
|
+
|
|
259
|
+
// ============================================================
|
|
260
|
+
// USER CODE PLACEHOLDER
|
|
261
|
+
// ============================================================
|
|
262
|
+
// USER_MODULE_CODE
|
|
263
|
+
// USER_TEST_CODE
|
|
264
|
+
|
|
265
|
+
// ============================================================
|
|
266
|
+
// RPC SERVER - Expose exports via capnweb
|
|
267
|
+
// ============================================================
|
|
268
|
+
class ExportsRpcTarget extends RpcTarget {
|
|
269
|
+
constructor() {
|
|
270
|
+
super();
|
|
271
|
+
for (const [key, value] of Object.entries(exports)) {
|
|
272
|
+
if (typeof value === 'function') {
|
|
273
|
+
this[key] = value;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
list() {
|
|
279
|
+
return Object.keys(exports);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
get(name) {
|
|
283
|
+
return exports[name];
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// ============================================================
|
|
288
|
+
// WORKER ENTRY POINT
|
|
289
|
+
// ============================================================
|
|
290
|
+
export default {
|
|
291
|
+
async fetch(request, env) {
|
|
292
|
+
const url = new URL(request.url);
|
|
293
|
+
|
|
294
|
+
// Route: GET / - Return info about exports
|
|
295
|
+
if (request.method === 'GET' && url.pathname === '/') {
|
|
296
|
+
return Response.json({
|
|
297
|
+
exports: Object.keys(exports),
|
|
298
|
+
rpc: '/rpc',
|
|
299
|
+
execute: '/execute'
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Route: /rpc - capnweb RPC to module exports
|
|
304
|
+
if (url.pathname === '/rpc') {
|
|
305
|
+
return newWorkersRpcResponse(request, new ExportsRpcTarget());
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Route: GET /:name - Simple JSON endpoint to access exports
|
|
309
|
+
if (request.method === 'GET' && url.pathname !== '/execute') {
|
|
310
|
+
const name = url.pathname.slice(1);
|
|
311
|
+
const value = exports[name];
|
|
312
|
+
|
|
313
|
+
if (!(name in exports)) {
|
|
314
|
+
return Response.json({ error: `Export "${name}" not found` }, { status: 404 });
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
if (typeof value !== 'function') {
|
|
318
|
+
return Response.json({ result: value });
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
try {
|
|
322
|
+
const args = [];
|
|
323
|
+
const argsParam = url.searchParams.get('args');
|
|
324
|
+
if (argsParam) {
|
|
325
|
+
try {
|
|
326
|
+
const parsed = JSON.parse(argsParam);
|
|
327
|
+
if (Array.isArray(parsed)) args.push(...parsed);
|
|
328
|
+
else args.push(parsed);
|
|
329
|
+
} catch {
|
|
330
|
+
args.push(argsParam);
|
|
331
|
+
}
|
|
332
|
+
} else {
|
|
333
|
+
const params = Object.fromEntries(url.searchParams.entries());
|
|
334
|
+
if (Object.keys(params).length > 0) {
|
|
335
|
+
for (const [key, val] of Object.entries(params)) {
|
|
336
|
+
const num = Number(val);
|
|
337
|
+
params[key] = !isNaN(num) && val !== '' ? num : val;
|
|
338
|
+
}
|
|
339
|
+
args.push(params);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
const result = await value(...args);
|
|
343
|
+
return Response.json({ result });
|
|
344
|
+
} catch (e) {
|
|
345
|
+
return Response.json({ error: e.message }, { status: 500 });
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Route: /execute - Run tests and scripts
|
|
350
|
+
let scriptResult = undefined;
|
|
351
|
+
let scriptError = null;
|
|
352
|
+
|
|
353
|
+
// USER_SCRIPT_CODE
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
// Run all pending tests
|
|
357
|
+
const testStart = Date.now();
|
|
358
|
+
const hasOnly = pendingTests.some(t => t.only);
|
|
359
|
+
const testsToRun = hasOnly ? pendingTests.filter(t => t.only || t.skip) : pendingTests;
|
|
360
|
+
|
|
361
|
+
for (const { name, fn, hooks, skip } of testsToRun) {
|
|
362
|
+
testResults.total++;
|
|
363
|
+
|
|
364
|
+
if (skip) {
|
|
365
|
+
testResults.skipped++;
|
|
366
|
+
testResults.tests.push({ name, passed: true, skipped: true, duration: 0 });
|
|
367
|
+
continue;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
const start = Date.now();
|
|
371
|
+
try {
|
|
372
|
+
// Run beforeEach hooks
|
|
373
|
+
if (hooks?.before) {
|
|
374
|
+
for (const hook of hooks.before) {
|
|
375
|
+
const hookResult = hook();
|
|
376
|
+
if (hookResult && typeof hookResult.then === 'function') {
|
|
377
|
+
await hookResult;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// Run the test
|
|
383
|
+
const result = fn();
|
|
384
|
+
if (result && typeof result.then === 'function') {
|
|
385
|
+
await result;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// Run afterEach hooks
|
|
389
|
+
if (hooks?.after) {
|
|
390
|
+
for (const hook of hooks.after) {
|
|
391
|
+
const hookResult = hook();
|
|
392
|
+
if (hookResult && typeof hookResult.then === 'function') {
|
|
393
|
+
await hookResult;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
testResults.passed++;
|
|
399
|
+
testResults.tests.push({ name, passed: true, duration: Date.now() - start });
|
|
400
|
+
} catch (e) {
|
|
401
|
+
testResults.failed++;
|
|
402
|
+
testResults.tests.push({
|
|
403
|
+
name,
|
|
404
|
+
passed: false,
|
|
405
|
+
error: e.message || String(e),
|
|
406
|
+
duration: Date.now() - start
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
testResults.duration = Date.now() - testStart;
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
const hasTests = pendingTests.length > 0;
|
|
415
|
+
const success = scriptError === null && (!hasTests || testResults.failed === 0);
|
|
416
|
+
|
|
417
|
+
return Response.json({
|
|
418
|
+
success,
|
|
419
|
+
value: scriptResult,
|
|
420
|
+
logs,
|
|
421
|
+
testResults: hasTests ? testResults : undefined,
|
|
422
|
+
error: scriptError || undefined,
|
|
423
|
+
duration: 0
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
};
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ai-evaluate v2.2.0
|
|
3
|
+
* Static worker template for evaluate.workers.do
|
|
4
|
+
* Generated: 2026-05-26T11:50:49.389Z
|
|
5
|
+
*
|
|
6
|
+
* @license MIT
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// Base worker scaffold without capnweb dependency
|
|
10
|
+
// Use this for dev mode or when capnweb is not needed
|
|
11
|
+
|
|
12
|
+
const logs = [];
|
|
13
|
+
|
|
14
|
+
// Capture console output
|
|
15
|
+
const originalConsole = { ...console };
|
|
16
|
+
const captureConsole = (level) => (...args) => {
|
|
17
|
+
logs.push({
|
|
18
|
+
level,
|
|
19
|
+
message: args.map(a => typeof a === 'object' ? JSON.stringify(a) : String(a)).join(' '),
|
|
20
|
+
timestamp: Date.now()
|
|
21
|
+
});
|
|
22
|
+
originalConsole[level](...args);
|
|
23
|
+
};
|
|
24
|
+
console.log = captureConsole('log');
|
|
25
|
+
console.warn = captureConsole('warn');
|
|
26
|
+
console.error = captureConsole('error');
|
|
27
|
+
console.info = captureConsole('info');
|
|
28
|
+
console.debug = captureConsole('debug');
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
// Test framework (vitest-compatible API)
|
|
32
|
+
let currentDescribe = '';
|
|
33
|
+
let beforeEachFns = [];
|
|
34
|
+
let afterEachFns = [];
|
|
35
|
+
|
|
36
|
+
const describe = (name, fn) => {
|
|
37
|
+
const prev = currentDescribe;
|
|
38
|
+
const prevBeforeEach = [...beforeEachFns];
|
|
39
|
+
const prevAfterEach = [...afterEachFns];
|
|
40
|
+
currentDescribe = currentDescribe ? currentDescribe + ' > ' + name : name;
|
|
41
|
+
try { fn(); } finally {
|
|
42
|
+
currentDescribe = prev;
|
|
43
|
+
beforeEachFns = prevBeforeEach;
|
|
44
|
+
afterEachFns = prevAfterEach;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// Hooks
|
|
49
|
+
const beforeEach = (fn) => { beforeEachFns.push(fn); };
|
|
50
|
+
const afterEach = (fn) => { afterEachFns.push(fn); };
|
|
51
|
+
|
|
52
|
+
const it = (name, fn) => {
|
|
53
|
+
const fullName = currentDescribe ? currentDescribe + ' > ' + name : name;
|
|
54
|
+
const hooks = { before: [...beforeEachFns], after: [...afterEachFns] };
|
|
55
|
+
pendingTests.push({ name: fullName, fn, hooks });
|
|
56
|
+
};
|
|
57
|
+
const test = it;
|
|
58
|
+
|
|
59
|
+
it.skip = (name, fn) => {
|
|
60
|
+
const fullName = currentDescribe ? currentDescribe + ' > ' + name : name;
|
|
61
|
+
pendingTests.push({ name: fullName, fn: null, skip: true });
|
|
62
|
+
};
|
|
63
|
+
test.skip = it.skip;
|
|
64
|
+
|
|
65
|
+
it.only = (name, fn) => {
|
|
66
|
+
const fullName = currentDescribe ? currentDescribe + ' > ' + name : name;
|
|
67
|
+
const hooks = { before: [...beforeEachFns], after: [...afterEachFns] };
|
|
68
|
+
pendingTests.push({ name: fullName, fn, hooks, only: true });
|
|
69
|
+
};
|
|
70
|
+
test.only = it.only;
|
|
71
|
+
|
|
72
|
+
// Deep equality check
|
|
73
|
+
const deepEqual = (a, b) => {
|
|
74
|
+
if (a === b) return true;
|
|
75
|
+
if (a == null || b == null) return false;
|
|
76
|
+
if (typeof a !== typeof b) return false;
|
|
77
|
+
if (typeof a !== 'object') return false;
|
|
78
|
+
if (Array.isArray(a) !== Array.isArray(b)) return false;
|
|
79
|
+
if (Array.isArray(a)) {
|
|
80
|
+
if (a.length !== b.length) return false;
|
|
81
|
+
return a.every((v, i) => deepEqual(v, b[i]));
|
|
82
|
+
}
|
|
83
|
+
const keysA = Object.keys(a);
|
|
84
|
+
const keysB = Object.keys(b);
|
|
85
|
+
if (keysA.length !== keysB.length) return false;
|
|
86
|
+
return keysA.every(k => deepEqual(a[k], b[k]));
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
// Expect implementation with vitest-compatible matchers
|
|
90
|
+
const expect = (actual) => {
|
|
91
|
+
const matchers = {
|
|
92
|
+
toBe: (expected) => {
|
|
93
|
+
if (actual !== expected) {
|
|
94
|
+
throw new Error(\
|
|
95
|
+
|
|
96
|
+
// Module exports object
|
|
97
|
+
const exports = {};
|
|
98
|
+
const pendingTests = [];
|
|
99
|
+
const testResults = { total: 0, passed: 0, failed: 0, skipped: 0, tests: [], duration: 0 };
|
|
100
|
+
|
|
101
|
+
// ============================================================
|
|
102
|
+
// USER CODE PLACEHOLDER
|
|
103
|
+
// ============================================================
|
|
104
|
+
// USER_MODULE_CODE
|
|
105
|
+
// USER_TEST_CODE
|
|
106
|
+
// USER_SCRIPT_CODE
|
|
107
|
+
|
|
108
|
+
// ============================================================
|
|
109
|
+
// WORKER ENTRY POINT
|
|
110
|
+
// ============================================================
|
|
111
|
+
export default {
|
|
112
|
+
async fetch(request, env) {
|
|
113
|
+
const url = new URL(request.url);
|
|
114
|
+
|
|
115
|
+
// Route: GET / - Return info
|
|
116
|
+
if (request.method === 'GET' && url.pathname === '/') {
|
|
117
|
+
return Response.json({
|
|
118
|
+
exports: Object.keys(exports),
|
|
119
|
+
execute: '/execute'
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Route: /execute - Run tests and scripts
|
|
124
|
+
let scriptResult = undefined;
|
|
125
|
+
let scriptError = null;
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
// Run all pending tests
|
|
129
|
+
const testStart = Date.now();
|
|
130
|
+
const hasOnly = pendingTests.some(t => t.only);
|
|
131
|
+
const testsToRun = hasOnly ? pendingTests.filter(t => t.only || t.skip) : pendingTests;
|
|
132
|
+
|
|
133
|
+
for (const { name, fn, hooks, skip } of testsToRun) {
|
|
134
|
+
testResults.total++;
|
|
135
|
+
|
|
136
|
+
if (skip) {
|
|
137
|
+
testResults.skipped++;
|
|
138
|
+
testResults.tests.push({ name, passed: true, skipped: true, duration: 0 });
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const start = Date.now();
|
|
143
|
+
try {
|
|
144
|
+
// Run beforeEach hooks
|
|
145
|
+
if (hooks?.before) {
|
|
146
|
+
for (const hook of hooks.before) {
|
|
147
|
+
const hookResult = hook();
|
|
148
|
+
if (hookResult && typeof hookResult.then === 'function') {
|
|
149
|
+
await hookResult;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Run the test
|
|
155
|
+
const result = fn();
|
|
156
|
+
if (result && typeof result.then === 'function') {
|
|
157
|
+
await result;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Run afterEach hooks
|
|
161
|
+
if (hooks?.after) {
|
|
162
|
+
for (const hook of hooks.after) {
|
|
163
|
+
const hookResult = hook();
|
|
164
|
+
if (hookResult && typeof hookResult.then === 'function') {
|
|
165
|
+
await hookResult;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
testResults.passed++;
|
|
171
|
+
testResults.tests.push({ name, passed: true, duration: Date.now() - start });
|
|
172
|
+
} catch (e) {
|
|
173
|
+
testResults.failed++;
|
|
174
|
+
testResults.tests.push({
|
|
175
|
+
name,
|
|
176
|
+
passed: false,
|
|
177
|
+
error: e.message || String(e),
|
|
178
|
+
duration: Date.now() - start
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
testResults.duration = Date.now() - testStart;
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
const hasTests = pendingTests.length > 0;
|
|
187
|
+
const success = scriptError === null && (!hasTests || testResults.failed === 0);
|
|
188
|
+
|
|
189
|
+
return Response.json({
|
|
190
|
+
success,
|
|
191
|
+
value: scriptResult,
|
|
192
|
+
logs,
|
|
193
|
+
testResults: hasTests ? testResults : undefined,
|
|
194
|
+
error: scriptError || undefined,
|
|
195
|
+
duration: 0
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
};
|
package/.turbo/turbo-build.log
DELETED
package/.turbo/turbo-test.log
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
> ai-evaluate@2.1.3 test /Users/nathanclevenger/projects/primitives.org.ai/packages/ai-evaluate
|
|
3
|
-
> vitest
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
DEV v2.1.9 /Users/nathanclevenger/projects/primitives.org.ai/packages/ai-evaluate
|
|
7
|
-
|
|
8
|
-
✓ test/worker-template.test.ts (65 tests) 7ms
|
|
9
|
-
stdout | test/evaluate.test.ts > evaluate > script execution > captures console output
|
|
10
|
-
hello
|
|
11
|
-
|
|
12
|
-
stderr | test/evaluate.test.ts > evaluate > script execution > captures console output
|
|
13
|
-
warning
|
|
14
|
-
error
|
|
15
|
-
|
|
16
|
-
stdout | test/index.test.ts > types > LogEntry has correct shape
|
|
17
|
-
test
|
|
18
|
-
|
|
19
|
-
stderr | test/evaluate.test.ts > evaluate > script execution > handles script errors
|
|
20
|
-
Script error: test error
|
|
21
|
-
|
|
22
|
-
✓ test/index.test.ts (8 tests) 1959ms
|
|
23
|
-
✓ types > EvaluateOptions interface is usable 1765ms
|
|
24
|
-
stderr | test/evaluate-extended.test.ts > evaluate - extended tests > module errors > captures module runtime errors
|
|
25
|
-
Module error: module error
|
|
26
|
-
|
|
27
|
-
stdout | test/evaluate-extended.test.ts > evaluate - extended tests > console methods > captures console.info
|
|
28
|
-
info message
|
|
29
|
-
|
|
30
|
-
stdout | test/evaluate-extended.test.ts > evaluate - extended tests > console methods > captures console.debug
|
|
31
|
-
debug message
|
|
32
|
-
|
|
33
|
-
stdout | test/evaluate-extended.test.ts > evaluate - extended tests > console methods > stringifies objects in console output
|
|
34
|
-
{ a: 1 }
|
|
35
|
-
|
|
36
|
-
stdout | test/evaluate-extended.test.ts > evaluate - extended tests > console methods > joins multiple console arguments
|
|
37
|
-
a b c
|
|
38
|
-
|
|
39
|
-
stderr | test/evaluate-extended.test.ts > evaluate - extended tests > async scripts > handles Promise rejection in script
|
|
40
|
-
Script error: async error
|
|
41
|
-
|
|
42
|
-
✓ test/evaluate.test.ts (18 tests) 2319ms
|
|
43
|
-
✓ evaluate > script execution > executes simple expressions 1762ms
|
|
44
|
-
✓ test/evaluate-extended.test.ts (40 tests) 2896ms
|
|
45
|
-
✓ evaluate - extended tests > edge cases > handles empty options 1762ms
|
|
46
|
-
|
|
47
|
-
Test Files 4 passed (4)
|
|
48
|
-
Tests 131 passed (131)
|
|
49
|
-
Start at 16:04:47
|
|
50
|
-
Duration 3.30s (transform 119ms, setup 0ms, collect 216ms, tests 7.18s, environment 0ms, prepare 174ms)
|
|
51
|
-
|
|
52
|
-
PASS Waiting for file changes...
|
|
53
|
-
press h to show help, press q to quit
|
|
54
|
-
ELIFECYCLE Test failed. See above for more details.
|