@ricsam/isolate 0.1.3 → 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.
- package/README.md +25 -2
- package/dist/cjs/internal/async-context/index.cjs +140 -0
- package/dist/cjs/internal/async-context/index.cjs.map +10 -0
- package/dist/cjs/internal/client/connection.cjs +175 -123
- package/dist/cjs/internal/client/connection.cjs.map +3 -3
- package/dist/cjs/internal/console/index.cjs +2 -2
- package/dist/cjs/internal/console/index.cjs.map +2 -2
- package/dist/cjs/internal/core/index.cjs +13 -5
- package/dist/cjs/internal/core/index.cjs.map +3 -3
- package/dist/cjs/internal/crypto/index.cjs +2 -2
- package/dist/cjs/internal/crypto/index.cjs.map +2 -2
- package/dist/cjs/internal/daemon/connection.cjs +77 -12
- package/dist/cjs/internal/daemon/connection.cjs.map +3 -3
- package/dist/cjs/internal/encoding/index.cjs.map +1 -1
- package/dist/cjs/internal/fetch/index.cjs +80 -18
- package/dist/cjs/internal/fetch/index.cjs.map +3 -3
- package/dist/cjs/internal/fetch/stream-state.cjs.map +1 -1
- package/dist/cjs/internal/fs/index.cjs +2 -2
- package/dist/cjs/internal/fs/index.cjs.map +2 -2
- package/dist/cjs/internal/module-loader/bundle.cjs +225 -8
- package/dist/cjs/internal/module-loader/bundle.cjs.map +3 -3
- package/dist/cjs/internal/path/index.cjs.map +1 -1
- package/dist/cjs/internal/playwright/index.cjs +2 -2
- package/dist/cjs/internal/playwright/index.cjs.map +2 -2
- package/dist/cjs/internal/runtime/index.cjs +78 -6
- package/dist/cjs/internal/runtime/index.cjs.map +3 -3
- package/dist/cjs/internal/test-environment/index.cjs +2 -2
- package/dist/cjs/internal/test-environment/index.cjs.map +2 -2
- package/dist/cjs/internal/timers/index.cjs +9 -4
- package/dist/cjs/internal/timers/index.cjs.map +3 -3
- package/dist/cjs/internal/typecheck/isolate-types.cjs +36 -1
- package/dist/cjs/internal/typecheck/isolate-types.cjs.map +3 -3
- package/dist/cjs/package.json +1 -1
- package/dist/mjs/internal/async-context/index.mjs +100 -0
- package/dist/mjs/internal/async-context/index.mjs.map +10 -0
- package/dist/mjs/internal/client/connection.mjs +176 -123
- package/dist/mjs/internal/client/connection.mjs.map +3 -3
- package/dist/mjs/internal/console/index.mjs +2 -2
- package/dist/mjs/internal/console/index.mjs.map +2 -2
- package/dist/mjs/internal/core/index.mjs +13 -5
- package/dist/mjs/internal/core/index.mjs.map +3 -3
- package/dist/mjs/internal/crypto/index.mjs +2 -2
- package/dist/mjs/internal/crypto/index.mjs.map +2 -2
- package/dist/mjs/internal/daemon/connection.mjs +77 -12
- package/dist/mjs/internal/daemon/connection.mjs.map +3 -3
- package/dist/mjs/internal/encoding/index.mjs.map +1 -1
- package/dist/mjs/internal/fetch/index.mjs +80 -18
- package/dist/mjs/internal/fetch/index.mjs.map +3 -3
- package/dist/mjs/internal/fetch/stream-state.mjs.map +1 -1
- package/dist/mjs/internal/fs/index.mjs +2 -2
- package/dist/mjs/internal/fs/index.mjs.map +2 -2
- package/dist/mjs/internal/module-loader/bundle.mjs +225 -8
- package/dist/mjs/internal/module-loader/bundle.mjs.map +3 -3
- package/dist/mjs/internal/path/index.mjs.map +1 -1
- package/dist/mjs/internal/playwright/index.mjs +2 -2
- package/dist/mjs/internal/playwright/index.mjs.map +2 -2
- package/dist/mjs/internal/runtime/index.mjs +78 -6
- package/dist/mjs/internal/runtime/index.mjs.map +3 -3
- package/dist/mjs/internal/test-environment/index.mjs +2 -2
- package/dist/mjs/internal/test-environment/index.mjs.map +2 -2
- package/dist/mjs/internal/timers/index.mjs +9 -4
- package/dist/mjs/internal/timers/index.mjs.map +3 -3
- package/dist/mjs/internal/typecheck/isolate-types.mjs +36 -1
- package/dist/mjs/internal/typecheck/isolate-types.mjs.map +3 -3
- package/dist/mjs/package.json +1 -1
- package/dist/types/internal/async-context/index.d.ts +5 -0
- package/dist/types/internal/console/index.d.ts +1 -1
- package/dist/types/internal/core/index.d.ts +2 -2
- package/dist/types/internal/crypto/index.d.ts +1 -1
- package/dist/types/internal/daemon/types.d.ts +1 -0
- package/dist/types/internal/encoding/index.d.ts +1 -1
- package/dist/types/internal/fetch/index.d.ts +1 -1
- package/dist/types/internal/fetch/stream-state.d.ts +1 -1
- package/dist/types/internal/fs/index.d.ts +1 -1
- package/dist/types/internal/path/index.d.ts +1 -1
- package/dist/types/internal/playwright/index.d.ts +1 -1
- package/dist/types/internal/test-environment/index.d.ts +1 -1
- package/dist/types/internal/timers/index.d.ts +1 -1
- package/dist/types/internal/typecheck/isolate-types.d.ts +2 -2
- 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=
|
|
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": "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",
|
|
8
|
-
"debugId": "
|
|
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 =
|
|
645
|
+
const callbackId = allocateLocalCallbackId();
|
|
635
646
|
instance.returnedCallbacks.set(callbackId, fn);
|
|
636
647
|
return callbackId;
|
|
637
648
|
},
|
|
638
649
|
registerPromise: (promise) => {
|
|
639
|
-
const promiseId =
|
|
650
|
+
const promiseId = allocateLocalCallbackId();
|
|
640
651
|
instance.returnedPromises.set(promiseId, promise);
|
|
641
652
|
return promiseId;
|
|
642
653
|
},
|
|
643
654
|
registerIterator: (iterator) => {
|
|
644
|
-
const iteratorId =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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,
|
|
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,
|
|
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
|
|
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
|
-
|
|
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=
|
|
2017
|
+
//# debugId=0C2C837A78ED90B564756E2164756E21
|