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
package/src/evaluate.ts DELETED
@@ -1,329 +0,0 @@
1
- /**
2
- * Evaluate code in a sandboxed environment
3
- *
4
- * Uses Cloudflare worker_loaders for secure code execution.
5
- * For Node.js/local development, import from 'ai-evaluate/node' instead.
6
- *
7
- * Requires:
8
- * - LOADER binding (worker_loaders)
9
- * - TEST binding (ai-tests service) - optional, only needed for test assertions
10
- */
11
-
12
- import type { EvaluateOptions, EvaluateResult, WorkerLoader, SandboxEnv } from './types.js'
13
- import { generateWorkerCode } from './worker-template/index.js'
14
- import { CAPNWEB_SOURCE } from './capnweb-bundle.js'
15
- import { COMPATIBILITY_DATE, normalizeImport, extractPackageName } from './shared.js'
16
-
17
- /**
18
- * Generate a minimal worker for simple script execution
19
- * This doesn't require capnweb or TEST binding
20
- */
21
- function generateSimpleWorkerCode(options: {
22
- module?: string
23
- script?: string
24
- imports?: string[]
25
- }): string {
26
- const { module = '', script = '', imports = [] } = options
27
-
28
- // Build import statements for pre-fetched external modules
29
- // Modules are fetched by the host worker and included in the worker definition
30
- const importStatements = imports
31
- .map((url, i) => `import * as __import${i}__ from './__external_${i}__.js';`)
32
- .join('\n')
33
-
34
- // Make imports available as globals
35
- const importGlobals = imports
36
- .map((specifier, i) => {
37
- const pkgName = extractPackageName(specifier, i)
38
- const varName = pkgName === 'lodash' ? '_' : pkgName
39
- return `globalThis.${varName} = __import${i}__.default || __import${i}__;
40
- globalThis.pkg = __import${i}__.default || __import${i}__;`
41
- })
42
- .join('\n')
43
-
44
- // Wrap script to capture return value (code is embedded at build time, no eval)
45
- const wrappedScript = script
46
- ? `const __executeScript__ = async () => { ${script} }; const __result__ = await __executeScript__();`
47
- : 'const __result__ = undefined;'
48
-
49
- return `
50
- // Simple Sandbox Worker
51
- ${importStatements}
52
-
53
- const logs = [];
54
-
55
- // Capture console output
56
- const originalConsole = { ...console };
57
- const captureConsole = (level) => (...args) => {
58
- logs.push({
59
- level,
60
- message: args.map(a => typeof a === 'object' ? JSON.stringify(a) : String(a)).join(' '),
61
- timestamp: Date.now()
62
- });
63
- originalConsole[level](...args);
64
- };
65
- console.log = captureConsole('log');
66
- console.warn = captureConsole('warn');
67
- console.error = captureConsole('error');
68
- console.info = captureConsole('info');
69
-
70
- // Make imports available globally
71
- ${importGlobals}
72
-
73
- // User module code (if any)
74
- ${module}
75
-
76
- export default {
77
- async fetch(request, env) {
78
- try {
79
- // Execute the script (embedded at generation time - no new Function())
80
- ${wrappedScript}
81
-
82
- return Response.json({
83
- success: true,
84
- value: __result__,
85
- logs,
86
- duration: 0
87
- });
88
- } catch (error) {
89
- return Response.json({
90
- success: false,
91
- error: error.message || String(error),
92
- logs,
93
- duration: 0
94
- });
95
- }
96
- }
97
- };
98
- `
99
- }
100
-
101
- /**
102
- * Evaluate code in a sandboxed worker
103
- *
104
- * @example
105
- * ```ts
106
- * import { evaluate } from 'ai-evaluate'
107
- *
108
- * // Run a simple script
109
- * const result = await evaluate({
110
- * script: 'return 1 + 1'
111
- * }, env)
112
- * // { success: true, value: 2, logs: [], duration: ... }
113
- * ```
114
- */
115
- export async function evaluate(
116
- options: EvaluateOptions,
117
- env?: SandboxEnv
118
- ): Promise<EvaluateResult> {
119
- const start = Date.now()
120
-
121
- try {
122
- // Require worker_loaders binding (check lowercase first, then legacy uppercase)
123
- const loader = env?.loader || env?.LOADER
124
- if (!loader) {
125
- return {
126
- success: false,
127
- logs: [],
128
- error:
129
- 'Sandbox requires worker_loaders binding. Add to wrangler.toml: [[worker_loaders]] binding = "LOADER". For Node.js, use: import { evaluate } from "ai-evaluate/node"',
130
- duration: Date.now() - start,
131
- }
132
- }
133
-
134
- // Use simple worker for basic script execution (no tests, no SDK)
135
- const useSimpleWorker = !options.tests && !options.sdk
136
-
137
- if (useSimpleWorker) {
138
- return await evaluateSimple(options, loader, start)
139
- }
140
-
141
- // Use full worker template for tests and SDK features
142
- return await evaluateWithWorkerLoader(options, loader, env?.TEST, start)
143
- } catch (error) {
144
- return {
145
- success: false,
146
- logs: [],
147
- error: error instanceof Error ? error.message : String(error),
148
- duration: Date.now() - start,
149
- }
150
- }
151
- }
152
-
153
- /**
154
- * Pre-fetch external modules from URLs or package names
155
- * Returns a map of module name to source code
156
- *
157
- * Supports:
158
- * - Full URLs: https://esm.sh/lodash@4.17.21
159
- * - Bare package names: lodash, lodash@4.17.21, @scope/pkg
160
- *
161
- * Handles esm.sh's redirect-style modules by following the internal import paths.
162
- */
163
- async function prefetchModules(imports: string[]): Promise<Record<string, string>> {
164
- const modules: Record<string, string> = {}
165
-
166
- await Promise.all(
167
- imports.map(async (specifier, i) => {
168
- try {
169
- // Normalize bare package names to esm.sh URLs
170
- const url = normalizeImport(specifier)
171
-
172
- // For esm.sh URLs, try to get the bundled version directly
173
- let fetchUrl = url
174
- if (url.includes('esm.sh/') && !url.includes('.mjs') && !url.includes('.js')) {
175
- // Parse the esm.sh URL to construct the bundle path
176
- // e.g., https://esm.sh/lodash@4.17.21 -> https://esm.sh/lodash@4.17.21/es2022/lodash.bundle.mjs
177
- const urlObj = new URL(url)
178
- const pathParts = urlObj.pathname.slice(1).split('/')
179
- const pkgSpec = pathParts[0] // e.g., "lodash@4.17.21"
180
- const pkgName = pkgSpec.split('@')[0]
181
- fetchUrl = `${urlObj.origin}/${pkgSpec}/es2022/${pkgName}.bundle.mjs`
182
- }
183
-
184
- const response = await fetch(fetchUrl, { redirect: 'follow' })
185
- if (!response.ok) {
186
- // Fallback to original URL if bundle URL fails
187
- const fallbackResponse = await fetch(url, { redirect: 'follow' })
188
- if (!fallbackResponse.ok) {
189
- throw new Error(`Failed to fetch ${url}: ${fallbackResponse.status}`)
190
- }
191
- const source = await fallbackResponse.text()
192
- modules[`__external_${i}__.js`] = source
193
- return
194
- }
195
- const source = await response.text()
196
- // Use a simple module name that can be imported
197
- const moduleName = `__external_${i}__.js`
198
- modules[moduleName] = source
199
- } catch (error) {
200
- throw new Error(
201
- `Failed to fetch import ${specifier}: ${
202
- error instanceof Error ? error.message : String(error)
203
- }`
204
- )
205
- }
206
- })
207
- )
208
-
209
- return modules
210
- }
211
-
212
- /**
213
- * Simple evaluation without capnweb/TEST dependencies
214
- */
215
- async function evaluateSimple(
216
- options: EvaluateOptions,
217
- loader: WorkerLoader,
218
- start: number
219
- ): Promise<EvaluateResult> {
220
- // Pre-fetch any external modules
221
- let externalModules: Record<string, string> = {}
222
- if (options.imports && options.imports.length > 0) {
223
- try {
224
- externalModules = await prefetchModules(options.imports)
225
- } catch (error) {
226
- return {
227
- success: false,
228
- logs: [],
229
- error: error instanceof Error ? error.message : String(error),
230
- duration: Date.now() - start,
231
- }
232
- }
233
- }
234
-
235
- const workerCode = generateSimpleWorkerCode({
236
- module: options.module,
237
- script: options.script,
238
- imports: options.imports,
239
- })
240
-
241
- const id = `sandbox-${Date.now()}-${Math.random().toString(36).slice(2)}`
242
-
243
- const worker = loader.get(id, async () => ({
244
- mainModule: 'worker.js',
245
- modules: {
246
- 'worker.js': workerCode,
247
- ...externalModules,
248
- },
249
- compatibilityDate: COMPATIBILITY_DATE,
250
- // Block network if fetch is false or null
251
- globalOutbound: options.fetch === false || options.fetch === null ? null : undefined,
252
- }))
253
-
254
- // Get the entrypoint and call fetch
255
- const entrypoint = worker.getEntrypoint()
256
- const response = await entrypoint.fetch(new Request('http://sandbox/execute'))
257
- const result = (await response.json()) as EvaluateResult
258
-
259
- return {
260
- ...result,
261
- duration: Date.now() - start,
262
- }
263
- }
264
-
265
- /**
266
- * Evaluate using full worker template with capnweb and TEST binding
267
- */
268
- async function evaluateWithWorkerLoader(
269
- options: EvaluateOptions,
270
- loader: WorkerLoader,
271
- testService: unknown,
272
- start: number
273
- ): Promise<EvaluateResult> {
274
- const workerCode = generateWorkerCode({
275
- module: options.module,
276
- tests: options.tests,
277
- script: options.script,
278
- sdk: options.sdk,
279
- imports: options.imports,
280
- fetch: options.fetch,
281
- })
282
- const id = `sandbox-${Date.now()}-${Math.random().toString(36).slice(2)}`
283
-
284
- const worker = loader.get(id, async () => ({
285
- mainModule: 'worker.js',
286
- modules: {
287
- 'worker.js': workerCode,
288
- // Include capnweb as a module so the worker can import it
289
- 'capnweb.js': CAPNWEB_SOURCE,
290
- },
291
- compatibilityDate: COMPATIBILITY_DATE,
292
- // Block network if fetch is false or null
293
- globalOutbound: options.fetch === false || options.fetch === null ? null : undefined,
294
- bindings: {
295
- TEST: testService,
296
- },
297
- }))
298
-
299
- // Get the entrypoint and call fetch (required by Cloudflare worker_loaders API)
300
- const entrypoint = worker.getEntrypoint()
301
- const response = await entrypoint.fetch(new Request('http://sandbox/execute'))
302
- const result = (await response.json()) as EvaluateResult
303
-
304
- return {
305
- ...result,
306
- duration: Date.now() - start,
307
- }
308
- }
309
-
310
- /**
311
- * Create an evaluate function bound to a specific environment
312
- *
313
- * Useful for Cloudflare Workers where env is passed to fetch handler.
314
- *
315
- * @example
316
- * ```ts
317
- * // In a Cloudflare Worker
318
- * export default {
319
- * async fetch(request, env) {
320
- * const sandbox = createEvaluator(env)
321
- * const result = await sandbox({ script: '1 + 1' })
322
- * return Response.json(result)
323
- * }
324
- * }
325
- * ```
326
- */
327
- export function createEvaluator(env: SandboxEnv) {
328
- return (options: EvaluateOptions) => evaluate(options, env)
329
- }
package/src/index.ts DELETED
@@ -1,23 +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
-
11
- export { evaluate, createEvaluator } from './evaluate.js'
12
- export { normalizeImport, normalizeImports } from './shared.js'
13
-
14
- export type {
15
- EvaluateOptions,
16
- EvaluateResult,
17
- LogEntry,
18
- TestResults,
19
- TestResult,
20
- SandboxEnv,
21
- SDKConfig,
22
- FetchConfig,
23
- } from './types.js'