@ricsam/isolate 0.1.4 → 0.1.6

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 +45 -2
  2. package/dist/cjs/internal/async-context/index.cjs +401 -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 +22 -6
  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 +119 -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 +277 -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 +42 -7
  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 +361 -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 +22 -6
  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 +119 -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 +277 -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 +42 -7
  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,7 +2,7 @@
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/internal/encoding/index.ts"],
4
4
  "sourcesContent": [
5
- "import type ivm from \"isolated-vm\";\n\nexport interface EncodingHandle {\n dispose(): void;\n}\n\nconst encodingCode = `\n(function() {\n // Define DOMException if not available\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 const base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n // Build reverse lookup table\n const base64Lookup = new Map();\n for (let i = 0; i < base64Chars.length; i++) {\n base64Lookup.set(base64Chars[i], i);\n }\n\n globalThis.btoa = function btoa(str) {\n if (str === undefined) {\n throw new TypeError(\"1 argument required, but only 0 present.\");\n }\n\n str = String(str);\n\n // Check for characters outside Latin-1 range\n for (let i = 0; i < str.length; i++) {\n if (str.charCodeAt(i) > 255) {\n throw new DOMException(\n \"The string to be encoded contains characters outside of the Latin1 range.\",\n \"InvalidCharacterError\"\n );\n }\n }\n\n if (str.length === 0) {\n return '';\n }\n\n let result = '';\n let i = 0;\n\n while (i < str.length) {\n const a = str.charCodeAt(i++);\n const bExists = i < str.length;\n const b = bExists ? str.charCodeAt(i++) : 0;\n const cExists = i < str.length;\n const c = cExists ? str.charCodeAt(i++) : 0;\n\n const triplet = (a << 16) | (b << 8) | c;\n\n result += base64Chars[(triplet >> 18) & 0x3F];\n result += base64Chars[(triplet >> 12) & 0x3F];\n result += bExists ? base64Chars[(triplet >> 6) & 0x3F] : '=';\n result += cExists ? base64Chars[triplet & 0x3F] : '=';\n }\n\n return result;\n };\n\n globalThis.atob = function atob(str) {\n if (str === undefined) {\n throw new TypeError(\"1 argument required, but only 0 present.\");\n }\n\n str = String(str);\n\n // Remove whitespace\n str = str.replace(/[\\\\t\\\\n\\\\f\\\\r ]/g, '');\n\n // Validate characters and length\n if (str.length === 0) {\n return '';\n }\n\n // Check for invalid characters (before padding normalization)\n for (let i = 0; i < str.length; i++) {\n const c = str[i];\n if (c !== '=' && !base64Lookup.has(c)) {\n throw new DOMException(\n \"The string to be decoded is not correctly encoded.\",\n \"InvalidCharacterError\"\n );\n }\n }\n\n // Validate padding position (must be at end)\n const paddingIndex = str.indexOf('=');\n if (paddingIndex !== -1) {\n for (let i = paddingIndex; i < str.length; i++) {\n if (str[i] !== '=') {\n throw new DOMException(\n \"The string to be decoded is not correctly encoded.\",\n \"InvalidCharacterError\"\n );\n }\n }\n const paddingLength = str.length - paddingIndex;\n if (paddingLength > 2) {\n throw new DOMException(\n \"The string to be decoded is not correctly encoded.\",\n \"InvalidCharacterError\"\n );\n }\n }\n\n // Length without padding must be valid (can't have remainder of 1)\n const strWithoutPadding = str.replace(/=/g, '');\n if (strWithoutPadding.length % 4 === 1) {\n throw new DOMException(\n \"The string to be decoded is not correctly encoded.\",\n \"InvalidCharacterError\"\n );\n }\n\n // Pad to multiple of 4 if needed (for inputs without explicit padding)\n while (str.length % 4 !== 0) {\n str += '=';\n }\n\n let result = '';\n let i = 0;\n\n while (i < str.length) {\n const a = base64Lookup.get(str[i++]) ?? 0;\n const b = base64Lookup.get(str[i++]) ?? 0;\n const c = base64Lookup.get(str[i++]) ?? 0;\n const d = base64Lookup.get(str[i++]) ?? 0;\n\n const triplet = (a << 18) | (b << 12) | (c << 6) | d;\n\n result += String.fromCharCode((triplet >> 16) & 0xFF);\n if (str[i - 2] !== '=') {\n result += String.fromCharCode((triplet >> 8) & 0xFF);\n }\n if (str[i - 1] !== '=') {\n result += String.fromCharCode(triplet & 0xFF);\n }\n }\n\n return result;\n };\n\n // ============================================\n // Buffer implementation\n // ============================================\n\n const BUFFER_SYMBOL = Symbol.for('__isBuffer');\n\n class Buffer extends Uint8Array {\n constructor(arg, encodingOrOffset, length) {\n if (typeof arg === 'number') {\n super(arg);\n } else if (typeof arg === 'string') {\n const bytes = stringToBytes(arg, encodingOrOffset || 'utf8');\n super(bytes);\n } else if (arg instanceof ArrayBuffer) {\n if (typeof encodingOrOffset === 'number') {\n super(arg, encodingOrOffset, length);\n } else {\n super(arg);\n }\n } else if (ArrayBuffer.isView(arg)) {\n super(arg.buffer, arg.byteOffset, arg.byteLength);\n } else if (Array.isArray(arg)) {\n super(arg);\n } else {\n super(arg);\n }\n Object.defineProperty(this, BUFFER_SYMBOL, { value: true, writable: false });\n }\n\n toString(encoding = 'utf8') {\n encoding = normalizeEncoding(encoding);\n if (encoding === 'utf8') {\n return new TextDecoder('utf-8').decode(this);\n } else if (encoding === 'base64') {\n return bytesToBase64(this);\n } else if (encoding === 'hex') {\n return bytesToHex(this);\n }\n return new TextDecoder('utf-8').decode(this);\n }\n\n slice(start, end) {\n const sliced = super.slice(start, end);\n return Buffer.from(sliced);\n }\n\n subarray(start, end) {\n const sub = super.subarray(start, end);\n const buf = new Buffer(sub.length);\n buf.set(sub);\n return buf;\n }\n\n static from(value, encodingOrOffset, length) {\n if (typeof value === 'string') {\n return new Buffer(value, encodingOrOffset);\n }\n if (value instanceof ArrayBuffer) {\n if (typeof encodingOrOffset === 'number') {\n return new Buffer(value, encodingOrOffset, length);\n }\n return new Buffer(value);\n }\n if (ArrayBuffer.isView(value)) {\n return new Buffer(value);\n }\n if (Array.isArray(value)) {\n return new Buffer(value);\n }\n if (value && typeof value[Symbol.iterator] === 'function') {\n return new Buffer(Array.from(value));\n }\n throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object');\n }\n\n static alloc(size, fill, encoding) {\n if (typeof size !== 'number' || size < 0) {\n throw new RangeError('Invalid size');\n }\n const buf = new Buffer(size);\n if (fill !== undefined) {\n if (typeof fill === 'number') {\n buf.fill(fill);\n } else if (typeof fill === 'string') {\n const fillBytes = stringToBytes(fill, encoding || 'utf8');\n for (let i = 0; i < size; i++) {\n buf[i] = fillBytes[i % fillBytes.length];\n }\n } else if (Buffer.isBuffer(fill) || fill instanceof Uint8Array) {\n for (let i = 0; i < size; i++) {\n buf[i] = fill[i % fill.length];\n }\n }\n }\n return buf;\n }\n\n static allocUnsafe(size) {\n if (typeof size !== 'number' || size < 0) {\n throw new RangeError('Invalid size');\n }\n return new Buffer(size);\n }\n\n static concat(list, totalLength) {\n if (!Array.isArray(list)) {\n throw new TypeError('list argument must be an array');\n }\n if (list.length === 0) {\n return Buffer.alloc(0);\n }\n if (totalLength === undefined) {\n totalLength = 0;\n for (const buf of list) {\n totalLength += buf.length;\n }\n }\n const result = Buffer.alloc(totalLength);\n let offset = 0;\n for (const buf of list) {\n if (offset + buf.length > totalLength) {\n result.set(buf.subarray(0, totalLength - offset), offset);\n break;\n }\n result.set(buf, offset);\n offset += buf.length;\n }\n return result;\n }\n\n static isBuffer(obj) {\n return obj != null && obj[BUFFER_SYMBOL] === true;\n }\n\n static byteLength(string, encoding = 'utf8') {\n if (typeof string !== 'string') {\n if (ArrayBuffer.isView(string) || string instanceof ArrayBuffer) {\n return string.byteLength;\n }\n throw new TypeError('First argument must be a string, Buffer, or ArrayBuffer');\n }\n encoding = normalizeEncoding(encoding);\n if (encoding === 'utf8') {\n return new TextEncoder().encode(string).length;\n } else if (encoding === 'base64') {\n const padding = (string.match(/=+$/) || [''])[0].length;\n return Math.floor((string.length * 3) / 4) - padding;\n } else if (encoding === 'hex') {\n return Math.floor(string.length / 2);\n }\n return new TextEncoder().encode(string).length;\n }\n\n static isEncoding(encoding) {\n return ['utf8', 'utf-8', 'base64', 'hex'].includes(normalizeEncoding(encoding));\n }\n }\n\n function normalizeEncoding(encoding) {\n if (!encoding) return 'utf8';\n const lower = String(encoding).toLowerCase().replace('-', '');\n if (lower === 'utf8' || lower === 'utf-8') return 'utf8';\n if (lower === 'base64') return 'base64';\n if (lower === 'hex') return 'hex';\n return lower;\n }\n\n function stringToBytes(str, encoding) {\n encoding = normalizeEncoding(encoding);\n if (encoding === 'utf8') {\n return new TextEncoder().encode(str);\n } else if (encoding === 'base64') {\n return base64ToBytes(str);\n } else if (encoding === 'hex') {\n return hexToBytes(str);\n }\n return new TextEncoder().encode(str);\n }\n\n function base64ToBytes(str) {\n const binary = atob(str);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n }\n\n function bytesToBase64(bytes) {\n let binary = '';\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n }\n\n function hexToBytes(str) {\n if (str.length % 2 !== 0) {\n throw new TypeError('Invalid hex string');\n }\n const bytes = new Uint8Array(str.length / 2);\n for (let i = 0; i < str.length; i += 2) {\n const byte = parseInt(str.substr(i, 2), 16);\n if (isNaN(byte)) {\n throw new TypeError('Invalid hex string');\n }\n bytes[i / 2] = byte;\n }\n return bytes;\n }\n\n function bytesToHex(bytes) {\n let hex = '';\n for (let i = 0; i < bytes.length; i++) {\n hex += bytes[i].toString(16).padStart(2, '0');\n }\n return hex;\n }\n\n globalThis.Buffer = Buffer;\n})();\n`;\n\n/**\n * Setup encoding APIs in an isolated-vm context\n *\n * Injects:\n * - atob/btoa for Base64 encoding/decoding\n * - Buffer class for binary data handling (utf8, base64, hex)\n *\n * @example\n * const handle = await setupEncoding(context);\n * await context.eval(`\n * const encoded = btoa(\"hello\");\n * const decoded = atob(encoded);\n * const buf = Buffer.from(\"hello\");\n * const hex = buf.toString(\"hex\");\n * `);\n */\nexport async function setupEncoding(\n context: ivm.Context\n): Promise<EncodingHandle> {\n context.evalSync(encodingCode);\n return {\n dispose() {\n // No resources to cleanup for pure JS injection\n },\n };\n}\n"
5
+ "import type ivm from \"@ricsam/isolated-vm\";\n\nexport interface EncodingHandle {\n dispose(): void;\n}\n\nconst encodingCode = `\n(function() {\n // Define DOMException if not available\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 const base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';\n\n // Build reverse lookup table\n const base64Lookup = new Map();\n for (let i = 0; i < base64Chars.length; i++) {\n base64Lookup.set(base64Chars[i], i);\n }\n\n globalThis.btoa = function btoa(str) {\n if (str === undefined) {\n throw new TypeError(\"1 argument required, but only 0 present.\");\n }\n\n str = String(str);\n\n // Check for characters outside Latin-1 range\n for (let i = 0; i < str.length; i++) {\n if (str.charCodeAt(i) > 255) {\n throw new DOMException(\n \"The string to be encoded contains characters outside of the Latin1 range.\",\n \"InvalidCharacterError\"\n );\n }\n }\n\n if (str.length === 0) {\n return '';\n }\n\n let result = '';\n let i = 0;\n\n while (i < str.length) {\n const a = str.charCodeAt(i++);\n const bExists = i < str.length;\n const b = bExists ? str.charCodeAt(i++) : 0;\n const cExists = i < str.length;\n const c = cExists ? str.charCodeAt(i++) : 0;\n\n const triplet = (a << 16) | (b << 8) | c;\n\n result += base64Chars[(triplet >> 18) & 0x3F];\n result += base64Chars[(triplet >> 12) & 0x3F];\n result += bExists ? base64Chars[(triplet >> 6) & 0x3F] : '=';\n result += cExists ? base64Chars[triplet & 0x3F] : '=';\n }\n\n return result;\n };\n\n globalThis.atob = function atob(str) {\n if (str === undefined) {\n throw new TypeError(\"1 argument required, but only 0 present.\");\n }\n\n str = String(str);\n\n // Remove whitespace\n str = str.replace(/[\\\\t\\\\n\\\\f\\\\r ]/g, '');\n\n // Validate characters and length\n if (str.length === 0) {\n return '';\n }\n\n // Check for invalid characters (before padding normalization)\n for (let i = 0; i < str.length; i++) {\n const c = str[i];\n if (c !== '=' && !base64Lookup.has(c)) {\n throw new DOMException(\n \"The string to be decoded is not correctly encoded.\",\n \"InvalidCharacterError\"\n );\n }\n }\n\n // Validate padding position (must be at end)\n const paddingIndex = str.indexOf('=');\n if (paddingIndex !== -1) {\n for (let i = paddingIndex; i < str.length; i++) {\n if (str[i] !== '=') {\n throw new DOMException(\n \"The string to be decoded is not correctly encoded.\",\n \"InvalidCharacterError\"\n );\n }\n }\n const paddingLength = str.length - paddingIndex;\n if (paddingLength > 2) {\n throw new DOMException(\n \"The string to be decoded is not correctly encoded.\",\n \"InvalidCharacterError\"\n );\n }\n }\n\n // Length without padding must be valid (can't have remainder of 1)\n const strWithoutPadding = str.replace(/=/g, '');\n if (strWithoutPadding.length % 4 === 1) {\n throw new DOMException(\n \"The string to be decoded is not correctly encoded.\",\n \"InvalidCharacterError\"\n );\n }\n\n // Pad to multiple of 4 if needed (for inputs without explicit padding)\n while (str.length % 4 !== 0) {\n str += '=';\n }\n\n let result = '';\n let i = 0;\n\n while (i < str.length) {\n const a = base64Lookup.get(str[i++]) ?? 0;\n const b = base64Lookup.get(str[i++]) ?? 0;\n const c = base64Lookup.get(str[i++]) ?? 0;\n const d = base64Lookup.get(str[i++]) ?? 0;\n\n const triplet = (a << 18) | (b << 12) | (c << 6) | d;\n\n result += String.fromCharCode((triplet >> 16) & 0xFF);\n if (str[i - 2] !== '=') {\n result += String.fromCharCode((triplet >> 8) & 0xFF);\n }\n if (str[i - 1] !== '=') {\n result += String.fromCharCode(triplet & 0xFF);\n }\n }\n\n return result;\n };\n\n // ============================================\n // Buffer implementation\n // ============================================\n\n const BUFFER_SYMBOL = Symbol.for('__isBuffer');\n\n class Buffer extends Uint8Array {\n constructor(arg, encodingOrOffset, length) {\n if (typeof arg === 'number') {\n super(arg);\n } else if (typeof arg === 'string') {\n const bytes = stringToBytes(arg, encodingOrOffset || 'utf8');\n super(bytes);\n } else if (arg instanceof ArrayBuffer) {\n if (typeof encodingOrOffset === 'number') {\n super(arg, encodingOrOffset, length);\n } else {\n super(arg);\n }\n } else if (ArrayBuffer.isView(arg)) {\n super(arg.buffer, arg.byteOffset, arg.byteLength);\n } else if (Array.isArray(arg)) {\n super(arg);\n } else {\n super(arg);\n }\n Object.defineProperty(this, BUFFER_SYMBOL, { value: true, writable: false });\n }\n\n toString(encoding = 'utf8') {\n encoding = normalizeEncoding(encoding);\n if (encoding === 'utf8') {\n return new TextDecoder('utf-8').decode(this);\n } else if (encoding === 'base64') {\n return bytesToBase64(this);\n } else if (encoding === 'hex') {\n return bytesToHex(this);\n }\n return new TextDecoder('utf-8').decode(this);\n }\n\n slice(start, end) {\n const sliced = super.slice(start, end);\n return Buffer.from(sliced);\n }\n\n subarray(start, end) {\n const sub = super.subarray(start, end);\n const buf = new Buffer(sub.length);\n buf.set(sub);\n return buf;\n }\n\n static from(value, encodingOrOffset, length) {\n if (typeof value === 'string') {\n return new Buffer(value, encodingOrOffset);\n }\n if (value instanceof ArrayBuffer) {\n if (typeof encodingOrOffset === 'number') {\n return new Buffer(value, encodingOrOffset, length);\n }\n return new Buffer(value);\n }\n if (ArrayBuffer.isView(value)) {\n return new Buffer(value);\n }\n if (Array.isArray(value)) {\n return new Buffer(value);\n }\n if (value && typeof value[Symbol.iterator] === 'function') {\n return new Buffer(Array.from(value));\n }\n throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object');\n }\n\n static alloc(size, fill, encoding) {\n if (typeof size !== 'number' || size < 0) {\n throw new RangeError('Invalid size');\n }\n const buf = new Buffer(size);\n if (fill !== undefined) {\n if (typeof fill === 'number') {\n buf.fill(fill);\n } else if (typeof fill === 'string') {\n const fillBytes = stringToBytes(fill, encoding || 'utf8');\n for (let i = 0; i < size; i++) {\n buf[i] = fillBytes[i % fillBytes.length];\n }\n } else if (Buffer.isBuffer(fill) || fill instanceof Uint8Array) {\n for (let i = 0; i < size; i++) {\n buf[i] = fill[i % fill.length];\n }\n }\n }\n return buf;\n }\n\n static allocUnsafe(size) {\n if (typeof size !== 'number' || size < 0) {\n throw new RangeError('Invalid size');\n }\n return new Buffer(size);\n }\n\n static concat(list, totalLength) {\n if (!Array.isArray(list)) {\n throw new TypeError('list argument must be an array');\n }\n if (list.length === 0) {\n return Buffer.alloc(0);\n }\n if (totalLength === undefined) {\n totalLength = 0;\n for (const buf of list) {\n totalLength += buf.length;\n }\n }\n const result = Buffer.alloc(totalLength);\n let offset = 0;\n for (const buf of list) {\n if (offset + buf.length > totalLength) {\n result.set(buf.subarray(0, totalLength - offset), offset);\n break;\n }\n result.set(buf, offset);\n offset += buf.length;\n }\n return result;\n }\n\n static isBuffer(obj) {\n return obj != null && obj[BUFFER_SYMBOL] === true;\n }\n\n static byteLength(string, encoding = 'utf8') {\n if (typeof string !== 'string') {\n if (ArrayBuffer.isView(string) || string instanceof ArrayBuffer) {\n return string.byteLength;\n }\n throw new TypeError('First argument must be a string, Buffer, or ArrayBuffer');\n }\n encoding = normalizeEncoding(encoding);\n if (encoding === 'utf8') {\n return new TextEncoder().encode(string).length;\n } else if (encoding === 'base64') {\n const padding = (string.match(/=+$/) || [''])[0].length;\n return Math.floor((string.length * 3) / 4) - padding;\n } else if (encoding === 'hex') {\n return Math.floor(string.length / 2);\n }\n return new TextEncoder().encode(string).length;\n }\n\n static isEncoding(encoding) {\n return ['utf8', 'utf-8', 'base64', 'hex'].includes(normalizeEncoding(encoding));\n }\n }\n\n function normalizeEncoding(encoding) {\n if (!encoding) return 'utf8';\n const lower = String(encoding).toLowerCase().replace('-', '');\n if (lower === 'utf8' || lower === 'utf-8') return 'utf8';\n if (lower === 'base64') return 'base64';\n if (lower === 'hex') return 'hex';\n return lower;\n }\n\n function stringToBytes(str, encoding) {\n encoding = normalizeEncoding(encoding);\n if (encoding === 'utf8') {\n return new TextEncoder().encode(str);\n } else if (encoding === 'base64') {\n return base64ToBytes(str);\n } else if (encoding === 'hex') {\n return hexToBytes(str);\n }\n return new TextEncoder().encode(str);\n }\n\n function base64ToBytes(str) {\n const binary = atob(str);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n }\n\n function bytesToBase64(bytes) {\n let binary = '';\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n }\n\n function hexToBytes(str) {\n if (str.length % 2 !== 0) {\n throw new TypeError('Invalid hex string');\n }\n const bytes = new Uint8Array(str.length / 2);\n for (let i = 0; i < str.length; i += 2) {\n const byte = parseInt(str.substr(i, 2), 16);\n if (isNaN(byte)) {\n throw new TypeError('Invalid hex string');\n }\n bytes[i / 2] = byte;\n }\n return bytes;\n }\n\n function bytesToHex(bytes) {\n let hex = '';\n for (let i = 0; i < bytes.length; i++) {\n hex += bytes[i].toString(16).padStart(2, '0');\n }\n return hex;\n }\n\n globalThis.Buffer = Buffer;\n})();\n`;\n\n/**\n * Setup encoding APIs in an isolated-vm context\n *\n * Injects:\n * - atob/btoa for Base64 encoding/decoding\n * - Buffer class for binary data handling (utf8, base64, hex)\n *\n * @example\n * const handle = await setupEncoding(context);\n * await context.eval(`\n * const encoded = btoa(\"hello\");\n * const decoded = atob(encoded);\n * const buf = Buffer.from(\"hello\");\n * const hex = buf.toString(\"hex\");\n * `);\n */\nexport async function setupEncoding(\n context: ivm.Context\n): Promise<EncodingHandle> {\n context.evalSync(encodingCode);\n return {\n dispose() {\n // No resources to cleanup for pure JS injection\n },\n };\n}\n"
6
6
  ],
7
7
  "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAMA,IAAM,eAAe;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;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;AAgYrB,eAAsB,aAAa,CACjC,SACyB;AAAA,EACzB,QAAQ,SAAS,YAAY;AAAA,EAC7B,OAAO;AAAA,IACL,OAAO,GAAG;AAAA,EAGZ;AAAA;",
8
8
  "debugId": "45DC5B28BDBCE20A64756E2164756E21",
@@ -67,7 +67,7 @@ __export(exports_fetch, {
67
67
  clearAllInstanceState: () => import_core.clearAllInstanceState
68
68
  });
69
69
  module.exports = __toCommonJS(exports_fetch);
70
- var import_isolated_vm = __toESM(require("isolated-vm"));
70
+ var import_isolated_vm = __toESM(require("@ricsam/isolated-vm"));
71
71
  var import_core = require("../core/index.cjs");
72
72
  var import_stream_state = require("./stream-state.cjs");
73
73
  var instanceStateMap = new WeakMap;
@@ -1911,21 +1911,32 @@ function setupClientWebSocket(context, clientWsCommandCallbacks) {
1911
1911
  }
1912
1912
  };
1913
1913
 
1914
+ const __wrapAsyncContextCallback = (callback, options = {}) => (
1915
+ typeof callback === 'function' && globalThis.__isolateAsyncContextInternals?.wrapCallback
1916
+ ? globalThis.__isolateAsyncContextInternals.wrapCallback(callback, options)
1917
+ : callback
1918
+ );
1919
+ const __releaseAsyncContextCallback = (callback) => (
1920
+ typeof callback === 'function' && globalThis.__isolateAsyncContextInternals?.releaseCallback
1921
+ ? globalThis.__isolateAsyncContextInternals.releaseCallback(callback)
1922
+ : false
1923
+ );
1924
+
1914
1925
  // Helper to dispatch events
1915
1926
  function dispatchEvent(ws, event) {
1916
1927
  const listeners = ws._listeners.get(event.type) || [];
1917
1928
  for (const listener of listeners) {
1918
1929
  try {
1919
- listener.call(ws, event);
1930
+ listener.wrapped.call(ws, event);
1920
1931
  } catch (e) {
1921
1932
  console.error('WebSocket event listener error:', e);
1922
1933
  }
1923
1934
  }
1924
1935
  // Also call on* handler if set
1925
- const handler = ws['on' + event.type];
1926
- if (typeof handler === 'function') {
1936
+ const handler = ws._handlers.get(event.type);
1937
+ if (handler?.wrapped) {
1927
1938
  try {
1928
- handler.call(ws, event);
1939
+ handler.wrapped.call(ws, event);
1929
1940
  } catch (e) {
1930
1941
  console.error('WebSocket handler error:', e);
1931
1942
  }
@@ -1946,12 +1957,21 @@ function setupClientWebSocket(context, clientWsCommandCallbacks) {
1946
1957
  #protocol = '';
1947
1958
  #binaryType = 'blob';
1948
1959
  _listeners = new Map();
1949
-
1950
- // Event handlers
1951
- onopen = null;
1952
- onmessage = null;
1953
- onerror = null;
1954
- onclose = null;
1960
+ _handlers = new Map([
1961
+ ['open', null],
1962
+ ['message', null],
1963
+ ['error', null],
1964
+ ['close', null],
1965
+ ]);
1966
+
1967
+ get onopen() { return this._handlers.get('open')?.original ?? null; }
1968
+ set onopen(handler) { this._setHandler('open', handler); }
1969
+ get onmessage() { return this._handlers.get('message')?.original ?? null; }
1970
+ set onmessage(handler) { this._setHandler('message', handler); }
1971
+ get onerror() { return this._handlers.get('error')?.original ?? null; }
1972
+ set onerror(handler) { this._setHandler('error', handler); }
1973
+ get onclose() { return this._handlers.get('close')?.original ?? null; }
1974
+ set onclose(handler) { this._setHandler('close', handler); }
1955
1975
 
1956
1976
  constructor(url, protocols) {
1957
1977
  // Validate URL
@@ -2036,6 +2056,24 @@ function setupClientWebSocket(context, clientWsCommandCallbacks) {
2036
2056
  get CLOSING() { return WebSocket.CLOSING; }
2037
2057
  get CLOSED() { return WebSocket.CLOSED; }
2038
2058
 
2059
+ _setHandler(type, handler) {
2060
+ const previous = this._handlers.get(type);
2061
+ if (previous?.wrapped) {
2062
+ __releaseAsyncContextCallback(previous.wrapped);
2063
+ }
2064
+ if (typeof handler !== 'function') {
2065
+ this._handlers.set(type, null);
2066
+ return;
2067
+ }
2068
+ this._handlers.set(type, {
2069
+ original: handler,
2070
+ wrapped: __wrapAsyncContextCallback(handler, {
2071
+ resource: this,
2072
+ type: 'isolate.websocket',
2073
+ }),
2074
+ });
2075
+ }
2076
+
2039
2077
  send(data) {
2040
2078
  if (this.#readyState === WebSocket.CONNECTING) {
2041
2079
  throw new DOMException("Failed to execute 'send' on 'WebSocket': Still in CONNECTING state.", 'InvalidStateError');
@@ -2109,16 +2147,23 @@ function setupClientWebSocket(context, clientWsCommandCallbacks) {
2109
2147
  listeners = [];
2110
2148
  this._listeners.set(type, listeners);
2111
2149
  }
2112
- if (!listeners.includes(listener)) {
2113
- listeners.push(listener);
2150
+ if (!listeners.some((entry) => entry.original === listener)) {
2151
+ listeners.push({
2152
+ original: listener,
2153
+ wrapped: __wrapAsyncContextCallback(listener, {
2154
+ resource: this,
2155
+ type: 'isolate.websocket',
2156
+ }),
2157
+ });
2114
2158
  }
2115
2159
  }
2116
2160
 
2117
2161
  removeEventListener(type, listener, options) {
2118
2162
  const listeners = this._listeners.get(type);
2119
2163
  if (!listeners) return;
2120
- const index = listeners.indexOf(listener);
2164
+ const index = listeners.findIndex((entry) => entry.original === listener || entry.wrapped === listener);
2121
2165
  if (index !== -1) {
2166
+ __releaseAsyncContextCallback(listeners[index].wrapped);
2122
2167
  listeners.splice(index, 1);
2123
2168
  }
2124
2169
  }
@@ -2177,6 +2222,18 @@ function setupClientWebSocket(context, clientWsCommandCallbacks) {
2177
2222
  this.#readyState = WebSocket.CLOSED;
2178
2223
  const event = new _CloseEvent('close', { code, reason, wasClean });
2179
2224
  dispatchEvent(this, event);
2225
+ for (const handler of this._handlers.values()) {
2226
+ if (handler?.wrapped) {
2227
+ __releaseAsyncContextCallback(handler.wrapped);
2228
+ }
2229
+ }
2230
+ for (const listeners of this._listeners.values()) {
2231
+ for (const listener of listeners) {
2232
+ __releaseAsyncContextCallback(listener.wrapped);
2233
+ }
2234
+ }
2235
+ this._handlers.clear();
2236
+ this._listeners.clear();
2180
2237
  __clientWebSockets.delete(this.#socketId);
2181
2238
  }
2182
2239
  }
@@ -2212,9 +2269,41 @@ function setupServe(context) {
2212
2269
  context.evalSync(`
2213
2270
  (function() {
2214
2271
  globalThis.__serveOptions__ = null;
2272
+ const __wrapAsyncContextCallback = (callback, options = {}) => (
2273
+ typeof callback === 'function' && globalThis.__isolateAsyncContextInternals?.wrapCallback
2274
+ ? globalThis.__isolateAsyncContextInternals.wrapCallback(callback, options)
2275
+ : callback
2276
+ );
2277
+
2278
+ function wrapServeOptions(options) {
2279
+ if (!options || typeof options !== 'object') {
2280
+ return options;
2281
+ }
2282
+
2283
+ const wrapped = { ...options };
2284
+ if (typeof options.fetch === 'function') {
2285
+ wrapped.fetch = __wrapAsyncContextCallback(options.fetch, {
2286
+ type: 'isolate.serve',
2287
+ });
2288
+ }
2289
+
2290
+ if (options.websocket && typeof options.websocket === 'object') {
2291
+ wrapped.websocket = { ...options.websocket };
2292
+ for (const name of ['open', 'message', 'close', 'error']) {
2293
+ if (typeof options.websocket[name] === 'function') {
2294
+ wrapped.websocket[name] = __wrapAsyncContextCallback(
2295
+ options.websocket[name],
2296
+ { type: 'isolate.serve.websocket' },
2297
+ );
2298
+ }
2299
+ }
2300
+ }
2301
+
2302
+ return wrapped;
2303
+ }
2215
2304
 
2216
2305
  function serve(options) {
2217
- globalThis.__serveOptions__ = options;
2306
+ globalThis.__serveOptions__ = wrapServeOptions(options);
2218
2307
  }
2219
2308
 
2220
2309
  globalThis.serve = serve;
@@ -2252,6 +2341,16 @@ async function setupFetch(context, options) {
2252
2341
  context.evalSync(`
2253
2342
  (function() {
2254
2343
  const __eventListeners = new Map();
2344
+ const __wrapAsyncContextCallback = (callback) => (
2345
+ typeof callback === 'function' && globalThis.__isolateAsyncContextInternals?.wrapCallback
2346
+ ? globalThis.__isolateAsyncContextInternals.wrapCallback(callback, { type: 'isolate.event' })
2347
+ : callback
2348
+ );
2349
+ const __releaseAsyncContextCallback = (callback) => (
2350
+ typeof callback === 'function' && globalThis.__isolateAsyncContextInternals?.releaseCallback
2351
+ ? globalThis.__isolateAsyncContextInternals.releaseCallback(callback)
2352
+ : false
2353
+ );
2255
2354
 
2256
2355
  globalThis.__on = function(event, callback) {
2257
2356
  let listeners = __eventListeners.get(event);
@@ -2259,9 +2358,11 @@ async function setupFetch(context, options) {
2259
2358
  listeners = new Set();
2260
2359
  __eventListeners.set(event, listeners);
2261
2360
  }
2262
- listeners.add(callback);
2361
+ const wrapped = __wrapAsyncContextCallback(callback);
2362
+ listeners.add(wrapped);
2263
2363
  return function() {
2264
- listeners.delete(callback);
2364
+ listeners.delete(wrapped);
2365
+ __releaseAsyncContextCallback(wrapped);
2265
2366
  if (listeners.size === 0) {
2266
2367
  __eventListeners.delete(event);
2267
2368
  }
@@ -2637,4 +2738,4 @@ async function setupFetch(context, options) {
2637
2738
  };
2638
2739
  }
2639
2740
 
2640
- //# debugId=C7AE0924BFE61B3564756E2164756E21
2741
+ //# debugId=9AF8B200C8CF0CEC64756E2164756E21