ai-evaluate 2.1.8 → 2.2.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 (61) hide show
  1. package/dist/evaluate.d.ts.map +1 -1
  2. package/dist/evaluate.js.map +1 -1
  3. package/dist/index.d.ts +1 -1
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/miniflare-pool.d.ts.map +1 -1
  6. package/dist/miniflare-pool.js.map +1 -1
  7. package/dist/node.d.ts.map +1 -1
  8. package/dist/node.js.map +1 -1
  9. package/dist/static/index.d.ts +111 -0
  10. package/dist/static/index.d.ts.map +1 -0
  11. package/dist/static/index.js +347 -0
  12. package/dist/static/index.js.map +1 -0
  13. package/dist/type-guards.d.ts.map +1 -1
  14. package/dist/type-guards.js.map +1 -1
  15. package/dist/worker-template/core.d.ts.map +1 -1
  16. package/dist/worker-template/core.js +1 -1
  17. package/dist/worker-template/core.js.map +1 -1
  18. package/package.json +17 -4
  19. package/public/capnweb.mjs +220 -0
  20. package/public/index.mjs +426 -0
  21. package/public/scaffold.mjs +198 -0
  22. package/.turbo/turbo-build.log +0 -4
  23. package/.turbo/turbo-test.log +0 -54
  24. package/.turbo/turbo-typecheck.log +0 -4
  25. package/CHANGELOG.md +0 -48
  26. package/example/package.json +0 -20
  27. package/example/src/index.ts +0 -221
  28. package/example/wrangler.jsonc +0 -25
  29. package/src/capnweb-bundle.ts +0 -2596
  30. package/src/evaluate.ts +0 -329
  31. package/src/index.ts +0 -23
  32. package/src/miniflare-pool.ts +0 -395
  33. package/src/node.ts +0 -245
  34. package/src/repl.ts +0 -228
  35. package/src/shared.ts +0 -186
  36. package/src/type-guards.ts +0 -323
  37. package/src/types.ts +0 -196
  38. package/src/validation.ts +0 -120
  39. package/src/worker-template/code-transforms.ts +0 -32
  40. package/src/worker-template/core.ts +0 -557
  41. package/src/worker-template/helpers.ts +0 -90
  42. package/src/worker-template/index.ts +0 -23
  43. package/src/worker-template/sdk-generator.ts +0 -2515
  44. package/src/worker-template/test-generator.ts +0 -358
  45. package/test/evaluate-extended.test.js +0 -429
  46. package/test/evaluate-extended.test.ts +0 -469
  47. package/test/evaluate.test.js +0 -235
  48. package/test/evaluate.test.ts +0 -253
  49. package/test/index.test.js +0 -77
  50. package/test/index.test.ts +0 -95
  51. package/test/miniflare-pool.test.ts +0 -246
  52. package/test/node.test.ts +0 -467
  53. package/test/security.test.ts +0 -1009
  54. package/test/shared.test.ts +0 -105
  55. package/test/type-guards.test.ts +0 -303
  56. package/test/validation.test.ts +0 -240
  57. package/test/worker-template.test.js +0 -365
  58. package/test/worker-template.test.ts +0 -432
  59. package/tsconfig.json +0 -22
  60. package/vitest.config.js +0 -21
  61. package/vitest.config.ts +0 -28
@@ -0,0 +1,220 @@
1
+ /**
2
+ * ai-evaluate v2.1.8
3
+ * Static worker template for evaluate.workers.do
4
+ * Generated: 2026-01-26T01:42:47.000Z
5
+ *
6
+ * @license MIT
7
+ */
8
+
9
+ // Bundled capnweb RPC library for Cloudflare Workers
10
+ import * as cfw from 'cloudflare:workers';
11
+
12
+ // src/symbols.ts
13
+ var WORKERS_MODULE_SYMBOL = Symbol("workers-module");
14
+ globalThis[WORKERS_MODULE_SYMBOL] = cfw;
15
+
16
+ // src/core.ts
17
+ if (!Symbol.dispose) {
18
+ Symbol.dispose = Symbol.for("dispose");
19
+ }
20
+ if (!Symbol.asyncDispose) {
21
+ Symbol.asyncDispose = Symbol.for("asyncDispose");
22
+ }
23
+ if (!Promise.withResolvers) {
24
+ Promise.withResolvers = function() {
25
+ let resolve;
26
+ let reject;
27
+ const promise = new Promise((res, rej) => {
28
+ resolve = res;
29
+ reject = rej;
30
+ });
31
+ return { promise, resolve, reject };
32
+ };
33
+ }
34
+ var workersModule = globalThis[WORKERS_MODULE_SYMBOL];
35
+ var RpcTarget = workersModule ? workersModule.RpcTarget : class {
36
+ };
37
+ function typeForRpc(value) {
38
+ switch (typeof value) {
39
+ case "boolean":
40
+ case "number":
41
+ case "string":
42
+ return "primitive";
43
+ case "undefined":
44
+ return "undefined";
45
+ case "object":
46
+ case "function":
47
+ break;
48
+ case "bigint":
49
+ return "bigint";
50
+ default:
51
+ return "unsupported";
52
+ }
53
+ if (value === null) {
54
+ return "primitive";
55
+ }
56
+ let prototype = Object.getPrototypeOf(value);
57
+ switch (prototype) {
58
+ case Object.prototype:
59
+ return "object";
60
+ case Function.prototype:
61
+ return "function";
62
+ case Array.prototype:
63
+ return "array";
64
+ case Date.prototype:
65
+ return "date";
66
+ case Uint8Array.prototype:
67
+ return "bytes";
68
+ // TODO: All other structured clone types.
69
+ case RpcStub.prototype:
70
+ return "stub";
71
+ case RpcPromise.prototype:
72
+ return "rpc-promise";
73
+ // TODO: Promise<T> or thenable
74
+ default:
75
+ if (workersModule) {
76
+ if (prototype == workersModule.RpcStub.prototype || value instanceof workersModule.ServiceStub) {
77
+ return "rpc-target";
78
+ } else if (prototype == workersModule.RpcPromise.prototype || prototype == workersModule.RpcProperty.prototype) {
79
+ return "rpc-thenable";
80
+ }
81
+ }
82
+ if (value instanceof RpcTarget) {
83
+ return "rpc-target";
84
+ }
85
+ if (value instanceof Error) {
86
+ return "error";
87
+ }
88
+ return "unsupported";
89
+ }
90
+ }
91
+ function mapNotLoaded() {
92
+ throw new Error("RPC map() implementation was not loaded.");
93
+ }
94
+ var mapImpl = { applyMap: mapNotLoaded, sendMap: mapNotLoaded };
95
+ var StubHook = class {
96
+ };
97
+ var ErrorStubHook = class extends StubHook {
98
+ constructor(error) {
99
+ super();
100
+ this.error = error;
101
+ }
102
+ call(path, args) {
103
+ return this;
104
+ }
105
+ map(path, captures, instructions) {
106
+ return this;
107
+ }
108
+ get(path) {
109
+ return this;
110
+ }
111
+ dup() {
112
+ return this;
113
+ }
114
+ pull() {
115
+ return Promise.reject(this.error);
116
+ }
117
+ ignoreUnhandledRejections() {
118
+ }
119
+ dispose() {
120
+ }
121
+ onBroken(callback) {
122
+ try {
123
+ callback(this.error);
124
+ } catch (err) {
125
+ Promise.resolve(err);
126
+ }
127
+ }
128
+ };
129
+ var DISPOSED_HOOK = new ErrorStubHook(
130
+ new Error("Attempted to use RPC stub after it has been disposed.")
131
+ );
132
+ var doCall = (hook, path, params) => {
133
+ return hook.call(path, params);
134
+ };
135
+ function withCallInterceptor(interceptor, callback) {
136
+ let oldValue = doCall;
137
+ doCall = interceptor;
138
+ try {
139
+ return callback();
140
+ } finally {
141
+ doCall = oldValue;
142
+ }
143
+ }
144
+ var RAW_STUB = Symbol("realStub");
145
+ var PROXY_HANDLERS = {
146
+ apply(target, thisArg, argumentsList) {
147
+ let stub = target.raw;
148
+ return new RpcPromise(doCall(
149
+ stub.hook,
150
+ stub.pathIfPromise || [],
151
+ RpcPayload.fromAppParams(argumentsList)
152
+ ), []);
153
+ },
154
+ get(target, prop, receiver) {
155
+ let stub = target.raw;
156
+ if (prop === RAW_STUB) {
157
+ return stub;
158
+ } else if (prop in RpcPromise.prototype) {
159
+ return stub[prop];
160
+ } else if (typeof prop === "string") {
161
+ return new RpcPromise(
162
+ stub.hook,
163
+ stub.pathIfPromise ? [...stub.pathIfPromise, prop] : [prop]
164
+ );
165
+ } else if (prop === Symbol.dispose && (!stub.pathIfPromise || stub.pathIfPromise.length == 0)) {
166
+ return () => {
167
+ stub.hook.dispose();
168
+ stub.hook = DISPOSED_HOOK;
169
+ };
170
+ } else {
171
+ return void 0;
172
+ }
173
+ },
174
+ has(target, prop) {
175
+ let stub = target.raw;
176
+ if (prop === RAW_STUB) {
177
+ return true;
178
+ } else if (prop in RpcPromise.prototype) {
179
+ return prop in stub;
180
+ } else if (typeof prop === "string") {
181
+ return true;
182
+ } else if (prop === Symbol.dispose && (!stub.pathIfPromise || stub.pathIfPromise.length == 0)) {
183
+ return true;
184
+ } else {
185
+ return false;
186
+ }
187
+ },
188
+ construct(target, args) {
189
+ throw new Error("An RPC stub cannot be used as a constructor.");
190
+ },
191
+ defineProperty(target, property, attributes) {
192
+ throw new Error("Can't define properties on RPC stubs.");
193
+ },
194
+ deleteProperty(target, p) {
195
+ throw new Error("Can't delete properties on RPC stubs.");
196
+ },
197
+ getOwnPropertyDescriptor(target, p) {
198
+ return void 0;
199
+ },
200
+ getPrototypeOf(target) {
201
+ return Object.getPrototypeOf(target.raw);
202
+ },
203
+ isExtensible(target) {
204
+ return false;
205
+ },
206
+ ownKeys(target) {
207
+ return [];
208
+ },
209
+ preventExtensions(target) {
210
+ return true;
211
+ },
212
+ set(target, p, newValue, receiver) {
213
+ throw new Error("Can't assign properties on RPC stubs.");
214
+ },
215
+ setPrototypeOf(target, v) {
216
+ throw new Error("Can't override prototype of RPC stubs.");
217
+ }
218
+ };
219
+ var RpcStub = class _RpcStub extends RpcTarget {
220
+ // Although \
@@ -0,0 +1,426 @@
1
+ /**
2
+ * ai-evaluate v2.1.8
3
+ * Static worker template for evaluate.workers.do
4
+ * Generated: 2026-01-26T01:42:47.000Z
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
+ };