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
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Miniflare instance pool for improved performance
|
|
3
|
+
*
|
|
4
|
+
* Reuses Miniflare instances between evaluations instead of creating/disposing
|
|
5
|
+
* for each evaluation, providing 4-5x performance improvement.
|
|
6
|
+
*
|
|
7
|
+
* Uses Miniflare's setOptions() to update the worker script between uses,
|
|
8
|
+
* avoiding the expensive instance creation/teardown cycle.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Global pool state (singleton per process)
|
|
12
|
+
*/
|
|
13
|
+
let pool = [];
|
|
14
|
+
let poolConfig = {
|
|
15
|
+
size: 3,
|
|
16
|
+
maxIdleTime: 30000,
|
|
17
|
+
};
|
|
18
|
+
let idleCleanupInterval = null;
|
|
19
|
+
let MiniflareClass = null;
|
|
20
|
+
let isShuttingDown = false;
|
|
21
|
+
// Default worker script for warm instances
|
|
22
|
+
const WARM_WORKER_SCRIPT = `
|
|
23
|
+
export default {
|
|
24
|
+
async fetch(request, env) {
|
|
25
|
+
return new Response('ready', { status: 200 });
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
`;
|
|
29
|
+
/**
|
|
30
|
+
* Configure the Miniflare pool
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* import { configurePool } from 'ai-evaluate/node'
|
|
35
|
+
*
|
|
36
|
+
* configurePool({
|
|
37
|
+
* size: 5, // Keep 5 warm instances
|
|
38
|
+
* maxIdleTime: 60000 // Dispose after 60s idle
|
|
39
|
+
* })
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export function configurePool(config) {
|
|
43
|
+
poolConfig = {
|
|
44
|
+
size: config.size ?? poolConfig.size,
|
|
45
|
+
maxIdleTime: config.maxIdleTime ?? poolConfig.maxIdleTime,
|
|
46
|
+
};
|
|
47
|
+
startIdleCleanup();
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Get the current pool configuration
|
|
51
|
+
*/
|
|
52
|
+
export function getPoolConfig() {
|
|
53
|
+
return { ...poolConfig };
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Get pool statistics for monitoring
|
|
57
|
+
*/
|
|
58
|
+
export function getPoolStats() {
|
|
59
|
+
const available = pool.filter((p) => !p.inUse).length;
|
|
60
|
+
return {
|
|
61
|
+
size: pool.length,
|
|
62
|
+
available,
|
|
63
|
+
inUse: pool.length - available,
|
|
64
|
+
config: { ...poolConfig },
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Initialize the Miniflare class (lazy load)
|
|
69
|
+
*/
|
|
70
|
+
async function getMiniflareClass() {
|
|
71
|
+
if (!MiniflareClass) {
|
|
72
|
+
const { Miniflare } = await import('miniflare');
|
|
73
|
+
MiniflareClass = Miniflare;
|
|
74
|
+
}
|
|
75
|
+
return MiniflareClass;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Create a new Miniflare instance with a warm worker
|
|
79
|
+
*/
|
|
80
|
+
async function createInstance() {
|
|
81
|
+
const Miniflare = await getMiniflareClass();
|
|
82
|
+
return new Miniflare({
|
|
83
|
+
modules: true,
|
|
84
|
+
script: WARM_WORKER_SCRIPT,
|
|
85
|
+
compatibilityDate: '2026-01-01',
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Start the idle cleanup interval
|
|
90
|
+
*/
|
|
91
|
+
function startIdleCleanup() {
|
|
92
|
+
if (idleCleanupInterval) {
|
|
93
|
+
clearInterval(idleCleanupInterval);
|
|
94
|
+
}
|
|
95
|
+
idleCleanupInterval = setInterval(async () => {
|
|
96
|
+
if (isShuttingDown)
|
|
97
|
+
return;
|
|
98
|
+
const now = Date.now();
|
|
99
|
+
const toDispose = [];
|
|
100
|
+
// Find idle instances beyond the idle timeout
|
|
101
|
+
for (let i = pool.length - 1; i >= 0; i--) {
|
|
102
|
+
const item = pool[i];
|
|
103
|
+
if (!item.inUse && now - item.lastUsed > poolConfig.maxIdleTime) {
|
|
104
|
+
// Keep at least one warm instance
|
|
105
|
+
if (pool.filter((p) => !p.inUse && !toDispose.includes(p)).length > 1) {
|
|
106
|
+
toDispose.push(item);
|
|
107
|
+
pool.splice(i, 1);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// Dispose old instances
|
|
112
|
+
for (const item of toDispose) {
|
|
113
|
+
try {
|
|
114
|
+
await item.instance.dispose();
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
// Ignore disposal errors
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}, 5000); // Check every 5 seconds
|
|
121
|
+
// Don't keep the process alive just for cleanup
|
|
122
|
+
if (idleCleanupInterval.unref) {
|
|
123
|
+
idleCleanupInterval.unref();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Acquire a Miniflare instance from the pool and configure it with a worker
|
|
128
|
+
*
|
|
129
|
+
* If a free instance is available, it will be reconfigured and returned.
|
|
130
|
+
* Otherwise, a new instance will be created (up to pool size limit).
|
|
131
|
+
* If pool is exhausted, creates a temporary instance.
|
|
132
|
+
*
|
|
133
|
+
* @param workerOptions - Configuration for the worker to run
|
|
134
|
+
* @returns Object with the configured instance and a release function
|
|
135
|
+
*/
|
|
136
|
+
export async function acquireInstance(workerOptions) {
|
|
137
|
+
if (isShuttingDown) {
|
|
138
|
+
throw new Error('Pool is shutting down');
|
|
139
|
+
}
|
|
140
|
+
// Start idle cleanup if not started
|
|
141
|
+
if (!idleCleanupInterval) {
|
|
142
|
+
startIdleCleanup();
|
|
143
|
+
}
|
|
144
|
+
const { script, compatibilityDate = '2026-01-01', outboundService } = workerOptions;
|
|
145
|
+
// Build the options for setOptions
|
|
146
|
+
const updateOptions = {
|
|
147
|
+
modules: true,
|
|
148
|
+
script,
|
|
149
|
+
compatibilityDate,
|
|
150
|
+
};
|
|
151
|
+
// Only add outboundService if it's defined (for blocking network)
|
|
152
|
+
if (outboundService !== undefined) {
|
|
153
|
+
updateOptions.outboundService = outboundService;
|
|
154
|
+
}
|
|
155
|
+
// Try to find an available instance
|
|
156
|
+
const available = pool.find((p) => !p.inUse);
|
|
157
|
+
if (available) {
|
|
158
|
+
available.inUse = true;
|
|
159
|
+
// Reconfigure the instance with the new worker script
|
|
160
|
+
await available.instance.setOptions(updateOptions);
|
|
161
|
+
return {
|
|
162
|
+
instance: available.instance,
|
|
163
|
+
release: async () => {
|
|
164
|
+
available.inUse = false;
|
|
165
|
+
available.lastUsed = Date.now();
|
|
166
|
+
},
|
|
167
|
+
isPooled: true,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
// Create new instance if pool not full
|
|
171
|
+
if (pool.length < poolConfig.size) {
|
|
172
|
+
const Miniflare = await getMiniflareClass();
|
|
173
|
+
const instance = new Miniflare(updateOptions);
|
|
174
|
+
const pooled = {
|
|
175
|
+
instance,
|
|
176
|
+
inUse: true,
|
|
177
|
+
lastUsed: Date.now(),
|
|
178
|
+
createdAt: Date.now(),
|
|
179
|
+
};
|
|
180
|
+
pool.push(pooled);
|
|
181
|
+
return {
|
|
182
|
+
instance,
|
|
183
|
+
release: async () => {
|
|
184
|
+
pooled.inUse = false;
|
|
185
|
+
pooled.lastUsed = Date.now();
|
|
186
|
+
},
|
|
187
|
+
isPooled: true,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
// Pool exhausted - create temporary instance
|
|
191
|
+
const Miniflare = await getMiniflareClass();
|
|
192
|
+
const tempInstance = new Miniflare(updateOptions);
|
|
193
|
+
return {
|
|
194
|
+
instance: tempInstance,
|
|
195
|
+
release: async () => {
|
|
196
|
+
// Dispose temporary instance immediately
|
|
197
|
+
await tempInstance.dispose();
|
|
198
|
+
},
|
|
199
|
+
isPooled: false,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Pre-warm the pool with instances
|
|
204
|
+
*
|
|
205
|
+
* Call this at application startup to avoid cold start latency.
|
|
206
|
+
*
|
|
207
|
+
* @example
|
|
208
|
+
* ```ts
|
|
209
|
+
* import { warmPool } from 'ai-evaluate/node'
|
|
210
|
+
*
|
|
211
|
+
* // Pre-warm 3 instances at startup
|
|
212
|
+
* await warmPool(3)
|
|
213
|
+
* ```
|
|
214
|
+
*/
|
|
215
|
+
export async function warmPool(count) {
|
|
216
|
+
const targetCount = count ?? poolConfig.size;
|
|
217
|
+
const toCreate = Math.max(0, targetCount - pool.length);
|
|
218
|
+
const promises = [];
|
|
219
|
+
for (let i = 0; i < toCreate; i++) {
|
|
220
|
+
promises.push((async () => {
|
|
221
|
+
const instance = await createInstance();
|
|
222
|
+
pool.push({
|
|
223
|
+
instance,
|
|
224
|
+
inUse: false,
|
|
225
|
+
lastUsed: Date.now(),
|
|
226
|
+
createdAt: Date.now(),
|
|
227
|
+
});
|
|
228
|
+
})());
|
|
229
|
+
}
|
|
230
|
+
await Promise.all(promises);
|
|
231
|
+
// Start idle cleanup if not already started
|
|
232
|
+
if (!idleCleanupInterval) {
|
|
233
|
+
startIdleCleanup();
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Dispose all instances and clean up the pool
|
|
238
|
+
*
|
|
239
|
+
* Call this before process exit to ensure clean shutdown.
|
|
240
|
+
*
|
|
241
|
+
* @example
|
|
242
|
+
* ```ts
|
|
243
|
+
* import { disposePool } from 'ai-evaluate/node'
|
|
244
|
+
*
|
|
245
|
+
* process.on('beforeExit', async () => {
|
|
246
|
+
* await disposePool()
|
|
247
|
+
* })
|
|
248
|
+
* ```
|
|
249
|
+
*/
|
|
250
|
+
export async function disposePool() {
|
|
251
|
+
isShuttingDown = true;
|
|
252
|
+
if (idleCleanupInterval) {
|
|
253
|
+
clearInterval(idleCleanupInterval);
|
|
254
|
+
idleCleanupInterval = null;
|
|
255
|
+
}
|
|
256
|
+
const instances = [...pool];
|
|
257
|
+
pool = [];
|
|
258
|
+
await Promise.all(instances.map(async (item) => {
|
|
259
|
+
try {
|
|
260
|
+
await item.instance.dispose();
|
|
261
|
+
}
|
|
262
|
+
catch {
|
|
263
|
+
// Ignore disposal errors
|
|
264
|
+
}
|
|
265
|
+
}));
|
|
266
|
+
isShuttingDown = false;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Reset the pool (for testing purposes)
|
|
270
|
+
*/
|
|
271
|
+
export async function resetPool() {
|
|
272
|
+
await disposePool();
|
|
273
|
+
poolConfig = {
|
|
274
|
+
size: 3,
|
|
275
|
+
maxIdleTime: 30000,
|
|
276
|
+
};
|
|
277
|
+
MiniflareClass = null;
|
|
278
|
+
}
|
|
279
|
+
// Register cleanup on process exit
|
|
280
|
+
if (typeof process !== 'undefined') {
|
|
281
|
+
const cleanup = () => {
|
|
282
|
+
isShuttingDown = true;
|
|
283
|
+
if (idleCleanupInterval) {
|
|
284
|
+
clearInterval(idleCleanupInterval);
|
|
285
|
+
}
|
|
286
|
+
// Synchronous disposal attempt - best effort
|
|
287
|
+
for (const item of pool) {
|
|
288
|
+
try {
|
|
289
|
+
// Fire and forget - we're exiting anyway
|
|
290
|
+
item.instance.dispose().catch(() => { });
|
|
291
|
+
}
|
|
292
|
+
catch {
|
|
293
|
+
// Ignore errors during shutdown
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
pool = [];
|
|
297
|
+
};
|
|
298
|
+
process.on('exit', cleanup);
|
|
299
|
+
process.on('SIGINT', () => {
|
|
300
|
+
cleanup();
|
|
301
|
+
process.exit(0);
|
|
302
|
+
});
|
|
303
|
+
process.on('SIGTERM', () => {
|
|
304
|
+
cleanup();
|
|
305
|
+
process.exit(0);
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
//# sourceMappingURL=miniflare-pool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"miniflare-pool.js","sourceRoot":"","sources":["../src/miniflare-pool.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA6CH;;GAEG;AACH,IAAI,IAAI,GAAqB,EAAE,CAAA;AAC/B,IAAI,UAAU,GAAyB;IACrC,IAAI,EAAE,CAAC;IACP,WAAW,EAAE,KAAK;CACnB,CAAA;AACD,IAAI,mBAAmB,GAA0B,IAAI,CAAA;AACrD,IAAI,cAAc,GAAgC,IAAI,CAAA;AACtD,IAAI,cAAc,GAAG,KAAK,CAAA;AAE1B,2CAA2C;AAC3C,MAAM,kBAAkB,GAAG;;;;;;CAM1B,CAAA;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,aAAa,CAAC,MAAkB;IAC9C,UAAU,GAAG;QACX,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,UAAU,CAAC,IAAI;QACpC,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,UAAU,CAAC,WAAW;KAC1D,CAAA;IACD,gBAAgB,EAAE,CAAA;AACpB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO,EAAE,GAAG,UAAU,EAAE,CAAA;AAC1B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY;IAM1B,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAA;IACrD,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,MAAM;QACjB,SAAS;QACT,KAAK,EAAE,IAAI,CAAC,MAAM,GAAG,SAAS;QAC9B,MAAM,EAAE,EAAE,GAAG,UAAU,EAAE;KAC1B,CAAA;AACH,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,iBAAiB;IAC9B,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAA;QAC/C,cAAc,GAAG,SAAiC,CAAA;IACpD,CAAC;IACD,OAAO,cAAc,CAAA;AACvB,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,cAAc;IAC3B,MAAM,SAAS,GAAG,MAAM,iBAAiB,EAAE,CAAA;IAC3C,OAAO,IAAI,SAAS,CAAC;QACnB,OAAO,EAAE,IAAI;QACb,MAAM,EAAE,kBAAkB;QAC1B,iBAAiB,EAAE,YAAY;KAChC,CAAC,CAAA;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,gBAAgB;IACvB,IAAI,mBAAmB,EAAE,CAAC;QACxB,aAAa,CAAC,mBAAmB,CAAC,CAAA;IACpC,CAAC;IAED,mBAAmB,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;QAC3C,IAAI,cAAc;YAAE,OAAM;QAE1B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QACtB,MAAM,SAAS,GAAqB,EAAE,CAAA;QAEtC,8CAA8C;QAC9C,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;YACpB,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,GAAG,GAAG,IAAI,CAAC,QAAQ,GAAG,UAAU,CAAC,WAAW,EAAE,CAAC;gBAChE,kCAAkC;gBAClC,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACtE,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;oBACpB,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;gBACnB,CAAC;YACH,CAAC;QACH,CAAC;QAED,wBAAwB;QACxB,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;YAC7B,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAA;YAC/B,CAAC;YAAC,MAAM,CAAC;gBACP,yBAAyB;YAC3B,CAAC;QACH,CAAC;IACH,CAAC,EAAE,IAAI,CAAC,CAAA,CAAC,wBAAwB;IAEjC,gDAAgD;IAChD,IAAI,mBAAmB,CAAC,KAAK,EAAE,CAAC;QAC9B,mBAAmB,CAAC,KAAK,EAAE,CAAA;IAC7B,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,aAA4B;IAKhE,IAAI,cAAc,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAA;IAC1C,CAAC;IAED,oCAAoC;IACpC,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACzB,gBAAgB,EAAE,CAAA;IACpB,CAAC;IAED,MAAM,EAAE,MAAM,EAAE,iBAAiB,GAAG,YAAY,EAAE,eAAe,EAAE,GAAG,aAAa,CAAA;IAEnF,mCAAmC;IACnC,MAAM,aAAa,GAAyB;QAC1C,OAAO,EAAE,IAAI;QACb,MAAM;QACN,iBAAiB;KAClB,CAAA;IAED,kEAAkE;IAClE,IAAI,eAAe,KAAK,SAAS,EAAE,CAAC;QAClC,aAAa,CAAC,eAAe,GAAG,eAAe,CAAA;IACjD,CAAC;IAED,oCAAoC;IACpC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;IAC5C,IAAI,SAAS,EAAE,CAAC;QACd,SAAS,CAAC,KAAK,GAAG,IAAI,CAAA;QACtB,sDAAsD;QACtD,MAAM,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC,aAAa,CAAC,CAAA;QAClD,OAAO;YACL,QAAQ,EAAE,SAAS,CAAC,QAAQ;YAC5B,OAAO,EAAE,KAAK,IAAI,EAAE;gBAClB,SAAS,CAAC,KAAK,GAAG,KAAK,CAAA;gBACvB,SAAS,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;YACjC,CAAC;YACD,QAAQ,EAAE,IAAI;SACf,CAAA;IACH,CAAC;IAED,uCAAuC;IACvC,IAAI,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC,IAAI,EAAE,CAAC;QAClC,MAAM,SAAS,GAAG,MAAM,iBAAiB,EAAE,CAAA;QAC3C,MAAM,QAAQ,GAAG,IAAI,SAAS,CAAC,aAAa,CAAC,CAAA;QAC7C,MAAM,MAAM,GAAmB;YAC7B,QAAQ;YACR,KAAK,EAAE,IAAI;YACX,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE;YACpB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB,CAAA;QACD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QACjB,OAAO;YACL,QAAQ;YACR,OAAO,EAAE,KAAK,IAAI,EAAE;gBAClB,MAAM,CAAC,KAAK,GAAG,KAAK,CAAA;gBACpB,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;YAC9B,CAAC;YACD,QAAQ,EAAE,IAAI;SACf,CAAA;IACH,CAAC;IAED,6CAA6C;IAC7C,MAAM,SAAS,GAAG,MAAM,iBAAiB,EAAE,CAAA;IAC3C,MAAM,YAAY,GAAG,IAAI,SAAS,CAAC,aAAa,CAAC,CAAA;IACjD,OAAO;QACL,QAAQ,EAAE,YAAY;QACtB,OAAO,EAAE,KAAK,IAAI,EAAE;YAClB,yCAAyC;YACzC,MAAM,YAAY,CAAC,OAAO,EAAE,CAAA;QAC9B,CAAC;QACD,QAAQ,EAAE,KAAK;KAChB,CAAA;AACH,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,KAAc;IAC3C,MAAM,WAAW,GAAG,KAAK,IAAI,UAAU,CAAC,IAAI,CAAA;IAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,CAAA;IAEvD,MAAM,QAAQ,GAAoB,EAAE,CAAA;IACpC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC;QAClC,QAAQ,CAAC,IAAI,CACX,CAAC,KAAK,IAAI,EAAE;YACV,MAAM,QAAQ,GAAG,MAAM,cAAc,EAAE,CAAA;YACvC,IAAI,CAAC,IAAI,CAAC;gBACR,QAAQ;gBACR,KAAK,EAAE,KAAK;gBACZ,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE;gBACpB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;aACtB,CAAC,CAAA;QACJ,CAAC,CAAC,EAAE,CACL,CAAA;IACH,CAAC;IAED,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IAE3B,4CAA4C;IAC5C,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACzB,gBAAgB,EAAE,CAAA;IACpB,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,cAAc,GAAG,IAAI,CAAA;IAErB,IAAI,mBAAmB,EAAE,CAAC;QACxB,aAAa,CAAC,mBAAmB,CAAC,CAAA;QAClC,mBAAmB,GAAG,IAAI,CAAA;IAC5B,CAAC;IAED,MAAM,SAAS,GAAG,CAAC,GAAG,IAAI,CAAC,CAAA;IAC3B,IAAI,GAAG,EAAE,CAAA;IAET,MAAM,OAAO,CAAC,GAAG,CACf,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QAC3B,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAA;QAC/B,CAAC;QAAC,MAAM,CAAC;YACP,yBAAyB;QAC3B,CAAC;IACH,CAAC,CAAC,CACH,CAAA;IAED,cAAc,GAAG,KAAK,CAAA;AACxB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,MAAM,WAAW,EAAE,CAAA;IACnB,UAAU,GAAG;QACX,IAAI,EAAE,CAAC;QACP,WAAW,EAAE,KAAK;KACnB,CAAA;IACD,cAAc,GAAG,IAAI,CAAA;AACvB,CAAC;AAED,mCAAmC;AACnC,IAAI,OAAO,OAAO,KAAK,WAAW,EAAE,CAAC;IACnC,MAAM,OAAO,GAAG,GAAG,EAAE;QACnB,cAAc,GAAG,IAAI,CAAA;QACrB,IAAI,mBAAmB,EAAE,CAAC;YACxB,aAAa,CAAC,mBAAmB,CAAC,CAAA;QACpC,CAAC;QACD,6CAA6C;QAC7C,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;YACxB,IAAI,CAAC;gBACH,yCAAyC;gBACzC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;YACzC,CAAC;YAAC,MAAM,CAAC;gBACP,gCAAgC;YAClC,CAAC;QACH,CAAC;QACD,IAAI,GAAG,EAAE,CAAA;IACX,CAAC,CAAA;IAED,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC3B,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;QACxB,OAAO,EAAE,CAAA;QACT,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC,CAAC,CAAA;IACF,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;QACzB,OAAO,EAAE,CAAA;QACT,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC,CAAC,CAAA;AACJ,CAAC"}
|
package/dist/node.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAgB,UAAU,
|
|
1
|
+
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAgB,UAAU,EAAe,MAAM,YAAY,CAAA;AAoCxG;;GAEG;AACH,wBAAsB,QAAQ,CAC5B,OAAO,EAAE,eAAe,EACxB,GAAG,CAAC,EAAE,UAAU,GACf,OAAO,CAAC,cAAc,CAAC,CAmCzB;AAkJD;;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/dist/node.js
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* Uses Cloudflare worker_loaders when available, falls back to Miniflare for local dev.
|
|
5
5
|
* For Workers-only builds, import from 'ai-evaluate' instead.
|
|
6
6
|
*/
|
|
7
|
-
import { generateWorkerCode, generateDevWorkerCode } from './worker-template.js';
|
|
7
|
+
import { generateWorkerCode, generateDevWorkerCode } from './worker-template/index.js';
|
|
8
|
+
import { isDomainAllowed, normalizeImports } from './shared.js';
|
|
8
9
|
/**
|
|
9
10
|
* Check if code contains JSX syntax that needs transformation
|
|
10
11
|
*/
|
|
@@ -52,6 +53,7 @@ export async function evaluate(options, env) {
|
|
|
52
53
|
module: transformedModule,
|
|
53
54
|
tests: transformedTests,
|
|
54
55
|
script: transformedScript,
|
|
56
|
+
imports: normalizeImports(options.imports),
|
|
55
57
|
};
|
|
56
58
|
// Use worker_loaders if available (Cloudflare Workers)
|
|
57
59
|
// Check lowercase first (preferred), then legacy uppercase
|
|
@@ -103,6 +105,23 @@ async function evaluateWithWorkerLoader(options, loader, testService, start) {
|
|
|
103
105
|
duration: Date.now() - start,
|
|
104
106
|
};
|
|
105
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* Determine if network access should be blocked based on fetch options
|
|
110
|
+
* fetch: false | null -> block
|
|
111
|
+
*/
|
|
112
|
+
function shouldBlockNetwork(options) {
|
|
113
|
+
return options.fetch === false || options.fetch === null;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Get allowlist domains if fetch is an array
|
|
117
|
+
* fetch: string[] -> allowlist
|
|
118
|
+
*/
|
|
119
|
+
function getAllowlistDomains(options) {
|
|
120
|
+
if (Array.isArray(options.fetch)) {
|
|
121
|
+
return options.fetch;
|
|
122
|
+
}
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
106
125
|
/**
|
|
107
126
|
* Evaluate using Miniflare (for Node.js/development)
|
|
108
127
|
*/
|
|
@@ -116,19 +135,32 @@ async function evaluateWithMiniflare(options, start) {
|
|
|
116
135
|
imports: options.imports,
|
|
117
136
|
fetch: options.fetch, // Pass fetch option to worker template
|
|
118
137
|
});
|
|
119
|
-
//
|
|
120
|
-
|
|
121
|
-
const
|
|
138
|
+
// Determine outbound service configuration based on fetch option
|
|
139
|
+
const blockNetwork = shouldBlockNetwork(options);
|
|
140
|
+
const allowlistDomains = getAllowlistDomains(options);
|
|
141
|
+
let outboundService;
|
|
142
|
+
if (blockNetwork) {
|
|
143
|
+
outboundService = () => {
|
|
144
|
+
throw new Error('Network access blocked: fetch is disabled in this sandbox');
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
else if (allowlistDomains) {
|
|
148
|
+
outboundService = (request) => {
|
|
149
|
+
const url = request.url;
|
|
150
|
+
if (!isDomainAllowed(url, allowlistDomains)) {
|
|
151
|
+
const hostname = new URL(url).hostname;
|
|
152
|
+
throw new Error(`Network access blocked: domain not in allowlist. Attempted: ${hostname}`);
|
|
153
|
+
}
|
|
154
|
+
// Allow the request by returning a fetched response
|
|
155
|
+
return fetch(request);
|
|
156
|
+
};
|
|
157
|
+
}
|
|
122
158
|
const mf = new Miniflare({
|
|
123
159
|
modules: true,
|
|
124
160
|
script: workerCode,
|
|
125
161
|
compatibilityDate: '2026-01-01',
|
|
126
|
-
//
|
|
127
|
-
...(
|
|
128
|
-
outboundService: () => {
|
|
129
|
-
throw new Error('Network access blocked: fetch is disabled in this sandbox');
|
|
130
|
-
},
|
|
131
|
-
}),
|
|
162
|
+
// Configure outbound service based on fetch mode
|
|
163
|
+
...(outboundService && { outboundService }),
|
|
132
164
|
});
|
|
133
165
|
try {
|
|
134
166
|
const timeout = options.timeout || 5000;
|
package/dist/node.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.js","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"node.js","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"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"}
|
package/dist/shared.d.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
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
|
+
import type { EvaluateResult } from './types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Compatibility date for dynamic workers (2026)
|
|
10
|
+
*/
|
|
11
|
+
export declare const COMPATIBILITY_DATE = "2026-01-01";
|
|
12
|
+
/**
|
|
13
|
+
* Normalize an import specifier to a full URL
|
|
14
|
+
*
|
|
15
|
+
* Supports:
|
|
16
|
+
* - Full URLs: https://esm.sh/lodash@4.17.21 (unchanged)
|
|
17
|
+
* - Bare package names: lodash -> https://esm.sh/lodash
|
|
18
|
+
* - Package with version: lodash@4.17.21 -> https://esm.sh/lodash@4.17.21
|
|
19
|
+
* - Scoped packages: @scope/pkg -> https://esm.sh/@scope/pkg
|
|
20
|
+
*/
|
|
21
|
+
export declare function normalizeImport(specifier: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* Normalize an array of import specifiers
|
|
24
|
+
*/
|
|
25
|
+
export declare function normalizeImports(imports: string[] | undefined): string[] | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* Extract package name from import specifier for variable naming
|
|
28
|
+
* Supports: lodash, lodash@4.17.21, @scope/pkg, https://esm.sh/lodash
|
|
29
|
+
*/
|
|
30
|
+
export declare function extractPackageName(specifier: string, index: number): string;
|
|
31
|
+
/**
|
|
32
|
+
* Default sandbox URL for worker fetch requests
|
|
33
|
+
*/
|
|
34
|
+
export declare const SANDBOX_URL = "http://sandbox/execute";
|
|
35
|
+
/**
|
|
36
|
+
* Generate a unique sandbox worker ID
|
|
37
|
+
*/
|
|
38
|
+
export declare const generateSandboxId: () => string;
|
|
39
|
+
/**
|
|
40
|
+
* Create an error result with consistent structure
|
|
41
|
+
*/
|
|
42
|
+
export declare function createErrorResult(error: unknown, start: number): EvaluateResult;
|
|
43
|
+
/**
|
|
44
|
+
* Process a result from worker execution, adding duration
|
|
45
|
+
*/
|
|
46
|
+
export declare function processResult(result: EvaluateResult, start: number): EvaluateResult;
|
|
47
|
+
/**
|
|
48
|
+
* Check if a domain matches a pattern (supports wildcards)
|
|
49
|
+
* @param domain - The domain to check (e.g., 'api.example.com')
|
|
50
|
+
* @param pattern - The pattern to match against (e.g., '*.example.com' or 'api.example.com')
|
|
51
|
+
* @returns true if the domain matches the pattern
|
|
52
|
+
*/
|
|
53
|
+
export declare function matchesDomainPattern(domain: string, pattern: string): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Check if a URL's domain is in the allowed list
|
|
56
|
+
* @param url - The URL to check
|
|
57
|
+
* @param allowedDomains - List of allowed domains (supports wildcards like '*.example.com')
|
|
58
|
+
* @returns true if the URL's domain is allowed
|
|
59
|
+
*/
|
|
60
|
+
export declare function isDomainAllowed(url: string, allowedDomains: string[]): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* Generate JavaScript code for domain checking in workers
|
|
63
|
+
* This is embedded into the worker source code
|
|
64
|
+
*/
|
|
65
|
+
export declare function generateDomainCheckCode(allowedDomains: string[]): string;
|
|
66
|
+
//# sourceMappingURL=shared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../src/shared.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAEhD;;GAEG;AACH,eAAO,MAAM,kBAAkB,eAAe,CAAA;AAE9C;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAQzD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,SAAS,GAAG,MAAM,EAAE,GAAG,SAAS,CAGpF;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAW3E;AAED;;GAEG;AACH,eAAO,MAAM,WAAW,2BAA2B,CAAA;AAEnD;;GAEG;AACH,eAAO,MAAM,iBAAiB,QAAO,MAC2B,CAAA;AAEhE;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,cAAc,CAO/E;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,GAAG,cAAc,CAKnF;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAoB7E;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,GAAG,OAAO,CAgB9E;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,cAAc,EAAE,MAAM,EAAE,GAAG,MAAM,CAsCxE"}
|
package/dist/shared.js
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
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
|
+
* Compatibility date for dynamic workers (2026)
|
|
9
|
+
*/
|
|
10
|
+
export const COMPATIBILITY_DATE = '2026-01-01';
|
|
11
|
+
/**
|
|
12
|
+
* Normalize an import specifier to a full URL
|
|
13
|
+
*
|
|
14
|
+
* Supports:
|
|
15
|
+
* - Full URLs: https://esm.sh/lodash@4.17.21 (unchanged)
|
|
16
|
+
* - Bare package names: lodash -> https://esm.sh/lodash
|
|
17
|
+
* - Package with version: lodash@4.17.21 -> https://esm.sh/lodash@4.17.21
|
|
18
|
+
* - Scoped packages: @scope/pkg -> https://esm.sh/@scope/pkg
|
|
19
|
+
*/
|
|
20
|
+
export function normalizeImport(specifier) {
|
|
21
|
+
// Already a URL - return as-is
|
|
22
|
+
if (specifier.includes('://')) {
|
|
23
|
+
return specifier;
|
|
24
|
+
}
|
|
25
|
+
// Bare package name or scoped package - prepend esm.sh
|
|
26
|
+
return `https://esm.sh/${specifier}`;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Normalize an array of import specifiers
|
|
30
|
+
*/
|
|
31
|
+
export function normalizeImports(imports) {
|
|
32
|
+
if (!imports || imports.length === 0)
|
|
33
|
+
return imports;
|
|
34
|
+
return imports.map(normalizeImport);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Extract package name from import specifier for variable naming
|
|
38
|
+
* Supports: lodash, lodash@4.17.21, @scope/pkg, https://esm.sh/lodash
|
|
39
|
+
*/
|
|
40
|
+
export function extractPackageName(specifier, index) {
|
|
41
|
+
let pkgName;
|
|
42
|
+
if (specifier.includes('://')) {
|
|
43
|
+
// Full URL - extract from path
|
|
44
|
+
const match = specifier.match(/esm\.sh\/(@?[^@/]+)/);
|
|
45
|
+
pkgName = match ? match[1].replace(/^@/, '').replace(/-/g, '_') : `pkg${index}`;
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
// Bare package name - extract before @ version
|
|
49
|
+
pkgName = specifier.split('@')[0].replace(/^@/, '').replace(/-/g, '_').replace(/\//g, '_');
|
|
50
|
+
}
|
|
51
|
+
return pkgName;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Default sandbox URL for worker fetch requests
|
|
55
|
+
*/
|
|
56
|
+
export const SANDBOX_URL = 'http://sandbox/execute';
|
|
57
|
+
/**
|
|
58
|
+
* Generate a unique sandbox worker ID
|
|
59
|
+
*/
|
|
60
|
+
export const generateSandboxId = () => `sandbox-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
61
|
+
/**
|
|
62
|
+
* Create an error result with consistent structure
|
|
63
|
+
*/
|
|
64
|
+
export function createErrorResult(error, start) {
|
|
65
|
+
return {
|
|
66
|
+
success: false,
|
|
67
|
+
logs: [],
|
|
68
|
+
error: error instanceof Error ? error.message : String(error),
|
|
69
|
+
duration: Date.now() - start,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Process a result from worker execution, adding duration
|
|
74
|
+
*/
|
|
75
|
+
export function processResult(result, start) {
|
|
76
|
+
return {
|
|
77
|
+
...result,
|
|
78
|
+
duration: Date.now() - start,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Check if a domain matches a pattern (supports wildcards)
|
|
83
|
+
* @param domain - The domain to check (e.g., 'api.example.com')
|
|
84
|
+
* @param pattern - The pattern to match against (e.g., '*.example.com' or 'api.example.com')
|
|
85
|
+
* @returns true if the domain matches the pattern
|
|
86
|
+
*/
|
|
87
|
+
export function matchesDomainPattern(domain, pattern) {
|
|
88
|
+
// Normalize both to lowercase
|
|
89
|
+
const normalizedDomain = domain.toLowerCase();
|
|
90
|
+
const normalizedPattern = pattern.toLowerCase();
|
|
91
|
+
// Exact match
|
|
92
|
+
if (normalizedDomain === normalizedPattern) {
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
// Wildcard pattern: *.example.com
|
|
96
|
+
if (normalizedPattern.startsWith('*.')) {
|
|
97
|
+
const suffix = normalizedPattern.slice(2); // Remove '*.'
|
|
98
|
+
// Domain must end with the suffix and have at least one character before it
|
|
99
|
+
// e.g., 'api.example.com' matches '*.example.com'
|
|
100
|
+
// but 'example.com' does not match '*.example.com'
|
|
101
|
+
return normalizedDomain.endsWith('.' + suffix) || normalizedDomain === suffix;
|
|
102
|
+
}
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Check if a URL's domain is in the allowed list
|
|
107
|
+
* @param url - The URL to check
|
|
108
|
+
* @param allowedDomains - List of allowed domains (supports wildcards like '*.example.com')
|
|
109
|
+
* @returns true if the URL's domain is allowed
|
|
110
|
+
*/
|
|
111
|
+
export function isDomainAllowed(url, allowedDomains) {
|
|
112
|
+
try {
|
|
113
|
+
const parsedUrl = new URL(url);
|
|
114
|
+
const hostname = parsedUrl.hostname;
|
|
115
|
+
for (const pattern of allowedDomains) {
|
|
116
|
+
if (matchesDomainPattern(hostname, pattern)) {
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
// Invalid URL - not allowed
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Generate JavaScript code for domain checking in workers
|
|
129
|
+
* This is embedded into the worker source code
|
|
130
|
+
*/
|
|
131
|
+
export function generateDomainCheckCode(allowedDomains) {
|
|
132
|
+
const domainsJson = JSON.stringify(allowedDomains);
|
|
133
|
+
return `
|
|
134
|
+
// Domain allowlist checking
|
|
135
|
+
const __allowedDomains__ = ${domainsJson};
|
|
136
|
+
|
|
137
|
+
const __matchesDomainPattern__ = (domain, pattern) => {
|
|
138
|
+
const normalizedDomain = domain.toLowerCase();
|
|
139
|
+
const normalizedPattern = pattern.toLowerCase();
|
|
140
|
+
if (normalizedDomain === normalizedPattern) return true;
|
|
141
|
+
if (normalizedPattern.startsWith('*.')) {
|
|
142
|
+
const suffix = normalizedPattern.slice(2);
|
|
143
|
+
return normalizedDomain.endsWith('.' + suffix) || normalizedDomain === suffix;
|
|
144
|
+
}
|
|
145
|
+
return false;
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
const __isDomainAllowed__ = (url) => {
|
|
149
|
+
try {
|
|
150
|
+
const parsedUrl = new URL(url);
|
|
151
|
+
const hostname = parsedUrl.hostname;
|
|
152
|
+
for (const pattern of __allowedDomains__) {
|
|
153
|
+
if (__matchesDomainPattern__(hostname, pattern)) return true;
|
|
154
|
+
}
|
|
155
|
+
return false;
|
|
156
|
+
} catch { return false; }
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const __originalFetch__ = globalThis.fetch;
|
|
160
|
+
globalThis.fetch = async (input, init) => {
|
|
161
|
+
const url = typeof input === 'string' ? input : input instanceof Request ? input.url : String(input);
|
|
162
|
+
if (!__isDomainAllowed__(url)) {
|
|
163
|
+
throw new Error(\`Network access blocked: domain not in allowlist. Attempted: \${new URL(url).hostname}\`);
|
|
164
|
+
}
|
|
165
|
+
return __originalFetch__(input, init);
|
|
166
|
+
};
|
|
167
|
+
`;
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=shared.js.map
|