@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,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": "2B61D31B7C8C40BA64756E2164756E21",
@@ -1,5 +1,5 @@
1
1
  // src/internal/fetch/index.ts
2
- import ivm from "isolated-vm";
2
+ import ivm from "@ricsam/isolated-vm";
3
3
  import { setupCore, clearAllInstanceState } from "../core/index.mjs";
4
4
  import {
5
5
  getStreamRegistryForContext,
@@ -1847,21 +1847,27 @@ function setupClientWebSocket(context, clientWsCommandCallbacks) {
1847
1847
  }
1848
1848
  };
1849
1849
 
1850
+ const __wrapAsyncContextCallback = (callback) => (
1851
+ typeof callback === 'function' && globalThis.AsyncContext?.Snapshot?.wrap
1852
+ ? globalThis.AsyncContext.Snapshot.wrap(callback)
1853
+ : callback
1854
+ );
1855
+
1850
1856
  // Helper to dispatch events
1851
1857
  function dispatchEvent(ws, event) {
1852
1858
  const listeners = ws._listeners.get(event.type) || [];
1853
1859
  for (const listener of listeners) {
1854
1860
  try {
1855
- listener.call(ws, event);
1861
+ listener.wrapped.call(ws, event);
1856
1862
  } catch (e) {
1857
1863
  console.error('WebSocket event listener error:', e);
1858
1864
  }
1859
1865
  }
1860
1866
  // Also call on* handler if set
1861
- const handler = ws['on' + event.type];
1862
- if (typeof handler === 'function') {
1867
+ const handler = ws._handlers.get(event.type);
1868
+ if (handler?.wrapped) {
1863
1869
  try {
1864
- handler.call(ws, event);
1870
+ handler.wrapped.call(ws, event);
1865
1871
  } catch (e) {
1866
1872
  console.error('WebSocket handler error:', e);
1867
1873
  }
@@ -1882,12 +1888,21 @@ function setupClientWebSocket(context, clientWsCommandCallbacks) {
1882
1888
  #protocol = '';
1883
1889
  #binaryType = 'blob';
1884
1890
  _listeners = new Map();
1885
-
1886
- // Event handlers
1887
- onopen = null;
1888
- onmessage = null;
1889
- onerror = null;
1890
- onclose = null;
1891
+ _handlers = new Map([
1892
+ ['open', null],
1893
+ ['message', null],
1894
+ ['error', null],
1895
+ ['close', null],
1896
+ ]);
1897
+
1898
+ get onopen() { return this._handlers.get('open')?.original ?? null; }
1899
+ set onopen(handler) { this._setHandler('open', handler); }
1900
+ get onmessage() { return this._handlers.get('message')?.original ?? null; }
1901
+ set onmessage(handler) { this._setHandler('message', handler); }
1902
+ get onerror() { return this._handlers.get('error')?.original ?? null; }
1903
+ set onerror(handler) { this._setHandler('error', handler); }
1904
+ get onclose() { return this._handlers.get('close')?.original ?? null; }
1905
+ set onclose(handler) { this._setHandler('close', handler); }
1891
1906
 
1892
1907
  constructor(url, protocols) {
1893
1908
  // Validate URL
@@ -1972,6 +1987,17 @@ function setupClientWebSocket(context, clientWsCommandCallbacks) {
1972
1987
  get CLOSING() { return WebSocket.CLOSING; }
1973
1988
  get CLOSED() { return WebSocket.CLOSED; }
1974
1989
 
1990
+ _setHandler(type, handler) {
1991
+ if (typeof handler !== 'function') {
1992
+ this._handlers.set(type, null);
1993
+ return;
1994
+ }
1995
+ this._handlers.set(type, {
1996
+ original: handler,
1997
+ wrapped: __wrapAsyncContextCallback(handler),
1998
+ });
1999
+ }
2000
+
1975
2001
  send(data) {
1976
2002
  if (this.#readyState === WebSocket.CONNECTING) {
1977
2003
  throw new DOMException("Failed to execute 'send' on 'WebSocket': Still in CONNECTING state.", 'InvalidStateError');
@@ -2045,15 +2071,18 @@ function setupClientWebSocket(context, clientWsCommandCallbacks) {
2045
2071
  listeners = [];
2046
2072
  this._listeners.set(type, listeners);
2047
2073
  }
2048
- if (!listeners.includes(listener)) {
2049
- listeners.push(listener);
2074
+ if (!listeners.some((entry) => entry.original === listener)) {
2075
+ listeners.push({
2076
+ original: listener,
2077
+ wrapped: __wrapAsyncContextCallback(listener),
2078
+ });
2050
2079
  }
2051
2080
  }
2052
2081
 
2053
2082
  removeEventListener(type, listener, options) {
2054
2083
  const listeners = this._listeners.get(type);
2055
2084
  if (!listeners) return;
2056
- const index = listeners.indexOf(listener);
2085
+ const index = listeners.findIndex((entry) => entry.original === listener || entry.wrapped === listener);
2057
2086
  if (index !== -1) {
2058
2087
  listeners.splice(index, 1);
2059
2088
  }
@@ -2148,9 +2177,36 @@ function setupServe(context) {
2148
2177
  context.evalSync(`
2149
2178
  (function() {
2150
2179
  globalThis.__serveOptions__ = null;
2180
+ const __wrapAsyncContextCallback = (callback) => (
2181
+ typeof callback === 'function' && globalThis.AsyncContext?.Snapshot?.wrap
2182
+ ? globalThis.AsyncContext.Snapshot.wrap(callback)
2183
+ : callback
2184
+ );
2185
+
2186
+ function wrapServeOptions(options) {
2187
+ if (!options || typeof options !== 'object') {
2188
+ return options;
2189
+ }
2190
+
2191
+ const wrapped = { ...options };
2192
+ if (typeof options.fetch === 'function') {
2193
+ wrapped.fetch = __wrapAsyncContextCallback(options.fetch);
2194
+ }
2195
+
2196
+ if (options.websocket && typeof options.websocket === 'object') {
2197
+ wrapped.websocket = { ...options.websocket };
2198
+ for (const name of ['open', 'message', 'close', 'error']) {
2199
+ if (typeof options.websocket[name] === 'function') {
2200
+ wrapped.websocket[name] = __wrapAsyncContextCallback(options.websocket[name]);
2201
+ }
2202
+ }
2203
+ }
2204
+
2205
+ return wrapped;
2206
+ }
2151
2207
 
2152
2208
  function serve(options) {
2153
- globalThis.__serveOptions__ = options;
2209
+ globalThis.__serveOptions__ = wrapServeOptions(options);
2154
2210
  }
2155
2211
 
2156
2212
  globalThis.serve = serve;
@@ -2188,6 +2244,11 @@ async function setupFetch(context, options) {
2188
2244
  context.evalSync(`
2189
2245
  (function() {
2190
2246
  const __eventListeners = new Map();
2247
+ const __wrapAsyncContextCallback = (callback) => (
2248
+ typeof callback === 'function' && globalThis.AsyncContext?.Snapshot?.wrap
2249
+ ? globalThis.AsyncContext.Snapshot.wrap(callback)
2250
+ : callback
2251
+ );
2191
2252
 
2192
2253
  globalThis.__on = function(event, callback) {
2193
2254
  let listeners = __eventListeners.get(event);
@@ -2195,9 +2256,10 @@ async function setupFetch(context, options) {
2195
2256
  listeners = new Set();
2196
2257
  __eventListeners.set(event, listeners);
2197
2258
  }
2198
- listeners.add(callback);
2259
+ const wrapped = __wrapAsyncContextCallback(callback);
2260
+ listeners.add(wrapped);
2199
2261
  return function() {
2200
- listeners.delete(callback);
2262
+ listeners.delete(wrapped);
2201
2263
  if (listeners.size === 0) {
2202
2264
  __eventListeners.delete(event);
2203
2265
  }
@@ -2577,4 +2639,4 @@ export {
2577
2639
  clearAllInstanceState
2578
2640
  };
2579
2641
 
2580
- //# debugId=E4E922B4BB22197964756E2164756E21
2642
+ //# debugId=60FF4FEB06AFDED964756E2164756E21