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.
Files changed (74) hide show
  1. package/README.md +16 -0
  2. package/dist/evaluate.d.ts.map +1 -1
  3. package/dist/evaluate.js +10 -10
  4. package/dist/evaluate.js.map +1 -1
  5. package/dist/index.d.ts +1 -1
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/miniflare-pool.d.ts.map +1 -1
  8. package/dist/miniflare-pool.js +1 -1
  9. package/dist/miniflare-pool.js.map +1 -1
  10. package/dist/node.d.ts.map +1 -1
  11. package/dist/node.js.map +1 -1
  12. package/dist/repl.js +6 -6
  13. package/dist/repl.js.map +1 -1
  14. package/dist/shared.d.ts.map +1 -1
  15. package/dist/shared.js +5 -2
  16. package/dist/shared.js.map +1 -1
  17. package/dist/static/index.d.ts +111 -0
  18. package/dist/static/index.d.ts.map +1 -0
  19. package/dist/static/index.js +347 -0
  20. package/dist/static/index.js.map +1 -0
  21. package/dist/type-guards.d.ts.map +1 -1
  22. package/dist/type-guards.js +64 -62
  23. package/dist/type-guards.js.map +1 -1
  24. package/dist/worker-template/core.d.ts.map +1 -1
  25. package/dist/worker-template/core.js +1 -1
  26. package/dist/worker-template/core.js.map +1 -1
  27. package/package.json +19 -6
  28. package/public/capnweb.mjs +220 -0
  29. package/public/index.mjs +426 -0
  30. package/public/scaffold.mjs +198 -0
  31. package/.turbo/turbo-build.log +0 -4
  32. package/.turbo/turbo-test.log +0 -54
  33. package/.turbo/turbo-typecheck.log +0 -4
  34. package/CHANGELOG.md +0 -48
  35. package/dist/worker-template.d.ts +0 -41
  36. package/dist/worker-template.d.ts.map +0 -1
  37. package/dist/worker-template.js +0 -3748
  38. package/dist/worker-template.js.map +0 -1
  39. package/example/package.json +0 -20
  40. package/example/src/index.ts +0 -221
  41. package/example/wrangler.jsonc +0 -25
  42. package/src/capnweb-bundle.ts +0 -2596
  43. package/src/evaluate.ts +0 -329
  44. package/src/index.ts +0 -23
  45. package/src/miniflare-pool.ts +0 -395
  46. package/src/node.ts +0 -245
  47. package/src/repl.ts +0 -228
  48. package/src/shared.ts +0 -186
  49. package/src/type-guards.ts +0 -323
  50. package/src/types.ts +0 -196
  51. package/src/validation.ts +0 -120
  52. package/src/worker-template/code-transforms.ts +0 -32
  53. package/src/worker-template/core.ts +0 -557
  54. package/src/worker-template/helpers.ts +0 -90
  55. package/src/worker-template/index.ts +0 -23
  56. package/src/worker-template/sdk-generator.ts +0 -2515
  57. package/src/worker-template/test-generator.ts +0 -358
  58. package/test/evaluate-extended.test.js +0 -429
  59. package/test/evaluate-extended.test.ts +0 -469
  60. package/test/evaluate.test.js +0 -235
  61. package/test/evaluate.test.ts +0 -253
  62. package/test/index.test.js +0 -77
  63. package/test/index.test.ts +0 -95
  64. package/test/miniflare-pool.test.ts +0 -246
  65. package/test/node.test.ts +0 -467
  66. package/test/security.test.ts +0 -1009
  67. package/test/shared.test.ts +0 -105
  68. package/test/type-guards.test.ts +0 -303
  69. package/test/validation.test.ts +0 -240
  70. package/test/worker-template.test.js +0 -365
  71. package/test/worker-template.test.ts +0 -432
  72. package/tsconfig.json +0 -22
  73. package/vitest.config.js +0 -21
  74. 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'