@ricsam/quickjs-runtime 0.2.15 → 0.2.17

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 CHANGED
@@ -20,6 +20,8 @@ const handle = setupRuntime(context, {
20
20
  onLog: (level, args) => console.log(`[${level}]`, ...args),
21
21
  },
22
22
  },
23
+ // Crypto API - pass true to enable
24
+ crypto: true,
23
25
  // Encoding API (atob/btoa) - pass true to enable
24
26
  encoding: true,
25
27
  });
@@ -29,6 +31,7 @@ handle.core; // CoreHandle (always present)
29
31
  handle.fetch; // FetchHandle (if enabled)
30
32
  handle.fs; // FsHandle (if enabled)
31
33
  handle.console; // ConsoleHandle (if enabled)
34
+ handle.crypto; // CryptoHandle (if enabled)
32
35
  handle.encoding; // EncodingHandle (if enabled)
33
36
 
34
37
  handle.dispose(); // Cleanup all
@@ -40,6 +43,7 @@ handle.dispose(); // Cleanup all
40
43
  const handle = setupRuntime(context, {
41
44
  fetch: true, // Enable fetch with default options
42
45
  console: true, // Enable console with no handlers (silent)
46
+ crypto: true, // Enable Web Crypto API
43
47
  encoding: true, // Enable atob/btoa
44
48
  });
45
49
  ```
@@ -52,6 +52,7 @@ __export(exports_src, {
52
52
  module.exports = __toCommonJS(exports_src);
53
53
  __reExport(exports_src, require("@ricsam/quickjs-core"), module.exports);
54
54
  __reExport(exports_src, require("@ricsam/quickjs-console"), module.exports);
55
+ __reExport(exports_src, require("@ricsam/quickjs-crypto"), module.exports);
55
56
  __reExport(exports_src, require("@ricsam/quickjs-encoding"), module.exports);
56
57
  __reExport(exports_src, require("@ricsam/quickjs-fetch"), module.exports);
57
58
  __reExport(exports_src, require("@ricsam/quickjs-fs"), module.exports);
@@ -62,6 +63,7 @@ var import_quickjs_fs = require("@ricsam/quickjs-fs");
62
63
  var import_quickjs_console = require("@ricsam/quickjs-console");
63
64
  var import_quickjs_encoding = require("@ricsam/quickjs-encoding");
64
65
  var import_quickjs_timers = require("@ricsam/quickjs-timers");
66
+ var import_quickjs_crypto = require("@ricsam/quickjs-crypto");
65
67
  function setupRuntime(context, options = {}) {
66
68
  const stateMap = import_quickjs_core.createStateMap();
67
69
  const core = import_quickjs_core.setupCore(context, { stateMap });
@@ -70,6 +72,7 @@ function setupRuntime(context, options = {}) {
70
72
  let consoleHandle;
71
73
  let encoding;
72
74
  let timers;
75
+ let cryptoHandle;
73
76
  if (options.fetch) {
74
77
  const fetchOptions = options.fetch === true ? { stateMap, coreHandle: core } : { ...options.fetch, stateMap, coreHandle: core };
75
78
  fetch = import_quickjs_fetch.setupFetch(context, fetchOptions);
@@ -93,6 +96,10 @@ function setupRuntime(context, options = {}) {
93
96
  const timersOptions = options.timers === true ? { stateMap, coreHandle: core } : { ...options.timers, stateMap, coreHandle: core };
94
97
  timers = import_quickjs_timers.setupTimers(context, timersOptions);
95
98
  }
99
+ if (options.crypto) {
100
+ const cryptoOptions = options.crypto === true ? { stateMap, coreHandle: core } : { ...options.crypto, stateMap, coreHandle: core };
101
+ cryptoHandle = import_quickjs_crypto.setupCrypto(context, cryptoOptions);
102
+ }
96
103
  return {
97
104
  core,
98
105
  fetch,
@@ -100,6 +107,7 @@ function setupRuntime(context, options = {}) {
100
107
  console: consoleHandle,
101
108
  encoding,
102
109
  timers,
110
+ crypto: cryptoHandle,
103
111
  stateMap,
104
112
  get context() {
105
113
  return context;
@@ -124,6 +132,7 @@ function setupRuntime(context, options = {}) {
124
132
  if (result.error)
125
133
  result.error.dispose();
126
134
  }
135
+ cryptoHandle?.dispose();
127
136
  timers?.dispose();
128
137
  encoding?.dispose();
129
138
  consoleHandle?.dispose();
@@ -172,4 +181,4 @@ function setupRuntime(context, options = {}) {
172
181
  }
173
182
  })
174
183
 
175
- //# debugId=08932F65633CC6C364756E2164756E21
184
+ //# debugId=9F06C7428583920964756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/index.ts"],
4
4
  "sourcesContent": [
5
- "// Re-export everything from sub-packages\nexport * from \"@ricsam/quickjs-core\";\nexport * from \"@ricsam/quickjs-console\";\nexport * from \"@ricsam/quickjs-encoding\";\nexport * from \"@ricsam/quickjs-fetch\";\nexport * from \"@ricsam/quickjs-fs\";\nexport * from \"@ricsam/quickjs-timers\";\n\nimport type { QuickJSContext } from \"quickjs-emscripten\";\nimport {\n setupCore,\n createStateMap,\n cleanupUnmarshaledHandles,\n clearAllInstanceState,\n type StateMap,\n type CoreHandle,\n} from \"@ricsam/quickjs-core\";\nimport {\n setupFetch,\n type SetupFetchOptions,\n type FetchHandle,\n} from \"@ricsam/quickjs-fetch\";\nimport {\n setupFs,\n type SetupFsOptions,\n type FsHandle,\n} from \"@ricsam/quickjs-fs\";\nimport {\n setupConsole,\n type SetupConsoleOptions,\n type ConsoleHandle,\n} from \"@ricsam/quickjs-console\";\nimport {\n setupEncoding,\n type SetupEncodingOptions,\n type EncodingHandle,\n} from \"@ricsam/quickjs-encoding\";\nimport {\n setupTimers,\n type SetupTimersOptions,\n type TimersHandle,\n} from \"@ricsam/quickjs-timers\";\n\n/**\n * Options for setting up the runtime\n */\nexport interface SetupRuntimeOptions {\n /**\n * Fetch API options\n * Pass `true` to enable with defaults\n * Pass `false` or omit to disable\n */\n fetch?: SetupFetchOptions | boolean;\n\n /**\n * File system options\n * Pass options object to enable\n * Pass `false` or omit to disable\n */\n fs?: SetupFsOptions | false;\n\n /**\n * Console options\n * Pass `true` to enable with defaults\n * Pass handlers object to customize\n * Pass `false` or omit to disable\n */\n console?: SetupConsoleOptions | boolean;\n\n /**\n * Encoding options (atob/btoa)\n * Pass `true` to enable with defaults\n * Pass `false` or omit to disable\n */\n encoding?: SetupEncodingOptions | boolean;\n\n /**\n * Timer options (setTimeout, setInterval, clearTimeout, clearInterval)\n * Pass `true` to enable with defaults\n * Pass `false` or omit to disable\n */\n timers?: SetupTimersOptions | boolean;\n}\n\n/**\n * Handle returned from setupRuntime\n */\nexport interface RuntimeHandle {\n /** Core handle (always present) */\n core: CoreHandle;\n\n /** Fetch handle (if enabled) */\n fetch?: FetchHandle;\n\n /** File system handle (if enabled) */\n fs?: FsHandle;\n\n /** Console handle (if enabled) */\n console?: ConsoleHandle;\n\n /** Encoding handle (if enabled) */\n encoding?: EncodingHandle;\n\n /** Timers handle (if enabled) */\n timers?: TimersHandle;\n\n /** Shared state map */\n readonly stateMap: StateMap;\n\n /** Get the underlying QuickJS context */\n readonly context: QuickJSContext;\n\n /**\n * Drain all pending jobs with timeout.\n * Call BEFORE dispose() to prevent GC assertion failures.\n * @param maxIterations - Maximum iterations (default: 1000)\n * @returns true if all jobs completed, false if timed out\n */\n drainPendingJobs(maxIterations?: number): boolean;\n\n /** Dispose all handles and cleanup */\n dispose(): void;\n}\n\n/**\n * Setup multiple APIs in a QuickJS context\n *\n * @example\n * const handle = setupRuntime(context, {\n * fetch: {\n * onFetch: async (req) => fetch(req),\n * },\n * fs: {\n * getDirectory: async (path) => createNodeDirectoryHandle(`/sandbox${path}`),\n * },\n * });\n *\n * // Use the context...\n *\n * handle.dispose();\n */\nexport function setupRuntime(\n context: QuickJSContext,\n options: SetupRuntimeOptions = {}\n): RuntimeHandle {\n const stateMap = createStateMap();\n\n // Always setup core\n const core = setupCore(context, { stateMap });\n\n let fetch: FetchHandle | undefined;\n let fs: FsHandle | undefined;\n let consoleHandle: ConsoleHandle | undefined;\n let encoding: EncodingHandle | undefined;\n let timers: TimersHandle | undefined;\n\n // Setup fetch if enabled\n if (options.fetch) {\n const fetchOptions: SetupFetchOptions =\n options.fetch === true\n ? { stateMap, coreHandle: core }\n : { ...options.fetch, stateMap, coreHandle: core };\n\n fetch = setupFetch(context, fetchOptions);\n }\n\n // Setup fs if provided\n if (options.fs) {\n fs = setupFs(context, {\n ...options.fs,\n stateMap,\n coreHandle: core,\n });\n }\n\n // Setup console if enabled\n if (options.console) {\n const consoleOptions: SetupConsoleOptions =\n options.console === true\n ? { stateMap, coreHandle: core }\n : { ...options.console, stateMap, coreHandle: core };\n\n consoleHandle = setupConsole(context, consoleOptions);\n }\n\n // Setup encoding if enabled\n if (options.encoding) {\n const encodingOptions: SetupEncodingOptions =\n options.encoding === true\n ? { stateMap, coreHandle: core }\n : { ...options.encoding, stateMap, coreHandle: core };\n\n encoding = setupEncoding(context, encodingOptions);\n }\n\n // Setup timers if enabled\n if (options.timers) {\n const timersOptions: SetupTimersOptions =\n options.timers === true\n ? { stateMap, coreHandle: core }\n : { ...options.timers, stateMap, coreHandle: core };\n\n timers = setupTimers(context, timersOptions);\n }\n\n return {\n core,\n fetch,\n fs,\n console: consoleHandle,\n encoding,\n timers,\n stateMap,\n get context() {\n return context;\n },\n drainPendingJobs(maxIterations = 1000): boolean {\n for (let i = 0; i < maxIterations; i++) {\n if (!context.runtime.hasPendingJob()) {\n return true;\n }\n const result = context.runtime.executePendingJobs();\n if (result.error) {\n result.error.dispose();\n }\n }\n return !context.runtime.hasPendingJob();\n },\n dispose() {\n // Drain pending jobs before disposal\n for (let i = 0; i < 1000; i++) {\n if (!context.runtime.hasPendingJob()) break;\n const result = context.runtime.executePendingJobs();\n if (result.error) result.error.dispose();\n }\n\n // Dispose sub-handles in reverse order\n timers?.dispose();\n encoding?.dispose();\n consoleHandle?.dispose();\n fs?.dispose();\n fetch?.dispose();\n\n // Drain pending jobs again after sub-handle disposal\n // (fetch?.dispose() calls evalCode which can create new jobs)\n for (let i = 0; i < 1000; i++) {\n if (!context.runtime.hasPendingJob()) break;\n const result = context.runtime.executePendingJobs();\n if (result.error) result.error.dispose();\n }\n\n // Clean up tracked handles\n cleanupUnmarshaledHandles(context);\n clearAllInstanceState();\n\n // Clear globals to help GC break circular references\n try {\n const clearGlobals = context.evalCode(`\n (function() {\n const keysToDelete = Object.keys(globalThis).filter(k =>\n k !== 'globalThis' && k !== 'undefined' && k !== 'NaN' && k !== 'Infinity'\n );\n for (const key of keysToDelete) {\n try { globalThis[key] = undefined; } catch (e) {}\n }\n for (const key of keysToDelete) {\n try { delete globalThis[key]; } catch (e) {}\n }\n return keysToDelete.length;\n })()\n `);\n if (clearGlobals.error) {\n clearGlobals.error.dispose();\n } else {\n clearGlobals.value.dispose();\n }\n } catch (e) {\n // Ignore errors during cleanup\n }\n\n // Final drain\n for (let i = 0; i < 100; i++) {\n if (!context.runtime.hasPendingJob()) break;\n const result = context.runtime.executePendingJobs();\n if (result.error) result.error.dispose();\n }\n\n core.dispose();\n },\n };\n}\n"
5
+ "// Re-export everything from sub-packages\nexport * from \"@ricsam/quickjs-core\";\nexport * from \"@ricsam/quickjs-console\";\nexport * from \"@ricsam/quickjs-crypto\";\nexport * from \"@ricsam/quickjs-encoding\";\nexport * from \"@ricsam/quickjs-fetch\";\nexport * from \"@ricsam/quickjs-fs\";\nexport * from \"@ricsam/quickjs-timers\";\n\nimport type { QuickJSContext } from \"quickjs-emscripten\";\nimport {\n setupCore,\n createStateMap,\n cleanupUnmarshaledHandles,\n clearAllInstanceState,\n type StateMap,\n type CoreHandle,\n} from \"@ricsam/quickjs-core\";\nimport {\n setupFetch,\n type SetupFetchOptions,\n type FetchHandle,\n} from \"@ricsam/quickjs-fetch\";\nimport {\n setupFs,\n type SetupFsOptions,\n type FsHandle,\n} from \"@ricsam/quickjs-fs\";\nimport {\n setupConsole,\n type SetupConsoleOptions,\n type ConsoleHandle,\n} from \"@ricsam/quickjs-console\";\nimport {\n setupEncoding,\n type SetupEncodingOptions,\n type EncodingHandle,\n} from \"@ricsam/quickjs-encoding\";\nimport {\n setupTimers,\n type SetupTimersOptions,\n type TimersHandle,\n} from \"@ricsam/quickjs-timers\";\nimport {\n setupCrypto,\n type SetupCryptoOptions,\n type CryptoHandle,\n} from \"@ricsam/quickjs-crypto\";\n\n/**\n * Options for setting up the runtime\n */\nexport interface SetupRuntimeOptions {\n /**\n * Fetch API options\n * Pass `true` to enable with defaults\n * Pass `false` or omit to disable\n */\n fetch?: SetupFetchOptions | boolean;\n\n /**\n * File system options\n * Pass options object to enable\n * Pass `false` or omit to disable\n */\n fs?: SetupFsOptions | false;\n\n /**\n * Console options\n * Pass `true` to enable with defaults\n * Pass handlers object to customize\n * Pass `false` or omit to disable\n */\n console?: SetupConsoleOptions | boolean;\n\n /**\n * Encoding options (atob/btoa)\n * Pass `true` to enable with defaults\n * Pass `false` or omit to disable\n */\n encoding?: SetupEncodingOptions | boolean;\n\n /**\n * Timer options (setTimeout, setInterval, clearTimeout, clearInterval)\n * Pass `true` to enable with defaults\n * Pass `false` or omit to disable\n */\n timers?: SetupTimersOptions | boolean;\n\n /**\n * Crypto API options (crypto.subtle, crypto.getRandomValues, crypto.randomUUID)\n * Pass `true` to enable with defaults\n * Pass `false` or omit to disable\n */\n crypto?: SetupCryptoOptions | boolean;\n}\n\n/**\n * Handle returned from setupRuntime\n */\nexport interface RuntimeHandle {\n /** Core handle (always present) */\n core: CoreHandle;\n\n /** Fetch handle (if enabled) */\n fetch?: FetchHandle;\n\n /** File system handle (if enabled) */\n fs?: FsHandle;\n\n /** Console handle (if enabled) */\n console?: ConsoleHandle;\n\n /** Encoding handle (if enabled) */\n encoding?: EncodingHandle;\n\n /** Timers handle (if enabled) */\n timers?: TimersHandle;\n\n /** Crypto handle (if enabled) */\n crypto?: CryptoHandle;\n\n /** Shared state map */\n readonly stateMap: StateMap;\n\n /** Get the underlying QuickJS context */\n readonly context: QuickJSContext;\n\n /**\n * Drain all pending jobs with timeout.\n * Call BEFORE dispose() to prevent GC assertion failures.\n * @param maxIterations - Maximum iterations (default: 1000)\n * @returns true if all jobs completed, false if timed out\n */\n drainPendingJobs(maxIterations?: number): boolean;\n\n /** Dispose all handles and cleanup */\n dispose(): void;\n}\n\n/**\n * Setup multiple APIs in a QuickJS context\n *\n * @example\n * const handle = setupRuntime(context, {\n * fetch: {\n * onFetch: async (req) => fetch(req),\n * },\n * fs: {\n * getDirectory: async (path) => createNodeDirectoryHandle(`/sandbox${path}`),\n * },\n * });\n *\n * // Use the context...\n *\n * handle.dispose();\n */\nexport function setupRuntime(\n context: QuickJSContext,\n options: SetupRuntimeOptions = {}\n): RuntimeHandle {\n const stateMap = createStateMap();\n\n // Always setup core\n const core = setupCore(context, { stateMap });\n\n let fetch: FetchHandle | undefined;\n let fs: FsHandle | undefined;\n let consoleHandle: ConsoleHandle | undefined;\n let encoding: EncodingHandle | undefined;\n let timers: TimersHandle | undefined;\n let cryptoHandle: CryptoHandle | undefined;\n\n // Setup fetch if enabled\n if (options.fetch) {\n const fetchOptions: SetupFetchOptions =\n options.fetch === true\n ? { stateMap, coreHandle: core }\n : { ...options.fetch, stateMap, coreHandle: core };\n\n fetch = setupFetch(context, fetchOptions);\n }\n\n // Setup fs if provided\n if (options.fs) {\n fs = setupFs(context, {\n ...options.fs,\n stateMap,\n coreHandle: core,\n });\n }\n\n // Setup console if enabled\n if (options.console) {\n const consoleOptions: SetupConsoleOptions =\n options.console === true\n ? { stateMap, coreHandle: core }\n : { ...options.console, stateMap, coreHandle: core };\n\n consoleHandle = setupConsole(context, consoleOptions);\n }\n\n // Setup encoding if enabled\n if (options.encoding) {\n const encodingOptions: SetupEncodingOptions =\n options.encoding === true\n ? { stateMap, coreHandle: core }\n : { ...options.encoding, stateMap, coreHandle: core };\n\n encoding = setupEncoding(context, encodingOptions);\n }\n\n // Setup timers if enabled\n if (options.timers) {\n const timersOptions: SetupTimersOptions =\n options.timers === true\n ? { stateMap, coreHandle: core }\n : { ...options.timers, stateMap, coreHandle: core };\n\n timers = setupTimers(context, timersOptions);\n }\n\n // Setup crypto if enabled\n if (options.crypto) {\n const cryptoOptions: SetupCryptoOptions =\n options.crypto === true\n ? { stateMap, coreHandle: core }\n : { ...options.crypto, stateMap, coreHandle: core };\n\n cryptoHandle = setupCrypto(context, cryptoOptions);\n }\n\n return {\n core,\n fetch,\n fs,\n console: consoleHandle,\n encoding,\n timers,\n crypto: cryptoHandle,\n stateMap,\n get context() {\n return context;\n },\n drainPendingJobs(maxIterations = 1000): boolean {\n for (let i = 0; i < maxIterations; i++) {\n if (!context.runtime.hasPendingJob()) {\n return true;\n }\n const result = context.runtime.executePendingJobs();\n if (result.error) {\n result.error.dispose();\n }\n }\n return !context.runtime.hasPendingJob();\n },\n dispose() {\n // Drain pending jobs before disposal\n for (let i = 0; i < 1000; i++) {\n if (!context.runtime.hasPendingJob()) break;\n const result = context.runtime.executePendingJobs();\n if (result.error) result.error.dispose();\n }\n\n // Dispose sub-handles in reverse order\n cryptoHandle?.dispose();\n timers?.dispose();\n encoding?.dispose();\n consoleHandle?.dispose();\n fs?.dispose();\n fetch?.dispose();\n\n // Drain pending jobs again after sub-handle disposal\n // (fetch?.dispose() calls evalCode which can create new jobs)\n for (let i = 0; i < 1000; i++) {\n if (!context.runtime.hasPendingJob()) break;\n const result = context.runtime.executePendingJobs();\n if (result.error) result.error.dispose();\n }\n\n // Clean up tracked handles\n cleanupUnmarshaledHandles(context);\n clearAllInstanceState();\n\n // Clear globals to help GC break circular references\n try {\n const clearGlobals = context.evalCode(`\n (function() {\n const keysToDelete = Object.keys(globalThis).filter(k =>\n k !== 'globalThis' && k !== 'undefined' && k !== 'NaN' && k !== 'Infinity'\n );\n for (const key of keysToDelete) {\n try { globalThis[key] = undefined; } catch (e) {}\n }\n for (const key of keysToDelete) {\n try { delete globalThis[key]; } catch (e) {}\n }\n return keysToDelete.length;\n })()\n `);\n if (clearGlobals.error) {\n clearGlobals.error.dispose();\n } else {\n clearGlobals.value.dispose();\n }\n } catch (e) {\n // Ignore errors during cleanup\n }\n\n // Final drain\n for (let i = 0; i < 100; i++) {\n if (!context.runtime.hasPendingJob()) break;\n const result = context.runtime.executePendingJobs();\n if (result.error) result.error.dispose();\n }\n\n core.dispose();\n },\n };\n}\n"
6
6
  ],
7
- "mappings": "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",
8
- "debugId": "08932F65633CC6C364756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "9F06C7428583920964756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@ricsam/quickjs-runtime",
3
- "version": "0.2.15",
3
+ "version": "0.2.17",
4
4
  "type": "commonjs"
5
5
  }
@@ -2,6 +2,7 @@
2
2
  // packages/runtime/src/index.ts
3
3
  export * from "@ricsam/quickjs-core";
4
4
  export * from "@ricsam/quickjs-console";
5
+ export * from "@ricsam/quickjs-crypto";
5
6
  export * from "@ricsam/quickjs-encoding";
6
7
  export * from "@ricsam/quickjs-fetch";
7
8
  export * from "@ricsam/quickjs-fs";
@@ -27,6 +28,9 @@ import {
27
28
  import {
28
29
  setupTimers
29
30
  } from "@ricsam/quickjs-timers";
31
+ import {
32
+ setupCrypto
33
+ } from "@ricsam/quickjs-crypto";
30
34
  function setupRuntime(context, options = {}) {
31
35
  const stateMap = createStateMap();
32
36
  const core = setupCore(context, { stateMap });
@@ -35,6 +39,7 @@ function setupRuntime(context, options = {}) {
35
39
  let consoleHandle;
36
40
  let encoding;
37
41
  let timers;
42
+ let cryptoHandle;
38
43
  if (options.fetch) {
39
44
  const fetchOptions = options.fetch === true ? { stateMap, coreHandle: core } : { ...options.fetch, stateMap, coreHandle: core };
40
45
  fetch = setupFetch(context, fetchOptions);
@@ -58,6 +63,10 @@ function setupRuntime(context, options = {}) {
58
63
  const timersOptions = options.timers === true ? { stateMap, coreHandle: core } : { ...options.timers, stateMap, coreHandle: core };
59
64
  timers = setupTimers(context, timersOptions);
60
65
  }
66
+ if (options.crypto) {
67
+ const cryptoOptions = options.crypto === true ? { stateMap, coreHandle: core } : { ...options.crypto, stateMap, coreHandle: core };
68
+ cryptoHandle = setupCrypto(context, cryptoOptions);
69
+ }
61
70
  return {
62
71
  core,
63
72
  fetch,
@@ -65,6 +74,7 @@ function setupRuntime(context, options = {}) {
65
74
  console: consoleHandle,
66
75
  encoding,
67
76
  timers,
77
+ crypto: cryptoHandle,
68
78
  stateMap,
69
79
  get context() {
70
80
  return context;
@@ -89,6 +99,7 @@ function setupRuntime(context, options = {}) {
89
99
  if (result.error)
90
100
  result.error.dispose();
91
101
  }
102
+ cryptoHandle?.dispose();
92
103
  timers?.dispose();
93
104
  encoding?.dispose();
94
105
  consoleHandle?.dispose();
@@ -139,4 +150,4 @@ export {
139
150
  setupRuntime
140
151
  };
141
152
 
142
- //# debugId=91E27187E6392B3064756E2164756E21
153
+ //# debugId=3A1DE579F5C2FCF564756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/index.ts"],
4
4
  "sourcesContent": [
5
- "// Re-export everything from sub-packages\nexport * from \"@ricsam/quickjs-core\";\nexport * from \"@ricsam/quickjs-console\";\nexport * from \"@ricsam/quickjs-encoding\";\nexport * from \"@ricsam/quickjs-fetch\";\nexport * from \"@ricsam/quickjs-fs\";\nexport * from \"@ricsam/quickjs-timers\";\n\nimport type { QuickJSContext } from \"quickjs-emscripten\";\nimport {\n setupCore,\n createStateMap,\n cleanupUnmarshaledHandles,\n clearAllInstanceState,\n type StateMap,\n type CoreHandle,\n} from \"@ricsam/quickjs-core\";\nimport {\n setupFetch,\n type SetupFetchOptions,\n type FetchHandle,\n} from \"@ricsam/quickjs-fetch\";\nimport {\n setupFs,\n type SetupFsOptions,\n type FsHandle,\n} from \"@ricsam/quickjs-fs\";\nimport {\n setupConsole,\n type SetupConsoleOptions,\n type ConsoleHandle,\n} from \"@ricsam/quickjs-console\";\nimport {\n setupEncoding,\n type SetupEncodingOptions,\n type EncodingHandle,\n} from \"@ricsam/quickjs-encoding\";\nimport {\n setupTimers,\n type SetupTimersOptions,\n type TimersHandle,\n} from \"@ricsam/quickjs-timers\";\n\n/**\n * Options for setting up the runtime\n */\nexport interface SetupRuntimeOptions {\n /**\n * Fetch API options\n * Pass `true` to enable with defaults\n * Pass `false` or omit to disable\n */\n fetch?: SetupFetchOptions | boolean;\n\n /**\n * File system options\n * Pass options object to enable\n * Pass `false` or omit to disable\n */\n fs?: SetupFsOptions | false;\n\n /**\n * Console options\n * Pass `true` to enable with defaults\n * Pass handlers object to customize\n * Pass `false` or omit to disable\n */\n console?: SetupConsoleOptions | boolean;\n\n /**\n * Encoding options (atob/btoa)\n * Pass `true` to enable with defaults\n * Pass `false` or omit to disable\n */\n encoding?: SetupEncodingOptions | boolean;\n\n /**\n * Timer options (setTimeout, setInterval, clearTimeout, clearInterval)\n * Pass `true` to enable with defaults\n * Pass `false` or omit to disable\n */\n timers?: SetupTimersOptions | boolean;\n}\n\n/**\n * Handle returned from setupRuntime\n */\nexport interface RuntimeHandle {\n /** Core handle (always present) */\n core: CoreHandle;\n\n /** Fetch handle (if enabled) */\n fetch?: FetchHandle;\n\n /** File system handle (if enabled) */\n fs?: FsHandle;\n\n /** Console handle (if enabled) */\n console?: ConsoleHandle;\n\n /** Encoding handle (if enabled) */\n encoding?: EncodingHandle;\n\n /** Timers handle (if enabled) */\n timers?: TimersHandle;\n\n /** Shared state map */\n readonly stateMap: StateMap;\n\n /** Get the underlying QuickJS context */\n readonly context: QuickJSContext;\n\n /**\n * Drain all pending jobs with timeout.\n * Call BEFORE dispose() to prevent GC assertion failures.\n * @param maxIterations - Maximum iterations (default: 1000)\n * @returns true if all jobs completed, false if timed out\n */\n drainPendingJobs(maxIterations?: number): boolean;\n\n /** Dispose all handles and cleanup */\n dispose(): void;\n}\n\n/**\n * Setup multiple APIs in a QuickJS context\n *\n * @example\n * const handle = setupRuntime(context, {\n * fetch: {\n * onFetch: async (req) => fetch(req),\n * },\n * fs: {\n * getDirectory: async (path) => createNodeDirectoryHandle(`/sandbox${path}`),\n * },\n * });\n *\n * // Use the context...\n *\n * handle.dispose();\n */\nexport function setupRuntime(\n context: QuickJSContext,\n options: SetupRuntimeOptions = {}\n): RuntimeHandle {\n const stateMap = createStateMap();\n\n // Always setup core\n const core = setupCore(context, { stateMap });\n\n let fetch: FetchHandle | undefined;\n let fs: FsHandle | undefined;\n let consoleHandle: ConsoleHandle | undefined;\n let encoding: EncodingHandle | undefined;\n let timers: TimersHandle | undefined;\n\n // Setup fetch if enabled\n if (options.fetch) {\n const fetchOptions: SetupFetchOptions =\n options.fetch === true\n ? { stateMap, coreHandle: core }\n : { ...options.fetch, stateMap, coreHandle: core };\n\n fetch = setupFetch(context, fetchOptions);\n }\n\n // Setup fs if provided\n if (options.fs) {\n fs = setupFs(context, {\n ...options.fs,\n stateMap,\n coreHandle: core,\n });\n }\n\n // Setup console if enabled\n if (options.console) {\n const consoleOptions: SetupConsoleOptions =\n options.console === true\n ? { stateMap, coreHandle: core }\n : { ...options.console, stateMap, coreHandle: core };\n\n consoleHandle = setupConsole(context, consoleOptions);\n }\n\n // Setup encoding if enabled\n if (options.encoding) {\n const encodingOptions: SetupEncodingOptions =\n options.encoding === true\n ? { stateMap, coreHandle: core }\n : { ...options.encoding, stateMap, coreHandle: core };\n\n encoding = setupEncoding(context, encodingOptions);\n }\n\n // Setup timers if enabled\n if (options.timers) {\n const timersOptions: SetupTimersOptions =\n options.timers === true\n ? { stateMap, coreHandle: core }\n : { ...options.timers, stateMap, coreHandle: core };\n\n timers = setupTimers(context, timersOptions);\n }\n\n return {\n core,\n fetch,\n fs,\n console: consoleHandle,\n encoding,\n timers,\n stateMap,\n get context() {\n return context;\n },\n drainPendingJobs(maxIterations = 1000): boolean {\n for (let i = 0; i < maxIterations; i++) {\n if (!context.runtime.hasPendingJob()) {\n return true;\n }\n const result = context.runtime.executePendingJobs();\n if (result.error) {\n result.error.dispose();\n }\n }\n return !context.runtime.hasPendingJob();\n },\n dispose() {\n // Drain pending jobs before disposal\n for (let i = 0; i < 1000; i++) {\n if (!context.runtime.hasPendingJob()) break;\n const result = context.runtime.executePendingJobs();\n if (result.error) result.error.dispose();\n }\n\n // Dispose sub-handles in reverse order\n timers?.dispose();\n encoding?.dispose();\n consoleHandle?.dispose();\n fs?.dispose();\n fetch?.dispose();\n\n // Drain pending jobs again after sub-handle disposal\n // (fetch?.dispose() calls evalCode which can create new jobs)\n for (let i = 0; i < 1000; i++) {\n if (!context.runtime.hasPendingJob()) break;\n const result = context.runtime.executePendingJobs();\n if (result.error) result.error.dispose();\n }\n\n // Clean up tracked handles\n cleanupUnmarshaledHandles(context);\n clearAllInstanceState();\n\n // Clear globals to help GC break circular references\n try {\n const clearGlobals = context.evalCode(`\n (function() {\n const keysToDelete = Object.keys(globalThis).filter(k =>\n k !== 'globalThis' && k !== 'undefined' && k !== 'NaN' && k !== 'Infinity'\n );\n for (const key of keysToDelete) {\n try { globalThis[key] = undefined; } catch (e) {}\n }\n for (const key of keysToDelete) {\n try { delete globalThis[key]; } catch (e) {}\n }\n return keysToDelete.length;\n })()\n `);\n if (clearGlobals.error) {\n clearGlobals.error.dispose();\n } else {\n clearGlobals.value.dispose();\n }\n } catch (e) {\n // Ignore errors during cleanup\n }\n\n // Final drain\n for (let i = 0; i < 100; i++) {\n if (!context.runtime.hasPendingJob()) break;\n const result = context.runtime.executePendingJobs();\n if (result.error) result.error.dispose();\n }\n\n core.dispose();\n },\n };\n}\n"
5
+ "// Re-export everything from sub-packages\nexport * from \"@ricsam/quickjs-core\";\nexport * from \"@ricsam/quickjs-console\";\nexport * from \"@ricsam/quickjs-crypto\";\nexport * from \"@ricsam/quickjs-encoding\";\nexport * from \"@ricsam/quickjs-fetch\";\nexport * from \"@ricsam/quickjs-fs\";\nexport * from \"@ricsam/quickjs-timers\";\n\nimport type { QuickJSContext } from \"quickjs-emscripten\";\nimport {\n setupCore,\n createStateMap,\n cleanupUnmarshaledHandles,\n clearAllInstanceState,\n type StateMap,\n type CoreHandle,\n} from \"@ricsam/quickjs-core\";\nimport {\n setupFetch,\n type SetupFetchOptions,\n type FetchHandle,\n} from \"@ricsam/quickjs-fetch\";\nimport {\n setupFs,\n type SetupFsOptions,\n type FsHandle,\n} from \"@ricsam/quickjs-fs\";\nimport {\n setupConsole,\n type SetupConsoleOptions,\n type ConsoleHandle,\n} from \"@ricsam/quickjs-console\";\nimport {\n setupEncoding,\n type SetupEncodingOptions,\n type EncodingHandle,\n} from \"@ricsam/quickjs-encoding\";\nimport {\n setupTimers,\n type SetupTimersOptions,\n type TimersHandle,\n} from \"@ricsam/quickjs-timers\";\nimport {\n setupCrypto,\n type SetupCryptoOptions,\n type CryptoHandle,\n} from \"@ricsam/quickjs-crypto\";\n\n/**\n * Options for setting up the runtime\n */\nexport interface SetupRuntimeOptions {\n /**\n * Fetch API options\n * Pass `true` to enable with defaults\n * Pass `false` or omit to disable\n */\n fetch?: SetupFetchOptions | boolean;\n\n /**\n * File system options\n * Pass options object to enable\n * Pass `false` or omit to disable\n */\n fs?: SetupFsOptions | false;\n\n /**\n * Console options\n * Pass `true` to enable with defaults\n * Pass handlers object to customize\n * Pass `false` or omit to disable\n */\n console?: SetupConsoleOptions | boolean;\n\n /**\n * Encoding options (atob/btoa)\n * Pass `true` to enable with defaults\n * Pass `false` or omit to disable\n */\n encoding?: SetupEncodingOptions | boolean;\n\n /**\n * Timer options (setTimeout, setInterval, clearTimeout, clearInterval)\n * Pass `true` to enable with defaults\n * Pass `false` or omit to disable\n */\n timers?: SetupTimersOptions | boolean;\n\n /**\n * Crypto API options (crypto.subtle, crypto.getRandomValues, crypto.randomUUID)\n * Pass `true` to enable with defaults\n * Pass `false` or omit to disable\n */\n crypto?: SetupCryptoOptions | boolean;\n}\n\n/**\n * Handle returned from setupRuntime\n */\nexport interface RuntimeHandle {\n /** Core handle (always present) */\n core: CoreHandle;\n\n /** Fetch handle (if enabled) */\n fetch?: FetchHandle;\n\n /** File system handle (if enabled) */\n fs?: FsHandle;\n\n /** Console handle (if enabled) */\n console?: ConsoleHandle;\n\n /** Encoding handle (if enabled) */\n encoding?: EncodingHandle;\n\n /** Timers handle (if enabled) */\n timers?: TimersHandle;\n\n /** Crypto handle (if enabled) */\n crypto?: CryptoHandle;\n\n /** Shared state map */\n readonly stateMap: StateMap;\n\n /** Get the underlying QuickJS context */\n readonly context: QuickJSContext;\n\n /**\n * Drain all pending jobs with timeout.\n * Call BEFORE dispose() to prevent GC assertion failures.\n * @param maxIterations - Maximum iterations (default: 1000)\n * @returns true if all jobs completed, false if timed out\n */\n drainPendingJobs(maxIterations?: number): boolean;\n\n /** Dispose all handles and cleanup */\n dispose(): void;\n}\n\n/**\n * Setup multiple APIs in a QuickJS context\n *\n * @example\n * const handle = setupRuntime(context, {\n * fetch: {\n * onFetch: async (req) => fetch(req),\n * },\n * fs: {\n * getDirectory: async (path) => createNodeDirectoryHandle(`/sandbox${path}`),\n * },\n * });\n *\n * // Use the context...\n *\n * handle.dispose();\n */\nexport function setupRuntime(\n context: QuickJSContext,\n options: SetupRuntimeOptions = {}\n): RuntimeHandle {\n const stateMap = createStateMap();\n\n // Always setup core\n const core = setupCore(context, { stateMap });\n\n let fetch: FetchHandle | undefined;\n let fs: FsHandle | undefined;\n let consoleHandle: ConsoleHandle | undefined;\n let encoding: EncodingHandle | undefined;\n let timers: TimersHandle | undefined;\n let cryptoHandle: CryptoHandle | undefined;\n\n // Setup fetch if enabled\n if (options.fetch) {\n const fetchOptions: SetupFetchOptions =\n options.fetch === true\n ? { stateMap, coreHandle: core }\n : { ...options.fetch, stateMap, coreHandle: core };\n\n fetch = setupFetch(context, fetchOptions);\n }\n\n // Setup fs if provided\n if (options.fs) {\n fs = setupFs(context, {\n ...options.fs,\n stateMap,\n coreHandle: core,\n });\n }\n\n // Setup console if enabled\n if (options.console) {\n const consoleOptions: SetupConsoleOptions =\n options.console === true\n ? { stateMap, coreHandle: core }\n : { ...options.console, stateMap, coreHandle: core };\n\n consoleHandle = setupConsole(context, consoleOptions);\n }\n\n // Setup encoding if enabled\n if (options.encoding) {\n const encodingOptions: SetupEncodingOptions =\n options.encoding === true\n ? { stateMap, coreHandle: core }\n : { ...options.encoding, stateMap, coreHandle: core };\n\n encoding = setupEncoding(context, encodingOptions);\n }\n\n // Setup timers if enabled\n if (options.timers) {\n const timersOptions: SetupTimersOptions =\n options.timers === true\n ? { stateMap, coreHandle: core }\n : { ...options.timers, stateMap, coreHandle: core };\n\n timers = setupTimers(context, timersOptions);\n }\n\n // Setup crypto if enabled\n if (options.crypto) {\n const cryptoOptions: SetupCryptoOptions =\n options.crypto === true\n ? { stateMap, coreHandle: core }\n : { ...options.crypto, stateMap, coreHandle: core };\n\n cryptoHandle = setupCrypto(context, cryptoOptions);\n }\n\n return {\n core,\n fetch,\n fs,\n console: consoleHandle,\n encoding,\n timers,\n crypto: cryptoHandle,\n stateMap,\n get context() {\n return context;\n },\n drainPendingJobs(maxIterations = 1000): boolean {\n for (let i = 0; i < maxIterations; i++) {\n if (!context.runtime.hasPendingJob()) {\n return true;\n }\n const result = context.runtime.executePendingJobs();\n if (result.error) {\n result.error.dispose();\n }\n }\n return !context.runtime.hasPendingJob();\n },\n dispose() {\n // Drain pending jobs before disposal\n for (let i = 0; i < 1000; i++) {\n if (!context.runtime.hasPendingJob()) break;\n const result = context.runtime.executePendingJobs();\n if (result.error) result.error.dispose();\n }\n\n // Dispose sub-handles in reverse order\n cryptoHandle?.dispose();\n timers?.dispose();\n encoding?.dispose();\n consoleHandle?.dispose();\n fs?.dispose();\n fetch?.dispose();\n\n // Drain pending jobs again after sub-handle disposal\n // (fetch?.dispose() calls evalCode which can create new jobs)\n for (let i = 0; i < 1000; i++) {\n if (!context.runtime.hasPendingJob()) break;\n const result = context.runtime.executePendingJobs();\n if (result.error) result.error.dispose();\n }\n\n // Clean up tracked handles\n cleanupUnmarshaledHandles(context);\n clearAllInstanceState();\n\n // Clear globals to help GC break circular references\n try {\n const clearGlobals = context.evalCode(`\n (function() {\n const keysToDelete = Object.keys(globalThis).filter(k =>\n k !== 'globalThis' && k !== 'undefined' && k !== 'NaN' && k !== 'Infinity'\n );\n for (const key of keysToDelete) {\n try { globalThis[key] = undefined; } catch (e) {}\n }\n for (const key of keysToDelete) {\n try { delete globalThis[key]; } catch (e) {}\n }\n return keysToDelete.length;\n })()\n `);\n if (clearGlobals.error) {\n clearGlobals.error.dispose();\n } else {\n clearGlobals.value.dispose();\n }\n } catch (e) {\n // Ignore errors during cleanup\n }\n\n // Final drain\n for (let i = 0; i < 100; i++) {\n if (!context.runtime.hasPendingJob()) break;\n const result = context.runtime.executePendingJobs();\n if (result.error) result.error.dispose();\n }\n\n core.dispose();\n },\n };\n}\n"
6
6
  ],
7
- "mappings": ";;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AAAA;AAAA;AAKA;AAAA;AAAA;AAKA;AAAA;AAAA;AAKA;AAAA;AAAA;AAKA;AAAA;AAAA;AAwGO,SAAS,YAAY,CAC1B,SACA,UAA+B,CAAC,GACjB;AAAA,EACf,MAAM,WAAW,eAAe;AAAA,EAGhC,MAAM,OAAO,UAAU,SAAS,EAAE,SAAS,CAAC;AAAA,EAE5C,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EAGJ,IAAI,QAAQ,OAAO;AAAA,IACjB,MAAM,eACJ,QAAQ,UAAU,OACd,EAAE,UAAU,YAAY,KAAK,IAC7B,KAAK,QAAQ,OAAO,UAAU,YAAY,KAAK;AAAA,IAErD,QAAQ,WAAW,SAAS,YAAY;AAAA,EAC1C;AAAA,EAGA,IAAI,QAAQ,IAAI;AAAA,IACd,KAAK,QAAQ,SAAS;AAAA,SACjB,QAAQ;AAAA,MACX;AAAA,MACA,YAAY;AAAA,IACd,CAAC;AAAA,EACH;AAAA,EAGA,IAAI,QAAQ,SAAS;AAAA,IACnB,MAAM,iBACJ,QAAQ,YAAY,OAChB,EAAE,UAAU,YAAY,KAAK,IAC7B,KAAK,QAAQ,SAAS,UAAU,YAAY,KAAK;AAAA,IAEvD,gBAAgB,aAAa,SAAS,cAAc;AAAA,EACtD;AAAA,EAGA,IAAI,QAAQ,UAAU;AAAA,IACpB,MAAM,kBACJ,QAAQ,aAAa,OACjB,EAAE,UAAU,YAAY,KAAK,IAC7B,KAAK,QAAQ,UAAU,UAAU,YAAY,KAAK;AAAA,IAExD,WAAW,cAAc,SAAS,eAAe;AAAA,EACnD;AAAA,EAGA,IAAI,QAAQ,QAAQ;AAAA,IAClB,MAAM,gBACJ,QAAQ,WAAW,OACf,EAAE,UAAU,YAAY,KAAK,IAC7B,KAAK,QAAQ,QAAQ,UAAU,YAAY,KAAK;AAAA,IAEtD,SAAS,YAAY,SAAS,aAAa;AAAA,EAC7C;AAAA,EAEA,OAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,QACI,OAAO,GAAG;AAAA,MACZ,OAAO;AAAA;AAAA,IAET,gBAAgB,CAAC,gBAAgB,MAAe;AAAA,MAC9C,SAAS,IAAI,EAAG,IAAI,eAAe,KAAK;AAAA,QACtC,IAAI,CAAC,QAAQ,QAAQ,cAAc,GAAG;AAAA,UACpC,OAAO;AAAA,QACT;AAAA,QACA,MAAM,SAAS,QAAQ,QAAQ,mBAAmB;AAAA,QAClD,IAAI,OAAO,OAAO;AAAA,UAChB,OAAO,MAAM,QAAQ;AAAA,QACvB;AAAA,MACF;AAAA,MACA,OAAO,CAAC,QAAQ,QAAQ,cAAc;AAAA;AAAA,IAExC,OAAO,GAAG;AAAA,MAER,SAAS,IAAI,EAAG,IAAI,MAAM,KAAK;AAAA,QAC7B,IAAI,CAAC,QAAQ,QAAQ,cAAc;AAAA,UAAG;AAAA,QACtC,MAAM,SAAS,QAAQ,QAAQ,mBAAmB;AAAA,QAClD,IAAI,OAAO;AAAA,UAAO,OAAO,MAAM,QAAQ;AAAA,MACzC;AAAA,MAGA,QAAQ,QAAQ;AAAA,MAChB,UAAU,QAAQ;AAAA,MAClB,eAAe,QAAQ;AAAA,MACvB,IAAI,QAAQ;AAAA,MACZ,OAAO,QAAQ;AAAA,MAIf,SAAS,IAAI,EAAG,IAAI,MAAM,KAAK;AAAA,QAC7B,IAAI,CAAC,QAAQ,QAAQ,cAAc;AAAA,UAAG;AAAA,QACtC,MAAM,SAAS,QAAQ,QAAQ,mBAAmB;AAAA,QAClD,IAAI,OAAO;AAAA,UAAO,OAAO,MAAM,QAAQ;AAAA,MACzC;AAAA,MAGA,0BAA0B,OAAO;AAAA,MACjC,sBAAsB;AAAA,MAGtB,IAAI;AAAA,QACF,MAAM,eAAe,QAAQ,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAarC;AAAA,QACD,IAAI,aAAa,OAAO;AAAA,UACtB,aAAa,MAAM,QAAQ;AAAA,QAC7B,EAAO;AAAA,UACL,aAAa,MAAM,QAAQ;AAAA;AAAA,QAE7B,OAAO,GAAG;AAAA,MAKZ,SAAS,IAAI,EAAG,IAAI,KAAK,KAAK;AAAA,QAC5B,IAAI,CAAC,QAAQ,QAAQ,cAAc;AAAA,UAAG;AAAA,QACtC,MAAM,SAAS,QAAQ,QAAQ,mBAAmB;AAAA,QAClD,IAAI,OAAO;AAAA,UAAO,OAAO,MAAM,QAAQ;AAAA,MACzC;AAAA,MAEA,KAAK,QAAQ;AAAA;AAAA,EAEjB;AAAA;",
8
- "debugId": "91E27187E6392B3064756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "3A1DE579F5C2FCF564756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@ricsam/quickjs-runtime",
3
- "version": "0.2.15",
3
+ "version": "0.2.17",
4
4
  "type": "module"
5
5
  }
@@ -1,5 +1,6 @@
1
1
  export * from "@ricsam/quickjs-core";
2
2
  export * from "@ricsam/quickjs-console";
3
+ export * from "@ricsam/quickjs-crypto";
3
4
  export * from "@ricsam/quickjs-encoding";
4
5
  export * from "@ricsam/quickjs-fetch";
5
6
  export * from "@ricsam/quickjs-fs";
@@ -11,6 +12,7 @@ import { type SetupFsOptions, type FsHandle } from "@ricsam/quickjs-fs";
11
12
  import { type SetupConsoleOptions, type ConsoleHandle } from "@ricsam/quickjs-console";
12
13
  import { type SetupEncodingOptions, type EncodingHandle } from "@ricsam/quickjs-encoding";
13
14
  import { type SetupTimersOptions, type TimersHandle } from "@ricsam/quickjs-timers";
15
+ import { type SetupCryptoOptions, type CryptoHandle } from "@ricsam/quickjs-crypto";
14
16
  /**
15
17
  * Options for setting up the runtime
16
18
  */
@@ -46,6 +48,12 @@ export interface SetupRuntimeOptions {
46
48
  * Pass `false` or omit to disable
47
49
  */
48
50
  timers?: SetupTimersOptions | boolean;
51
+ /**
52
+ * Crypto API options (crypto.subtle, crypto.getRandomValues, crypto.randomUUID)
53
+ * Pass `true` to enable with defaults
54
+ * Pass `false` or omit to disable
55
+ */
56
+ crypto?: SetupCryptoOptions | boolean;
49
57
  }
50
58
  /**
51
59
  * Handle returned from setupRuntime
@@ -63,6 +71,8 @@ export interface RuntimeHandle {
63
71
  encoding?: EncodingHandle;
64
72
  /** Timers handle (if enabled) */
65
73
  timers?: TimersHandle;
74
+ /** Crypto handle (if enabled) */
75
+ crypto?: CryptoHandle;
66
76
  /** Shared state map */
67
77
  readonly stateMap: StateMap;
68
78
  /** Get the underlying QuickJS context */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ricsam/quickjs-runtime",
3
- "version": "0.2.15",
3
+ "version": "0.2.17",
4
4
  "main": "./dist/cjs/index.cjs",
5
5
  "types": "./dist/types/index.d.ts",
6
6
  "exports": {
@@ -16,12 +16,13 @@
16
16
  "typecheck": "tsc --noEmit"
17
17
  },
18
18
  "dependencies": {
19
- "@ricsam/quickjs-core": "^0.2.12",
20
- "@ricsam/quickjs-console": "^0.2.12",
21
- "@ricsam/quickjs-encoding": "^0.2.12",
22
- "@ricsam/quickjs-fetch": "^0.2.13",
23
- "@ricsam/quickjs-fs": "^0.2.12",
24
- "@ricsam/quickjs-timers": "^0.2.12",
19
+ "@ricsam/quickjs-core": "^0.2.14",
20
+ "@ricsam/quickjs-console": "^0.2.14",
21
+ "@ricsam/quickjs-crypto": "^0.2.14",
22
+ "@ricsam/quickjs-encoding": "^0.2.14",
23
+ "@ricsam/quickjs-fetch": "^0.2.15",
24
+ "@ricsam/quickjs-fs": "^0.2.14",
25
+ "@ricsam/quickjs-timers": "^0.2.14",
25
26
  "quickjs-emscripten": "^0.31.0"
26
27
  },
27
28
  "peerDependencies": {