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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest'
|
|
2
|
-
import { generateWorkerCode, generateDevWorkerCode } from '../src/worker-template.js'
|
|
2
|
+
import { generateWorkerCode, generateDevWorkerCode } from '../src/worker-template/index.js'
|
|
3
3
|
|
|
4
4
|
describe('generateWorkerCode (production)', () => {
|
|
5
5
|
describe('basic structure', () => {
|
|
@@ -27,21 +27,21 @@ describe('generateWorkerCode (production)', () => {
|
|
|
27
27
|
describe('module embedding', () => {
|
|
28
28
|
it('embeds module code when provided', () => {
|
|
29
29
|
const code = generateWorkerCode({
|
|
30
|
-
module: 'exports.foo = 42;'
|
|
30
|
+
module: 'exports.foo = 42;',
|
|
31
31
|
})
|
|
32
32
|
expect(code).toContain('exports.foo = 42;')
|
|
33
33
|
})
|
|
34
34
|
|
|
35
35
|
it('extracts export names from exports.name pattern', () => {
|
|
36
36
|
const code = generateWorkerCode({
|
|
37
|
-
module: 'exports.add = (a, b) => a + b; exports.sub = (a, b) => a - b;'
|
|
37
|
+
module: 'exports.add = (a, b) => a + b; exports.sub = (a, b) => a - b;',
|
|
38
38
|
})
|
|
39
39
|
expect(code).toContain('const { add, sub } = exports')
|
|
40
40
|
})
|
|
41
41
|
|
|
42
42
|
it('extracts export names from exports["name"] pattern', () => {
|
|
43
43
|
const code = generateWorkerCode({
|
|
44
|
-
module: 'exports["myFunc"] = () => {};'
|
|
44
|
+
module: 'exports["myFunc"] = () => {};',
|
|
45
45
|
})
|
|
46
46
|
expect(code).toContain('myFunc')
|
|
47
47
|
})
|
|
@@ -55,7 +55,7 @@ describe('generateWorkerCode (production)', () => {
|
|
|
55
55
|
describe('test embedding', () => {
|
|
56
56
|
it('embeds test code when provided', () => {
|
|
57
57
|
const code = generateWorkerCode({
|
|
58
|
-
tests: 'describe("test", () => {});'
|
|
58
|
+
tests: 'describe("test", () => {});',
|
|
59
59
|
})
|
|
60
60
|
expect(code).toContain('describe("test", () => {});')
|
|
61
61
|
})
|
|
@@ -69,7 +69,7 @@ describe('generateWorkerCode (production)', () => {
|
|
|
69
69
|
describe('script embedding', () => {
|
|
70
70
|
it('embeds script code when provided', () => {
|
|
71
71
|
const code = generateWorkerCode({
|
|
72
|
-
script: 'return 42;'
|
|
72
|
+
script: 'return 42;',
|
|
73
73
|
})
|
|
74
74
|
expect(code).toContain('return 42;')
|
|
75
75
|
})
|
|
@@ -91,7 +91,9 @@ describe('generateWorkerCode (production)', () => {
|
|
|
91
91
|
const code = generateWorkerCode({})
|
|
92
92
|
expect(code).toContain('const describe = (name, fn) => testService.describe(name, fn)')
|
|
93
93
|
expect(code).toContain('const it = (name, fn) => testService.it(name, fn)')
|
|
94
|
-
expect(code).toContain(
|
|
94
|
+
expect(code).toContain(
|
|
95
|
+
'const expect = (value, message) => testService.expect(value, message)'
|
|
96
|
+
)
|
|
95
97
|
})
|
|
96
98
|
|
|
97
99
|
it('includes skip and only modifiers', () => {
|
|
@@ -106,7 +108,7 @@ describe('generateWorkerCode (production)', () => {
|
|
|
106
108
|
describe('capnweb RPC', () => {
|
|
107
109
|
it('imports capnweb', () => {
|
|
108
110
|
const code = generateWorkerCode({})
|
|
109
|
-
expect(code).toContain("import { RpcTarget, newWorkersRpcResponse } from 'capnweb'")
|
|
111
|
+
expect(code).toContain("import { RpcTarget, newWorkersRpcResponse } from 'capnweb.js'")
|
|
110
112
|
})
|
|
111
113
|
|
|
112
114
|
it('creates ExportsRpcTarget class', () => {
|
|
@@ -123,7 +125,7 @@ describe('generateWorkerCode (production)', () => {
|
|
|
123
125
|
it('handles GET / route for info', () => {
|
|
124
126
|
const code = generateWorkerCode({})
|
|
125
127
|
expect(code).toContain("url.pathname === '/'")
|
|
126
|
-
expect(code).toContain(
|
|
128
|
+
expect(code).toContain('exports: Object.keys(exports)')
|
|
127
129
|
})
|
|
128
130
|
})
|
|
129
131
|
|
|
@@ -162,7 +164,7 @@ describe('generateWorkerCode (production)', () => {
|
|
|
162
164
|
describe('ES module syntax support', () => {
|
|
163
165
|
it('transforms export const to CommonJS', () => {
|
|
164
166
|
const code = generateWorkerCode({
|
|
165
|
-
module: 'export const add = (a, b) => a + b'
|
|
167
|
+
module: 'export const add = (a, b) => a + b',
|
|
166
168
|
})
|
|
167
169
|
expect(code).toContain('const add = exports.add =')
|
|
168
170
|
expect(code).toContain('const { add } = exports')
|
|
@@ -170,7 +172,7 @@ describe('generateWorkerCode (production)', () => {
|
|
|
170
172
|
|
|
171
173
|
it('transforms export function to CommonJS', () => {
|
|
172
174
|
const code = generateWorkerCode({
|
|
173
|
-
module: 'export function multiply(a, b) { return a * b }'
|
|
175
|
+
module: 'export function multiply(a, b) { return a * b }',
|
|
174
176
|
})
|
|
175
177
|
expect(code).toContain('function multiply')
|
|
176
178
|
expect(code).toContain('exports.multiply = multiply')
|
|
@@ -182,7 +184,7 @@ describe('generateWorkerCode (production)', () => {
|
|
|
182
184
|
module: `
|
|
183
185
|
export const foo = 1
|
|
184
186
|
exports.bar = 2
|
|
185
|
-
|
|
187
|
+
`,
|
|
186
188
|
})
|
|
187
189
|
expect(code).toContain('const foo = exports.foo =')
|
|
188
190
|
expect(code).toContain('exports.bar = 2')
|
|
@@ -194,14 +196,14 @@ describe('generateWorkerCode (production)', () => {
|
|
|
194
196
|
describe('script auto-return', () => {
|
|
195
197
|
it('auto-returns single expressions', () => {
|
|
196
198
|
const code = generateWorkerCode({
|
|
197
|
-
script: 'add(1, 2)'
|
|
199
|
+
script: 'add(1, 2)',
|
|
198
200
|
})
|
|
199
201
|
expect(code).toContain('return add(1, 2)')
|
|
200
202
|
})
|
|
201
203
|
|
|
202
204
|
it('does not modify scripts with return', () => {
|
|
203
205
|
const code = generateWorkerCode({
|
|
204
|
-
script: 'return add(1, 2)'
|
|
206
|
+
script: 'return add(1, 2)',
|
|
205
207
|
})
|
|
206
208
|
expect(code).toContain('return add(1, 2)')
|
|
207
209
|
expect(code).not.toContain('return return')
|
|
@@ -209,7 +211,7 @@ describe('generateWorkerCode (production)', () => {
|
|
|
209
211
|
|
|
210
212
|
it('does not modify throw statements', () => {
|
|
211
213
|
const code = generateWorkerCode({
|
|
212
|
-
script: 'throw new Error("test")'
|
|
214
|
+
script: 'throw new Error("test")',
|
|
213
215
|
})
|
|
214
216
|
expect(code).toContain('throw new Error("test")')
|
|
215
217
|
expect(code).not.toContain('return throw')
|
|
@@ -220,7 +222,7 @@ describe('generateWorkerCode (production)', () => {
|
|
|
220
222
|
script: `
|
|
221
223
|
const x = 1
|
|
222
224
|
x + 1
|
|
223
|
-
|
|
225
|
+
`,
|
|
224
226
|
})
|
|
225
227
|
expect(code).toContain('return x + 1')
|
|
226
228
|
})
|
|
@@ -404,7 +406,7 @@ describe('generateDevWorkerCode (development)', () => {
|
|
|
404
406
|
describe('module embedding', () => {
|
|
405
407
|
it('embeds module code when provided', () => {
|
|
406
408
|
const code = generateDevWorkerCode({
|
|
407
|
-
module: 'exports.foo = 42;'
|
|
409
|
+
module: 'exports.foo = 42;',
|
|
408
410
|
})
|
|
409
411
|
expect(code).toContain('exports.foo = 42;')
|
|
410
412
|
})
|
|
@@ -413,7 +415,7 @@ describe('generateDevWorkerCode (development)', () => {
|
|
|
413
415
|
describe('test embedding', () => {
|
|
414
416
|
it('embeds test code when provided', () => {
|
|
415
417
|
const code = generateDevWorkerCode({
|
|
416
|
-
tests: 'describe("test", () => {});'
|
|
418
|
+
tests: 'describe("test", () => {});',
|
|
417
419
|
})
|
|
418
420
|
expect(code).toContain('describe("test", () => {});')
|
|
419
421
|
})
|
|
@@ -422,7 +424,7 @@ describe('generateDevWorkerCode (development)', () => {
|
|
|
422
424
|
describe('script embedding', () => {
|
|
423
425
|
it('embeds script code when provided', () => {
|
|
424
426
|
const code = generateDevWorkerCode({
|
|
425
|
-
script: 'return 42;'
|
|
427
|
+
script: 'return 42;',
|
|
426
428
|
})
|
|
427
429
|
expect(code).toContain('return 42;')
|
|
428
430
|
})
|
package/src/evaluate.js
DELETED
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Evaluate code in a sandboxed environment
|
|
3
|
-
*
|
|
4
|
-
* Uses Cloudflare worker_loaders in production,
|
|
5
|
-
* Miniflare in development/Node.
|
|
6
|
-
*
|
|
7
|
-
* Requires ai-tests service binding (TEST) for assertions and test running.
|
|
8
|
-
*/
|
|
9
|
-
import { generateWorkerCode, generateDevWorkerCode } from './worker-template.js';
|
|
10
|
-
/**
|
|
11
|
-
* Check if code contains JSX syntax that needs transformation
|
|
12
|
-
*/
|
|
13
|
-
function containsJSX(code) {
|
|
14
|
-
if (!code)
|
|
15
|
-
return false;
|
|
16
|
-
// Look for JSX patterns
|
|
17
|
-
const jsxPattern = /<[A-Z][a-zA-Z0-9]*[\s/>]|<[a-z][a-z0-9-]*[\s/>]|<>|<\/>/;
|
|
18
|
-
const jsxReturnPattern = /return\s*\(\s*<|return\s+<[A-Za-z]/;
|
|
19
|
-
return jsxPattern.test(code) || jsxReturnPattern.test(code);
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Transform JSX in code using esbuild
|
|
23
|
-
*/
|
|
24
|
-
async function transformJSX(code) {
|
|
25
|
-
if (!code || !containsJSX(code))
|
|
26
|
-
return code;
|
|
27
|
-
try {
|
|
28
|
-
const { transform } = await import('esbuild');
|
|
29
|
-
const result = await transform(code, {
|
|
30
|
-
loader: 'tsx',
|
|
31
|
-
jsxFactory: 'h',
|
|
32
|
-
jsxFragment: 'Fragment',
|
|
33
|
-
target: 'esnext',
|
|
34
|
-
format: 'esm',
|
|
35
|
-
});
|
|
36
|
-
return result.code;
|
|
37
|
-
}
|
|
38
|
-
catch (error) {
|
|
39
|
-
// If transform fails, return original code and let sandbox handle the error
|
|
40
|
-
console.error('JSX transform failed:', error);
|
|
41
|
-
return code;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Evaluate code in a sandboxed worker
|
|
46
|
-
*
|
|
47
|
-
* @example
|
|
48
|
-
* ```ts
|
|
49
|
-
* import { evaluate } from 'ai-sandbox'
|
|
50
|
-
*
|
|
51
|
-
* // Run a simple script
|
|
52
|
-
* const result = await evaluate({
|
|
53
|
-
* script: 'return 1 + 1'
|
|
54
|
-
* })
|
|
55
|
-
* // { success: true, value: 2, logs: [], duration: ... }
|
|
56
|
-
*
|
|
57
|
-
* // With a module and tests
|
|
58
|
-
* const result = await evaluate({
|
|
59
|
-
* module: `
|
|
60
|
-
* exports.add = (a, b) => a + b;
|
|
61
|
-
* exports.multiply = (a, b) => a * b;
|
|
62
|
-
* `,
|
|
63
|
-
* tests: `
|
|
64
|
-
* describe('math', () => {
|
|
65
|
-
* it('adds numbers', () => {
|
|
66
|
-
* expect(add(2, 3)).toBe(5);
|
|
67
|
-
* });
|
|
68
|
-
* it('multiplies numbers', () => {
|
|
69
|
-
* expect(multiply(2, 3)).toBe(6);
|
|
70
|
-
* });
|
|
71
|
-
* });
|
|
72
|
-
* `,
|
|
73
|
-
* script: 'return add(10, 20)'
|
|
74
|
-
* })
|
|
75
|
-
* ```
|
|
76
|
-
*/
|
|
77
|
-
export async function evaluate(options, env) {
|
|
78
|
-
const start = Date.now();
|
|
79
|
-
try {
|
|
80
|
-
// Transform JSX in module, tests, and script before evaluation
|
|
81
|
-
const transformedOptions = {
|
|
82
|
-
...options,
|
|
83
|
-
module: options.module ? await transformJSX(options.module) : options.module,
|
|
84
|
-
tests: options.tests ? await transformJSX(options.tests) : options.tests,
|
|
85
|
-
script: options.script ? await transformJSX(options.script) : options.script,
|
|
86
|
-
};
|
|
87
|
-
// Use worker_loaders if available (Cloudflare Workers)
|
|
88
|
-
if (env?.LOADER && env?.TEST) {
|
|
89
|
-
return await evaluateWithWorkerLoader(transformedOptions, env.LOADER, env.TEST, start);
|
|
90
|
-
}
|
|
91
|
-
// Fall back to Miniflare with local TestService (Node.js)
|
|
92
|
-
return await evaluateWithMiniflare(transformedOptions, start);
|
|
93
|
-
}
|
|
94
|
-
catch (error) {
|
|
95
|
-
return {
|
|
96
|
-
success: false,
|
|
97
|
-
logs: [],
|
|
98
|
-
error: error instanceof Error ? error.message : String(error),
|
|
99
|
-
duration: Date.now() - start
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
/**
|
|
104
|
-
* Evaluate using Cloudflare worker_loaders binding
|
|
105
|
-
*/
|
|
106
|
-
async function evaluateWithWorkerLoader(options, loader, testService, start) {
|
|
107
|
-
const workerCode = generateWorkerCode({
|
|
108
|
-
module: options.module,
|
|
109
|
-
tests: options.tests,
|
|
110
|
-
script: options.script,
|
|
111
|
-
sdk: options.sdk,
|
|
112
|
-
imports: options.imports
|
|
113
|
-
});
|
|
114
|
-
const id = `sandbox-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
115
|
-
const worker = loader.get(id, async () => ({
|
|
116
|
-
mainModule: 'worker.js',
|
|
117
|
-
modules: {
|
|
118
|
-
'worker.js': workerCode
|
|
119
|
-
},
|
|
120
|
-
compatibilityDate: '2024-01-01',
|
|
121
|
-
// Block network access only if fetch: null
|
|
122
|
-
globalOutbound: options.fetch === null ? null : undefined,
|
|
123
|
-
bindings: {
|
|
124
|
-
TEST: testService
|
|
125
|
-
}
|
|
126
|
-
}));
|
|
127
|
-
const response = await worker.fetch(new Request('http://sandbox/execute'));
|
|
128
|
-
const result = await response.json();
|
|
129
|
-
return {
|
|
130
|
-
...result,
|
|
131
|
-
duration: Date.now() - start
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* Evaluate using Miniflare (for Node.js/development)
|
|
136
|
-
*
|
|
137
|
-
* For local dev, we use generateDevWorkerCode which bundles the test
|
|
138
|
-
* framework directly. In production, the sandbox worker uses RPC to
|
|
139
|
-
* a deployed ai-tests worker.
|
|
140
|
-
*/
|
|
141
|
-
async function evaluateWithMiniflare(options, start) {
|
|
142
|
-
// Dynamic import to avoid bundling in production
|
|
143
|
-
const { Miniflare } = await import('miniflare');
|
|
144
|
-
const workerCode = generateDevWorkerCode({
|
|
145
|
-
module: options.module,
|
|
146
|
-
tests: options.tests,
|
|
147
|
-
script: options.script,
|
|
148
|
-
sdk: options.sdk,
|
|
149
|
-
imports: options.imports
|
|
150
|
-
});
|
|
151
|
-
const mf = new Miniflare({
|
|
152
|
-
modules: true,
|
|
153
|
-
script: workerCode,
|
|
154
|
-
compatibilityDate: '2024-01-01'
|
|
155
|
-
});
|
|
156
|
-
try {
|
|
157
|
-
const response = await mf.dispatchFetch('http://sandbox/execute');
|
|
158
|
-
const result = await response.json();
|
|
159
|
-
return {
|
|
160
|
-
...result,
|
|
161
|
-
duration: Date.now() - start
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
finally {
|
|
165
|
-
await mf.dispose();
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
/**
|
|
169
|
-
* Create an evaluate function bound to a specific environment
|
|
170
|
-
*
|
|
171
|
-
* Useful for Cloudflare Workers where env is passed to fetch handler.
|
|
172
|
-
*
|
|
173
|
-
* @example
|
|
174
|
-
* ```ts
|
|
175
|
-
* // In a Cloudflare Worker
|
|
176
|
-
* export default {
|
|
177
|
-
* async fetch(request, env) {
|
|
178
|
-
* const sandbox = createEvaluator(env)
|
|
179
|
-
* const result = await sandbox({ script: '1 + 1' })
|
|
180
|
-
* return Response.json(result)
|
|
181
|
-
* }
|
|
182
|
-
* }
|
|
183
|
-
* ```
|
|
184
|
-
*/
|
|
185
|
-
export function createEvaluator(env) {
|
|
186
|
-
return (options) => evaluate(options, env);
|
|
187
|
-
}
|
package/src/index.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ai-sandbox - Secure code execution in sandboxed environments
|
|
3
|
-
*
|
|
4
|
-
* Provides evaluate() for running untrusted code safely using:
|
|
5
|
-
* - Cloudflare worker_loaders in production
|
|
6
|
-
* - Miniflare in development/Node.js
|
|
7
|
-
*
|
|
8
|
-
* @packageDocumentation
|
|
9
|
-
*/
|
|
10
|
-
export { evaluate, createEvaluator } from './evaluate.js';
|
package/src/node.d.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Evaluate code in a sandboxed environment (Node.js version)
|
|
3
|
-
*
|
|
4
|
-
* Uses Cloudflare worker_loaders when available, falls back to Miniflare for local dev.
|
|
5
|
-
* For Workers-only builds, import from 'ai-evaluate' instead.
|
|
6
|
-
*/
|
|
7
|
-
import type { EvaluateOptions, EvaluateResult, SandboxEnv } from './types.js';
|
|
8
|
-
/**
|
|
9
|
-
* Evaluate code in a sandboxed worker (Node.js version with Miniflare fallback)
|
|
10
|
-
*/
|
|
11
|
-
export declare function evaluate(options: EvaluateOptions, env?: SandboxEnv): Promise<EvaluateResult>;
|
|
12
|
-
/**
|
|
13
|
-
* Create an evaluate function bound to a specific environment
|
|
14
|
-
*/
|
|
15
|
-
export declare function createEvaluator(env?: SandboxEnv): (options: EvaluateOptions) => Promise<EvaluateResult>;
|
|
16
|
-
export type { EvaluateOptions, EvaluateResult, SandboxEnv } from './types.js';
|
|
17
|
-
//# sourceMappingURL=node.d.ts.map
|
package/src/node.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["node.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAgB,UAAU,EAAE,MAAM,YAAY,CAAA;AAmC3F;;GAEG;AACH,wBAAsB,QAAQ,CAC5B,OAAO,EAAE,eAAe,EACxB,GAAG,CAAC,EAAE,UAAU,GACf,OAAO,CAAC,cAAc,CAAC,CA+BzB;AA6GD;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,CAAC,EAAE,UAAU,IACtC,SAAS,eAAe,6BACjC;AAGD,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA"}
|
package/src/node.js
DELETED
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Evaluate code in a sandboxed environment (Node.js version)
|
|
3
|
-
*
|
|
4
|
-
* Uses Cloudflare worker_loaders when available, falls back to Miniflare for local dev.
|
|
5
|
-
* For Workers-only builds, import from 'ai-evaluate' instead.
|
|
6
|
-
*/
|
|
7
|
-
import { generateWorkerCode, generateDevWorkerCode } from './worker-template.js';
|
|
8
|
-
/**
|
|
9
|
-
* Check if code contains JSX syntax that needs transformation
|
|
10
|
-
*/
|
|
11
|
-
function containsJSX(code) {
|
|
12
|
-
if (!code)
|
|
13
|
-
return false;
|
|
14
|
-
const jsxPattern = /<[A-Z][a-zA-Z0-9]*[\s/>]|<[a-z][a-z0-9-]*[\s/>]|<>|<\/>/;
|
|
15
|
-
const jsxReturnPattern = /return\s*\(\s*<|return\s+<[A-Za-z]/;
|
|
16
|
-
return jsxPattern.test(code) || jsxReturnPattern.test(code);
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Transform JSX in code using esbuild
|
|
20
|
-
*/
|
|
21
|
-
async function transformJSX(code) {
|
|
22
|
-
if (!code || !containsJSX(code))
|
|
23
|
-
return code;
|
|
24
|
-
try {
|
|
25
|
-
const { transform } = await import('esbuild');
|
|
26
|
-
const result = await transform(code, {
|
|
27
|
-
loader: 'tsx',
|
|
28
|
-
jsxFactory: 'h',
|
|
29
|
-
jsxFragment: 'Fragment',
|
|
30
|
-
target: 'esnext',
|
|
31
|
-
format: 'esm',
|
|
32
|
-
});
|
|
33
|
-
return result.code;
|
|
34
|
-
}
|
|
35
|
-
catch (error) {
|
|
36
|
-
console.error('JSX transform failed:', error);
|
|
37
|
-
return code;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Evaluate code in a sandboxed worker (Node.js version with Miniflare fallback)
|
|
42
|
-
*/
|
|
43
|
-
export async function evaluate(options, env) {
|
|
44
|
-
const start = Date.now();
|
|
45
|
-
try {
|
|
46
|
-
// Transform JSX in module, tests, and script before evaluation
|
|
47
|
-
const transformedModule = options.module ? await transformJSX(options.module) : undefined;
|
|
48
|
-
const transformedTests = options.tests ? await transformJSX(options.tests) : undefined;
|
|
49
|
-
const transformedScript = options.script ? await transformJSX(options.script) : undefined;
|
|
50
|
-
const transformedOptions = {
|
|
51
|
-
...options,
|
|
52
|
-
module: transformedModule,
|
|
53
|
-
tests: transformedTests,
|
|
54
|
-
script: transformedScript,
|
|
55
|
-
};
|
|
56
|
-
// Use worker_loaders if available (Cloudflare Workers)
|
|
57
|
-
if (env?.LOADER && env?.TEST) {
|
|
58
|
-
return await evaluateWithWorkerLoader(transformedOptions, env.LOADER, env.TEST, start);
|
|
59
|
-
}
|
|
60
|
-
// Fall back to Miniflare (Node.js/local development)
|
|
61
|
-
return await evaluateWithMiniflare(transformedOptions, start);
|
|
62
|
-
}
|
|
63
|
-
catch (error) {
|
|
64
|
-
return {
|
|
65
|
-
success: false,
|
|
66
|
-
logs: [],
|
|
67
|
-
error: error instanceof Error ? error.message : String(error),
|
|
68
|
-
duration: Date.now() - start,
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Evaluate using Cloudflare worker_loaders binding
|
|
74
|
-
*/
|
|
75
|
-
async function evaluateWithWorkerLoader(options, loader, testService, start) {
|
|
76
|
-
const workerCode = generateWorkerCode({
|
|
77
|
-
module: options.module,
|
|
78
|
-
tests: options.tests,
|
|
79
|
-
script: options.script,
|
|
80
|
-
sdk: options.sdk,
|
|
81
|
-
imports: options.imports,
|
|
82
|
-
});
|
|
83
|
-
const id = `sandbox-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
84
|
-
const worker = loader.get(id, async () => ({
|
|
85
|
-
mainModule: 'worker.js',
|
|
86
|
-
modules: {
|
|
87
|
-
'worker.js': workerCode,
|
|
88
|
-
},
|
|
89
|
-
compatibilityDate: '2026-01-01',
|
|
90
|
-
globalOutbound: options.fetch === null ? null : undefined,
|
|
91
|
-
bindings: {
|
|
92
|
-
TEST: testService,
|
|
93
|
-
},
|
|
94
|
-
}));
|
|
95
|
-
const entrypoint = worker.getEntrypoint();
|
|
96
|
-
const response = await entrypoint.fetch(new Request('http://sandbox/execute'));
|
|
97
|
-
const result = (await response.json());
|
|
98
|
-
return {
|
|
99
|
-
...result,
|
|
100
|
-
duration: Date.now() - start,
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
/**
|
|
104
|
-
* Evaluate using Miniflare (for Node.js/development)
|
|
105
|
-
*/
|
|
106
|
-
async function evaluateWithMiniflare(options, start) {
|
|
107
|
-
const { Miniflare } = await import('miniflare');
|
|
108
|
-
const workerCode = generateDevWorkerCode({
|
|
109
|
-
module: options.module,
|
|
110
|
-
tests: options.tests,
|
|
111
|
-
script: options.script,
|
|
112
|
-
sdk: options.sdk,
|
|
113
|
-
imports: options.imports,
|
|
114
|
-
fetch: options.fetch, // Pass fetch option to worker template
|
|
115
|
-
});
|
|
116
|
-
// Block outbound network requests at Miniflare level when fetch: null
|
|
117
|
-
// This complements the globalThis.fetch override in the worker template
|
|
118
|
-
const blockNetwork = options.fetch === null;
|
|
119
|
-
const mf = new Miniflare({
|
|
120
|
-
modules: true,
|
|
121
|
-
script: workerCode,
|
|
122
|
-
compatibilityDate: '2026-01-01',
|
|
123
|
-
// Block all outbound fetch/connect when network is disabled
|
|
124
|
-
...(blockNetwork && {
|
|
125
|
-
outboundService: () => {
|
|
126
|
-
throw new Error('Network access blocked: fetch is disabled in this sandbox');
|
|
127
|
-
},
|
|
128
|
-
}),
|
|
129
|
-
});
|
|
130
|
-
try {
|
|
131
|
-
const timeout = options.timeout || 5000;
|
|
132
|
-
const controller = new AbortController();
|
|
133
|
-
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
134
|
-
try {
|
|
135
|
-
const response = await mf.dispatchFetch('http://sandbox/execute', {
|
|
136
|
-
signal: controller.signal,
|
|
137
|
-
});
|
|
138
|
-
clearTimeout(timeoutId);
|
|
139
|
-
const result = (await response.json());
|
|
140
|
-
return {
|
|
141
|
-
...result,
|
|
142
|
-
duration: Date.now() - start,
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
catch (err) {
|
|
146
|
-
clearTimeout(timeoutId);
|
|
147
|
-
if (err.name === 'AbortError') {
|
|
148
|
-
return {
|
|
149
|
-
success: false,
|
|
150
|
-
logs: [],
|
|
151
|
-
error: `Timeout: Script execution exceeded ${timeout}ms`,
|
|
152
|
-
duration: Date.now() - start,
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
throw err;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
finally {
|
|
159
|
-
await mf.dispose();
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
/**
|
|
163
|
-
* Create an evaluate function bound to a specific environment
|
|
164
|
-
*/
|
|
165
|
-
export function createEvaluator(env) {
|
|
166
|
-
return (options) => evaluate(options, env);
|
|
167
|
-
}
|
|
168
|
-
//# sourceMappingURL=node.js.map
|
package/src/node.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"node.js","sourceRoot":"","sources":["node.ts"],"names":[],"mappings":"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"}
|