runframe 1.0.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 (71) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +351 -0
  3. package/dist/async.d.ts +38 -0
  4. package/dist/async.d.ts.map +1 -0
  5. package/dist/async.js +98 -0
  6. package/dist/async.js.map +1 -0
  7. package/dist/benchmark.d.ts +9 -0
  8. package/dist/benchmark.d.ts.map +1 -0
  9. package/dist/benchmark.js +216 -0
  10. package/dist/benchmark.js.map +1 -0
  11. package/dist/capabilities.d.ts +26 -0
  12. package/dist/capabilities.d.ts.map +1 -0
  13. package/dist/capabilities.js +110 -0
  14. package/dist/capabilities.js.map +1 -0
  15. package/dist/deterministic.d.ts +81 -0
  16. package/dist/deterministic.d.ts.map +1 -0
  17. package/dist/deterministic.js +135 -0
  18. package/dist/deterministic.js.map +1 -0
  19. package/dist/index.d.ts +17 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +12 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/limits.d.ts +24 -0
  24. package/dist/limits.d.ts.map +1 -0
  25. package/dist/limits.js +42 -0
  26. package/dist/limits.js.map +1 -0
  27. package/dist/memory-optimization.d.ts +43 -0
  28. package/dist/memory-optimization.d.ts.map +1 -0
  29. package/dist/memory-optimization.js +103 -0
  30. package/dist/memory-optimization.js.map +1 -0
  31. package/dist/optimization-examples.d.ts +33 -0
  32. package/dist/optimization-examples.d.ts.map +1 -0
  33. package/dist/optimization-examples.js +255 -0
  34. package/dist/optimization-examples.js.map +1 -0
  35. package/dist/optimized-index.d.ts +12 -0
  36. package/dist/optimized-index.d.ts.map +1 -0
  37. package/dist/optimized-index.js +9 -0
  38. package/dist/optimized-index.js.map +1 -0
  39. package/dist/optimized-sandbox.d.ts +77 -0
  40. package/dist/optimized-sandbox.d.ts.map +1 -0
  41. package/dist/optimized-sandbox.js +153 -0
  42. package/dist/optimized-sandbox.js.map +1 -0
  43. package/dist/sandbox.d.ts +25 -0
  44. package/dist/sandbox.d.ts.map +1 -0
  45. package/dist/sandbox.js +55 -0
  46. package/dist/sandbox.js.map +1 -0
  47. package/dist/script-cache.d.ts +48 -0
  48. package/dist/script-cache.d.ts.map +1 -0
  49. package/dist/script-cache.js +97 -0
  50. package/dist/script-cache.js.map +1 -0
  51. package/dist/stats.d.ts +41 -0
  52. package/dist/stats.d.ts.map +1 -0
  53. package/dist/stats.js +70 -0
  54. package/dist/stats.js.map +1 -0
  55. package/dist/test-corpus.d.ts +15 -0
  56. package/dist/test-corpus.d.ts.map +1 -0
  57. package/dist/test-corpus.js +225 -0
  58. package/dist/test-corpus.js.map +1 -0
  59. package/dist/vm-runtime.d.ts +21 -0
  60. package/dist/vm-runtime.d.ts.map +1 -0
  61. package/dist/vm-runtime.js +276 -0
  62. package/dist/vm-runtime.js.map +1 -0
  63. package/dist/worker-pool.d.ts +62 -0
  64. package/dist/worker-pool.d.ts.map +1 -0
  65. package/dist/worker-pool.js +144 -0
  66. package/dist/worker-pool.js.map +1 -0
  67. package/dist/worker.d.ts +2 -0
  68. package/dist/worker.d.ts.map +1 -0
  69. package/dist/worker.js +39 -0
  70. package/dist/worker.js.map +1 -0
  71. package/package.json +67 -0
@@ -0,0 +1,225 @@
1
+ /**
2
+ * Escape test corpus: Known sandboxing attacks that MUST fail
3
+ * Used to verify the sandbox actually blocks dangerous operations
4
+ */
5
+ export const ESCAPE_TESTS = [
6
+ {
7
+ name: "Prototype poisoning: Array.prototype.push",
8
+ code: `
9
+ Array.prototype.push = function() { throw new Error("ESCAPED!"); };
10
+ const arr = [];
11
+ arr.push(1);
12
+ `,
13
+ shouldBlock: true
14
+ },
15
+ {
16
+ name: "Prototype poisoning: Object.prototype.toString",
17
+ code: `
18
+ Object.prototype.toString = () => "ESCAPED";
19
+ ({}).toString();
20
+ `,
21
+ shouldBlock: true
22
+ },
23
+ {
24
+ name: "Function constructor escape",
25
+ code: `
26
+ const fn = Function("return process.env");
27
+ fn();
28
+ `,
29
+ shouldBlock: true
30
+ },
31
+ {
32
+ name: "eval() forbidden",
33
+ code: `
34
+ eval("process.exit(1)");
35
+ `,
36
+ shouldBlock: true
37
+ },
38
+ {
39
+ name: "require() forbidden",
40
+ code: `
41
+ const fs = require("fs");
42
+ fs.readFileSync("/etc/passwd");
43
+ `,
44
+ shouldBlock: true
45
+ },
46
+ {
47
+ name: "process global forbidden",
48
+ code: `
49
+ process.exit(1);
50
+ `,
51
+ shouldBlock: true
52
+ },
53
+ {
54
+ name: "Worker threads forbidden",
55
+ code: `
56
+ const { Worker } = require("worker_threads");
57
+ new Worker("x.js");
58
+ `,
59
+ shouldBlock: true
60
+ },
61
+ {
62
+ name: "Buffer forbidden",
63
+ code: `
64
+ const buf = Buffer.alloc(1024);
65
+ buf.toString();
66
+ `,
67
+ shouldBlock: true
68
+ },
69
+ {
70
+ name: "Dynamic import forbidden",
71
+ code: `
72
+ import("fs").then(m => m.readFileSync("/"));
73
+ `,
74
+ shouldBlock: true
75
+ },
76
+ {
77
+ name: "Constructor property escape",
78
+ code: `
79
+ const arr = [];
80
+ const Ctor = arr.constructor.constructor;
81
+ const fn = new Ctor("return process");
82
+ fn();
83
+ `,
84
+ shouldBlock: true
85
+ },
86
+ {
87
+ name: "Symbol.iterator manipulation",
88
+ code: `
89
+ Array.prototype[Symbol.iterator] = function() {
90
+ throw new Error("ESCAPED");
91
+ };
92
+ const arr = [1, 2, 3];
93
+ for (const x of arr) {}
94
+ `,
95
+ shouldBlock: true
96
+ },
97
+ {
98
+ name: "__proto__ poisoning",
99
+ code: `
100
+ const obj = {};
101
+ obj.__proto__.ESCAPED = true;
102
+ ({}).ESCAPED;
103
+ `,
104
+ shouldBlock: true
105
+ },
106
+ {
107
+ name: "Constructor.constructor escape via array",
108
+ code: `
109
+ const Ctor = [].constructor.constructor;
110
+ const fn = new Ctor("return process");
111
+ fn();
112
+ `,
113
+ shouldBlock: true
114
+ },
115
+ {
116
+ name: "Constructor.constructor escape via object",
117
+ code: `
118
+ const Ctor = ({}).constructor.constructor;
119
+ const fn = new Ctor("return process");
120
+ fn();
121
+ `,
122
+ shouldBlock: true
123
+ },
124
+ {
125
+ name: "Constructor.constructor escape via string",
126
+ code: `
127
+ const Ctor = "".constructor.constructor;
128
+ const fn = new Ctor("return process");
129
+ fn();
130
+ `,
131
+ shouldBlock: true
132
+ },
133
+ {
134
+ name: "getPrototypeOf escape",
135
+ code: `
136
+ const proto = Object.getPrototypeOf([]);
137
+ const Ctor = proto.constructor.constructor;
138
+ new Ctor("process.exit()")();
139
+ `,
140
+ shouldBlock: true
141
+ },
142
+ {
143
+ name: "Reflection getOwnPropertyDescriptor escape",
144
+ code: `
145
+ const desc = Object.getOwnPropertyDescriptor({}, "x");
146
+ desc.constructor.constructor("process.exit()")();
147
+ `,
148
+ shouldBlock: true
149
+ },
150
+ {
151
+ name: "__proto__ pollution",
152
+ code: `
153
+ const obj = {};
154
+ obj.__proto__.ESCAPED = true;
155
+ ({}).ESCAPED;
156
+ `,
157
+ shouldBlock: true
158
+ },
159
+ {
160
+ name: "Safe: Basic arithmetic",
161
+ code: `
162
+ 1 + 2 + 3;
163
+ `,
164
+ shouldBlock: false
165
+ },
166
+ {
167
+ name: "Safe: Array operations",
168
+ code: `
169
+ const arr = [1, 2, 3];
170
+ arr.map(x => x * 2);
171
+ `,
172
+ shouldBlock: false
173
+ },
174
+ {
175
+ name: "Safe: Object creation",
176
+ code: `
177
+ const obj = { a: 1, b: 2 };
178
+ Object.keys(obj);
179
+ `,
180
+ shouldBlock: false
181
+ },
182
+ {
183
+ name: "Safe: JSON serialization",
184
+ code: `
185
+ JSON.stringify({ x: 1, y: 2 });
186
+ `,
187
+ shouldBlock: false
188
+ },
189
+ {
190
+ name: "Safe: String operations",
191
+ code: `
192
+ "hello world".toUpperCase().split(" ");
193
+ `,
194
+ shouldBlock: false
195
+ },
196
+ {
197
+ name: "Safe: Math operations",
198
+ code: `
199
+ Math.sqrt(16) + Math.PI;
200
+ `,
201
+ shouldBlock: false
202
+ },
203
+ {
204
+ name: "Safe: Deterministic date",
205
+ code: `
206
+ const d = new Date();
207
+ d.getTime();
208
+ `,
209
+ shouldBlock: false
210
+ }
211
+ ];
212
+ /**
213
+ * Check if a test result is correct
214
+ */
215
+ export function checkTestResult(test, threw, timedOut) {
216
+ if (test.shouldBlock) {
217
+ // Dangerous code should either throw or timeout
218
+ return threw || timedOut;
219
+ }
220
+ else {
221
+ // Safe code should succeed without throwing
222
+ return !threw && !timedOut;
223
+ }
224
+ }
225
+ //# sourceMappingURL=test-corpus.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-corpus.js","sourceRoot":"","sources":["../src/test-corpus.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import { CapabilityGrant } from "./capabilities.js";
2
+ import { StatsCollector } from "./stats.js";
3
+ import { PromiseTracker } from "./async.js";
4
+ /**
5
+ * Freeze all intrinsic constructors and their prototypes
6
+ * This prevents prototype poisoning attacks AND constructor.constructor escapes
7
+ */
8
+ export declare function freezeIntrinsics(): void;
9
+ export declare function createSandboxScope(capabilities: CapabilityGrant, statsCollector: StatsCollector, promiseTracker: PromiseTracker, seed?: number): Record<string, unknown>;
10
+ export interface SandboxRuntimeOptions {
11
+ capabilities?: Partial<CapabilityGrant>;
12
+ seed?: number;
13
+ }
14
+ /**
15
+ * Run code in a strict, isolated VM context with full tracking
16
+ */
17
+ export declare function runInSandbox(code: string, options?: SandboxRuntimeOptions): Promise<{
18
+ result: unknown;
19
+ stats: StatsCollector;
20
+ }>;
21
+ //# sourceMappingURL=vm-runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vm-runtime.d.ts","sourceRoot":"","sources":["../src/vm-runtime.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,eAAe,EAChB,MAAM,mBAAmB,CAAC;AAO3B,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,cAAc,EAA4B,MAAM,YAAY,CAAC;AAoDtE;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAsCvC;AAmED,wBAAgB,kBAAkB,CAChC,YAAY,EAAE,eAAe,EAC7B,cAAc,EAAE,cAAc,EAC9B,cAAc,EAAE,cAAc,EAC9B,IAAI,CAAC,EAAE,MAAM,GACZ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA6GzB;AAED,MAAM,WAAW,qBAAqB;IACpC,YAAY,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,cAAc,CAAA;CAAE,CAAC,CA6DrD"}
@@ -0,0 +1,276 @@
1
+ import vm from "node:vm";
2
+ import { createCapabilityGrant, createCapabilityMembrane } from "./capabilities.js";
3
+ import { createDeterministicGlobals } from "./deterministic.js";
4
+ import { StatsCollector } from "./stats.js";
5
+ import { PromiseTracker, createPromiseInterceptor } from "./async.js";
6
+ /**
7
+ * Intrinsics that we want to lock down
8
+ * These are the core objects that malicious code could use to break out
9
+ */
10
+ const INTRINSICS_TO_FREEZE = [
11
+ Object,
12
+ Array,
13
+ Function,
14
+ Promise,
15
+ Map,
16
+ Set,
17
+ WeakMap,
18
+ WeakSet,
19
+ Date,
20
+ RegExp,
21
+ Error,
22
+ TypeError,
23
+ ReferenceError,
24
+ SyntaxError,
25
+ RangeError
26
+ ];
27
+ /**
28
+ * Recursively freeze an object and all its properties
29
+ * Prevents any modification of the prototype chain
30
+ */
31
+ function deepFreeze(obj, visited = new WeakSet()) {
32
+ if (obj === null || typeof obj !== "object")
33
+ return;
34
+ if (visited.has(obj))
35
+ return;
36
+ visited.add(obj);
37
+ Object.freeze(obj);
38
+ // Freeze all properties
39
+ for (const prop of Object.getOwnPropertyNames(obj)) {
40
+ const descriptor = Object.getOwnPropertyDescriptor(obj, prop);
41
+ if (descriptor && descriptor.value) {
42
+ deepFreeze(descriptor.value, visited);
43
+ }
44
+ }
45
+ // Freeze symbol properties too
46
+ for (const sym of Object.getOwnPropertySymbols(obj)) {
47
+ const descriptor = Object.getOwnPropertyDescriptor(obj, sym);
48
+ if (descriptor && descriptor.value) {
49
+ deepFreeze(descriptor.value, visited);
50
+ }
51
+ }
52
+ }
53
+ /**
54
+ * Freeze all intrinsic constructors and their prototypes
55
+ * This prevents prototype poisoning attacks AND constructor.constructor escapes
56
+ */
57
+ export function freezeIntrinsics() {
58
+ // Freeze each intrinsic deeply
59
+ for (const intrinsic of INTRINSICS_TO_FREEZE) {
60
+ deepFreeze(intrinsic);
61
+ deepFreeze(intrinsic.prototype);
62
+ }
63
+ // Block .constructor access on all prototype chains
64
+ const blockConstructor = (proto) => {
65
+ if (proto === null || typeof proto !== "object")
66
+ return;
67
+ try {
68
+ Object.defineProperty(proto, "constructor", {
69
+ value: undefined,
70
+ writable: false,
71
+ enumerable: false,
72
+ configurable: false
73
+ });
74
+ }
75
+ catch { }
76
+ };
77
+ // Block on all prototypes
78
+ for (const intrinsic of INTRINSICS_TO_FREEZE) {
79
+ blockConstructor(intrinsic.prototype);
80
+ blockConstructor(Object.getPrototypeOf(intrinsic));
81
+ }
82
+ // Freeze Object static methods that could be used to escape
83
+ Object.freeze(Object.getPrototypeOf);
84
+ Object.freeze(Object.getOwnPropertyDescriptor);
85
+ Object.freeze(Object.getOwnPropertyNames);
86
+ Object.freeze(Object.keys);
87
+ Object.freeze(Object.values);
88
+ Object.freeze(Object.entries);
89
+ // Block Reflect API if available
90
+ if (typeof Reflect !== "undefined") {
91
+ Object.freeze(Reflect);
92
+ }
93
+ }
94
+ /**
95
+ * Create a Proxy handler that blocks dangerous property access
96
+ * Prevents constructor.constructor and __proto__ escapes
97
+ */
98
+ function createConstructorBlockingProxy(target) {
99
+ return new Proxy(target, {
100
+ get(obj, prop, receiver) {
101
+ // Block constructor property
102
+ if (prop === "constructor" ||
103
+ prop === "__proto__" ||
104
+ prop === "__constructor") {
105
+ throw new Error(`Access to property '${String(prop)}' is forbidden`);
106
+ }
107
+ // Block dangerous reflection methods
108
+ if (prop === "getPrototypeOf" ||
109
+ prop === "setPrototypeOf" ||
110
+ prop === "getOwnPropertyDescriptor" ||
111
+ prop === "getOwnPropertyNames" ||
112
+ prop === "getOwnPropertySymbols") {
113
+ throw new Error(`Access to reflection method '${String(prop)}' is forbidden`);
114
+ }
115
+ return Reflect.get(obj, prop, receiver);
116
+ },
117
+ set(obj, prop, value) {
118
+ if (prop === "constructor" || prop === "__proto__") {
119
+ throw new Error(`Cannot assign to property '${String(prop)}'`);
120
+ }
121
+ return false; // Reject all writes
122
+ },
123
+ has(obj, prop) {
124
+ if (prop === "constructor" || prop === "__proto__") {
125
+ return false;
126
+ }
127
+ return Reflect.has(obj, prop);
128
+ },
129
+ ownKeys(obj) {
130
+ return Reflect.ownKeys(obj).filter((key) => key !== "constructor" && key !== "__proto__");
131
+ },
132
+ getOwnPropertyDescriptor(obj, prop) {
133
+ if (prop === "constructor" || prop === "__proto__") {
134
+ return undefined;
135
+ }
136
+ return Reflect.getOwnPropertyDescriptor(obj, prop);
137
+ }
138
+ });
139
+ }
140
+ export function createSandboxScope(capabilities, statsCollector, promiseTracker, seed) {
141
+ const deterministicGlobals = createDeterministicGlobals(seed);
142
+ const sandbox = Object.create(null, {
143
+ // Safe console (captured, no actual I/O)
144
+ console: {
145
+ value: createCapabilityMembrane({
146
+ log: (..._args) => {
147
+ // no-op: prevent information leakage
148
+ },
149
+ error: (..._args) => {
150
+ // no-op
151
+ },
152
+ warn: (..._args) => {
153
+ // no-op
154
+ },
155
+ info: (..._args) => {
156
+ // no-op
157
+ },
158
+ debug: (..._args) => {
159
+ // no-op
160
+ }
161
+ }, "console", capabilities.console),
162
+ writable: false,
163
+ enumerable: true
164
+ },
165
+ // Deterministic date
166
+ Date: {
167
+ value: createCapabilityMembrane(deterministicGlobals.Date, "date", capabilities.date),
168
+ writable: false,
169
+ enumerable: true
170
+ },
171
+ // Safe Math (no random)
172
+ Math: {
173
+ value: createCapabilityMembrane(deterministicGlobals.Math, "math", capabilities.math),
174
+ writable: false,
175
+ enumerable: true
176
+ },
177
+ // Safe JSON
178
+ JSON: {
179
+ value: createCapabilityMembrane(deterministicGlobals.JSON, "json", capabilities.json),
180
+ writable: false,
181
+ enumerable: true
182
+ },
183
+ // Promise with tracking
184
+ Promise: {
185
+ value: createPromiseInterceptor(promiseTracker),
186
+ writable: false,
187
+ enumerable: true
188
+ },
189
+ // Safe undefined (can't be shadowed)
190
+ undefined: {
191
+ value: undefined,
192
+ writable: false,
193
+ enumerable: true
194
+ },
195
+ // Stats collector hook
196
+ __STATS__: {
197
+ value: statsCollector,
198
+ writable: false,
199
+ enumerable: false
200
+ },
201
+ // Deterministic seed function (if enabled)
202
+ __SEED__: {
203
+ value: deterministicGlobals.Math_random,
204
+ writable: false,
205
+ enumerable: false
206
+ },
207
+ // Block reflection APIs
208
+ Object: {
209
+ value: createConstructorBlockingProxy(Object),
210
+ writable: false,
211
+ enumerable: true
212
+ },
213
+ // Remove Reflect if available
214
+ Reflect: {
215
+ value: createConstructorBlockingProxy(Reflect || {}),
216
+ writable: false,
217
+ enumerable: false
218
+ }
219
+ });
220
+ // Lock down the sandbox object itself
221
+ return Object.freeze(sandbox);
222
+ }
223
+ /**
224
+ * Run code in a strict, isolated VM context with full tracking
225
+ */
226
+ export async function runInSandbox(code, options = {}) {
227
+ const stats = new StatsCollector();
228
+ stats.start();
229
+ try {
230
+ // Step 1: Freeze intrinsics FIRST, before creating context
231
+ freezeIntrinsics();
232
+ const capabilities = createCapabilityGrant(options.capabilities);
233
+ const promiseTracker = new PromiseTracker();
234
+ // Step 2: Build sandbox scope with capabilities and tracking
235
+ const sandbox = createSandboxScope(capabilities, stats, promiseTracker, options.seed);
236
+ // Step 3: Create VM context with strict settings
237
+ const context = vm.createContext(sandbox, {
238
+ name: "node-sandbox",
239
+ codeGeneration: {
240
+ strings: false, // No eval, Function constructor
241
+ wasm: false // No WebAssembly
242
+ }
243
+ });
244
+ // Step 4: Wrap user code in strict mode
245
+ const wrapped = `
246
+ "use strict";
247
+ (async () => {
248
+ return (${code});
249
+ })();
250
+ `;
251
+ // Step 5: Compile and execute
252
+ const script = new vm.Script(wrapped, {
253
+ filename: "sandboxed.js",
254
+ lineOffset: 0,
255
+ columnOffset: 0
256
+ });
257
+ // Extra safety timeout (main limit is in main thread)
258
+ const result = await script.runInContext(context, {
259
+ timeout: 10000, // 10 second internal timeout
260
+ displayErrors: true,
261
+ breakOnSigint: true
262
+ });
263
+ // Wait for all promises to settle
264
+ await promiseTracker.waitForAll(5000);
265
+ stats.markCompleted();
266
+ return { result, stats };
267
+ }
268
+ catch (err) {
269
+ stats.recordError(err instanceof Error ? err.message : String(err));
270
+ throw err;
271
+ }
272
+ finally {
273
+ stats.updateMemory();
274
+ }
275
+ }
276
+ //# sourceMappingURL=vm-runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vm-runtime.js","sourceRoot":"","sources":["../src/vm-runtime.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Worker thread pool for reusing workers
3
+ * Dramatically reduces memory and spawn overhead
4
+ */
5
+ import { Worker } from "node:worker_threads";
6
+ export interface PooledWorker {
7
+ worker: Worker;
8
+ busy: boolean;
9
+ lastUsed: number;
10
+ }
11
+ export interface PoolConfig {
12
+ minWorkers: number;
13
+ maxWorkers: number;
14
+ idleTimeout: number;
15
+ memoryMb: number;
16
+ }
17
+ export declare class WorkerPool {
18
+ private workers;
19
+ private waitQueue;
20
+ private config;
21
+ constructor(config: PoolConfig);
22
+ private createPooledWorker;
23
+ /**
24
+ * Get an available worker from the pool
25
+ */
26
+ acquire(): Promise<Worker>;
27
+ /**
28
+ * Release worker back to pool
29
+ */
30
+ release(worker: Worker): void;
31
+ /**
32
+ * Clean up idle workers
33
+ */
34
+ cleanup(): void;
35
+ /**
36
+ * Terminate all workers
37
+ */
38
+ destroy(): Promise<void>;
39
+ /**
40
+ * Get pool stats
41
+ */
42
+ stats(): PoolStats;
43
+ }
44
+ export interface PoolStats {
45
+ totalWorkers: number;
46
+ busyWorkers: number;
47
+ idleWorkers: number;
48
+ waitingRequests: number;
49
+ }
50
+ /**
51
+ * Default pool configuration
52
+ */
53
+ export declare const DEFAULT_POOL_CONFIG: PoolConfig;
54
+ /**
55
+ * High-concurrency configuration
56
+ */
57
+ export declare const HIGH_CONCURRENCY_CONFIG: PoolConfig;
58
+ /**
59
+ * Low-resource configuration
60
+ */
61
+ export declare const LOW_RESOURCE_CONFIG: PoolConfig;
62
+ //# sourceMappingURL=worker-pool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker-pool.d.ts","sourceRoot":"","sources":["../src/worker-pool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAO7C,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,OAAO,CAAsB;IACrC,OAAO,CAAC,SAAS,CAGT;IACR,OAAO,CAAC,MAAM,CAAa;gBAEf,MAAM,EAAE,UAAU;IAQ9B,OAAO,CAAC,kBAAkB;IAY1B;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC;IA4BhC;;OAEG;IACH,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAgB7B;;OAEG;IACH,OAAO,IAAI,IAAI;IAsBf;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ9B;;OAEG;IACH,KAAK,IAAI,SAAS;CAQnB;AAED,MAAM,WAAW,SAAS;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,eAAO,MAAM,mBAAmB,EAAE,UAKjC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,uBAAuB,EAAE,UAKrC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,mBAAmB,EAAE,UAKjC,CAAC"}