@ricsam/isolate 0.1.4 → 0.1.5

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 (80) hide show
  1. package/README.md +25 -2
  2. package/dist/cjs/internal/async-context/index.cjs +140 -0
  3. package/dist/cjs/internal/async-context/index.cjs.map +10 -0
  4. package/dist/cjs/internal/client/connection.cjs +175 -123
  5. package/dist/cjs/internal/client/connection.cjs.map +3 -3
  6. package/dist/cjs/internal/console/index.cjs +2 -2
  7. package/dist/cjs/internal/console/index.cjs.map +2 -2
  8. package/dist/cjs/internal/core/index.cjs +13 -5
  9. package/dist/cjs/internal/core/index.cjs.map +3 -3
  10. package/dist/cjs/internal/crypto/index.cjs +2 -2
  11. package/dist/cjs/internal/crypto/index.cjs.map +2 -2
  12. package/dist/cjs/internal/daemon/connection.cjs +77 -12
  13. package/dist/cjs/internal/daemon/connection.cjs.map +3 -3
  14. package/dist/cjs/internal/encoding/index.cjs.map +1 -1
  15. package/dist/cjs/internal/fetch/index.cjs +80 -18
  16. package/dist/cjs/internal/fetch/index.cjs.map +3 -3
  17. package/dist/cjs/internal/fetch/stream-state.cjs.map +1 -1
  18. package/dist/cjs/internal/fs/index.cjs +2 -2
  19. package/dist/cjs/internal/fs/index.cjs.map +2 -2
  20. package/dist/cjs/internal/module-loader/bundle.cjs +201 -1
  21. package/dist/cjs/internal/module-loader/bundle.cjs.map +3 -3
  22. package/dist/cjs/internal/path/index.cjs.map +1 -1
  23. package/dist/cjs/internal/playwright/index.cjs +2 -2
  24. package/dist/cjs/internal/playwright/index.cjs.map +2 -2
  25. package/dist/cjs/internal/runtime/index.cjs +78 -6
  26. package/dist/cjs/internal/runtime/index.cjs.map +3 -3
  27. package/dist/cjs/internal/test-environment/index.cjs +2 -2
  28. package/dist/cjs/internal/test-environment/index.cjs.map +2 -2
  29. package/dist/cjs/internal/timers/index.cjs +9 -4
  30. package/dist/cjs/internal/timers/index.cjs.map +3 -3
  31. package/dist/cjs/internal/typecheck/isolate-types.cjs +36 -1
  32. package/dist/cjs/internal/typecheck/isolate-types.cjs.map +3 -3
  33. package/dist/cjs/package.json +1 -1
  34. package/dist/mjs/internal/async-context/index.mjs +100 -0
  35. package/dist/mjs/internal/async-context/index.mjs.map +10 -0
  36. package/dist/mjs/internal/client/connection.mjs +176 -123
  37. package/dist/mjs/internal/client/connection.mjs.map +3 -3
  38. package/dist/mjs/internal/console/index.mjs +2 -2
  39. package/dist/mjs/internal/console/index.mjs.map +2 -2
  40. package/dist/mjs/internal/core/index.mjs +13 -5
  41. package/dist/mjs/internal/core/index.mjs.map +3 -3
  42. package/dist/mjs/internal/crypto/index.mjs +2 -2
  43. package/dist/mjs/internal/crypto/index.mjs.map +2 -2
  44. package/dist/mjs/internal/daemon/connection.mjs +77 -12
  45. package/dist/mjs/internal/daemon/connection.mjs.map +3 -3
  46. package/dist/mjs/internal/encoding/index.mjs.map +1 -1
  47. package/dist/mjs/internal/fetch/index.mjs +80 -18
  48. package/dist/mjs/internal/fetch/index.mjs.map +3 -3
  49. package/dist/mjs/internal/fetch/stream-state.mjs.map +1 -1
  50. package/dist/mjs/internal/fs/index.mjs +2 -2
  51. package/dist/mjs/internal/fs/index.mjs.map +2 -2
  52. package/dist/mjs/internal/module-loader/bundle.mjs +201 -1
  53. package/dist/mjs/internal/module-loader/bundle.mjs.map +3 -3
  54. package/dist/mjs/internal/path/index.mjs.map +1 -1
  55. package/dist/mjs/internal/playwright/index.mjs +2 -2
  56. package/dist/mjs/internal/playwright/index.mjs.map +2 -2
  57. package/dist/mjs/internal/runtime/index.mjs +78 -6
  58. package/dist/mjs/internal/runtime/index.mjs.map +3 -3
  59. package/dist/mjs/internal/test-environment/index.mjs +2 -2
  60. package/dist/mjs/internal/test-environment/index.mjs.map +2 -2
  61. package/dist/mjs/internal/timers/index.mjs +9 -4
  62. package/dist/mjs/internal/timers/index.mjs.map +3 -3
  63. package/dist/mjs/internal/typecheck/isolate-types.mjs +36 -1
  64. package/dist/mjs/internal/typecheck/isolate-types.mjs.map +3 -3
  65. package/dist/mjs/package.json +1 -1
  66. package/dist/types/internal/async-context/index.d.ts +5 -0
  67. package/dist/types/internal/console/index.d.ts +1 -1
  68. package/dist/types/internal/core/index.d.ts +2 -2
  69. package/dist/types/internal/crypto/index.d.ts +1 -1
  70. package/dist/types/internal/daemon/types.d.ts +1 -0
  71. package/dist/types/internal/encoding/index.d.ts +1 -1
  72. package/dist/types/internal/fetch/index.d.ts +1 -1
  73. package/dist/types/internal/fetch/stream-state.d.ts +1 -1
  74. package/dist/types/internal/fs/index.d.ts +1 -1
  75. package/dist/types/internal/path/index.d.ts +1 -1
  76. package/dist/types/internal/playwright/index.d.ts +1 -1
  77. package/dist/types/internal/test-environment/index.d.ts +1 -1
  78. package/dist/types/internal/timers/index.d.ts +1 -1
  79. package/dist/types/internal/typecheck/isolate-types.d.ts +2 -2
  80. package/package.json +8 -3
@@ -66,7 +66,7 @@ __export(exports_crypto, {
66
66
  setupCrypto: () => setupCrypto
67
67
  });
68
68
  module.exports = __toCommonJS(exports_crypto);
69
- var import_isolated_vm = __toESM(require("isolated-vm"));
69
+ var import_isolated_vm = __toESM(require("@ricsam/isolated-vm"));
70
70
  var import_node_crypto = __toESM(require("node:crypto"));
71
71
  var cryptoKeysByContext = new WeakMap;
72
72
  var nextKeyId = 1;
@@ -467,4 +467,4 @@ async function setupCrypto(context) {
467
467
  };
468
468
  }
469
469
 
470
- //# debugId=7B5ADA3029912B4064756E2164756E21
470
+ //# debugId=1177B61C32157E2F64756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/internal/crypto/index.ts"],
4
4
  "sourcesContent": [
5
- "import ivm from \"isolated-vm\";\nimport crypto from \"node:crypto\";\n\nexport interface CryptoHandle {\n dispose(): void;\n}\n\n// Host-side key storage for crypto.subtle\nconst cryptoKeysByContext = new WeakMap<ivm.Context, Map<number, crypto.webcrypto.CryptoKey>>();\nlet nextKeyId = 1;\n\nfunction getKeyMapForContext(context: ivm.Context): Map<number, crypto.webcrypto.CryptoKey> {\n let map = cryptoKeysByContext.get(context);\n if (!map) {\n map = new Map();\n cryptoKeysByContext.set(context, map);\n }\n return map;\n}\n\nfunction deserializeAlgorithm(algorithm: Record<string, unknown>): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(algorithm)) {\n if (value && typeof value === 'object' && !Array.isArray(value) &&\n Object.keys(value).every(k => /^\\d+$/.test(k))) {\n // Convert {\"0\": n, \"1\": m, ...} back to Uint8Array\n const length = Object.keys(value).length;\n const arr = new Uint8Array(length);\n for (let i = 0; i < length; i++) {\n arr[i] = (value as Record<string, number>)[String(i)] ?? 0;\n }\n result[key] = arr;\n } else {\n result[key] = value;\n }\n }\n return result;\n}\n\n/**\n * Setup Web Crypto API in an isolated-vm context\n *\n * Provides crypto.getRandomValues and crypto.randomUUID\n *\n * @example\n * const handle = await setupCrypto(context);\n * await context.eval(`\n * const uuid = crypto.randomUUID();\n * const array = new Uint8Array(16);\n * crypto.getRandomValues(array);\n * `);\n */\nexport async function setupCrypto(\n context: ivm.Context\n): Promise<CryptoHandle> {\n const global = context.global;\n\n // Register host callbacks\n global.setSync(\n \"__crypto_randomUUID\",\n new ivm.Callback(() => {\n return crypto.randomUUID();\n })\n );\n\n global.setSync(\n \"__crypto_getRandomValues\",\n new ivm.Callback((byteLength: number) => {\n const buffer = Buffer.alloc(byteLength);\n crypto.randomFillSync(buffer);\n return Array.from(buffer);\n })\n );\n\n // Get key map for this context\n const keyMap = getKeyMapForContext(context);\n\n // crypto.subtle.importKey - async reference\n const importKeyRef = new ivm.Reference(\n async (\n format: string,\n keyDataJson: string,\n algorithmJson: string,\n extractable: boolean,\n keyUsagesJson: string\n ) => {\n const keyData = JSON.parse(keyDataJson) as number[];\n const algorithm = JSON.parse(algorithmJson);\n const keyUsages = JSON.parse(keyUsagesJson) as crypto.webcrypto.KeyUsage[];\n\n try {\n let cryptoKey: crypto.webcrypto.CryptoKey;\n if (format === \"raw\") {\n const importData = new Uint8Array(keyData);\n cryptoKey = await crypto.webcrypto.subtle.importKey(\n \"raw\",\n importData,\n algorithm,\n extractable,\n keyUsages\n );\n } else if (format === \"jwk\") {\n const importData = keyData as unknown as crypto.webcrypto.JsonWebKey;\n cryptoKey = await crypto.webcrypto.subtle.importKey(\n \"jwk\",\n importData,\n algorithm,\n extractable,\n keyUsages\n );\n } else {\n throw new Error(`[NotSupportedError]Unsupported key format: ${format}`);\n }\n\n // Store key on host and return ID\n const keyId = nextKeyId++;\n keyMap.set(keyId, cryptoKey);\n return keyId;\n } catch (err) {\n if (err instanceof Error) {\n throw new Error(`[${err.name}]${err.message}`);\n }\n throw err;\n }\n }\n );\n global.setSync(\"__crypto_subtle_importKey_ref\", importKeyRef);\n\n // crypto.subtle.sign - async reference\n const signRef = new ivm.Reference(\n async (algorithmJson: string, keyId: number, dataJson: string) => {\n const algorithm = JSON.parse(algorithmJson);\n const data = new Uint8Array(JSON.parse(dataJson) as number[]);\n\n const cryptoKey = keyMap.get(keyId);\n if (!cryptoKey) {\n throw new Error(\"[InvalidAccessError]Key not found\");\n }\n\n try {\n const signature = await crypto.webcrypto.subtle.sign(\n algorithm,\n cryptoKey,\n data\n );\n return JSON.stringify(Array.from(new Uint8Array(signature)));\n } catch (err) {\n if (err instanceof Error) {\n throw new Error(`[${err.name}]${err.message}`);\n }\n throw err;\n }\n }\n );\n global.setSync(\"__crypto_subtle_sign_ref\", signRef);\n\n // crypto.subtle.verify - async reference\n const verifyRef = new ivm.Reference(\n async (\n algorithmJson: string,\n keyId: number,\n signatureJson: string,\n dataJson: string\n ) => {\n const algorithm = JSON.parse(algorithmJson);\n const signature = new Uint8Array(JSON.parse(signatureJson) as number[]);\n const data = new Uint8Array(JSON.parse(dataJson) as number[]);\n\n const cryptoKey = keyMap.get(keyId);\n if (!cryptoKey) {\n throw new Error(\"[InvalidAccessError]Key not found\");\n }\n\n try {\n return await crypto.webcrypto.subtle.verify(\n algorithm,\n cryptoKey,\n signature,\n data\n );\n } catch (err) {\n if (err instanceof Error) {\n throw new Error(`[${err.name}]${err.message}`);\n }\n throw err;\n }\n }\n );\n global.setSync(\"__crypto_subtle_verify_ref\", verifyRef);\n\n // crypto.subtle.digest - async reference\n const digestRef = new ivm.Reference(\n async (algorithmJson: string, dataJson: string) => {\n const algorithm = JSON.parse(algorithmJson);\n const data = new Uint8Array(JSON.parse(dataJson) as number[]);\n\n try {\n const hash = await crypto.webcrypto.subtle.digest(algorithm, data);\n return JSON.stringify(Array.from(new Uint8Array(hash)));\n } catch (err) {\n if (err instanceof Error) {\n throw new Error(`[${err.name}]${err.message}`);\n }\n throw err;\n }\n }\n );\n global.setSync(\"__crypto_subtle_digest_ref\", digestRef);\n\n // crypto.subtle.deriveBits - async reference\n const deriveBitsRef = new ivm.Reference(\n async (algorithmJson: string, keyId: number, length: number) => {\n const algorithm = deserializeAlgorithm(JSON.parse(algorithmJson));\n\n const cryptoKey = keyMap.get(keyId);\n if (!cryptoKey) {\n throw new Error(\"[InvalidAccessError]Key not found\");\n }\n\n try {\n const bits = await crypto.webcrypto.subtle.deriveBits(\n algorithm as unknown as crypto.webcrypto.EcdhKeyDeriveParams | crypto.webcrypto.HkdfParams | crypto.webcrypto.Pbkdf2Params,\n cryptoKey,\n length\n );\n return JSON.stringify(Array.from(new Uint8Array(bits)));\n } catch (err) {\n if (err instanceof Error) {\n throw new Error(`[${err.name}]${err.message}`);\n }\n throw err;\n }\n }\n );\n global.setSync(\"__crypto_subtle_deriveBits_ref\", deriveBitsRef);\n\n // crypto.subtle.deriveKey - async reference\n const deriveKeyRef = new ivm.Reference(\n async (\n algorithmJson: string,\n baseKeyId: number,\n derivedKeyAlgorithmJson: string,\n extractable: boolean,\n keyUsagesJson: string\n ) => {\n const algorithm = deserializeAlgorithm(JSON.parse(algorithmJson));\n const derivedKeyAlgorithm = JSON.parse(derivedKeyAlgorithmJson);\n const keyUsages = JSON.parse(keyUsagesJson) as crypto.webcrypto.KeyUsage[];\n\n const baseKey = keyMap.get(baseKeyId);\n if (!baseKey) {\n throw new Error(\"[InvalidAccessError]Key not found\");\n }\n\n try {\n const derivedKey = await crypto.webcrypto.subtle.deriveKey(\n algorithm as unknown as crypto.webcrypto.EcdhKeyDeriveParams | crypto.webcrypto.HkdfParams | crypto.webcrypto.Pbkdf2Params,\n baseKey,\n derivedKeyAlgorithm,\n extractable,\n keyUsages\n );\n\n // Store derived key on host and return ID\n const keyId = nextKeyId++;\n keyMap.set(keyId, derivedKey);\n return keyId;\n } catch (err) {\n if (err instanceof Error) {\n throw new Error(`[${err.name}]${err.message}`);\n }\n throw err;\n }\n }\n );\n global.setSync(\"__crypto_subtle_deriveKey_ref\", deriveKeyRef);\n\n // Inject the crypto object into the isolate\n const cryptoCode = `\n(function() {\n // DOMException polyfill (Pattern #12)\n if (typeof DOMException === 'undefined') {\n globalThis.DOMException = class DOMException extends Error {\n constructor(message, name) {\n super(message);\n this.name = name || 'DOMException';\n }\n };\n }\n\n // Helper to decode error from host\n function __decodeError(err) {\n if (!(err instanceof Error)) return err;\n const match = err.message.match(/^\\\\[(TypeError|RangeError|NotSupportedError|InvalidAccessError|OperationError|DataError|Error)\\\\](.*)$/);\n if (match) {\n if (['NotSupportedError', 'InvalidAccessError', 'OperationError', 'DataError'].includes(match[1])) {\n return new DOMException(match[2], match[1]);\n }\n const ErrorType = globalThis[match[1]] || Error;\n return new ErrorType(match[2]);\n }\n return err;\n }\n\n // CryptoKey class to wrap key IDs\n const _cryptoKeyIds = new WeakMap();\n\n class CryptoKey {\n constructor(keyId, algorithm, extractable, usages, type) {\n _cryptoKeyIds.set(this, keyId);\n this._algorithm = algorithm;\n this._extractable = extractable;\n this._usages = usages;\n this._type = type || 'secret';\n }\n\n _getKeyId() {\n return _cryptoKeyIds.get(this);\n }\n\n get algorithm() {\n return this._algorithm;\n }\n\n get extractable() {\n return this._extractable;\n }\n\n get usages() {\n return [...this._usages];\n }\n\n get type() {\n return this._type;\n }\n }\n\n globalThis.CryptoKey = CryptoKey;\n\n // Helper to convert data to byte array\n function toByteArray(data) {\n if (typeof data === 'string') {\n return Array.from(new TextEncoder().encode(data));\n }\n if (data instanceof ArrayBuffer) {\n return Array.from(new Uint8Array(data));\n }\n if (ArrayBuffer.isView(data)) {\n return Array.from(new Uint8Array(data.buffer, data.byteOffset, data.byteLength));\n }\n throw new TypeError('Data must be a BufferSource');\n }\n\n // Normalize algorithm to object form\n function normalizeAlgorithm(algorithm) {\n if (typeof algorithm === 'string') {\n return { name: algorithm };\n }\n return algorithm;\n }\n\n globalThis.crypto = {\n randomUUID() {\n return __crypto_randomUUID();\n },\n\n getRandomValues(typedArray) {\n // Validate input is an integer TypedArray\n if (!(typedArray instanceof Int8Array ||\n typedArray instanceof Uint8Array ||\n typedArray instanceof Uint8ClampedArray ||\n typedArray instanceof Int16Array ||\n typedArray instanceof Uint16Array ||\n typedArray instanceof Int32Array ||\n typedArray instanceof Uint32Array ||\n typedArray instanceof BigInt64Array ||\n typedArray instanceof BigUint64Array)) {\n throw new TypeError(\"Argument 1 must be an integer typed array\");\n }\n\n const byteLength = typedArray.byteLength;\n if (byteLength > 65536) {\n throw new DOMException(\n \"The ArrayBufferView's byte length exceeds the number of bytes of entropy available via this API (65536)\",\n \"QuotaExceededError\"\n );\n }\n\n // Get random bytes from host\n const bytes = __crypto_getRandomValues(byteLength);\n\n // Copy bytes into the TypedArray\n const view = new Uint8Array(typedArray.buffer, typedArray.byteOffset, typedArray.byteLength);\n for (let i = 0; i < bytes.length; i++) {\n view[i] = bytes[i];\n }\n\n return typedArray;\n },\n\n subtle: {\n async importKey(format, keyData, algorithm, extractable, keyUsages) {\n try {\n const normalizedAlgo = normalizeAlgorithm(algorithm);\n let keyDataJson;\n\n if (format === 'raw') {\n keyDataJson = JSON.stringify(toByteArray(keyData));\n } else if (format === 'jwk') {\n keyDataJson = JSON.stringify(keyData);\n } else {\n throw new DOMException('Unsupported key format: ' + format, 'NotSupportedError');\n }\n\n const keyId = await __crypto_subtle_importKey_ref.apply(undefined, [\n format,\n keyDataJson,\n JSON.stringify(normalizedAlgo),\n extractable,\n JSON.stringify(keyUsages)\n ], { result: { promise: true, copy: true } });\n\n return new CryptoKey(keyId, normalizedAlgo, extractable, keyUsages);\n } catch (err) {\n throw __decodeError(err);\n }\n },\n\n async sign(algorithm, key, data) {\n try {\n if (!(key instanceof CryptoKey)) {\n throw new TypeError('Key must be a CryptoKey');\n }\n const normalizedAlgo = normalizeAlgorithm(algorithm);\n const signatureBytesJson = await __crypto_subtle_sign_ref.apply(undefined, [\n JSON.stringify(normalizedAlgo),\n key._getKeyId(),\n JSON.stringify(toByteArray(data))\n ], { result: { promise: true, copy: true } });\n const signatureBytes = JSON.parse(signatureBytesJson);\n return new Uint8Array(signatureBytes).buffer;\n } catch (err) {\n throw __decodeError(err);\n }\n },\n\n async verify(algorithm, key, signature, data) {\n try {\n if (!(key instanceof CryptoKey)) {\n throw new TypeError('Key must be a CryptoKey');\n }\n const normalizedAlgo = normalizeAlgorithm(algorithm);\n return await __crypto_subtle_verify_ref.apply(undefined, [\n JSON.stringify(normalizedAlgo),\n key._getKeyId(),\n JSON.stringify(toByteArray(signature)),\n JSON.stringify(toByteArray(data))\n ], { result: { promise: true, copy: true } });\n } catch (err) {\n throw __decodeError(err);\n }\n },\n\n async digest(algorithm, data) {\n try {\n const normalizedAlgo = normalizeAlgorithm(algorithm);\n const hashBytesJson = await __crypto_subtle_digest_ref.apply(undefined, [\n JSON.stringify(normalizedAlgo),\n JSON.stringify(toByteArray(data))\n ], { result: { promise: true, copy: true } });\n const hashBytes = JSON.parse(hashBytesJson);\n return new Uint8Array(hashBytes).buffer;\n } catch (err) {\n throw __decodeError(err);\n }\n },\n\n async deriveBits(algorithm, baseKey, length) {\n try {\n if (!(baseKey instanceof CryptoKey)) {\n throw new TypeError('Key must be a CryptoKey');\n }\n const normalizedAlgo = normalizeAlgorithm(algorithm);\n const bitsBytesJson = await __crypto_subtle_deriveBits_ref.apply(undefined, [\n JSON.stringify(normalizedAlgo),\n baseKey._getKeyId(),\n length\n ], { result: { promise: true, copy: true } });\n const bitsBytes = JSON.parse(bitsBytesJson);\n return new Uint8Array(bitsBytes).buffer;\n } catch (err) {\n throw __decodeError(err);\n }\n },\n\n async deriveKey(algorithm, baseKey, derivedKeyAlgorithm, extractable, keyUsages) {\n try {\n if (!(baseKey instanceof CryptoKey)) {\n throw new TypeError('Key must be a CryptoKey');\n }\n const normalizedAlgo = normalizeAlgorithm(algorithm);\n const normalizedDerivedAlgo = normalizeAlgorithm(derivedKeyAlgorithm);\n const keyId = await __crypto_subtle_deriveKey_ref.apply(undefined, [\n JSON.stringify(normalizedAlgo),\n baseKey._getKeyId(),\n JSON.stringify(normalizedDerivedAlgo),\n extractable,\n JSON.stringify(keyUsages)\n ], { result: { promise: true, copy: true } });\n return new CryptoKey(keyId, normalizedDerivedAlgo, extractable, keyUsages);\n } catch (err) {\n throw __decodeError(err);\n }\n }\n }\n };\n})();\n`;\n\n context.evalSync(cryptoCode);\n\n return {\n dispose() {\n // Clean up key storage for this context\n keyMap.clear();\n },\n };\n}\n"
5
+ "import ivm from \"@ricsam/isolated-vm\";\nimport crypto from \"node:crypto\";\n\nexport interface CryptoHandle {\n dispose(): void;\n}\n\n// Host-side key storage for crypto.subtle\nconst cryptoKeysByContext = new WeakMap<ivm.Context, Map<number, crypto.webcrypto.CryptoKey>>();\nlet nextKeyId = 1;\n\nfunction getKeyMapForContext(context: ivm.Context): Map<number, crypto.webcrypto.CryptoKey> {\n let map = cryptoKeysByContext.get(context);\n if (!map) {\n map = new Map();\n cryptoKeysByContext.set(context, map);\n }\n return map;\n}\n\nfunction deserializeAlgorithm(algorithm: Record<string, unknown>): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(algorithm)) {\n if (value && typeof value === 'object' && !Array.isArray(value) &&\n Object.keys(value).every(k => /^\\d+$/.test(k))) {\n // Convert {\"0\": n, \"1\": m, ...} back to Uint8Array\n const length = Object.keys(value).length;\n const arr = new Uint8Array(length);\n for (let i = 0; i < length; i++) {\n arr[i] = (value as Record<string, number>)[String(i)] ?? 0;\n }\n result[key] = arr;\n } else {\n result[key] = value;\n }\n }\n return result;\n}\n\n/**\n * Setup Web Crypto API in an isolated-vm context\n *\n * Provides crypto.getRandomValues and crypto.randomUUID\n *\n * @example\n * const handle = await setupCrypto(context);\n * await context.eval(`\n * const uuid = crypto.randomUUID();\n * const array = new Uint8Array(16);\n * crypto.getRandomValues(array);\n * `);\n */\nexport async function setupCrypto(\n context: ivm.Context\n): Promise<CryptoHandle> {\n const global = context.global;\n\n // Register host callbacks\n global.setSync(\n \"__crypto_randomUUID\",\n new ivm.Callback(() => {\n return crypto.randomUUID();\n })\n );\n\n global.setSync(\n \"__crypto_getRandomValues\",\n new ivm.Callback((byteLength: number) => {\n const buffer = Buffer.alloc(byteLength);\n crypto.randomFillSync(buffer);\n return Array.from(buffer);\n })\n );\n\n // Get key map for this context\n const keyMap = getKeyMapForContext(context);\n\n // crypto.subtle.importKey - async reference\n const importKeyRef = new ivm.Reference(\n async (\n format: string,\n keyDataJson: string,\n algorithmJson: string,\n extractable: boolean,\n keyUsagesJson: string\n ) => {\n const keyData = JSON.parse(keyDataJson) as number[];\n const algorithm = JSON.parse(algorithmJson);\n const keyUsages = JSON.parse(keyUsagesJson) as crypto.webcrypto.KeyUsage[];\n\n try {\n let cryptoKey: crypto.webcrypto.CryptoKey;\n if (format === \"raw\") {\n const importData = new Uint8Array(keyData);\n cryptoKey = await crypto.webcrypto.subtle.importKey(\n \"raw\",\n importData,\n algorithm,\n extractable,\n keyUsages\n );\n } else if (format === \"jwk\") {\n const importData = keyData as unknown as crypto.webcrypto.JsonWebKey;\n cryptoKey = await crypto.webcrypto.subtle.importKey(\n \"jwk\",\n importData,\n algorithm,\n extractable,\n keyUsages\n );\n } else {\n throw new Error(`[NotSupportedError]Unsupported key format: ${format}`);\n }\n\n // Store key on host and return ID\n const keyId = nextKeyId++;\n keyMap.set(keyId, cryptoKey);\n return keyId;\n } catch (err) {\n if (err instanceof Error) {\n throw new Error(`[${err.name}]${err.message}`);\n }\n throw err;\n }\n }\n );\n global.setSync(\"__crypto_subtle_importKey_ref\", importKeyRef);\n\n // crypto.subtle.sign - async reference\n const signRef = new ivm.Reference(\n async (algorithmJson: string, keyId: number, dataJson: string) => {\n const algorithm = JSON.parse(algorithmJson);\n const data = new Uint8Array(JSON.parse(dataJson) as number[]);\n\n const cryptoKey = keyMap.get(keyId);\n if (!cryptoKey) {\n throw new Error(\"[InvalidAccessError]Key not found\");\n }\n\n try {\n const signature = await crypto.webcrypto.subtle.sign(\n algorithm,\n cryptoKey,\n data\n );\n return JSON.stringify(Array.from(new Uint8Array(signature)));\n } catch (err) {\n if (err instanceof Error) {\n throw new Error(`[${err.name}]${err.message}`);\n }\n throw err;\n }\n }\n );\n global.setSync(\"__crypto_subtle_sign_ref\", signRef);\n\n // crypto.subtle.verify - async reference\n const verifyRef = new ivm.Reference(\n async (\n algorithmJson: string,\n keyId: number,\n signatureJson: string,\n dataJson: string\n ) => {\n const algorithm = JSON.parse(algorithmJson);\n const signature = new Uint8Array(JSON.parse(signatureJson) as number[]);\n const data = new Uint8Array(JSON.parse(dataJson) as number[]);\n\n const cryptoKey = keyMap.get(keyId);\n if (!cryptoKey) {\n throw new Error(\"[InvalidAccessError]Key not found\");\n }\n\n try {\n return await crypto.webcrypto.subtle.verify(\n algorithm,\n cryptoKey,\n signature,\n data\n );\n } catch (err) {\n if (err instanceof Error) {\n throw new Error(`[${err.name}]${err.message}`);\n }\n throw err;\n }\n }\n );\n global.setSync(\"__crypto_subtle_verify_ref\", verifyRef);\n\n // crypto.subtle.digest - async reference\n const digestRef = new ivm.Reference(\n async (algorithmJson: string, dataJson: string) => {\n const algorithm = JSON.parse(algorithmJson);\n const data = new Uint8Array(JSON.parse(dataJson) as number[]);\n\n try {\n const hash = await crypto.webcrypto.subtle.digest(algorithm, data);\n return JSON.stringify(Array.from(new Uint8Array(hash)));\n } catch (err) {\n if (err instanceof Error) {\n throw new Error(`[${err.name}]${err.message}`);\n }\n throw err;\n }\n }\n );\n global.setSync(\"__crypto_subtle_digest_ref\", digestRef);\n\n // crypto.subtle.deriveBits - async reference\n const deriveBitsRef = new ivm.Reference(\n async (algorithmJson: string, keyId: number, length: number) => {\n const algorithm = deserializeAlgorithm(JSON.parse(algorithmJson));\n\n const cryptoKey = keyMap.get(keyId);\n if (!cryptoKey) {\n throw new Error(\"[InvalidAccessError]Key not found\");\n }\n\n try {\n const bits = await crypto.webcrypto.subtle.deriveBits(\n algorithm as unknown as crypto.webcrypto.EcdhKeyDeriveParams | crypto.webcrypto.HkdfParams | crypto.webcrypto.Pbkdf2Params,\n cryptoKey,\n length\n );\n return JSON.stringify(Array.from(new Uint8Array(bits)));\n } catch (err) {\n if (err instanceof Error) {\n throw new Error(`[${err.name}]${err.message}`);\n }\n throw err;\n }\n }\n );\n global.setSync(\"__crypto_subtle_deriveBits_ref\", deriveBitsRef);\n\n // crypto.subtle.deriveKey - async reference\n const deriveKeyRef = new ivm.Reference(\n async (\n algorithmJson: string,\n baseKeyId: number,\n derivedKeyAlgorithmJson: string,\n extractable: boolean,\n keyUsagesJson: string\n ) => {\n const algorithm = deserializeAlgorithm(JSON.parse(algorithmJson));\n const derivedKeyAlgorithm = JSON.parse(derivedKeyAlgorithmJson);\n const keyUsages = JSON.parse(keyUsagesJson) as crypto.webcrypto.KeyUsage[];\n\n const baseKey = keyMap.get(baseKeyId);\n if (!baseKey) {\n throw new Error(\"[InvalidAccessError]Key not found\");\n }\n\n try {\n const derivedKey = await crypto.webcrypto.subtle.deriveKey(\n algorithm as unknown as crypto.webcrypto.EcdhKeyDeriveParams | crypto.webcrypto.HkdfParams | crypto.webcrypto.Pbkdf2Params,\n baseKey,\n derivedKeyAlgorithm,\n extractable,\n keyUsages\n );\n\n // Store derived key on host and return ID\n const keyId = nextKeyId++;\n keyMap.set(keyId, derivedKey);\n return keyId;\n } catch (err) {\n if (err instanceof Error) {\n throw new Error(`[${err.name}]${err.message}`);\n }\n throw err;\n }\n }\n );\n global.setSync(\"__crypto_subtle_deriveKey_ref\", deriveKeyRef);\n\n // Inject the crypto object into the isolate\n const cryptoCode = `\n(function() {\n // DOMException polyfill (Pattern #12)\n if (typeof DOMException === 'undefined') {\n globalThis.DOMException = class DOMException extends Error {\n constructor(message, name) {\n super(message);\n this.name = name || 'DOMException';\n }\n };\n }\n\n // Helper to decode error from host\n function __decodeError(err) {\n if (!(err instanceof Error)) return err;\n const match = err.message.match(/^\\\\[(TypeError|RangeError|NotSupportedError|InvalidAccessError|OperationError|DataError|Error)\\\\](.*)$/);\n if (match) {\n if (['NotSupportedError', 'InvalidAccessError', 'OperationError', 'DataError'].includes(match[1])) {\n return new DOMException(match[2], match[1]);\n }\n const ErrorType = globalThis[match[1]] || Error;\n return new ErrorType(match[2]);\n }\n return err;\n }\n\n // CryptoKey class to wrap key IDs\n const _cryptoKeyIds = new WeakMap();\n\n class CryptoKey {\n constructor(keyId, algorithm, extractable, usages, type) {\n _cryptoKeyIds.set(this, keyId);\n this._algorithm = algorithm;\n this._extractable = extractable;\n this._usages = usages;\n this._type = type || 'secret';\n }\n\n _getKeyId() {\n return _cryptoKeyIds.get(this);\n }\n\n get algorithm() {\n return this._algorithm;\n }\n\n get extractable() {\n return this._extractable;\n }\n\n get usages() {\n return [...this._usages];\n }\n\n get type() {\n return this._type;\n }\n }\n\n globalThis.CryptoKey = CryptoKey;\n\n // Helper to convert data to byte array\n function toByteArray(data) {\n if (typeof data === 'string') {\n return Array.from(new TextEncoder().encode(data));\n }\n if (data instanceof ArrayBuffer) {\n return Array.from(new Uint8Array(data));\n }\n if (ArrayBuffer.isView(data)) {\n return Array.from(new Uint8Array(data.buffer, data.byteOffset, data.byteLength));\n }\n throw new TypeError('Data must be a BufferSource');\n }\n\n // Normalize algorithm to object form\n function normalizeAlgorithm(algorithm) {\n if (typeof algorithm === 'string') {\n return { name: algorithm };\n }\n return algorithm;\n }\n\n globalThis.crypto = {\n randomUUID() {\n return __crypto_randomUUID();\n },\n\n getRandomValues(typedArray) {\n // Validate input is an integer TypedArray\n if (!(typedArray instanceof Int8Array ||\n typedArray instanceof Uint8Array ||\n typedArray instanceof Uint8ClampedArray ||\n typedArray instanceof Int16Array ||\n typedArray instanceof Uint16Array ||\n typedArray instanceof Int32Array ||\n typedArray instanceof Uint32Array ||\n typedArray instanceof BigInt64Array ||\n typedArray instanceof BigUint64Array)) {\n throw new TypeError(\"Argument 1 must be an integer typed array\");\n }\n\n const byteLength = typedArray.byteLength;\n if (byteLength > 65536) {\n throw new DOMException(\n \"The ArrayBufferView's byte length exceeds the number of bytes of entropy available via this API (65536)\",\n \"QuotaExceededError\"\n );\n }\n\n // Get random bytes from host\n const bytes = __crypto_getRandomValues(byteLength);\n\n // Copy bytes into the TypedArray\n const view = new Uint8Array(typedArray.buffer, typedArray.byteOffset, typedArray.byteLength);\n for (let i = 0; i < bytes.length; i++) {\n view[i] = bytes[i];\n }\n\n return typedArray;\n },\n\n subtle: {\n async importKey(format, keyData, algorithm, extractable, keyUsages) {\n try {\n const normalizedAlgo = normalizeAlgorithm(algorithm);\n let keyDataJson;\n\n if (format === 'raw') {\n keyDataJson = JSON.stringify(toByteArray(keyData));\n } else if (format === 'jwk') {\n keyDataJson = JSON.stringify(keyData);\n } else {\n throw new DOMException('Unsupported key format: ' + format, 'NotSupportedError');\n }\n\n const keyId = await __crypto_subtle_importKey_ref.apply(undefined, [\n format,\n keyDataJson,\n JSON.stringify(normalizedAlgo),\n extractable,\n JSON.stringify(keyUsages)\n ], { result: { promise: true, copy: true } });\n\n return new CryptoKey(keyId, normalizedAlgo, extractable, keyUsages);\n } catch (err) {\n throw __decodeError(err);\n }\n },\n\n async sign(algorithm, key, data) {\n try {\n if (!(key instanceof CryptoKey)) {\n throw new TypeError('Key must be a CryptoKey');\n }\n const normalizedAlgo = normalizeAlgorithm(algorithm);\n const signatureBytesJson = await __crypto_subtle_sign_ref.apply(undefined, [\n JSON.stringify(normalizedAlgo),\n key._getKeyId(),\n JSON.stringify(toByteArray(data))\n ], { result: { promise: true, copy: true } });\n const signatureBytes = JSON.parse(signatureBytesJson);\n return new Uint8Array(signatureBytes).buffer;\n } catch (err) {\n throw __decodeError(err);\n }\n },\n\n async verify(algorithm, key, signature, data) {\n try {\n if (!(key instanceof CryptoKey)) {\n throw new TypeError('Key must be a CryptoKey');\n }\n const normalizedAlgo = normalizeAlgorithm(algorithm);\n return await __crypto_subtle_verify_ref.apply(undefined, [\n JSON.stringify(normalizedAlgo),\n key._getKeyId(),\n JSON.stringify(toByteArray(signature)),\n JSON.stringify(toByteArray(data))\n ], { result: { promise: true, copy: true } });\n } catch (err) {\n throw __decodeError(err);\n }\n },\n\n async digest(algorithm, data) {\n try {\n const normalizedAlgo = normalizeAlgorithm(algorithm);\n const hashBytesJson = await __crypto_subtle_digest_ref.apply(undefined, [\n JSON.stringify(normalizedAlgo),\n JSON.stringify(toByteArray(data))\n ], { result: { promise: true, copy: true } });\n const hashBytes = JSON.parse(hashBytesJson);\n return new Uint8Array(hashBytes).buffer;\n } catch (err) {\n throw __decodeError(err);\n }\n },\n\n async deriveBits(algorithm, baseKey, length) {\n try {\n if (!(baseKey instanceof CryptoKey)) {\n throw new TypeError('Key must be a CryptoKey');\n }\n const normalizedAlgo = normalizeAlgorithm(algorithm);\n const bitsBytesJson = await __crypto_subtle_deriveBits_ref.apply(undefined, [\n JSON.stringify(normalizedAlgo),\n baseKey._getKeyId(),\n length\n ], { result: { promise: true, copy: true } });\n const bitsBytes = JSON.parse(bitsBytesJson);\n return new Uint8Array(bitsBytes).buffer;\n } catch (err) {\n throw __decodeError(err);\n }\n },\n\n async deriveKey(algorithm, baseKey, derivedKeyAlgorithm, extractable, keyUsages) {\n try {\n if (!(baseKey instanceof CryptoKey)) {\n throw new TypeError('Key must be a CryptoKey');\n }\n const normalizedAlgo = normalizeAlgorithm(algorithm);\n const normalizedDerivedAlgo = normalizeAlgorithm(derivedKeyAlgorithm);\n const keyId = await __crypto_subtle_deriveKey_ref.apply(undefined, [\n JSON.stringify(normalizedAlgo),\n baseKey._getKeyId(),\n JSON.stringify(normalizedDerivedAlgo),\n extractable,\n JSON.stringify(keyUsages)\n ], { result: { promise: true, copy: true } });\n return new CryptoKey(keyId, normalizedDerivedAlgo, extractable, keyUsages);\n } catch (err) {\n throw __decodeError(err);\n }\n }\n }\n };\n})();\n`;\n\n context.evalSync(cryptoCode);\n\n return {\n dispose() {\n // Clean up key storage for this context\n keyMap.clear();\n },\n };\n}\n"
6
6
  ],
7
7
  "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAgB,IAAhB;AACmB,IAAnB;AAOA,IAAM,sBAAsB,IAAI;AAChC,IAAI,YAAY;AAEhB,SAAS,mBAAmB,CAAC,SAA+D;AAAA,EAC1F,IAAI,MAAM,oBAAoB,IAAI,OAAO;AAAA,EACzC,IAAI,CAAC,KAAK;AAAA,IACR,MAAM,IAAI;AAAA,IACV,oBAAoB,IAAI,SAAS,GAAG;AAAA,EACtC;AAAA,EACA,OAAO;AAAA;AAGT,SAAS,oBAAoB,CAAC,WAA6D;AAAA,EACzF,MAAM,SAAkC,CAAC;AAAA,EACzC,YAAY,KAAK,UAAU,OAAO,QAAQ,SAAS,GAAG;AAAA,IACpD,IAAI,SAAS,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,KAC1D,OAAO,KAAK,KAAK,EAAE,MAAM,OAAK,QAAQ,KAAK,CAAC,CAAC,GAAG;AAAA,MAElD,MAAM,SAAS,OAAO,KAAK,KAAK,EAAE;AAAA,MAClC,MAAM,MAAM,IAAI,WAAW,MAAM;AAAA,MACjC,SAAS,IAAI,EAAG,IAAI,QAAQ,KAAK;AAAA,QAC/B,IAAI,KAAM,MAAiC,OAAO,CAAC,MAAM;AAAA,MAC3D;AAAA,MACA,OAAO,OAAO;AAAA,IAChB,EAAO;AAAA,MACL,OAAO,OAAO;AAAA;AAAA,EAElB;AAAA,EACA,OAAO;AAAA;AAgBT,eAAsB,WAAW,CAC/B,SACuB;AAAA,EACvB,MAAM,SAAS,QAAQ;AAAA,EAGvB,OAAO,QACL,uBACA,IAAI,2BAAI,SAAS,MAAM;AAAA,IACrB,OAAO,2BAAO,WAAW;AAAA,GAC1B,CACH;AAAA,EAEA,OAAO,QACL,4BACA,IAAI,2BAAI,SAAS,CAAC,eAAuB;AAAA,IACvC,MAAM,SAAS,OAAO,MAAM,UAAU;AAAA,IACtC,2BAAO,eAAe,MAAM;AAAA,IAC5B,OAAO,MAAM,KAAK,MAAM;AAAA,GACzB,CACH;AAAA,EAGA,MAAM,SAAS,oBAAoB,OAAO;AAAA,EAG1C,MAAM,eAAe,IAAI,2BAAI,UAC3B,OACE,QACA,aACA,eACA,aACA,kBACG;AAAA,IACH,MAAM,UAAU,KAAK,MAAM,WAAW;AAAA,IACtC,MAAM,YAAY,KAAK,MAAM,aAAa;AAAA,IAC1C,MAAM,YAAY,KAAK,MAAM,aAAa;AAAA,IAE1C,IAAI;AAAA,MACF,IAAI;AAAA,MACJ,IAAI,WAAW,OAAO;AAAA,QACpB,MAAM,aAAa,IAAI,WAAW,OAAO;AAAA,QACzC,YAAY,MAAM,2BAAO,UAAU,OAAO,UACxC,OACA,YACA,WACA,aACA,SACF;AAAA,MACF,EAAO,SAAI,WAAW,OAAO;AAAA,QAC3B,MAAM,aAAa;AAAA,QACnB,YAAY,MAAM,2BAAO,UAAU,OAAO,UACxC,OACA,YACA,WACA,aACA,SACF;AAAA,MACF,EAAO;AAAA,QACL,MAAM,IAAI,MAAM,8CAA8C,QAAQ;AAAA;AAAA,MAIxE,MAAM,QAAQ;AAAA,MACd,OAAO,IAAI,OAAO,SAAS;AAAA,MAC3B,OAAO;AAAA,MACP,OAAO,KAAK;AAAA,MACZ,IAAI,eAAe,OAAO;AAAA,QACxB,MAAM,IAAI,MAAM,IAAI,IAAI,QAAQ,IAAI,SAAS;AAAA,MAC/C;AAAA,MACA,MAAM;AAAA;AAAA,GAGZ;AAAA,EACA,OAAO,QAAQ,iCAAiC,YAAY;AAAA,EAG5D,MAAM,UAAU,IAAI,2BAAI,UACtB,OAAO,eAAuB,OAAe,aAAqB;AAAA,IAChE,MAAM,YAAY,KAAK,MAAM,aAAa;AAAA,IAC1C,MAAM,OAAO,IAAI,WAAW,KAAK,MAAM,QAAQ,CAAa;AAAA,IAE5D,MAAM,YAAY,OAAO,IAAI,KAAK;AAAA,IAClC,IAAI,CAAC,WAAW;AAAA,MACd,MAAM,IAAI,MAAM,mCAAmC;AAAA,IACrD;AAAA,IAEA,IAAI;AAAA,MACF,MAAM,YAAY,MAAM,2BAAO,UAAU,OAAO,KAC9C,WACA,WACA,IACF;AAAA,MACA,OAAO,KAAK,UAAU,MAAM,KAAK,IAAI,WAAW,SAAS,CAAC,CAAC;AAAA,MAC3D,OAAO,KAAK;AAAA,MACZ,IAAI,eAAe,OAAO;AAAA,QACxB,MAAM,IAAI,MAAM,IAAI,IAAI,QAAQ,IAAI,SAAS;AAAA,MAC/C;AAAA,MACA,MAAM;AAAA;AAAA,GAGZ;AAAA,EACA,OAAO,QAAQ,4BAA4B,OAAO;AAAA,EAGlD,MAAM,YAAY,IAAI,2BAAI,UACxB,OACE,eACA,OACA,eACA,aACG;AAAA,IACH,MAAM,YAAY,KAAK,MAAM,aAAa;AAAA,IAC1C,MAAM,YAAY,IAAI,WAAW,KAAK,MAAM,aAAa,CAAa;AAAA,IACtE,MAAM,OAAO,IAAI,WAAW,KAAK,MAAM,QAAQ,CAAa;AAAA,IAE5D,MAAM,YAAY,OAAO,IAAI,KAAK;AAAA,IAClC,IAAI,CAAC,WAAW;AAAA,MACd,MAAM,IAAI,MAAM,mCAAmC;AAAA,IACrD;AAAA,IAEA,IAAI;AAAA,MACF,OAAO,MAAM,2BAAO,UAAU,OAAO,OACnC,WACA,WACA,WACA,IACF;AAAA,MACA,OAAO,KAAK;AAAA,MACZ,IAAI,eAAe,OAAO;AAAA,QACxB,MAAM,IAAI,MAAM,IAAI,IAAI,QAAQ,IAAI,SAAS;AAAA,MAC/C;AAAA,MACA,MAAM;AAAA;AAAA,GAGZ;AAAA,EACA,OAAO,QAAQ,8BAA8B,SAAS;AAAA,EAGtD,MAAM,YAAY,IAAI,2BAAI,UACxB,OAAO,eAAuB,aAAqB;AAAA,IACjD,MAAM,YAAY,KAAK,MAAM,aAAa;AAAA,IAC1C,MAAM,OAAO,IAAI,WAAW,KAAK,MAAM,QAAQ,CAAa;AAAA,IAE5D,IAAI;AAAA,MACF,MAAM,OAAO,MAAM,2BAAO,UAAU,OAAO,OAAO,WAAW,IAAI;AAAA,MACjE,OAAO,KAAK,UAAU,MAAM,KAAK,IAAI,WAAW,IAAI,CAAC,CAAC;AAAA,MACtD,OAAO,KAAK;AAAA,MACZ,IAAI,eAAe,OAAO;AAAA,QACxB,MAAM,IAAI,MAAM,IAAI,IAAI,QAAQ,IAAI,SAAS;AAAA,MAC/C;AAAA,MACA,MAAM;AAAA;AAAA,GAGZ;AAAA,EACA,OAAO,QAAQ,8BAA8B,SAAS;AAAA,EAGtD,MAAM,gBAAgB,IAAI,2BAAI,UAC5B,OAAO,eAAuB,OAAe,WAAmB;AAAA,IAC9D,MAAM,YAAY,qBAAqB,KAAK,MAAM,aAAa,CAAC;AAAA,IAEhE,MAAM,YAAY,OAAO,IAAI,KAAK;AAAA,IAClC,IAAI,CAAC,WAAW;AAAA,MACd,MAAM,IAAI,MAAM,mCAAmC;AAAA,IACrD;AAAA,IAEA,IAAI;AAAA,MACF,MAAM,OAAO,MAAM,2BAAO,UAAU,OAAO,WACzC,WACA,WACA,MACF;AAAA,MACA,OAAO,KAAK,UAAU,MAAM,KAAK,IAAI,WAAW,IAAI,CAAC,CAAC;AAAA,MACtD,OAAO,KAAK;AAAA,MACZ,IAAI,eAAe,OAAO;AAAA,QACxB,MAAM,IAAI,MAAM,IAAI,IAAI,QAAQ,IAAI,SAAS;AAAA,MAC/C;AAAA,MACA,MAAM;AAAA;AAAA,GAGZ;AAAA,EACA,OAAO,QAAQ,kCAAkC,aAAa;AAAA,EAG9D,MAAM,eAAe,IAAI,2BAAI,UAC3B,OACE,eACA,WACA,yBACA,aACA,kBACG;AAAA,IACH,MAAM,YAAY,qBAAqB,KAAK,MAAM,aAAa,CAAC;AAAA,IAChE,MAAM,sBAAsB,KAAK,MAAM,uBAAuB;AAAA,IAC9D,MAAM,YAAY,KAAK,MAAM,aAAa;AAAA,IAE1C,MAAM,UAAU,OAAO,IAAI,SAAS;AAAA,IACpC,IAAI,CAAC,SAAS;AAAA,MACZ,MAAM,IAAI,MAAM,mCAAmC;AAAA,IACrD;AAAA,IAEA,IAAI;AAAA,MACF,MAAM,aAAa,MAAM,2BAAO,UAAU,OAAO,UAC/C,WACA,SACA,qBACA,aACA,SACF;AAAA,MAGA,MAAM,QAAQ;AAAA,MACd,OAAO,IAAI,OAAO,UAAU;AAAA,MAC5B,OAAO;AAAA,MACP,OAAO,KAAK;AAAA,MACZ,IAAI,eAAe,OAAO;AAAA,QACxB,MAAM,IAAI,MAAM,IAAI,IAAI,QAAQ,IAAI,SAAS;AAAA,MAC/C;AAAA,MACA,MAAM;AAAA;AAAA,GAGZ;AAAA,EACA,OAAO,QAAQ,iCAAiC,YAAY;AAAA,EAG5D,MAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiPnB,QAAQ,SAAS,UAAU;AAAA,EAE3B,OAAO;AAAA,IACL,OAAO,GAAG;AAAA,MAER,OAAO,MAAM;AAAA;AAAA,EAEjB;AAAA;",
8
- "debugId": "7B5ADA3029912B4064756E2164756E21",
8
+ "debugId": "1177B61C32157E2F64756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -102,6 +102,7 @@ function handleConnection(socket, state) {
102
102
  pendingCallbacks: new Map,
103
103
  nextRequestId: 1,
104
104
  nextCallbackId: 1,
105
+ nextLocalCallbackId: 1e6,
105
106
  nextStreamId: 1,
106
107
  activeStreams: new Map,
107
108
  streamReceivers: new Map,
@@ -216,6 +217,9 @@ async function handleMessage(message, connection, state) {
216
217
  case import_protocol.MessageType.CALLBACK_RESPONSE:
217
218
  handleCallbackResponse(message, connection);
218
219
  break;
220
+ case import_protocol.MessageType.CALLBACK_INVOKE:
221
+ await handleCallbackInvoke(message, connection, state);
222
+ break;
219
223
  case import_protocol.MessageType.WS_OPEN:
220
224
  await handleWsOpen(message, connection, state);
221
225
  break;
@@ -629,19 +633,26 @@ async function handleCreateRuntime(message, connection, state) {
629
633
  let bridgedCustomFunctions;
630
634
  let customFnMarshalOptions;
631
635
  if (customCallbacks) {
636
+ const allocateLocalCallbackId = () => {
637
+ const currentConnection = callbackContext.connection;
638
+ if (!currentConnection) {
639
+ throw new Error("Cannot register callback without an active client connection");
640
+ }
641
+ return currentConnection.nextLocalCallbackId++;
642
+ };
632
643
  const createMarshalContext = () => ({
633
644
  registerCallback: (fn) => {
634
- const callbackId = instance.nextLocalCallbackId++;
645
+ const callbackId = allocateLocalCallbackId();
635
646
  instance.returnedCallbacks.set(callbackId, fn);
636
647
  return callbackId;
637
648
  },
638
649
  registerPromise: (promise) => {
639
- const promiseId = instance.nextLocalCallbackId++;
650
+ const promiseId = allocateLocalCallbackId();
640
651
  instance.returnedPromises.set(promiseId, promise);
641
652
  return promiseId;
642
653
  },
643
654
  registerIterator: (iterator) => {
644
- const iteratorId = instance.nextLocalCallbackId++;
655
+ const iteratorId = allocateLocalCallbackId();
645
656
  instance.returnedIterators.set(iteratorId, iterator);
646
657
  return iteratorId;
647
658
  }
@@ -652,7 +663,7 @@ async function handleCreateRuntime(message, connection, state) {
652
663
  if (import_protocol.isPromiseRef(value)) {
653
664
  if ("__resolveCallbackId" in value)
654
665
  return value;
655
- const resolveCallbackId = instance.nextLocalCallbackId++;
666
+ const resolveCallbackId = allocateLocalCallbackId();
656
667
  instance.returnedCallbacks.set(resolveCallbackId, async (promiseId) => {
657
668
  const promise = instance.returnedPromises.get(promiseId);
658
669
  if (!promise)
@@ -668,7 +679,7 @@ async function handleCreateRuntime(message, connection, state) {
668
679
  if (import_protocol.isAsyncIteratorRef(value)) {
669
680
  if ("__nextCallbackId" in value)
670
681
  return value;
671
- const nextCallbackId = instance.nextLocalCallbackId++;
682
+ const nextCallbackId = allocateLocalCallbackId();
672
683
  instance.returnedCallbacks.set(nextCallbackId, async (iteratorId) => {
673
684
  const iterator = instance.returnedIterators.get(iteratorId);
674
685
  if (!iterator)
@@ -680,7 +691,7 @@ async function handleCreateRuntime(message, connection, state) {
680
691
  const marshalledValue = await import_protocol.marshalValue(result2.value, ctx);
681
692
  return { done: result2.done, value: addCallbackIdsToRefs(marshalledValue) };
682
693
  });
683
- const returnCallbackId = instance.nextLocalCallbackId++;
694
+ const returnCallbackId = allocateLocalCallbackId();
684
695
  instance.returnedCallbacks.set(returnCallbackId, async (iteratorId, returnValue) => {
685
696
  const iterator = instance.returnedIterators.get(iteratorId);
686
697
  instance.returnedIterators.delete(iteratorId);
@@ -691,7 +702,7 @@ async function handleCreateRuntime(message, connection, state) {
691
702
  const marshalledValue = await import_protocol.marshalValue(result2.value, ctx);
692
703
  return { done: true, value: addCallbackIdsToRefs(marshalledValue) };
693
704
  });
694
- const throwCallbackId = instance.nextLocalCallbackId++;
705
+ const throwCallbackId = allocateLocalCallbackId();
695
706
  instance.returnedCallbacks.set(throwCallbackId, async (iteratorId, errorValue) => {
696
707
  const iterator = instance.returnedIterators.get(iteratorId);
697
708
  if (!iterator) {
@@ -730,6 +741,11 @@ async function handleCreateRuntime(message, connection, state) {
730
741
  return result;
731
742
  };
732
743
  const LOCAL_CALLBACK_THRESHOLD = 1e6;
744
+ const marshalArgsForClient = async (args) => {
745
+ const ctx = createMarshalContext();
746
+ const marshalledArgs = await import_protocol.marshalValue(args, ctx);
747
+ return addCallbackIdsToRefs(marshalledArgs);
748
+ };
733
749
  const invokeCallback = async (callbackId, args) => {
734
750
  if (callbackId >= LOCAL_CALLBACK_THRESHOLD) {
735
751
  const callback = instance.returnedCallbacks.get(callbackId);
@@ -739,14 +755,15 @@ async function handleCreateRuntime(message, connection, state) {
739
755
  return await callback(...args);
740
756
  } else {
741
757
  const conn = await waitForConnection(callbackContext);
758
+ const marshalledArgs = await marshalArgsForClient(args);
742
759
  try {
743
- return await invokeClientCallback(conn, callbackId, args, {
760
+ return await invokeClientCallback(conn, callbackId, marshalledArgs, {
744
761
  signal: getCurrentHostSignal(instance)
745
762
  });
746
763
  } catch (err) {
747
764
  if (callbackContext.reconnectionPromise && !callbackContext.connection) {
748
765
  const newConn = await callbackContext.reconnectionPromise.promise;
749
- return invokeClientCallback(newConn, callbackId, args, {
766
+ return invokeClientCallback(newConn, callbackId, marshalledArgs, {
750
767
  signal: getCurrentHostSignal(instance)
751
768
  });
752
769
  }
@@ -768,7 +785,8 @@ async function handleCreateRuntime(message, connection, state) {
768
785
  const nextCallbackId = callbackContext_.custom.get(`${name}:next`);
769
786
  const returnCallbackId = callbackContext_.custom.get(`${name}:return`);
770
787
  async function* bridgedIterator() {
771
- const startResult = await invokeCallbackWithReconnect(callbackContext_, () => callbackContext_.custom.get(`${name}:start`), args, `AsyncIterator '${name}' start`, invokeClientCallback, { signal: getCurrentHostSignal(instance) });
788
+ const marshalledArgs = await marshalArgsForClient(args);
789
+ const startResult = await invokeCallbackWithReconnect(callbackContext_, () => callbackContext_.custom.get(`${name}:start`), marshalledArgs, `AsyncIterator '${name}' start`, invokeClientCallback, { signal: getCurrentHostSignal(instance) });
772
790
  const iteratorId = startResult.iteratorId;
773
791
  try {
774
792
  while (true) {
@@ -794,7 +812,8 @@ async function handleCreateRuntime(message, connection, state) {
794
812
  bridgedCustomFunctions[name] = {
795
813
  type: registration.type,
796
814
  fn: async (...args) => {
797
- return invokeCallbackWithReconnect(callbackContext_, () => callbackContext_.custom.get(name), args, `Custom function '${name}'`, invokeClientCallback, { signal: getCurrentHostSignal(instance) });
815
+ const marshalledArgs = await marshalArgsForClient(args);
816
+ return invokeCallbackWithReconnect(callbackContext_, () => callbackContext_.custom.get(name), marshalledArgs, `Custom function '${name}'`, invokeClientCallback, { signal: getCurrentHostSignal(instance) });
798
817
  }
799
818
  };
800
819
  }
@@ -1454,6 +1473,52 @@ function handleCallbackResponse(message, connection) {
1454
1473
  pending.resolve(message.result);
1455
1474
  }
1456
1475
  }
1476
+ async function handleCallbackInvoke(message, connection, state) {
1477
+ const response = {
1478
+ type: import_protocol.MessageType.CALLBACK_RESPONSE,
1479
+ requestId: message.requestId
1480
+ };
1481
+ let instance;
1482
+ for (const isolateId of connection.isolates) {
1483
+ const candidate = state.isolates.get(isolateId);
1484
+ if (candidate?.returnedCallbacks?.has(message.callbackId)) {
1485
+ instance = candidate;
1486
+ break;
1487
+ }
1488
+ }
1489
+ if (!instance) {
1490
+ response.error = {
1491
+ name: "Error",
1492
+ message: `Unknown callback: ${message.callbackId}`
1493
+ };
1494
+ sendMessage(connection.socket, response);
1495
+ return;
1496
+ }
1497
+ instance.lastActivity = Date.now();
1498
+ const callback = instance.returnedCallbacks.get(message.callbackId);
1499
+ if (!callback) {
1500
+ response.error = {
1501
+ name: "Error",
1502
+ message: `Unknown callback: ${message.callbackId}`
1503
+ };
1504
+ sendMessage(connection.socket, response);
1505
+ return;
1506
+ }
1507
+ try {
1508
+ response.result = await requestContextStorage.run({
1509
+ ...message.context ?? {},
1510
+ signal: getCurrentHostSignal(instance)
1511
+ }, async () => await callback(...message.args));
1512
+ } catch (err) {
1513
+ const error = err;
1514
+ response.error = {
1515
+ name: error.name,
1516
+ message: error.message,
1517
+ stack: error.stack
1518
+ };
1519
+ }
1520
+ sendMessage(connection.socket, response);
1521
+ }
1457
1522
  async function invokeClientCallback(connection, callbackId, args, options) {
1458
1523
  const requestId = connection.nextCallbackId++;
1459
1524
  const timeoutMs = options?.timeoutMs ?? DEFAULT_CALLBACK_TIMEOUT_MS;
@@ -1949,4 +2014,4 @@ async function handleClearCollectedData(message, connection, state) {
1949
2014
  }
1950
2015
  }
1951
2016
 
1952
- //# debugId=16FDF3C30EC7DFD264756E2164756E21
2017
+ //# debugId=0C2C837A78ED90B564756E2164756E21