@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
@@ -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": "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",
8
- "debugId": "56846119A4CC968B64756E2164756E21",
8
+ "debugId": "0B21DFAE8F92325664756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -78,6 +78,7 @@ function handleConnection(socket, state) {
78
78
  pendingCallbacks: new Map,
79
79
  nextRequestId: 1,
80
80
  nextCallbackId: 1,
81
+ nextLocalCallbackId: 1e6,
81
82
  nextStreamId: 1,
82
83
  activeStreams: new Map,
83
84
  streamReceivers: new Map,
@@ -192,6 +193,9 @@ async function handleMessage(message, connection, state) {
192
193
  case MessageType.CALLBACK_RESPONSE:
193
194
  handleCallbackResponse(message, connection);
194
195
  break;
196
+ case MessageType.CALLBACK_INVOKE:
197
+ await handleCallbackInvoke(message, connection, state);
198
+ break;
195
199
  case MessageType.WS_OPEN:
196
200
  await handleWsOpen(message, connection, state);
197
201
  break;
@@ -605,19 +609,26 @@ async function handleCreateRuntime(message, connection, state) {
605
609
  let bridgedCustomFunctions;
606
610
  let customFnMarshalOptions;
607
611
  if (customCallbacks) {
612
+ const allocateLocalCallbackId = () => {
613
+ const currentConnection = callbackContext.connection;
614
+ if (!currentConnection) {
615
+ throw new Error("Cannot register callback without an active client connection");
616
+ }
617
+ return currentConnection.nextLocalCallbackId++;
618
+ };
608
619
  const createMarshalContext = () => ({
609
620
  registerCallback: (fn) => {
610
- const callbackId = instance.nextLocalCallbackId++;
621
+ const callbackId = allocateLocalCallbackId();
611
622
  instance.returnedCallbacks.set(callbackId, fn);
612
623
  return callbackId;
613
624
  },
614
625
  registerPromise: (promise) => {
615
- const promiseId = instance.nextLocalCallbackId++;
626
+ const promiseId = allocateLocalCallbackId();
616
627
  instance.returnedPromises.set(promiseId, promise);
617
628
  return promiseId;
618
629
  },
619
630
  registerIterator: (iterator) => {
620
- const iteratorId = instance.nextLocalCallbackId++;
631
+ const iteratorId = allocateLocalCallbackId();
621
632
  instance.returnedIterators.set(iteratorId, iterator);
622
633
  return iteratorId;
623
634
  }
@@ -628,7 +639,7 @@ async function handleCreateRuntime(message, connection, state) {
628
639
  if (isPromiseRef(value)) {
629
640
  if ("__resolveCallbackId" in value)
630
641
  return value;
631
- const resolveCallbackId = instance.nextLocalCallbackId++;
642
+ const resolveCallbackId = allocateLocalCallbackId();
632
643
  instance.returnedCallbacks.set(resolveCallbackId, async (promiseId) => {
633
644
  const promise = instance.returnedPromises.get(promiseId);
634
645
  if (!promise)
@@ -644,7 +655,7 @@ async function handleCreateRuntime(message, connection, state) {
644
655
  if (isAsyncIteratorRef(value)) {
645
656
  if ("__nextCallbackId" in value)
646
657
  return value;
647
- const nextCallbackId = instance.nextLocalCallbackId++;
658
+ const nextCallbackId = allocateLocalCallbackId();
648
659
  instance.returnedCallbacks.set(nextCallbackId, async (iteratorId) => {
649
660
  const iterator = instance.returnedIterators.get(iteratorId);
650
661
  if (!iterator)
@@ -656,7 +667,7 @@ async function handleCreateRuntime(message, connection, state) {
656
667
  const marshalledValue = await marshalValue(result2.value, ctx);
657
668
  return { done: result2.done, value: addCallbackIdsToRefs(marshalledValue) };
658
669
  });
659
- const returnCallbackId = instance.nextLocalCallbackId++;
670
+ const returnCallbackId = allocateLocalCallbackId();
660
671
  instance.returnedCallbacks.set(returnCallbackId, async (iteratorId, returnValue) => {
661
672
  const iterator = instance.returnedIterators.get(iteratorId);
662
673
  instance.returnedIterators.delete(iteratorId);
@@ -667,7 +678,7 @@ async function handleCreateRuntime(message, connection, state) {
667
678
  const marshalledValue = await marshalValue(result2.value, ctx);
668
679
  return { done: true, value: addCallbackIdsToRefs(marshalledValue) };
669
680
  });
670
- const throwCallbackId = instance.nextLocalCallbackId++;
681
+ const throwCallbackId = allocateLocalCallbackId();
671
682
  instance.returnedCallbacks.set(throwCallbackId, async (iteratorId, errorValue) => {
672
683
  const iterator = instance.returnedIterators.get(iteratorId);
673
684
  if (!iterator) {
@@ -706,6 +717,11 @@ async function handleCreateRuntime(message, connection, state) {
706
717
  return result;
707
718
  };
708
719
  const LOCAL_CALLBACK_THRESHOLD = 1e6;
720
+ const marshalArgsForClient = async (args) => {
721
+ const ctx = createMarshalContext();
722
+ const marshalledArgs = await marshalValue(args, ctx);
723
+ return addCallbackIdsToRefs(marshalledArgs);
724
+ };
709
725
  const invokeCallback = async (callbackId, args) => {
710
726
  if (callbackId >= LOCAL_CALLBACK_THRESHOLD) {
711
727
  const callback = instance.returnedCallbacks.get(callbackId);
@@ -715,14 +731,15 @@ async function handleCreateRuntime(message, connection, state) {
715
731
  return await callback(...args);
716
732
  } else {
717
733
  const conn = await waitForConnection(callbackContext);
734
+ const marshalledArgs = await marshalArgsForClient(args);
718
735
  try {
719
- return await invokeClientCallback(conn, callbackId, args, {
736
+ return await invokeClientCallback(conn, callbackId, marshalledArgs, {
720
737
  signal: getCurrentHostSignal(instance)
721
738
  });
722
739
  } catch (err) {
723
740
  if (callbackContext.reconnectionPromise && !callbackContext.connection) {
724
741
  const newConn = await callbackContext.reconnectionPromise.promise;
725
- return invokeClientCallback(newConn, callbackId, args, {
742
+ return invokeClientCallback(newConn, callbackId, marshalledArgs, {
726
743
  signal: getCurrentHostSignal(instance)
727
744
  });
728
745
  }
@@ -744,7 +761,8 @@ async function handleCreateRuntime(message, connection, state) {
744
761
  const nextCallbackId = callbackContext_.custom.get(`${name}:next`);
745
762
  const returnCallbackId = callbackContext_.custom.get(`${name}:return`);
746
763
  async function* bridgedIterator() {
747
- const startResult = await invokeCallbackWithReconnect(callbackContext_, () => callbackContext_.custom.get(`${name}:start`), args, `AsyncIterator '${name}' start`, invokeClientCallback, { signal: getCurrentHostSignal(instance) });
764
+ const marshalledArgs = await marshalArgsForClient(args);
765
+ const startResult = await invokeCallbackWithReconnect(callbackContext_, () => callbackContext_.custom.get(`${name}:start`), marshalledArgs, `AsyncIterator '${name}' start`, invokeClientCallback, { signal: getCurrentHostSignal(instance) });
748
766
  const iteratorId = startResult.iteratorId;
749
767
  try {
750
768
  while (true) {
@@ -770,7 +788,8 @@ async function handleCreateRuntime(message, connection, state) {
770
788
  bridgedCustomFunctions[name] = {
771
789
  type: registration.type,
772
790
  fn: async (...args) => {
773
- return invokeCallbackWithReconnect(callbackContext_, () => callbackContext_.custom.get(name), args, `Custom function '${name}'`, invokeClientCallback, { signal: getCurrentHostSignal(instance) });
791
+ const marshalledArgs = await marshalArgsForClient(args);
792
+ return invokeCallbackWithReconnect(callbackContext_, () => callbackContext_.custom.get(name), marshalledArgs, `Custom function '${name}'`, invokeClientCallback, { signal: getCurrentHostSignal(instance) });
774
793
  }
775
794
  };
776
795
  }
@@ -1430,6 +1449,52 @@ function handleCallbackResponse(message, connection) {
1430
1449
  pending.resolve(message.result);
1431
1450
  }
1432
1451
  }
1452
+ async function handleCallbackInvoke(message, connection, state) {
1453
+ const response = {
1454
+ type: MessageType.CALLBACK_RESPONSE,
1455
+ requestId: message.requestId
1456
+ };
1457
+ let instance;
1458
+ for (const isolateId of connection.isolates) {
1459
+ const candidate = state.isolates.get(isolateId);
1460
+ if (candidate?.returnedCallbacks?.has(message.callbackId)) {
1461
+ instance = candidate;
1462
+ break;
1463
+ }
1464
+ }
1465
+ if (!instance) {
1466
+ response.error = {
1467
+ name: "Error",
1468
+ message: `Unknown callback: ${message.callbackId}`
1469
+ };
1470
+ sendMessage(connection.socket, response);
1471
+ return;
1472
+ }
1473
+ instance.lastActivity = Date.now();
1474
+ const callback = instance.returnedCallbacks.get(message.callbackId);
1475
+ if (!callback) {
1476
+ response.error = {
1477
+ name: "Error",
1478
+ message: `Unknown callback: ${message.callbackId}`
1479
+ };
1480
+ sendMessage(connection.socket, response);
1481
+ return;
1482
+ }
1483
+ try {
1484
+ response.result = await requestContextStorage.run({
1485
+ ...message.context ?? {},
1486
+ signal: getCurrentHostSignal(instance)
1487
+ }, async () => await callback(...message.args));
1488
+ } catch (err) {
1489
+ const error = err;
1490
+ response.error = {
1491
+ name: error.name,
1492
+ message: error.message,
1493
+ stack: error.stack
1494
+ };
1495
+ }
1496
+ sendMessage(connection.socket, response);
1497
+ }
1433
1498
  async function invokeClientCallback(connection, callbackId, args, options) {
1434
1499
  const requestId = connection.nextCallbackId++;
1435
1500
  const timeoutMs = options?.timeoutMs ?? DEFAULT_CALLBACK_TIMEOUT_MS;
@@ -1928,4 +1993,4 @@ export {
1928
1993
  handleConnection
1929
1994
  };
1930
1995
 
1931
- //# debugId=821596E06E80F8D064756E2164756E21
1996
+ //# debugId=665A564AAE317D3264756E2164756E21