@nodetool-ai/sandbox-runtime 0.0.0-stage → 0.8.9-bootstrap.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 (218) hide show
  1. package/README.md +24 -2
  2. package/dist/.nodetool-build-stamp +1 -0
  3. package/dist/host-access-gate.d.ts +24 -0
  4. package/dist/host-access-gate.d.ts.map +1 -0
  5. package/dist/host-access-gate.js +31 -0
  6. package/dist/host-access-gate.js.map +1 -0
  7. package/dist/index.d.ts +32 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +318 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/js-sandbox-worker/engine.d.ts +4 -0
  12. package/dist/js-sandbox-worker/engine.d.ts.map +1 -0
  13. package/dist/js-sandbox-worker/engine.js +82 -0
  14. package/dist/js-sandbox-worker/engine.js.map +1 -0
  15. package/dist/js-sandbox-worker/host.d.ts +136 -0
  16. package/dist/js-sandbox-worker/host.d.ts.map +1 -0
  17. package/dist/js-sandbox-worker/host.js +482 -0
  18. package/dist/js-sandbox-worker/host.js.map +1 -0
  19. package/dist/js-sandbox-worker/interpreter.d.ts +276 -0
  20. package/dist/js-sandbox-worker/interpreter.d.ts.map +1 -0
  21. package/dist/js-sandbox-worker/interpreter.js +1318 -0
  22. package/dist/js-sandbox-worker/interpreter.js.map +1 -0
  23. package/dist/js-sandbox-worker/protocol.d.ts +168 -0
  24. package/dist/js-sandbox-worker/protocol.d.ts.map +1 -0
  25. package/dist/js-sandbox-worker/protocol.js +217 -0
  26. package/dist/js-sandbox-worker/protocol.js.map +1 -0
  27. package/dist/js-sandbox-worker/worker-entry.d.ts +26 -0
  28. package/dist/js-sandbox-worker/worker-entry.d.ts.map +1 -0
  29. package/dist/js-sandbox-worker/worker-entry.js +308 -0
  30. package/dist/js-sandbox-worker/worker-entry.js.map +1 -0
  31. package/dist/limits.d.ts +77 -0
  32. package/dist/limits.d.ts.map +1 -0
  33. package/dist/limits.js +56 -0
  34. package/dist/limits.js.map +1 -0
  35. package/dist/sandbox-bootstrap-modules.d.ts +54 -0
  36. package/dist/sandbox-bootstrap-modules.d.ts.map +1 -0
  37. package/dist/sandbox-bootstrap-modules.js +104 -0
  38. package/dist/sandbox-bootstrap-modules.js.map +1 -0
  39. package/dist/sandbox-bytes.d.ts +43 -0
  40. package/dist/sandbox-bytes.d.ts.map +1 -0
  41. package/dist/sandbox-bytes.js +61 -0
  42. package/dist/sandbox-bytes.js.map +1 -0
  43. package/dist/sandbox-canvas-api.d.ts +30 -0
  44. package/dist/sandbox-canvas-api.d.ts.map +1 -0
  45. package/dist/sandbox-canvas-api.js +81 -0
  46. package/dist/sandbox-canvas-api.js.map +1 -0
  47. package/dist/sandbox-constants.d.ts +5 -0
  48. package/dist/sandbox-constants.d.ts.map +1 -0
  49. package/dist/sandbox-constants.js +13 -0
  50. package/dist/sandbox-constants.js.map +1 -0
  51. package/dist/sandbox-json-transport.d.ts +107 -0
  52. package/dist/sandbox-json-transport.d.ts.map +1 -0
  53. package/dist/sandbox-json-transport.js +324 -0
  54. package/dist/sandbox-json-transport.js.map +1 -0
  55. package/dist/timeline-capture.d.ts +21 -0
  56. package/dist/timeline-capture.d.ts.map +1 -0
  57. package/dist/timeline-capture.js +564 -0
  58. package/dist/timeline-capture.js.map +1 -0
  59. package/dist/utils/type-guards.d.ts +26 -0
  60. package/dist/utils/type-guards.d.ts.map +1 -0
  61. package/dist/utils/type-guards.js +44 -0
  62. package/dist/utils/type-guards.js.map +1 -0
  63. package/package.json +138 -4
  64. package/vendor/README.md +17 -0
  65. package/vendor/quickjs/LICENSE +21 -0
  66. package/vendor/quickjs/PROVENANCE.json +8 -0
  67. package/vendor/quickjs/adapter/fetch.d.ts +56 -0
  68. package/vendor/quickjs/adapter/fetch.js +140 -0
  69. package/vendor/quickjs/createTimeInterval.d.ts +9 -0
  70. package/vendor/quickjs/createTimeInterval.js +22 -0
  71. package/vendor/quickjs/createVirtualFileSystem.d.ts +13 -0
  72. package/vendor/quickjs/createVirtualFileSystem.js +191 -0
  73. package/vendor/quickjs/index.d.ts +77 -0
  74. package/vendor/quickjs/index.js +77 -0
  75. package/vendor/quickjs/loadAsyncQuickJs.d.ts +12 -0
  76. package/vendor/quickjs/loadAsyncQuickJs.js +66 -0
  77. package/vendor/quickjs/loadQuickJs.d.ts +12 -0
  78. package/vendor/quickjs/loadQuickJs.js +73 -0
  79. package/vendor/quickjs/modules/assert.d.ts +2 -0
  80. package/vendor/quickjs/modules/assert.js +47 -0
  81. package/vendor/quickjs/modules/buffer.d.ts +2 -0
  82. package/vendor/quickjs/modules/buffer.js +106 -0
  83. package/vendor/quickjs/modules/build/test-lib.js +2 -0
  84. package/vendor/quickjs/modules/events.d.ts +2 -0
  85. package/vendor/quickjs/modules/events.js +4 -0
  86. package/vendor/quickjs/modules/fs.d.ts +2 -0
  87. package/vendor/quickjs/modules/fs.js +76 -0
  88. package/vendor/quickjs/modules/fs_promises.d.ts +2 -0
  89. package/vendor/quickjs/modules/fs_promises.js +328 -0
  90. package/vendor/quickjs/modules/module.d.ts +2 -0
  91. package/vendor/quickjs/modules/module.js +33 -0
  92. package/vendor/quickjs/modules/nodeCompatibility/headers.d.ts +2 -0
  93. package/vendor/quickjs/modules/nodeCompatibility/headers.js +58 -0
  94. package/vendor/quickjs/modules/nodeCompatibility/request.d.ts +2 -0
  95. package/vendor/quickjs/modules/nodeCompatibility/request.js +5 -0
  96. package/vendor/quickjs/modules/nodeCompatibility/response.d.ts +2 -0
  97. package/vendor/quickjs/modules/nodeCompatibility/response.js +5 -0
  98. package/vendor/quickjs/modules/path.d.ts +2 -0
  99. package/vendor/quickjs/modules/path.js +504 -0
  100. package/vendor/quickjs/modules/process.d.ts +2 -0
  101. package/vendor/quickjs/modules/process.js +309 -0
  102. package/vendor/quickjs/modules/punycode.d.ts +2 -0
  103. package/vendor/quickjs/modules/punycode.js +443 -0
  104. package/vendor/quickjs/modules/querystring.d.ts +2 -0
  105. package/vendor/quickjs/modules/querystring.js +15 -0
  106. package/vendor/quickjs/modules/string_decoder.d.ts +2 -0
  107. package/vendor/quickjs/modules/string_decoder.js +223 -0
  108. package/vendor/quickjs/modules/timers.d.ts +2 -0
  109. package/vendor/quickjs/modules/timers.js +10 -0
  110. package/vendor/quickjs/modules/timers_promises.d.ts +2 -0
  111. package/vendor/quickjs/modules/timers_promises.js +40 -0
  112. package/vendor/quickjs/modules/url.d.ts +2 -0
  113. package/vendor/quickjs/modules/url.js +104 -0
  114. package/vendor/quickjs/modules/util.d.ts +2 -0
  115. package/vendor/quickjs/modules/util.js +233 -0
  116. package/vendor/quickjs/package.json +3 -0
  117. package/vendor/quickjs/sandbox/asyncVersion/createAsyncEvalCodeFunction.d.ts +4 -0
  118. package/vendor/quickjs/sandbox/asyncVersion/createAsyncEvalCodeFunction.js +76 -0
  119. package/vendor/quickjs/sandbox/asyncVersion/createAsyncValidateCodeFunction.d.ts +3 -0
  120. package/vendor/quickjs/sandbox/asyncVersion/createAsyncValidateCodeFunction.js +22 -0
  121. package/vendor/quickjs/sandbox/asyncVersion/executeAsyncSandboxFunction.d.ts +12 -0
  122. package/vendor/quickjs/sandbox/asyncVersion/executeAsyncSandboxFunction.js +9 -0
  123. package/vendor/quickjs/sandbox/asyncVersion/getAsyncModuleLoader.d.ts +4 -0
  124. package/vendor/quickjs/sandbox/asyncVersion/getAsyncModuleLoader.js +30 -0
  125. package/vendor/quickjs/sandbox/asyncVersion/modulePathNormalizerAsync.d.ts +2 -0
  126. package/vendor/quickjs/sandbox/asyncVersion/modulePathNormalizerAsync.js +12 -0
  127. package/vendor/quickjs/sandbox/asyncVersion/prepareAsyncNodeCompatibility.d.ts +3 -0
  128. package/vendor/quickjs/sandbox/asyncVersion/prepareAsyncNodeCompatibility.js +11 -0
  129. package/vendor/quickjs/sandbox/asyncVersion/prepareAsyncSandbox.d.ts +4 -0
  130. package/vendor/quickjs/sandbox/asyncVersion/prepareAsyncSandbox.js +10 -0
  131. package/vendor/quickjs/sandbox/expose/expose.d.ts +3 -0
  132. package/vendor/quickjs/sandbox/expose/expose.js +155 -0
  133. package/vendor/quickjs/sandbox/expose/isES2015Class.d.ts +1 -0
  134. package/vendor/quickjs/sandbox/expose/isES2015Class.js +4 -0
  135. package/vendor/quickjs/sandbox/expose/isObject.d.ts +1 -0
  136. package/vendor/quickjs/sandbox/expose/isObject.js +4 -0
  137. package/vendor/quickjs/sandbox/expose/pendingHostPromises.d.ts +6 -0
  138. package/vendor/quickjs/sandbox/expose/pendingHostPromises.js +40 -0
  139. package/vendor/quickjs/sandbox/getMaxIntervalAmount.d.ts +8 -0
  140. package/vendor/quickjs/sandbox/getMaxIntervalAmount.js +12 -0
  141. package/vendor/quickjs/sandbox/getMaxTimeoutAmount.d.ts +8 -0
  142. package/vendor/quickjs/sandbox/getMaxTimeoutAmount.js +12 -0
  143. package/vendor/quickjs/sandbox/handleEvalError.d.ts +2 -0
  144. package/vendor/quickjs/sandbox/handleEvalError.js +21 -0
  145. package/vendor/quickjs/sandbox/handleToNative/handleToNative.d.ts +9 -0
  146. package/vendor/quickjs/sandbox/handleToNative/handleToNative.js +153 -0
  147. package/vendor/quickjs/sandbox/handleToNative/serializer/index.d.ts +10 -0
  148. package/vendor/quickjs/sandbox/handleToNative/serializer/index.js +36 -0
  149. package/vendor/quickjs/sandbox/handleToNative/serializer/serializeArrayBuffer.d.ts +2 -0
  150. package/vendor/quickjs/sandbox/handleToNative/serializer/serializeArrayBuffer.js +4 -0
  151. package/vendor/quickjs/sandbox/handleToNative/serializer/serializeBuffer.d.ts +2 -0
  152. package/vendor/quickjs/sandbox/handleToNative/serializer/serializeBuffer.js +16 -0
  153. package/vendor/quickjs/sandbox/handleToNative/serializer/serializeDate.d.ts +2 -0
  154. package/vendor/quickjs/sandbox/handleToNative/serializer/serializeDate.js +16 -0
  155. package/vendor/quickjs/sandbox/handleToNative/serializer/serializeError.d.ts +2 -0
  156. package/vendor/quickjs/sandbox/handleToNative/serializer/serializeError.js +18 -0
  157. package/vendor/quickjs/sandbox/handleToNative/serializer/serializeHeaders.d.ts +2 -0
  158. package/vendor/quickjs/sandbox/handleToNative/serializer/serializeHeaders.js +17 -0
  159. package/vendor/quickjs/sandbox/handleToNative/serializer/serializeMap.d.ts +2 -0
  160. package/vendor/quickjs/sandbox/handleToNative/serializer/serializeMap.js +18 -0
  161. package/vendor/quickjs/sandbox/handleToNative/serializer/serializeSet.d.ts +2 -0
  162. package/vendor/quickjs/sandbox/handleToNative/serializer/serializeSet.js +16 -0
  163. package/vendor/quickjs/sandbox/handleToNative/serializer/serializeURLSearchParams.d.ts +2 -0
  164. package/vendor/quickjs/sandbox/handleToNative/serializer/serializeURLSearchParams.js +17 -0
  165. package/vendor/quickjs/sandbox/handleToNative/serializer/serializeUrl.d.ts +2 -0
  166. package/vendor/quickjs/sandbox/handleToNative/serializer/serializeUrl.js +17 -0
  167. package/vendor/quickjs/sandbox/helper.d.ts +2 -0
  168. package/vendor/quickjs/sandbox/helper.js +14 -0
  169. package/vendor/quickjs/sandbox/provide/provideConsole.d.ts +6 -0
  170. package/vendor/quickjs/sandbox/provide/provideConsole.js +53 -0
  171. package/vendor/quickjs/sandbox/provide/provideEnv.d.ts +3 -0
  172. package/vendor/quickjs/sandbox/provide/provideEnv.js +10 -0
  173. package/vendor/quickjs/sandbox/provide/provideFs.d.ts +4 -0
  174. package/vendor/quickjs/sandbox/provide/provideFs.js +159 -0
  175. package/vendor/quickjs/sandbox/provide/provideHttp.d.ts +9 -0
  176. package/vendor/quickjs/sandbox/provide/provideHttp.js +42 -0
  177. package/vendor/quickjs/sandbox/provide/provideTimingFunctions.d.ts +7 -0
  178. package/vendor/quickjs/sandbox/provide/provideTimingFunctions.js +119 -0
  179. package/vendor/quickjs/sandbox/setupFileSystem.d.ts +3 -0
  180. package/vendor/quickjs/sandbox/setupFileSystem.js +13 -0
  181. package/vendor/quickjs/sandbox/syncVersion/createEvalCodeFunction.d.ts +4 -0
  182. package/vendor/quickjs/sandbox/syncVersion/createEvalCodeFunction.js +76 -0
  183. package/vendor/quickjs/sandbox/syncVersion/createValidateCodeFunction.d.ts +3 -0
  184. package/vendor/quickjs/sandbox/syncVersion/createValidateCodeFunction.js +22 -0
  185. package/vendor/quickjs/sandbox/syncVersion/executeSandboxFunction.d.ts +12 -0
  186. package/vendor/quickjs/sandbox/syncVersion/executeSandboxFunction.js +9 -0
  187. package/vendor/quickjs/sandbox/syncVersion/getModuleLoader.d.ts +4 -0
  188. package/vendor/quickjs/sandbox/syncVersion/getModuleLoader.js +30 -0
  189. package/vendor/quickjs/sandbox/syncVersion/modulePathNormalizer.d.ts +2 -0
  190. package/vendor/quickjs/sandbox/syncVersion/modulePathNormalizer.js +12 -0
  191. package/vendor/quickjs/sandbox/syncVersion/prepareNodeCompatibility.d.ts +3 -0
  192. package/vendor/quickjs/sandbox/syncVersion/prepareNodeCompatibility.js +11 -0
  193. package/vendor/quickjs/sandbox/syncVersion/prepareSandbox.d.ts +4 -0
  194. package/vendor/quickjs/sandbox/syncVersion/prepareSandbox.js +10 -0
  195. package/vendor/quickjs/types/CodeFunctionInput.d.ts +12 -0
  196. package/vendor/quickjs/types/CodeFunctionInput.js +1 -0
  197. package/vendor/quickjs/types/ErrorResponse.d.ts +9 -0
  198. package/vendor/quickjs/types/ErrorResponse.js +1 -0
  199. package/vendor/quickjs/types/LoadQuickJsOptions.d.ts +3 -0
  200. package/vendor/quickjs/types/LoadQuickJsOptions.js +1 -0
  201. package/vendor/quickjs/types/OkResponse.d.ts +4 -0
  202. package/vendor/quickjs/types/OkResponse.js +1 -0
  203. package/vendor/quickjs/types/OkResponseCheck.d.ts +3 -0
  204. package/vendor/quickjs/types/OkResponseCheck.js +1 -0
  205. package/vendor/quickjs/types/Prettify.d.ts +3 -0
  206. package/vendor/quickjs/types/Prettify.js +1 -0
  207. package/vendor/quickjs/types/RuntimeOptions.d.ts +87 -0
  208. package/vendor/quickjs/types/RuntimeOptions.js +1 -0
  209. package/vendor/quickjs/types/SandboxEvalCode.d.ts +5 -0
  210. package/vendor/quickjs/types/SandboxEvalCode.js +1 -0
  211. package/vendor/quickjs/types/SandboxFunction.d.ts +16 -0
  212. package/vendor/quickjs/types/SandboxFunction.js +1 -0
  213. package/vendor/quickjs/types/SandboxOptions.d.ts +152 -0
  214. package/vendor/quickjs/types/SandboxOptions.js +1 -0
  215. package/vendor/quickjs/types/SandboxValidateCode.d.ts +9 -0
  216. package/vendor/quickjs/types/SandboxValidateCode.js +1 -0
  217. package/vendor/quickjs/types/Serializer.d.ts +2 -0
  218. package/vendor/quickjs/types/Serializer.js +1 -0
@@ -0,0 +1,76 @@
1
+ import { createTimeInterval } from '../../createTimeInterval.js';
2
+ import { rejectAndFlushPendingHostPromises } from '../expose/pendingHostPromises.js';
3
+ import { getMaxIntervalAmount } from '../getMaxIntervalAmount.js';
4
+ import { getMaxTimeoutAmount } from '../getMaxTimeoutAmount.js';
5
+ import { handleEvalError } from '../handleEvalError.js';
6
+ import { handleToNative } from '../handleToNative/handleToNative.js';
7
+ import { provideTimingFunctions } from '../provide/provideTimingFunctions.js';
8
+ export const createAsyncEvalCodeFunction = (input, scope) => {
9
+ const { ctx, sandboxOptions, transpileFile } = input;
10
+ return async (code, filename = '/src/index.js', evalOptions) => {
11
+ const eventLoopinterval = createTimeInterval(() => ctx.runtime.executePendingJobs(), 0);
12
+ const timeoutMs = sandboxOptions.executionTimeout ?? 0;
13
+ let timeoutId;
14
+ let nativePromise;
15
+ let timedOut = false;
16
+ const { dispose: disposeTimer } = provideTimingFunctions(ctx, {
17
+ maxTimeoutCount: getMaxTimeoutAmount(sandboxOptions),
18
+ maxIntervalCount: getMaxIntervalAmount(sandboxOptions),
19
+ });
20
+ const disposeStep = () => {
21
+ if (timeoutId) {
22
+ clearTimeout(timeoutId);
23
+ }
24
+ eventLoopinterval?.clear();
25
+ disposeTimer();
26
+ };
27
+ try {
28
+ const jsCode = transpileFile(code);
29
+ const evalResult = await ctx.evalCodeAsync(jsCode, filename, {
30
+ strict: true,
31
+ strip: false,
32
+ backtraceBarrier: true,
33
+ ...evalOptions,
34
+ type: 'module',
35
+ });
36
+ const handle = scope.manage(ctx.unwrapResult(evalResult));
37
+ const native = handleToNative(ctx, handle, scope);
38
+ nativePromise = (async () => {
39
+ const res = await native;
40
+ return res.default;
41
+ })();
42
+ const result = await Promise.race([
43
+ nativePromise,
44
+ new Promise((_resolve, reject) => {
45
+ if (timeoutMs > 0) {
46
+ timeoutId = setTimeout(() => {
47
+ timedOut = true;
48
+ const err = new Error('The script execution has exceeded the maximum allowed time limit.');
49
+ err.name = 'ExecutionTimeout';
50
+ reject(err);
51
+ }, timeoutMs);
52
+ }
53
+ }),
54
+ ]);
55
+ return { ok: true, data: result };
56
+ }
57
+ catch (err) {
58
+ return handleEvalError(err);
59
+ }
60
+ finally {
61
+ if (timedOut && nativePromise) {
62
+ // Reject unresolved host-injected promises to avoid leaving QuickJS promises
63
+ // pending while disposing the runtime after timeout.
64
+ await rejectAndFlushPendingHostPromises(ctx);
65
+ // Force-fast interrupt handling and give pending guest jobs a short window to settle.
66
+ ctx.runtime.setInterruptHandler(() => true);
67
+ const cleanupWait = Math.min(Math.max(timeoutMs, 50), 1000);
68
+ await Promise.race([
69
+ nativePromise.catch(() => undefined),
70
+ new Promise(resolve => setTimeout(resolve, cleanupWait)),
71
+ ]);
72
+ }
73
+ disposeStep();
74
+ }
75
+ };
76
+ };
@@ -0,0 +1,3 @@
1
+ import type { CodeFunctionAsyncInput } from '../../types/CodeFunctionInput.js';
2
+ import type { SandboxValidateCode } from '../../types/SandboxValidateCode.js';
3
+ export declare const createAsyncValidateCodeFunction: (input: CodeFunctionAsyncInput) => SandboxValidateCode;
@@ -0,0 +1,22 @@
1
+ import { handleEvalError } from '../handleEvalError.js';
2
+ export const createAsyncValidateCodeFunction = (input) => {
3
+ const { ctx } = input;
4
+ return async (code, filename = '/src/index.js', evalOptions) => {
5
+ try {
6
+ ctx
7
+ .unwrapResult(await ctx.evalCodeAsync(code, filename, {
8
+ strict: true,
9
+ strip: true,
10
+ backtraceBarrier: true,
11
+ ...evalOptions,
12
+ type: 'module',
13
+ compileOnly: true,
14
+ }))
15
+ .dispose();
16
+ return { ok: true };
17
+ }
18
+ catch (err) {
19
+ return handleEvalError(err);
20
+ }
21
+ };
22
+ };
@@ -0,0 +1,12 @@
1
+ import type { IFs } from 'memfs';
2
+ import type { QuickJSAsyncContext, Scope } from 'quickjs-emscripten-core';
3
+ import type { AsyncSandboxFunction } from '../../types/SandboxFunction.js';
4
+ import type { SandboxAsyncOptions } from '../../types/SandboxOptions.js';
5
+ export declare const executeAsyncSandboxFunction: <T>(input: {
6
+ ctx: QuickJSAsyncContext;
7
+ fs: IFs;
8
+ scope: Scope;
9
+ sandboxOptions: SandboxAsyncOptions;
10
+ sandboxedFunction: AsyncSandboxFunction<T>;
11
+ transpileFile: (input: string) => string;
12
+ }) => Promise<T>;
@@ -0,0 +1,9 @@
1
+ import { createAsyncEvalCodeFunction } from './createAsyncEvalCodeFunction.js';
2
+ import { createAsyncValidateCodeFunction } from './createAsyncValidateCodeFunction.js';
3
+ export const executeAsyncSandboxFunction = async (input) => {
4
+ const { ctx, sandboxOptions, sandboxedFunction, fs, transpileFile } = input;
5
+ const opt = { ctx, sandboxOptions, transpileFile };
6
+ const evalCode = createAsyncEvalCodeFunction(opt, input.scope);
7
+ const validateCode = createAsyncValidateCodeFunction(opt);
8
+ return await sandboxedFunction({ ctx, evalCode, validateCode, mountedFs: fs });
9
+ };
@@ -0,0 +1,4 @@
1
+ import type { IFs } from 'memfs';
2
+ import type { JSModuleLoaderAsync } from 'quickjs-emscripten-core';
3
+ import type { RuntimeOptions } from '../../types/RuntimeOptions.js';
4
+ export declare const getAsyncModuleLoader: (fs: IFs, _runtimeOptions: RuntimeOptions) => JSModuleLoaderAsync;
@@ -0,0 +1,30 @@
1
+ import { join } from 'node:path';
2
+ export const getAsyncModuleLoader = (fs, _runtimeOptions) => {
3
+ const moduleLoader = (inputName, _context) => {
4
+ let name = inputName;
5
+ // if it does not exist
6
+ if (!fs.existsSync(name)) {
7
+ // try to add the .js extension
8
+ if (fs.existsSync(`${name}.js`)) {
9
+ name = `${name}.js`;
10
+ }
11
+ else {
12
+ return { error: new Error(`Module '${inputName}' not installed or available`) };
13
+ }
14
+ }
15
+ // if it is a folder, we need to use the index.js file
16
+ if (fs.lstatSync(name).isDirectory()) {
17
+ name = join(name, 'index.js');
18
+ if (!fs.existsSync(name)) {
19
+ return { error: new Error(`Module '${inputName}' not installed or available`) };
20
+ }
21
+ }
22
+ // workaround: as we can not provide the real import.meta.url functionality, we replace it dynamically with the current value string
23
+ const value = fs.readFileSync(name)?.toString().replaceAll('import.meta.url', `'file://${name}'`);
24
+ if (!value) {
25
+ return { error: new Error(`Module '${name}' not installed or available`) };
26
+ }
27
+ return { value };
28
+ };
29
+ return moduleLoader;
30
+ };
@@ -0,0 +1,2 @@
1
+ import type { JSModuleNormalizerAsync } from 'quickjs-emscripten-core';
2
+ export declare const modulePathNormalizerAsync: JSModuleNormalizerAsync;
@@ -0,0 +1,12 @@
1
+ import { join, resolve } from 'node:path';
2
+ export const modulePathNormalizerAsync = async (baseName, requestedName) => {
3
+ // relative import
4
+ if (requestedName.startsWith('.')) {
5
+ const parts = baseName.split('/');
6
+ parts.pop();
7
+ return resolve(`/${parts.join('/')}`, requestedName);
8
+ }
9
+ // module import
10
+ const moduleName = requestedName.replace('node:', '');
11
+ return join('/node_modules', moduleName);
12
+ };
@@ -0,0 +1,3 @@
1
+ import type { QuickJSAsyncContext } from 'quickjs-emscripten-core';
2
+ import type { SandboxAsyncOptions } from '../../types/SandboxOptions.js';
3
+ export declare const prepareAsyncNodeCompatibility: (vm: QuickJSAsyncContext, sandboxOptions: SandboxAsyncOptions) => Promise<void>;
@@ -0,0 +1,11 @@
1
+ export const prepareAsyncNodeCompatibility = async (vm, sandboxOptions) => {
2
+ vm.unwrapResult(await vm.evalCodeAsync(`
3
+ import 'node:buffer';
4
+ import 'node:util';
5
+ import 'node:url';
6
+ import '@node_compatibility/headers';
7
+ import '@node_compatibility/request';
8
+ import '@node_compatibility/response';
9
+ ${sandboxOptions.enableTestUtils ? "import 'test'" : ''}
10
+ `, undefined, { type: 'module' })).dispose();
11
+ };
@@ -0,0 +1,4 @@
1
+ import type { IFs } from 'memfs';
2
+ import type { QuickJSAsyncContext, Scope } from 'quickjs-emscripten-core';
3
+ import type { SandboxBaseOptions } from '../../types/SandboxOptions.js';
4
+ export declare const prepareAsyncSandbox: (ctx: QuickJSAsyncContext, scope: Scope, sandboxOptions: SandboxBaseOptions, fs: IFs) => void;
@@ -0,0 +1,10 @@
1
+ import { provideConsole } from '../provide/provideConsole.js';
2
+ import { provideEnv } from '../provide/provideEnv.js';
3
+ import { provideFs } from '../provide/provideFs.js';
4
+ import { provideHttp } from '../provide/provideHttp.js';
5
+ export const prepareAsyncSandbox = (ctx, scope, sandboxOptions, fs) => {
6
+ provideFs(ctx, scope, sandboxOptions, fs);
7
+ provideConsole(ctx, scope, sandboxOptions);
8
+ provideEnv(ctx, scope, sandboxOptions);
9
+ provideHttp(ctx, scope, sandboxOptions, { fs: sandboxOptions.allowFs ? fs : undefined });
10
+ };
@@ -0,0 +1,3 @@
1
+ import { type QuickJSAsyncContext, type QuickJSContext, type QuickJSHandle, Scope } from 'quickjs-emscripten-core';
2
+ export declare const getHandle: (scope: Scope, ctx: QuickJSContext | QuickJSAsyncContext, name: string, input: unknown) => QuickJSHandle;
3
+ export declare const expose: (ctx: QuickJSContext | QuickJSAsyncContext, _parentScope: Scope, input: Record<string, unknown>, parent?: QuickJSHandle) => void;
@@ -0,0 +1,155 @@
1
+ import { Scope } from 'quickjs-emscripten-core';
2
+ import { HEADERS_MARKER } from '../../adapter/fetch.js';
3
+ import { handleToNative } from '../handleToNative/handleToNative.js';
4
+ import { isES2015Class } from './isES2015Class.js';
5
+ import { isObject } from './isObject.js';
6
+ import { registerPendingHostPromise, unregisterPendingHostPromise } from './pendingHostPromises.js';
7
+ export const getHandle = (scope, ctx, name, input) => {
8
+ // null
9
+ if (input === null) {
10
+ return ctx.null;
11
+ }
12
+ // null
13
+ if (input === undefined) {
14
+ return ctx.undefined;
15
+ }
16
+ // Map serialized fetch headers from host to a native Headers instance in guest.
17
+ if (input && typeof input === 'object' && HEADERS_MARKER in input && '_headers' in input) {
18
+ const headersValue = input._headers;
19
+ const headersJson = JSON.stringify(headersValue);
20
+ return ctx.unwrapResult(ctx.evalCode(`new Headers(${headersJson})`));
21
+ }
22
+ // Array Buffer
23
+ if (input instanceof ArrayBuffer) {
24
+ return ctx.newArrayBuffer(input);
25
+ }
26
+ // Promise
27
+ if (input instanceof Promise) {
28
+ const promise = ctx.newPromise();
29
+ registerPendingHostPromise(ctx, promise);
30
+ promise.settled.finally(() => {
31
+ unregisterPendingHostPromise(ctx, promise);
32
+ if (ctx.alive) {
33
+ ctx.runtime.executePendingJobs();
34
+ }
35
+ });
36
+ input.then(r => {
37
+ if (!ctx.alive || !promise.alive) {
38
+ return;
39
+ }
40
+ const handle = getHandle(scope, ctx, '', r);
41
+ promise.resolve(handle);
42
+ handle.dispose();
43
+ }, e => {
44
+ if (!ctx.alive || !promise.alive) {
45
+ return;
46
+ }
47
+ const handle = getHandle(scope, ctx, '', e);
48
+ promise.reject(handle);
49
+ handle.dispose();
50
+ });
51
+ return promise.handle;
52
+ }
53
+ switch (typeof input) {
54
+ case 'number':
55
+ return ctx.newNumber(input);
56
+ case 'string':
57
+ return ctx.newString(input);
58
+ case 'boolean':
59
+ return input ? ctx.true : ctx.false;
60
+ case 'bigint':
61
+ return ctx.newBigInt(input);
62
+ case 'symbol':
63
+ return ctx.newSymbolFor(input);
64
+ case 'function':
65
+ return ctx.newFunction(name, function (...args) {
66
+ const s = new Scope();
67
+ const that = handleToNative(ctx, this, s);
68
+ if (this) {
69
+ this.dispose();
70
+ }
71
+ if (isES2015Class(input) && isObject(that)) {
72
+ const result = new input(...args);
73
+ for (const [key, value] of Object.entries(result)) {
74
+ ctx.setProp(this, key, getHandle(s, ctx, key, value));
75
+ }
76
+ s.dispose();
77
+ return this;
78
+ }
79
+ const rawParam = [];
80
+ for (const param of args) {
81
+ const p = s.manage(param);
82
+ rawParam.push(handleToNative(ctx, p, s));
83
+ }
84
+ try {
85
+ const handle = getHandle(s, ctx, '', input.apply(that, rawParam));
86
+ return handle;
87
+ }
88
+ finally {
89
+ s.dispose();
90
+ }
91
+ });
92
+ }
93
+ if (typeof input === 'object' || input === null) {
94
+ if (input instanceof Date) {
95
+ const x = ctx.evalCode(`new Date(${input.getTime()})`);
96
+ return x.unwrap();
97
+ }
98
+ const prototype = Object.getPrototypeOf(input);
99
+ const prototypeHandle = prototype && prototype !== Object.prototype && prototype !== Array.prototype
100
+ ? getHandle(scope, ctx, '', prototype)
101
+ : undefined;
102
+ const handle = Array.isArray(input) ? ctx.newArray() : ctx.newObject(prototypeHandle);
103
+ setProperties(ctx, scope, input, handle);
104
+ prototypeHandle?.dispose();
105
+ return handle;
106
+ }
107
+ throw new Error(`unsupported data type in ${name} ${typeof input}`);
108
+ };
109
+ const setProperties = (ctx, scope,
110
+ // biome-ignore lint/complexity/noBannedTypes: ok here
111
+ input, parent) => {
112
+ const descs = ctx.newObject();
113
+ const setEntry = (key, desc) => {
114
+ const keyHandle = getHandle(scope, ctx, '', key);
115
+ const valueHandle = typeof desc.value === 'undefined' ? undefined : getHandle(scope, ctx, '', desc.value);
116
+ const getterHandle = typeof desc.get === 'undefined' ? undefined : getHandle(scope, ctx, '', desc.get);
117
+ const setterHandle = typeof desc.set === 'undefined' ? undefined : getHandle(scope, ctx, '', desc.set);
118
+ const descObj = ctx.newObject();
119
+ for (const [k, v] of Object.entries(desc)) {
120
+ const v2 = k === 'value' ? valueHandle : k === 'get' ? getterHandle : k === 'set' ? setterHandle : v ? ctx.true : ctx.false;
121
+ if (v2) {
122
+ ctx.setProp(descObj, k, v2);
123
+ }
124
+ }
125
+ ctx.setProp(descs, keyHandle, descObj);
126
+ keyHandle.dispose();
127
+ valueHandle?.dispose();
128
+ getterHandle?.dispose();
129
+ setterHandle?.dispose();
130
+ descObj.dispose();
131
+ };
132
+ const desc = Object.getOwnPropertyDescriptors(input);
133
+ for (const [k, v] of Object.entries(desc)) {
134
+ setEntry(k, v);
135
+ }
136
+ for (const k of Object.getOwnPropertySymbols(desc)) {
137
+ setEntry(k, desc[k]);
138
+ }
139
+ const fnHandle = ctx.unwrapResult(ctx.evalCode('Object.defineProperties'));
140
+ const callHandle = ctx.unwrapResult(ctx.callFunction(fnHandle, ctx.undefined, parent, descs));
141
+ callHandle.dispose();
142
+ fnHandle.dispose();
143
+ descs.dispose();
144
+ };
145
+ const addProp = (scope, ctx, parent, name, value) => {
146
+ const handle = scope.manage(getHandle(scope, ctx, name, value));
147
+ ctx.setProp(parent, name, handle);
148
+ };
149
+ export const expose = (ctx, _parentScope, input, parent) => {
150
+ const scope = new Scope();
151
+ for (const [key, value] of Object.entries(input)) {
152
+ addProp(scope, ctx, parent ?? ctx.global, key, value);
153
+ }
154
+ scope.dispose();
155
+ };
@@ -0,0 +1 @@
1
+ export declare function isES2015Class(cls: any): cls is new (...args: any[]) => any;
@@ -0,0 +1,4 @@
1
+ const classRegex = new RegExp(/^class\s/);
2
+ export function isES2015Class(cls) {
3
+ return typeof cls === 'function' && classRegex.test(Function.prototype.toString.call(cls));
4
+ }
@@ -0,0 +1 @@
1
+ export declare function isObject(value: any): value is object | Function;
@@ -0,0 +1,4 @@
1
+ // biome-ignore lint/complexity/noBannedTypes: ok here
2
+ export function isObject(value) {
3
+ return typeof value === 'function' || (typeof value === 'object' && value !== null);
4
+ }
@@ -0,0 +1,6 @@
1
+ import type { QuickJSAsyncContext, QuickJSContext, QuickJSDeferredPromise } from 'quickjs-emscripten-core';
2
+ type ContextType = QuickJSContext | QuickJSAsyncContext;
3
+ export declare const registerPendingHostPromise: (ctx: ContextType, promise: QuickJSDeferredPromise) => void;
4
+ export declare const unregisterPendingHostPromise: (ctx: ContextType, promise: QuickJSDeferredPromise) => void;
5
+ export declare const rejectAndFlushPendingHostPromises: (ctx: ContextType, message?: string, maxWaitMs?: number) => Promise<void>;
6
+ export {};
@@ -0,0 +1,40 @@
1
+ const pendingHostPromises = new WeakMap();
2
+ export const registerPendingHostPromise = (ctx, promise) => {
3
+ const current = pendingHostPromises.get(ctx);
4
+ if (current) {
5
+ current.add(promise);
6
+ return;
7
+ }
8
+ pendingHostPromises.set(ctx, new Set([promise]));
9
+ };
10
+ export const unregisterPendingHostPromise = (ctx, promise) => {
11
+ const current = pendingHostPromises.get(ctx);
12
+ if (!current) {
13
+ return;
14
+ }
15
+ current.delete(promise);
16
+ if (current.size === 0) {
17
+ pendingHostPromises.delete(ctx);
18
+ }
19
+ };
20
+ export const rejectAndFlushPendingHostPromises = async (ctx, message = 'Sandbox timed out before async host call finished.', maxWaitMs = 100) => {
21
+ const current = pendingHostPromises.get(ctx);
22
+ if (!current || current.size === 0) {
23
+ return;
24
+ }
25
+ const pending = Array.from(current);
26
+ for (const deferred of pending) {
27
+ try {
28
+ const errHandle = ctx.newError(new Error(message));
29
+ deferred.reject(errHandle);
30
+ errHandle.dispose();
31
+ }
32
+ catch {
33
+ // ignore rejected/dead deferred or context teardown race
34
+ }
35
+ }
36
+ await Promise.race([
37
+ Promise.allSettled(pending.map(p => p.settled)),
38
+ new Promise(resolve => setTimeout(resolve, maxWaitMs)),
39
+ ]);
40
+ };
@@ -0,0 +1,8 @@
1
+ import type { SandboxBaseOptions } from '../index.js';
2
+ /**
3
+ * Determines the maximum allowed amount of concurrent intervals.
4
+ *
5
+ * @param runtimeOptions - The sandbox options containing `maxIntervalCount`.
6
+ * @returns The configured `maxIntervalCount` or `10` if none is set.
7
+ */
8
+ export declare const getMaxIntervalAmount: (runtimeOptions: SandboxBaseOptions) => number;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Determines the maximum allowed amount of concurrent intervals.
3
+ *
4
+ * @param runtimeOptions - The sandbox options containing `maxIntervalCount`.
5
+ * @returns The configured `maxIntervalCount` or `10` if none is set.
6
+ */
7
+ export const getMaxIntervalAmount = (runtimeOptions) => {
8
+ if (!runtimeOptions.maxIntervalCount || runtimeOptions.maxIntervalCount <= 0) {
9
+ return 10;
10
+ }
11
+ return runtimeOptions.maxIntervalCount;
12
+ };
@@ -0,0 +1,8 @@
1
+ import type { SandboxBaseOptions } from '../index.js';
2
+ /**
3
+ * Determines the maximum allowed amount of concurrent timeouts.
4
+ *
5
+ * @param runtimeOptions - The sandbox options containing `maxTimeoutCount`.
6
+ * @returns The configured `maxTimeoutCount` or `10` if none is set.
7
+ */
8
+ export declare const getMaxTimeoutAmount: (runtimeOptions: SandboxBaseOptions) => number;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Determines the maximum allowed amount of concurrent timeouts.
3
+ *
4
+ * @param runtimeOptions - The sandbox options containing `maxTimeoutCount`.
5
+ * @returns The configured `maxTimeoutCount` or `10` if none is set.
6
+ */
7
+ export const getMaxTimeoutAmount = (runtimeOptions) => {
8
+ if (!runtimeOptions.maxTimeoutCount || runtimeOptions.maxTimeoutCount <= 0) {
9
+ return 10;
10
+ }
11
+ return runtimeOptions.maxTimeoutCount;
12
+ };
@@ -0,0 +1,2 @@
1
+ import type { ErrorResponse } from '../types/ErrorResponse.js';
2
+ export declare const handleEvalError: (err: unknown) => ErrorResponse;
@@ -0,0 +1,21 @@
1
+ export const handleEvalError = (err) => {
2
+ return err instanceof Error
3
+ ? {
4
+ ok: false,
5
+ error: {
6
+ name: err.name,
7
+ message: err.message,
8
+ stack: err.stack,
9
+ },
10
+ isSyntaxError: err.name === 'SyntaxError',
11
+ }
12
+ : {
13
+ ok: false,
14
+ error: {
15
+ name: 'UnknownError',
16
+ message: typeof err === 'string' ? err : 'An unknown error occurred.',
17
+ stack: '',
18
+ },
19
+ isSyntaxError: false,
20
+ };
21
+ };
@@ -0,0 +1,9 @@
1
+ import { type QuickJSAsyncContext, type QuickJSContext, type QuickJSHandle, Scope } from 'quickjs-emscripten-core';
2
+ /**
3
+ * Serialize data from guest to host
4
+ *
5
+ * @param ctx The sandbox context
6
+ * @param handle The QuickJS handle to serialize
7
+ * @returns
8
+ */
9
+ export declare const handleToNative: (ctx: QuickJSContext | QuickJSAsyncContext, handle: QuickJSHandle, rootScope?: Scope) => any;