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/repl.ts DELETED
@@ -1,228 +0,0 @@
1
- /**
2
- * REPL session support for ai-evaluate
3
- *
4
- * Provides persistent evaluation sessions with context preservation.
5
- */
6
-
7
- import type { EvaluateOptions, EvaluateResult, SandboxEnv, SDKConfig } from './types.js'
8
-
9
- /**
10
- * REPL session configuration
11
- */
12
- export interface ReplSessionConfig {
13
- /** Use local Miniflare instead of remote workers */
14
- local?: boolean
15
- /** Authentication token for remote execution */
16
- auth?: string
17
- /** SDK configuration for platform primitives */
18
- sdk?: SDKConfig | boolean
19
- /** Code to run when session starts (defines globals, imports) */
20
- prelude?: string
21
- /** Timeout for each evaluation in milliseconds */
22
- timeout?: number
23
- /** Allow network access */
24
- allowNetwork?: boolean
25
- }
26
-
27
- /**
28
- * Result from a REPL evaluation
29
- */
30
- export interface ReplEvalResult extends EvaluateResult {
31
- /** Variables exported during evaluation */
32
- exports?: Record<string, unknown>
33
- }
34
-
35
- /**
36
- * REPL session with persistent context
37
- */
38
- export interface ReplSession {
39
- /** Evaluate code in the session context */
40
- eval(code: string): Promise<ReplEvalResult>
41
-
42
- /** Get current session context (accumulated exports) */
43
- getContext(): Record<string, unknown>
44
-
45
- /** Set a value in the session context */
46
- setContext(key: string, value: unknown): void
47
-
48
- /** Clear the session context */
49
- clearContext(): void
50
-
51
- /** Run prelude code (called automatically on first eval) */
52
- runPrelude(): Promise<void>
53
-
54
- /** Close the session and release resources */
55
- close(): Promise<void>
56
- }
57
-
58
- /**
59
- * Create a REPL session for interactive code evaluation
60
- *
61
- * @example
62
- * ```ts
63
- * import { createReplSession } from 'ai-evaluate/repl'
64
- *
65
- * const session = await createReplSession({ local: true })
66
- *
67
- * await session.eval('const sum = (a, b) => a + b')
68
- * const result = await session.eval('sum(1, 2)')
69
- * console.log(result.value) // 3
70
- *
71
- * await session.close()
72
- * ```
73
- */
74
- export async function createReplSession(
75
- config?: ReplSessionConfig,
76
- env?: SandboxEnv
77
- ): Promise<ReplSession> {
78
- // Context accumulates across evaluations
79
- let context: Record<string, unknown> = {}
80
- let preludeRun = false
81
- let miniflare: unknown = null
82
-
83
- // Build module code from accumulated context
84
- function buildContextModule(): string {
85
- const entries = Object.entries(context)
86
- if (entries.length === 0) return ''
87
-
88
- return entries
89
- .map(([key, value]) => {
90
- if (typeof value === 'function') {
91
- return `export const ${key} = ${value.toString()}`
92
- }
93
- return `export const ${key} = ${JSON.stringify(value)}`
94
- })
95
- .join('\n')
96
- }
97
-
98
- // Get the evaluate function (local or remote)
99
- async function getEvaluate(): Promise<
100
- (options: EvaluateOptions, env?: SandboxEnv) => Promise<EvaluateResult>
101
- > {
102
- if (config?.local) {
103
- // Use local Miniflare via node.ts
104
- const { evaluate } = await import('./node.js')
105
- return evaluate
106
- } else if (env) {
107
- // Use remote worker loaders
108
- const { evaluate } = await import('./evaluate.js')
109
- return (options) => evaluate(options, env)
110
- } else {
111
- // Default to local if no env
112
- const { evaluate } = await import('./node.js')
113
- return evaluate
114
- }
115
- }
116
-
117
- const evaluate = await getEvaluate()
118
-
119
- async function runPrelude(): Promise<void> {
120
- if (preludeRun || !config?.prelude) return
121
- preludeRun = true
122
-
123
- const result = await evaluate(
124
- {
125
- module: config.prelude,
126
- script: 'return Object.keys(module)',
127
- sdk: config.sdk,
128
- timeout: config.timeout,
129
- fetch: config.allowNetwork === false ? null : undefined,
130
- },
131
- env
132
- )
133
-
134
- if (result.success && Array.isArray(result.value)) {
135
- // Store exported names in context
136
- for (const key of result.value) {
137
- context[key] = `__prelude_${key}__`
138
- }
139
- }
140
- }
141
-
142
- return {
143
- async eval(code: string): Promise<ReplEvalResult> {
144
- await runPrelude()
145
-
146
- // Wrap code to capture any declared variables
147
- const contextModule = buildContextModule()
148
- const preludeModule = config?.prelude || ''
149
-
150
- // Try to parse as expression first, then as statement
151
- const isExpression =
152
- !code.includes('const ') &&
153
- !code.includes('let ') &&
154
- !code.includes('function ') &&
155
- !code.includes('class ') &&
156
- !code.includes('export ')
157
-
158
- const script = isExpression
159
- ? `return (${code})`
160
- : code.includes('return ')
161
- ? code
162
- : `${code}\nreturn undefined`
163
-
164
- const result = await evaluate(
165
- {
166
- module: preludeModule + '\n' + contextModule,
167
- script,
168
- sdk: config?.sdk,
169
- timeout: config?.timeout,
170
- fetch: config?.allowNetwork === false ? null : undefined,
171
- },
172
- env
173
- )
174
-
175
- return result
176
- },
177
-
178
- getContext(): Record<string, unknown> {
179
- return { ...context }
180
- },
181
-
182
- setContext(key: string, value: unknown): void {
183
- context[key] = value
184
- },
185
-
186
- clearContext(): void {
187
- context = {}
188
- },
189
-
190
- runPrelude,
191
-
192
- async close(): Promise<void> {
193
- context = {}
194
- preludeRun = false
195
- if (
196
- miniflare &&
197
- typeof (miniflare as { dispose?: () => Promise<void> }).dispose === 'function'
198
- ) {
199
- await (miniflare as { dispose: () => Promise<void> }).dispose()
200
- miniflare = null
201
- }
202
- },
203
- }
204
- }
205
-
206
- /**
207
- * Quick evaluation helper for one-off evaluations
208
- *
209
- * @example
210
- * ```ts
211
- * import { quickEval } from 'ai-evaluate/repl'
212
- *
213
- * const result = await quickEval('1 + 2 * 3')
214
- * console.log(result.value) // 7
215
- * ```
216
- */
217
- export async function quickEval(
218
- code: string,
219
- config?: ReplSessionConfig,
220
- env?: SandboxEnv
221
- ): Promise<ReplEvalResult> {
222
- const session = await createReplSession(config, env)
223
- try {
224
- return await session.eval(code)
225
- } finally {
226
- await session.close()
227
- }
228
- }
package/src/shared.ts DELETED
@@ -1,186 +0,0 @@
1
- /**
2
- * Shared utilities for ai-evaluate
3
- *
4
- * Contains constants and helper functions used by both
5
- * evaluate.ts (Workers) and node.ts (Node.js/Miniflare)
6
- */
7
-
8
- import type { EvaluateResult } from './types.js'
9
-
10
- /**
11
- * Compatibility date for dynamic workers (2026)
12
- */
13
- export const COMPATIBILITY_DATE = '2026-01-01'
14
-
15
- /**
16
- * Normalize an import specifier to a full URL
17
- *
18
- * Supports:
19
- * - Full URLs: https://esm.sh/lodash@4.17.21 (unchanged)
20
- * - Bare package names: lodash -> https://esm.sh/lodash
21
- * - Package with version: lodash@4.17.21 -> https://esm.sh/lodash@4.17.21
22
- * - Scoped packages: @scope/pkg -> https://esm.sh/@scope/pkg
23
- */
24
- export function normalizeImport(specifier: string): string {
25
- // Already a URL - return as-is
26
- if (specifier.includes('://')) {
27
- return specifier
28
- }
29
-
30
- // Bare package name or scoped package - prepend esm.sh
31
- return `https://esm.sh/${specifier}`
32
- }
33
-
34
- /**
35
- * Normalize an array of import specifiers
36
- */
37
- export function normalizeImports(imports: string[] | undefined): string[] | undefined {
38
- if (!imports || imports.length === 0) return imports
39
- return imports.map(normalizeImport)
40
- }
41
-
42
- /**
43
- * Extract package name from import specifier for variable naming
44
- * Supports: lodash, lodash@4.17.21, @scope/pkg, https://esm.sh/lodash
45
- */
46
- export function extractPackageName(specifier: string, index: number): string {
47
- let pkgName: string
48
- if (specifier.includes('://')) {
49
- // Full URL - extract from path
50
- const match = specifier.match(/esm\.sh\/(@?[^@/]+)/)
51
- pkgName = match ? match[1].replace(/^@/, '').replace(/-/g, '_') : `pkg${index}`
52
- } else {
53
- // Bare package name - extract before @ version
54
- pkgName = specifier.split('@')[0].replace(/^@/, '').replace(/-/g, '_').replace(/\//g, '_')
55
- }
56
- return pkgName
57
- }
58
-
59
- /**
60
- * Default sandbox URL for worker fetch requests
61
- */
62
- export const SANDBOX_URL = 'http://sandbox/execute'
63
-
64
- /**
65
- * Generate a unique sandbox worker ID
66
- */
67
- export const generateSandboxId = (): string =>
68
- `sandbox-${Date.now()}-${Math.random().toString(36).slice(2)}`
69
-
70
- /**
71
- * Create an error result with consistent structure
72
- */
73
- export function createErrorResult(error: unknown, start: number): EvaluateResult {
74
- return {
75
- success: false,
76
- logs: [],
77
- error: error instanceof Error ? error.message : String(error),
78
- duration: Date.now() - start,
79
- }
80
- }
81
-
82
- /**
83
- * Process a result from worker execution, adding duration
84
- */
85
- export function processResult(result: EvaluateResult, start: number): EvaluateResult {
86
- return {
87
- ...result,
88
- duration: Date.now() - start,
89
- }
90
- }
91
-
92
- /**
93
- * Check if a domain matches a pattern (supports wildcards)
94
- * @param domain - The domain to check (e.g., 'api.example.com')
95
- * @param pattern - The pattern to match against (e.g., '*.example.com' or 'api.example.com')
96
- * @returns true if the domain matches the pattern
97
- */
98
- export function matchesDomainPattern(domain: string, pattern: string): boolean {
99
- // Normalize both to lowercase
100
- const normalizedDomain = domain.toLowerCase()
101
- const normalizedPattern = pattern.toLowerCase()
102
-
103
- // Exact match
104
- if (normalizedDomain === normalizedPattern) {
105
- return true
106
- }
107
-
108
- // Wildcard pattern: *.example.com
109
- if (normalizedPattern.startsWith('*.')) {
110
- const suffix = normalizedPattern.slice(2) // Remove '*.'
111
- // Domain must end with the suffix and have at least one character before it
112
- // e.g., 'api.example.com' matches '*.example.com'
113
- // but 'example.com' does not match '*.example.com'
114
- return normalizedDomain.endsWith('.' + suffix) || normalizedDomain === suffix
115
- }
116
-
117
- return false
118
- }
119
-
120
- /**
121
- * Check if a URL's domain is in the allowed list
122
- * @param url - The URL to check
123
- * @param allowedDomains - List of allowed domains (supports wildcards like '*.example.com')
124
- * @returns true if the URL's domain is allowed
125
- */
126
- export function isDomainAllowed(url: string, allowedDomains: string[]): boolean {
127
- try {
128
- const parsedUrl = new URL(url)
129
- const hostname = parsedUrl.hostname
130
-
131
- for (const pattern of allowedDomains) {
132
- if (matchesDomainPattern(hostname, pattern)) {
133
- return true
134
- }
135
- }
136
-
137
- return false
138
- } catch {
139
- // Invalid URL - not allowed
140
- return false
141
- }
142
- }
143
-
144
- /**
145
- * Generate JavaScript code for domain checking in workers
146
- * This is embedded into the worker source code
147
- */
148
- export function generateDomainCheckCode(allowedDomains: string[]): string {
149
- const domainsJson = JSON.stringify(allowedDomains)
150
-
151
- return `
152
- // Domain allowlist checking
153
- const __allowedDomains__ = ${domainsJson};
154
-
155
- const __matchesDomainPattern__ = (domain, pattern) => {
156
- const normalizedDomain = domain.toLowerCase();
157
- const normalizedPattern = pattern.toLowerCase();
158
- if (normalizedDomain === normalizedPattern) return true;
159
- if (normalizedPattern.startsWith('*.')) {
160
- const suffix = normalizedPattern.slice(2);
161
- return normalizedDomain.endsWith('.' + suffix) || normalizedDomain === suffix;
162
- }
163
- return false;
164
- };
165
-
166
- const __isDomainAllowed__ = (url) => {
167
- try {
168
- const parsedUrl = new URL(url);
169
- const hostname = parsedUrl.hostname;
170
- for (const pattern of __allowedDomains__) {
171
- if (__matchesDomainPattern__(hostname, pattern)) return true;
172
- }
173
- return false;
174
- } catch { return false; }
175
- };
176
-
177
- const __originalFetch__ = globalThis.fetch;
178
- globalThis.fetch = async (input, init) => {
179
- const url = typeof input === 'string' ? input : input instanceof Request ? input.url : String(input);
180
- if (!__isDomainAllowed__(url)) {
181
- throw new Error(\`Network access blocked: domain not in allowlist. Attempted: \${new URL(url).hostname}\`);
182
- }
183
- return __originalFetch__(input, init);
184
- };
185
- `
186
- }