@php-wasm/universal 3.1.0 → 3.1.2

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/index.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../../../packages/php-wasm/universal/src/lib/rethrow-file-system-error.ts","../../../../packages/php-wasm/universal/src/lib/fs-helpers.ts","../../../../packages/php-wasm/universal/src/lib/php-worker.ts","../../../../packages/php-wasm/universal/src/lib/is-exit-code.ts","../../../../packages/php-wasm/universal/src/lib/load-php-runtime.ts","../../../../packages/php-wasm/universal/src/lib/php-response.ts","../../../../packages/php-wasm/universal/src/lib/error-event-polyfill.ts","../../../../packages/php-wasm/universal/src/lib/wasm-error-reporting.ts","../../../../packages/php-wasm/universal/src/lib/php.ts","../../../../packages/php-wasm/universal/src/lib/ini.ts","../../../../packages/php-wasm/universal/src/lib/error-reporting.ts","../../../../packages/php-wasm/universal/src/lib/http-cookie-store.ts","../../../../packages/php-wasm/universal/src/lib/stream-read-file-from-php.ts","../../../../packages/php-wasm/universal/src/lib/iterate-files.ts","../../../../packages/php-wasm/universal/src/lib/write-files-stream-to-php.ts","../../../../packages/php-wasm/universal/src/lib/single-php-instance-manager.ts","../../../../packages/php-wasm/universal/src/lib/php-process-manager.ts","../../../../packages/php-wasm/universal/src/lib/supported-php-versions.ts","../../../../packages/php-wasm/universal/src/lib/urls.ts","../../../../packages/php-wasm/universal/src/lib/encode-as-multipart.ts","../../../../packages/php-wasm/universal/src/lib/php-request-handler.ts","../../../../packages/php-wasm/universal/src/lib/rotate-php-runtime.ts","../../../../packages/php-wasm/universal/src/lib/write-files.ts","../../../../packages/php-wasm/universal/src/lib/proxy-file-system.ts","../../../../packages/php-wasm/universal/src/lib/sandboxed-spawn-handler-factory.ts","../../../../packages/php-wasm/universal/src/lib/comlink-sync.ts","../../../../packages/php-wasm/universal/src/lib/comlink-node-process-adapter.ts","../../../../packages/php-wasm/universal/src/lib/serialize-error.ts","../../../../packages/php-wasm/universal/src/lib/api.ts","../../../../packages/php-wasm/universal/src/lib/file-lock-manager.ts","../../../../packages/php-wasm/universal/src/lib/file-lock-interval-tree.ts","../../../../packages/php-wasm/universal/src/lib/file-lock-manager-in-memory.ts","../../../../packages/php-wasm/universal/src/lib/file-lock-manager-composite.ts","../../../../packages/php-wasm/universal/src/lib/object-pool-proxy.ts"],"sourcesContent":["/**\n * Emscripten's filesystem-related Exception.\n *\n * @see https://emscripten.org/docs/api_reference/Filesystem-API.html\n * @see https://github.com/emscripten-core/emscripten/blob/main/system/lib/libc/musl/arch/emscripten/bits/errno.h\n * @see https://github.com/emscripten-core/emscripten/blob/38eedc630f17094b3202fd48ac0c2c585dbea31e/system/include/wasi/api.h#L336\n */\n\nexport class ErrnoError extends Error {\n\tconstructor(errno: number, message?: string, options?: any) {\n\t\tsuper(message, options);\n\t\tthis.name = 'ErrnoError';\n\t\tthis.errno = errno;\n\t}\n\n\tnode?: any;\n\terrno: number;\n}\n/**\n * @see https://github.com/emscripten-core/emscripten/blob/38eedc630f17094b3202fd48ac0c2c585dbea31e/system/include/wasi/api.h#L336\n */\nexport const FileErrorCodes = {\n\t0: 'No error occurred. System call completed successfully.',\n\t1: 'Argument list too long.',\n\t2: 'Permission denied.',\n\t3: 'Address in use.',\n\t4: 'Address not available.',\n\t5: 'Address family not supported.',\n\t6: 'Resource unavailable, or operation would block.',\n\t7: 'Connection already in progress.',\n\t8: 'Bad file descriptor.',\n\t9: 'Bad message.',\n\t10: 'Device or resource busy.',\n\t11: 'Operation canceled.',\n\t12: 'No child processes.',\n\t13: 'Connection aborted.',\n\t14: 'Connection refused.',\n\t15: 'Connection reset.',\n\t16: 'Resource deadlock would occur.',\n\t17: 'Destination address required.',\n\t18: 'Mathematics argument out of domain of function.',\n\t19: 'Reserved.',\n\t20: 'File exists.',\n\t21: 'Bad address.',\n\t22: 'File too large.',\n\t23: 'Host is unreachable.',\n\t24: 'Identifier removed.',\n\t25: 'Illegal byte sequence.',\n\t26: 'Operation in progress.',\n\t27: 'Interrupted function.',\n\t28: 'Invalid argument.',\n\t29: 'I/O error.',\n\t30: 'Socket is connected.',\n\t31: 'There is a directory under that path.',\n\t32: 'Too many levels of symbolic links.',\n\t33: 'File descriptor value too large.',\n\t34: 'Too many links.',\n\t35: 'Message too large.',\n\t36: 'Reserved.',\n\t37: 'Filename too long.',\n\t38: 'Network is down.',\n\t39: 'Connection aborted by network.',\n\t40: 'Network unreachable.',\n\t41: 'Too many files open in system.',\n\t42: 'No buffer space available.',\n\t43: 'No such device.',\n\t44: 'There is no such file or directory OR the parent directory does not exist.',\n\t45: 'Executable file format error.',\n\t46: 'No locks available.',\n\t47: 'Reserved.',\n\t48: 'Not enough space.',\n\t49: 'No message of the desired type.',\n\t50: 'Protocol not available.',\n\t51: 'No space left on device.',\n\t52: 'Function not supported.',\n\t53: 'The socket is not connected.',\n\t54: 'Not a directory or a symbolic link to a directory.',\n\t55: 'Directory not empty.',\n\t56: 'State not recoverable.',\n\t57: 'Not a socket.',\n\t58: 'Not supported, or operation not supported on socket.',\n\t59: 'Inappropriate I/O control operation.',\n\t60: 'No such device or address.',\n\t61: 'Value too large to be stored in data type.',\n\t62: 'Previous owner died.',\n\t63: 'Operation not permitted.',\n\t64: 'Broken pipe.',\n\t65: 'Protocol error.',\n\t66: 'Protocol not supported.',\n\t67: 'Protocol wrong type for socket.',\n\t68: 'Result too large.',\n\t69: 'Read-only file system.',\n\t70: 'Invalid seek.',\n\t71: 'No such process.',\n\t72: 'Reserved.',\n\t73: 'Connection timed out.',\n\t74: 'Text file busy.',\n\t75: 'Cross-device link.',\n\t76: 'Extension: Capabilities insufficient.',\n} as any;\n\nexport function getEmscriptenFsError(e: any) {\n\tconst errno = typeof e === 'object' ? ((e as any)?.errno as any) : null;\n\tif (errno in FileErrorCodes) {\n\t\treturn FileErrorCodes[errno];\n\t}\n}\n\nexport function rethrowFileSystemError(messagePrefix = '') {\n\treturn function catchFileSystemError(value: (...args: any[]) => any) {\n\t\treturn function (...args: any[]) {\n\t\t\ttry {\n\t\t\t\t// @ts-expect-error Parameter 'this' implicitly has an 'any' type.ts(7006)\n\t\t\t\treturn value.apply(this, args);\n\t\t\t} catch (e) {\n\t\t\t\tconst errno =\n\t\t\t\t\ttypeof e === 'object' ? ((e as any)?.errno as any) : null;\n\t\t\t\tif (errno in FileErrorCodes) {\n\t\t\t\t\tconst errmsg = FileErrorCodes[errno];\n\t\t\t\t\tconst path = typeof args[1] === 'string' ? args[1] : null;\n\t\t\t\t\tconst formattedPrefix =\n\t\t\t\t\t\tpath !== null\n\t\t\t\t\t\t\t? messagePrefix.replaceAll('{path}', path)\n\t\t\t\t\t\t\t: messagePrefix;\n\t\t\t\t\tthrow new ErrnoError(\n\t\t\t\t\t\terrno,\n\t\t\t\t\t\t`${formattedPrefix}: ${errmsg}`,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcause: e,\n\t\t\t\t\t\t}\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tthrow e;\n\t\t\t}\n\t\t};\n\t};\n}\n","import type { Emscripten } from './emscripten-types';\nimport {\n\tErrnoError,\n\tgetEmscriptenFsError,\n\trethrowFileSystemError,\n} from './rethrow-file-system-error';\nimport { logger } from '@php-wasm/logger';\nimport { dirname, joinPaths } from '@php-wasm/util';\n\nexport interface RmDirOptions {\n\t/**\n\t * If true, recursively removes the directory and all its contents.\n\t * Default: true.\n\t */\n\trecursive?: boolean;\n}\n\nexport interface ListFilesOptions {\n\t/**\n\t * If true, prepend given folder path to all file names.\n\t * Default: false.\n\t */\n\tprependPath: boolean;\n}\n\nexport class FSHelpers {\n\t/**\n\t * Reads a file from the PHP filesystem and returns it as a string.\n\t *\n\t * @throws {@link @php-wasm/universal:ErrnoError} – If the file doesn't exist.\n\t * @param FS\n\t * @param path - The file path to read.\n\t * @returns The file contents.\n\t */\n\tstatic readFileAsText(FS: Emscripten.RootFS, path: string) {\n\t\treturn new TextDecoder().decode(FSHelpers.readFileAsBuffer(FS, path));\n\t}\n\n\t/**\n\t * Reads a file from the PHP filesystem and returns it as an array buffer.\n\t *\n\t * @throws {@link @php-wasm/universal:ErrnoError} – If the file doesn't exist.\n\t * @param FS\n\t * @param path - The file path to read.\n\t * @returns The file contents.\n\t */\n\tstatic readFileAsBuffer(FS: Emscripten.RootFS, path: string): Uint8Array {\n\t\treturn FS.readFile(path);\n\t}\n\n\t/**\n\t * Overwrites data in a file in the PHP filesystem.\n\t * Creates a new file if one doesn't exist yet.\n\t *\n\t * @param FS\n\t * @param path - The file path to write to.\n\t * @param data - The data to write to the file.\n\t */\n\tstatic writeFile(\n\t\tFS: Emscripten.RootFS,\n\t\tpath: string,\n\t\tdata: string | Uint8Array | Buffer\n\t) {\n\t\tFS.writeFile(path, data);\n\t}\n\n\t/**\n\t * Removes a file from the PHP filesystem.\n\t *\n\t * @throws {@link @php-wasm/universal:ErrnoError} – If the file doesn't exist.\n\t * @param FS\n\t * @param path - The file path to remove.\n\t */\n\tstatic unlink(FS: Emscripten.RootFS, path: string) {\n\t\tFS.unlink(path);\n\t}\n\n\t/**\n\t * Moves a file or directory in the PHP filesystem to a\n\t * new location.\n\t *\n\t * @param FS\n\t * @param fromPath The path to rename.\n\t * @param toPath The new path.\n\t */\n\tstatic mv(FS: Emscripten.RootFS, fromPath: string, toPath: string) {\n\t\ttry {\n\t\t\t// FS.rename moves the inode within the same filesystem.\n\t\t\t// If fromPath and toPath are on different filesystems,\n\t\t\t// the operation will fail. In that case, we need to do\n\t\t\t// a recursive copy of all the files and remove the original.\n\t\t\t// Note this is also what happens in the linux `mv` command.\n\t\t\tconst fromMount = FS.lookupPath(fromPath).node.mount;\n\t\t\tconst toMount = FSHelpers.fileExists(FS, toPath)\n\t\t\t\t? FS.lookupPath(toPath).node.mount\n\t\t\t\t: FS.lookupPath(dirname(toPath)).node.mount;\n\t\t\tconst movingBetweenFilesystems =\n\t\t\t\tfromMount.mountpoint !== toMount.mountpoint;\n\n\t\t\tif (movingBetweenFilesystems) {\n\t\t\t\tFSHelpers.copyRecursive(FS, fromPath, toPath);\n\t\t\t\tif (FSHelpers.isDir(FS, fromPath)) {\n\t\t\t\t\tFSHelpers.rmdir(FS, fromPath, { recursive: true });\n\t\t\t\t} else {\n\t\t\t\t\tFS.unlink(fromPath);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tFS.rename(fromPath, toPath);\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tconst errmsg = getEmscriptenFsError(e);\n\t\t\tif (!errmsg) {\n\t\t\t\tthrow e;\n\t\t\t}\n\t\t\tthrow new Error(\n\t\t\t\t`Could not move ${fromPath} to ${toPath}: ${errmsg}`,\n\t\t\t\t{\n\t\t\t\t\tcause: e,\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Removes a directory from the PHP filesystem.\n\t *\n\t * @param FS\n\t * @param path The directory path to remove.\n\t * @param options Options for the removal.\n\t */\n\tstatic rmdir(\n\t\tFS: Emscripten.RootFS,\n\t\tpath: string,\n\t\toptions: RmDirOptions = { recursive: true }\n\t) {\n\t\t/**\n\t\t * Mount points cannot be removed and will throw a ErrnoError with\n\t\t * the code 10 (EBUSY).\n\t\t * To prevent the recursive option from removing internal files before\n\t\t * failing to remove the mount point, we need to check if the path is a\n\t\t * mount point and throw an error early.\n\t\t *\n\t\t * Because a mountpoint can be a symlink, we should not follow it.\n\t\t * Otherwise, a mounted sylink would point to the symlinked path,\n\t\t * instead of the mountpoint.\n\t\t */\n\t\tconst mountPoint = FS.lookupPath(path, { follow: false });\n\t\tif (mountPoint?.node.mount.mountpoint === path) {\n\t\t\tthrow new ErrnoError(10);\n\t\t}\n\n\t\tif (options?.recursive) {\n\t\t\tFSHelpers.listFiles(FS, path).forEach((file) => {\n\t\t\t\tconst filePath = `${path}/${file}`;\n\t\t\t\tif (FSHelpers.isDir(FS, filePath)) {\n\t\t\t\t\tFSHelpers.rmdir(FS, filePath, options);\n\t\t\t\t} else {\n\t\t\t\t\tFSHelpers.unlink(FS, filePath);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t\tif (FS.getPath(FS.lookupPath(path).node) === FS.cwd()) {\n\t\t\tFS.chdir(joinPaths(FS.cwd(), '..'));\n\t\t}\n\t\tFS.rmdir(path);\n\t}\n\n\t/**\n\t * Lists the files and directories in the given directory.\n\t *\n\t * @param FS\n\t * @param path - The directory path to list.\n\t * @param options - Options for the listing.\n\t * @returns The list of files and directories in the given directory.\n\t */\n\tstatic listFiles(\n\t\tFS: Emscripten.RootFS,\n\t\tpath: string,\n\t\toptions: ListFilesOptions = { prependPath: false }\n\t): string[] {\n\t\tif (!FSHelpers.fileExists(FS, path)) {\n\t\t\treturn [];\n\t\t}\n\t\ttry {\n\t\t\tconst files = FS.readdir(path).filter(\n\t\t\t\t(name: string) => name !== '.' && name !== '..'\n\t\t\t);\n\t\t\tif (options.prependPath) {\n\t\t\t\tconst prepend = path.replace(/\\/$/, '');\n\t\t\t\treturn files.map((name: string) => `${prepend}/${name}`);\n\t\t\t}\n\t\t\treturn files;\n\t\t} catch (e) {\n\t\t\tlogger.error(e, { path });\n\t\t\treturn [];\n\t\t}\n\t}\n\n\t/**\n\t * Checks if a directory exists in the PHP filesystem.\n\t *\n\t * @param FS\n\t * @param path – The path to check.\n\t * @returns True if the path is a directory, false otherwise.\n\t */\n\tstatic isDir(FS: Emscripten.RootFS, path: string): boolean {\n\t\tif (!FSHelpers.fileExists(FS, path)) {\n\t\t\treturn false;\n\t\t}\n\t\treturn FS.isDir(FS.lookupPath(path, { follow: true }).node.mode);\n\t}\n\n\t/**\n\t * Checks if a file exists in the PHP filesystem.\n\t *\n\t * @param FS\n\t * @param path – The path to check.\n\t * @returns True if the path is a file, false otherwise.\n\t */\n\tstatic isFile(FS: Emscripten.RootFS, path: string): boolean {\n\t\tif (!FSHelpers.fileExists(FS, path)) {\n\t\t\treturn false;\n\t\t}\n\t\treturn FS.isFile(FS.lookupPath(path, { follow: true }).node.mode);\n\t}\n\n\t/**\n\t * Creates a symlink in the PHP filesystem.\n\t *\n\t * @param FS\n\t * @param target\n\t * @param link\n\t */\n\tstatic symlink(FS: Emscripten.RootFS, target: string, link: string): any {\n\t\treturn FS.symlink(target, link);\n\t}\n\n\t/**\n\t * Checks if a path is a symlink in the PHP filesystem.\n\t *\n\t * @param FS\n\t * @param path\n\t * @returns True if the path is a symlink, false otherwise.\n\t */\n\tstatic isSymlink(FS: Emscripten.RootFS, path: string): boolean {\n\t\tif (!FSHelpers.fileExists(FS, path)) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn FS.isLink(FS.lookupPath(path).node.mode);\n\t}\n\n\t/**\n\t * Reads the target of a symlink in the PHP filesystem.\n\t * @param FS\n\t * @param path\n\t * @returns The target of the symlink.\n\t * @throws {@link @php-wasm/universal:ErrnoError} – If the path is not a symlink.\n\t */\n\tstatic readlink(FS: Emscripten.RootFS, path: string): string {\n\t\treturn FS.readlink(path);\n\t}\n\n\t/**\n\t * Gets the real path of a file in the PHP filesystem.\n\t * @param FS\n\t * @param path\n\t *\n\t * @returns The real path of the file.\n\t */\n\tstatic realpath(FS: Emscripten.RootFS, path: string): string {\n\t\treturn FS.lookupPath(path, { follow: true }).path;\n\t}\n\n\t/**\n\t * Checks if a file (or a directory) exists in the PHP filesystem.\n\t *\n\t * @param FS\n\t * @param path - The file path to check.\n\t * @returns True if the file exists, false otherwise.\n\t */\n\tstatic fileExists(FS: Emscripten.RootFS, path: string): boolean {\n\t\ttry {\n\t\t\tFS.lookupPath(path);\n\t\t\treturn true;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Recursively creates a directory with the given path in the PHP filesystem.\n\t * For example, if the path is `/root/php/data`, and `/root` already exists,\n\t * it will create the directories `/root/php` and `/root/php/data`.\n\t *\n\t * @param FS\n\t * @param path - The directory path to create.\n\t */\n\tstatic mkdir(FS: Emscripten.RootFS, path: string) {\n\t\tFS.mkdirTree(path);\n\t}\n\n\tstatic copyRecursive(\n\t\tFS: Emscripten.FileSystemInstance,\n\t\tfromPath: string,\n\t\ttoPath: string\n\t) {\n\t\tconst fromNode = FS.lookupPath(fromPath).node;\n\t\tif (FS.isDir(fromNode.mode)) {\n\t\t\tFS.mkdirTree(toPath);\n\t\t\tconst filenames = FS.readdir(fromPath).filter(\n\t\t\t\t(name: string) => name !== '.' && name !== '..'\n\t\t\t);\n\t\t\tfor (const filename of filenames) {\n\t\t\t\tFSHelpers.copyRecursive(\n\t\t\t\t\tFS,\n\t\t\t\t\tjoinPaths(fromPath, filename),\n\t\t\t\t\tjoinPaths(toPath, filename)\n\t\t\t\t);\n\t\t\t}\n\t\t} else if (FS.isLink(fromNode.mode)) {\n\t\t\tFS.symlink(FS.readlink(fromPath), toPath);\n\t\t} else {\n\t\t\tFS.writeFile(toPath, FS.readFile(fromPath));\n\t\t}\n\t}\n}\n\n// Apply decorators manually until the decorator syntax is supported\n// by Node.js. We do this so we can take advantage of Node.js type stripping\n// in the meantime.\n// TODO: Inline these decorators once Node.js supports it.\nFSHelpers.readFileAsText = rethrowFileSystemError('Could not read \"{path}\"')(\n\tFSHelpers.readFileAsText\n);\nFSHelpers.readFileAsBuffer = rethrowFileSystemError('Could not read \"{path}\"')(\n\tFSHelpers.readFileAsBuffer\n);\nFSHelpers.writeFile = rethrowFileSystemError('Could not write to \"{path}\"')(\n\tFSHelpers.writeFile\n);\nFSHelpers.unlink = rethrowFileSystemError('Could not unlink \"{path}\"')(\n\tFSHelpers.unlink\n);\nFSHelpers.rmdir = rethrowFileSystemError('Could not remove directory \"{path}\"')(\n\tFSHelpers.rmdir\n);\nFSHelpers.listFiles = rethrowFileSystemError(\n\t'Could not list files in \"{path}\"'\n)(FSHelpers.listFiles);\nFSHelpers.isDir = rethrowFileSystemError('Could not stat \"{path}\"')(\n\tFSHelpers.isDir\n);\nFSHelpers.isFile = rethrowFileSystemError('Could not stat \"{path}\"')(\n\tFSHelpers.isFile\n);\nFSHelpers.realpath = rethrowFileSystemError('Could not stat \"{path}\"')(\n\tFSHelpers.realpath\n);\nFSHelpers.fileExists = rethrowFileSystemError('Could not stat \"{path}\"')(\n\tFSHelpers.fileExists\n);\nFSHelpers.mkdir = rethrowFileSystemError('Could not create directory \"{path}\"')(\n\tFSHelpers.mkdir\n);\nFSHelpers.copyRecursive = rethrowFileSystemError(\n\t'Could not copy files from \"{path}\"'\n)(FSHelpers.copyRecursive);\n","import type { EmscriptenDownloadMonitor } from '@php-wasm/progress';\nimport type { ListFilesOptions, RmDirOptions } from './fs-helpers';\nimport type { PHP } from './php';\nimport type { PHPRequestHandler } from './php-request-handler';\nimport type { PHPResponse, StreamedPHPResponse } from './php-response';\nimport type {\n\tMessageListener,\n\tPHPEvent,\n\tPHPRequest,\n\tPHPRunOptions,\n} from './universal-php';\n\nconst _private = new WeakMap<\n\tPHPWorker,\n\t{\n\t\trequestHandler?: PHPRequestHandler;\n\t\tphp?: PHP;\n\t\tmonitor?: EmscriptenDownloadMonitor;\n\t}\n>();\n\nexport type LimitedPHPApi = Pick<\n\tPHP,\n\t| 'request'\n\t| 'defineConstant'\n\t| 'mkdir'\n\t| 'mkdirTree'\n\t| 'readFileAsText'\n\t| 'readFileAsBuffer'\n\t| 'writeFile'\n\t| 'unlink'\n\t| 'mv'\n\t| 'rmdir'\n\t| 'listFiles'\n\t| 'isDir'\n\t| 'fileExists'\n\t| 'chdir'\n\t| 'run'\n\t| 'onMessage'\n> & {\n\tdocumentRoot: PHP['documentRoot'];\n\tabsoluteUrl: PHP['absoluteUrl'];\n\taddEventListener:\n\t\t| PHP['addEventListener']\n\t\t| ((event: string, listener: (event: any) => any) => void);\n\tremoveEventListener:\n\t\t| PHP['removeEventListener']\n\t\t| ((event: string, listener: (event: any) => any) => void);\n};\n\nexport type PHPWorkerEvent = PHPEvent | { type: string };\nexport type PHPWorkerEventListener = (event: PHPWorkerEvent) => void;\n/**\n * A PHP client that can be used to run PHP code in the browser.\n */\nexport class PHPWorker implements LimitedPHPApi, AsyncDisposable {\n\t/** @inheritDoc @php-wasm/universal!RequestHandler.absoluteUrl */\n\tabsoluteUrl = '';\n\t/** @inheritDoc @php-wasm/universal!RequestHandler.documentRoot */\n\tdocumentRoot = '';\n\n\tprivate chroot: string | null = null;\n\n\t#eventListeners: Map<string, Set<PHPWorkerEventListener>> = new Map();\n\n\tonMessageListeners: MessageListener[] = [];\n\t/** @inheritDoc */\n\tconstructor(\n\t\trequestHandler?: PHPRequestHandler,\n\t\tmonitor?: EmscriptenDownloadMonitor\n\t) {\n\t\t/**\n\t\t * Workaround for TypeScript limitation.\n\t\t * Declaring a private field using the EcmaScript syntax like this:\n\t\t *\n\t\t * #php: PHP\n\t\t *\n\t\t * Makes that field a part of the public API of the class. This means\n\t\t * you can no longer assign seemingly compatible objects:\n\t\t *\n\t\t * ```ts\n\t\t * class PrivateEcma {\n\t\t * #privateProp: string = '';\n\t\t * callback() { }\n\t\t * }\n\t\t * interface CompatibleInterface {\n\t\t * callback(): void;\n\t\t * }\n\t\t * const compatObj: CompatibleInterface = {} as any;\n\t\t * const tsObj: PrivateEcma = compatObj;\n\t\t * // Property '#privateProp' is missing in type 'CompatibleInterface' but\n\t\t * // required in type 'PrivateEcma'\n\t\t * ```\n\t\t */\n\t\t_private.set(this, {\n\t\t\tmonitor,\n\t\t});\n\t\tif (requestHandler) {\n\t\t\tthis.__internal_setRequestHandler(requestHandler);\n\t\t}\n\t}\n\n\tpublic __internal_setRequestHandler(requestHandler: PHPRequestHandler) {\n\t\tthis.absoluteUrl = requestHandler.absoluteUrl;\n\t\tthis.documentRoot = requestHandler.documentRoot;\n\t\tthis.chroot = this.documentRoot;\n\t\t_private.set(this, {\n\t\t\t..._private.get(this),\n\t\t\trequestHandler,\n\t\t});\n\t}\n\n\t/**\n\t * @internal\n\t * @deprecated\n\t * Do not use this method directly in the code consuming\n\t * the web API. It will change or even be removed without\n\t * a warning.\n\t */\n\tprotected __internal_getPHP() {\n\t\treturn _private.get(this)!.php;\n\t}\n\n\t/**\n\t * @internal\n\t * @deprecated\n\t * Do not use this method directly in the code consuming\n\t * the web API. It will change or even be removed without\n\t * a warning.\n\t */\n\tprotected __internal_getRequestHandler() {\n\t\treturn _private.get(this)!.requestHandler;\n\t}\n\n\tasync setPrimaryPHP(php: PHP) {\n\t\t_private.set(this, {\n\t\t\t..._private.get(this)!,\n\t\t\tphp,\n\t\t});\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!PHPRequestHandler.pathToInternalUrl */\n\tpathToInternalUrl(path: string): string {\n\t\treturn _private.get(this)!.requestHandler!.pathToInternalUrl(path);\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!PHPRequestHandler.internalUrlToPath */\n\tinternalUrlToPath(internalUrl: string): string {\n\t\treturn _private\n\t\t\t.get(this)!\n\t\t\t.requestHandler!.internalUrlToPath(internalUrl);\n\t}\n\n\t/**\n\t * The onDownloadProgress event listener.\n\t */\n\tasync onDownloadProgress(\n\t\tcallback: (progress: CustomEvent<ProgressEvent>) => void\n\t): Promise<void> {\n\t\treturn _private\n\t\t\t.get(this)!\n\t\t\t.monitor?.addEventListener('progress', callback as any);\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!PHP.mv */\n\tasync mv(fromPath: string, toPath: string) {\n\t\treturn _private.get(this)!.php!.mv(fromPath, toPath);\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!PHP.rmdir */\n\tasync rmdir(path: string, options?: RmDirOptions) {\n\t\treturn _private.get(this)!.php!.rmdir(path, options);\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!PHPRequestHandler.request */\n\tasync request(request: PHPRequest): Promise<PHPResponse> {\n\t\tconst requestHandler = _private.get(this)!.requestHandler!;\n\t\treturn await requestHandler.request(request);\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!/PHP.run */\n\tasync run(request: PHPRunOptions): Promise<PHPResponse> {\n\t\tconst { php, reap } = await this.acquirePHPInstance();\n\t\ttry {\n\t\t\treturn await php.run(request);\n\t\t} finally {\n\t\t\treap();\n\t\t}\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!/PHP.cli */\n\tasync cli(\n\t\targv: string[],\n\t\toptions?: { env?: Record<string, string> }\n\t): Promise<StreamedPHPResponse> {\n\t\tconst { php, reap } = await this.acquirePHPInstance();\n\t\tlet response: StreamedPHPResponse;\n\t\ttry {\n\t\t\tresponse = await php.cli(argv, options);\n\t\t} catch (error) {\n\t\t\treap();\n\t\t\tthrow error;\n\t\t}\n\t\t/**\n\t\t * Register the reap() callback to run asynchronously once\n\t\t * the response is finished.\n\t\t *\n\t\t * We don't await for response.finished here. It is a\n\t\t * `StreamedPHPResponse` instance and the caller may want\n\t\t * to start processing the streamed data immediately.\n\t\t */\n\t\tresponse.finished.finally(reap);\n\t\treturn response;\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!/PHP.chdir */\n\tchdir(path: string): void {\n\t\t// Remember the new chroot for all PHP instances yet to be acquired.\n\t\tthis.chroot = path;\n\t\treturn _private.get(this)!.php!.chdir(path);\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!/PHP.chdir */\n\tcwd(): string {\n\t\treturn _private.get(this)!.php!.cwd();\n\t}\n\n\t/**\n\t * @returns A PHP instance with a consistent chroot.\n\t */\n\tprivate async acquirePHPInstance() {\n\t\tconst { php, reap } = await _private\n\t\t\t.get(this)!\n\t\t\t.requestHandler!.instanceManager.acquirePHPInstance();\n\t\tif (this.chroot !== null) {\n\t\t\tphp.chdir(this.chroot);\n\t\t}\n\t\tthis.registerWorkerListeners(php);\n\t\treturn { php, reap };\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!/PHP.setSapiName */\n\tsetSapiName(newName: string): void {\n\t\t_private.get(this)!.php!.setSapiName(newName);\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!/PHP.mkdir */\n\tmkdir(path: string): void {\n\t\treturn _private.get(this)!.php!.mkdir(path);\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!/PHP.mkdirTree */\n\tmkdirTree(path: string): void {\n\t\treturn _private.get(this)!.php!.mkdirTree(path);\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!/PHP.readFileAsText */\n\treadFileAsText(path: string): string {\n\t\treturn _private.get(this)!.php!.readFileAsText(path);\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!/PHP.readFileAsBuffer */\n\treadFileAsBuffer(path: string): Uint8Array {\n\t\treturn _private.get(this)!.php!.readFileAsBuffer(path);\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!/PHP.writeFile */\n\twriteFile(path: string, data: string | Uint8Array): void {\n\t\treturn _private.get(this)!.php!.writeFile(path, data);\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!/PHP.unlink */\n\tunlink(path: string): void {\n\t\treturn _private.get(this)!.php!.unlink(path);\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!/PHP.listFiles */\n\tlistFiles(path: string, options?: ListFilesOptions): string[] {\n\t\treturn _private.get(this)!.php!.listFiles(path, options);\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!/PHP.isDir */\n\tisDir(path: string): boolean {\n\t\treturn _private.get(this)!.php!.isDir(path);\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!/PHP.isFile */\n\tisFile(path: string): boolean {\n\t\treturn _private.get(this)!.php!.isFile(path);\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!/PHP.fileExists */\n\tfileExists(path: string): boolean {\n\t\treturn _private.get(this)!.php!.fileExists(path);\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!/PHP.onMessage */\n\tonMessage(listener: MessageListener) {\n\t\tthis.onMessageListeners.push(listener);\n\t\treturn async () => {\n\t\t\tthis.onMessageListeners = this.onMessageListeners.filter(\n\t\t\t\t(l) => l !== listener\n\t\t\t);\n\t\t};\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!/PHP.defineConstant */\n\tdefineConstant(key: string, value: string | boolean | number | null): void {\n\t\t_private.get(this)!.php!.defineConstant(key, value);\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!/PHP.addEventListener */\n\taddEventListener(\n\t\teventType: PHPWorkerEvent['type'],\n\t\tlistener: PHPWorkerEventListener\n\t): void {\n\t\tif (!this.#eventListeners.has(eventType)) {\n\t\t\tthis.#eventListeners.set(eventType, new Set());\n\t\t}\n\t\tthis.#eventListeners.get(eventType)!.add(listener);\n\t}\n\n\t/**\n\t * Removes an event listener for a PHP event.\n\t * @param eventType - The type of event to remove the listener from.\n\t * @param listener - The listener function to be removed.\n\t */\n\tremoveEventListener(\n\t\teventType: PHPWorkerEvent['type'],\n\t\tlistener: PHPWorkerEventListener\n\t) {\n\t\tthis.#eventListeners.get(eventType)?.delete(listener);\n\t}\n\n\tprotected dispatchEvent<Event extends PHPWorkerEvent>(event: Event) {\n\t\tconst listeners = this.#eventListeners.get(event.type);\n\t\tif (!listeners) {\n\t\t\treturn;\n\t\t}\n\t\tfor (const listener of listeners) {\n\t\t\tlistener(event);\n\t\t}\n\t}\n\n\tprotected registerWorkerListeners(php: PHP) {\n\t\tphp.addEventListener('*', async (event) => {\n\t\t\tthis.dispatchEvent(event);\n\t\t});\n\t\tphp.onMessage(async (message) => {\n\t\t\tfor (const listener of this.onMessageListeners) {\n\t\t\t\tconst returnData = await listener(message);\n\t\t\t\tif (returnData) {\n\t\t\t\t\treturn returnData;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn '';\n\t\t});\n\t}\n\n\tasync [Symbol.asyncDispose]() {\n\t\tawait _private.get(this)!.requestHandler?.[Symbol.asyncDispose]();\n\t}\n}\n","/**\n * Check if the Emscripten-thrown error is an exit code 0 error.\n *\n * @param e The error to check\n * @returns True if the error appears to represent an exit code or status\n */\nexport function isExitCode(e: any): e is { status: number } {\n\tif (!(e instanceof Error)) {\n\t\treturn false;\n\t}\n\treturn e?.name === 'ExitStatus' && 'status' in e;\n}\n","import { logger } from '@php-wasm/logger';\nimport type { IncomingMessage, Server, ServerResponse } from 'http';\n\nconst RuntimeId = Symbol('RuntimeId');\nconst loadedRuntimes: Map<number, PHPRuntime> = new Map();\nlet lastRuntimeId = 0;\n\n/**\n * Loads the PHP runtime with the given arguments and data dependencies.\n *\n * This function handles the entire PHP initialization pipeline. In particular,\n * it:\n *\n * * Instantiates the Emscripten PHP module\n * * Wires it together with the data dependencies and loads them\n * * Ensures is all happens in a correct order\n * * Waits until the entire loading sequence is finished\n *\n * Basic usage:\n *\n * ```js\n * const phpLoaderModule = await getPHPLoaderModule(\"7.4\");\n * const php = await loadPHPRuntime( phpLoaderModule );\n * console.log(php.run(`<?php echo \"Hello, world!\"; `));\n * // { stdout: ArrayBuffer containing the string \"Hello, world!\", stderr: [''], exitCode: 0 }\n * ```\n *\n * **The PHP loader module:**\n *\n * In the basic usage example, `phpLoaderModule` is **not** a vanilla\n * Emscripten module. Instead, it's an ESM module that wraps the regular\n * Emscripten output and adds some extra functionality. It's generated by the\n * Dockerfile shipped with this repo. Here's the API it provides:\n *\n * ```js\n * // php.wasm size in bytes:\n * export const dependenciesTotalSize = 5644199;\n *\n * // php.wasm filename:\n * export const dependencyFilename = 'php.wasm';\n *\n * // Run Emscripten's generated module:\n * export default function(jsEnv, emscriptenModuleArgs) {}\n * ```\n *\n * **PHP Filesystem:**\n *\n * Once initialized, the PHP has its own filesystem separate from the project\n * files. It's provided by [Emscripten and uses its FS library](https://emscripten.org/docs/api_reference/Filesystem-API.html).\n *\n * The API exposed to you via the PHP class is succinct and abstracts\n * certain unintuitive parts of low-level filesystem interactions.\n *\n * Here's how to use it:\n *\n * ```js\n * // Recursively create a /var/www directory\n * php.mkdirTree('/var/www');\n *\n * console.log(php.fileExists('/var/www/file.txt'));\n * // false\n *\n * php.writeFile('/var/www/file.txt', 'Hello from the filesystem!');\n *\n * console.log(php.fileExists('/var/www/file.txt'));\n * // true\n *\n * console.log(php.readFile('/var/www/file.txt'));\n * // \"Hello from the filesystem!\n *\n * // Delete the file:\n * php.unlink('/var/www/file.txt');\n * ```\n *\n * For more details consult the PHP class directly.\n *\n * **Data dependencies:**\n *\n * Using existing PHP packages by manually recreating them file-by-file would\n * be quite inconvenient. Fortunately, Emscripten provides a \"data dependencies\"\n * feature.\n *\n * Data dependencies consist of a `dependency.data` file and a `dependency.js`\n * loader and can be packaged with the [file_packager.py tool](\n * https://emscripten.org/docs/porting/files/packaging_files.html#packaging-using-the-file-packager-tool).\n * This project requires wrapping the Emscripten-generated `dependency.js` file\n * in an ES module as follows:\n *\n * 1. Prepend `export default function(emscriptenPHPModule) {'; `\n * 2. Prepend `export const dependencyFilename = '<DATA FILE NAME>'; `\n * 3. Prepend `export const dependenciesTotalSize = <DATA FILE SIZE>;`\n * 4. Append `}`\n *\n * Be sure to use the `--export-name=\"emscriptenPHPModule\"` file_packager.py\n * option.\n *\n * You want the final output to look as follows:\n *\n * ```js\n * export const dependenciesTotalSize = 5644199;\n * export const dependencyFilename = 'dependency.data';\n * export default function(emscriptenPHPModule) {\n * // Emscripten-generated code:\n * var Module = typeof emscriptenPHPModule !== 'undefined' ? emscriptenPHPModule : {};\n * // ... the rest of it ...\n * }\n * ```\n *\n * Such a constructions enables loading the `dependency.js` as an ES Module\n * using `import(\"/dependency.js\")`.\n *\n * Once it's ready, you can load PHP and your data dependencies as follows:\n *\n * ```js\n * const [phpLoaderModule, wordPressLoaderModule] = await Promise.all([\n * getPHPLoaderModule(\"7.4\"),\n * import(\"/wp.js\")\n * ]);\n * const php = await loadPHPRuntime(phpLoaderModule, {}, [wordPressLoaderModule]);\n * ```\n *\n * @public\n * @param phpLoaderModule - The ESM-wrapped Emscripten module. Consult the Dockerfile for the build process.\n * @param options - The Emscripten module arguments, see https://emscripten.org/docs/api_reference/module.html#affecting-execution.\n * @returns Loaded runtime id.\n */\n\nexport async function loadPHPRuntime(\n\tphpLoaderModule: PHPLoaderModule,\n\t...options: EmscriptenOptions[]\n): Promise<number> {\n\tconst phpModuleArgs = Object.assign({}, ...options);\n\n\tconst [phpReady, resolvePHP, rejectPHP] = makePromise();\n\n\tconst PHPRuntime = phpLoaderModule.init(currentJsRuntime, {\n\t\tonAbort(reason) {\n\t\t\trejectPHP(reason);\n\t\t\t// This can happen after PHP has been initialized so\n\t\t\t// let's just log it.\n\t\t\tlogger.error(reason);\n\t\t},\n\t\tENV: {},\n\t\t// Emscripten sometimes prepends a '/' to the path, which\n\t\t// breaks vite dev mode. An identity `locateFile` function\n\t\t// fixes it.\n\t\tlocateFile: (path) => path,\n\t\t...phpModuleArgs,\n\t\tnoInitialRun: true,\n\t\tonRuntimeInitialized() {\n\t\t\tif (phpModuleArgs.onRuntimeInitialized) {\n\t\t\t\tphpModuleArgs.onRuntimeInitialized(PHPRuntime);\n\t\t\t}\n\t\t\tresolvePHP();\n\t\t},\n\t});\n\n\tawait phpReady;\n\n\tconst id = ++lastRuntimeId;\n\n\t// TODO: Ask @adamziel why this is here.\n\t// eslint-disable-next-line @typescript-eslint/no-unused-expressions -- why is this here?\n\tPHPRuntime.FS;\n\tPHPRuntime.id = id;\n\tPHPRuntime.originalExit = PHPRuntime._exit;\n\n\tPHPRuntime._exit = function (code: number) {\n\t\tif (PHPRuntime.outboundNetworkProxyServer) {\n\t\t\tPHPRuntime.outboundNetworkProxyServer.close();\n\t\t\tPHPRuntime.outboundNetworkProxyServer.closeAllConnections();\n\t\t}\n\t\tloadedRuntimes.delete(id);\n\t\treturn PHPRuntime.originalExit(code);\n\t};\n\n\tPHPRuntime[RuntimeId] = id;\n\tloadedRuntimes.set(id, PHPRuntime);\n\treturn id;\n}\n\nexport type RuntimeType = 'NODE' | 'WEB' | 'WORKER';\n\ndeclare const self: WindowOrWorkerGlobalScope;\ndeclare const WorkerGlobalScope: object | undefined;\n\nexport type PHPRuntimeId = number;\n\n/**\n * Retrieves a PHP runtime by its ID and removes it from the internal registry.\n *\n * When you call `loadPHPRuntime()`, it creates an Emscripten-based PHP instance and\n * stores it in a module-level Map keyed by a numeric ID. This function is the only\n * way to retrieve that runtime object so you can actually use it.\n *\n * The \"pop\" semantic is intentional: retrieving a runtime also removes it from the\n * registry. This prevents memory leaks since the registry would otherwise hold\n * references to every runtime ever created. Once you pop a runtime, you own it and\n * are responsible for its lifecycle.\n *\n * Typical usage flow:\n * ```ts\n * // 1. Load a PHP runtime (returns just the ID)\n * const runtimeId = await loadPHPRuntime(phpLoaderModule);\n *\n * // 2. Pop the runtime to get the actual Emscripten module\n * const phpRuntime = popLoadedRuntime(runtimeId);\n *\n * // 3. Now you can use phpRuntime to run PHP code, access the filesystem, etc.\n * ```\n *\n * @param id - The numeric ID returned by `loadPHPRuntime()`.\n * @param options.dangerouslyKeepTheRuntimeInTheMap - Test-only escape hatch. When true,\n * retrieves the runtime without removing it from the registry. This violates\n * the function's contract and only works when `process.env.TEST` is set.\n * Never use this in production code.\n * @returns The PHP runtime object (an Emscripten module instance).\n * @throws If no runtime exists with the given ID.\n */\nexport function popLoadedRuntime(\n\tid: PHPRuntimeId,\n\t{\n\t\tdangerouslyKeepTheRuntimeInTheMap = false,\n\t}: { dangerouslyKeepTheRuntimeInTheMap?: boolean } = {}\n): PHPRuntime {\n\tconst runtime = loadedRuntimes.get(id);\n\tif (!runtime) {\n\t\tthrow new Error(`Runtime with id ${id} not found`);\n\t}\n\tif (dangerouslyKeepTheRuntimeInTheMap) {\n\t\tif (!process?.env?.['TEST']) {\n\t\t\tthrow new Error('Cannot pop runtime in non-test environment');\n\t\t}\n\t\treturn runtime;\n\t}\n\n\tloadedRuntimes.delete(id);\n\treturn runtime;\n}\n\nexport const currentJsRuntime = (function () {\n\tif (typeof process !== 'undefined' && process.release?.name === 'node') {\n\t\treturn 'NODE';\n\t} else if (typeof window !== 'undefined') {\n\t\treturn 'WEB';\n\t} else if (\n\t\ttypeof WorkerGlobalScope !== 'undefined' &&\n\t\tself instanceof (WorkerGlobalScope as any)\n\t) {\n\t\treturn 'WORKER';\n\t} else {\n\t\treturn 'NODE';\n\t}\n})();\n\n/**\n * Creates and exposes Promise resolve/reject methods for later use.\n */\nconst makePromise = () => {\n\tconst methods: any = [];\n\n\tconst promise = new Promise((resolve, reject) => {\n\t\tmethods.push(resolve, reject);\n\t});\n\tmethods.unshift(promise);\n\n\treturn methods as [Promise<any>, (v?: any) => void, (e?: any) => void];\n};\n\nexport type PHPRuntime = any;\n\nexport type PHPLoaderModule = {\n\tdependencyFilename: string;\n\tdependenciesTotalSize: number;\n\tinit: (jsRuntime: string, options: EmscriptenOptions) => PHPRuntime;\n};\n\nexport type DataModule = {\n\tdependencyFilename: string;\n\tdependenciesTotalSize: number;\n\tdefault: (phpRuntime: PHPRuntime) => void;\n};\n\nexport type EmscriptenOptions = {\n\tonAbort?: (message: string) => void;\n\t/**\n\t * Set to true for debugging tricky WebAssembly errors.\n\t */\n\tdebug?: boolean;\n\tENV?: Record<string, string>;\n\tlocateFile?: (path: string) => string;\n\tnoInitialRun?: boolean;\n\tprint?: (message: string) => void;\n\tprintErr?: (message: string) => void;\n\tquit?: (status: number, toThrow: any) => void;\n\tonRuntimeInitialized?: (phpRuntime: PHPRuntime) => void;\n\tmonitorRunDependencies?: (left: number) => void;\n\tonMessage?: (listener: EmscriptenMessageListener) => void;\n\toutboundNetworkProxyServer?: Server<\n\t\ttypeof IncomingMessage,\n\t\ttypeof ServerResponse\n\t>;\n\tinstantiateWasm?: (\n\t\tinfo: WebAssembly.Imports,\n\t\treceiveInstance: (\n\t\t\tinstance: WebAssembly.Instance,\n\t\t\tmodule: WebAssembly.Module\n\t\t) => void\n\t) => void;\n} & Record<string, any>;\n\nexport type EmscriptenMessageListener = (type: string, data: string) => void;\n","/*\n * This type is used in Comlink.transferHandlers.set('PHPResponse', { ... })\n * so be sure to update that if you change this type.\n */\nexport interface PHPResponseData {\n\t/**\n\t * Response headers.\n\t */\n\treadonly headers: Record<string, string[]>;\n\n\t/**\n\t * Response body. Contains the output from `echo`,\n\t * `print`, inline HTML etc.\n\t */\n\treadonly bytes: Uint8Array;\n\n\t/**\n\t * Stderr contents, if any.\n\t */\n\treadonly errors: string;\n\n\t/**\n\t * The exit code of the script. `0` is a success, while\n\t * `1` and `2` indicate an error.\n\t */\n\treadonly exitCode: number;\n\n\t/**\n\t * Response HTTP status code, e.g. 200.\n\t */\n\treadonly httpStatusCode: number;\n}\n\nconst responseTexts: Record<number, string> = {\n\t500: 'Internal Server Error',\n\t502: 'Bad Gateway',\n\t404: 'Not Found',\n\t403: 'Forbidden',\n\t401: 'Unauthorized',\n\t400: 'Bad Request',\n\t301: 'Moved Permanently',\n\t302: 'Found',\n\t307: 'Temporary Redirect',\n\t308: 'Permanent Redirect',\n\t204: 'No Content',\n\t201: 'Created',\n\t200: 'OK',\n};\n\nexport class StreamedPHPResponse {\n\t/**\n\t * Response headers.\n\t */\n\tprivate readonly headersStream: ReadableStream<Uint8Array>;\n\n\t/**\n\t * Response body. Contains the output from `echo`,\n\t * `print`, inline HTML etc.\n\t */\n\treadonly stdout: ReadableStream<Uint8Array>;\n\n\t/**\n\t * Stderr contents, if any.\n\t */\n\treadonly stderr: ReadableStream<Uint8Array>;\n\n\t/**\n\t * The exit code of the script. `0` is a success, anything\n\t * else is an error.\n\t */\n\treadonly exitCode: Promise<number>;\n\n\tprivate parsedHeaders: Promise<{\n\t\theaders: Record<string, string[]>;\n\t\thttpStatusCode: number;\n\t}> | null = null;\n\n\tprivate cachedStdoutBytes: Promise<Uint8Array> | null = null;\n\tprivate cachedStderrText: Promise<string> | null = null;\n\n\tconstructor(\n\t\theaders: ReadableStream<Uint8Array>,\n\t\tstdout: ReadableStream<Uint8Array>,\n\t\tstderr: ReadableStream<Uint8Array>,\n\t\texitCode: Promise<number>\n\t) {\n\t\tthis.headersStream = headers;\n\t\tthis.stdout = stdout;\n\t\tthis.stderr = stderr;\n\t\tthis.exitCode = exitCode;\n\t}\n\n\t/**\n\t * True if the response is successful (HTTP status code 200-399),\n\t * false otherwise.\n\t */\n\tasync ok(): Promise<boolean> {\n\t\ttry {\n\t\t\tconst statusCode = await this.httpStatusCode;\n\t\t\treturn statusCode >= 200 && statusCode < 400;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Resolves when the response has finished processing – either successfully or not.\n\t */\n\tget finished(): Promise<void> {\n\t\treturn Promise.allSettled([this.exitCode.finally(() => {})]).then(\n\t\t\t() => {}\n\t\t);\n\t}\n\n\t/**\n\t * Resolves once HTTP headers are available.\n\t */\n\tget headers(): Promise<Record<string, string[]>> {\n\t\treturn this.getParsedHeaders().then((headers) => headers.headers);\n\t}\n\n\t/**\n\t * Resolves once HTTP status code is available.\n\t */\n\tget httpStatusCode(): Promise<number> {\n\t\treturn this.getParsedHeaders()\n\t\t\t.then((headers) => headers.httpStatusCode)\n\t\t\t.then((result) => {\n\t\t\t\tif (result !== undefined) {\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\t\t\t\t// If exit code is 0 or not available yet, fall back to parsed headers\n\t\t\t\treturn this.getParsedHeaders().then(\n\t\t\t\t\t(headers) => headers.httpStatusCode,\n\t\t\t\t\t() => 200\n\t\t\t\t);\n\t\t\t})\n\t\t\t.catch(() => 500);\n\t}\n\n\t/**\n\t * Exposes the stdout bytes as they're produced by the PHP instance\n\t */\n\tget stdoutText(): Promise<string> {\n\t\treturn this.stdoutBytes.then((bytes) =>\n\t\t\tnew TextDecoder().decode(bytes)\n\t\t);\n\t}\n\n\t/**\n\t * Exposes the stdout bytes as they're produced by the PHP instance\n\t */\n\tget stdoutBytes(): Promise<Uint8Array> {\n\t\tif (!this.cachedStdoutBytes) {\n\t\t\tthis.cachedStdoutBytes = streamToBytes(this.stdout);\n\t\t}\n\t\treturn this.cachedStdoutBytes;\n\t}\n\n\t/**\n\t * Exposes the stderr bytes as they're produced by the PHP instance\n\t */\n\tget stderrText(): Promise<string> {\n\t\tif (!this.cachedStderrText) {\n\t\t\tthis.cachedStderrText = streamToText(this.stderr);\n\t\t}\n\t\treturn this.cachedStderrText;\n\t}\n\n\tprivate async getParsedHeaders() {\n\t\tif (!this.parsedHeaders) {\n\t\t\tthis.parsedHeaders = parseHeadersStream(this.headersStream);\n\t\t}\n\t\treturn await this.parsedHeaders;\n\t}\n}\n\nasync function parseHeadersStream(\n\theadersStream: ReadableStream<Uint8Array>\n): Promise<{\n\theaders: Record<string, string[]>;\n\thttpStatusCode: number;\n}> {\n\tconst headersText = await streamToText(headersStream);\n\tlet headersData;\n\ttry {\n\t\theadersData = JSON.parse(headersText);\n\t} catch {\n\t\treturn { headers: {}, httpStatusCode: 200 };\n\t}\n\tconst headers: PHPResponse['headers'] = {};\n\tfor (const line of headersData.headers) {\n\t\t// Skip invalid response headers and the last \"__terminator__\" line.\n\t\t// @TODO: Should we log a warning on an invalid header line?\n\t\t// What's the typical browser behavior when encountering such a line?\n\t\tif (!line.includes(': ')) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst colonIndex = line.indexOf(': ');\n\t\tconst headerName = line.substring(0, colonIndex).toLowerCase();\n\t\tconst headerValue = line.substring(colonIndex + 2);\n\t\tif (!(headerName in headers)) {\n\t\t\theaders[headerName] = [] as string[];\n\t\t}\n\t\theaders[headerName].push(headerValue);\n\t}\n\treturn {\n\t\theaders,\n\t\thttpStatusCode: headersData.status,\n\t};\n}\n\nasync function streamToText(\n\tstream: ReadableStream<Uint8Array>\n): Promise<string> {\n\tconst reader = (stream as ReadableStream<BufferSource>)\n\t\t.pipeThrough(new TextDecoderStream())\n\t\t.getReader();\n\tconst text: string[] = [];\n\twhile (true) {\n\t\tconst { done, value } = await reader.read();\n\t\tif (done) {\n\t\t\treturn text.join('');\n\t\t}\n\t\tif (value) {\n\t\t\ttext.push(value);\n\t\t}\n\t}\n}\n\nasync function streamToBytes(\n\tstream: ReadableStream<Uint8Array>\n): Promise<Uint8Array> {\n\tconst reader = stream.getReader();\n\tconst chunks: Uint8Array[] = [];\n\n\twhile (true) {\n\t\tconst { done, value } = await reader.read();\n\t\tif (done) {\n\t\t\tconst totalLength = chunks.reduce(\n\t\t\t\t(acc, chunk) => acc + chunk.byteLength,\n\t\t\t\t0\n\t\t\t);\n\t\t\tconst result = new Uint8Array(totalLength);\n\t\t\tlet offset = 0;\n\t\t\tfor (const chunk of chunks) {\n\t\t\t\tresult.set(chunk, offset);\n\t\t\t\toffset += chunk.byteLength;\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\t\tif (value) {\n\t\t\tchunks.push(value);\n\t\t}\n\t}\n}\n\n/**\n * PHP response. Body is an `ArrayBuffer` because it can\n * contain binary data.\n *\n * This type is used in Comlink.transferHandlers.set('PHPResponse', \\{ ... \\})\n * so be sure to update that if you change this type.\n */\nexport class PHPResponse implements PHPResponseData {\n\t/** @inheritDoc */\n\treadonly headers: Record<string, string[]>;\n\n\t/** @inheritDoc */\n\treadonly bytes: Uint8Array;\n\n\t/** @inheritDoc */\n\treadonly errors: string;\n\n\t/** @inheritDoc */\n\treadonly exitCode: number;\n\n\t/** @inheritDoc */\n\treadonly httpStatusCode: number;\n\n\tconstructor(\n\t\thttpStatusCode: number,\n\t\theaders: Record<string, string[]>,\n\t\tbody: Uint8Array,\n\t\terrors = '',\n\t\texitCode = 0\n\t) {\n\t\tthis.httpStatusCode = httpStatusCode;\n\t\tthis.headers = headers;\n\t\tthis.bytes = body;\n\t\tthis.exitCode = exitCode;\n\t\tthis.errors = errors;\n\t}\n\n\tstatic forHttpCode(httpStatusCode: number, text = '') {\n\t\treturn new PHPResponse(\n\t\t\thttpStatusCode,\n\t\t\t{},\n\t\t\tnew TextEncoder().encode(\n\t\t\t\ttext || responseTexts[httpStatusCode] || ''\n\t\t\t)\n\t\t);\n\t}\n\n\tstatic fromRawData(data: PHPResponseData): PHPResponse {\n\t\treturn new PHPResponse(\n\t\t\tdata.httpStatusCode,\n\t\t\tdata.headers,\n\t\t\tdata.bytes,\n\t\t\tdata.errors,\n\t\t\tdata.exitCode\n\t\t);\n\t}\n\n\tstatic async fromStreamedResponse(\n\t\tstreamedResponse: StreamedPHPResponse\n\t): Promise<PHPResponse> {\n\t\tawait streamedResponse.finished;\n\t\treturn new PHPResponse(\n\t\t\tawait streamedResponse.httpStatusCode,\n\t\t\tawait streamedResponse.headers,\n\t\t\tawait streamedResponse.stdoutBytes,\n\t\t\tawait streamedResponse.stderrText,\n\t\t\tawait streamedResponse.exitCode\n\t\t);\n\t}\n\n\t/**\n\t * True if the response is successful (HTTP status code 200-399),\n\t * false otherwise.\n\t */\n\tok(): boolean {\n\t\treturn this.httpStatusCode >= 200 && this.httpStatusCode < 400;\n\t}\n\n\ttoRawData(): PHPResponseData {\n\t\treturn {\n\t\t\theaders: this.headers,\n\t\t\tbytes: this.bytes,\n\t\t\terrors: this.errors,\n\t\t\texitCode: this.exitCode,\n\t\t\thttpStatusCode: this.httpStatusCode,\n\t\t};\n\t}\n\n\t/**\n\t * Response body as JSON.\n\t */\n\tget json() {\n\t\treturn JSON.parse(this.text);\n\t}\n\n\t/**\n\t * Response body as text.\n\t */\n\tget text() {\n\t\treturn new TextDecoder().decode(this.bytes);\n\t}\n}\n","/*\n * Node.js Polyfill for ErrorEvent.\n */\n\nconst kError = Symbol('error');\nconst kMessage = Symbol('message');\n\ninterface ErrorEventOptions {\n\t/* The error that generated this event */\n\terror?: Error;\n\t/* The error message */\n\tmessage?: string;\n}\n/**\n * Class representing an error event.\n *\n * @extends Event\n */\nclass ErrorEvent2 extends Event {\n\t[kError]: any;\n\t[kMessage]: any;\n\t/**\n\t * Create a new `ErrorEvent`.\n\t *\n\t * @param type The name of the event\n\t * @param options A dictionary object that allows for setting\n\t * attributes via object members of the same name.\n\t */\n\tconstructor(type: 'error', options: ErrorEventOptions = {}) {\n\t\tsuper(type);\n\n\t\tthis[kError] = options.error === undefined ? null : options.error;\n\t\tthis[kMessage] = options.message === undefined ? '' : options.message;\n\t}\n\n\tget error() {\n\t\treturn this[kError];\n\t}\n\n\tget message() {\n\t\treturn this[kMessage];\n\t}\n}\nObject.defineProperty(ErrorEvent2.prototype, 'error', { enumerable: true });\nObject.defineProperty(ErrorEvent2.prototype, 'message', { enumerable: true });\n\nexport const ErrorEvent =\n\ttypeof globalThis.ErrorEvent === 'function'\n\t\t? globalThis.ErrorEvent\n\t\t: ErrorEvent2;\n","import { ErrorEvent } from './error-event-polyfill';\nimport { isExitCode } from './is-exit-code';\nimport { logger } from '@php-wasm/logger';\n\ntype Runtime = {\n\twasmExports: Record<string, unknown>;\n\tlastAsyncifyStackSource?: Error;\n};\n\nexport class UnhandledRejectionsTarget extends EventTarget {\n\tlistenersCount = 0;\n\toverride addEventListener(\n\t\ttype: unknown,\n\t\tcallback: unknown,\n\t\toptions?: boolean | AddEventListenerOptions\n\t): void {\n\t\t++this.listenersCount;\n\t\tsuper.addEventListener(\n\t\t\ttype as string,\n\t\t\tcallback as EventListener,\n\t\t\toptions\n\t\t);\n\t}\n\toverride removeEventListener(\n\t\ttype: unknown,\n\t\tcallback: unknown,\n\t\toptions?: boolean | EventListenerOptions\n\t): void {\n\t\t--this.listenersCount;\n\t\tsuper.removeEventListener(\n\t\t\ttype as string,\n\t\t\tcallback as EventListener,\n\t\t\toptions\n\t\t);\n\t}\n\thasListeners() {\n\t\treturn this.listenersCount > 0;\n\t}\n}\n\n/**\n * Creates Asyncify errors listener.\n *\n * Emscripten turns Asyncify errors into unhandled rejections by\n * throwing them outside of the context of the original function call.\n *\n * With this listener, we can catch and rethrow them in a proper context,\n * or at least log them in a more readable way.\n *\n * @param runtime\n */\nexport function improveWASMErrorReporting(runtime: Runtime) {\n\tconst target = new UnhandledRejectionsTarget();\n\tfor (const key in runtime.wasmExports) {\n\t\tif (typeof runtime.wasmExports[key] == 'function') {\n\t\t\tconst original = runtime.wasmExports[key] as any;\n\t\t\truntime.wasmExports[key] = function (...args: any[]) {\n\t\t\t\ttry {\n\t\t\t\t\treturn original(...args);\n\t\t\t\t} catch (e) {\n\t\t\t\t\tif (!(e instanceof Error)) {\n\t\t\t\t\t\tthrow e;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (runtime.lastAsyncifyStackSource) {\n\t\t\t\t\t\te.cause = runtime.lastAsyncifyStackSource;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst clearMessage = clarifyErrorMessage(\n\t\t\t\t\t\te,\n\t\t\t\t\t\truntime.lastAsyncifyStackSource?.stack\n\t\t\t\t\t);\n\n\t\t\t\t\tif (target.hasListeners()) {\n\t\t\t\t\t\te.message = clearMessage;\n\t\t\t\t\t\tconst event = new ErrorEvent('error', { error: e });\n\t\t\t\t\t\ttarget.dispatchEvent(event);\n\t\t\t\t\t\tthrow e;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!isExitCode(e) || e.status !== 0) {\n\t\t\t\t\t\tshowCriticalErrorBox(clearMessage);\n\t\t\t\t\t}\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t}\n\treturn target;\n}\n\nlet functionsMaybeMissingFromAsyncify: string[] = [];\nexport function getFunctionsMaybeMissingFromAsyncify() {\n\treturn functionsMaybeMissingFromAsyncify;\n}\n\nexport function clarifyErrorMessage(\n\tcrypticError: Error,\n\tasyncifyStack?: string\n) {\n\tif (crypticError.message === 'unreachable') {\n\t\tlet betterMessage = UNREACHABLE_ERROR;\n\t\tif (!asyncifyStack) {\n\t\t\tbetterMessage +=\n\t\t\t\t`\\n\\nThis stack trace is lacking. For a better one initialize \\n` +\n\t\t\t\t`the PHP runtime with debug: true, e.g. loadNodeRuntime('8.1', { emscriptenOptions: { debug: true } }).\\n\\n`;\n\t\t}\n\n\t\t// Extract all the PHP functions from the entire error chain.\n\t\tconst uniqueFunctions = new Set<string>(\n\t\t\textractPHPFunctionsFromStack(asyncifyStack || '')\n\t\t);\n\t\tlet lastError = crypticError;\n\t\tdo {\n\t\t\tfor (const fn of extractPHPFunctionsFromStack(\n\t\t\t\tlastError.stack || ''\n\t\t\t)) {\n\t\t\t\tuniqueFunctions.add(fn);\n\t\t\t}\n\t\t\tlastError = lastError.cause as Error;\n\t\t} while (lastError);\n\t\tfunctionsMaybeMissingFromAsyncify = Array.from(uniqueFunctions);\n\n\t\tfor (const fn of uniqueFunctions) {\n\t\t\tbetterMessage += ` * ${fn}\\n`;\n\t\t}\n\n\t\tbetterMessage += `Original error message: ${crypticError.message}\\n`;\n\n\t\treturn betterMessage;\n\t}\n\treturn crypticError.message;\n}\n\nconst UNREACHABLE_ERROR = `\n\"unreachable\" WASM instruction executed.\n\nThe typical reason is a PHP function missing from the ASYNCIFY_ONLY\nlist when building PHP.wasm.\n\nYou will need to file a new issue in the WordPress Playground repository\nand paste this error message there:\n\nhttps://github.com/WordPress/wordpress-playground/issues/new\n\nIf you're a core developer, the typical fix is to:\n\n* Isolate a minimal reproduction of the error\n* Add a reproduction of the error to php-asyncify.spec.ts in the WordPress Playground repository\n* Run 'npm run fix-asyncify'\n* Commit the changes, push to the repo, release updated NPM packages\n\nBelow is a list of all the PHP functions found in the stack trace to\nhelp with the minimal reproduction. If they're all already listed in\nthe Dockerfile, you'll need to trigger this error again with long stack\ntraces enabled. In node.js, you can do it using the --stack-trace-limit=100\nCLI option: \\n\\n`;\n\n// ANSI escape codes for CLI colors and formats\nconst redBg = '\\x1b[41m';\nconst bold = '\\x1b[1m';\nconst reset = '\\x1b[0m';\nconst eol = '\\x1B[K';\n\nlet logged = false;\nexport function showCriticalErrorBox(message: string) {\n\tif (logged) {\n\t\treturn;\n\t}\n\tlogged = true;\n\tif (message?.trim().startsWith('Program terminated with exit')) {\n\t\treturn;\n\t}\n\tlogger.log(`${redBg}\\n${eol}\\n${bold} WASM ERROR${reset}${redBg}`);\n\tfor (const line of message.split('\\n')) {\n\t\tlogger.log(`${eol} ${line} `);\n\t}\n\tlogger.log(`${reset}`);\n}\n\nfunction extractPHPFunctionsFromStack(stack: string) {\n\ttry {\n\t\tconst names = stack\n\t\t\t.split('\\n')\n\t\t\t.slice(1)\n\t\t\t.map((line) => {\n\t\t\t\tconst parts = line.trim().substring('at '.length).split(' ');\n\t\t\t\treturn {\n\t\t\t\t\tfn: parts.length >= 2 ? parts[0] : '<unknown>',\n\t\t\t\t\tisWasm: line.includes('wasm:/'),\n\t\t\t\t};\n\t\t\t})\n\t\t\t.filter(\n\t\t\t\t({ fn, isWasm }) =>\n\t\t\t\t\tisWasm &&\n\t\t\t\t\t!fn.startsWith('dynCall_') &&\n\t\t\t\t\t!fn.startsWith('invoke_')\n\t\t\t)\n\t\t\t.map(({ fn }) => fn);\n\t\treturn Array.from(new Set(names));\n\t} catch {\n\t\treturn [];\n\t}\n}\n","import { logger } from '@php-wasm/logger';\nimport {\n\tSemaphore,\n\tbasename,\n\tcreateSpawnHandler,\n\tjoinPaths,\n} from '@php-wasm/util';\nimport type { Emscripten } from './emscripten-types';\nimport type { ListFilesOptions, RmDirOptions } from './fs-helpers';\nimport { FSHelpers } from './fs-helpers';\nimport { isExitCode } from './is-exit-code';\nimport type { PHPRuntimeId } from './load-php-runtime';\nimport { popLoadedRuntime } from './load-php-runtime';\nimport type { PHPRequestHandler } from './php-request-handler';\nimport { PHPResponse, StreamedPHPResponse } from './php-response';\nimport type {\n\tChildProcess,\n\tMessageListener,\n\tPHPEvent,\n\tPHPEventListener,\n\tPHPRequest,\n\tPHPRequestHeaders,\n\tPHPRunOptions,\n\tSpawnHandler,\n} from './universal-php';\nimport type { UnhandledRejectionsTarget } from './wasm-error-reporting';\nimport {\n\tgetFunctionsMaybeMissingFromAsyncify,\n\timproveWASMErrorReporting,\n} from './wasm-error-reporting';\n\nconst STRING = 'string';\nconst NUMBER = 'number';\n\nexport const __private__dont__use = Symbol('__private__dont__use');\n\ntype ErrorSource = 'request' | 'php-wasm';\nexport class PHPExecutionFailureError extends Error {\n\tresponse: PHPResponse;\n\tsource: ErrorSource;\n\n\tconstructor(message: string, response: PHPResponse, source: ErrorSource) {\n\t\tsuper(message);\n\t\tthis.response = response;\n\t\tthis.source = source;\n\t}\n}\n\nexport type UnmountFunction = (() => Promise<any>) | (() => any);\nexport type MountHandler = (\n\tphp: PHP,\n\tFS: Emscripten.RootFS,\n\tvfsMountPoint: string\n) => UnmountFunction | Promise<UnmountFunction>;\n\nexport const PHP_INI_PATH = '/internal/shared/php.ini';\nconst AUTO_PREPEND_SCRIPT = '/internal/shared/auto_prepend_file.php';\n\nexport const USE_OPCACHE = true;\nconst OPCACHE_FILE_FOLDER = '/internal/shared/opcache';\n\ntype MountObject = {\n\tmountHandler: MountHandler;\n\tunmount: () => Promise<any>;\n};\n\n/**\n * An environment-agnostic wrapper around the Emscripten PHP runtime\n * that universals the super low-level API and provides a more convenient\n * higher-level API.\n *\n * It exposes a minimal set of methods to run PHP scripts and to\n * interact with the PHP filesystem.\n */\nexport class PHP implements Disposable {\n\tprotected [__private__dont__use]: any;\n\t#sapiName?: string;\n\t#phpWasmInitCalled = false;\n\t#wasmErrorsTarget: UnhandledRejectionsTarget | null = null;\n\t#eventListeners: Map<string, Set<PHPEventListener>> = new Map([\n\t\t// Listen to all events\n\t\t['*', new Set()],\n\t]);\n\t#messageListeners: MessageListener[] = [];\n\t#mounts: Record<string, MountObject> = {};\n\t#rotationOptions: {\n\t\tenabled: boolean;\n\t\trecreateRuntime: () => Promise<number> | number;\n\t\tneedsRotating: boolean;\n\t\tmaxRequests: number;\n\t\trequestsMade: number;\n\t} = {\n\t\tenabled: false,\n\t\trecreateRuntime: () => 0,\n\t\tneedsRotating: false,\n\t\tmaxRequests: 400,\n\t\trequestsMade: 0,\n\t};\n\n\trequestHandler?: PHPRequestHandler;\n\n\t/**\n\t * An exclusive lock that prevent multiple requests from running at\n\t * the same time.\n\t */\n\tsemaphore: Semaphore;\n\n\t/**\n\t * Initializes a PHP runtime.\n\t *\n\t * @internal\n\t * @param PHPRuntime - Optional. PHP Runtime ID as initialized by loadPHPRuntime.\n\t * @param requestHandlerOptions - Optional. Options for the PHPRequestHandler. If undefined, no request handler will be initialized.\n\t */\n\tconstructor(PHPRuntimeId?: PHPRuntimeId) {\n\t\tthis.semaphore = new Semaphore({ concurrency: 1 });\n\t\tif (PHPRuntimeId !== undefined) {\n\t\t\tthis.initializeRuntime(PHPRuntimeId);\n\t\t}\n\t\t/**\n\t\t * Listen to PHP runtime crashes.\n\t\t *\n\t\t * Registering an actual event listener helps with testing. The\n\t\t * test cases can dispatch synthetic error events and confirm the\n\t\t * PHP runtime is properly rotated.\n\t\t */\n\t\tthis.addEventListener('request.error', (event: any) => {\n\t\t\tif (event.source === 'php-wasm') {\n\t\t\t\tthis.#rotationOptions.needsRotating = true;\n\t\t\t}\n\t\t});\n\t}\n\t/**\n\t * Adds an event listener for a PHP event.\n\t * @param eventType - The type of event to listen for.\n\t * @param listener - The listener function to be called when the event is triggered.\n\t */\n\taddEventListener(\n\t\teventType: PHPEvent['type'] | '*',\n\t\tlistener: PHPEventListener\n\t) {\n\t\tif (!this.#eventListeners.has(eventType)) {\n\t\t\tthis.#eventListeners.set(eventType, new Set());\n\t\t}\n\t\tthis.#eventListeners.get(eventType)!.add(listener);\n\t}\n\n\t/**\n\t * Removes an event listener for a PHP event.\n\t * @param eventType - The type of event to remove the listener from.\n\t * @param listener - The listener function to be removed.\n\t */\n\tremoveEventListener(\n\t\teventType: PHPEvent['type'] | '*',\n\t\tlistener: PHPEventListener\n\t) {\n\t\tthis.#eventListeners.get(eventType)?.delete(listener);\n\t}\n\n\tdispatchEvent<Event extends PHPEvent>(event: Event) {\n\t\tconst listeners = [\n\t\t\t...(this.#eventListeners.get(event.type) || []),\n\t\t\t...(this.#eventListeners.get('*') || []),\n\t\t];\n\t\tif (!listeners) {\n\t\t\treturn;\n\t\t}\n\t\tfor (const listener of listeners) {\n\t\t\tlistener(event);\n\t\t}\n\t}\n\n\t/**\n\t * Listens to message sent by the PHP code.\n\t *\n\t * To dispatch messages, call:\n\t *\n\t * post_message_to_js(string $data)\n\t *\n\t * Arguments:\n\t * $data (string) – Data to pass to JavaScript.\n\t *\n\t * @example\n\t *\n\t * ```ts\n\t * const php = await PHP.load('8.0');\n\t *\n\t * php.onMessage(\n\t * // The data is always passed as a string\n\t * function (data: string) {\n\t * // Let's decode and log the data:\n\t * console.log(JSON.parse(data));\n\t * }\n\t * );\n\t *\n\t * // Now that we have a listener in place, let's\n\t * // dispatch a message:\n\t * await php.run({\n\t * code: `<?php\n\t * post_message_to_js(\n\t * json_encode([\n\t * 'post_id' => '15',\n\t * 'post_title' => 'This is a blog post!'\n\t * ])\n\t * ));\n\t * `,\n\t * });\n\t * ```\n\t *\n\t * @param listener Callback function to handle the message.\n\t */\n\tonMessage(listener: MessageListener) {\n\t\tthis.#messageListeners.push(listener);\n\t\treturn async () => {\n\t\t\tthis.#messageListeners = this.#messageListeners.filter(\n\t\t\t\t(l) => l !== listener\n\t\t\t);\n\t\t};\n\t}\n\n\tasync setSpawnHandler(handler: SpawnHandler | string) {\n\t\tif (typeof handler === 'string') {\n\t\t\t// This workaround is needed because the\n\t\t\t// Comlink messaging library used by Playground\n\t\t\t// has a hard time serializing a composite\n\t\t\t// handler object.\n\t\t\t// @TODO: Don't eval text-based functions here. Instead\n\t\t\t// use a MessagePort to communicate with the\n\t\t\t//\t\t parent context.\n\t\t\t// Perhaps this library would be useful:\n\t\t\t// https://github.com/WebReflection/coincident/\n\t\t\thandler = createSpawnHandler(eval(handler));\n\t\t}\n\t\tthis[__private__dont__use].spawnProcess = handler;\n\t}\n\n\t/** @deprecated Use PHPRequestHandler instead. */\n\tget absoluteUrl() {\n\t\treturn this.requestHandler!.absoluteUrl;\n\t}\n\n\t/** @deprecated Use PHPRequestHandler instead. */\n\tget documentRoot() {\n\t\treturn this.requestHandler!.documentRoot;\n\t}\n\n\t/** @deprecated Use PHPRequestHandler instead. */\n\tpathToInternalUrl(path: string): string {\n\t\treturn this.requestHandler!.pathToInternalUrl(path);\n\t}\n\n\t/** @deprecated Use PHPRequestHandler instead. */\n\tinternalUrlToPath(internalUrl: string): string {\n\t\treturn this.requestHandler!.internalUrlToPath(internalUrl);\n\t}\n\n\tinitializeRuntime(runtimeId: PHPRuntimeId) {\n\t\tif (this[__private__dont__use]) {\n\t\t\tthrow new Error('PHP runtime already initialized.');\n\t\t}\n\t\tconst runtime = popLoadedRuntime(runtimeId);\n\t\tif (!runtime) {\n\t\t\tthrow new Error('Invalid PHP runtime id.');\n\t\t}\n\t\tthis[__private__dont__use] = runtime;\n\t\tthis[__private__dont__use].ccall(\n\t\t\t'wasm_set_phpini_path',\n\t\t\tnull,\n\t\t\t['string'],\n\t\t\t[PHP_INI_PATH]\n\t\t);\n\n\t\tif (!this.fileExists(PHP_INI_PATH)) {\n\t\t\tconst opcacheConfig = USE_OPCACHE\n\t\t\t\t? [\n\t\t\t\t\t\t// OPCache\n\t\t\t\t\t\t'opcache.enable = 1',\n\t\t\t\t\t\t'opcache.enable_cli = 1',\n\t\t\t\t\t\t'opcache.jit = 0',\n\t\t\t\t\t\t'opcache.interned_strings_buffer = 8',\n\t\t\t\t\t\t'opcache.max_accelerated_files = 1000',\n\t\t\t\t\t\t'opcache.memory_consumption = 64',\n\t\t\t\t\t\t'opcache.max_wasted_percentage = 5',\n\t\t\t\t\t\t'opcache.file_cache = ' + OPCACHE_FILE_FOLDER,\n\t\t\t\t\t\t// Always enable the file cache.\n\t\t\t\t\t\t'opcache.file_cache_only = 1',\n\t\t\t\t\t\t'opcache.file_cache_consistency_checks = 1',\n\t\t\t\t\t]\n\t\t\t\t: [];\n\n\t\t\t/*if (\n\t\t\t\tUSE_OPCACHE &&\n\t\t\t\t!(\n\t\t\t\t\truntime.phpVersion.major === 8 &&\n\t\t\t\t\truntime.phpVersion.minor === 4\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\t// Old versions of PHP are RAM hungry. By using the file cache, we can reduce\n\t\t\t\t// the RAM usage during the first caching.\n\t\t\t\topcacheConfig.push(\n\t\t\t\t\t'opcache.file_cache_only = 1',\n\t\t\t\t\t'opcache.file_cache_consistency_checks = 1'\n\t\t\t\t);\n\t\t\t}*/\n\n\t\t\tif (!this.fileExists(OPCACHE_FILE_FOLDER)) {\n\t\t\t\tthis.mkdir(OPCACHE_FILE_FOLDER);\n\t\t\t}\n\n\t\t\tthis.writeFile(\n\t\t\t\tPHP_INI_PATH,\n\t\t\t\t[\n\t\t\t\t\t'auto_prepend_file=' + AUTO_PREPEND_SCRIPT,\n\t\t\t\t\t'memory_limit=256M',\n\t\t\t\t\t'ignore_repeated_errors = 1',\n\t\t\t\t\t'error_reporting = E_ALL',\n\t\t\t\t\t'display_errors = 1',\n\t\t\t\t\t'html_errors = 1',\n\t\t\t\t\t'display_startup_errors = On',\n\t\t\t\t\t'log_errors = 1',\n\t\t\t\t\t'always_populate_raw_post_data = -1',\n\t\t\t\t\t'upload_max_filesize = 2000M',\n\t\t\t\t\t'post_max_size = 2000M',\n\t\t\t\t\t'allow_url_fopen = On',\n\t\t\t\t\t'allow_url_include = Off',\n\t\t\t\t\t'session.save_path = /home/web_user',\n\t\t\t\t\t'implicit_flush = 1',\n\t\t\t\t\t'output_buffering = 0',\n\t\t\t\t\t'max_execution_time = 0',\n\t\t\t\t\t'max_input_time = -1',\n\t\t\t\t\t...opcacheConfig,\n\t\t\t\t].join('\\n')\n\t\t\t);\n\t\t}\n\t\tif (!this.fileExists(AUTO_PREPEND_SCRIPT)) {\n\t\t\tthis.writeFile(\n\t\t\t\tAUTO_PREPEND_SCRIPT,\n\t\t\t\t`<?php\n\t\t\t\t// Define constants set via defineConstant() calls\n\t\t\t\tif(file_exists('/internal/shared/consts.json')) {\n\t\t\t\t\t$consts = json_decode(file_get_contents('/internal/shared/consts.json'), true);\n\t\t\t\t\tforeach ($consts as $const => $value) {\n\t\t\t\t\t\tif (!defined($const) && is_scalar($value)) {\n\t\t\t\t\t\t\tdefine($const, $value);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Preload all the files from /internal/shared/preload\n\t\t\t\tforeach (glob('/internal/shared/preload/*.php') as $file) {\n\t\t\t\t\trequire_once $file;\n\t\t\t\t}\n\t\t\t\t`\n\t\t\t);\n\t\t}\n\n\t\truntime['onMessage'] = async (\n\t\t\tdata: string\n\t\t): Promise<string | Uint8Array> => {\n\t\t\tfor (const listener of this.#messageListeners) {\n\t\t\t\tconst returnData = await listener(data);\n\n\t\t\t\tif (returnData) {\n\t\t\t\t\treturn returnData;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn '';\n\t\t};\n\n\t\tthis.#wasmErrorsTarget = improveWASMErrorReporting(runtime);\n\t\tthis.dispatchEvent({\n\t\t\ttype: 'runtime.initialized',\n\t\t});\n\t}\n\n\t/** @inheritDoc */\n\tasync setSapiName(newName: string) {\n\t\tconst result = this[__private__dont__use].ccall(\n\t\t\t'wasm_set_sapi_name',\n\t\t\tNUMBER,\n\t\t\t[STRING],\n\t\t\t[newName]\n\t\t);\n\t\tif (result !== 0) {\n\t\t\tthrow new Error(\n\t\t\t\t'Could not set SAPI name. This can only be done before the PHP WASM module is initialized.' +\n\t\t\t\t\t'Did you already dispatch any requests?'\n\t\t\t);\n\t\t}\n\t\tthis.#sapiName = newName;\n\t}\n\n\t/**\n\t * Changes the current working directory in the PHP filesystem.\n\t * This is the directory that will be used as the base for relative paths.\n\t * For example, if the current working directory is `/root/php`, and the\n\t * path is `data`, the absolute path will be `/root/php/data`.\n\t *\n\t * @param path - The new working directory.\n\t */\n\tchdir(path: string) {\n\t\tthis[__private__dont__use].FS.chdir(path);\n\t}\n\n\t/**\n\t * Gets the current working directory in the PHP filesystem.\n\t *\n\t * @returns The current working directory.\n\t */\n\tcwd() {\n\t\treturn this[__private__dont__use].FS.cwd();\n\t}\n\n\t/**\n\t * Changes the permissions of a file or directory.\n\t * @param path - The path to the file or directory.\n\t * @param mode - The new permissions.\n\t */\n\tchmod(path: string, mode: number) {\n\t\tthis[__private__dont__use].FS.chmod(path, mode);\n\t}\n\n\t/**\n\t * Do not use. Use new PHPRequestHandler() instead.\n\t * @deprecated\n\t */\n\tasync request(request: PHPRequest): Promise<PHPResponse> {\n\t\tlogger.debug(\n\t\t\t'PHP.request() is deprecated. Please use new PHPRequestHandler() instead.'\n\t\t);\n\t\tif (!this.requestHandler) {\n\t\t\tthrow new Error('No request handler available.');\n\t\t}\n\t\treturn this.requestHandler.request(request);\n\t}\n\n\t/**\n\t * Runs PHP code.\n\t *\n\t * This low-level method directly interacts with the WebAssembly\n\t * PHP interpreter.\n\t *\n\t * Every time you call run(), it prepares the PHP\n\t * environment and:\n\t *\n\t * * Resets the internal PHP state\n\t * * Populates superglobals ($_SERVER, $_GET, etc.)\n\t * * Handles file uploads\n\t * * Populates input streams (stdin, argv, etc.)\n\t * * Sets the current working directory\n\t *\n\t * You can use run() in two primary modes:\n\t *\n\t * ### Code snippet mode\n\t *\n\t * In this mode, you pass a string containing PHP code to run.\n\t *\n\t * ```ts\n\t * const result = await php.run({\n\t * \tcode: `<?php echo \"Hello world!\";`\n\t * });\n\t * // result.text === \"Hello world!\"\n\t * ```\n\t *\n\t * In this mode, information like __DIR__ or __FILE__ isn't very\n\t * useful because the code is not associated with any file.\n\t *\n\t * Under the hood, the PHP snippet is passed to the `zend_eval_string`\n\t * C function.\n\t *\n\t * ### File mode\n\t *\n\t * In the file mode, you pass a scriptPath and PHP executes a file\n\t * found at a that path:\n\t *\n\t * ```ts\n\t * php.writeFile(\n\t * \t\"/www/index.php\",\n\t * \t`<?php echo \"Hello world!\";\"`\n\t * );\n\t * const result = await php.run({\n\t * \tscriptPath: \"/www/index.php\"\n\t * });\n\t * // result.text === \"Hello world!\"\n\t * ```\n\t *\n\t * In this mode, you can rely on path-related information like __DIR__\n\t * or __FILE__.\n\t *\n\t * Under the hood, the PHP file is executed with the `php_execute_script`\n\t * C function.\n\t *\n\t * The `run()` method cannot be used in conjunction with `cli()`.\n\t *\n\t * @example\n\t * ```js\n\t * const result = await php.run({\n\t * \tcode: `<?php\n\t * \t\t$fp = fopen('php://stderr', 'w');\n\t * \t\tfwrite($fp, \"Hello, world!\");\n\t * \t`\n\t * });\n\t * // result.errors === \"Hello, world!\"\n\t * ```\n\t *\n\t * @deprecated Use stream() instead.\n\t * @param request - PHP runtime options.\n\t */\n\tasync run(request: PHPRunOptions): Promise<PHPResponse> {\n\t\tconst streamedResponse = await this.runStream(request);\n\t\tconst syncResponse =\n\t\t\tawait PHPResponse.fromStreamedResponse(streamedResponse);\n\n\t\tif (syncResponse.exitCode !== 0) {\n\t\t\t// Legacy run() behavior: throw if PHP exited with a non-zero exit code.\n\t\t\t// It could be a WASM crash, but it could be a PHP userland error such\n\t\t\t// as \"Fatal error: Uncaught Error: Call to undefined function no_such_function()\".\n\t\t\t//\n\t\t\t// runStream() does not throw just because an exitCode is non-zero.\n\t\t\tthrow new PHPExecutionFailureError(\n\t\t\t\t`PHP.run() failed with exit code ${syncResponse.exitCode}. \\n\\n=== Stdout ===\\n ${syncResponse.text}\\n\\n=== Stderr ===\\n ${syncResponse.errors}`,\n\t\t\t\tsyncResponse,\n\t\t\t\t'request'\n\t\t\t) as PHPExecutionFailureError;\n\t\t}\n\n\t\treturn syncResponse;\n\t}\n\t/**\n\t * Runs PHP code and returns a StreamedPHPResponse object that can be used to\n\t * process the output incrementally.\n\t *\n\t * This low-level method directly interacts with the WebAssembly\n\t * PHP interpreter and provides streaming capabilities for processing\n\t * PHP output as it becomes available.\n\t *\n\t * Every time you call stream(), it prepares the PHP\n\t * environment and:\n\t *\n\t * * Resets the internal PHP state\n\t * * Populates superglobals ($_SERVER, $_GET, etc.)\n\t * * Handles file uploads\n\t * * Populates input streams (stdin, argv, etc.)\n\t * * Sets the current working directory\n\t *\n\t * You can use stream() in two primary modes:\n\t *\n\t * ### Code snippet mode\n\t *\n\t * In this mode, you pass a string containing PHP code to run.\n\t *\n\t * ```ts\n\t * const streamedResponse = await php.stream({\n\t * \tcode: `<?php echo \"Hello world!\";`\n\t * });\n\t * // Process output incrementally\n\t * for await (const chunk of streamedResponse.text) {\n\t * \tconsole.log(chunk);\n\t * }\n\t * ```\n\t *\n\t * In this mode, information like __DIR__ or __FILE__ isn't very\n\t * useful because the code is not associated with any file.\n\t *\n\t * Under the hood, the PHP snippet is passed to the `zend_eval_string`\n\t * C function.\n\t *\n\t * ### File mode\n\t *\n\t * In the file mode, you pass a scriptPath and PHP executes a file\n\t * found at that path:\n\t *\n\t * ```ts\n\t * php.writeFile(\n\t * \t\"/www/index.php\",\n\t * \t`<?php echo \"Hello world!\";\"`\n\t * );\n\t * const streamedResponse = await php.stream({\n\t * \tscriptPath: \"/www/index.php\"\n\t * });\n\t * // Process output incrementally\n\t * for await (const chunk of streamedResponse.text) {\n\t * \tconsole.log(chunk);\n\t * }\n\t * ```\n\t *\n\t * In this mode, you can rely on path-related information like __DIR__\n\t * or __FILE__.\n\t *\n\t * Under the hood, the PHP file is executed with the `php_execute_script`\n\t * C function.\n\t *\n\t * The `stream()` method cannot be used in conjunction with `cli()`.\n\t *\n\t * @example\n\t * ```js\n\t * const streamedResponse = await php.stream({\n\t * \tcode: `<?php\n\t * \t\tfor ($i = 0; $i < 5; $i++) {\n\t * \t\t\techo \"Line $i\\n\";\n\t * \t\t\tflush();\n\t * \t\t}\n\t * \t`\n\t * });\n\t *\n\t * // Process output as it becomes available\n\t * for await (const chunk of streamedResponse.text) {\n\t * \tconsole.log('Received:', chunk);\n\t * }\n\t *\n\t * // Get the final exit code\n\t * const exitCode = await streamedResponse.exitCode;\n\t * console.log('Exit code:', exitCode);\n\t * ```\n\t *\n\t * @see run() – a synchronous version of this method.\n\t * @param request - PHP runtime options.\n\t * @returns A StreamedPHPResponse object.\n\t */\n\tasync runStream(request: PHPRunOptions): Promise<StreamedPHPResponse> {\n\t\t/*\n\t\t * Prevent multiple requests from running at the same time.\n\t\t * For example, if a request is made to a PHP file that\n\t\t * requests another PHP file, the second request may\n\t\t * be dispatched before the first one is finished.\n\t\t */\n\t\tconst release = await this.semaphore.acquire();\n\t\tlet heapBodyPointer: number | undefined;\n\t\tconst streamedResponsePromise = this.#executeWithErrorHandling(\n\t\t\tasync () => {\n\t\t\t\tif (!this.#phpWasmInitCalled) {\n\t\t\t\t\tawait this[__private__dont__use].ccall(\n\t\t\t\t\t\t'php_wasm_init',\n\t\t\t\t\t\tnull,\n\t\t\t\t\t\t[],\n\t\t\t\t\t\t[],\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tisAsync: true,\n\t\t\t\t\t\t}\n\t\t\t\t\t);\n\t\t\t\t\tthis.#phpWasmInitCalled = true;\n\t\t\t\t}\n\t\t\t\tif (\n\t\t\t\t\trequest.scriptPath &&\n\t\t\t\t\t!this.fileExists(request.scriptPath)\n\t\t\t\t) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`The script path \"${request.scriptPath}\" does not exist.`\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tthis.#setRelativeRequestUri(request.relativeUri || '');\n\t\t\t\tthis.#setRequestMethod(request.method || 'GET');\n\t\t\t\tconst requestHeaders = normalizeHeaders(request.headers || {});\n\t\t\t\tconst host = requestHeaders['host'] || 'example.com:443';\n\n\t\t\t\tconst port = this.#inferPortFromHostAndProtocol(\n\t\t\t\t\thost,\n\t\t\t\t\trequest.protocol || 'http'\n\t\t\t\t);\n\t\t\t\tthis.#setRequestHost(host);\n\t\t\t\tthis.#setRequestPort(port);\n\t\t\t\tthis.#setRequestHeaders(requestHeaders);\n\t\t\t\tif (request.body) {\n\t\t\t\t\theapBodyPointer = this.#setRequestBody(request.body);\n\t\t\t\t}\n\t\t\t\tif (typeof request.code === 'string') {\n\t\t\t\t\tthis.writeFile('/internal/eval.php', request.code);\n\t\t\t\t\tthis.#setScriptPath('/internal/eval.php');\n\t\t\t\t} else if (typeof request.scriptPath === 'string') {\n\t\t\t\t\tthis.#setScriptPath(request.scriptPath || '');\n\t\t\t\t} else {\n\t\t\t\t\tthrow new TypeError(\n\t\t\t\t\t\t'The request object must have either a `code` or a ' +\n\t\t\t\t\t\t\t'`scriptPath` property.'\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tconst $_SERVER = this.#prepareServerEntries(\n\t\t\t\t\trequest.$_SERVER,\n\t\t\t\t\trequestHeaders,\n\t\t\t\t\tport\n\t\t\t\t);\n\n\t\t\t\tfor (const key in $_SERVER) {\n\t\t\t\t\tthis.#setServerGlobalEntry(key, $_SERVER[key]);\n\t\t\t\t}\n\n\t\t\t\tconst env = request.env || {};\n\t\t\t\tfor (const key in env) {\n\t\t\t\t\tthis.#setEnv(key, env[key]);\n\t\t\t\t}\n\n\t\t\t\treturn await this[__private__dont__use].ccall(\n\t\t\t\t\t'wasm_sapi_handle_request',\n\t\t\t\t\tNUMBER,\n\t\t\t\t\t[],\n\t\t\t\t\t[],\n\t\t\t\t\t{ async: true }\n\t\t\t\t);\n\t\t\t}\n\t\t);\n\n\t\tconst cleanup = () => {\n\t\t\tif (heapBodyPointer) {\n\t\t\t\ttry {\n\t\t\t\t\tthis[__private__dont__use].free(heapBodyPointer);\n\t\t\t\t} catch (e) {\n\t\t\t\t\tlogger.error(e);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Release the \"request in progress\" semaphore.\n\t\t\trelease();\n\n\t\t\t/**\n\t\t\t * Notify the filesystem journal (and any other listeners) that the request has ended.\n\t\t\t */\n\t\t\tthis.dispatchEvent({\n\t\t\t\ttype: 'request.end',\n\t\t\t});\n\t\t};\n\n\t\t// Free up resources once the request is fully handled.\n\t\treturn streamedResponsePromise.then(\n\t\t\t(streamedResponse) => {\n\t\t\t\tstreamedResponse.finished.finally(cleanup);\n\t\t\t\treturn streamedResponse;\n\t\t\t},\n\t\t\t(error) => {\n\t\t\t\ttry {\n\t\t\t\t\tcleanup();\n\t\t\t\t} catch {\n\t\t\t\t\t// ... do nothing, just rethrow the original error in the finally section belos ...\n\t\t\t\t} finally {\n\t\t\t\t\t// eslint-disable-next-line no-unsafe-finally\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t}\n\n\t/**\n\t * Prepares the $_SERVER entries for the PHP runtime.\n\t *\n\t * @param defaults Default entries to include in $_SERVER.\n\t * @param headers HTTP headers to include in $_SERVER (as HTTP_ prefixed entries).\n\t * @param port HTTP port, used to determine infer $_SERVER['HTTPS'] value if none\n\t * was provided.\n\t * @returns Computed $_SERVER entries.\n\t */\n\t#prepareServerEntries(\n\t\tdefaults: Record<string, string> | undefined,\n\t\theaders: PHPRequestHeaders,\n\t\tport: number\n\t): Record<string, string> {\n\t\tconst $_SERVER = {\n\t\t\t...(defaults || {}),\n\t\t};\n\t\t$_SERVER['HTTPS'] = $_SERVER['HTTPS'] || port === 443 ? 'on' : 'off';\n\t\tfor (const name in headers) {\n\t\t\tlet HTTP_prefix = 'HTTP_';\n\t\t\t/**\n\t\t\t * Some headers are special and don't have the HTTP_ prefix.\n\t\t\t */\n\t\t\tif (\n\t\t\t\t['content-type', 'content-length'].includes(name.toLowerCase())\n\t\t\t) {\n\t\t\t\tHTTP_prefix = '';\n\t\t\t}\n\t\t\t$_SERVER[`${HTTP_prefix}${name.toUpperCase().replace(/-/g, '_')}`] =\n\t\t\t\theaders[name];\n\t\t}\n\t\treturn $_SERVER;\n\t}\n\n\t#setRelativeRequestUri(uri: string) {\n\t\tthis[__private__dont__use].ccall(\n\t\t\t'wasm_set_request_uri',\n\t\t\tnull,\n\t\t\t[STRING],\n\t\t\t[uri]\n\t\t);\n\t\tlet queryString = '';\n\t\tif (uri.includes('?')) {\n\t\t\tqueryString = uri.substring(uri.indexOf('?') + 1);\n\t\t}\n\t\tthis[__private__dont__use].ccall(\n\t\t\t'wasm_set_query_string',\n\t\t\tnull,\n\t\t\t[STRING],\n\t\t\t[queryString]\n\t\t);\n\t}\n\n\t#setRequestHost(host: string) {\n\t\tthis[__private__dont__use].ccall(\n\t\t\t'wasm_set_request_host',\n\t\t\tnull,\n\t\t\t[STRING],\n\t\t\t[host]\n\t\t);\n\t}\n\n\t#setRequestPort(port: number) {\n\t\tthis[__private__dont__use].ccall(\n\t\t\t'wasm_set_request_port',\n\t\t\tnull,\n\t\t\t[NUMBER],\n\t\t\t[port]\n\t\t);\n\t}\n\n\t#inferPortFromHostAndProtocol(host: string, protocol: string) {\n\t\tlet port;\n\t\ttry {\n\t\t\tport = parseInt(new URL(host).port, 10);\n\t\t} catch {\n\t\t\t// ignore\n\t\t}\n\n\t\tif (!port || isNaN(port) || port === 80) {\n\t\t\tport = protocol === 'https' ? 443 : 80;\n\t\t}\n\t\treturn port;\n\t}\n\n\t#setRequestMethod(method: string) {\n\t\tthis[__private__dont__use].ccall(\n\t\t\t'wasm_set_request_method',\n\t\t\tnull,\n\t\t\t[STRING],\n\t\t\t[method]\n\t\t);\n\t}\n\n\t#setRequestHeaders(headers: PHPRequestHeaders) {\n\t\tif (headers['cookie']) {\n\t\t\tthis[__private__dont__use].ccall(\n\t\t\t\t'wasm_set_cookies',\n\t\t\t\tnull,\n\t\t\t\t[STRING],\n\t\t\t\t[headers['cookie']]\n\t\t\t);\n\t\t}\n\t\tif (headers['content-type']) {\n\t\t\tthis[__private__dont__use].ccall(\n\t\t\t\t'wasm_set_content_type',\n\t\t\t\tnull,\n\t\t\t\t[STRING],\n\t\t\t\t[headers['content-type']]\n\t\t\t);\n\t\t}\n\t\tif (headers['content-length']) {\n\t\t\tthis[__private__dont__use].ccall(\n\t\t\t\t'wasm_set_content_length',\n\t\t\t\tnull,\n\t\t\t\t[NUMBER],\n\t\t\t\t[parseInt(headers['content-length'], 10)]\n\t\t\t);\n\t\t}\n\t}\n\n\t#setRequestBody(body: string | Uint8Array) {\n\t\tlet size, contentLength;\n\t\tif (typeof body === 'string') {\n\t\t\tlogger.warn(\n\t\t\t\t'Passing a string as the request body is deprecated. Please use a Uint8Array instead. See ' +\n\t\t\t\t\t'https://github.com/WordPress/wordpress-playground/issues/997 for more details'\n\t\t\t);\n\t\t\tcontentLength = this[__private__dont__use].lengthBytesUTF8(body);\n\t\t\tsize = contentLength + 1;\n\t\t} else {\n\t\t\tcontentLength = body.byteLength;\n\t\t\tsize = body.byteLength;\n\t\t}\n\n\t\tconst heapBodyPointer = this[__private__dont__use].malloc(size);\n\t\tif (!heapBodyPointer) {\n\t\t\tthrow new Error('Could not allocate memory for the request body.');\n\t\t}\n\n\t\t// Write the string to the WASM memory\n\t\tif (typeof body === 'string') {\n\t\t\tthis[__private__dont__use].stringToUTF8(\n\t\t\t\tbody,\n\t\t\t\theapBodyPointer,\n\t\t\t\tsize + 1\n\t\t\t);\n\t\t} else {\n\t\t\tthis[__private__dont__use].HEAPU8.set(body, heapBodyPointer);\n\t\t}\n\n\t\tthis[__private__dont__use].ccall(\n\t\t\t'wasm_set_request_body',\n\t\t\tnull,\n\t\t\t[NUMBER],\n\t\t\t[heapBodyPointer]\n\t\t);\n\t\tthis[__private__dont__use].ccall(\n\t\t\t'wasm_set_content_length',\n\t\t\tnull,\n\t\t\t[NUMBER],\n\t\t\t[contentLength]\n\t\t);\n\t\treturn heapBodyPointer;\n\t}\n\n\t#setScriptPath(path: string) {\n\t\tthis[__private__dont__use].ccall(\n\t\t\t'wasm_set_path_translated',\n\t\t\tnull,\n\t\t\t[STRING],\n\t\t\t[path]\n\t\t);\n\t}\n\n\t#setServerGlobalEntry(key: string, value: string) {\n\t\tthis[__private__dont__use].ccall(\n\t\t\t'wasm_add_SERVER_entry',\n\t\t\tnull,\n\t\t\t[STRING, STRING],\n\t\t\t[key, value]\n\t\t);\n\t}\n\n\t#setEnv(name: string, value: string) {\n\t\tthis[__private__dont__use].ccall(\n\t\t\t'wasm_add_ENV_entry',\n\t\t\tnull,\n\t\t\t[STRING, STRING],\n\t\t\t[name, value]\n\t\t);\n\t}\n\n\t/**\n\t * Defines a constant in the PHP runtime.\n\t * @param key - The name of the constant.\n\t * @param value - The value of the constant.\n\t */\n\tdefineConstant(key: string, value: string | boolean | number | null) {\n\t\tlet consts = {};\n\t\ttry {\n\t\t\tconsts = JSON.parse(\n\t\t\t\tthis.fileExists('/internal/shared/consts.json')\n\t\t\t\t\t? this.readFileAsText('/internal/shared/consts.json') ||\n\t\t\t\t\t\t\t'{}'\n\t\t\t\t\t: '{}'\n\t\t\t);\n\t\t} catch {\n\t\t\t// ignore\n\t\t}\n\t\tthis.writeFile(\n\t\t\t'/internal/shared/consts.json',\n\t\t\tJSON.stringify({\n\t\t\t\t...consts,\n\t\t\t\t[key]: value,\n\t\t\t})\n\t\t);\n\t}\n\n\t/**\n\t * Executes a PHP runtime function with proper error handling and streaming setup.\n\t * Sets up streaming infrastructure and returns a StreamedPHPResponse.\n\t *\n\t * @param executionFn - Function that returns the exit code or a promise of exit code\n\t * @returns Promise that resolves to a StreamedPHPResponse\n\t */\n\tasync #executeWithErrorHandling(\n\t\texecutionFn: () => any\n\t): Promise<StreamedPHPResponse> {\n\t\tif (\n\t\t\tthis.#rotationOptions.enabled &&\n\t\t\tthis.#rotationOptions.needsRotating\n\t\t) {\n\t\t\tawait this.rotateRuntime();\n\t\t}\n\t\t++this.#rotationOptions.requestsMade;\n\t\tif (\n\t\t\tthis.#rotationOptions.requestsMade >=\n\t\t\tthis.#rotationOptions.maxRequests\n\t\t) {\n\t\t\tthis.#rotationOptions.needsRotating = true;\n\t\t}\n\n\t\tconst emscriptenModule = this[__private__dont__use];\n\n\t\tconst headers = await createInvertedReadableStream<Uint8Array>();\n\t\temscriptenModule.onHeaders = (chunk: Uint8Array) => {\n\t\t\tif (streamsClosed || headersClosed) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// slice() chunk to clone the data and preserve it for the reader later on.\n\t\t\t// We need that because the ArrayBuffer underlying `chunk` may change\n\t\t\t// after this callback return. Without cloning, the reader would read\n\t\t\t// whatever bytes are available in the ArrayBuffer at the time of the read.\n\t\t\theaders.controller.enqueue(chunk.slice());\n\t\t};\n\t\tlet headersClosed = false;\n\t\tconst closeHeadersStream = () => {\n\t\t\tif (!headersClosed) {\n\t\t\t\theadersClosed = true;\n\t\t\t\theaders.controller.close();\n\t\t\t}\n\t\t};\n\n\t\tconst stdout = await createInvertedReadableStream<Uint8Array>();\n\t\temscriptenModule.onStdout = (chunk: Uint8Array) => {\n\t\t\tcloseHeadersStream();\n\t\t\tif (streamsClosed) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstdout.controller.enqueue(chunk.slice());\n\t\t};\n\n\t\tconst stderr = await createInvertedReadableStream<Uint8Array>();\n\t\temscriptenModule.onStderr = (chunk: Uint8Array) => {\n\t\t\tif (streamsClosed) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstderr.controller.enqueue(chunk.slice());\n\t\t};\n\n\t\tlet streamsClosed = false;\n\n\t\tlet errorListener: any;\n\n\t\tconst runExecutionFunction = async () => {\n\t\t\ttry {\n\t\t\t\t/*\n\t\t\t\t * Emscripten throws WASM failures outside of the promise chain so we need\n\t\t\t\t * to listen for them here and rethrow in the correct context. Otherwise we\n\t\t\t\t * get crashes and unhandled promise rejections without any useful error\n\t\t\t\t * messages or meaningful stack traces.\n\t\t\t\t */\n\t\t\t\tconst exitCode = await Promise.race([\n\t\t\t\t\texecutionFn(),\n\t\t\t\t\tnew Promise((_, reject) => {\n\t\t\t\t\t\terrorListener = (e: ErrorEvent) => {\n\t\t\t\t\t\t\tif (!isExitCode(e.error)) {\n\t\t\t\t\t\t\t\treject(e.error);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t\tthis.#wasmErrorsTarget?.addEventListener(\n\t\t\t\t\t\t\t'error',\n\t\t\t\t\t\t\terrorListener,\n\t\t\t\t\t\t\t{ once: true }\n\t\t\t\t\t\t);\n\t\t\t\t\t}),\n\t\t\t\t]);\n\t\t\t\treturn exitCode;\n\t\t\t} catch (e) {\n\t\t\t\t/**\n\t\t\t\t * Emscripten sometimes communicates program exit as an error. Let's\n\t\t\t\t * turn exit code errors into integers again.\n\t\t\t\t */\n\t\t\t\tif (isExitCode(e)) {\n\t\t\t\t\treturn e.status;\n\t\t\t\t}\n\n\t\t\t\t// Non-exit-code errors indicate a WASM runtime crash. Let's clean up and throw.\n\t\t\t\tstdout.controller.error(e);\n\t\t\t\tstderr.controller.error(e);\n\t\t\t\theaders.controller.error(e);\n\t\t\t\tstreamsClosed = true;\n\n\t\t\t\t/**\n\t\t\t\t * A non-exit-code error means an irrecoverable crash. Let's make\n\t\t\t\t * it very clear to the consumers of this API – every method\n\t\t\t\t * call on this PHP instance will throw an error from now on.\n\t\t\t\t */\n\t\t\t\tfor (const name in this) {\n\t\t\t\t\tif (typeof this[name] === 'function') {\n\t\t\t\t\t\t(this as any)[name] = () => {\n\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t`PHP runtime has crashed – see the earlier error for details.`\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t(this as any).functionsMaybeMissingFromAsyncify =\n\t\t\t\t\tgetFunctionsMaybeMissingFromAsyncify();\n\n\t\t\t\tthrow e;\n\t\t\t} finally {\n\t\t\t\tif (!streamsClosed) {\n\t\t\t\t\tstdout.controller.close();\n\t\t\t\t\tstderr.controller.close();\n\t\t\t\t\tcloseHeadersStream();\n\t\t\t\t\tstreamsClosed = true;\n\t\t\t\t}\n\t\t\t\tthis.#wasmErrorsTarget?.removeEventListener(\n\t\t\t\t\t'error',\n\t\t\t\t\terrorListener\n\t\t\t\t);\n\t\t\t}\n\t\t};\n\n\t\t/**\n\t\t * Dispatch a request.error event for any global crash handlers. For example,\n\t\t * Playground web uses this to automatically display a \"Report crash\" modal.\n\t\t */\n\t\tconst exitCodePromise = runExecutionFunction().then(\n\t\t\t(exitCode) => {\n\t\t\t\t/**\n\t\t\t\t * Emit errors related to PHP script failures (exit code other than 0)\n\t\t\t\t */\n\t\t\t\tif (exitCode !== 0) {\n\t\t\t\t\tthis.dispatchEvent({\n\t\t\t\t\t\ttype: 'request.error',\n\t\t\t\t\t\terror: new Error(\n\t\t\t\t\t\t\t`PHP.run() failed with exit code ${exitCode}.`\n\t\t\t\t\t\t),\n\t\t\t\t\t\t// Distinguish between PHP request and PHP-wasm errors\n\t\t\t\t\t\tsource: 'php-wasm',\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn exitCode;\n\t\t\t},\n\t\t\t(error) => {\n\t\t\t\t/**\n\t\t\t\t * Emit all other errors.\n\t\t\t\t */\n\t\t\t\t// Distinguish between PHP request and PHP-wasm errors\n\t\t\t\tconst source = (error as any).source ?? 'php-wasm';\n\t\t\t\tthis.dispatchEvent({\n\t\t\t\t\ttype: 'request.error',\n\t\t\t\t\terror: error as any as Error,\n\t\t\t\t\tsource,\n\t\t\t\t});\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t);\n\n\t\treturn new StreamedPHPResponse(\n\t\t\theaders.stream,\n\t\t\tstdout.stream,\n\t\t\tstderr.stream,\n\t\t\texitCodePromise\n\t\t);\n\t}\n\n\t/**\n\t * Recursively creates a directory with the given path in the PHP filesystem.\n\t * For example, if the path is `/root/php/data`, and `/root` already exists,\n\t * it will create the directories `/root/php` and `/root/php/data`.\n\t *\n\t * @param path - The directory path to create.\n\t */\n\tmkdir(path: string) {\n\t\tconst result = FSHelpers.mkdir(this[__private__dont__use].FS, path);\n\t\tthis.dispatchEvent({ type: 'filesystem.write' });\n\t\treturn result;\n\t}\n\n\t/**\n\t * @deprecated Use mkdir instead.\n\t */\n\tmkdirTree(path: string) {\n\t\treturn FSHelpers.mkdir(this[__private__dont__use].FS, path);\n\t}\n\n\t/**\n\t * Reads a file from the PHP filesystem and returns it as a string.\n\t *\n\t * @throws {@link @php-wasm/universal:ErrnoError} – If the file doesn't exist.\n\t * @param path - The file path to read.\n\t * @returns The file contents.\n\t */\n\treadFileAsText(path: string) {\n\t\treturn FSHelpers.readFileAsText(this[__private__dont__use].FS, path);\n\t}\n\n\t/**\n\t * Reads a file from the PHP filesystem and returns it as an array buffer.\n\t *\n\t * @throws {@link @php-wasm/universal:ErrnoError} – If the file doesn't exist.\n\t * @param path - The file path to read.\n\t * @returns The file contents.\n\t */\n\treadFileAsBuffer(path: string): Uint8Array {\n\t\treturn FSHelpers.readFileAsBuffer(this[__private__dont__use].FS, path);\n\t}\n\n\t/**\n\t * Overwrites data in a file in the PHP filesystem.\n\t * Creates a new file if one doesn't exist yet.\n\t *\n\t * @param path - The file path to write to.\n\t * @param data - The data to write to the file.\n\t */\n\twriteFile(path: string, data: string | Uint8Array | Buffer) {\n\t\tconst result = FSHelpers.writeFile(\n\t\t\tthis[__private__dont__use].FS,\n\t\t\tpath,\n\t\t\tdata\n\t\t);\n\t\tthis.dispatchEvent({ type: 'filesystem.write' });\n\t\treturn result;\n\t}\n\n\t/**\n\t * Removes a file from the PHP filesystem.\n\t *\n\t * @throws {@link @php-wasm/universal:ErrnoError} – If the file doesn't exist.\n\t * @param path - The file path to remove.\n\t */\n\tunlink(path: string) {\n\t\tconst result = FSHelpers.unlink(this[__private__dont__use].FS, path);\n\t\tthis.dispatchEvent({ type: 'filesystem.write' });\n\t\treturn result;\n\t}\n\n\t/**\n\t * Moves a file or directory in the PHP filesystem to a\n\t * new location.\n\t *\n\t * @param oldPath The path to rename.\n\t * @param newPath The new path.\n\t */\n\tmv(fromPath: string, toPath: string) {\n\t\tconst result = FSHelpers.mv(\n\t\t\tthis[__private__dont__use].FS,\n\t\t\tfromPath,\n\t\t\ttoPath\n\t\t);\n\t\tthis.dispatchEvent({ type: 'filesystem.write' });\n\t\treturn result;\n\t}\n\n\t/**\n\t * Removes a directory from the PHP filesystem.\n\t *\n\t * @param path The directory path to remove.\n\t * @param options Options for the removal.\n\t */\n\trmdir(path: string, options: RmDirOptions = { recursive: true }) {\n\t\tconst result = FSHelpers.rmdir(\n\t\t\tthis[__private__dont__use].FS,\n\t\t\tpath,\n\t\t\toptions\n\t\t);\n\t\tthis.dispatchEvent({ type: 'filesystem.write' });\n\t\treturn result;\n\t}\n\n\t/**\n\t * Lists the files and directories in the given directory.\n\t *\n\t * @param path - The directory path to list.\n\t * @param options - Options for the listing.\n\t * @returns The list of files and directories in the given directory.\n\t */\n\tlistFiles(\n\t\tpath: string,\n\t\toptions: ListFilesOptions = { prependPath: false }\n\t) {\n\t\treturn FSHelpers.listFiles(\n\t\t\tthis[__private__dont__use].FS,\n\t\t\tpath,\n\t\t\toptions\n\t\t);\n\t}\n\n\t/**\n\t * Checks if a directory exists in the PHP filesystem.\n\t *\n\t * @param path – The path to check.\n\t * @returns True if the path is a directory, false otherwise.\n\t */\n\tisDir(path: string) {\n\t\treturn FSHelpers.isDir(this[__private__dont__use].FS, path);\n\t}\n\n\t/**\n\t * Checks if a file exists in the PHP filesystem.\n\t *\n\t * @param path – The path to check.\n\t * @returns True if the path is a file, false otherwise.\n\t */\n\tisFile(path: string) {\n\t\treturn FSHelpers.isFile(this[__private__dont__use].FS, path);\n\t}\n\n\t/**\n\t * Creates a symlink in the PHP filesystem.\n\t * @param target\n\t * @param path\n\t */\n\tsymlink(target: string, path: string) {\n\t\treturn FSHelpers.symlink(this[__private__dont__use].FS, target, path);\n\t}\n\n\t/**\n\t * Checks if a path is a symlink in the PHP filesystem.\n\t *\n\t * @param path\n\t * @returns True if the path is a symlink, false otherwise.\n\t */\n\tisSymlink(path: string) {\n\t\treturn FSHelpers.isSymlink(this[__private__dont__use].FS, path);\n\t}\n\n\t/**\n\t * Reads the target of a symlink in the PHP filesystem.\n\t *\n\t * @param path\n\t * @returns The target of the symlink.\n\t */\n\treadlink(path: string) {\n\t\treturn FSHelpers.readlink(this[__private__dont__use].FS, path);\n\t}\n\n\t/**\n\t * Resolves the real path of a file in the PHP filesystem.\n\t * @param path\n\t * @returns The real path of the file.\n\t */\n\trealpath(path: string) {\n\t\treturn FSHelpers.realpath(this[__private__dont__use].FS, path);\n\t}\n\n\t/**\n\t * Checks if a file (or a directory) exists in the PHP filesystem.\n\t *\n\t * @param path - The file path to check.\n\t * @returns True if the file exists, false otherwise.\n\t */\n\tfileExists(path: string) {\n\t\treturn FSHelpers.fileExists(this[__private__dont__use].FS, path);\n\t}\n\n\t/**\n\t * Enables inline PHP runtime rotation after a certain number of requests\n\t * or an internal crash.\n\t */\n\tenableRuntimeRotation(options: {\n\t\trecreateRuntime: () => Promise<number> | number;\n\t\tmaxRequests?: number;\n\t}) {\n\t\tthis.#rotationOptions = {\n\t\t\t...this.#rotationOptions,\n\t\t\tenabled: true,\n\t\t\trecreateRuntime: options.recreateRuntime,\n\t\t\tmaxRequests: options.maxRequests ?? 400,\n\t\t};\n\t}\n\n\tprivate async rotateRuntime() {\n\t\tif (!this.#rotationOptions.enabled) {\n\t\t\tthrow new Error(\n\t\t\t\t'Runtime rotation is not enabled. Call enableRuntimeRotation() first.'\n\t\t\t);\n\t\t}\n\t\tawait this.hotSwapPHPRuntime(\n\t\t\tawait this.#rotationOptions.recreateRuntime()\n\t\t);\n\t\tthis.#rotationOptions.requestsMade = 0;\n\t\tthis.#rotationOptions.needsRotating = false;\n\t}\n\n\t/**\n\t * Hot-swaps the PHP runtime for a new one without\n\t * interrupting the operations of this PHP instance.\n\t *\n\t * @param runtime\n\t */\n\tasync hotSwapPHPRuntime(runtime: number) {\n\t\t// Once we secure the lock and have the new runtime ready,\n\t\t// the rest of the swap handler is synchronous to make sure\n\t\t// no other operations acts on the old runtime or FS.\n\t\t// If there was await anywhere here, we'd risk applyng\n\t\t// asynchronous changes to either the filesystem or the\n\t\t// old PHP runtime without propagating them to the new\n\t\t// runtime.\n\n\t\tconst oldFS = this[__private__dont__use].FS;\n\t\tconst oldRootLevelPaths = this.listFiles('/').map((file) => `/${file}`);\n\t\tconst oldSpawnProcess = this[__private__dont__use].spawnProcess;\n\n\t\t// Temporarily set CWD to / and restore it at the end of this method.\n\t\t//\n\t\t// There's a chance cleaning up old mounts via mount.unmount()\n\t\t// will attempt removing the CWD. Normally, this would throw\n\t\t// FS.ErrnoError(10) EBUSY and interrupt the PHP runtime rotation,\n\t\t// leaving us in a broken state.\n\t\t//\n\t\t// Even though removing the CWD directory is not allowed by the\n\t\t// filesystem, we don't care that much here – we're merely freeing\n\t\t// all the resources allocated by the old filesystem before it's\n\t\t// garbage collected. We are about to recreate the same filesystem\n\t\t// structure and mounts in another PHP runtime.\n\t\t//\n\t\t// Therefore, let's suspend the strict EBUSY check by setting the CWD\n\t\t// to / for the cleanup purposes. We'll attempt to restore the original\n\t\t// CWD on the new runtime once we re-apply all the mounts there. We'll\n\t\t// only have a real reason to throw an error if the CWD path does not\n\t\t// exist in the new filesystem after the rotation.\n\t\tconst oldCWD = oldFS.cwd();\n\t\toldFS.chdir('/');\n\n\t\t// Remember mounts to apply to new runtime\n\t\tconst mountHandlersToReapplyInOrder = Object.entries(this.#mounts).map(\n\t\t\t([vfsPath, mount]) => ({\n\t\t\t\tmountHandler: mount.mountHandler,\n\t\t\t\tvfsPath,\n\t\t\t})\n\t\t);\n\n\t\t// Unmount all the mount handlers in reverse order because each nested\n\t\t// mount depends upon the parent mount which preceded it.\n\t\tconst mountsToUnmountInReverseOrder = Object.values(\n\t\t\tthis.#mounts\n\t\t).reverse();\n\t\tfor (const mount of mountsToUnmountInReverseOrder) {\n\t\t\tawait mount.unmount();\n\t\t}\n\n\t\t// Kill the current runtime\n\t\ttry {\n\t\t\tthis.exit();\n\t\t} catch {\n\t\t\t// Ignore the exit-related exception\n\t\t}\n\n\t\t// Initialize the new runtime\n\t\tthis.initializeRuntime(runtime);\n\n\t\tif (oldSpawnProcess) {\n\t\t\tthis[__private__dont__use].spawnProcess = oldSpawnProcess;\n\t\t}\n\n\t\tif (this.#sapiName) {\n\t\t\tthis.setSapiName(this.#sapiName);\n\t\t}\n\n\t\t/**\n\t\t * Ensure the new PHP instance has the same file structure as the old one.\n\t\t *\n\t\t * Catch: The underlying filesystems may be completely separate but they may be\n\t\t * partially shared via NODEFS or PROXYFS mounts. We need to be careful and only\n\t\t * recreate the MEMFS directories that aren't already shared – otherwise we'll\n\t\t * write data to shared paths that other, concurrent workers may be using.\n\t\t */\n\t\tconst newFs = this[__private__dont__use].FS;\n\t\tfor (const path of oldRootLevelPaths) {\n\t\t\t// The /request directory holds per-request state that is isolated to a\n\t\t\t// single PHP instance. Let's not copy it.\n\t\t\tif (path && path !== '/request') {\n\t\t\t\tcopyMEMFSNodes(oldFS, newFs, path);\n\t\t\t}\n\t\t}\n\n\t\t// Re-mount all the mount handlers in order\n\t\tfor (const { mountHandler, vfsPath } of mountHandlersToReapplyInOrder) {\n\t\t\tthis.mkdir(vfsPath);\n\t\t\tawait this.mount(vfsPath, mountHandler);\n\t\t}\n\t\ttry {\n\t\t\tnewFs.chdir(oldCWD);\n\t\t} catch (e) {\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to restore CWD to ${oldCWD} after PHP runtime rotation.`,\n\t\t\t\t{\n\t\t\t\t\tcause: e,\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Mounts a filesystem to a given path in the PHP filesystem.\n\t *\n\t * @param virtualFSPath - Where to mount it in the PHP virtual filesystem.\n\t * @param mountHandler - The mount handler to use.\n\t * @return Unmount function to unmount the filesystem.\n\t */\n\tasync mount(\n\t\tvirtualFSPath: string,\n\t\tmountHandler: MountHandler\n\t): Promise<UnmountFunction> {\n\t\tconst unmountCallback = await mountHandler(\n\t\t\tthis,\n\t\t\tthis[__private__dont__use].FS,\n\t\t\tvirtualFSPath\n\t\t);\n\t\tconst mountObject = {\n\t\t\tmountHandler,\n\t\t\tunmount: async () => {\n\t\t\t\tawait unmountCallback();\n\t\t\t\tdelete this.#mounts[virtualFSPath];\n\t\t\t},\n\t\t};\n\t\tthis.#mounts[virtualFSPath] = mountObject;\n\t\treturn () => {\n\t\t\tmountObject.unmount();\n\t\t};\n\t}\n\n\t/**\n\t * Starts a PHP CLI session with given arguments.\n\t *\n\t * This method can only be used when PHP was compiled with the CLI SAPI\n\t * and it cannot be used in conjunction with `run()`.\n\t *\n\t * Once this method finishes running, the PHP instance is no\n\t * longer usable and should be discarded. This is because PHP\n\t * internally cleans up all the resources and calls exit().\n\t *\n\t * @param argv - The arguments to pass to the CLI.\n\t * @returns The exit code of the CLI session.\n\t */\n\tasync cli(\n\t\targv: string[],\n\t\toptions: { env?: Record<string, string>; cwd?: string } = {}\n\t): Promise<StreamedPHPResponse> {\n\t\tif (basename(argv[0] ?? '') !== 'php') {\n\t\t\treturn this.subProcess(argv, options);\n\t\t}\n\n\t\tif (this.#phpWasmInitCalled) {\n\t\t\tthis.#rotationOptions.needsRotating = true;\n\t\t}\n\n\t\tconst release = await this.semaphore.acquire();\n\n\t\treturn await this.#executeWithErrorHandling(() => {\n\t\t\tconst env = options.env || {};\n\t\t\tfor (const [key, value] of Object.entries(env)) {\n\t\t\t\tthis.#setEnv(key, value);\n\t\t\t}\n\t\t\t// Enforce the use of the internal php.ini file.\n\t\t\targv = [argv[0], '-c', PHP_INI_PATH, ...argv.slice(1)];\n\t\t\tfor (const arg of argv) {\n\t\t\t\tthis[__private__dont__use].ccall(\n\t\t\t\t\t'wasm_add_cli_arg',\n\t\t\t\t\tnull,\n\t\t\t\t\t[STRING],\n\t\t\t\t\t[arg]\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn this[__private__dont__use].ccall('run_cli', null, [], [], {\n\t\t\t\tasync: true,\n\t\t\t});\n\t\t})\n\t\t\t.then((response) => {\n\t\t\t\tresponse.exitCode.finally(release);\n\t\t\t\treturn response;\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\tthis.#rotationOptions.needsRotating = true;\n\t\t\t});\n\t}\n\n\t/**\n\t * Runs an arbitrary CLI command using the spawn handler associated\n\t * with this PHP instance.\n\t *\n\t * @param argv\n\t * @param options\n\t * @returns StreamedPHPResponse.\n\t */\n\tprivate async subProcess(\n\t\targv: string[],\n\t\toptions: { env?: Record<string, string>; cwd?: string } = {}\n\t): Promise<StreamedPHPResponse> {\n\t\tconst process = this[__private__dont__use].spawnProcess(\n\t\t\targv[0],\n\t\t\targv.slice(1),\n\t\t\t{\n\t\t\t\tenv: options.env,\n\t\t\t\tcwd: options.cwd ?? this.cwd(),\n\t\t\t}\n\t\t) as ChildProcess;\n\n\t\tconst stderrStream = await createInvertedReadableStream<Uint8Array>();\n\t\tprocess.on('error', (error) => {\n\t\t\tstderrStream.controller.error(error);\n\t\t});\n\t\tprocess.stderr.on('data', (data) => {\n\t\t\tstderrStream.controller.enqueue(data);\n\t\t});\n\n\t\tconst stdoutStream = await createInvertedReadableStream<Uint8Array>();\n\t\tprocess.stdout.on('data', (data) => {\n\t\t\tstdoutStream.controller.enqueue(data);\n\t\t});\n\n\t\tprocess.on('exit', () => {\n\t\t\t// Delay until next tick to ensure we don't close the streams before\n\t\t\t// emitting the error event on the stderrStream.\n\t\t\tsetTimeout(() => {\n\t\t\t\t/**\n\t\t\t\t * Ignore any close() errors, e.g. \"stream already closed\". We just\n\t\t\t\t * need to try to call close() and forget about this subprocess.\n\t\t\t\t */\n\t\t\t\ttry {\n\t\t\t\t\tstderrStream.controller.close();\n\t\t\t\t} catch {\n\t\t\t\t\t// Ignore error\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tstdoutStream.controller.close();\n\t\t\t\t} catch {\n\t\t\t\t\t// Ignore error\n\t\t\t\t}\n\t\t\t}, 0);\n\t\t});\n\n\t\treturn new StreamedPHPResponse(\n\t\t\t// Headers stream\n\t\t\tnew ReadableStream({\n\t\t\t\tstart(controller) {\n\t\t\t\t\tcontroller.close();\n\t\t\t\t},\n\t\t\t}),\n\t\t\tstdoutStream.stream,\n\t\t\tstderrStream.stream,\n\t\t\t// Exit code\n\t\t\tnew Promise((resolve) => {\n\t\t\t\tprocess.on('exit', (code) => {\n\t\t\t\t\tresolve(code);\n\t\t\t\t});\n\t\t\t})\n\t\t);\n\t}\n\n\tsetSkipShebang(shouldSkip: boolean) {\n\t\tthis[__private__dont__use].ccall(\n\t\t\t'wasm_set_skip_shebang',\n\t\t\tnull,\n\t\t\t[NUMBER],\n\t\t\t[shouldSkip ? 1 : 0]\n\t\t);\n\t}\n\n\texit(code = 0) {\n\t\tthis.dispatchEvent({\n\t\t\ttype: 'runtime.beforeExit',\n\t\t});\n\t\ttry {\n\t\t\tthis[__private__dont__use]._exit(code);\n\t\t} catch {\n\t\t\t// ignore the exit error\n\t\t}\n\n\t\t// Clean up any initialized state\n\t\tthis.#phpWasmInitCalled = false;\n\n\t\t// Delete any links between this PHP instance and the runtime\n\t\tthis.#wasmErrorsTarget = null;\n\n\t\tif (this[__private__dont__use]) {\n\t\t\tdelete this[__private__dont__use]['onMessage'];\n\t\t\tdelete this[__private__dont__use];\n\t\t}\n\t}\n\n\t[Symbol.dispose]() {\n\t\tthis.exit(0);\n\t}\n}\n\nexport function normalizeHeaders(\n\theaders: PHPRequestHeaders\n): PHPRequestHeaders {\n\tconst normalized: PHPRequestHeaders = {};\n\tfor (const key in headers) {\n\t\tnormalized[key.toLowerCase()] = headers[key];\n\t}\n\treturn normalized;\n}\n\n/**\n * Copies the MEMFS directory structure from one FS in another FS.\n * Non-MEMFS nodes are ignored.\n */\nfunction copyMEMFSNodes(\n\tsource: Emscripten.FileSystemInstance,\n\ttarget: Emscripten.FileSystemInstance,\n\tpath: string\n) {\n\tif (\n\t\tgetNodeType(source, path) !== 'memfs' ||\n\t\t!['memfs', 'missing'].includes(getNodeType(target, path))\n\t) {\n\t\treturn;\n\t}\n\n\tconst oldNode = source.lookupPath(path);\n\tif (!source.isDir(oldNode.node.mode)) {\n\t\ttarget.writeFile(path, source.readFile(path));\n\t\treturn;\n\t}\n\n\ttarget.mkdirTree(path);\n\tconst filenames = source\n\t\t.readdir(path)\n\t\t.filter((name: string) => name !== '.' && name !== '..');\n\tfor (const filename of filenames) {\n\t\tcopyMEMFSNodes(source, target, joinPaths(path, filename));\n\t}\n}\n\n/**\n * Creates a readable stream with inverted control flow,\n * based on the specified underlying source.\n *\n * In this case, inverting control flow means exposing the controller\n * so the consumer can insert data into the stream.\n *\n * @param source - The underlying source to use.\n * @returns The resulting stream and its associated controller.\n */\nasync function createInvertedReadableStream<T = BufferSource>(\n\tsource: UnderlyingSource<T> = {}\n): Promise<{\n\tstream: ReadableStream<T>;\n\tcontroller: ReadableStreamDefaultController<T>;\n}> {\n\tlet controllerResolve: (\n\t\tcontroller: ReadableStreamDefaultController<T>\n\t) => void;\n\tconst controllerPromise = new Promise<ReadableStreamDefaultController<T>>(\n\t\t(resolve) => {\n\t\t\tcontrollerResolve = resolve;\n\t\t}\n\t);\n\n\tconst stream = new ReadableStream<T>({\n\t\t...source,\n\t\tstart(controller) {\n\t\t\t// Type assertion to handle the controller type mismatch\n\t\t\tcontrollerResolve(controller as ReadableStreamDefaultController<T>);\n\t\t\tif (source.start) {\n\t\t\t\treturn source.start(controller);\n\t\t\t}\n\t\t\treturn undefined;\n\t\t},\n\t});\n\n\tconst controller = await controllerPromise;\n\n\treturn {\n\t\tstream,\n\t\tcontroller,\n\t};\n}\n\nconst getNodeType = (fs: Emscripten.FileSystemInstance, path: string) => {\n\ttry {\n\t\tconst target = fs.lookupPath(path, { follow: true });\n\t\treturn 'contents' in target.node\n\t\t\t? 'memfs'\n\t\t\t: /**\n\t\t\t\t * Could be NODEFS, PROXYFS, etc.\n\t\t\t\t */\n\t\t\t\t'not-memfs';\n\t} catch {\n\t\treturn 'missing';\n\t}\n};\n","import { PHP_INI_PATH } from './php';\nimport type { UniversalPHP } from './universal-php';\nimport { stringify, parse } from 'ini';\n\n/**\n * Reads the php.ini file and returns its entries.\n *\n * @param php The PHP instance.\n * @param entries Optional. If provided, only the specified entries will be returned.\n * @returns The php.ini entries.\n */\nexport async function getPhpIniEntries(php: UniversalPHP, entries?: string[]) {\n\tconst ini = parse(await php.readFileAsText(PHP_INI_PATH));\n\tif (entries === undefined) {\n\t\treturn ini;\n\t}\n\tconst result: Record<string, unknown> = {};\n\tfor (const key of entries) {\n\t\tresult[key] = ini[key];\n\t}\n\treturn result;\n}\n\n/**\n * Rewrites the php.ini file with the given entries.\n *\n * @param php The PHP instance.\n * @param entries The entries to write to the php.ini file.\n */\nexport async function setPhpIniEntries(\n\tphp: UniversalPHP,\n\tentries: Record<string, unknown>\n) {\n\tconst ini = parse(await php.readFileAsText(PHP_INI_PATH));\n\tfor (const [key, value] of Object.entries(entries)) {\n\t\tif (value === undefined || value === null) {\n\t\t\tdelete ini[key];\n\t\t} else {\n\t\t\tini[key] = value;\n\t\t}\n\t}\n\tawait php.writeFile(PHP_INI_PATH, stringify(ini));\n}\n\n/**\n * Sets php.ini values to the given values, executes a callback,\n * and restores the original php.ini values. This is useful for\n * running code with temporary php.ini values, such as when\n * disabling network-related PHP functions just to run WordPress\n * installer.\n *\n * @example\n * ```ts\n *\tawait withPHPIniValues(\n *\t\tphp,\n *\t\t{\n *\t\t\tdisable_functions: 'fsockopen',\n *\t\t\tallow_url_fopen: '0',\n *\t\t},\n *\t\tasync () => await runWpInstallationWizard(php, {\n *\t\t\toptions: {},\n *\t\t})\n *\t);\n *\t```\n *\n * @param php The PHP instance.\n * @param phpIniValues The php.ini values to set.\n * @param callback The callback to execute.\n * @returns The result of the callback.\n */\nexport async function withPHPIniValues(\n\tphp: UniversalPHP,\n\tphpIniValues: Record<string, string>,\n\tcallback: () => Promise<any>\n) {\n\tconst iniBefore = await php.readFileAsText(PHP_INI_PATH);\n\ttry {\n\t\tawait setPhpIniEntries(php, phpIniValues);\n\t\treturn await callback();\n\t} finally {\n\t\tawait php.writeFile(PHP_INI_PATH, iniBefore);\n\t}\n}\n","import type { StreamedPHPResponse } from './php-response';\nimport { PHPResponse } from './php-response';\n\nexport async function printDebugDetails(\n\te: any,\n\tstreamedResponse?: StreamedPHPResponse\n) {\n\tif (streamedResponse) {\n\t\tprintResponseDebugDetails(\n\t\t\tawait PHPResponse.fromStreamedResponse(streamedResponse)\n\t\t);\n\t}\n\tawait prettyPrintFullStackTrace(e);\n}\n\n/**\n * Pretty prints the full stack trace of the error and all its causes.\n * Includes debug details for each error in the chain.\n * This is needed\n *\n * @param e\n */\nexport async function prettyPrintFullStackTrace(e: any) {\n\tlet current = e;\n\tlet isFirst = true;\n\twhile (current) {\n\t\tif (!isFirst) {\n\t\t\tprocess.stderr.write('\\nCaused by:\\n\\n');\n\t\t}\n\n\t\tprocess.stderr.write(current.originalErrorClassName ?? current.name);\n\t\tprocess.stderr.write(': ' + current.message + '\\n');\n\t\tprocess.stderr.write(\n\t\t\t(current.stack + '').split('\\n').slice(1).join('\\n')\n\t\t);\n\t\tprocess.stderr.write(`\\n`);\n\t\tif (current.response) {\n\t\t\tprintResponseDebugDetails(current.response);\n\t\t}\n\t\tif (current.phpLogs) {\n\t\t\tprocess.stderr.write(`\\n\\n==== PHP error log ====\\n\\n`);\n\t\t\tprocess.stderr.write(current.phpLogs);\n\t\t}\n\t\tcurrent = current.cause;\n\t\tisFirst = false;\n\t}\n\tprocess.stderr.write('\\n');\n}\n\nexport function printResponseDebugDetails(response: PHPResponse) {\n\t// Print a short summary of what we have:\n\tprocess.stderr.write(\n\t\t`\\n exitCode=${response.exitCode} httpStatusCode=${response.httpStatusCode} `\n\t);\n\tconst hasHeaders =\n\t\tresponse.headers && Object.keys(response.headers).length > 0;\n\tif (!hasHeaders) {\n\t\tprocess.stderr.write(`responseHeaders=(empty) `);\n\t}\n\tif (!response.text) {\n\t\tprocess.stderr.write(`stdout=(empty) `);\n\t}\n\tif (!response.errors) {\n\t\tprocess.stderr.write(`stderr=(empty) `);\n\t}\n\tprocess.stderr.write(`\\n`);\n\n\t// Print all the extended information in a separate section:\n\tif (hasHeaders) {\n\t\tprocess.stderr.write(\n\t\t\t`\\n==== PHP response headers ====\\n\\n${JSON.stringify(\n\t\t\t\tresponse.headers,\n\t\t\t\tnull,\n\t\t\t\t2\n\t\t\t)}\\n\\n`\n\t\t);\n\t}\n\n\tif (response.text) {\n\t\tprocess.stderr.write(`\\n==== PHP stdout ====\\n\\n`);\n\t\tprocess.stderr.write(response.text);\n\t}\n\n\tif (response.errors) {\n\t\tprocess.stderr.write(`\\n==== PHP stderr ====\\n\\n`);\n\t\tprocess.stderr.write(response.errors);\n\t}\n\tprocess.stderr.write(`\\n`);\n}\n","import { logger } from '@php-wasm/logger';\nimport type { CookieStore } from './php-request-handler';\n/**\n * @public\n */\nexport class HttpCookieStore implements CookieStore {\n\tcookies: Record<string, string> = {};\n\n\trememberCookiesFromResponseHeaders(headers: Record<string, string[]>) {\n\t\tif (!headers?.['set-cookie']) {\n\t\t\treturn;\n\t\t}\n\t\tfor (const setCookie of headers['set-cookie']) {\n\t\t\ttry {\n\t\t\t\tif (!setCookie.includes('=')) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst equalsIndex = setCookie.indexOf('=');\n\t\t\t\tconst name = setCookie.substring(0, equalsIndex);\n\t\t\t\tconst value = setCookie\n\t\t\t\t\t.substring(equalsIndex + 1)\n\t\t\t\t\t.split(';')[0];\n\t\t\t\tthis.cookies[name] = value;\n\t\t\t} catch (e) {\n\t\t\t\tlogger.error(e);\n\t\t\t}\n\t\t}\n\t}\n\n\tgetCookieRequestHeader() {\n\t\tconst cookiesArray: string[] = [];\n\t\tfor (const name in this.cookies) {\n\t\t\tcookiesArray.push(`${name}=${this.cookies[name]}`);\n\t\t}\n\t\treturn cookiesArray.join('; ');\n\t}\n}\n","import type { UniversalPHP } from './universal-php';\n\n/**\n * Reads a file from PHP filesystem using a stream.\n */\nexport function streamReadFileFromPHP(php: UniversalPHP, path: string) {\n\treturn new ReadableStream({\n\t\tasync pull(controller) {\n\t\t\tconst buffer = await php.readFileAsBuffer(path);\n\t\t\tcontroller.enqueue(buffer);\n\t\t\tcontroller.close();\n\t\t},\n\t});\n}\n","import { joinPaths, normalizePath } from '@php-wasm/util';\nimport { StreamedFile } from '@php-wasm/stream-compression';\nimport type { UniversalPHP } from './universal-php';\nimport { streamReadFileFromPHP } from './stream-read-file-from-php';\n\nexport type IteratePhpFilesOptions = {\n\t/**\n\t * Should yield paths relative to the root directory?\n\t * If false, all paths will be absolute.\n\t */\n\trelativePaths?: boolean;\n\n\t/**\n\t * A prefix to add to all paths.\n\t * Only used if `relativePaths` is true.\n\t */\n\tpathPrefix?: string;\n\n\t/**\n\t * A list of paths to exclude from the results.\n\t */\n\texceptPaths?: string[];\n};\n\n/**\n * Iterates over all files in a php directory and its subdirectories.\n *\n * @param php - The PHP instance.\n * @param root - The root directory to start iterating from.\n * @param options - Optional configuration.\n * @returns All files found in the tree.\n */\nexport async function* iteratePhpFiles(\n\tphp: UniversalPHP,\n\troot: string,\n\t{\n\t\trelativePaths = true,\n\t\tpathPrefix,\n\t\texceptPaths = [],\n\t}: IteratePhpFilesOptions = {}\n): AsyncGenerator<File> {\n\troot = normalizePath(root);\n\tconst stack: string[] = [root];\n\twhile (stack.length) {\n\t\tconst currentParent = stack.pop();\n\t\tif (!currentParent) {\n\t\t\treturn;\n\t\t}\n\t\tconst files = await php.listFiles(currentParent);\n\t\tfor (const file of files) {\n\t\t\tconst absPath = `${currentParent}/${file}`;\n\t\t\tif (exceptPaths.includes(absPath.substring(root.length + 1))) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst isDir = await php.isDir(absPath);\n\t\t\tif (isDir) {\n\t\t\t\tstack.push(absPath);\n\t\t\t} else {\n\t\t\t\tyield new StreamedFile(\n\t\t\t\t\tstreamReadFileFromPHP(php, absPath),\n\t\t\t\t\trelativePaths\n\t\t\t\t\t\t? joinPaths(\n\t\t\t\t\t\t\t\tpathPrefix || '',\n\t\t\t\t\t\t\t\tabsPath.substring(root.length + 1)\n\t\t\t\t\t\t )\n\t\t\t\t\t\t: absPath\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n}\n","import { dirname, joinPaths } from '@php-wasm/util';\nimport type { UniversalPHP } from './universal-php';\n\n/**\n * Writes streamed files to PHP filesystem.\n */\nexport function writeFilesStreamToPhp(php: UniversalPHP, root: string) {\n\treturn new WritableStream({\n\t\tasync write(file: File) {\n\t\t\tconst filePath = joinPaths(root, file.name);\n\t\t\tif (file.type === 'directory') {\n\t\t\t\tawait php.mkdir(filePath);\n\t\t\t} else {\n\t\t\t\tawait php.mkdir(dirname(filePath));\n\t\t\t\tawait php.writeFile(\n\t\t\t\t\tfilePath,\n\t\t\t\t\tnew Uint8Array(await file.arrayBuffer())\n\t\t\t\t);\n\t\t\t}\n\t\t},\n\t});\n}\n","import type { PHP } from './php';\nimport type { PHPInstanceManager, AcquiredPHP } from './php-instance-manager';\n\nexport interface SinglePHPInstanceManagerOptions {\n\t/**\n\t * Either provide an existing PHP instance...\n\t */\n\tphp?: PHP;\n\t/**\n\t * ...or a factory to create one on demand.\n\t */\n\tphpFactory?: () => Promise<PHP>;\n}\n\n/**\n * A minimal PHP instance manager that manages a single PHP instance.\n *\n * Unlike PHPProcessManager, this does not maintain a pool of instances\n * or implement concurrency control. It simply returns the same PHP\n * instance for every request.\n *\n * This is suitable for CLI contexts where:\n * - Only one PHP instance is needed\n * - Runtime rotation is handled separately via php.enableRuntimeRotation()\n * - Concurrency is not a concern (each worker has its own instance)\n */\nexport class SinglePHPInstanceManager implements PHPInstanceManager {\n\tprivate php: PHP | undefined;\n\tprivate phpPromise: Promise<PHP> | undefined;\n\tprivate phpFactory?: () => Promise<PHP>;\n\tprivate isAcquired = false;\n\n\tconstructor(options: SinglePHPInstanceManagerOptions) {\n\t\tif (!options.php && !options.phpFactory) {\n\t\t\tthrow new Error(\n\t\t\t\t'SinglePHPInstanceManager requires either php or phpFactory'\n\t\t\t);\n\t\t}\n\t\tthis.php = options.php;\n\t\tthis.phpFactory = options.phpFactory;\n\t}\n\n\tasync getPrimaryPhp(): Promise<PHP> {\n\t\tif (!this.php) {\n\t\t\tif (!this.phpPromise) {\n\t\t\t\tthis.phpPromise = this.phpFactory!().then((php) => {\n\t\t\t\t\tthis.php = php;\n\t\t\t\t\tthis.phpPromise = undefined;\n\t\t\t\t\treturn php;\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn this.phpPromise;\n\t\t}\n\t\treturn this.php;\n\t}\n\n\tasync acquirePHPInstance(): Promise<AcquiredPHP> {\n\t\tif (this.isAcquired) {\n\t\t\tthrow new Error(\n\t\t\t\t'The PHP instance already acquired. SinglePHPInstanceManager cannot spawn another PHP instance since, by definition, it only manages a single PHP instance.'\n\t\t\t);\n\t\t}\n\t\tconst php = await this.getPrimaryPhp();\n\t\tthis.isAcquired = true;\n\t\treturn {\n\t\t\tphp,\n\t\t\treap: () => {\n\t\t\t\t// For single-instance manager, reap is a no-op.\n\t\t\t\t// The instance is reused for all requests.\n\t\t\t\tthis.isAcquired = false;\n\t\t\t},\n\t\t};\n\t}\n\n\tasync [Symbol.asyncDispose](): Promise<void> {\n\t\tif (this.php) {\n\t\t\tthis.php.exit();\n\t\t}\n\t}\n}\n","import { AcquireTimeoutError, Semaphore } from '@php-wasm/util';\nimport type { PHP } from './php';\nimport type { PHPInstanceManager, AcquiredPHP } from './php-instance-manager';\n\nexport type PHPFactoryOptions = {\n\tisPrimary: boolean;\n};\n\nexport type PHPFactory = (options: PHPFactoryOptions) => Promise<PHP>;\n\nexport interface ProcessManagerOptions {\n\t/**\n\t * The maximum number of PHP instances that can be in use at\n\t * the same time.\n\t */\n\tmaxPhpInstances?: number;\n\t/**\n\t * The number of milliseconds to wait for a PHP instance when\n\t * all instances are busy. If the timeout is reached, we assume\n\t * all the PHP instances are deadlocked and throw MaxPhpInstancesError.\n\t *\n\t * Default: 30000\n\t */\n\ttimeout?: number;\n\t/**\n\t * A factory function used for spawning new PHP instances.\n\t */\n\tphpFactory?: PHPFactory;\n}\n\nexport class MaxPhpInstancesError extends Error {\n\tconstructor(limit: number) {\n\t\tsuper(\n\t\t\t`Requested more concurrent PHP instances than the limit (${limit}).`\n\t\t);\n\t\tthis.name = this.constructor.name;\n\t}\n}\n\n/**\n * A PHP Process manager that maintains a pool of reusable PHP instances.\n *\n * Instances are spawned on demand up to `maxPhpInstances` and reused across\n * requests. The first instance spawned is the \"primary\" instance which\n * contains the reference filesystem used by all other instances.\n *\n * The semaphore controls how many requests can be processed concurrently.\n * When all instances are busy, new requests wait in a queue until an\n * instance becomes available or the timeout is reached.\n */\nexport class PHPProcessManager implements PHPInstanceManager {\n\t/** All PHP instances that have been spawned. */\n\tprivate instances: PHP[] = [];\n\n\t/** Instances that are currently idle and available for use. */\n\tprivate idleInstances: PHP[] = [];\n\n\t/** Maximum number of concurrent PHP instances allowed. */\n\tprivate maxPhpInstances: number;\n\n\t/** Factory function for creating new PHP instances. */\n\tprivate phpFactory?: PHPFactory;\n\n\t/** Controls concurrent access to PHP instances. */\n\tprivate semaphore: Semaphore;\n\n\t/** Prevents spawning duplicate primary instances during concurrent calls. */\n\tprivate primaryPhpPromise?: Promise<PHP>;\n\n\tconstructor(options?: ProcessManagerOptions) {\n\t\tthis.maxPhpInstances = options?.maxPhpInstances ?? 2;\n\t\tthis.phpFactory = options?.phpFactory;\n\t\tthis.semaphore = new Semaphore({\n\t\t\tconcurrency: this.maxPhpInstances,\n\t\t\ttimeout: options?.timeout || 30000,\n\t\t});\n\t}\n\n\t/**\n\t * Get the primary PHP instance (the first one spawned).\n\t * If no instance exists yet, one will be spawned and marked as idle.\n\t */\n\tasync getPrimaryPhp(): Promise<PHP> {\n\t\tif (this.instances.length > 0) {\n\t\t\treturn this.instances[0];\n\t\t}\n\n\t\tif (!this.primaryPhpPromise) {\n\t\t\tthis.primaryPhpPromise = this.spawnInstance(true);\n\t\t}\n\t\ttry {\n\t\t\treturn await this.primaryPhpPromise;\n\t\t} finally {\n\t\t\tthis.primaryPhpPromise = undefined;\n\t\t}\n\t}\n\n\t/**\n\t * Acquire a PHP instance for processing a request.\n\t *\n\t * Returns an idle instance from the pool, or spawns a new one if\n\t * the pool isn't at capacity. If all instances are busy, waits\n\t * until one becomes available.\n\t *\n\t * @throws {MaxPhpInstancesError} when the timeout is reached waiting\n\t * for an available instance.\n\t */\n\tasync acquirePHPInstance(): Promise<AcquiredPHP> {\n\t\tlet releaseSemaphore: () => void;\n\t\ttry {\n\t\t\treleaseSemaphore = await this.semaphore.acquire();\n\t\t} catch (error) {\n\t\t\tif (error instanceof AcquireTimeoutError) {\n\t\t\t\tthrow new MaxPhpInstancesError(this.maxPhpInstances);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\n\t\tconst php = await this.getOrSpawnInstance();\n\t\treturn {\n\t\t\tphp,\n\t\t\treap: () => {\n\t\t\t\tthis.idleInstances.push(php);\n\t\t\t\treleaseSemaphore();\n\t\t\t},\n\t\t};\n\t}\n\n\t/**\n\t * Get an idle instance or spawn a new one.\n\t */\n\tprivate async getOrSpawnInstance(): Promise<PHP> {\n\t\tif (this.instances.length === 0) {\n\t\t\tawait this.getPrimaryPhp();\n\t\t}\n\t\tif (this.idleInstances.length === 0) {\n\t\t\tawait this.spawnInstance(false);\n\t\t}\n\t\treturn this.idleInstances.pop()!;\n\t}\n\n\t/**\n\t * Spawn a new PHP instance.\n\t */\n\tprivate async spawnInstance(isPrimary: boolean): Promise<PHP> {\n\t\tif (!this.phpFactory) {\n\t\t\tthrow new Error(\n\t\t\t\t'phpFactory must be set before spawning instances.'\n\t\t\t);\n\t\t}\n\t\tconst php = await this.phpFactory({ isPrimary });\n\t\tthis.instances.push(php);\n\t\tthis.idleInstances.push(php);\n\t\treturn php;\n\t}\n\n\tasync [Symbol.asyncDispose]() {\n\t\tfor (const php of this.instances) {\n\t\t\tphp.exit();\n\t\t}\n\t\tthis.instances = [];\n\t\tthis.idleInstances = [];\n\t}\n}\n","export const SupportedPHPVersions = [\n\t'8.5',\n\t'8.4',\n\t'8.3',\n\t'8.2',\n\t'8.1',\n\t'8.0',\n\t'7.4',\n] as const;\nexport const LatestSupportedPHPVersion = SupportedPHPVersions[0];\nexport const SupportedPHPVersionsList = SupportedPHPVersions as any as string[];\nexport type SupportedPHPVersion = (typeof SupportedPHPVersions)[number];\n","/**\n * The default base used to convert a path into the URL object.\n */\nexport const DEFAULT_BASE_URL = 'http://example.com';\n\n/**\n * Returns a string representing the path, query, and\n * fragment of the given URL.\n *\n * @example\n * ```js\n * const url = new URL('http://example.com/foo/bar?baz=qux#quux');\n * toRelativeUrl(url); // '/foo/bar?baz=qux#quux'\n * ```\n *\n * @param url The URL.\n * @returns The path, query, and fragment.\n */\nexport function toRelativeUrl(url: URL): string {\n\t/**\n\t * The origin of an about:blank URL is a string \"null\". The URL is not\n\t * relative, but there's also nothing we can do to make it \"more relative\"\n\t * so let's just bale out and return the URL as is.\n\t *\n\t * @see https://html.spec.whatwg.org/multipage/browsers.html#concept-origin (Opaque origins)\n\t */\n\tif (url.origin === 'null') {\n\t\treturn url.toString();\n\t}\n\treturn url.toString().substring(url.origin.length);\n}\n\n/**\n * Removes the given prefix from the given path.\n *\n * @example\n * ```js\n * removePathPrefix('/foo/bar', '/foo'); // '/bar'\n * removePathPrefix('/bar', '/foo'); // '/bar'\n * ```\n *\n * @param path The path to remove the prefix from.\n * @param prefix The prefix to remove.\n * @returns Path with the prefix removed.\n */\nexport function removePathPrefix(path: string, prefix: string): string {\n\tif (!prefix || !path.startsWith(prefix)) {\n\t\treturn path;\n\t}\n\treturn path.substring(prefix.length);\n}\n\n/**\n * Ensures the given path has the given prefix.\n *\n * @example\n * ```js\n * ensurePathPrefix('/bar', '/foo'); // '/foo/bar'\n * ensurePathPrefix('/foo/bar', '/foo'); // '/foo/bar'\n * ```\n *\n * @param path\n * @param prefix\n * @returns Path with the prefix added.\n */\nexport function ensurePathPrefix(path: string, prefix: string): string {\n\tif (!prefix || path.startsWith(prefix)) {\n\t\treturn path;\n\t}\n\treturn prefix + path;\n}\n","/**\n * Encodes a multipart/form-data request body.\n *\n * @param data - The form data to encode.\n * @returns The encoded body and a correctly formatted content type header.\n */\nexport async function encodeAsMultipart(\n\tdata: Record<string, string | Uint8Array | File>\n) {\n\tconst boundary = `----${Math.random().toString(36).slice(2)}`;\n\tconst contentType = `multipart/form-data; boundary=${boundary}`;\n\n\tconst textEncoder = new TextEncoder();\n\tconst parts: (string | Uint8Array)[] = [];\n\tfor (const [name, value] of Object.entries(data)) {\n\t\tparts.push(`--${boundary}\\r\\n`);\n\t\tparts.push(`Content-Disposition: form-data; name=\"${name}\"`);\n\t\tif (value instanceof File) {\n\t\t\tparts.push(`; filename=\"${value.name}\"`);\n\t\t}\n\t\tparts.push(`\\r\\n`);\n\t\tif (value instanceof File) {\n\t\t\tparts.push(`Content-Type: application/octet-stream`);\n\t\t\tparts.push(`\\r\\n`);\n\t\t}\n\t\tparts.push(`\\r\\n`);\n\t\tif (value instanceof File) {\n\t\t\tparts.push(await fileToUint8Array(value));\n\t\t} else {\n\t\t\tparts.push(value);\n\t\t}\n\t\tparts.push(`\\r\\n`);\n\t}\n\tparts.push(`--${boundary}--\\r\\n`);\n\n\tconst length = parts.reduce((acc, part) => acc + part.length, 0);\n\tconst bytes = new Uint8Array(length);\n\tlet offset = 0;\n\tfor (const part of parts) {\n\t\tbytes.set(\n\t\t\ttypeof part === 'string' ? textEncoder.encode(part) : part,\n\t\t\toffset\n\t\t);\n\t\toffset += part.length;\n\t}\n\treturn { bytes, contentType };\n}\n\nfunction fileToUint8Array(file: File): Promise<Uint8Array> {\n\t/**\n\t * @mbuella: Use File.arrayBuffer() to get a Uint8Array from a file, avoiding FileReader\n\t * which is browser-specific. This method is supported in major browsers and NodeJS/Deno runtimes.\n\t */\n\treturn file.arrayBuffer().then((fileBuffer) => new Uint8Array(fileBuffer));\n}\n","import { dirname, joinPaths } from '@php-wasm/util';\nimport {\n\tensurePathPrefix,\n\ttoRelativeUrl,\n\tremovePathPrefix,\n\tDEFAULT_BASE_URL,\n} from './urls';\nimport type { PHP, PHPExecutionFailureError } from './php';\nimport { normalizeHeaders } from './php';\nimport { PHPResponse } from './php-response';\nimport type { PHPRequest, PHPRunOptions } from './universal-php';\nimport { encodeAsMultipart } from './encode-as-multipart';\nimport type { PHPFactoryOptions } from './php-process-manager';\nimport { MaxPhpInstancesError, PHPProcessManager } from './php-process-manager';\nimport type { PHPInstanceManager, AcquiredPHP } from './php-instance-manager';\nimport { SinglePHPInstanceManager } from './single-php-instance-manager';\nimport { HttpCookieStore } from './http-cookie-store';\nimport mimeTypes from './mime-types.json';\n\nexport type RewriteRule = {\n\tmatch: RegExp;\n\treplacement: string;\n};\n\nexport type FileNotFoundToResponse = {\n\ttype: 'response';\n\tresponse: PHPResponse;\n};\nexport type FileNotFoundToInternalRedirect = {\n\ttype: 'internal-redirect';\n\turi: string;\n};\nexport type FileNotFoundTo404 = { type: '404' };\n\nexport type FileNotFoundAction =\n\t| FileNotFoundToResponse\n\t| FileNotFoundToInternalRedirect\n\t| FileNotFoundTo404;\n\nexport type FileNotFoundGetActionCallback = (\n\trelativePath: string\n) => FileNotFoundAction;\n\n/**\n * Interface for cookie storage implementations.\n * This allows different cookie handling strategies to be used with the PHP request handler.\n */\nexport interface CookieStore {\n\t/**\n\t * Processes and stores cookies from response headers\n\t * @param headers Response headers containing Set-Cookie directives\n\t */\n\trememberCookiesFromResponseHeaders(headers: Record<string, string[]>): void;\n\n\t/**\n\t * Gets the cookie header string for the next request\n\t * @returns Formatted cookie header string\n\t */\n\tgetCookieRequestHeader(): string;\n}\n\n/**\n * Maps a URL path prefix to an absolute filesystem path.\n * Similar to Nginx's `alias` directive or Apache's `Alias` directive.\n *\n * @example\n * ```ts\n * // Requests to /phpmyadmin/* will be served from /tools/phpmyadmin/*\n * { urlPrefix: '/phpmyadmin', fsPath: '/tools/phpmyadmin' }\n * ```\n */\nexport type PathAlias = {\n\t/**\n\t * The URL path prefix to match (e.g., '/phpmyadmin').\n\t */\n\turlPrefix: string;\n\n\t/**\n\t * The absolute filesystem path to serve files from.\n\t */\n\tfsPath: string;\n};\n\ninterface BaseConfiguration {\n\t/**\n\t * The directory in the PHP filesystem where the server will look\n\t * for the files to serve. Default: `/var/www`.\n\t */\n\tdocumentRoot?: string;\n\t/**\n\t * Request Handler URL. Used to populate $_SERVER details like HTTP_HOST.\n\t */\n\tabsoluteUrl?: string;\n\n\t/**\n\t * Rewrite rules\n\t */\n\trewriteRules?: RewriteRule[];\n\n\t/**\n\t * Path aliases that map URL prefixes to filesystem paths outside\n\t * the document root. Similar to Nginx's `alias` directive.\n\t *\n\t * @example\n\t * ```ts\n\t * pathAliases: [\n\t * { urlPrefix: '/phpmyadmin', fsPath: '/tools/phpmyadmin' }\n\t * ]\n\t * ```\n\t */\n\tpathAliases?: PathAlias[];\n\n\t/**\n\t * A callback that decides how to handle a file-not-found condition for a\n\t * given request URI.\n\t */\n\tgetFileNotFoundAction?: FileNotFoundGetActionCallback;\n}\n\nexport type PHPRequestHandlerFactoryArgs = PHPFactoryOptions & {\n\trequestHandler: PHPRequestHandler;\n};\n\nexport type PHPRequestHandlerConfiguration = BaseConfiguration & {\n\tcookieStore?: CookieStore | false;\n\n\t// One of the following must be provided:\n\n\t/**\n\t * Provide a single PHP instance directly.\n\t * PHPRequestHandler will create a SinglePHPInstanceManager internally.\n\t * This is the simplest option for CLI contexts with a single PHP instance.\n\t */\n\tphp?: PHP;\n\n\t/**\n\t * Provide a factory function to create PHP instances.\n\t * PHPRequestHandler will create a PHPProcessManager internally.\n\t */\n\tphpFactory?: (requestHandler: PHPRequestHandlerFactoryArgs) => Promise<PHP>;\n\n\t/**\n\t * The maximum number of PHP instances that can exist at\n\t * the same time. Only used when phpFactory is provided.\n\t */\n\tmaxPhpInstances?: number;\n};\n\n/**\n * Handles HTTP requests using PHP runtime as a backend.\n *\n * @public\n * @example Use PHPRequestHandler implicitly with a new PHP instance:\n * ```js\n * import { PHP } from '@php-wasm/web';\n *\n * const php = await PHP.load( '7.4', {\n * requestHandler: {\n * // PHP FS path to serve the files from:\n * documentRoot: '/www',\n *\n * // Used to populate $_SERVER['SERVER_NAME'] etc.:\n * absoluteUrl: 'http://127.0.0.1'\n * }\n * } );\n *\n * php.mkdirTree('/www');\n * php.writeFile('/www/index.php', '<?php echo \"Hi from PHP!\"; ');\n *\n * const response = await php.request({ path: '/index.php' });\n * console.log(response.text);\n * // \"Hi from PHP!\"\n * ```\n *\n * @example Explicitly create a PHPRequestHandler instance and run a PHP script:\n * ```js\n * import {\n * loadPHPRuntime,\n * PHP,\n * PHPRequestHandler,\n * getPHPLoaderModule,\n * } from '@php-wasm/web';\n *\n * const runtime = await loadPHPRuntime( await getPHPLoaderModule('7.4') );\n * const php = new PHP( runtime );\n *\n * php.mkdirTree('/www');\n * php.writeFile('/www/index.php', '<?php echo \"Hi from PHP!\"; ');\n *\n * const server = new PHPRequestHandler(php, {\n * // PHP FS path to serve the files from:\n * documentRoot: '/www',\n *\n * // Used to populate $_SERVER['SERVER_NAME'] etc.:\n * absoluteUrl: 'http://127.0.0.1'\n * });\n *\n * const response = server.request({ path: '/index.php' });\n * console.log(response.text);\n * // \"Hi from PHP!\"\n * ```\n */\nexport class PHPRequestHandler implements AsyncDisposable {\n\t#DOCROOT: string;\n\t#PROTOCOL: string;\n\t#HOSTNAME: string;\n\t#PORT: number;\n\t#HOST: string;\n\t#PATHNAME: string;\n\t#ABSOLUTE_URL: string;\n\t#cookieStore: CookieStore | false;\n\t#pathAliases: PathAlias[];\n\trewriteRules: RewriteRule[];\n\t/**\n\t * The instance manager used for PHP instance lifecycle.\n\t * This is either a provided instanceManager or a PHPProcessManager\n\t * created from the phpFactory.\n\t */\n\tinstanceManager: PHPInstanceManager;\n\tgetFileNotFoundAction: FileNotFoundGetActionCallback;\n\n\t/**\n\t * The request handler needs to decide whether to serve a static asset or\n\t * run the PHP interpreter. For static assets it should just reuse the primary\n\t * PHP even if there's 50 concurrent requests to serve. However, for\n\t * dynamic PHP requests, it needs to grab an available interpreter.\n\t * Therefore, it cannot just accept PHP as an argument as serving requests\n\t * requires access to ProcessManager.\n\t *\n\t * @param php - The PHP instance.\n\t * @param config - Request Handler configuration.\n\t */\n\tconstructor(config: PHPRequestHandlerConfiguration) {\n\t\tconst {\n\t\t\tdocumentRoot = '/www/',\n\t\t\tabsoluteUrl = typeof location === 'object'\n\t\t\t\t? location.href\n\t\t\t\t: DEFAULT_BASE_URL,\n\t\t\trewriteRules = [],\n\t\t\tpathAliases = [],\n\t\t\tgetFileNotFoundAction = () => ({ type: '404' }),\n\t\t} = config;\n\n\t\tconst setChroot = (php: PHP) => {\n\t\t\t// Always set managed PHP's cwd to the document root.\n\t\t\tif (!php.isDir(documentRoot)) {\n\t\t\t\tphp.mkdir(documentRoot);\n\t\t\t}\n\t\t\tphp.chdir(documentRoot);\n\n\t\t\t// @TODO: Decouple PHP and request handler\n\t\t\t(php as any).requestHandler = this;\n\t\t};\n\n\t\tif (config.php) {\n\t\t\tsetChroot(config.php);\n\t\t\tthis.instanceManager = new SinglePHPInstanceManager({\n\t\t\t\tphp: config.php,\n\t\t\t});\n\t\t} else if (config.phpFactory) {\n\t\t\tthis.instanceManager = new PHPProcessManager({\n\t\t\t\tphpFactory: async (info) => {\n\t\t\t\t\tconst php = await config.phpFactory!({\n\t\t\t\t\t\t...info,\n\t\t\t\t\t\trequestHandler: this,\n\t\t\t\t\t});\n\t\t\t\t\tsetChroot(php);\n\t\t\t\t\treturn php;\n\t\t\t\t},\n\t\t\t\tmaxPhpInstances: config.maxPhpInstances,\n\t\t\t});\n\t\t} else {\n\t\t\tthrow new Error(\n\t\t\t\t'Either php or phpFactory must be provided in the configuration.'\n\t\t\t);\n\t\t}\n\n\t\t/**\n\t\t * By default, config.cookieStore is undefined, so we use the\n\t\t * HttpCookieStore implementation, otherwise we use the one\n\t\t * provided in the config.\n\t\t *\n\t\t * By explicitly checking for `undefined` we allow the user to pass\n\t\t * `null` as config.cookieStore and disable the cookie store.\n\t\t */\n\t\tthis.#cookieStore =\n\t\t\tconfig.cookieStore === undefined\n\t\t\t\t? new HttpCookieStore()\n\t\t\t\t: config.cookieStore;\n\t\tthis.#DOCROOT = documentRoot;\n\n\t\tconst url = new URL(absoluteUrl);\n\t\tthis.#HOSTNAME = url.hostname;\n\t\tthis.#PORT = url.port\n\t\t\t? Number(url.port)\n\t\t\t: url.protocol === 'https:'\n\t\t\t\t? 443\n\t\t\t\t: 80;\n\t\tthis.#PROTOCOL = (url.protocol || '').replace(':', '');\n\t\tconst isNonStandardPort = this.#PORT !== 443 && this.#PORT !== 80;\n\t\tthis.#HOST = [\n\t\t\tthis.#HOSTNAME,\n\t\t\tisNonStandardPort ? `:${this.#PORT}` : '',\n\t\t].join('');\n\t\tthis.#PATHNAME = url.pathname.replace(/\\/+$/, '');\n\t\tthis.#ABSOLUTE_URL = [\n\t\t\t`${this.#PROTOCOL}://`,\n\t\t\tthis.#HOST,\n\t\t\tthis.#PATHNAME,\n\t\t].join('');\n\t\tthis.rewriteRules = rewriteRules;\n\t\tthis.#pathAliases = pathAliases;\n\t\tthis.getFileNotFoundAction = getFileNotFoundAction;\n\t}\n\n\tasync getPrimaryPhp() {\n\t\treturn await this.instanceManager.getPrimaryPhp();\n\t}\n\n\t/**\n\t * Converts a path to an absolute URL based at the PHPRequestHandler\n\t * root.\n\t *\n\t * @param path The server path to convert to an absolute URL.\n\t * @returns The absolute URL.\n\t */\n\tpathToInternalUrl(path: string): string {\n\t\tif (!path.startsWith('/')) {\n\t\t\tpath = `/${path}`;\n\t\t}\n\t\treturn `${this.absoluteUrl}${path}`;\n\t}\n\n\t/**\n\t * Converts an absolute URL based at the PHPRequestHandler to a relative path\n\t * without the server pathname and scope.\n\t *\n\t * @param internalUrl An absolute URL based at the PHPRequestHandler root.\n\t * @returns The relative path.\n\t */\n\tinternalUrlToPath(internalUrl: string): string {\n\t\tconst url = new URL(internalUrl, 'https://playground.internal');\n\t\tif (url.pathname.startsWith(this.#PATHNAME)) {\n\t\t\turl.pathname = url.pathname.slice(this.#PATHNAME.length);\n\t\t}\n\t\treturn toRelativeUrl(url);\n\t}\n\n\t/**\n\t * The absolute URL of this PHPRequestHandler instance.\n\t */\n\tget absoluteUrl() {\n\t\treturn this.#ABSOLUTE_URL;\n\t}\n\n\t/**\n\t * The directory in the PHP filesystem where the server will look\n\t * for the files to serve. Default: `/var/www`.\n\t */\n\tget documentRoot() {\n\t\treturn this.#DOCROOT;\n\t}\n\n\t/**\n\t * Serves the request – either by serving a static file, or by\n\t * dispatching it to the PHP runtime.\n\t *\n\t * The request() method mode behaves like a web server and only works if\n\t * the PHP was initialized with a `requestHandler` option (which the online\n\t * version of WordPress Playground does by default).\n\t *\n\t * In the request mode, you pass an object containing the request information\n\t * (method, headers, body, etc.) and the path to the PHP file to run:\n\t *\n\t * ```ts\n\t * const php = PHP.load('7.4', {\n\t * \trequestHandler: {\n\t * \t\tdocumentRoot: \"/www\"\n\t * \t}\n\t * })\n\t * php.writeFile(\"/www/index.php\", `<?php echo file_get_contents(\"php://input\");`);\n\t * const result = await php.request({\n\t * \tmethod: \"GET\",\n\t * \theaders: {\n\t * \t\t\"Content-Type\": \"text/plain\"\n\t * \t},\n\t * \tbody: \"Hello world!\",\n\t * \tpath: \"/www/index.php\"\n\t * });\n\t * // result.text === \"Hello world!\"\n\t * ```\n\t *\n\t * The `request()` method cannot be used in conjunction with `cli()`.\n\t *\n\t * @example\n\t * ```js\n\t * const output = await php.request({\n\t * \tmethod: 'GET',\n\t * \turl: '/index.php',\n\t * \theaders: {\n\t * \t\t'X-foo': 'bar',\n\t * \t},\n\t * \tbody: {\n\t * \t\tfoo: 'bar',\n\t * \t},\n\t * });\n\t * console.log(output.stdout); // \"Hello world!\"\n\t * ```\n\t *\n\t * @param request - PHP Request data.\n\t */\n\tasync request(request: PHPRequest): Promise<PHPResponse> {\n\t\tconst isAbsolute = looksLikeAbsoluteUrl(request.url);\n\t\tconst originalRequestUrl = new URL(\n\t\t\t// Remove the hash part of the URL as it's not meant for the server.\n\t\t\trequest.url.split('#')[0],\n\t\t\tisAbsolute ? undefined : DEFAULT_BASE_URL\n\t\t);\n\n\t\tconst rewrittenRequestUrl = this.#applyRewriteRules(originalRequestUrl);\n\t\tconst primaryPhp = await this.getPrimaryPhp();\n\t\t/**\n\t\t * Turn a URL such as `https://playground/scope:my-site/wp-admin/index.php`\n\t\t * into a site-relative path, such as `/wp-admin/index.php`.\n\t\t */\n\t\tconst siteRelativePath = removePathPrefix(\n\t\t\t/**\n\t\t\t * URL.pathname returns a URL-encoded path. We need to decode it\n\t\t\t * before using it as a filesystem path.\n\t\t\t */\n\t\t\tdecodeURIComponent(rewrittenRequestUrl.pathname),\n\t\t\tthis.#PATHNAME\n\t\t);\n\t\tlet fsPath = this.#resolveToFsPath(siteRelativePath);\n\t\tif (primaryPhp.isDir(fsPath)) {\n\t\t\t// Ensure directory URIs have a trailing slash. Otherwise,\n\t\t\t// relative URIs in index.php or index.html files are relative\n\t\t\t// to the next directory up.\n\t\t\t//\n\t\t\t// Example:\n\t\t\t// For an index page served for URI \"/settings\", we naturally expect\n\t\t\t// links to be relative to \"/settings\", but without the trailing\n\t\t\t// slash, a relative link \"edit.php\" resolves to \"/edit.php\"\n\t\t\t// rather than \"/settings/edit.php\".\n\t\t\t//\n\t\t\t// This treatment of relative links is correct behavior for the browser:\n\t\t\t// https://www.rfc-editor.org/rfc/rfc3986#section-5.2.3\n\t\t\t//\n\t\t\t// But user intent for `/settings/index.php` is that its relative\n\t\t\t// URIs are relative to `/settings/`. So we redirect to add a\n\t\t\t// trailing slash to directory URIs to meet this expecatation.\n\t\t\t//\n\t\t\t// This behavior is also necessary for WordPress to function properly.\n\t\t\t// Otherwise, when viewing the WP admin dashboard at `/wp-admin`,\n\t\t\t// links to other admin pages like `edit.php` will incorrectly\n\t\t\t// resolve to `/edit.php` rather than `/wp-admin/edit.php`.\n\t\t\tif (!siteRelativePath.endsWith('/')) {\n\t\t\t\treturn new PHPResponse(\n\t\t\t\t\t301,\n\t\t\t\t\t{ Location: [`${rewrittenRequestUrl.pathname}/`] },\n\t\t\t\t\tnew Uint8Array(0)\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// We can only satisfy requests for directories with a default file\n\t\t\t// so let's first resolve to a default path when available.\n\t\t\tfor (const possibleIndexFile of ['index.php', 'index.html']) {\n\t\t\t\tconst possibleIndexPath = joinPaths(fsPath, possibleIndexFile);\n\t\t\t\tif (primaryPhp.isFile(possibleIndexPath)) {\n\t\t\t\t\tfsPath = possibleIndexPath;\n\n\t\t\t\t\t// Include the resolved index file in the final rewritten request URL.\n\t\t\t\t\trewrittenRequestUrl.pathname = joinPaths(\n\t\t\t\t\t\trewrittenRequestUrl.pathname,\n\t\t\t\t\t\tpossibleIndexFile\n\t\t\t\t\t);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (!primaryPhp.isFile(fsPath)) {\n\t\t\t/**\n\t\t\t * Try resolving a partial path.\n\t\t\t *\n\t\t\t * Example:\n\t\t\t *\n\t\t\t * – Request URL: /file.php/index.php\n\t\t\t * – Document Root: /var/www\n\t\t\t *\n\t\t\t * If /var/www/file.php/index.php does not exist, but /var/www/file.php does,\n\t\t\t * use /var/www/file.php. This is also what Apache and PHP Dev Server do.\n\t\t\t */\n\t\t\tlet pathToTry = siteRelativePath;\n\t\t\twhile (\n\t\t\t\tpathToTry.startsWith('/') &&\n\t\t\t\tpathToTry !== dirname(pathToTry)\n\t\t\t) {\n\t\t\t\tpathToTry = dirname(pathToTry);\n\t\t\t\tconst resolvedPathToTry = this.#resolveToFsPath(pathToTry);\n\t\t\t\tif (\n\t\t\t\t\tprimaryPhp.isFile(resolvedPathToTry) &&\n\t\t\t\t\t// Only run partial path resolution for PHP files.\n\t\t\t\t\tresolvedPathToTry.endsWith('.php')\n\t\t\t\t) {\n\t\t\t\t\tfsPath = this.#resolveToFsPath(pathToTry);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (!primaryPhp.isFile(fsPath)) {\n\t\t\tconst fileNotFoundAction = this.getFileNotFoundAction(\n\t\t\t\trewrittenRequestUrl.pathname\n\t\t\t);\n\t\t\tswitch (fileNotFoundAction.type) {\n\t\t\t\tcase 'response':\n\t\t\t\t\treturn fileNotFoundAction.response;\n\t\t\t\tcase 'internal-redirect':\n\t\t\t\t\tfsPath = joinPaths(this.#DOCROOT, fileNotFoundAction.uri);\n\t\t\t\t\tbreak;\n\t\t\t\tcase '404':\n\t\t\t\t\treturn PHPResponse.forHttpCode(404);\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t'Unsupported file-not-found action type: ' +\n\t\t\t\t\t\t\t// Cast because TS asserts the remaining possibility is `never`\n\t\t\t\t\t\t\t`'${\n\t\t\t\t\t\t\t\t(fileNotFoundAction as FileNotFoundAction).type\n\t\t\t\t\t\t\t}'`\n\t\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// We need to confirm that the current target file exists because\n\t\t// file-not-found fallback actions may redirect to non-existent files.\n\t\tif (primaryPhp.isFile(fsPath)) {\n\t\t\tif (fsPath.endsWith('.php')) {\n\t\t\t\tconst response = await this.#spawnPHPAndDispatchRequest(\n\t\t\t\t\trequest,\n\t\t\t\t\toriginalRequestUrl,\n\t\t\t\t\trewrittenRequestUrl,\n\t\t\t\t\tfsPath\n\t\t\t\t);\n\n\t\t\t\t/**\n\t\t\t\t * If the response is but the exit code is non-zero, let's rewrite the\n\t\t\t\t * HTTP status code as 500. We're acting as a HTTP server here and\n\t\t\t\t * this behavior is in line with what Nginx and Apache do.\n\t\t\t\t */\n\t\t\t\tif (response.ok() && response.exitCode !== 0) {\n\t\t\t\t\treturn new PHPResponse(\n\t\t\t\t\t\t500,\n\t\t\t\t\t\tresponse.headers,\n\t\t\t\t\t\tresponse.bytes,\n\t\t\t\t\t\tresponse.errors,\n\t\t\t\t\t\tresponse.exitCode\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn response;\n\t\t\t} else {\n\t\t\t\treturn this.#serveStaticFile(primaryPhp, fsPath);\n\t\t\t}\n\t\t} else {\n\t\t\treturn PHPResponse.forHttpCode(404);\n\t\t}\n\t}\n\n\t/**\n\t * Apply the rewrite rules to the original request URL.\n\t *\n\t * @param originalRequestUrl - The original request URL.\n\t * @returns The rewritten request URL.\n\t */\n\t#applyRewriteRules(originalRequestUrl: URL): URL {\n\t\tconst siteRelativePath = removePathPrefix(\n\t\t\tdecodeURIComponent(originalRequestUrl.pathname),\n\t\t\tthis.#PATHNAME\n\t\t);\n\t\tconst rewrittenRequestPath = applyRewriteRules(\n\t\t\tsiteRelativePath,\n\t\t\tthis.rewriteRules\n\t\t);\n\t\tconst rewrittenRequestUrl = new URL(\n\t\t\tjoinPaths(this.#PATHNAME, rewrittenRequestPath),\n\t\t\toriginalRequestUrl.toString()\n\t\t);\n\t\t// Merge the query string parameters from the original request URL.\n\t\tfor (const [key, value] of originalRequestUrl.searchParams.entries()) {\n\t\t\trewrittenRequestUrl.searchParams.append(key, value);\n\t\t}\n\t\treturn rewrittenRequestUrl;\n\t}\n\n\t/**\n\t * Resolves a URL path to a filesystem path, checking path aliases first.\n\t *\n\t * If the URL path matches a configured alias prefix, the alias's\n\t * filesystem path is used instead of the document root.\n\t *\n\t * @param urlPath - The URL path to resolve (e.g., '/phpmyadmin/index.php')\n\t * @returns The resolved filesystem path\n\t */\n\t#resolveToFsPath(urlPath: string): string {\n\t\t// Check if the URL path matches any alias\n\t\tfor (const alias of this.#pathAliases) {\n\t\t\tif (\n\t\t\t\turlPath === alias.urlPrefix ||\n\t\t\t\turlPath.startsWith(alias.urlPrefix + '/')\n\t\t\t) {\n\t\t\t\t// Replace the URL prefix with the filesystem path\n\t\t\t\tconst relativePath = urlPath.slice(alias.urlPrefix.length);\n\t\t\t\treturn joinPaths(alias.fsPath, relativePath);\n\t\t\t}\n\t\t}\n\t\t// No alias matched, use the document root\n\t\treturn joinPaths(this.#DOCROOT, urlPath);\n\t}\n\n\t/**\n\t * Serves a static file from the PHP filesystem.\n\t *\n\t * @param fsPath - Absolute path of the static file to serve.\n\t * @returns The response.\n\t */\n\t#serveStaticFile(php: PHP, fsPath: string): PHPResponse {\n\t\tconst arrayBuffer = php.readFileAsBuffer(fsPath);\n\t\treturn new PHPResponse(\n\t\t\t200,\n\t\t\t{\n\t\t\t\t'content-length': [`${arrayBuffer.byteLength}`],\n\t\t\t\t// @TODO: Infer the content-type from the arrayBuffer instead of the\n\t\t\t\t// file path. The code below won't return the correct mime-type if the\n\t\t\t\t// extension was tampered with.\n\t\t\t\t'content-type': [inferMimeType(fsPath)],\n\t\t\t\t'accept-ranges': ['bytes'],\n\t\t\t\t'cache-control': ['public, max-age=0'],\n\t\t\t},\n\t\t\tarrayBuffer\n\t\t);\n\t}\n\n\t/**\n\t * Spawns a new PHP instance and dispatches a request to it.\n\t */\n\tasync #spawnPHPAndDispatchRequest(\n\t\trequest: PHPRequest,\n\t\toriginalRequestUrl: URL,\n\t\trewrittenRequestUrl: URL,\n\t\tscriptPath: string\n\t): Promise<PHPResponse> {\n\t\tlet spawnedPHP: AcquiredPHP | undefined = undefined;\n\t\ttry {\n\t\t\tspawnedPHP = await this.instanceManager!.acquirePHPInstance();\n\t\t} catch (e) {\n\t\t\tif (e instanceof MaxPhpInstancesError) {\n\t\t\t\treturn PHPResponse.forHttpCode(502);\n\t\t\t} else {\n\t\t\t\treturn PHPResponse.forHttpCode(500);\n\t\t\t}\n\t\t}\n\t\ttry {\n\t\t\treturn await this.#dispatchToPHP(\n\t\t\t\tspawnedPHP.php,\n\t\t\t\trequest,\n\t\t\t\toriginalRequestUrl,\n\t\t\t\trewrittenRequestUrl,\n\t\t\t\tscriptPath\n\t\t\t);\n\t\t} finally {\n\t\t\tspawnedPHP.reap();\n\t\t}\n\t}\n\n\t/**\n\t * Runs the requested PHP file with all the request and $_SERVER\n\t * superglobals populated.\n\t *\n\t * @param request - The request.\n\t * @returns The response.\n\t */\n\tasync #dispatchToPHP(\n\t\tphp: PHP,\n\t\trequest: PHPRequest,\n\t\toriginalRequestUrl: URL,\n\t\trewrittenRequestUrl: URL,\n\t\tscriptPath: string\n\t): Promise<PHPResponse> {\n\t\tlet preferredMethod: PHPRunOptions['method'] = 'GET';\n\n\t\tconst headers: Record<string, string> = {\n\t\t\thost: this.#HOST,\n\t\t\t...normalizeHeaders(request.headers || {}),\n\t\t};\n\t\tif (this.#cookieStore) {\n\t\t\theaders['cookie'] = this.#cookieStore.getCookieRequestHeader();\n\t\t}\n\n\t\tlet body = request.body;\n\t\tif (typeof body === 'object' && !(body instanceof Uint8Array)) {\n\t\t\tpreferredMethod = 'POST';\n\t\t\tconst { bytes, contentType } = await encodeAsMultipart(body);\n\t\t\tbody = bytes;\n\t\t\theaders['content-type'] = contentType;\n\t\t}\n\n\t\ttry {\n\t\t\tconst response = await php.run({\n\t\t\t\trelativeUri: ensurePathPrefix(\n\t\t\t\t\ttoRelativeUrl(new URL(rewrittenRequestUrl.toString())),\n\t\t\t\t\tthis.#PATHNAME\n\t\t\t\t),\n\t\t\t\tprotocol: this.#PROTOCOL,\n\t\t\t\tmethod: request.method || preferredMethod,\n\t\t\t\t$_SERVER: this.prepare_$_SERVER_superglobal(\n\t\t\t\t\toriginalRequestUrl,\n\t\t\t\t\trewrittenRequestUrl,\n\t\t\t\t\tscriptPath\n\t\t\t\t),\n\t\t\t\tbody,\n\t\t\t\tscriptPath,\n\t\t\t\theaders,\n\t\t\t});\n\t\t\tif (this.#cookieStore) {\n\t\t\t\tthis.#cookieStore.rememberCookiesFromResponseHeaders(\n\t\t\t\t\tresponse.headers\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn response;\n\t\t} catch (error) {\n\t\t\tconst executionError = error as PHPExecutionFailureError;\n\t\t\tif (executionError?.response) {\n\t\t\t\treturn executionError.response;\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t/**\n\t * Computes the essential $_SERVER entries for a request.\n\t *\n\t * php_wasm.c sets some defaults, assuming it runs as a CLI script.\n\t * This function overrides them with the values correct in the request\n\t * context.\n\t *\n\t * @TODO: Consolidate the $_SERVER setting logic into a single place instead\n\t * of splitting it between the C SAPI and the TypeScript code. The PHP\n\t * class has a `.cli()` method that could take care of the CLI-specific\n\t * $_SERVER values.\n\t *\n\t * Path and URL-related $_SERVER entries are theoretically documented\n\t * at https://www.php.net/manual/en/reserved.variables.server.php,\n\t * but that page is not very helpful in practice. Here are tables derived\n\t * by interacting with PHP servers:\n\t *\n\t * ## PHP Dev Server\n\t *\n\t * Setup:\n\t * – `/home/adam/subdir/script.php` file contains `<?php phpinfo(); ?>`\n\t * – `php -S 127.0.0.1:8041` running in `/home/adam` directory\n\t * – A request is sent to `http://127.0.0.1:8041/subdir/script.php/b.php/c.php`\n\t *\n\t * Results:\n\t *\n\t * $_SERVER['REQUEST_URI'] | `/subdir/script.php/b.php/c.php`\n\t * $_SERVER['SCRIPT_NAME'] | `/subdir/script.php`\n\t * $_SERVER['SCRIPT_FILENAME']| `/home/adam/subdir/script.php`\n\t * $_SERVER['PATH_INFO'] | `/b.php/c.php`\n\t * $_SERVER['PHP_SELF'] | `/subdir/script.php/b.php/c.php`\n\t *\n\t * ## Apache – rewriting rules\n\t *\n\t * Setup:\n\t * – `/var/www/html/subdir/script.php` file contains `<?php phpinfo(); ?>`\n\t * – Apache is listening on port 8041\n\t * – The document root is `/var/www/html`\n\t * – A request is sent to `http://127.0.0.1:8041/api/v1/user/123`\n\t *\n\t * .htaccess file:\n\t *\n\t * ```apache\n\t * RewriteEngine On\n\t * RewriteRule ^api/v1/user/([0-9]+)$ /subdir/script.php?endpoint=user&id=$1 [L,QSA]\n\t * ```\n\t *\n\t * Results:\n\t *\n\t * ```\n\t * $_SERVER['REQUEST_URI'] | /api/v1/user/123\n\t * $_SERVER['SCRIPT_NAME'] | /subdir/script.php\n\t * $_SERVER['SCRIPT_FILENAME'] | /var/www/html/subdir/script.php\n\t * $_SERVER['PATH_INFO'] | (key not set)\n\t * $_SERVER['PHP_SELF'] | /subdir/script.php\n\t * $_SERVER['QUERY_STRING'] | endpoint=user&id=123\n\t * $_SERVER['REDIRECT_STATUS'] | 200\n\t * $_SERVER['REDIRECT_URL'] | /api/v1/user/123\n\t * $_SERVER['REDIRECT_QUERY_STRING'] | endpoint=user&id=123\n\t * === $_GET Variables ===\n\t * $_GET['endpoint'] | user\n\t * $_GET['id'] | 123\n\t * ```\n\t *\n\t * ## Apache – vanilla request\n\t *\n\t * Setup:\n\t * – The same as above.\n\t * – A request sent http://localhost:8041/subdir/script.php?param=value\n\t *\n\t * Results:\n\t *\n\t * ```\n\t * $_SERVER['REQUEST_URI'] | /subdir/script.php?param=value\n\t * $_SERVER['SCRIPT_NAME'] | /subdir/script.php\n\t * $_SERVER['SCRIPT_FILENAME'] | /var/www/html/subdir/script.php\n\t * $_SERVER['PATH_INFO'] | (key not set)\n\t * $_SERVER['PHP_SELF'] | /subdir/script.php\n\t * $_SERVER['REDIRECT_URL'] | (key not set)\n\t * $_SERVER['REDIRECT_STATUS'] | (key not set)\n\t * $_SERVER['QUERY_STRING'] | param=value\n\t * $_SERVER['REQUEST_METHOD'] | GET\n\t * $_SERVER['DOCUMENT_ROOT'] | /var/www/html\n\t *\n\t * === $_GET Variables ===\n\t * $_GET['param'] | value\n\t * ```\n\t */\n\tprivate prepare_$_SERVER_superglobal(\n\t\toriginalRequestUrl: URL,\n\t\trewrittenRequestUrl: URL,\n\t\tresolvedScriptPath: string\n\t): Record<string, string> {\n\t\tconst $_SERVER: Record<string, string> = {\n\t\t\tREMOTE_ADDR: '127.0.0.1',\n\t\t\tDOCUMENT_ROOT: this.#DOCROOT,\n\t\t\tHTTPS: this.#ABSOLUTE_URL.startsWith('https://') ? 'on' : '',\n\t\t};\n\n\t\t/**\n\t\t * REQUEST_URI\n\t\t *\n\t\t * The original path + query string extracted from the requested URL\n\t\t * **before** applying any URL rewriting.\n\t\t */\n\t\t$_SERVER['REQUEST_URI'] =\n\t\t\toriginalRequestUrl.pathname + originalRequestUrl.search;\n\n\t\tif (resolvedScriptPath.startsWith(this.#DOCROOT)) {\n\t\t\t/**\n\t\t\t * SCRIPT_NAME\n\t\t\t *\n\t\t\t * > Contains the current script's path. This is useful for pages\n\t\t\t * > which need to point to themselves.\n\t\t\t *\n\t\t\t * Filesystem path of the script relative to the document root.\n\t\t\t * Note this is a filesystem path so URL rewriting is not applicable here.\n\t\t\t */\n\t\t\t$_SERVER['SCRIPT_NAME'] = resolvedScriptPath.substring(\n\t\t\t\tthis.#DOCROOT.length\n\t\t\t);\n\n\t\t\t/**\n\t\t\t * PHP_SELF – the path sourced from the final **request URL** after the\n\t\t\t * rewrite rules have been applied.\n\t\t\t *\n\t\t\t * php.net documentation is very misleading on this one:\n\t\t\t *\n\t\t\t * > The filename of the currently executing script, relative\n\t\t\t * > to the document root. For instance, $_SERVER['PHP_SELF']\n\t\t\t * > in a script at the address http://example.com/foo/bar.php\n\t\t\t * > would be /foo/bar.php.\n\t\t\t *\n\t\t\t * @see https://www.php.net/manual/en/reserved.variables.server.php#:~:text=PHP_SELF\n\t\t\t *\n\t\t\t * This is not what Apache, nor what the PHP dev server do:\n\t\t\t *\n\t\t\t * – Document Root: /var/www\n\t\t\t * – Script file: /var/www/subdir/script.php\n\t\t\t * – Requesting /subdir/script.php/b.php/c.php\n\t\t\t *\n\t\t\t * $_SERVER['PHP_SELF'] = \"/subdir/script.php/b.php/c.php\"\n\t\t\t *\n\t\t\t * So, in that regard, it is a URL path, not a filesystem path.\n\t\t\t *\n\t\t\t * When URL rewriting is involved, it's the same.\n\t\t\t *\n\t\t\t * Consider this Apache example from above:\n\t\t\t *\n\t\t\t * – Document Root: /var/www/html\n\t\t\t * – Script file: /var/www/html/subdir/script.php\n\t\t\t * – Rewrite rule: ^api/v1/user/([0-9]+)$ /subdir/script.php?endpoint=user&id=$1 [L,QSA]\n\t\t\t * – Requesting /api/v1/user/123\n\t\t\t *\n\t\t\t * $_SERVER['PHP_SELF'] = \"/subdir/script.php\"\n\t\t\t *\n\t\t\t * So, on the face value, this is a filesystem path. However, see\n\t\t\t * what happens if we slightly modify that rewrite rule to:\n\t\t\t *\n\t\t\t * – Rewrite rule: ^api/v1/user/([0-9]+)$ /subdir/script.php/next.php\n\t\t\t * ^^^^^^^^^\n\t\t\t * – Requesting /api/v1/user/123\n\t\t\t *\n\t\t\t * $_SERVER['PHP_SELF'] = \"/subdir/script.php/next.php\"\n\t\t\t *\n\t\t\t * So:\n\t\t\t * * PHP_SELF is not sourced from the filesystem path.\n\t\t\t * * PHP_SELF is sourced from the final request URL after the\n\t\t\t * rewrite rules have been applied.\n\t\t\t */\n\t\t\t$_SERVER['PHP_SELF'] = rewrittenRequestUrl.pathname;\n\n\t\t\t/**\n\t\t\t * PATH_INFO\n\t\t\t *\n\t\t\t * > Contains any client-provided pathname information trailing the actual\n\t\t\t * > script filename but preceding the query string, if available. For instance,\n\t\t\t * > if the current script was accessed via the URI http://www.example.com/php/path_info.php/some/stuff?foo=bar,\n\t\t\t * > then $_SERVER['PATH_INFO'] would contain /some/stuff.\n\t\t\t *\n\t\t\t * This **does not** include the query string.\n\t\t\t *\n\t\t\t * @see https://www.php.net/manual/en/reserved.variables.server.php#:~:text=PATH_INFO\n\t\t\t */\n\t\t\tif ($_SERVER['REQUEST_URI'].startsWith($_SERVER['SCRIPT_NAME'])) {\n\t\t\t\t$_SERVER['PATH_INFO'] = $_SERVER['REQUEST_URI'].substring(\n\t\t\t\t\t$_SERVER['SCRIPT_NAME'].length\n\t\t\t\t);\n\t\t\t\t// Remove the query string if present.\n\t\t\t\tif ($_SERVER['PATH_INFO'].includes('?')) {\n\t\t\t\t\t$_SERVER['PATH_INFO'] = $_SERVER['PATH_INFO'].substring(\n\t\t\t\t\t\t0,\n\t\t\t\t\t\t$_SERVER['PATH_INFO'].indexOf('?')\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * QUERY_STRING\n\t\t *\n\t\t * The query string from the original and rewritten request URLs.\n\t\t * Does not include the leading question mark.\n\t\t *\n\t\t * Note it contains all the query parameters from the original\n\t\t * URL merged with the new parameters from the rewritten request URLs.\n\t\t *\n\t\t * Example:\n\t\t * – Original request URL: /pretty/url?foo=bar&page=different-value\n\t\t * – Rewritten request URL: /pretty/url?page=pretty\n\t\t * – QUERY_STRING: page=pretty&foo=bar&page=different-value\n\t\t */\n\t\t$_SERVER['QUERY_STRING'] = rewrittenRequestUrl.search.substring(1);\n\n\t\t/**\n\t\t * There's a few relevant entries we are NOT setting here:\n\t\t *\n\t\t * – SCRIPT_FILENAME: Absolute path to the script file. It is set by\n\t\t * php_wasm.c.\n\t\t * – REDIRECT_STATUS: Apache sets it, but it's optional so we skip it.\n\t\t * – REDIRECT_URL: Apache sets it, but it's optional so we skip it.\n\t\t * – REDIRECT_QUERY_STRING: Apache sets it, but it's optional so we skip it.\n\t\t */\n\t\treturn $_SERVER;\n\t}\n\n\tasync [Symbol.asyncDispose]() {\n\t\tawait this.instanceManager[Symbol.asyncDispose]();\n\t}\n}\n\n/**\n * Naively infer a file mime type from its path.\n *\n * @todo Infer the mime type based on the file contents.\n * A naive function like this one can be inaccurate\n * and potentially have negative security consequences.\n *\n * @param path - The file path\n * @returns The inferred mime type.\n */\nexport function inferMimeType(path: string): string {\n\tconst extension = path.split('.').pop() as keyof typeof mimeTypes;\n\t// @TODO: Consider not sending a default mime type to let the browser guess\n\treturn mimeTypes[extension] || mimeTypes['_default'];\n}\n\n/**\n * Applies the given rewrite rules to the given path.\n *\n * @param path The path to apply the rules to.\n * @param rules The rules to apply.\n * @returns The path with the rules applied.\n */\nexport function applyRewriteRules(path: string, rules: RewriteRule[]): string {\n\tfor (const rule of rules) {\n\t\tif (new RegExp(rule.match).test(path)) {\n\t\t\tpath = path.replace(rule.match, rule.replacement);\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn path;\n}\n\n/**\n * Checks if the given URL looks like an absolute URL.\n *\n * @param url - The URL to check.\n * @returns `true` if the URL looks like an absolute URL, `false` otherwise.\n */\nfunction looksLikeAbsoluteUrl(url: string): boolean {\n\ttry {\n\t\t// NOTE: We could just use URL.canParse() but are avoiding it here\n\t\t// because we've seen users with older Safari versions that don't support it.\n\t\t// Maybe Playground will break in other ways for them,\n\t\t// but since this is an easy, low-risk change, let's give it a try.\n\t\tnew URL(url);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n","import type { PHP } from './php';\n\nexport interface RotateOptions {\n\tphp: PHP;\n\tcwd?: string;\n\trecreateRuntime: () => Promise<number> | number;\n\tmaxRequests?: number;\n}\n\n/**\n * Configures inline runtime rotation on the provided PHP instance.\n * Returns a cleanup function that disables rotation.\n *\n * @deprecated Use `php.enableRuntimeRotation()` instead.\n */\nexport function rotatePHPRuntime({\n\tphp,\n\trecreateRuntime,\n\tmaxRequests = 400,\n}: RotateOptions) {\n\treturn php.enableRuntimeRotation({\n\t\trecreateRuntime,\n\t\tmaxRequests,\n\t});\n}\n","import { dirname, joinPaths } from '@php-wasm/util';\nimport type { UniversalPHP } from './universal-php';\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface FileTree\n\textends Record<string, Uint8Array | string | FileTree> {}\n\nexport interface WriteFilesOptions {\n\t/**\n\t * Whether to wipe out the contents of the\n\t * root directory before writing the new files.\n\t */\n\trmRoot?: boolean;\n}\n\n/**\n * Writes multiple files to a specified directory in the Playground\n * filesystem.\n *\n * @example ```ts\n * await writeFiles(php, '/test', {\n * \t'file.txt': 'file',\n * \t'sub/file.txt': 'file',\n * \t'sub1/sub2/file.txt': 'file',\n * });\n * ```\n *\n * @param php\n * @param root\n * @param newFiles\n * @param options\n */\nexport async function writeFiles(\n\tphp: UniversalPHP,\n\troot: string,\n\tnewFiles: FileTree,\n\t{ rmRoot = false }: WriteFilesOptions = {}\n) {\n\tif (rmRoot) {\n\t\tif (await php.isDir(root)) {\n\t\t\tawait php.rmdir(root, { recursive: true });\n\t\t}\n\t}\n\tfor (const [relativePath, content] of Object.entries(newFiles)) {\n\t\tconst filePath = joinPaths(root, relativePath);\n\t\tif (!(await php.fileExists(dirname(filePath)))) {\n\t\t\tawait php.mkdir(dirname(filePath));\n\t\t}\n\t\tif (content instanceof Uint8Array || typeof content === 'string') {\n\t\t\tawait php.writeFile(filePath, content);\n\t\t} else {\n\t\t\tawait writeFiles(php, filePath, content);\n\t\t}\n\t}\n}\n","import type { PHP } from './php';\n\n/**\n * Adds mmap support to PROXYFS for memory-mapping files across PHP instances.\n *\n * Without mmap, libraries like ICU fail when accessing data files through PROXYFS.\n * ICU calls mmap to load icudt74l.dat when initializing Intl classes like Collator\n * and NumberFormatter. PROXYFS has no mmap implementation by default, causing these\n * calls to fail even when the data file exists in the proxied filesystem.\n *\n * This patches PROXYFS.stream_ops to add mmap and msync methods. The mmap implementation\n * allocates memory, reads the file through PROXYFS's existing read operations, and\n * returns a pointer to the allocated buffer—matching the behavior of POSIX mmap.\n *\n * @param phpInstance - The PHP instance whose PROXYFS should be patched\n */\nfunction ensureProxyFSHasMmapSupport(phpInstance: PHP) {\n\tconst __private__symbol = Object.getOwnPropertySymbols(phpInstance)[0];\n\t// @ts-ignore\n\tconst runtime = phpInstance[__private__symbol];\n\tconst PROXYFS = runtime.PROXYFS;\n\tconst FS = runtime.FS;\n\n\t// Skip if mmap is already defined\n\tif (PROXYFS.stream_ops.mmap) {\n\t\treturn;\n\t}\n\n\t/**\n\t * Maps a file into memory by allocating a buffer and reading the file contents into it.\n\t *\n\t * PROXYFS has no direct access to the underlying file buffer, so we simulate mmap\n\t * by allocating memory with malloc and copying the file contents through read operations.\n\t *\n\t * @param stream - The file stream to map\n\t * @param length - Number of bytes to map (may be incorrect for non-.dat files in PHP 7.4)\n\t * @param position - File offset to start mapping from (must be 0)\n\t * @param prot - Memory protection flags (unused, we always allocate read/write)\n\t * @param flags - Mapping flags (unused)\n\t * @returns Object with ptr (pointer to allocated memory) and allocated flag\n\t */\n\t/* eslint-disable @typescript-eslint/no-unused-vars */\n\tPROXYFS.stream_ops.mmap = function (\n\t\tstream: any,\n\t\tlength: number,\n\t\tposition: number,\n\t\tprot: number,\n\t\tflags: number\n\t) {\n\t\t/* eslint-enable @typescript-eslint/no-unused-vars */\n\t\t// Only files can be memory-mapped\n\t\tif (!FS.isFile(stream.node.mode)) {\n\t\t\tthrow new FS.ErrnoError(19); // ENODEV\n\t\t}\n\n\t\t// ICU only maps files from offset 0, so we don't support partial mapping\n\t\tif (position !== 0) {\n\t\t\tthrow new FS.ErrnoError(22); // EINVAL\n\t\t}\n\n\t\tconst ptr = runtime.malloc(length);\n\t\tif (!ptr) {\n\t\t\tthrow new FS.ErrnoError(48); // ENOMEM\n\t\t}\n\n\t\t// Read the file into the allocated memory. Create a subarray view of the heap\n\t\t// so read operations write directly to the correct memory location without\n\t\t// needing offset calculations.\n\t\tconst heap = runtime.HEAPU8.subarray(ptr, ptr + length);\n\t\tlet totalBytesRead = 0;\n\n\t\twhile (totalBytesRead < length) {\n\t\t\tconst bytesRead = stream.stream_ops.read(\n\t\t\t\tstream,\n\t\t\t\theap,\n\t\t\t\ttotalBytesRead,\n\t\t\t\tlength - totalBytesRead,\n\t\t\t\ttotalBytesRead\n\t\t\t);\n\n\t\t\tif (bytesRead <= 0) break;\n\t\t\ttotalBytesRead += bytesRead;\n\t\t}\n\n\t\t// Partial reads indicate I/O errors or premature EOF\n\t\tif (totalBytesRead !== length) {\n\t\t\truntime.free(ptr);\n\t\t\tthrow new FS.ErrnoError(5); // EIO\n\t\t}\n\n\t\treturn { ptr: ptr, allocated: true };\n\t};\n\n\t/**\n\t * Writes memory-mapped changes back to the file when the mapping is shared.\n\t *\n\t * Called by munmap to persist changes made to the mapped memory region.\n\t * MAP_PRIVATE mappings (flag bit 2) keep changes in memory only, while\n\t * MAP_SHARED mappings write changes back to the underlying file.\n\t *\n\t * ICU only reads from its data files, so this rarely gets called in practice.\n\t *\n\t * @param stream - The file stream\n\t * @param buffer - The memory buffer containing changes\n\t * @param offset - Offset in the buffer\n\t * @param length - Number of bytes to sync\n\t * @param mmapFlags - Flags from the original mmap call\n\t * @returns 0 on success\n\t */\n\tPROXYFS.stream_ops.msync = function (\n\t\tstream: any,\n\t\tbuffer: Uint8Array,\n\t\toffset: number,\n\t\tlength: number,\n\t\tmmapFlags: number\n\t) {\n\t\t// MAP_PRIVATE (flag bit 2) means changes stay in memory\n\t\tif (!(mmapFlags & 2)) {\n\t\t\tstream.stream_ops.write(\n\t\t\t\tstream,\n\t\t\t\tbuffer,\n\t\t\t\toffset,\n\t\t\t\tlength,\n\t\t\t\toffset,\n\t\t\t\tfalse\n\t\t\t);\n\t\t}\n\t\treturn 0;\n\t};\n}\n\n/**\n * Mounts directories from one PHP instance's filesystem into another using PROXYFS.\n *\n * This enables file sharing between PHP instances without duplicating the files in memory.\n * For example, mounting /wordpress from the parent instance into a child worker allows\n * both to access the same WordPress installation without copying the entire directory.\n *\n * The function automatically patches PROXYFS with mmap support before mounting, ensuring\n * libraries like ICU can memory-map data files through the proxied filesystem.\n *\n * @param sourceOfTruth - The PHP instance containing the original files\n * @param replica - The PHP instance that will access files through PROXYFS\n * @param paths - Absolute paths to mount (e.g., ['/wordpress', '/internal/shared'])\n */\nexport function proxyFileSystem(\n\tsourceOfTruth: PHP,\n\treplica: PHP,\n\tpaths: string[]\n) {\n\tensureProxyFSHasMmapSupport(replica);\n\n\t// We can't just import the symbol from the library because\n\t// Playground CLI is built as ESM and php-wasm-node is built as\n\t// CJS and the imported symbols will differ in the production build.\n\t// Get symbols from both instances to ensure correct property access.\n\tconst replicaSymbol = Object.getOwnPropertySymbols(replica)[0];\n\tconst sourceSymbol = Object.getOwnPropertySymbols(sourceOfTruth)[0];\n\tfor (const path of paths) {\n\t\tif (!replica.fileExists(path)) {\n\t\t\treplica.mkdir(path);\n\t\t}\n\t\tif (!sourceOfTruth.fileExists(path)) {\n\t\t\tsourceOfTruth.mkdir(path);\n\t\t}\n\t\t// @ts-ignore\n\t\treplica[replicaSymbol].FS.mount(\n\t\t\t// @ts-ignore\n\t\t\treplica[replicaSymbol].PROXYFS,\n\t\t\t{\n\t\t\t\troot: path,\n\t\t\t\t// @ts-ignore\n\t\t\t\tfs: sourceOfTruth[sourceSymbol].FS,\n\t\t\t},\n\t\t\tpath\n\t\t);\n\t}\n}\n\n/**\n * Answers whether the given path is to a shared filesystem.\n *\n * @param sourceOfTruth - The PHP instance that is the source of truth.\n * @param path - The path to check.\n * @returns True if the path is to a shared filesystem, false otherwise.\n */\nexport function isPathToSharedFS(sourceOfTruth: PHP, path: string) {\n\t// We can't just import the symbol from the library because\n\t// Playground CLI is built as ESM and php-wasm-node is built as\n\t// CJS and the imported symbols will different in the production build.\n\tconst __private__symbol = Object.getOwnPropertySymbols(sourceOfTruth)[0];\n\n\t// @ts-ignore\n\tconst FS = sourceOfTruth[__private__symbol].FS;\n\n\tconst fsResult = FS.lookupPath(path, { noent_okay: true });\n\treturn fsResult?.node?.isSharedFS ?? false;\n}\n","import { createSpawnHandler, splitShellCommand } from '@php-wasm/util';\nimport type { PHP } from './php';\nimport type { PHPWorker } from './php-worker';\nimport type { Remote } from './comlink-sync';\nimport { logger } from '@php-wasm/logger';\n\n/**\n * An isomorphic proc_open() handler that implements typical shell in TypeScript\n * without relying on a server runtime. It can be used in the browser and Node.js\n * alike whenever you need to spawn a PHP subprocess, query the terminal size, etc.\n * It is open for future expansion if more shell or busybox calls are needed, but\n * advanced shell features such as piping, stream redirection etc. are outside of\n * the scope of this minimal handler. If they become vital at any point, let's\n * explore bringing in an actual shell implementation or at least a proper command\n * parser.\n */\nexport function sandboxedSpawnHandlerFactory(\n\tgetPHPInstance?: () => Promise<{\n\t\tphp: PHP | Remote<PHPWorker>;\n\t\treap: () => void;\n\t}>\n) {\n\treturn createSpawnHandler(async function (args, processApi, options) {\n\t\tprocessApi.notifySpawn();\n\t\t/**\n\t\t * Blueprints v2 spawn through the Symfony Process class, which wraps the command in\n\t\t *\n\t\t * `/bin/sh -c \"exec ...\"`\n\t\t *\n\t\t * We need to unwrap it.\n\t\t *\n\t\t * We can't just call the /bin/sh binary because we're running a sandboxed shell handler with\n\t\t * no access to OS binaries. The OS binaries wouldn't be able to resolve PHP VFS paths anyway.\n\t\t */\n\t\tif (\n\t\t\targs?.[0] === '/bin/sh' &&\n\t\t\targs?.[1] === '-c' &&\n\t\t\ttypeof args[2] === 'string'\n\t\t) {\n\t\t\targs = splitShellCommand(args[2]);\n\t\t}\n\n\t\tif (args[0] === 'exec') {\n\t\t\targs.shift();\n\t\t}\n\n\t\tif (args[0].endsWith('.php') || args[0].endsWith('.phar')) {\n\t\t\targs.unshift('php');\n\t\t}\n\n\t\tconst binaryName = args[0].split('/').pop();\n\n\t\t// Mock programs required by wp-cli:\n\t\tif (\n\t\t\targs[0] === '/usr/bin/env' &&\n\t\t\targs[1] === 'stty' &&\n\t\t\targs[2] === 'size'\n\t\t) {\n\t\t\t// These numbers are hardcoded because this\n\t\t\t// spawnHandler is transmitted as a string to\n\t\t\t// the PHP backend and has no access to local\n\t\t\t// scope. It would be nice to find a way to\n\t\t\t// transfer / proxy a live object instead.\n\t\t\t// @TODO: Do not hardcode this\n\t\t\tprocessApi.stdout(`18 140`);\n\t\t\tprocessApi.exit(0);\n\t\t} else if (binaryName === 'tput' && args[1] === 'cols') {\n\t\t\tprocessApi.stdout(`140`);\n\t\t\tprocessApi.exit(0);\n\t\t} else if (binaryName === 'less') {\n\t\t\tprocessApi.on('stdin', (data) => {\n\t\t\t\tprocessApi.stdout(data);\n\t\t\t});\n\t\t\t// Exit after the stdin stream is exhausted.\n\t\t\tawait new Promise((resolve) => {\n\t\t\t\tprocessApi.childProcess.stdin.on('finish', () => {\n\t\t\t\t\tresolve(true);\n\t\t\t\t});\n\t\t\t});\n\t\t\tprocessApi.exit(0);\n\t\t\treturn;\n\t\t}\n\n\t\tif (!['php', 'ls', 'pwd'].includes(binaryName ?? '')) {\n\t\t\t// 127 is the exit code \"for command not found\".\n\t\t\tprocessApi.exit(127);\n\t\t\treturn;\n\t\t}\n\n\t\tif (!getPHPInstance) {\n\t\t\tlogger.warn(\n\t\t\t\t'Tried to spawn a PHP subprocess, but the sandboxed spawn handler was created without a getPHPInstance function.'\n\t\t\t);\n\t\t\tprocessApi.exit(127);\n\t\t\treturn;\n\t\t}\n\n\t\tconst { php, reap } = await getPHPInstance();\n\n\t\ttry {\n\t\t\tif (options.cwd) {\n\t\t\t\tawait php.chdir(options.cwd as string);\n\t\t\t}\n\n\t\t\tconst cwd = await php.cwd();\n\t\t\tswitch (binaryName) {\n\t\t\t\tcase 'php': {\n\t\t\t\t\t// Figure out more about setting env, putenv(), etc.\n\t\t\t\t\tconst result = await php.cli(args, {\n\t\t\t\t\t\tenv: {\n\t\t\t\t\t\t\t...options.env,\n\t\t\t\t\t\t\tSCRIPT_PATH: args[1],\n\t\t\t\t\t\t\t// Set SHELL_PIPE to 0 to ensure WP-CLI formats\n\t\t\t\t\t\t\t// the output as ASCII tables.\n\t\t\t\t\t\t\t// @see https://github.com/wp-cli/wp-cli/issues/1102\n\t\t\t\t\t\t\tSHELL_PIPE: '0',\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\n\t\t\t\t\tresult.stdout.pipeTo(\n\t\t\t\t\t\tnew WritableStream({\n\t\t\t\t\t\t\twrite(chunk) {\n\t\t\t\t\t\t\t\tprocessApi.stdout(chunk as any as ArrayBuffer);\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\t\t\t\t\tresult.stderr.pipeTo(\n\t\t\t\t\t\tnew WritableStream({\n\t\t\t\t\t\t\twrite(chunk) {\n\t\t\t\t\t\t\t\tprocessApi.stderr(chunk as any as ArrayBuffer);\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\t\t\t\t\tprocessApi.exit(await result.exitCode);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'ls': {\n\t\t\t\t\tconst files = await php.listFiles(args[1] ?? cwd);\n\t\t\t\t\tfor (const file of files) {\n\t\t\t\t\t\tprocessApi.stdout(file + '\\n');\n\t\t\t\t\t}\n\t\t\t\t\t// Technical limitation of subprocesses – we need to\n\t\t\t\t\t// wait before exiting to give consumer a chance to read\n\t\t\t\t\t// the output.\n\t\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, 10));\n\t\t\t\t\tprocessApi.exit(0);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'pwd': {\n\t\t\t\t\tprocessApi.stdout(cwd + '\\n');\n\t\t\t\t\t// Technical limitation of subprocesses – we need to\n\t\t\t\t\t// wait before exiting to give consumer a chance to read\n\t\t\t\t\t// the output.\n\t\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, 10));\n\t\t\t\t\tprocessApi.exit(0);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (e) {\n\t\t\t// An exception here means the PHP runtime has crashed.\n\t\t\tprocessApi.exit(1);\n\t\t\tthrow e;\n\t\t} finally {\n\t\t\treap();\n\t\t}\n\t});\n}\n","/* eslint-disable @typescript-eslint/no-unsafe-function-type */\n/* eslint-disable @typescript-eslint/no-misused-new */\n/* eslint-disable @typescript-eslint/no-empty-object-type */\nimport type { MessagePort as NodeMessagePort } from 'worker_threads';\n\n/**\n * Comlink library protocol extension to use synchronous messaging.\n *\n * Debugging Asyncify is too much of a burden. This extension enables exchanging\n * messages between threads synchronously so that we don't need to rely on Asyncify.\n *\n * Upsides:\n *\n * * Saves dozens-to-hundreds of hours on debugging Asyncify issues\n * * Increased reliability\n * * Useful stack traces when errors do happen.\n *\n * Downsides:\n *\n * * Fragmentation: Both synchronous and asynchronous handlers exist to get the best our of both\n * Asyncify and JSPI. * Node.js-only: This extension does not implement a Safari-friendly\n * transport. SharedArrayBuffer is an option, but\n * it requires more restrictive CORP+COEP headers which breaks, e.g., YouTube\n * embeds. Synchronous XHR might work if we really need Safari support for one of\n * the new asynchronous features, but other than that let's just skip adding new\n * asynchronous WASM features to Safari until WebKit supports stack switching.\n * * Message passing between workers is slow. Avoid using synchronous messaging for syscalls that\n * are invoked frequently and\n * handled asynchronously in the same worker.\n *\n * @see https://github.com/adamziel/js-synchronous-messaging for additional ideas.\n * @see https://github.com/WordPress/wordpress-playground/blob/9a9262cc62cc161d220a9992706b9ed2817f2eb5/packages/docs/site/docs/developers/23-architecture/07-wasm-asyncify.md\n */\ninterface SyncMessage {\n\t/** original Comlink envelope */\n\tid?: string;\n\ttype: MessageType;\n\t/** existing Comlink fields … */\n\t[k: string]: any;\n\t/** new part that carries the latch */\n\tnotifyBuffer?: SharedArrayBuffer;\n}\n\ninterface SyncTransport {\n\tafterResponseSent(ev: MessageEvent): void;\n\tsend(\n\t\tep: IsomorphicMessagePort,\n\t\tmsg: Omit<SyncMessage, 'id' | 'notifyBuffer'>,\n\t\ttransferables?: Transferable[]\n\t): WireValue;\n}\n\nexport function exposeSync(\n\tobj: any,\n\tep: Endpoint,\n\ttransport: SyncTransport,\n\tallowedOrigins: (string | RegExp)[] = ['*']\n) {\n\treturn expose(obj, ep, allowedOrigins, transport.afterResponseSent);\n}\n\n//////////////////////////////\n// 3. Consumer side //\n//////////////////////////////\n\nfunction createSyncProxy<T>(\n\tep: IsomorphicMessagePort,\n\tpath: (string | number | symbol)[] = [],\n\ttransport: SyncTransport\n): T {\n\treturn new Proxy(() => {}, {\n\t\tget(_t, prop) {\n\t\t\tif (prop === 'then') {\n\t\t\t\t// allow await‑usage without deadlocking\n\t\t\t\tif (!path.length)\n\t\t\t\t\treturn {\n\t\t\t\t\t\tthen: (_: any, res: any) =>\n\t\t\t\t\t\t\tres(createSyncProxy(ep, [], transport)),\n\t\t\t\t\t};\n\t\t\t}\n\t\t\treturn createSyncProxy(ep, [...path, prop], transport);\n\t\t},\n\n\t\tset(_t, prop, value) {\n\t\t\tconst [v, xfer] = toWireValue(value);\n\t\t\ttransport.send(\n\t\t\t\tep,\n\t\t\t\t{\n\t\t\t\t\ttype: MessageType.SET,\n\t\t\t\t\tpath: [...path, prop].map(String),\n\t\t\t\t\tvalue: v,\n\t\t\t\t},\n\t\t\t\txfer\n\t\t\t);\n\t\t\treturn true;\n\t\t},\n\n\t\tapply(_t, _thisArg, rawArgs) {\n\t\t\t// Special cases\n\t\t\tconst last = path.at(-1);\n\t\t\tif (last === 'bind')\n\t\t\t\treturn createSyncProxy(ep, path.slice(0, -1), transport);\n\n\t\t\tconst [argList, xfer] = processArguments(rawArgs);\n\t\t\tconst wire = transport.send(\n\t\t\t\tep,\n\t\t\t\t{\n\t\t\t\t\ttype: MessageType.APPLY,\n\t\t\t\t\tpath: path.map(String),\n\t\t\t\t\targumentList: argList,\n\t\t\t\t},\n\t\t\t\txfer\n\t\t\t);\n\n\t\t\treturn fromWireValue(wire);\n\t\t},\n\n\t\tconstruct(_t, rawArgs) {\n\t\t\tconst [argList, xfer] = processArguments(rawArgs);\n\t\t\tconst wire = transport.send(\n\t\t\t\tep,\n\t\t\t\t{\n\t\t\t\t\ttype: MessageType.CONSTRUCT,\n\t\t\t\t\tpath: path.map(String),\n\t\t\t\t\targumentList: argList,\n\t\t\t\t},\n\t\t\t\txfer\n\t\t\t);\n\t\t\treturn fromWireValue(wire);\n\t\t},\n\t}) as unknown as T;\n}\n\nexport function wrapSync<T>(\n\tep: IsomorphicMessagePort,\n\ttransport: SyncTransport\n): T {\n\treturn createSyncProxy<T>(ep, [], transport);\n}\n\n/// Transport ///\n\nexport type IsomorphicMessagePort = MessagePort | NodeMessagePort;\n\nexport class NodeSABSyncReceiveMessageTransport {\n\tprivate static receiveMessageOnPort: any;\n\n\tstatic async create() {\n\t\tif (!NodeSABSyncReceiveMessageTransport.receiveMessageOnPort) {\n\t\t\ttry {\n\t\t\t\tNodeSABSyncReceiveMessageTransport.receiveMessageOnPort =\n\t\t\t\t\trequire('worker_threads').receiveMessageOnPort;\n\t\t\t} catch {\n\t\t\t\tNodeSABSyncReceiveMessageTransport.receiveMessageOnPort =\n\t\t\t\t\tawait import('worker_threads').then(\n\t\t\t\t\t\t(m) => m.receiveMessageOnPort\n\t\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\treturn new NodeSABSyncReceiveMessageTransport();\n\t}\n\n\tprivate constructor() {}\n\n\tafterResponseSent(ev: MessageEvent) {\n\t\tconst { notifyBuffer } = ev.data as SyncMessage;\n\t\tif (notifyBuffer) {\n\t\t\tconst view = new Int32Array(notifyBuffer);\n\t\t\tview[0] = 1;\n\t\t\tAtomics.notify(view, 0);\n\t\t}\n\t}\n\tsend(\n\t\tep: IsomorphicMessagePort,\n\t\tmsg: Omit<SyncMessage, 'id' | 'notifyBuffer'>,\n\t\ttransferables?: Transferable[]\n\t): WireValue {\n\t\t// SharedArrayBuffer = one 32‑bit cell that starts at 0.\n\t\t// The other worker will set this to 1 when it has sent the response.\n\t\tconst latch = new SharedArrayBuffer(4);\n\t\tconst view = new Int32Array(latch);\n\t\tview[0] = 0;\n\n\t\tconst id = generateUUID();\n\t\tep.postMessage(\n\t\t\t{ ...msg, id, notifyBuffer: latch },\n\t\t\ttransferables as any\n\t\t);\n\n\t\t// Synchronous pull; Node.js-only. Browsers don't support receiveMessageOnPort.\n\t\tconst timeoutMs = 5000;\n\t\tconst result = Atomics.wait(view, 0, 0, timeoutMs);\n\t\tif (result === 'timed-out') {\n\t\t\tthrow new Error('Timeout waiting for response');\n\t\t}\n\t\twhile (true) {\n\t\t\tconst res =\n\t\t\t\tNodeSABSyncReceiveMessageTransport.receiveMessageOnPort(ep);\n\t\t\tif (res.message?.id === id) {\n\t\t\t\treturn res.message;\n\t\t\t} else if (!res) {\n\t\t\t\tthrow new Error('No response received');\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Original, unmodified Comlink library from Google:\n *\n * @license\n * Copyright 2019 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nexport const proxyMarker = Symbol('Comlink.proxy');\nexport const createEndpoint = Symbol('Comlink.endpoint');\nexport const releaseProxy = Symbol('Comlink.releaseProxy');\nexport const finalizer = Symbol('Comlink.finalizer');\n\nconst throwMarker = Symbol('Comlink.thrown');\n\n/**\n * @license\n * Copyright 2019 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nexport interface EventSource {\n\taddEventListener(\n\t\ttype: string,\n\t\tlistener: EventListenerOrEventListenerObject,\n\t\toptions?: object\n\t): void;\n\n\tremoveEventListener(\n\t\ttype: string,\n\t\tlistener: EventListenerOrEventListenerObject,\n\t\toptions?: object\n\t): void;\n}\n\nexport interface PostMessageWithOrigin {\n\tpostMessage(\n\t\tmessage: any,\n\t\ttargetOrigin: string,\n\t\ttransfer?: Transferable[]\n\t): void;\n}\n\nexport interface Endpoint extends EventSource {\n\tpostMessage(message: any, transfer?: Transferable[]): void;\n\n\tstart?: () => void;\n}\n\nexport const WireValueType = {\n\tRAW: 'RAW',\n\tPROXY: 'PROXY',\n\tTHROW: 'THROW',\n\tHANDLER: 'HANDLER',\n} as const;\n\nexport type WireValueType = typeof WireValueType;\n\nexport interface RawWireValue {\n\tid?: string;\n\ttype: WireValueType['RAW'];\n\tvalue: any;\n}\n\nexport interface HandlerWireValue {\n\tid?: string;\n\ttype: WireValueType['HANDLER'];\n\tname: string;\n\tvalue: unknown;\n}\n\nexport type WireValue = RawWireValue | HandlerWireValue;\n\nexport type MessageID = string;\n\nexport const MessageType = {\n\tGET: 'GET',\n\tSET: 'SET',\n\tAPPLY: 'APPLY',\n\tCONSTRUCT: 'CONSTRUCT',\n\tENDPOINT: 'ENDPOINT',\n\tRELEASE: 'RELEASE',\n} as const;\nexport type MessageType = typeof MessageType;\n\nexport interface GetMessage {\n\tid?: MessageID;\n\ttype: MessageType['GET'];\n\tpath: string[];\n}\n\nexport interface SetMessage {\n\tid?: MessageID;\n\ttype: MessageType['SET'];\n\tpath: string[];\n\tvalue: WireValue;\n}\n\nexport interface ApplyMessage {\n\tid?: MessageID;\n\ttype: MessageType['APPLY'];\n\tpath: string[];\n\targumentList: WireValue[];\n}\n\nexport interface ConstructMessage {\n\tid?: MessageID;\n\ttype: MessageType['CONSTRUCT'];\n\tpath: string[];\n\targumentList: WireValue[];\n}\n\nexport interface EndpointMessage {\n\tid?: MessageID;\n\ttype: MessageType['ENDPOINT'];\n}\n\nexport interface ReleaseMessage {\n\tid?: MessageID;\n\ttype: MessageType['RELEASE'];\n}\n\nexport type Message =\n\t| GetMessage\n\t| SetMessage\n\t| ApplyMessage\n\t| ConstructMessage\n\t| EndpointMessage\n\t| ReleaseMessage;\n\n/**\n * Interface of values that were marked to be proxied with `comlink.proxy()`.\n * Can also be implemented by classes.\n */\nexport interface ProxyMarked {\n\t[proxyMarker]: true;\n}\n\n/**\n * Takes a type and wraps it in a Promise, if it not already is one.\n * This is to avoid `Promise<Promise<T>>`.\n *\n * This is the inverse of `Unpromisify<T>`.\n */\ntype Promisify<T> = T extends Promise<unknown> ? T : Promise<T>;\n/**\n * Takes a type that may be Promise and unwraps the Promise type.\n * If `P` is not a Promise, it returns `P`.\n *\n * This is the inverse of `Promisify<T>`.\n */\ntype Unpromisify<P> = P extends Promise<infer T> ? T : P;\n\n/**\n * Takes the raw type of a remote property and returns the type that is visible to the local thread\n * on the proxy.\n *\n * Note: This needs to be its own type alias, otherwise it will not distribute over unions.\n * See https://www.typescriptlang.org/docs/handbook/advanced-types.html#distributive-conditional-types\n */\ntype RemoteProperty<T> =\n\t// If the value is a method, comlink will proxy it automatically.\n\t// Objects are only proxied if they are marked to be proxied.\n\t// Otherwise, the property is converted to a Promise that resolves the cloned value.\n\tT extends Function | ProxyMarked ? Remote<T> : Promisify<T>;\n\n/**\n * Takes the raw type of a property as a remote thread would see it through a proxy (e.g. when\n * passed in as a function argument) and returns the type that the local thread has to supply.\n *\n * This is the inverse of `RemoteProperty<T>`.\n *\n * Note: This needs to be its own type alias, otherwise it will not distribute over unions. See\n * https://www.typescriptlang.org/docs/handbook/advanced-types.html#distributive-conditional-types\n */\ntype LocalProperty<T> = T extends Function | ProxyMarked\n\t? Local<T>\n\t: Unpromisify<T>;\n\n/**\n * Proxies `T` if it is a `ProxyMarked`, clones it otherwise (as handled by structured cloning and\n * transfer handlers).\n */\nexport type ProxyOrClone<T> = T extends ProxyMarked ? Remote<T> : T;\n/**\n * Inverse of `ProxyOrClone<T>`.\n */\nexport type UnproxyOrClone<T> = T extends RemoteObject<ProxyMarked>\n\t? Local<T>\n\t: T;\n\n/**\n * Takes the raw type of a remote object in the other thread and returns the type as it is visible\n * to the local thread when proxied with `Comlink.proxy()`.\n *\n * This does not handle call signatures, which is handled by the more general `Remote<T>` type.\n *\n * @template T The raw type of a remote object as seen in the other thread.\n */\nexport type RemoteObject<T> = { [P in keyof T]: RemoteProperty<T[P]> };\n/**\n * Takes the type of an object as a remote thread would see it through a proxy (e.g. when passed in\n * as a function argument) and returns the type that the local thread has to supply.\n *\n * This does not handle call signatures, which is handled by the more general `Local<T>` type.\n *\n * This is the inverse of `RemoteObject<T>`.\n *\n * @template T The type of a proxied object.\n */\nexport type LocalObject<T> = { [P in keyof T]: LocalProperty<T[P]> };\n\n/**\n * Additional special comlink methods available on each proxy returned by `Comlink.wrap()`.\n */\nexport interface ProxyMethods {\n\t[createEndpoint]: () => Promise<MessagePort>;\n\t[releaseProxy]: () => void;\n}\n\n/**\n * Takes the raw type of a remote object, function or class in the other thread and returns the\n * type as it is visible to the local thread from the proxy return value of `Comlink.wrap()` or\n * `Comlink.proxy()`.\n */\nexport type Remote<T> =\n\t// Handle properties\n\tRemoteObject<T> &\n\t\t// Handle call signature (if present)\n\t\t(T extends (...args: infer TArguments) => infer TReturn\n\t\t\t? (\n\t\t\t\t\t...args: {\n\t\t\t\t\t\t[I in keyof TArguments]: UnproxyOrClone<TArguments[I]>;\n\t\t\t\t\t}\n\t\t\t ) => Promisify<ProxyOrClone<Unpromisify<TReturn>>>\n\t\t\t: unknown) &\n\t\t// Handle construct signature (if present)\n\t\t// The return of construct signatures is always proxied (whether marked or not)\n\t\t(T extends { new (...args: infer TArguments): infer TInstance }\n\t\t\t? {\n\t\t\t\t\tnew (\n\t\t\t\t\t\t...args: {\n\t\t\t\t\t\t\t[I in keyof TArguments]: UnproxyOrClone<\n\t\t\t\t\t\t\t\tTArguments[I]\n\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t}\n\t\t\t\t\t): Promisify<Remote<TInstance>>;\n\t\t\t }\n\t\t\t: unknown) &\n\t\t// Include additional special comlink methods available on the proxy.\n\t\tProxyMethods;\n\n/**\n * Expresses that a type can be either a sync or async.\n */\ntype MaybePromise<T> = Promise<T> | T;\n\n/**\n * Takes the raw type of a remote object, function or class as a remote thread would see it through\n * a proxy (e.g. when passed in as a function argument) and returns the type the local thread has\n * to supply.\n *\n * This is the inverse of `Remote<T>`. It takes a `Remote<T>` and returns its original input `T`.\n */\nexport type Local<T> =\n\t// Omit the special proxy methods (they don't need to be supplied, comlink adds them)\n\tOmit<LocalObject<T>, keyof ProxyMethods> &\n\t\t// Handle call signatures (if present)\n\t\t(T extends (...args: infer TArguments) => infer TReturn\n\t\t\t? (\n\t\t\t\t\t...args: {\n\t\t\t\t\t\t[I in keyof TArguments]: ProxyOrClone<TArguments[I]>;\n\t\t\t\t\t}\n\t\t\t ) => // The raw function could either be sync or async, but is always proxied automatically\n\t\t\t MaybePromise<UnproxyOrClone<Unpromisify<TReturn>>>\n\t\t\t: unknown) &\n\t\t// Handle construct signature (if present)\n\t\t// The return of construct signatures is always proxied (whether marked or not)\n\t\t(T extends { new (...args: infer TArguments): infer TInstance }\n\t\t\t? {\n\t\t\t\t\tnew (\n\t\t\t\t\t\t...args: {\n\t\t\t\t\t\t\t[I in keyof TArguments]: ProxyOrClone<\n\t\t\t\t\t\t\t\tTArguments[I]\n\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t}\n\t\t\t\t\t): // The raw constructor could either be sync or async, but is always proxied automatically\n\t\t\t\t\tMaybePromise<Local<Unpromisify<TInstance>>>;\n\t\t\t }\n\t\t\t: unknown);\n\nconst isObject = (val: unknown): val is object =>\n\t(typeof val === 'object' && val !== null) || typeof val === 'function';\n\n/**\n * Customizes the serialization of certain values as determined by `canHandle()`.\n *\n * @template T The input type being handled by this transfer handler.\n * @template S The serialized type sent over the wire.\n */\nexport interface TransferHandler<T, S> {\n\t/**\n\t * Gets called for every value to determine whether this transfer handler\n\t * should serialize the value, which includes checking that it is of the right\n\t * type (but can perform checks beyond that as well).\n\t */\n\tcanHandle(value: unknown): value is T;\n\n\t/**\n\t * Gets called with the value if `canHandle()` returned `true` to produce a\n\t * value that can be sent in a message, consisting of structured-cloneable\n\t * values and/or transferrable objects.\n\t */\n\tserialize(value: T): [S, Transferable[]];\n\n\t/**\n\t * Gets called to deserialize an incoming value that was serialized in the\n\t * other thread with this transfer handler (known through the name it was\n\t * registered under).\n\t */\n\tdeserialize(value: S): T;\n}\n\n/**\n * Internal transfer handle to handle objects marked to proxy.\n */\nconst proxyTransferHandler: TransferHandler<object, MessagePort> = {\n\tcanHandle: (val): val is ProxyMarked =>\n\t\tisObject(val) && (val as ProxyMarked)[proxyMarker],\n\tserialize(obj) {\n\t\tconst { port1, port2 } = new MessageChannel();\n\t\texpose(obj, port1);\n\t\treturn [port2, [port2]];\n\t},\n\tdeserialize(port) {\n\t\tport.start();\n\t\treturn wrap(port);\n\t},\n};\n\ninterface ThrownValue {\n\t[throwMarker]: unknown; // just needs to be present\n\tvalue: unknown;\n}\ntype SerializedThrownValue =\n\t| { isError: true; value: Error }\n\t| { isError: false; value: unknown };\ntype PendingListenersMap = Map<\n\tstring,\n\t(value: WireValue | PromiseLike<WireValue>) => void\n>;\n\n/**\n * Internal transfer handler to handle thrown exceptions.\n */\nconst throwTransferHandler: TransferHandler<\n\tThrownValue,\n\tSerializedThrownValue\n> = {\n\tcanHandle: (value): value is ThrownValue =>\n\t\tisObject(value) && throwMarker in value,\n\tserialize({ value }) {\n\t\tlet serialized: SerializedThrownValue;\n\t\tif (value instanceof Error) {\n\t\t\tserialized = {\n\t\t\t\tisError: true,\n\t\t\t\tvalue: {\n\t\t\t\t\tmessage: value.message,\n\t\t\t\t\tname: value.name,\n\t\t\t\t\tstack: value.stack,\n\t\t\t\t},\n\t\t\t};\n\t\t} else {\n\t\t\tserialized = { isError: false, value };\n\t\t}\n\t\treturn [serialized, []];\n\t},\n\tdeserialize(serialized) {\n\t\tif (serialized.isError) {\n\t\t\tthrow Object.assign(\n\t\t\t\tnew Error(serialized.value.message),\n\t\t\t\tserialized.value\n\t\t\t);\n\t\t}\n\t\tthrow serialized.value;\n\t},\n};\n\n/**\n * Allows customizing the serialization of certain values.\n */\nexport const transferHandlers = new Map<\n\tstring,\n\tTransferHandler<unknown, unknown>\n>([\n\t['proxy', proxyTransferHandler],\n\t['throw', throwTransferHandler],\n]);\n\nfunction isAllowedOrigin(\n\tallowedOrigins: (string | RegExp)[],\n\torigin: string\n): boolean {\n\tfor (const allowedOrigin of allowedOrigins) {\n\t\tif (origin === allowedOrigin || allowedOrigin === '*') {\n\t\t\treturn true;\n\t\t}\n\t\tif (allowedOrigin instanceof RegExp && allowedOrigin.test(origin)) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\nexport function expose(\n\tobj: any,\n\tep: Endpoint = globalThis as any,\n\tallowedOrigins: (string | RegExp)[] = ['*'],\n\tafterResponseSent?: (ev: MessageEvent) => void\n) {\n\tep.addEventListener('message', function callback(ev: MessageEvent) {\n\t\tif (!ev || !ev.data) {\n\t\t\treturn;\n\t\t}\n\t\tif (!isAllowedOrigin(allowedOrigins, ev.origin)) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.warn(`Invalid origin '${ev.origin}' for comlink proxy`);\n\t\t\treturn;\n\t\t}\n\t\tconst { id, type, path } = {\n\t\t\tpath: [] as string[],\n\t\t\t...(ev.data as Message),\n\t\t};\n\t\tconst argumentList = (ev.data.argumentList || []).map(fromWireValue);\n\t\tlet returnValue;\n\t\ttry {\n\t\t\tconst parent = path\n\t\t\t\t.slice(0, -1)\n\t\t\t\t.reduce((obj, prop) => obj[prop], obj);\n\t\t\tconst rawValue = path.reduce((obj, prop) => obj[prop], obj);\n\t\t\tswitch (type) {\n\t\t\t\tcase MessageType.GET:\n\t\t\t\t\t{\n\t\t\t\t\t\treturnValue = rawValue;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase MessageType.SET:\n\t\t\t\t\t{\n\t\t\t\t\t\tparent[path.slice(-1)[0]] = fromWireValue(\n\t\t\t\t\t\t\tev.data.value\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturnValue = true;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase MessageType.APPLY:\n\t\t\t\t\t{\n\t\t\t\t\t\treturnValue = rawValue.apply(parent, argumentList);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase MessageType.CONSTRUCT:\n\t\t\t\t\t{\n\t\t\t\t\t\tconst value = new rawValue(...argumentList);\n\t\t\t\t\t\treturnValue = proxy(value);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase MessageType.ENDPOINT:\n\t\t\t\t\t{\n\t\t\t\t\t\tconst { port1, port2 } = new MessageChannel();\n\t\t\t\t\t\texpose(obj, port2);\n\t\t\t\t\t\treturnValue = transfer(port1, [port1]);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase MessageType.RELEASE:\n\t\t\t\t\t{\n\t\t\t\t\t\treturnValue = undefined;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\treturn;\n\t\t\t}\n\t\t} catch (value) {\n\t\t\treturnValue = { value, [throwMarker]: 0 };\n\t\t}\n\t\tPromise.resolve(returnValue)\n\t\t\t.catch((value) => {\n\t\t\t\treturn { value, [throwMarker]: 0 };\n\t\t\t})\n\t\t\t.then((returnValue) => {\n\t\t\t\tconst [wireValue, transferables] = toWireValue(returnValue);\n\t\t\t\tep.postMessage({ ...wireValue, id }, transferables);\n\t\t\t\tif (type === MessageType.RELEASE) {\n\t\t\t\t\t// detach and deactive after sending release response above.\n\t\t\t\t\tep.removeEventListener('message', callback as any);\n\t\t\t\t\tcloseEndPoint(ep);\n\t\t\t\t\tif (\n\t\t\t\t\t\tfinalizer in obj &&\n\t\t\t\t\t\ttypeof obj[finalizer] === 'function'\n\t\t\t\t\t) {\n\t\t\t\t\t\tobj[finalizer]();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch(() => {\n\t\t\t\t// Send Serialization Error To Caller\n\t\t\t\tconst [wireValue, transferables] = toWireValue({\n\t\t\t\t\tvalue: new TypeError('Unserializable return value'),\n\t\t\t\t\t[throwMarker]: 0,\n\t\t\t\t});\n\t\t\t\tep.postMessage({ ...wireValue, id }, transferables);\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\tafterResponseSent?.(ev);\n\t\t\t});\n\t} as any);\n\tif (ep.start) {\n\t\tep.start();\n\t}\n}\n\nfunction isMessagePort(endpoint: Endpoint): endpoint is MessagePort {\n\treturn endpoint.constructor.name === 'MessagePort';\n}\n\nfunction closeEndPoint(endpoint: Endpoint) {\n\tif (isMessagePort(endpoint)) endpoint.close();\n}\n\nexport function wrap<T>(ep: Endpoint, target?: any): Remote<T> {\n\tconst pendingListeners: PendingListenersMap = new Map();\n\n\tep.addEventListener('message', function handleMessage(ev: Event) {\n\t\tconst { data } = ev as MessageEvent;\n\t\tif (!data || !data.id) {\n\t\t\treturn;\n\t\t}\n\t\tconst resolver = pendingListeners.get(data.id);\n\t\tif (!resolver) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tresolver(data);\n\t\t} finally {\n\t\t\tpendingListeners.delete(data.id);\n\t\t}\n\t});\n\n\treturn createProxy<T>(ep, pendingListeners, [], target) as any;\n}\n\nfunction throwIfProxyReleased(isReleased: boolean) {\n\tif (isReleased) {\n\t\tthrow new Error('Proxy has been released and is not useable');\n\t}\n}\n\nfunction releaseEndpoint(ep: Endpoint) {\n\treturn requestResponseMessage(ep, new Map(), {\n\t\ttype: MessageType.RELEASE,\n\t}).then(() => {\n\t\tcloseEndPoint(ep);\n\t});\n}\n\ninterface FinalizationRegistry<T> {\n\t// @ts-ignore\n\tnew (cb: (heldValue: T) => void): FinalizationRegistry<T>;\n\tregister(\n\t\tweakItem: object,\n\t\theldValue: T,\n\t\tunregisterToken?: object | undefined\n\t): void;\n\tunregister(unregisterToken: object): void;\n}\ndeclare const FinalizationRegistry: FinalizationRegistry<Endpoint>;\n\nconst proxyCounter = new WeakMap<Endpoint, number>();\nconst proxyFinalizers =\n\t'FinalizationRegistry' in globalThis &&\n\tnew FinalizationRegistry((ep: Endpoint) => {\n\t\tconst newCount = (proxyCounter.get(ep) || 0) - 1;\n\t\tproxyCounter.set(ep, newCount);\n\t\tif (newCount === 0) {\n\t\t\treleaseEndpoint(ep);\n\t\t}\n\t});\n\nfunction registerProxy(proxy: object, ep: Endpoint) {\n\tconst newCount = (proxyCounter.get(ep) || 0) + 1;\n\tproxyCounter.set(ep, newCount);\n\tif (proxyFinalizers) {\n\t\tproxyFinalizers.register(proxy, ep, proxy);\n\t}\n}\n\nfunction unregisterProxy(proxy: object) {\n\tif (proxyFinalizers) {\n\t\tproxyFinalizers.unregister(proxy);\n\t}\n}\n\nfunction createProxy<T>(\n\tep: Endpoint,\n\tpendingListeners: PendingListenersMap,\n\tpath: (string | number | symbol)[] = [],\n\ttarget: object = function () {}\n): Remote<T> {\n\tlet isProxyReleased = false;\n\tconst proxy = new Proxy(target, {\n\t\tget(_target, prop) {\n\t\t\tthrowIfProxyReleased(isProxyReleased);\n\t\t\tif (prop === releaseProxy) {\n\t\t\t\treturn () => {\n\t\t\t\t\tunregisterProxy(proxy);\n\t\t\t\t\treleaseEndpoint(ep);\n\t\t\t\t\tpendingListeners.clear();\n\t\t\t\t\tisProxyReleased = true;\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (prop === 'then') {\n\t\t\t\tif (path.length === 0) {\n\t\t\t\t\treturn { then: () => proxy };\n\t\t\t\t}\n\t\t\t\tconst r = requestResponseMessage(ep, pendingListeners, {\n\t\t\t\t\ttype: MessageType.GET,\n\t\t\t\t\tpath: path.map((p) => p.toString()),\n\t\t\t\t}).then(fromWireValue);\n\t\t\t\treturn r.then.bind(r);\n\t\t\t}\n\t\t\treturn createProxy(ep, pendingListeners, [...path, prop]);\n\t\t},\n\t\tset(_target, prop, rawValue) {\n\t\t\tthrowIfProxyReleased(isProxyReleased);\n\t\t\t// FIXME: ES6 Proxy Handler `set` methods are supposed to return a\n\t\t\t// boolean. To show good will, we return true asynchronously ¯\\_(ツ)_/¯\n\t\t\tconst [value, transferables] = toWireValue(rawValue);\n\t\t\treturn requestResponseMessage(\n\t\t\t\tep,\n\t\t\t\tpendingListeners,\n\t\t\t\t{\n\t\t\t\t\ttype: MessageType.SET,\n\t\t\t\t\tpath: [...path, prop].map((p) => p.toString()),\n\t\t\t\t\tvalue,\n\t\t\t\t},\n\t\t\t\ttransferables\n\t\t\t).then(fromWireValue) as any;\n\t\t},\n\t\tapply(_target, _thisArg, rawArgumentList) {\n\t\t\tthrowIfProxyReleased(isProxyReleased);\n\t\t\tconst last = path[path.length - 1];\n\t\t\tif ((last as any) === createEndpoint) {\n\t\t\t\treturn requestResponseMessage(ep, pendingListeners, {\n\t\t\t\t\ttype: MessageType.ENDPOINT,\n\t\t\t\t}).then(fromWireValue);\n\t\t\t}\n\t\t\t// We just pretend that `bind()` didn’t happen.\n\t\t\tif (last === 'bind') {\n\t\t\t\treturn createProxy(ep, pendingListeners, path.slice(0, -1));\n\t\t\t}\n\t\t\tconst [argumentList, transferables] =\n\t\t\t\tprocessArguments(rawArgumentList);\n\t\t\treturn requestResponseMessage(\n\t\t\t\tep,\n\t\t\t\tpendingListeners,\n\t\t\t\t{\n\t\t\t\t\ttype: MessageType.APPLY,\n\t\t\t\t\tpath: path.map((p) => p.toString()),\n\t\t\t\t\targumentList,\n\t\t\t\t},\n\t\t\t\ttransferables\n\t\t\t).then(fromWireValue);\n\t\t},\n\t\tconstruct(_target, rawArgumentList) {\n\t\t\tthrowIfProxyReleased(isProxyReleased);\n\t\t\tconst [argumentList, transferables] =\n\t\t\t\tprocessArguments(rawArgumentList);\n\t\t\treturn requestResponseMessage(\n\t\t\t\tep,\n\t\t\t\tpendingListeners,\n\t\t\t\t{\n\t\t\t\t\ttype: MessageType.CONSTRUCT,\n\t\t\t\t\tpath: path.map((p) => p.toString()),\n\t\t\t\t\targumentList,\n\t\t\t\t},\n\t\t\t\ttransferables\n\t\t\t).then(fromWireValue);\n\t\t},\n\t});\n\tregisterProxy(proxy, ep);\n\treturn proxy as any;\n}\n\nfunction myFlat<T>(arr: (T | T[])[]): T[] {\n\treturn Array.prototype.concat.apply([], arr);\n}\n\nfunction processArguments(argumentList: any[]): [WireValue[], Transferable[]] {\n\tconst processed = argumentList.map(toWireValue);\n\treturn [processed.map((v) => v[0]), myFlat(processed.map((v) => v[1]))];\n}\n\nconst transferCache = new WeakMap<any, Transferable[]>();\nexport function transfer<T>(obj: T, transfers: Transferable[]): T {\n\ttransferCache.set(obj, transfers);\n\treturn obj;\n}\n\nexport function proxy<T extends object>(obj: T): T & ProxyMarked {\n\treturn Object.assign(obj, { [proxyMarker]: true }) as any;\n}\n\nexport function windowEndpoint(\n\tw: PostMessageWithOrigin,\n\tcontext: EventSource = globalThis,\n\ttargetOrigin = '*'\n): Endpoint {\n\treturn {\n\t\tpostMessage: (msg: any, transferables: Transferable[]) =>\n\t\t\tw.postMessage(msg, targetOrigin, transferables),\n\t\taddEventListener: context.addEventListener.bind(context),\n\t\tremoveEventListener: context.removeEventListener.bind(context),\n\t};\n}\n\nfunction toWireValue(value: any): [WireValue, Transferable[]] {\n\tfor (const [name, handler] of transferHandlers) {\n\t\tif (handler.canHandle(value)) {\n\t\t\tconst [serializedValue, transferables] = handler.serialize(value);\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\ttype: WireValueType.HANDLER,\n\t\t\t\t\tname,\n\t\t\t\t\tvalue: serializedValue,\n\t\t\t\t},\n\t\t\t\ttransferables,\n\t\t\t];\n\t\t}\n\t}\n\treturn [\n\t\t{\n\t\t\ttype: WireValueType.RAW,\n\t\t\tvalue,\n\t\t},\n\t\ttransferCache.get(value) || [],\n\t];\n}\n\nfunction fromWireValue(value: WireValue): any {\n\tswitch (value.type) {\n\t\tcase WireValueType.HANDLER:\n\t\t\treturn transferHandlers.get(value.name)!.deserialize(value.value);\n\t\tcase WireValueType.RAW:\n\t\t\treturn value.value;\n\t}\n}\n\nfunction requestResponseMessage(\n\tep: Endpoint,\n\tpendingListeners: PendingListenersMap,\n\tmsg: Message,\n\ttransfers?: Transferable[]\n): Promise<WireValue> {\n\treturn new Promise((resolve) => {\n\t\tconst id = generateUUID();\n\t\tpendingListeners.set(id, resolve);\n\t\tif (ep.start) {\n\t\t\tep.start();\n\t\t}\n\t\tep.postMessage({ id, ...msg }, transfers);\n\t});\n}\n\nfunction generateUUID(): string {\n\treturn new Array(4)\n\t\t.fill(0)\n\t\t.map(() =>\n\t\t\tMath.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16)\n\t\t)\n\t\t.join('-');\n}\n\n// node-adapter.ts:\n\nexport interface NodeEndpoint {\n\tpostMessage(message: any, transfer?: any[]): void;\n\ton(\n\t\ttype: string,\n\t\tlistener: EventListenerOrEventListenerObject,\n\t\toptions?: object\n\t): void;\n\toff(\n\t\ttype: string,\n\t\tlistener: EventListenerOrEventListenerObject,\n\t\toptions?: object\n\t): void;\n\tstart?: () => void;\n}\n\nexport function nodeEndpoint(nep: NodeEndpoint): Endpoint {\n\tconst listeners = new WeakMap();\n\treturn {\n\t\tpostMessage: nep.postMessage.bind(nep),\n\t\taddEventListener: (_, eh) => {\n\t\t\tconst l = (data: any) => {\n\t\t\t\tif ('handleEvent' in eh) {\n\t\t\t\t\teh.handleEvent({ data } as MessageEvent);\n\t\t\t\t} else {\n\t\t\t\t\teh({ data } as MessageEvent);\n\t\t\t\t}\n\t\t\t};\n\t\t\tnep.on('message', l);\n\t\t\tlisteners.set(eh, l);\n\t\t},\n\t\tremoveEventListener: (_, eh) => {\n\t\t\tconst l = listeners.get(eh);\n\t\t\tif (!l) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tnep.off('message', l);\n\t\t\tlisteners.delete(eh);\n\t\t},\n\t\tstart: nep.start && nep.start.bind(nep),\n\t};\n}\n","import type { Endpoint } from './comlink-sync';\nimport type { EventEmitter } from 'events';\n\n// Handle the difference between EventEmitter (Node) and EventTarget (web).\nconst proxyByListener: WeakMap<\n\tEventListenerOrEventListenerObject,\n\t(...args: any[]) => void\n> = new WeakMap();\n\ntype EventEmitterWithSend = Pick<\n\tEventEmitter,\n\t'addListener' | 'removeListener'\n> & {\n\tsend?: (...args: any[]) => unknown;\n};\n\nexport interface NodeProcess {\n\tsend: (...args: any[]) => unknown;\n\taddListener: (\n\t\ttype: string,\n\t\tlistener: EventListenerOrEventListenerObject\n\t) => void;\n\tremoveListener: (\n\t\ttype: string,\n\t\tlistener: EventListenerOrEventListenerObject\n\t) => void;\n}\n\nexport function nodeProcessEndpoint(worker?: NodeProcess): Endpoint {\n\tconst emitter = (worker || process) as EventEmitter;\n\tif (typeof (emitter as EventEmitterWithSend).send !== 'function') {\n\t\tthrow new Error(\n\t\t\t'IPC channel is not available. Did you forget to fork the process?'\n\t\t);\n\t}\n\tconst emitterWithSend = emitter as EventEmitterWithSend;\n\n\treturn {\n\t\tpostMessage(message: unknown, _transferList?: Transferable[]) {\n\t\t\tif (_transferList && _transferList.length > 0) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t'Transferable objects are not supported for nodeProcessEndpoint'\n\t\t\t\t);\n\t\t\t}\n\t\t\temitterWithSend.send?.(message);\n\t\t},\n\n\t\taddEventListener(\n\t\t\ttype: string,\n\t\t\tlistener: EventListenerOrEventListenerObject\n\t\t) {\n\t\t\tconst proxy =\n\t\t\t\ttypeof listener === 'function'\n\t\t\t\t\t? (data: unknown) => listener({ data } as MessageEvent)\n\t\t\t\t\t: (data: unknown) =>\n\t\t\t\t\t\t\tlistener.handleEvent({ data } as MessageEvent);\n\t\t\tproxyByListener.set(listener, proxy);\n\t\t\temitterWithSend.addListener(type, proxy);\n\t\t},\n\n\t\tremoveEventListener(\n\t\t\ttype: string,\n\t\t\tlistener: EventListenerOrEventListenerObject\n\t\t) {\n\t\t\tconst proxy = proxyByListener.get(listener);\n\t\t\tif (!proxy) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tproxyByListener.delete(listener);\n\t\t\temitterWithSend.removeListener(type, proxy);\n\t\t},\n\n\t\tstart() {\n\t\t\t// EventEmitter-based endpoints do not need explicit start logic.\n\t\t},\n\t};\n}\n","/**\n * `serialize-error` package wrapped as a single file for compatibility\n * with both CJS and ESM.\n *\n * @see https://github.com/sindresorhus/serialize-error\n */\nconst list = [\n\t// Native ES errors https://262.ecma-international.org/12.0/#sec-well-known-intrinsic-objects\n\tError,\n\tEvalError,\n\tRangeError,\n\tReferenceError,\n\tSyntaxError,\n\tTypeError,\n\tURIError,\n\tAggregateError,\n\n\t// Built-in errors\n\tglobalThis.DOMException,\n\n\t// Node-specific errors\n\t// https://nodejs.org/api/errors.html\n\t(globalThis as any).AssertionError,\n\t(globalThis as any).SystemError,\n]\n\t// Non-native Errors are used with `globalThis` because they might be missing. This filter drops\n\t// them when undefined.\n\t.filter(Boolean)\n\t.map((constructor) => [constructor.name, constructor]);\n\nexport type ErrorObject = {\n\tname?: string;\n\tmessage?: string;\n\tstack?: string;\n\tcause?: unknown;\n\tcode?: string;\n} & Record<string, unknown>;\n\nexport const errorConstructors = new Map(list as any);\n\nexport function addKnownErrorConstructor(constructor: any) {\n\tconst { name } = constructor;\n\tif (errorConstructors.has(name)) {\n\t\tthrow new Error(`The error constructor \"${name}\" is already known.`);\n\t}\n\n\ttry {\n\t\t// eslint-disable-next-line no-new -- It just needs to be verified\n\t\tnew constructor();\n\t} catch (error) {\n\t\tthrow new Error(`The error constructor \"${name}\" is not compatible`, {\n\t\t\tcause: error,\n\t\t});\n\t}\n\n\terrorConstructors.set(name, constructor);\n}\n\nexport class NonError extends Error {\n\toverride name = 'NonError';\n\n\tconstructor(message: any) {\n\t\tsuper(NonError._prepareSuperMessage(message));\n\t}\n\n\tstatic _prepareSuperMessage(message: any) {\n\t\ttry {\n\t\t\treturn JSON.stringify(message);\n\t\t} catch {\n\t\t\treturn String(message);\n\t\t}\n\t}\n}\n\nconst errorProperties = [\n\t{\n\t\tproperty: 'name',\n\t\tenumerable: false,\n\t},\n\t{\n\t\tproperty: 'message',\n\t\tenumerable: false,\n\t},\n\t{\n\t\tproperty: 'stack',\n\t\tenumerable: false,\n\t},\n\t{\n\t\tproperty: 'code',\n\t\tenumerable: true,\n\t},\n\t{\n\t\tproperty: 'cause',\n\t\tenumerable: false,\n\t},\n\t{\n\t\tproperty: 'errors',\n\t\tenumerable: false,\n\t},\n];\n\nconst toJsonWasCalled = new WeakSet();\n\nconst toJSON = (from: any) => {\n\ttoJsonWasCalled.add(from);\n\tconst json = from.toJSON();\n\ttoJsonWasCalled.delete(from);\n\treturn json;\n};\n\nconst newError = (name: any) => {\n\tconst ErrorConstructor = errorConstructors.get(name) ?? (Error as any);\n\treturn ErrorConstructor === AggregateError\n\t\t? new ErrorConstructor([])\n\t\t: new ErrorConstructor();\n};\n\n// eslint-disable-next-line complexity\nconst destroyCircular = ({\n\tfrom,\n\tseen,\n\tto,\n\tforceEnumerable,\n\tmaxDepth,\n\tdepth,\n\tuseToJSON,\n\tserialize,\n}: {\n\tfrom?: any;\n\tseen: any[];\n\tto?: any;\n\tforceEnumerable: boolean;\n\tmaxDepth: number;\n\tdepth: number;\n\tuseToJSON: boolean;\n\tserialize: boolean;\n}) => {\n\tif (!to) {\n\t\tif (Array.isArray(from)) {\n\t\t\tto = [];\n\t\t} else if (!serialize && isErrorLike(from)) {\n\t\t\tto = newError(from.name);\n\t\t} else {\n\t\t\tto = {};\n\t\t}\n\t}\n\n\tseen.push(from);\n\n\tif (depth >= maxDepth) {\n\t\treturn to;\n\t}\n\n\tif (\n\t\tuseToJSON &&\n\t\ttypeof from.toJSON === 'function' &&\n\t\t!toJsonWasCalled.has(from)\n\t) {\n\t\treturn toJSON(from);\n\t}\n\n\tconst continueDestroyCircular = (value: any) =>\n\t\tdestroyCircular({\n\t\t\tfrom: value,\n\t\t\tseen: [...seen],\n\t\t\tforceEnumerable,\n\t\t\tmaxDepth,\n\t\t\tdepth,\n\t\t\tuseToJSON,\n\t\t\tserialize,\n\t\t});\n\n\tfor (const [key, value] of Object.entries(from)) {\n\t\tif (\n\t\t\tvalue &&\n\t\t\tvalue instanceof Uint8Array &&\n\t\t\tvalue.constructor.name === 'Buffer'\n\t\t) {\n\t\t\tto[key] = '[object Buffer]';\n\t\t\tcontinue;\n\t\t}\n\n\t\t// TODO: Use `stream.isReadable()` when targeting Node.js 18.\n\t\tif (\n\t\t\tvalue !== null &&\n\t\t\ttypeof value === 'object' &&\n\t\t\ttypeof (value as any).pipe === 'function'\n\t\t) {\n\t\t\tto[key] = '[object Stream]';\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (typeof value === 'function') {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (!value || typeof value !== 'object') {\n\t\t\t// Gracefully handle non-configurable errors like `DOMException`.\n\t\t\ttry {\n\t\t\t\tto[key] = value;\n\t\t\t} catch {\n\t\t\t\t// ignore\n\t\t\t}\n\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (!seen.includes(from[key])) {\n\t\t\tdepth++;\n\t\t\tto[key] = continueDestroyCircular(from[key]);\n\n\t\t\tcontinue;\n\t\t}\n\n\t\tto[key] = '[Circular]';\n\t}\n\n\tif (serialize || to instanceof Error) {\n\t\tfor (const { property, enumerable } of errorProperties) {\n\t\t\tif (from[property] !== undefined && from[property] !== null) {\n\t\t\t\tObject.defineProperty(to, property, {\n\t\t\t\t\tvalue:\n\t\t\t\t\t\tisErrorLike(from[property]) ||\n\t\t\t\t\t\tArray.isArray(from[property])\n\t\t\t\t\t\t\t? continueDestroyCircular(from[property])\n\t\t\t\t\t\t\t: from[property],\n\t\t\t\t\tenumerable: forceEnumerable ? true : enumerable,\n\t\t\t\t\tconfigurable: true,\n\t\t\t\t\twritable: true,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn to;\n};\n\nexport function serializeError(value: any, options: any = {}) {\n\tconst { maxDepth = Number.POSITIVE_INFINITY, useToJSON = true } = options;\n\n\tif (typeof value === 'object' && value !== null) {\n\t\treturn destroyCircular({\n\t\t\tfrom: value,\n\t\t\tseen: [],\n\t\t\tforceEnumerable: true,\n\t\t\tmaxDepth,\n\t\t\tdepth: 0,\n\t\t\tuseToJSON,\n\t\t\tserialize: true,\n\t\t});\n\t}\n\n\t// People sometimes throw things besides Error objects…\n\tif (typeof value === 'function') {\n\t\t// `JSON.stringify()` discards functions. We do too, unless a function is thrown directly.\n\t\t// We intentionally use `||` because `.name` is an empty string for anonymous functions.\n\t\treturn `[Function: ${value.name || 'anonymous'}]`;\n\t}\n\n\treturn value;\n}\n\nexport function deserializeError(value: any, options: any = {}) {\n\tconst { maxDepth = Number.POSITIVE_INFINITY } = options;\n\n\tif (value instanceof Error) {\n\t\treturn value;\n\t}\n\n\tif (isMinimumViableSerializedError(value)) {\n\t\treturn destroyCircular({\n\t\t\tfrom: value,\n\t\t\tseen: [],\n\t\t\tto: newError(value.name),\n\t\t\tmaxDepth,\n\t\t\tdepth: 0,\n\t\t\tserialize: false,\n\t\t} as any);\n\t}\n\n\treturn new NonError(value);\n}\n\nexport function isErrorLike(value: any) {\n\treturn (\n\t\tBoolean(value) &&\n\t\ttypeof value === 'object' &&\n\t\ttypeof value.name === 'string' &&\n\t\ttypeof value.message === 'string' &&\n\t\ttypeof value.stack === 'string'\n\t);\n}\n\n// Used as a weak check for immediately-passed objects, whereas `isErrorLike` is used for nested\n// values to avoid bad detection\nfunction isMinimumViableSerializedError(value: any) {\n\t// @ts-ignore\n\treturn (\n\t\tBoolean(value) &&\n\t\ttypeof value === 'object' &&\n\t\ttypeof value.message === 'string' &&\n\t\t!Array.isArray(value)\n\t);\n}\n","import type { PHPResponseData } from './php-response';\nimport { PHPResponse, StreamedPHPResponse } from './php-response';\nimport * as Comlink from './comlink-sync';\nimport {\n\tNodeSABSyncReceiveMessageTransport,\n\tnodeEndpoint as nodeWorkerEndpoint,\n\treleaseProxy,\n\ttype NodeEndpoint as NodeWorker,\n\ttype Remote,\n\ttype Endpoint,\n\ttype IsomorphicMessagePort,\n\ttype ProxyMethods,\n} from './comlink-sync';\nimport {\n\ttype NodeProcess,\n\tnodeProcessEndpoint,\n} from './comlink-node-process-adapter';\nimport * as ErrorSerializer from './serialize-error';\n\n// NOTE: It seems like we wouldn't have to explicitly specify\n// symbol type here, but it seems to resolve some type errors.\nexport const releaseApiProxy: typeof releaseProxy = releaseProxy;\n\nexport type WithAPIState = {\n\t/**\n\t * Resolves to true when the remote API is ready for\n\t * Comlink communication, but not necessarily fully initialized yet.\n\t */\n\tisConnected: () => Promise<void>;\n\t/**\n\t * Resolves to true when the remote API is declares it's\n\t * fully loaded and ready to be used.\n\t */\n\tisReady: () => Promise<void>;\n};\nexport type RemoteAPI<T> = Remote<T> & ProxyMethods & WithAPIState;\n\nexport async function consumeAPISync<APIType>(\n\tremote: IsomorphicMessagePort\n): Promise<APIType> {\n\tsetupTransferHandlers();\n\tconst transport = await NodeSABSyncReceiveMessageTransport.create();\n\treturn Comlink.wrapSync<APIType>(remote, transport);\n}\n\nexport function consumeAPI<APIType>(\n\tremote: Worker | Window | NodeWorker | NodeProcess,\n\tcontext: undefined | EventTarget = undefined\n): RemoteAPI<APIType> {\n\tsetupTransferHandlers();\n\n\tlet endpoint;\n\t/**\n\t * Previously we assumed we were running in a Node.js environment\n\t * when `import.meta.url` started with `file://`. But this assumption breaks\n\t * with webpack which emits file URLs for `import.meta.url`.\n\t * https://webpack.js.org/api/module-variables/#importmetaurl\n\t * \n\t * We replaced this with a more explicit check for `process.versions.node`.\n\t * See https://github.com/WordPress/wordpress-playground/pull/3248\n\t */\n\tconst appearsToBeNodeEnvironment =\n\t\ttypeof process !== 'undefined' &&\n\t\ttypeof process.versions !== 'undefined' &&\n\t\ttypeof process.versions.node !== 'undefined';\n\tif (appearsToBeNodeEnvironment) {\n\t\tif ('postMessage' in remote) {\n\t\t\tendpoint = nodeWorkerEndpoint(remote as NodeWorker);\n\t\t} else if ('send' in remote && 'addListener' in remote) {\n\t\t\tendpoint = nodeProcessEndpoint(remote as NodeProcess);\n\t\t} else {\n\t\t\tthrow new Error(\n\t\t\t\t'consumeAPI: remote does not look like a Worker, MessagePort, or Process'\n\t\t\t);\n\t\t}\n\t} else {\n\t\tendpoint =\n\t\t\tremote instanceof Worker\n\t\t\t\t? remote\n\t\t\t\t: Comlink.windowEndpoint(remote as Window, context);\n\t}\n\n\t/**\n\t * This shouldn't be necessary, but Comlink doesn't seem to\n\t * handle the initial isConnected() call correctly unless it's\n\t * explicitly provided here. This is especially weird\n\t * since the only thing this proxy does is to call the\n\t * isConnected() method on the remote API.\n\t *\n\t * @TODO: Remove this workaround.\n\t */\n\tconst api = Comlink.wrap<APIType & WithAPIState>(endpoint);\n\tconst methods = proxyClone(api);\n\treturn new Proxy(methods, {\n\t\tget: (target, prop) => {\n\t\t\tif (prop === 'isConnected') {\n\t\t\t\treturn async () => {\n\t\t\t\t\t// Keep retrying until the remote API confirms it's connected.\n\t\t\t\t\twhile (true) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tawait runWithTimeout(api.isConnected(), 200);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// Timeout exceeded, try again. We can't just use a single\n\t\t\t\t\t\t\t// `runWithTimeout` call because it won't reach the remote API\n\t\t\t\t\t\t\t// if it's not connected yet. Instead, we need to keep retrying\n\t\t\t\t\t\t\t// until the remote API is connected and registers a handler\n\t\t\t\t\t\t\t// for the `isConnected` method.\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn (api as any)[prop];\n\t\t},\n\t}) as unknown as RemoteAPI<APIType>;\n}\n\nasync function runWithTimeout<T>(\n\tpromise: Promise<T>,\n\ttimeout: number\n): Promise<T> {\n\treturn new Promise<T>((resolve, reject) => {\n\t\tsetTimeout(reject, timeout);\n\t\tpromise.then(resolve);\n\t});\n}\n\nexport type PublicAPI<Methods, PipedAPI = unknown> = RemoteAPI<\n\tMethods & PipedAPI\n>;\n\nexport function exposeAPI<Methods, PipedAPI>(\n\tapiMethods?: Methods,\n\tpipedApi?: PipedAPI,\n\ttargetWorker?: MessagePort | NodeWorker | NodeProcess\n): [() => void, (e: Error) => void, PublicAPI<Methods, PipedAPI>] {\n\tconst { setReady, setFailed, exposedApi } = prepareForExpose(\n\t\tapiMethods,\n\t\tpipedApi\n\t);\n\tlet endpoint: Endpoint | undefined;\n\tif (targetWorker) {\n\t\tif ('addEventListener' in targetWorker) {\n\t\t\t// TODO: MessagePort satisfies Endpoint at runtime but its\n\t\t\t// addEventListener overloads don't exactly match EventSource.\n\t\t\tendpoint = targetWorker as Endpoint;\n\t\t} else if ('postMessage' in targetWorker) {\n\t\t\tendpoint = nodeWorkerEndpoint(targetWorker);\n\t\t} else if ('send' in targetWorker && 'addListener' in targetWorker) {\n\t\t\tendpoint = nodeProcessEndpoint(targetWorker);\n\t\t} else {\n\t\t\tthrow new Error(\n\t\t\t\t'exposeAPI: targetWorker does not look like a Worker, MessagePort, or Process'\n\t\t\t);\n\t\t}\n\t} else {\n\t\tendpoint =\n\t\t\ttypeof window !== 'undefined'\n\t\t\t\t? Comlink.windowEndpoint(self.parent)\n\t\t\t\t: undefined;\n\t}\n\tComlink.expose(exposedApi, endpoint);\n\treturn [setReady, setFailed, exposedApi as PublicAPI<Methods, PipedAPI>];\n}\n\nexport async function exposeSyncAPI<Methods>(\n\tapiMethods: Methods,\n\tport: IsomorphicMessagePort\n): Promise<[() => void, (e: Error) => void, Methods]> {\n\tconst { setReady, setFailed, exposedApi } = prepareForExpose(apiMethods);\n\tconst transport = await NodeSABSyncReceiveMessageTransport.create();\n\tconst endpoint = nodeWorkerEndpoint(port as any);\n\tComlink.exposeSync(exposedApi, endpoint, transport);\n\treturn [setReady, setFailed, exposedApi as Methods];\n}\n\nfunction prepareForExpose<Methods, PipedAPI>(\n\tapiMethods?: Methods,\n\tpipedApi?: PipedAPI\n) {\n\tsetupTransferHandlers();\n\n\tconst connected = Promise.resolve();\n\n\tlet setReady: any;\n\tlet setFailed: any;\n\tconst ready = new Promise((resolve, reject) => {\n\t\tsetReady = resolve;\n\t\tsetFailed = reject;\n\t});\n\n\tconst methods = proxyClone(apiMethods);\n\tconst exposedApi = new Proxy(methods, {\n\t\tget: (target, prop) => {\n\t\t\tif (prop === 'isConnected') {\n\t\t\t\treturn () => connected;\n\t\t\t} else if (prop === 'isReady') {\n\t\t\t\treturn () => ready;\n\t\t\t} else if (prop in target) {\n\t\t\t\treturn target[prop];\n\t\t\t}\n\t\t\treturn (pipedApi as any)?.[prop];\n\t\t},\n\t}) as unknown as PublicAPI<Methods, PipedAPI>;\n\n\treturn { setReady, setFailed, exposedApi };\n}\n\nlet isTransferHandlersSetup = false;\nfunction setupTransferHandlers() {\n\tif (isTransferHandlersSetup) {\n\t\treturn;\n\t}\n\tisTransferHandlersSetup = true;\n\tComlink.transferHandlers.set('EVENT', {\n\t\tcanHandle: (obj): obj is CustomEvent => obj instanceof CustomEvent,\n\t\tserialize: (ev: CustomEvent) => {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tdetail: ev.detail,\n\t\t\t\t},\n\t\t\t\t[],\n\t\t\t];\n\t\t},\n\t\tdeserialize: (obj) => obj,\n\t});\n\tComlink.transferHandlers.set('FUNCTION', {\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n\t\tcanHandle: (obj: unknown): obj is Function => typeof obj === 'function',\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n\t\tserialize(obj: Function) {\n\t\t\tconst { port1, port2 } = new MessageChannel();\n\t\t\tComlink.expose(obj, port1);\n\t\t\treturn [port2, [port2]];\n\t\t},\n\t\tdeserialize(port: any) {\n\t\t\tport.start();\n\t\t\treturn Comlink.wrap(port);\n\t\t},\n\t});\n\tComlink.transferHandlers.set('MESSAGE_PORT', {\n\t\tcanHandle: (obj: unknown): obj is MessagePort =>\n\t\t\tobj instanceof MessagePort,\n\t\tserialize(port: MessagePort): [MessagePort, Transferable[]] {\n\t\t\treturn [port, [port]];\n\t\t},\n\t\tdeserialize(port: MessagePort): MessagePort {\n\t\t\treturn port;\n\t\t},\n\t});\n\tComlink.transferHandlers.set('PHPResponse', {\n\t\tcanHandle: (obj: unknown): obj is PHPResponseData =>\n\t\t\ttypeof obj === 'object' &&\n\t\t\tobj !== null &&\n\t\t\t'headers' in obj &&\n\t\t\t'bytes' in obj &&\n\t\t\t'errors' in obj &&\n\t\t\t'exitCode' in obj &&\n\t\t\t'httpStatusCode' in obj,\n\t\tserialize(obj: PHPResponse): [PHPResponseData, Transferable[]] {\n\t\t\tconst data = obj.toRawData();\n\t\t\t// Transfer the ArrayBuffer instead of cloning it to avoid\n\t\t\t// \"could not be cloned\" errors when the buffer is detached\n\t\t\tconst transferables: Transferable[] = [];\n\t\t\tif (data.bytes.buffer.byteLength > 0) {\n\t\t\t\ttransferables.push(data.bytes.buffer);\n\t\t\t}\n\t\t\treturn [data, transferables];\n\t\t},\n\t\tdeserialize(responseData: PHPResponseData): PHPResponse {\n\t\t\treturn PHPResponse.fromRawData(responseData);\n\t\t},\n\t});\n\t// Augment Comlink's throw handler to include Error the response and source\n\t// information in the serialized error object. BasePHP may throw\n\t// PHPExecutionFailureError which includes those information and we'll want to\n\t// display them for the user.\n\tconst throwHandler = Comlink.transferHandlers.get('throw')!;\n\tconst originalSerialize = throwHandler?.serialize;\n\tthrowHandler.serialize = ({ value }: any) => {\n\t\tconst serialized = originalSerialize({ value }) as any;\n\t\tif (value.response) {\n\t\t\tserialized[0].value.response = value.response;\n\t\t}\n\t\tif (value.source) {\n\t\t\tserialized[0].value.source = value.source;\n\t\t}\n\t\treturn serialized;\n\t};\n\n\tComlink.transferHandlers.set('StreamedPHPResponse', {\n\t\tcanHandle: (obj: unknown): obj is StreamedPHPResponse =>\n\t\t\tobj instanceof StreamedPHPResponse,\n\t\tserialize(obj: StreamedPHPResponse): [any, Transferable[]] {\n\t\t\tconst supportsStreams = supportsTransferableStreams();\n\t\t\tconst exitCodePort = promiseToPort(obj.exitCode);\n\t\t\tif (supportsStreams) {\n\t\t\t\tconst payload = {\n\t\t\t\t\t__type: 'StreamedPHPResponse',\n\t\t\t\t\theaders: (obj as any)['headersStream'],\n\t\t\t\t\tstdout: obj.stdout,\n\t\t\t\t\tstderr: obj.stderr,\n\t\t\t\t\texitCodePort,\n\t\t\t\t};\n\t\t\t\treturn [payload, [exitCodePort]];\n\t\t\t}\n\t\t\t// Fallback: bridge streams via MessagePorts\n\t\t\tconst headersPort = streamToPort((obj as any)['headersStream']);\n\t\t\tconst stdoutPort = streamToPort(obj.stdout);\n\t\t\tconst stderrPort = streamToPort(obj.stderr);\n\t\t\tconst payload = {\n\t\t\t\t__type: 'StreamedPHPResponse',\n\t\t\t\theadersPort,\n\t\t\t\tstdoutPort,\n\t\t\t\tstderrPort,\n\t\t\t\texitCodePort,\n\t\t\t};\n\t\t\treturn [\n\t\t\t\tpayload,\n\t\t\t\t[headersPort, stdoutPort, stderrPort, exitCodePort],\n\t\t\t];\n\t\t},\n\t\tdeserialize(data: any): StreamedPHPResponse {\n\t\t\tif (data.headers && data.stdout && data.stderr) {\n\t\t\t\tconst exitCode = portToPromise(\n\t\t\t\t\tdata.exitCodePort as MessagePort\n\t\t\t\t);\n\t\t\t\treturn new StreamedPHPResponse(\n\t\t\t\t\tdata.headers as ReadableStream<Uint8Array>,\n\t\t\t\t\tdata.stdout as ReadableStream<Uint8Array>,\n\t\t\t\t\tdata.stderr as ReadableStream<Uint8Array>,\n\t\t\t\t\texitCode\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst headers = portToStream(data.headersPort as MessagePort);\n\t\t\tconst stdout = portToStream(data.stdoutPort as MessagePort);\n\t\t\tconst stderr = portToStream(data.stderrPort as MessagePort);\n\t\t\tconst exitCode = portToPromise(data.exitCodePort as MessagePort);\n\t\t\treturn new StreamedPHPResponse(headers, stdout, stderr, exitCode);\n\t\t},\n\t});\n}\n\n// Utilities for transferring ReadableStreams and Promises via MessagePorts:\n\n/**\n * Safari does not support transferable streams, so we need to fallback to\n * MessagePorts.\n * Feature-detects whether this runtime supports transferring ReadableStreams\n * directly through postMessage (aka \"transferable streams\"). When false,\n * we must fall back to port-bridged streaming.\n */\nfunction supportsTransferableStreams(): boolean {\n\ttry {\n\t\tif (typeof ReadableStream === 'undefined') return false;\n\t\tconst { port1 } = new MessageChannel();\n\t\tconst rs = new ReadableStream();\n\t\tport1.postMessage(rs as any);\n\t\ttry {\n\t\t\tport1.close();\n\t\t} catch (_e) {\n\t\t\tvoid _e;\n\t\t}\n\t\treturn true;\n\t} catch (_e) {\n\t\tvoid _e;\n\t\treturn false;\n\t}\n}\n\n/**\n * Bridges a ReadableStream to a MessagePort by reading chunks and posting\n * messages to the port. Used as a fallback when transferable streams are not\n * supported (e.g., Safari).\n *\n * Protocol of the returned MessagePort:\n *\n * { t: 'chunk', b: ArrayBuffer } – next binary chunk\n * { t: 'close' } – end of stream\n * { t: 'error', m: string } – terminal error\n */\nfunction streamToPort(stream: ReadableStream<Uint8Array>): MessagePort {\n\tconst { port1, port2 } = new MessageChannel();\n\t(async () => {\n\t\tconst reader = stream.getReader();\n\t\ttry {\n\t\t\twhile (true) {\n\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\tif (done) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tport1.postMessage({ t: 'close' });\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Ignore error\n\t\t\t\t\t}\n\t\t\t\t\ttry {\n\t\t\t\t\t\tport1.close();\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Ignore error\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif (value) {\n\t\t\t\t\t// Ensure we transfer an owned buffer\n\t\t\t\t\tconst owned =\n\t\t\t\t\t\tvalue.byteOffset === 0 &&\n\t\t\t\t\t\tvalue.byteLength === value.buffer.byteLength\n\t\t\t\t\t\t\t? value\n\t\t\t\t\t\t\t: value.slice();\n\t\t\t\t\tconst buf = owned.buffer;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tport1.postMessage({ t: 'chunk', b: buf }, [\n\t\t\t\t\t\t\tbuf as unknown as Transferable,\n\t\t\t\t\t\t]);\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tport1.postMessage({\n\t\t\t\t\t\t\tt: 'chunk',\n\t\t\t\t\t\t\tb: owned.buffer.slice(0),\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (e: any) {\n\t\t\ttry {\n\t\t\t\tport1.postMessage({ t: 'error', m: e?.message || String(e) });\n\t\t\t} catch {\n\t\t\t\t// Ignore error\n\t\t\t}\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tport1.close();\n\t\t\t} catch {\n\t\t\t\t// Ignore error\n\t\t\t}\n\t\t}\n\t})();\n\treturn port2;\n}\n\n/**\n * Reconstructs a ReadableStream from a MessagePort using the inverse of the\n * streamToPort protocol. Each message enqueues data, closes, or errors.\n */\nfunction portToStream(port: MessagePort): ReadableStream<Uint8Array> {\n\treturn new ReadableStream<Uint8Array>({\n\t\tstart(controller) {\n\t\t\tconst onMessage = (ev: MessageEvent) => {\n\t\t\t\tconst data: any = (ev as any).data;\n\t\t\t\tif (!data) return;\n\t\t\t\tswitch (data.t) {\n\t\t\t\t\tcase 'chunk':\n\t\t\t\t\t\tcontroller.enqueue(new Uint8Array(data.b));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'close':\n\t\t\t\t\t\tcontroller.close();\n\t\t\t\t\t\tcleanup();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'error':\n\t\t\t\t\t\tcontroller.error(new Error(data.m || 'Stream error'));\n\t\t\t\t\t\tcleanup();\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t};\n\t\t\tconst cleanup = () => {\n\t\t\t\ttry {\n\t\t\t\t\tport.removeEventListener?.('message', onMessage as any);\n\t\t\t\t} catch {\n\t\t\t\t\t// Ignore error\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tport.onmessage = null;\n\t\t\t\t} catch {\n\t\t\t\t\t// Ignore error\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tport.close();\n\t\t\t\t} catch {\n\t\t\t\t\t// Ignore error\n\t\t\t\t}\n\t\t\t};\n\t\t\tif (port.addEventListener) {\n\t\t\t\tport.addEventListener('message', onMessage as any);\n\t\t\t} else if ((port as any).on) {\n\t\t\t\t(port as any).on('message', (data: any) =>\n\t\t\t\t\tonMessage({ data } as any)\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tport.onmessage = onMessage as any;\n\t\t\t}\n\t\t\tif (typeof port.start === 'function') {\n\t\t\t\tport.start();\n\t\t\t}\n\t\t},\n\t\tcancel() {\n\t\t\ttry {\n\t\t\t\tport.close();\n\t\t\t} catch {\n\t\t\t\t// Ignore error\n\t\t\t}\n\t\t},\n\t});\n}\n\n/**\n * Bridges a Promise to a MessagePort so it can be delivered across threads.\n *\n * Protocol of the returned MessagePort:\n *\n * { t: 'resolve', v: any } – promise resolved with value v\n * { t: 'reject', m: str } – promise rejected with message m\n */\nfunction promiseToPort(promise: Promise<any>): MessagePort {\n\tconst { port1, port2 } = new MessageChannel();\n\tpromise\n\t\t.then((value) => {\n\t\t\ttry {\n\t\t\t\tport1.postMessage({ t: 'resolve', v: value });\n\t\t\t} catch {\n\t\t\t\t// Ignore error\n\t\t\t}\n\t\t})\n\t\t.catch((err) => {\n\t\t\ttry {\n\t\t\t\tport1.postMessage({\n\t\t\t\t\tt: 'reject',\n\t\t\t\t\tm: (err as any)?.message || String(err),\n\t\t\t\t});\n\t\t\t} catch {\n\t\t\t\t// Ignore error\n\t\t\t}\n\t\t})\n\t\t.finally(() => {\n\t\t\ttry {\n\t\t\t\tport1.close();\n\t\t\t} catch {\n\t\t\t\t// Ignore error\n\t\t\t}\n\t\t});\n\treturn port2;\n}\n\n/**\n * Reconstructs a Promise from a MessagePort using the inverse of\n * promiseToPort. Resolves or rejects when the corresponding message arrives.\n */\nfunction portToPromise(port: MessagePort): Promise<any> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst onMessage = (ev: MessageEvent) => {\n\t\t\tconst data: any = (ev as any).data;\n\t\t\tif (!data) return;\n\t\t\tif (data.t === 'resolve') {\n\t\t\t\tcleanup();\n\t\t\t\tresolve(data.v);\n\t\t\t} else if (data.t === 'reject') {\n\t\t\t\tcleanup();\n\t\t\t\treject(new Error(data.m || ''));\n\t\t\t}\n\t\t};\n\t\tconst cleanup = () => {\n\t\t\ttry {\n\t\t\t\tport.removeEventListener?.('message', onMessage as any);\n\t\t\t} catch {\n\t\t\t\t// Ignore error\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tport.onmessage = null;\n\t\t\t} catch {\n\t\t\t\t// Ignore error\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tport.close();\n\t\t\t} catch {\n\t\t\t\t// Ignore error\n\t\t\t}\n\t\t};\n\t\tif (port.addEventListener) {\n\t\t\tport.addEventListener('message', onMessage as any);\n\t\t} else if ((port as any).on) {\n\t\t\t(port as any).on('message', (data: any) =>\n\t\t\t\tonMessage({ data } as any)\n\t\t\t);\n\t\t} else {\n\t\t\tport.onmessage = onMessage as any;\n\t\t}\n\t\tif (typeof port.start === 'function') {\n\t\t\tport.start();\n\t\t}\n\t});\n}\n\n// Augment Comlink's throw handler to include all the information carried by\n// the thrown object, including the cause, additional properties, etc.\ninterface UnserializedError {\n\tvalue: unknown;\n}\ntype SerializedError =\n\t| { isError: true; value: ErrorSerializer.ErrorObject }\n\t| { isError: false; value: unknown };\n\nconst throwTransferHandler = Comlink.transferHandlers.get(\n\t'throw'\n) as Comlink.TransferHandler<UnserializedError, SerializedError>;\n\nconst throwTransferHandlerCustom: Comlink.TransferHandler<\n\tUnserializedError,\n\tSerializedError\n> = {\n\tcanHandle: throwTransferHandler.canHandle,\n\tserialize: ({ value }) => {\n\t\tlet serialized: SerializedError;\n\t\tif (value instanceof Error) {\n\t\t\tserialized = {\n\t\t\t\tisError: true,\n\t\t\t\tvalue: ErrorSerializer.serializeError(value),\n\t\t\t};\n\t\t\t// The error class name is not serialized by serialize-error, let's add it manually.\n\t\t\tserialized.value['originalErrorClassName'] = value.constructor.name;\n\t\t} else {\n\t\t\tserialized = { isError: false, value };\n\t\t}\n\t\treturn [serialized, []];\n\t},\n\tdeserialize: (serialized) => {\n\t\tif (serialized.isError) {\n\t\t\tconst error = ErrorSerializer.deserializeError(serialized.value);\n\t\t\t/**\n\t\t\t * The original error from the web worker does not include any call\n\t\t\t * stack from the Playground web app. Let's include that information\n\t\t\t * in the error chain.\n\t\t\t *\n\t\t\t * We'll place it at the bottom of the error chain. This way the API\n\t\t\t * consumer gets the original error object and not an opaque\n\t\t\t * \"Comlink method call failed\" error, but they can still inspect\n\t\t\t * it further to see the full call stack.\n\t\t\t */\n\t\t\tconst additionalCallStack = new Error('Comlink method call failed');\n\t\t\tlet deepestError = error;\n\t\t\twhile (deepestError.cause) {\n\t\t\t\tdeepestError = deepestError.cause;\n\t\t\t}\n\t\t\tdeepestError.cause = additionalCallStack;\n\t\t\tthrow error;\n\t\t}\n\t\tthrow serialized.value;\n\t},\n};\n\nComlink.transferHandlers.set('throw', throwTransferHandlerCustom);\n\nfunction proxyClone(object: any): any {\n\treturn new Proxy(object, {\n\t\tget(target, prop) {\n\t\t\tswitch (typeof target[prop]) {\n\t\t\t\tcase 'function':\n\t\t\t\t\treturn (...args: any[]) => target[prop](...args);\n\t\t\t\tcase 'object':\n\t\t\t\t\tif (target[prop] === null) {\n\t\t\t\t\t\treturn target[prop];\n\t\t\t\t\t}\n\t\t\t\t\treturn proxyClone(target[prop]);\n\t\t\t\tcase 'undefined':\n\t\t\t\tcase 'number':\n\t\t\t\tcase 'string':\n\t\t\t\t\treturn target[prop];\n\t\t\t\tdefault:\n\t\t\t\t\treturn Comlink.proxy(target[prop]);\n\t\t\t}\n\t\t},\n\t});\n}\n","export const MAX_ADDRESSABLE_FILE_OFFSET = BigInt(Number.MAX_SAFE_INTEGER);\n// TODO: Use this BigInt once the native fs-ext-extra-prebuilt package supports it.\n//BigInt(2n ** 64n - 1n);\n\n/*\n * NOTE: These types are not important structurally,\n * but it helps clarity to use these aliases when making\n * data structures based on them.\n *\n * For example, the type\n * `Map<Path, Map<Pid, Map<Fd, WholeFileLockOp>>>`\n * conveys more intention to a reader than\n * `Map<string, Map<number, Map<number, WholeFileLockOp>>>`.\n */\nexport type Path = string;\nexport type Pid = number;\nexport type Fd = number;\n\n/**\n * This is an interface used to abstract byte range locking like fcntl()\n * and whole-file locking like flock().\n */\nexport type FileLockManager = {\n\t/**\n\t * Update the lock on the whole file.\n\t *\n\t * This method is for updating the lock on the whole file with the F_SETLKW fcntl() command.\n\t * https://sourceware.org/glibc/manual/2.41/html_node/File-Locks.html#index-F_005fSETLKW-1\n\t *\n\t * @param path - The path of the file to lock. This should be the path of the file in the\n\t * underlying filesystem.\n\t * @param op - The operation to perform, including 'shared', 'exclusive', or 'unlock'.\n\t * @returns A promise for a boolean value.\n\t */\n\tlockWholeFile: (path: Path, op: WholeFileLockOp) => boolean;\n\n\t/**\n\t * Update the lock on a byte range of a file.\n\t *\n\t * This method is for locking with the F_SETLK fcntl() command.\n\t * https://sourceware.org/glibc/manual/2.41/html_node/File-Locks.html#index-F_005fSETLK-1\n\t *\n\t * @param path - The path of the file to lock. This should be the path of the file in the\n\t * underlying filesystem.\n\t * @param requestedLock - The lock to request, including start, end, type, and pid.\n\t * @param waitForLock - Whether to block until the lock is acquired.\n\t * @returns A promise for a boolean value.\n\t * When locking: True if the lock was acquired, false if it was not.\n\t * When unlocking: Always true.\n\t */\n\tlockFileByteRange: (\n\t\tpath: Path,\n\t\trequestedLock: RequestedRangeLock,\n\t\twaitForLock: boolean\n\t) => boolean;\n\n\t/**\n\t * Get the first lock that would conflict with the specified lock.\n\t *\n\t * This method is meant to satisfy the needs of the F_GETLK fcntl() command.\n\t * https://sourceware.org/glibc/manual/2.41/html_node/File-Locks.html#index-F_005fGETLK-1\n\t *\n\t * @param path - The path of the file to check for conflicts. This should be the path\n\t * of the file in the underlying filesystem.\n\t * @param desiredLock - The lock to check for conflicts.\n\t * @returns A promise for the first conflicting lock,\n\t * or undefined if there is no conflict.\n\t */\n\tfindFirstConflictingByteRangeLock: (\n\t\tpath: Path,\n\t\tdesiredLock: RequestedRangeLock\n\t) => Omit<RequestedRangeLock, 'fd'> | undefined;\n\n\t/**\n\t * Release all locks for a given process.\n\t *\n\t * Used when a process exits or is otherwise terminated.\n\t *\n\t * @param pid - The PID of the process that wants to release the locks.\n\t */\n\treleaseLocksForProcess: (pid: number) => void;\n\n\t/**\n\t * Release all locks for the given process and file descriptor.\n\t *\n\t * @param pid The process ID to release locks for.\n\t * @param fd The file descriptor to release locks for.\n\t * @param path The path to the file to release locks for. This should be the path\n\t * of the file in the underlying filesystem.\n\t */\n\treleaseLocksOnFdClose: (pid: number, fd: number, path: Path) => void;\n};\n\nexport type ByteRange = {\n\tstart: bigint;\n\t// TODO: How to support special treatment of Infinity?\n\tend: bigint;\n};\n\nexport type RequestedRangeLock = ByteRange & {\n\t/**\n\t * The type of lock request\n\t */\n\ttype: 'shared' | 'exclusive' | 'unlocked';\n\t/**\n\t * The file descriptor to use. This should be the native file descriptor,\n\t * not the Emscripten file descriptor because it may be used to lock the file\n\t * using native OS file locking APIs.\n\t */\n\tfd: Fd;\n\t/** The process ID that owns this lock */\n\tpid: Pid;\n};\n\nexport type LockedRange = RequestedRangeLock & {\n\ttype: Exclude<RequestedRangeLock['type'], 'unlocked'>;\n};\n\nexport type ConflictingLockedRange = Omit<LockedRange, 'fd'>;\n\nexport type WholeFileLock = Readonly<\n\tWholeFileLock_Exclusive | WholeFileLock_Shared | WholeFileLock_Unlocked\n>;\n\nexport type WholeFileLock_Exclusive = {\n\ttype: 'exclusive';\n\tpid: Pid;\n\tfd: Fd;\n};\nexport type WholeFileLock_Shared = {\n\ttype: 'shared';\n\t/**\n\t * NOTE: flock() locks are associated with open file descriptors and duplicated file descriptors.\n\t * We do not currently recognize duplicate file descriptors.\n\t */\n\tpidFds: Map<Pid, Set<Fd>>;\n};\nexport type WholeFileLock_Unlocked = {\n\ttype: 'unlocked';\n};\n\nexport type WholeFileLockOp =\n\t| {\n\t\t\tpid: number;\n\t\t\tfd: number;\n\t\t\ttype: 'shared' | 'exclusive';\n\t\t\t/** Whether to block until the lock is acquired. */\n\t\t\twaitForLock: boolean;\n\t }\n\t| {\n\t\t\tpid: number;\n\t\t\tfd: number;\n\t\t\ttype: 'unlock';\n\t };\n","import type {\n\tByteRange,\n\tLockedRange,\n\tRequestedRangeLock,\n} from './file-lock-manager';\n\nclass IntervalNode {\n\trange: LockedRange;\n\tmax: bigint;\n\tleft: IntervalNode | null = null;\n\tright: IntervalNode | null = null;\n\n\tconstructor(range: LockedRange) {\n\t\tthis.range = range;\n\t\tthis.max = range.end;\n\t}\n}\n\nexport class FileLockIntervalTree {\n\tprivate root: IntervalNode | null = null;\n\n\tisEmpty() {\n\t\treturn this.root === null;\n\t}\n\n\t/**\n\t * Insert a new locked range into the tree\n\t */\n\tinsert(range: LockedRange): void {\n\t\tthis.root = this.insertNode(this.root, range);\n\t}\n\n\t/**\n\t * Find all ranges that overlap with the given range\n\t */\n\tfindOverlapping(range: ByteRange): LockedRange[] {\n\t\tconst result: LockedRange[] = [];\n\t\tthis.findOverlappingRanges(this.root, range, result);\n\t\treturn result;\n\t}\n\n\t/**\n\t * Remove a lock range from the tree\n\t */\n\tremove(range: RequestedRangeLock): void {\n\t\tthis.root = this.removeNode(this.root, range);\n\t}\n\n\t/**\n\t * Find all ranges locked by the given process.\n\t *\n\t * @param pid The process ID to find locks for.\n\t * @returns All locked ranges for the given process.\n\t */\n\tfindLocksForProcess(pid: number): RequestedRangeLock[] {\n\t\tconst result: RequestedRangeLock[] = [];\n\t\tthis.findLocksForProcessInNode(this.root, pid, result);\n\t\treturn result;\n\t}\n\n\t/**\n\t * Find the strictest existing lock type in the range lock tree.\n\t *\n\t * @returns The strictest existing lock type, or 'unlocked' if no locks exist.\n\t */\n\tfindStrictestExistingLockType(): RequestedRangeLock['type'] {\n\t\tlet maxType: RequestedRangeLock['type'] = 'unlocked';\n\n\t\tconst traverse = (node: IntervalNode | null) => {\n\t\t\tif (!node) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (node.range.type === 'exclusive') {\n\t\t\t\tmaxType = 'exclusive';\n\t\t\t\treturn; // Can stop early since exclusive is highest\n\t\t\t}\n\t\t\tif (node.range.type === 'shared') {\n\t\t\t\tmaxType = 'shared';\n\t\t\t}\n\t\t\ttraverse(node.left);\n\t\t\ttraverse(node.right);\n\t\t};\n\t\ttraverse(this.root);\n\n\t\treturn maxType;\n\t}\n\n\tprivate insertNode(\n\t\tnode: IntervalNode | null,\n\t\trange: LockedRange\n\t): IntervalNode {\n\t\tif (!node) {\n\t\t\treturn new IntervalNode(range);\n\t\t}\n\n\t\t// Insert to left subtree if start is less than node's start\n\t\tif (range.start < node.range.start) {\n\t\t\tnode.left = this.insertNode(node.left, range);\n\t\t} else {\n\t\t\tnode.right = this.insertNode(node.right, range);\n\t\t}\n\n\t\t// Update max value\n\t\tnode.max = this.bigintMax(node.max, range.end);\n\t\treturn node;\n\t}\n\n\tprivate bigintMax(...args: bigint[]): bigint {\n\t\treturn args.reduce((max, current) => {\n\t\t\treturn current > max ? current : max;\n\t\t}, args[0]);\n\t}\n\n\tprivate findOverlappingRanges(\n\t\tnode: IntervalNode | null,\n\t\trange: ByteRange,\n\t\tresult: LockedRange[]\n\t): void {\n\t\tif (!node) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Check if current node overlaps\n\t\tif (this.doRangesOverlap(node.range, range)) {\n\t\t\tresult.push(node.range);\n\t\t}\n\n\t\t// If left child exists and its max is greater than range start, search left\n\t\tif (node.left && node.left.max >= range.start) {\n\t\t\tthis.findOverlappingRanges(node.left, range, result);\n\t\t}\n\n\t\t// Search right if it could contain overlapping intervals\n\t\tif (node.right && node.range.start <= range.end) {\n\t\t\tthis.findOverlappingRanges(node.right, range, result);\n\t\t}\n\t}\n\n\tprivate doRangesOverlap(a: ByteRange, b: ByteRange): boolean {\n\t\treturn a.start < b.end && b.start < a.end;\n\t}\n\n\tprivate removeNode(\n\t\tnode: IntervalNode | null,\n\t\trange: RequestedRangeLock\n\t): IntervalNode | null {\n\t\tif (!node) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Check if current node is the one to remove\n\t\tif (this.areRangesEqual(node.range, range)) {\n\t\t\t// Handle cases of no children or one child\n\t\t\tif (!node.left) {\n\t\t\t\treturn node.right;\n\t\t\t}\n\t\t\tif (!node.right) {\n\t\t\t\treturn node.left;\n\t\t\t}\n\n\t\t\t// Node has two children - find successor\n\t\t\tconst successor = this.findMin(node.right);\n\t\t\tnode.range = successor.range;\n\t\t\tnode.right = this.removeNode(node.right, successor.range);\n\t\t} else if (range.start < node.range.start) {\n\t\t\tnode.left = this.removeNode(node.left, range);\n\t\t} else {\n\t\t\tnode.right = this.removeNode(node.right, range);\n\t\t}\n\n\t\t// Update max value\n\t\tnode.max = node.range.end;\n\t\tif (node.left) {\n\t\t\tnode.max = this.bigintMax(node.max, node.left.max);\n\t\t}\n\t\tif (node.right) {\n\t\t\tnode.max = this.bigintMax(node.max, node.right.max);\n\t\t}\n\n\t\treturn node;\n\t}\n\n\tprivate findMin(node: IntervalNode): IntervalNode {\n\t\tlet current = node;\n\t\twhile (current.left) {\n\t\t\tcurrent = current.left;\n\t\t}\n\t\treturn current;\n\t}\n\n\tprivate areRangesEqual(\n\t\ta: RequestedRangeLock,\n\t\tb: RequestedRangeLock\n\t): boolean {\n\t\treturn (\n\t\t\ta.start === b.start &&\n\t\t\ta.end === b.end &&\n\t\t\ta.pid === b.pid &&\n\t\t\ta.fd === b.fd\n\t\t);\n\t}\n\n\tprivate findLocksForProcessInNode(\n\t\tnode: IntervalNode | null,\n\t\tpid: number,\n\t\tresult: RequestedRangeLock[]\n\t): void {\n\t\tif (!node) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (node.range.pid === pid) {\n\t\t\tresult.push(node.range);\n\t\t}\n\n\t\tthis.findLocksForProcessInNode(node.left, pid, result);\n\t\tthis.findLocksForProcessInNode(node.right, pid, result);\n\t}\n}\n","import type {\n\tFileLockManager,\n\tRequestedRangeLock,\n\tWholeFileLock,\n\tWholeFileLockOp,\n\tPid,\n\tFd,\n} from './file-lock-manager';\nimport {\n\tMAX_ADDRESSABLE_FILE_OFFSET,\n\ttype LockedRange,\n} from './file-lock-manager';\nimport { FileLockIntervalTree } from './file-lock-interval-tree';\n\n/**\n * This is the file lock manager for use within JS runtimes like Node.js.\n *\n * A FileLockManagerInMemory is a wrapper around a Map of FileLock instances.\n * It provides methods for locking and unlocking files, as well as finding conflicting locks.\n */\nexport class FileLockManagerInMemory implements FileLockManager {\n\tlocks: Map<string, FileLock>;\n\n\t/**\n\t * Create a new FileLockManagerInMemory instance.\n\t *\n\t * @param nativeFlockSync A synchronous flock() function to lock files via the host OS.\n\t */\n\tconstructor() {\n\t\tthis.locks = new Map();\n\t}\n\n\t/**\n\t * Lock the whole file.\n\t *\n\t * @param path The path to the file to lock. This should be the path\n\t * of the file in the native filesystem.\n\t * @param op The whole file lock operation to perform.\n\t * @returns True if the lock was granted, false otherwise.\n\t */\n\tlockWholeFile(\n\t\tpath: string,\n\t\t/**\n\t\t * NOTE: FileLockManagerInMemory does not support waiting for a lock\n\t\t * because it is intended to be used with a native file lock manager\n\t\t * which does support waiting.\n\t\t */\n\t\top: Omit<WholeFileLockOp, 'waitForLock'>\n\t): boolean {\n\t\tif (this.locks.get(path) === undefined) {\n\t\t\tif (op.type === 'unlock') {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tthis.locks.set(path, new FileLock());\n\t\t}\n\n\t\tconst lock = this.locks.get(path)!;\n\t\tconst result = lock.lockWholeFile(op);\n\t\tthis.forgetPathIfUnlocked(path);\n\t\treturn result;\n\t}\n\n\t/**\n\t * Lock a byte range.\n\t *\n\t * @param path The path to the file to lock. This should be the path\n\t * of the file in the native filesystem.\n\t * @param requestedLock The byte range lock to perform.\n\t * @returns True if the lock was granted, false otherwise.\n\t */\n\tlockFileByteRange(\n\t\tpath: string,\n\t\t/**\n\t\t * NOTE: fcntl()-style F_SETLK/F_GETLK do not associate\n\t\t * resulting locks with a file descrtiptor, so we ignore fd here.\n\t\t */\n\t\trequestedLock: Omit<RequestedRangeLock, 'fd'>\n\t\t/**\n\t\t * NOTE: FileLockManagerInMemory does not support waiting for a lock\n\t\t * because it is intended to be used with a native file lock manager\n\t\t * which does support waiting.\n\t\t */\n\t\t// waitForLock: boolean,\n\t): boolean {\n\t\tif (!this.locks.has(path)) {\n\t\t\tif (requestedLock.type === 'unlocked') {\n\t\t\t\t// There is no existing lock. This is a no-op.\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tthis.locks.set(path, new FileLock());\n\t\t}\n\t\tconst lock = this.locks.get(path)!;\n\t\treturn lock.lockFileByteRange(requestedLock);\n\t}\n\n\t/**\n\t * Find the first conflicting byte range lock.\n\t *\n\t * @param path The path to the file to find the conflicting lock for.\n\t * @param desiredLock The desired byte range lock.\n\t * @returns The first conflicting byte range lock, or undefined if no conflicting lock exists.\n\t */\n\tfindFirstConflictingByteRangeLock(\n\t\tpath: string,\n\t\t/**\n\t\t * NOTE: fcntl()-style F_SETLK/F_GETLK do not associate\n\t\t * resulting locks with a file descrtiptor, so we ignore fd here.\n\t\t */\n\t\tdesiredLock: Omit<RequestedRangeLock, 'fd'>\n\t): Omit<RequestedRangeLock, 'fd'> | undefined {\n\t\tconst lock = this.locks.get(path);\n\t\tif (lock === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn lock.findFirstConflictingByteRangeLock(desiredLock);\n\t}\n\n\t/**\n\t * Release all locks for the given process.\n\t *\n\t * @param pid The process ID to release locks for.\n\t */\n\treleaseLocksForProcess(pid: number) {\n\t\t//logger.log('releaseLocksForProcess', pid);\n\t\tfor (const [path, lock] of this.locks.entries()) {\n\t\t\tlock.releaseLocksForProcess(pid);\n\t\t\tthis.forgetPathIfUnlocked(path);\n\t\t}\n\t}\n\n\t/**\n\t * Release all locks for the given process and file descriptor.\n\t *\n\t * @param pid The process ID to release locks for.\n\t * @param fd The file descriptor to release locks for.\n\t * @param path The path to the file to release locks for.\n\t */\n\treleaseLocksOnFdClose(pid: number, fd: number, nativePath: string) {\n\t\tconst lock = this.locks.get(nativePath);\n\t\tif (!lock) {\n\t\t\treturn;\n\t\t}\n\t\tlock.releaseLocksOnFdClose(pid, fd);\n\t\tthis.forgetPathIfUnlocked(nativePath);\n\t}\n\n\t/**\n\t * Forget the path if it is unlocked.\n\t *\n\t * @param path The path to the file to forget.\n\t */\n\tprivate forgetPathIfUnlocked(path: string) {\n\t\tconst lock = this.locks.get(path);\n\t\tif (!lock) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (lock.isUnlocked()) {\n\t\t\tthis.locks.delete(path);\n\t\t}\n\t}\n}\n\n/**\n * A FileLock instance encapsulates a native whole-file lock and file locking between\n * php-wasm processes.\n *\n * A FileLock supports php-wasm whole-file locks and byte range locks.\n * Before granting a php-wasm lock, a FileLock ensures that it first holds a compatible\n * native lock. If a compatible native lock cannot be acquired, the php-wasm lock is\n * not granted.\n */\nexport class FileLock {\n\tprivate wholeFileLock: WholeFileLock;\n\tprivate rangeLocks: FileLockIntervalTree;\n\n\tconstructor() {\n\t\tthis.rangeLocks = new FileLockIntervalTree();\n\t\tthis.wholeFileLock = { type: 'unlocked' };\n\t}\n\n\t/**\n\t * Lock the whole file.\n\t *\n\t * This method corresponds to the flock() function.\n\t *\n\t * @param op The whole file lock operation to perform.\n\t * @returns True if the lock was granted, false otherwise.\n\t */\n\tlockWholeFile(op: Omit<WholeFileLockOp, 'waitForLock'>): boolean {\n\t\tif (op.type === 'unlock') {\n\t\t\tconst originalType = this.wholeFileLock.type;\n\t\t\tif (originalType === 'unlocked') {\n\t\t\t\t// Do nothing because the whole file is already unlocked.\n\t\t\t} else if (\n\t\t\t\tthis.wholeFileLock.type === 'exclusive' &&\n\t\t\t\tthis.wholeFileLock.pid === op.pid &&\n\t\t\t\tthis.wholeFileLock.fd === op.fd\n\t\t\t) {\n\t\t\t\tthis.wholeFileLock = { type: 'unlocked' };\n\t\t\t} else if (\n\t\t\t\tthis.wholeFileLock.type === 'shared' &&\n\t\t\t\tthis.wholeFileLock.pidFds.has(op.pid) &&\n\t\t\t\tthis.wholeFileLock.pidFds.get(op.pid)!.has(op.fd)\n\t\t\t) {\n\t\t\t\tthis.wholeFileLock.pidFds.get(op.pid)!.delete(op.fd);\n\t\t\t\tif (this.wholeFileLock.pidFds.get(op.pid)!.size === 0) {\n\t\t\t\t\tthis.wholeFileLock.pidFds.delete(op.pid);\n\t\t\t\t}\n\n\t\t\t\tif (this.wholeFileLock.pidFds.size === 0) {\n\t\t\t\t\tthis.wholeFileLock = { type: 'unlocked' };\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tif (this.isThereAConflictWithRequestedWholeFileLock(op)) {\n\t\t\t// The requested lock conflicts with an existing lock.\n\t\t\treturn false;\n\t\t}\n\n\t\tif (op.type === 'exclusive') {\n\t\t\tthis.wholeFileLock = {\n\t\t\t\ttype: 'exclusive',\n\t\t\t\tpid: op.pid,\n\t\t\t\tfd: op.fd,\n\t\t\t};\n\n\t\t\treturn true;\n\t\t}\n\n\t\tif (op.type === 'shared') {\n\t\t\tif (this.wholeFileLock.type !== 'shared') {\n\t\t\t\tthis.wholeFileLock = {\n\t\t\t\t\ttype: 'shared',\n\t\t\t\t\tpidFds: new Map(),\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst sharedLock = this.wholeFileLock;\n\t\t\tif (!sharedLock.pidFds.has(op.pid)) {\n\t\t\t\tsharedLock.pidFds.set(op.pid, new Set());\n\t\t\t}\n\t\t\tsharedLock.pidFds.get(op.pid)!.add(op.fd);\n\n\t\t\treturn true;\n\t\t}\n\n\t\tthrow new Error(`Unexpected wholeFileLock() op: '${op.type}'`);\n\t}\n\n\t/**\n\t * Lock a byte range.\n\t *\n\t * This method corresponds to the fcntl() F_SETLK command.\n\t *\n\t * @param requestedLock The byte range lock to perform.\n\t * @returns True if the lock was granted, false otherwise.\n\t */\n\tlockFileByteRange(\n\t\trequestedLock: Omit<RequestedRangeLock, 'fd' | 'waitForLock'>\n\t): boolean {\n\t\tif (requestedLock.start === requestedLock.end) {\n\t\t\t/*\n\t\t\t * Treat a range with zero length as covering the entire remaining range.\n\t\t\t * POSIX Ref: https://pubs.opengroup.org/onlinepubs/9799919799/functions/fcntl.html\n\t\t\t * \"A lock shall be set to extend to the largest possible value of the file offset\n\t\t\t * for that file by setting l_len to 0.\"\n\t\t\t */\n\t\t\trequestedLock = {\n\t\t\t\t...requestedLock,\n\t\t\t\tend: MAX_ADDRESSABLE_FILE_OFFSET,\n\t\t\t};\n\t\t}\n\n\t\tif (requestedLock.type === 'unlocked') {\n\t\t\tconst overlappingLocksBySameProcess = this.rangeLocks\n\t\t\t\t.findOverlapping(requestedLock)\n\t\t\t\t.filter((lock) => lock.pid === requestedLock.pid);\n\n\t\t\tfor (const overlappingLock of overlappingLocksBySameProcess) {\n\t\t\t\tthis.rangeLocks.remove(overlappingLock);\n\n\t\t\t\tif (overlappingLock.start < requestedLock.start) {\n\t\t\t\t\t// This lock precedes our unlock range.\n\t\t\t\t\t// Preserve the part that does not overlap.\n\t\t\t\t\tthis.rangeLocks.insert({\n\t\t\t\t\t\t...overlappingLock,\n\t\t\t\t\t\tend: requestedLock.start,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tif (overlappingLock.end > requestedLock.end) {\n\t\t\t\t\t// This lock extends past our unlock range.\n\t\t\t\t\t// Preserve the part that does not overlap.\n\t\t\t\t\tthis.rangeLocks.insert({\n\t\t\t\t\t\t...overlappingLock,\n\t\t\t\t\t\tstart: requestedLock.end,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tif (this.isThereAConflictWithRequestedRangeLock(requestedLock)) {\n\t\t\t// A conflicting lock exists.\n\t\t\treturn false;\n\t\t}\n\n\t\tconst overlappingLocksFromSameProcess = this.rangeLocks\n\t\t\t.findOverlapping(requestedLock)\n\t\t\t.filter((lock) => lock.pid === requestedLock.pid);\n\n\t\tlet minStart = requestedLock.start;\n\t\tlet maxEnd = requestedLock.end;\n\t\tfor (const overlappingLock of overlappingLocksFromSameProcess) {\n\t\t\t// Remove overlapping locks from the same process because the requested\n\t\t\t// lock replaces them.\n\t\t\tthis.rangeLocks.remove(overlappingLock);\n\n\t\t\tif (overlappingLock.start < minStart) {\n\t\t\t\tminStart = overlappingLock.start;\n\t\t\t}\n\t\t\tif (overlappingLock.end > maxEnd) {\n\t\t\t\tmaxEnd = overlappingLock.end;\n\t\t\t}\n\t\t}\n\n\t\t// Overlapping locks from the same process are merged into a single lock of the requested type.\n\t\tconst mergedLock: LockedRange = {\n\t\t\t...(requestedLock as LockedRange),\n\t\t\tstart: minStart,\n\t\t\tend: maxEnd,\n\t\t};\n\t\tthis.rangeLocks.insert(mergedLock);\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Find the first conflicting byte range lock.\n\t *\n\t * This method corresponds to the fcntl() F_GETLK command.\n\t *\n\t * @param desiredLock The desired byte range lock.\n\t * @returns The first conflicting byte range lock, or undefined if no conflicting lock exists.\n\t */\n\tfindFirstConflictingByteRangeLock(\n\t\t/**\n\t\t * NOTE: fcntl()-style F_SETLK/F_GETLK do not associate\n\t\t * resulting locks with a file descrtiptor, so we ignore fd here.\n\t\t */\n\t\tdesiredLock: Omit<RequestedRangeLock, 'fd'>\n\t) {\n\t\tif (desiredLock.start === desiredLock.end) {\n\t\t\t/*\n\t\t\t * Treat a range with zero length as covering the entire remaining range.\n\t\t\t * POSIX Ref: https://pubs.opengroup.org/onlinepubs/9799919799/functions/fcntl.html\n\t\t\t * \"A lock shall be set to extend to the largest possible value of the file offset\n\t\t\t * for that file by setting l_len to 0.\"\n\t\t\t */\n\t\t\tdesiredLock = {\n\t\t\t\t...desiredLock,\n\t\t\t\tend: MAX_ADDRESSABLE_FILE_OFFSET,\n\t\t\t};\n\t\t}\n\t\tconst overlappingLocks = this.rangeLocks.findOverlapping(desiredLock);\n\t\tconst firstConflictingRangeLock = overlappingLocks.find(\n\t\t\t(lock) =>\n\t\t\t\tlock.pid !== desiredLock.pid &&\n\t\t\t\t(desiredLock.type === 'exclusive' || lock.type === 'exclusive')\n\t\t);\n\n\t\tif (firstConflictingRangeLock) {\n\t\t\treturn firstConflictingRangeLock;\n\t\t}\n\n\t\tif (this.wholeFileLock.type === 'unlocked') {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst wfl = this.wholeFileLock;\n\t\tif (wfl.type === 'exclusive' || desiredLock.type === 'exclusive') {\n\t\t\t// An exclusive lock conflicts with any other exclusive lock.\n\t\t\treturn {\n\t\t\t\ttype: this.wholeFileLock.type,\n\t\t\t\tstart: 0n,\n\t\t\t\tend: 0n,\n\t\t\t\tpid: -1,\n\t\t\t};\n\t\t}\n\n\t\t// Shared locks do not conflict with each other.\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Release all locks for the given process.\n\t *\n\t * @param pid The process ID to release locks for.\n\t */\n\treleaseLocksForProcess(pid: Pid) {\n\t\tfor (const rangeLock of this.rangeLocks.findLocksForProcess(pid)) {\n\t\t\tthis.lockFileByteRange({\n\t\t\t\t...rangeLock,\n\t\t\t\ttype: 'unlocked',\n\t\t\t});\n\t\t}\n\n\t\tif (\n\t\t\tthis.wholeFileLock.type === 'exclusive' &&\n\t\t\tthis.wholeFileLock.pid === pid\n\t\t) {\n\t\t\tthis.lockWholeFile({\n\t\t\t\tpid,\n\t\t\t\tfd: this.wholeFileLock.fd,\n\t\t\t\ttype: 'unlock',\n\t\t\t});\n\t\t} else if (\n\t\t\tthis.wholeFileLock.type === 'shared' &&\n\t\t\tthis.wholeFileLock.pidFds.has(pid)\n\t\t) {\n\t\t\tfor (const fd of this.wholeFileLock.pidFds.get(pid)!) {\n\t\t\t\tthis.lockWholeFile({\n\t\t\t\t\tpid,\n\t\t\t\t\tfd,\n\t\t\t\t\ttype: 'unlock',\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Release all locks for the given process and file descriptor.\n\t *\n\t * @param pid The process ID to release locks for.\n\t * @param fd The file descriptor to release locks for.\n\t */\n\treleaseLocksOnFdClose(pid: Pid, fd: Fd) {\n\t\t// Closing an fd for a file releases all fcntl locks for that file by the process.\n\t\t// POSIX Ref: https://pubs.opengroup.org/onlinepubs/9799919799/functions/fcntl.html\n\t\t// \"Closing a file descriptor shall release all locks held by the process on the file\n\t\t// associated with that file descriptor.\"\n\t\tfor (const rangeLock of this.rangeLocks.findLocksForProcess(pid)) {\n\t\t\tthis.lockFileByteRange({\n\t\t\t\t...rangeLock,\n\t\t\t\ttype: 'unlocked',\n\t\t\t});\n\t\t}\n\n\t\tthis.lockWholeFile({\n\t\t\tpid,\n\t\t\tfd,\n\t\t\ttype: 'unlock',\n\t\t});\n\t}\n\n\t/**\n\t * Check if the file lock is unlocked.\n\t *\n\t * @returns True if the file lock is unlocked, false otherwise.\n\t */\n\tisUnlocked(): boolean {\n\t\treturn (\n\t\t\tthis.wholeFileLock.type === 'unlocked' && this.rangeLocks.isEmpty()\n\t\t);\n\t}\n\n\t/**\n\t * Check if a lock exists that conflicts with the requested range lock.\n\t *\n\t * @param requestedLock The desired byte range lock.\n\t * @returns True if a conflicting lock exists, false otherwise.\n\t */\n\tprivate isThereAConflictWithRequestedRangeLock(\n\t\trequestedLock: Omit<RequestedRangeLock, 'fd' | 'waitForLock'>\n\t) {\n\t\treturn (\n\t\t\tthis.findFirstConflictingByteRangeLock(requestedLock) !== undefined\n\t\t);\n\t}\n\n\t/**\n\t * Check if a lock exists that conflicts with the requested whole-file lock.\n\t *\n\t * @param requestedLock The desired whole-file lock.\n\t * @returns True if a conflicting lock exists, false otherwise.\n\t */\n\tprivate isThereAConflictWithRequestedWholeFileLock(\n\t\trequestedLock: Omit<WholeFileLockOp, 'waitForLock'>\n\t) {\n\t\tif (requestedLock.type === 'exclusive') {\n\t\t\tif (\n\t\t\t\tthis.wholeFileLock.type === 'exclusive' &&\n\t\t\t\t(this.wholeFileLock.fd !== requestedLock.fd ||\n\t\t\t\t\tthis.wholeFileLock.pid !== requestedLock.pid)\n\t\t\t) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (\n\t\t\t\tthis.wholeFileLock.type === 'shared' &&\n\t\t\t\tArray.from(this.wholeFileLock.pidFds).some(\n\t\t\t\t\t([pid]) => pid !== requestedLock.pid\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tconst overlappingLocks = this.rangeLocks.findOverlapping({\n\t\t\t\tstart: 0n,\n\t\t\t\tend: MAX_ADDRESSABLE_FILE_OFFSET,\n\t\t\t});\n\t\t\tif (overlappingLocks.length > 0) {\n\t\t\t\t// Any range lock, including one by the same process,\n\t\t\t\t// conflict with an exclusive whole-file lock.\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tif (requestedLock.type === 'shared') {\n\t\t\tif (\n\t\t\t\tthis.wholeFileLock.type === 'exclusive' &&\n\t\t\t\tthis.wholeFileLock.pid !== requestedLock.pid\n\t\t\t) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tconst overlappingLocks = this.rangeLocks.findOverlapping({\n\t\t\t\tstart: 0n,\n\t\t\t\tend: MAX_ADDRESSABLE_FILE_OFFSET,\n\t\t\t});\n\t\t\tconst exclusiveRangeLocks = overlappingLocks.filter(\n\t\t\t\t(lock) => lock.type === 'exclusive'\n\t\t\t);\n\t\t\tif (exclusiveRangeLocks.length > 0) {\n\t\t\t\t// Any exclusive range lock, including one by the same process,\n\t\t\t\t// conflict with a shared whole-file lock.\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\treturn false;\n\t}\n}\n","import {\n\ttype Path,\n\ttype RequestedRangeLock,\n\ttype WholeFileLockOp,\n\ttype FileLockManager,\n} from './file-lock-manager';\nimport { logger } from '@php-wasm/logger';\n\n// TODO: Add optional granular tracing\nexport class FileLockManagerComposite implements FileLockManager {\n\tnativeLockManager: FileLockManager;\n\twasmLockManager: FileLockManager;\n\n\tconstructor({\n\t\tnativeLockManager,\n\t\twasmLockManager,\n\t}: {\n\t\tnativeLockManager: FileLockManager;\n\t\twasmLockManager: FileLockManager;\n\t}) {\n\t\tthis.nativeLockManager = nativeLockManager;\n\t\tthis.wasmLockManager = wasmLockManager;\n\t}\n\n\tlockWholeFile(path: Path, op: WholeFileLockOp): boolean {\n\t\tif (op.type !== 'unlock') {\n\t\t\t/**\n\t\t\t * We lock starting with the outside and moving to the inside.\n\t\t\t * - OS locking comes first as the highest authority.\n\t\t\t * - WASM locking comes next as our in-house authority.\n\t\t\t *\n\t\t\t * This ensures that we only offer locks to WASM instances when\n\t\t\t * the OS has granted a native lock to our process.\n\t\t\t */\n\t\t\tlet nativeResult;\n\t\t\tlet wasmResult;\n\t\t\ttry {\n\t\t\t\tnativeResult = this.nativeLockManager.lockWholeFile(path, op);\n\t\t\t\tif (!nativeResult) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\twasmResult = this.wasmLockManager.lockWholeFile(path, op);\n\t\t\t} catch (e) {\n\t\t\t\tlogger.error('Unexpected error in lockWholeFile()', e);\n\t\t\t} finally {\n\t\t\t\t// Rollback the native lock if the wasm lock throws\n\t\t\t\t// (e.g. comlink-sync timeout). Without this, the native\n\t\t\t\t// lock would be held indefinitely, blocking all other\n\t\t\t\t// workers.\n\t\t\t\tif (nativeResult && !wasmResult) {\n\t\t\t\t\t// Rollback the native lock if the wasm lock fails.\n\t\t\t\t\tthis.nativeLockManager.lockWholeFile(path, {\n\t\t\t\t\t\t...op,\n\t\t\t\t\t\ttype: 'unlock',\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn !!nativeResult && !!wasmResult;\n\t\t}\n\n\t\t/**\n\t\t * We unlock starting with the inside and moving to the outside.\n\t\t * - WASM locking comes first as our in-house authority.\n\t\t * - OS locking comes last as we return locks to the highest authority.\n\t\t *\n\t\t * This ensures that other OS processes cannot contend with WASM instances\n\t\t * for locks while WASM instances believe they still hold a lock.\n\t\t */\n\t\ttry {\n\t\t\tthis.wasmLockManager.lockWholeFile(path, op);\n\t\t} catch (e) {\n\t\t\tlogger.error(\n\t\t\t\t'Unexpected error unlocking whole file with in-memory lock manager',\n\t\t\t\te\n\t\t\t);\n\t\t}\n\t\ttry {\n\t\t\tthis.nativeLockManager.lockWholeFile(path, op);\n\t\t} catch (e) {\n\t\t\tlogger.error(\n\t\t\t\t'Unexpected error unlocking whole file with native lock manager',\n\t\t\t\te\n\t\t\t);\n\t\t}\n\t\treturn true;\n\t}\n\n\tlockFileByteRange(\n\t\tpath: Path,\n\t\trequestedLock: RequestedRangeLock,\n\t\twaitForLock: boolean\n\t): boolean {\n\t\tif (requestedLock.type !== 'unlocked') {\n\t\t\t/**\n\t\t\t * We lock starting with the outside and moving to the inside.\n\t\t\t * - OS locking comes first as the highest authority.\n\t\t\t * - WASM locking comes next as our in-house authority.\n\t\t\t *\n\t\t\t * This ensures that we only offer locks to WASM instances when\n\t\t\t * the OS has granted a native lock to our process.\n\t\t\t */\n\t\t\tlet nativeResult;\n\t\t\tlet wasmResult;\n\t\t\ttry {\n\t\t\t\tnativeResult = this.nativeLockManager.lockFileByteRange(\n\t\t\t\t\tpath,\n\t\t\t\t\trequestedLock,\n\t\t\t\t\twaitForLock\n\t\t\t\t);\n\t\t\t\tif (!nativeResult) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\twasmResult = this.wasmLockManager.lockFileByteRange(\n\t\t\t\t\tpath,\n\t\t\t\t\trequestedLock,\n\t\t\t\t\twaitForLock\n\t\t\t\t);\n\t\t\t} catch (e) {\n\t\t\t\tlogger.error('Unexpected error in lockFileByteRange()', e);\n\t\t\t} finally {\n\t\t\t\tif (nativeResult && !wasmResult) {\n\t\t\t\t\t// Rollback the native lock if the wasm lock fails.\n\t\t\t\t\tthis.nativeLockManager.lockFileByteRange(\n\t\t\t\t\t\tpath,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t...requestedLock,\n\t\t\t\t\t\t\ttype: 'unlocked',\n\t\t\t\t\t\t},\n\t\t\t\t\t\tfalse\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn !!nativeResult && !!wasmResult;\n\t\t}\n\n\t\t/**\n\t\t * We unlock starting with the inside and moving to the outside.\n\t\t * - WASM locking comes first as our in-house authority.\n\t\t * - OS locking comes last as we return locks to the highest authority.\n\t\t *\n\t\t * This ensures that other OS processes cannot contend with WASM instances\n\t\t * for locks while WASM instances believe they still hold a lock.\n\t\t */\n\t\ttry {\n\t\t\tthis.wasmLockManager.lockFileByteRange(\n\t\t\t\tpath,\n\t\t\t\trequestedLock,\n\t\t\t\twaitForLock\n\t\t\t);\n\t\t} catch (e) {\n\t\t\tlogger.error(\n\t\t\t\t'Unexpected error unlocking byte range with in-memory lock manager',\n\t\t\t\te\n\t\t\t);\n\t\t}\n\t\ttry {\n\t\t\tthis.nativeLockManager.lockFileByteRange(\n\t\t\t\tpath,\n\t\t\t\trequestedLock,\n\t\t\t\twaitForLock\n\t\t\t);\n\t\t} catch (e) {\n\t\t\tlogger.error(\n\t\t\t\t'Unexpected error unlocking byte range with native lock manager',\n\t\t\t\te\n\t\t\t);\n\t\t}\n\t\treturn true;\n\t}\n\n\tfindFirstConflictingByteRangeLock(\n\t\tpath: Path,\n\t\tdesiredLock: RequestedRangeLock\n\t): Omit<RequestedRangeLock, 'fd'> | undefined {\n\t\ttry {\n\t\t\t// Check native lock manager first, then wasm lock manager.\n\t\t\t// Return the first conflict found from either.\n\t\t\tconst nativeConflict =\n\t\t\t\tthis.nativeLockManager.findFirstConflictingByteRangeLock(\n\t\t\t\t\tpath,\n\t\t\t\t\tdesiredLock\n\t\t\t\t);\n\t\t\tif (nativeConflict) {\n\t\t\t\treturn nativeConflict;\n\t\t\t}\n\n\t\t\tconst wasmConflict =\n\t\t\t\tthis.wasmLockManager.findFirstConflictingByteRangeLock(\n\t\t\t\t\tpath,\n\t\t\t\t\tdesiredLock\n\t\t\t\t);\n\t\t\treturn wasmConflict;\n\t\t} catch (e) {\n\t\t\tlogger.error(\n\t\t\t\t'Unexpected error in findFirstConflictingByteRangeLock()',\n\t\t\t\te\n\t\t\t);\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\treleaseLocksForProcess(pid: number): void {\n\t\t/**\n\t\t * We unlock starting with the inside and moving to the outside.\n\t\t * - WASM locking comes first as our in-house authority.\n\t\t * - OS locking comes last as we return locks to the highest authority.\n\t\t *\n\t\t * This ensures that other OS processes cannot contend with WASM instances\n\t\t * for locks while WASM instances believe they still hold a lock.\n\t\t */\n\t\ttry {\n\t\t\tthis.wasmLockManager.releaseLocksForProcess(pid);\n\t\t} catch (e) {\n\t\t\tlogger.error(\n\t\t\t\t'Unexpected error in wasmLockManager.releaseLocksForProcess()',\n\t\t\t\te\n\t\t\t);\n\t\t}\n\n\t\ttry {\n\t\t\tthis.nativeLockManager.releaseLocksForProcess(pid);\n\t\t} catch (e) {\n\t\t\tlogger.error(\n\t\t\t\t'Unexpected error in nativeLockManager.releaseLocksForProcess()',\n\t\t\t\te\n\t\t\t);\n\t\t}\n\t}\n\n\treleaseLocksOnFdClose(pid: number, fd: number, path: Path): void {\n\t\t/**\n\t\t * We unlock starting with the inside and moving to the outside.\n\t\t * - WASM locking comes first as our in-house authority.\n\t\t * - OS locking comes last as we return locks to the highest authority.\n\t\t *\n\t\t * This ensures that other OS processes cannot contend with WASM instances\n\t\t * for locks while WASM instances believe they still hold a lock.\n\t\t */\n\t\ttry {\n\t\t\tthis.wasmLockManager.releaseLocksOnFdClose(pid, fd, path);\n\t\t} catch (e) {\n\t\t\tlogger.error(\n\t\t\t\t'Unexpected error in wasmLockManager.releaseLocksOnFdClose()',\n\t\t\t\te\n\t\t\t);\n\t\t}\n\n\t\ttry {\n\t\t\tthis.nativeLockManager.releaseLocksOnFdClose(pid, fd, path);\n\t\t} catch (e) {\n\t\t\tlogger.error(\n\t\t\t\t'Unexpected error in nativeLockManager.releaseLocksOnFdClose()',\n\t\t\t\te\n\t\t\t);\n\t\t}\n\t}\n}\n","/**\n * Converts an object type to a promisified version where:\n * - Methods return `Promise<Awaited<ReturnType>>` (no double-wrapping)\n * - Properties become `Promise<Awaited<PropertyType>>`\n */\ntype Promisified<T extends object> = {\n\t[K in keyof T]: T[K] extends (...args: infer A) => infer R\n\t\t? (...args: A) => Promise<Awaited<R>>\n\t\t: Promise<Awaited<T[K]>>;\n};\n\n/**\n * The type returned by `createObjectPoolProxy`. All method calls and\n * property accesses are wrapped in promises because acquiring a free\n * pool instance is inherently async.\n *\n * Dispose/asyncDispose symbols are omitted because the pool proxy\n * forwards calls to a single random instance — disposing one\n * instance out of the pool is never the intended behavior. Pool\n * lifecycle should be managed by the code that created the pool.\n */\nexport type Pooled<T extends object> = Omit<\n\tPromisified<T>,\n\ttypeof Symbol.dispose | typeof Symbol.asyncDispose\n>;\n\n/**\n * Creates a proxy that distributes method calls and property accesses\n * across a pool of object instances. Only one ongoing access per\n * instance is allowed at a time. If all instances are busy, accesses\n * wait until one becomes free.\n *\n * The returned proxy provides a promisified version of the original\n * interface: method calls and property accesses all return promises.\n */\nexport function createObjectPoolProxy<T extends object>(\n\tinstances: T[]\n): Pooled<T> {\n\tif (instances.length === 0) {\n\t\tthrow new Error('At least one instance is required');\n\t}\n\n\tconst freeInstances: T[] = [...instances];\n\tconst waitQueue: Array<(instance: T) => void> = [];\n\n\tfunction acquire(): Promise<T> {\n\t\tconst free = freeInstances.shift();\n\t\tif (free !== undefined) {\n\t\t\treturn Promise.resolve(free);\n\t\t}\n\t\treturn new Promise<T>((resolve) => {\n\t\t\twaitQueue.push(resolve);\n\t\t});\n\t}\n\n\tfunction release(instance: T): void {\n\t\tconst waiter = waitQueue.shift();\n\t\tif (waiter) {\n\t\t\twaiter(instance);\n\t\t} else {\n\t\t\tfreeInstances.push(instance);\n\t\t}\n\t}\n\n\tfunction withInstance<R>(fn: (instance: T) => R | Promise<R>): Promise<R> {\n\t\treturn acquire().then((instance) => {\n\t\t\tlet result: R | Promise<R>;\n\t\t\ttry {\n\t\t\t\tresult = fn(instance);\n\t\t\t} catch (e) {\n\t\t\t\trelease(instance);\n\t\t\t\tthrow e;\n\t\t\t}\n\t\t\tif (result != null && typeof (result as any).then === 'function') {\n\t\t\t\treturn (result as Promise<R>).then(\n\t\t\t\t\t(val) => {\n\t\t\t\t\t\trelease(instance);\n\t\t\t\t\t\treturn val;\n\t\t\t\t\t},\n\t\t\t\t\t(err) => {\n\t\t\t\t\t\trelease(instance);\n\t\t\t\t\t\tthrow err;\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t}\n\t\t\trelease(instance);\n\t\t\treturn result as R;\n\t\t});\n\t}\n\n\treturn new Proxy({} as Pooled<T>, {\n\t\tget(_target, prop: string | symbol) {\n\t\t\t// Support returning assigned target properties.\n\t\t\t// The main reason for this is to allow us to override methods\n\t\t\t// for testing purposes.\n\t\t\t// TODO: Add test for this feature?\n\t\t\tif (prop in _target) {\n\t\t\t\treturn (_target as any)[prop];\n\t\t\t}\n\n\t\t\t// Prevent the proxy from being treated as a thenable,\n\t\t\t// which would interfere with Promise resolution.\n\t\t\tif (prop === 'then') {\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\t// Return a dual-purpose proxy that works as both a method call\n\t\t\t// and a property access. This mirrors how comlink proxies handle\n\t\t\t// the ambiguity — the call site determines the behavior:\n\t\t\t// - playground.run(opts) → apply trap → method call\n\t\t\t// - await playground.docroot → .then accessed → property get\n\t\t\t//\n\t\t\t// We can't sample typeof on the instance to decide, because\n\t\t\t// comlink proxies are always functions regardless of whether\n\t\t\t// the remote value is a method or a property.\n\t\t\treturn new Proxy(function () {}, {\n\t\t\t\tapply(_target, _thisArg, args: any[]) {\n\t\t\t\t\treturn withInstance((inst) => (inst as any)[prop](...args));\n\t\t\t\t},\n\t\t\t\tget(_target, innerProp) {\n\t\t\t\t\tif (innerProp === 'then') {\n\t\t\t\t\t\treturn (resolve: any, reject: any) =>\n\t\t\t\t\t\t\twithInstance((inst) => (inst as any)[prop]).then(\n\t\t\t\t\t\t\t\tresolve,\n\t\t\t\t\t\t\t\treject\n\t\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\treturn undefined;\n\t\t\t\t},\n\t\t\t});\n\t\t},\n\t});\n}\n"],"names":["errno","message","options","e","messagePrefix","value","args","errmsg","path","formattedPrefix","FS","data","fromPath","toPath","fromMount","toMount","dirname","mountPoint","file","filePath","joinPaths","files","name","prepend","logger","target","link","fromNode","filenames","filename","requestHandler","monitor","__privateAdd","_eventListeners","__privateSet","php","internalUrl","callback","_a","request","reap","argv","response","error","newName","listener","l","key","eventType","__privateGet","event","listeners","returnData","phpLoaderModule","phpModuleArgs","phpReady","resolvePHP","rejectPHP","PHPRuntime","reason","id","code","dangerouslyKeepTheRuntimeInTheMap","runtime","methods","promise","resolve","reject","headers","stdout","stderr","exitCode","statusCode","result","bytes","headersStream","headersText","headersData","line","colonIndex","headerName","headerValue","stream","reader","text","done","chunks","totalLength","acc","chunk","offset","httpStatusCode","body","errors","streamedResponse","type","original","clearMessage","crypticError","asyncifyStack","betterMessage","uniqueFunctions","lastError","fn","stack","names","parts","isWasm","source","PHPRuntimeId","_PHP_instances","_sapiName","_phpWasmInitCalled","_wasmErrorsTarget","_messageListeners","_mounts","_rotationOptions","Semaphore","createSpawnHandler","runtimeId","opcacheConfig","mode","syncResponse","release","heapBodyPointer","streamedResponsePromise","__privateMethod","executeWithErrorHandling_fn","setRelativeRequestUri_fn","setRequestMethod_fn","requestHeaders","host","port","inferPortFromHostAndProtocol_fn","setRequestHost_fn","setRequestPort_fn","setRequestHeaders_fn","setRequestBody_fn","setScriptPath_fn","$_SERVER","prepareServerEntries_fn","setServerGlobalEntry_fn","env","setEnv_fn","cleanup","consts","oldFS","oldRootLevelPaths","oldSpawnProcess","oldCWD","mountHandlersToReapplyInOrder","vfsPath","mount","mountsToUnmountInReverseOrder","newFs","mountHandler","virtualFSPath","unmountCallback","mountObject","basename","arg","process","stderrStream","stdoutStream","controller","shouldSkip","defaults","HTTP_prefix","uri","queryString","protocol","method","size","contentLength","executionFn","emscriptenModule","streamsClosed","headersClosed","closeHeadersStream","errorListener","exitCodePromise","normalized","oldNode","controllerResolve","controllerPromise","fs","entries","ini","parse","stringify","phpIniValues","iniBefore","current","isFirst","hasHeaders","setCookie","equalsIndex","cookiesArray","buffer","root","relativePaths","pathPrefix","exceptPaths","normalizePath","currentParent","absPath","StreamedFile","limit","releaseSemaphore","AcquireTimeoutError","isPrimary","url","prefix","boundary","contentType","textEncoder","length","part","fileBuffer","config","_PHPRequestHandler_instances","_DOCROOT","_PROTOCOL","_HOSTNAME","_PORT","_HOST","_PATHNAME","_ABSOLUTE_URL","_cookieStore","_pathAliases","documentRoot","absoluteUrl","rewriteRules","pathAliases","getFileNotFoundAction","setChroot","info","isNonStandardPort","isAbsolute","originalRequestUrl","rewrittenRequestUrl","applyRewriteRules_fn","primaryPhp","siteRelativePath","fsPath","resolveToFsPath_fn","possibleIndexFile","possibleIndexPath","pathToTry","resolvedPathToTry","fileNotFoundAction","spawnPHPAndDispatchRequest_fn","serveStaticFile_fn","resolvedScriptPath","rewrittenRequestPath","urlPath","alias","relativePath","arrayBuffer","scriptPath","spawnedPHP","dispatchToPHP_fn","preferredMethod","executionError","extension","rules","rule","recreateRuntime","maxRequests","newFiles","rmRoot","content","phpInstance","__private__symbol","PROXYFS","position","prot","flags","ptr","heap","totalBytesRead","bytesRead","mmapFlags","sourceOfTruth","replica","paths","replicaSymbol","sourceSymbol","fsResult","getPHPInstance","processApi","splitShellCommand","binaryName","cwd","obj","ep","transport","allowedOrigins","_t","prop","_","res","v","xfer","_thisArg","rawArgs","argList","wire","m","ev","notifyBuffer","view","msg","transferables","latch","val","port1","port2","throwTransferHandler","serialized","origin","allowedOrigin","afterResponseSent","argumentList","returnValue","parent","rawValue","wireValue","endpoint","pendingListeners","resolver","isReleased","newCount","proxy","isProxyReleased","_target","r","p","rawArgumentList","last","arr","processed","transfers","w","context","targetOrigin","handler","serializedValue","nep","eh","worker","emitter","emitterWithSend","_transferList","constructor","from","json","ErrorConstructor","seen","to","forceEnumerable","maxDepth","depth","useToJSON","serialize","continueDestroyCircular","property","enumerable","remote","Comlink.wrapSync","nodeWorkerEndpoint","Comlink.windowEndpoint","api","Comlink.wrap","timeout","apiMethods","pipedApi","targetWorker","setReady","setFailed","exposedApi","Comlink.expose","Comlink.exposeSync","connected","ready","Comlink.transferHandlers","responseData","throwHandler","originalSerialize","supportsStreams","exitCodePort","headersPort","stdoutPort","stderrPort","rs","owned","buf","onMessage","err","ErrorSerializer.serializeError","ErrorSerializer.deserializeError","additionalCallStack","deepestError","object","Comlink.proxy","range","pid","maxType","traverse","node","max","a","b","successor","op","requestedLock","desiredLock","lock","fd","nativePath","sharedLock","overlappingLocksBySameProcess","overlappingLock","overlappingLocksFromSameProcess","minStart","maxEnd","mergedLock","firstConflictingRangeLock","rangeLock","nativeLockManager","wasmLockManager","nativeResult","wasmResult","waitForLock","nativeConflict","instances","freeInstances","waitQueue","acquire","free","instance","waiter","withInstance","inst","innerProp"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../../../../packages/php-wasm/universal/src/lib/rethrow-file-system-error.ts","../../../../packages/php-wasm/universal/src/lib/fs-helpers.ts","../../../../packages/php-wasm/universal/src/lib/php-worker.ts","../../../../packages/php-wasm/universal/src/lib/is-exit-code.ts","../../../../packages/php-wasm/universal/src/lib/load-php-runtime.ts","../../../../packages/php-wasm/universal/src/lib/php-response.ts","../../../../packages/php-wasm/universal/src/lib/error-event-polyfill.ts","../../../../packages/php-wasm/universal/src/lib/wasm-error-reporting.ts","../../../../packages/php-wasm/universal/src/lib/php.ts","../../../../packages/php-wasm/universal/src/lib/ini.ts","../../../../packages/php-wasm/universal/src/lib/error-reporting.ts","../../../../packages/php-wasm/universal/src/lib/http-cookie-store.ts","../../../../packages/php-wasm/universal/src/lib/stream-read-file-from-php.ts","../../../../packages/php-wasm/universal/src/lib/iterate-files.ts","../../../../packages/php-wasm/universal/src/lib/write-files-stream-to-php.ts","../../../../packages/php-wasm/universal/src/lib/single-php-instance-manager.ts","../../../../packages/php-wasm/universal/src/lib/php-process-manager.ts","../../../../packages/php-wasm/universal/src/lib/supported-php-versions.ts","../../../../packages/php-wasm/universal/src/lib/urls.ts","../../../../packages/php-wasm/universal/src/lib/encode-as-multipart.ts","../../../../packages/php-wasm/universal/src/lib/php-request-handler.ts","../../../../packages/php-wasm/universal/src/lib/rotate-php-runtime.ts","../../../../packages/php-wasm/universal/src/lib/write-files.ts","../../../../packages/php-wasm/universal/src/lib/proxy-file-system.ts","../../../../packages/php-wasm/universal/src/lib/sandboxed-spawn-handler-factory.ts","../../../../packages/php-wasm/universal/src/lib/comlink-sync.ts","../../../../packages/php-wasm/universal/src/lib/comlink-node-process-adapter.ts","../../../../packages/php-wasm/universal/src/lib/serialize-error.ts","../../../../packages/php-wasm/universal/src/lib/api.ts","../../../../packages/php-wasm/universal/src/lib/file-lock-manager.ts","../../../../packages/php-wasm/universal/src/lib/file-lock-interval-tree.ts","../../../../packages/php-wasm/universal/src/lib/file-lock-manager-in-memory.ts","../../../../packages/php-wasm/universal/src/lib/file-lock-manager-composite.ts","../../../../packages/php-wasm/universal/src/lib/object-pool-proxy.ts"],"sourcesContent":["/**\n * Emscripten's filesystem-related Exception.\n *\n * @see https://emscripten.org/docs/api_reference/Filesystem-API.html\n * @see https://github.com/emscripten-core/emscripten/blob/main/system/lib/libc/musl/arch/emscripten/bits/errno.h\n * @see https://github.com/emscripten-core/emscripten/blob/38eedc630f17094b3202fd48ac0c2c585dbea31e/system/include/wasi/api.h#L336\n */\n\nexport class ErrnoError extends Error {\n\tconstructor(errno: number, message?: string, options?: any) {\n\t\tsuper(message, options);\n\t\tthis.name = 'ErrnoError';\n\t\tthis.errno = errno;\n\t}\n\n\tnode?: any;\n\terrno: number;\n}\n/**\n * @see https://github.com/emscripten-core/emscripten/blob/38eedc630f17094b3202fd48ac0c2c585dbea31e/system/include/wasi/api.h#L336\n */\nexport const FileErrorCodes = {\n\t0: 'No error occurred. System call completed successfully.',\n\t1: 'Argument list too long.',\n\t2: 'Permission denied.',\n\t3: 'Address in use.',\n\t4: 'Address not available.',\n\t5: 'Address family not supported.',\n\t6: 'Resource unavailable, or operation would block.',\n\t7: 'Connection already in progress.',\n\t8: 'Bad file descriptor.',\n\t9: 'Bad message.',\n\t10: 'Device or resource busy.',\n\t11: 'Operation canceled.',\n\t12: 'No child processes.',\n\t13: 'Connection aborted.',\n\t14: 'Connection refused.',\n\t15: 'Connection reset.',\n\t16: 'Resource deadlock would occur.',\n\t17: 'Destination address required.',\n\t18: 'Mathematics argument out of domain of function.',\n\t19: 'Reserved.',\n\t20: 'File exists.',\n\t21: 'Bad address.',\n\t22: 'File too large.',\n\t23: 'Host is unreachable.',\n\t24: 'Identifier removed.',\n\t25: 'Illegal byte sequence.',\n\t26: 'Operation in progress.',\n\t27: 'Interrupted function.',\n\t28: 'Invalid argument.',\n\t29: 'I/O error.',\n\t30: 'Socket is connected.',\n\t31: 'There is a directory under that path.',\n\t32: 'Too many levels of symbolic links.',\n\t33: 'File descriptor value too large.',\n\t34: 'Too many links.',\n\t35: 'Message too large.',\n\t36: 'Reserved.',\n\t37: 'Filename too long.',\n\t38: 'Network is down.',\n\t39: 'Connection aborted by network.',\n\t40: 'Network unreachable.',\n\t41: 'Too many files open in system.',\n\t42: 'No buffer space available.',\n\t43: 'No such device.',\n\t44: 'There is no such file or directory OR the parent directory does not exist.',\n\t45: 'Executable file format error.',\n\t46: 'No locks available.',\n\t47: 'Reserved.',\n\t48: 'Not enough space.',\n\t49: 'No message of the desired type.',\n\t50: 'Protocol not available.',\n\t51: 'No space left on device.',\n\t52: 'Function not supported.',\n\t53: 'The socket is not connected.',\n\t54: 'Not a directory or a symbolic link to a directory.',\n\t55: 'Directory not empty.',\n\t56: 'State not recoverable.',\n\t57: 'Not a socket.',\n\t58: 'Not supported, or operation not supported on socket.',\n\t59: 'Inappropriate I/O control operation.',\n\t60: 'No such device or address.',\n\t61: 'Value too large to be stored in data type.',\n\t62: 'Previous owner died.',\n\t63: 'Operation not permitted.',\n\t64: 'Broken pipe.',\n\t65: 'Protocol error.',\n\t66: 'Protocol not supported.',\n\t67: 'Protocol wrong type for socket.',\n\t68: 'Result too large.',\n\t69: 'Read-only file system.',\n\t70: 'Invalid seek.',\n\t71: 'No such process.',\n\t72: 'Reserved.',\n\t73: 'Connection timed out.',\n\t74: 'Text file busy.',\n\t75: 'Cross-device link.',\n\t76: 'Extension: Capabilities insufficient.',\n} as any;\n\nexport function getEmscriptenFsError(e: any) {\n\tconst errno = typeof e === 'object' ? ((e as any)?.errno as any) : null;\n\tif (errno in FileErrorCodes) {\n\t\treturn FileErrorCodes[errno];\n\t}\n}\n\nexport function rethrowFileSystemError(messagePrefix = '') {\n\treturn function catchFileSystemError(value: (...args: any[]) => any) {\n\t\treturn function (...args: any[]) {\n\t\t\ttry {\n\t\t\t\t// @ts-expect-error Parameter 'this' implicitly has an 'any' type.ts(7006)\n\t\t\t\treturn value.apply(this, args);\n\t\t\t} catch (e) {\n\t\t\t\tconst errno =\n\t\t\t\t\ttypeof e === 'object' ? ((e as any)?.errno as any) : null;\n\t\t\t\tif (errno in FileErrorCodes) {\n\t\t\t\t\tconst errmsg = FileErrorCodes[errno];\n\t\t\t\t\tconst path = typeof args[1] === 'string' ? args[1] : null;\n\t\t\t\t\tconst formattedPrefix =\n\t\t\t\t\t\tpath !== null\n\t\t\t\t\t\t\t? messagePrefix.replaceAll('{path}', path)\n\t\t\t\t\t\t\t: messagePrefix;\n\t\t\t\t\tthrow new ErrnoError(\n\t\t\t\t\t\terrno,\n\t\t\t\t\t\t`${formattedPrefix}: ${errmsg}`,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcause: e,\n\t\t\t\t\t\t}\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tthrow e;\n\t\t\t}\n\t\t};\n\t};\n}\n","import type { Emscripten } from './emscripten-types';\nimport {\n\tErrnoError,\n\tgetEmscriptenFsError,\n\trethrowFileSystemError,\n} from './rethrow-file-system-error';\nimport { logger } from '@php-wasm/logger';\nimport { dirname, joinPaths } from '@php-wasm/util';\n\nexport interface RmDirOptions {\n\t/**\n\t * If true, recursively removes the directory and all its contents.\n\t * Default: true.\n\t */\n\trecursive?: boolean;\n}\n\nexport interface ListFilesOptions {\n\t/**\n\t * If true, prepend given folder path to all file names.\n\t * Default: false.\n\t */\n\tprependPath: boolean;\n}\n\nexport class FSHelpers {\n\t/**\n\t * Reads a file from the PHP filesystem and returns it as a string.\n\t *\n\t * @throws {@link @php-wasm/universal:ErrnoError} – If the file doesn't exist.\n\t * @param FS\n\t * @param path - The file path to read.\n\t * @returns The file contents.\n\t */\n\tstatic readFileAsText(FS: Emscripten.RootFS, path: string) {\n\t\treturn new TextDecoder().decode(FSHelpers.readFileAsBuffer(FS, path));\n\t}\n\n\t/**\n\t * Reads a file from the PHP filesystem and returns it as an array buffer.\n\t *\n\t * @throws {@link @php-wasm/universal:ErrnoError} – If the file doesn't exist.\n\t * @param FS\n\t * @param path - The file path to read.\n\t * @returns The file contents.\n\t */\n\tstatic readFileAsBuffer(FS: Emscripten.RootFS, path: string): Uint8Array {\n\t\treturn FS.readFile(path);\n\t}\n\n\t/**\n\t * Overwrites data in a file in the PHP filesystem.\n\t * Creates a new file if one doesn't exist yet.\n\t *\n\t * @param FS\n\t * @param path - The file path to write to.\n\t * @param data - The data to write to the file.\n\t */\n\tstatic writeFile(\n\t\tFS: Emscripten.RootFS,\n\t\tpath: string,\n\t\tdata: string | Uint8Array | Buffer\n\t) {\n\t\tFS.writeFile(path, data);\n\t}\n\n\t/**\n\t * Removes a file from the PHP filesystem.\n\t *\n\t * @throws {@link @php-wasm/universal:ErrnoError} – If the file doesn't exist.\n\t * @param FS\n\t * @param path - The file path to remove.\n\t */\n\tstatic unlink(FS: Emscripten.RootFS, path: string) {\n\t\tFS.unlink(path);\n\t}\n\n\t/**\n\t * Moves a file or directory in the PHP filesystem to a\n\t * new location.\n\t *\n\t * @param FS\n\t * @param fromPath The path to rename.\n\t * @param toPath The new path.\n\t */\n\tstatic mv(FS: Emscripten.RootFS, fromPath: string, toPath: string) {\n\t\ttry {\n\t\t\t// FS.rename moves the inode within the same filesystem.\n\t\t\t// If fromPath and toPath are on different filesystems,\n\t\t\t// the operation will fail. In that case, we need to do\n\t\t\t// a recursive copy of all the files and remove the original.\n\t\t\t// Note this is also what happens in the linux `mv` command.\n\t\t\tconst fromMount = FS.lookupPath(fromPath).node.mount;\n\t\t\tconst toMount = FSHelpers.fileExists(FS, toPath)\n\t\t\t\t? FS.lookupPath(toPath).node.mount\n\t\t\t\t: FS.lookupPath(dirname(toPath)).node.mount;\n\t\t\tconst movingBetweenFilesystems =\n\t\t\t\tfromMount.mountpoint !== toMount.mountpoint;\n\n\t\t\tif (movingBetweenFilesystems) {\n\t\t\t\tFSHelpers.copyRecursive(FS, fromPath, toPath);\n\t\t\t\tif (FSHelpers.isDir(FS, fromPath)) {\n\t\t\t\t\tFSHelpers.rmdir(FS, fromPath, { recursive: true });\n\t\t\t\t} else {\n\t\t\t\t\tFS.unlink(fromPath);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tFS.rename(fromPath, toPath);\n\t\t\t}\n\t\t} catch (e) {\n\t\t\tconst errmsg = getEmscriptenFsError(e);\n\t\t\tif (!errmsg) {\n\t\t\t\tthrow e;\n\t\t\t}\n\t\t\tthrow new Error(\n\t\t\t\t`Could not move ${fromPath} to ${toPath}: ${errmsg}`,\n\t\t\t\t{\n\t\t\t\t\tcause: e,\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Removes a directory from the PHP filesystem.\n\t *\n\t * @param FS\n\t * @param path The directory path to remove.\n\t * @param options Options for the removal.\n\t */\n\tstatic rmdir(\n\t\tFS: Emscripten.RootFS,\n\t\tpath: string,\n\t\toptions: RmDirOptions = { recursive: true }\n\t) {\n\t\t/**\n\t\t * Mount points cannot be removed and will throw a ErrnoError with\n\t\t * the code 10 (EBUSY).\n\t\t * To prevent the recursive option from removing internal files before\n\t\t * failing to remove the mount point, we need to check if the path is a\n\t\t * mount point and throw an error early.\n\t\t *\n\t\t * Because a mountpoint can be a symlink, we should not follow it.\n\t\t * Otherwise, a mounted sylink would point to the symlinked path,\n\t\t * instead of the mountpoint.\n\t\t */\n\t\tconst mountPoint = FS.lookupPath(path, { follow: false });\n\t\tif (mountPoint?.node.mount.mountpoint === path) {\n\t\t\tthrow new ErrnoError(10);\n\t\t}\n\n\t\tif (options?.recursive) {\n\t\t\tFSHelpers.listFiles(FS, path).forEach((file) => {\n\t\t\t\tconst filePath = `${path}/${file}`;\n\t\t\t\tif (FSHelpers.isDir(FS, filePath)) {\n\t\t\t\t\tFSHelpers.rmdir(FS, filePath, options);\n\t\t\t\t} else {\n\t\t\t\t\tFSHelpers.unlink(FS, filePath);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t\tif (FS.getPath(FS.lookupPath(path).node) === FS.cwd()) {\n\t\t\tFS.chdir(joinPaths(FS.cwd(), '..'));\n\t\t}\n\t\tFS.rmdir(path);\n\t}\n\n\t/**\n\t * Lists the files and directories in the given directory.\n\t *\n\t * @param FS\n\t * @param path - The directory path to list.\n\t * @param options - Options for the listing.\n\t * @returns The list of files and directories in the given directory.\n\t */\n\tstatic listFiles(\n\t\tFS: Emscripten.RootFS,\n\t\tpath: string,\n\t\toptions: ListFilesOptions = { prependPath: false }\n\t): string[] {\n\t\tif (!FSHelpers.fileExists(FS, path)) {\n\t\t\treturn [];\n\t\t}\n\t\ttry {\n\t\t\tconst files = FS.readdir(path).filter(\n\t\t\t\t(name: string) => name !== '.' && name !== '..'\n\t\t\t);\n\t\t\tif (options.prependPath) {\n\t\t\t\tconst prepend = path.replace(/\\/$/, '');\n\t\t\t\treturn files.map((name: string) => `${prepend}/${name}`);\n\t\t\t}\n\t\t\treturn files;\n\t\t} catch (e) {\n\t\t\tlogger.error(e, { path });\n\t\t\treturn [];\n\t\t}\n\t}\n\n\t/**\n\t * Checks if a directory exists in the PHP filesystem.\n\t *\n\t * @param FS\n\t * @param path – The path to check.\n\t * @returns True if the path is a directory, false otherwise.\n\t */\n\tstatic isDir(FS: Emscripten.RootFS, path: string): boolean {\n\t\tif (!FSHelpers.fileExists(FS, path)) {\n\t\t\treturn false;\n\t\t}\n\t\treturn FS.isDir(FS.lookupPath(path, { follow: true }).node.mode);\n\t}\n\n\t/**\n\t * Checks if a file exists in the PHP filesystem.\n\t *\n\t * @param FS\n\t * @param path – The path to check.\n\t * @returns True if the path is a file, false otherwise.\n\t */\n\tstatic isFile(FS: Emscripten.RootFS, path: string): boolean {\n\t\tif (!FSHelpers.fileExists(FS, path)) {\n\t\t\treturn false;\n\t\t}\n\t\treturn FS.isFile(FS.lookupPath(path, { follow: true }).node.mode);\n\t}\n\n\t/**\n\t * Creates a symlink in the PHP filesystem.\n\t *\n\t * @param FS\n\t * @param target\n\t * @param link\n\t */\n\tstatic symlink(FS: Emscripten.RootFS, target: string, link: string): any {\n\t\treturn FS.symlink(target, link);\n\t}\n\n\t/**\n\t * Checks if a path is a symlink in the PHP filesystem.\n\t *\n\t * @param FS\n\t * @param path\n\t * @returns True if the path is a symlink, false otherwise.\n\t */\n\tstatic isSymlink(FS: Emscripten.RootFS, path: string): boolean {\n\t\tif (!FSHelpers.fileExists(FS, path)) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn FS.isLink(FS.lookupPath(path).node.mode);\n\t}\n\n\t/**\n\t * Reads the target of a symlink in the PHP filesystem.\n\t * @param FS\n\t * @param path\n\t * @returns The target of the symlink.\n\t * @throws {@link @php-wasm/universal:ErrnoError} – If the path is not a symlink.\n\t */\n\tstatic readlink(FS: Emscripten.RootFS, path: string): string {\n\t\treturn FS.readlink(path);\n\t}\n\n\t/**\n\t * Gets the real path of a file in the PHP filesystem.\n\t * @param FS\n\t * @param path\n\t *\n\t * @returns The real path of the file.\n\t */\n\tstatic realpath(FS: Emscripten.RootFS, path: string): string {\n\t\treturn FS.lookupPath(path, { follow: true }).path;\n\t}\n\n\t/**\n\t * Checks if a file (or a directory) exists in the PHP filesystem.\n\t *\n\t * @param FS\n\t * @param path - The file path to check.\n\t * @returns True if the file exists, false otherwise.\n\t */\n\tstatic fileExists(FS: Emscripten.RootFS, path: string): boolean {\n\t\ttry {\n\t\t\tFS.lookupPath(path);\n\t\t\treturn true;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Recursively creates a directory with the given path in the PHP filesystem.\n\t * For example, if the path is `/root/php/data`, and `/root` already exists,\n\t * it will create the directories `/root/php` and `/root/php/data`.\n\t *\n\t * @param FS\n\t * @param path - The directory path to create.\n\t */\n\tstatic mkdir(FS: Emscripten.RootFS, path: string) {\n\t\tFS.mkdirTree(path);\n\t}\n\n\tstatic copyRecursive(\n\t\tFS: Emscripten.FileSystemInstance,\n\t\tfromPath: string,\n\t\ttoPath: string\n\t) {\n\t\tconst fromNode = FS.lookupPath(fromPath).node;\n\t\tif (FS.isDir(fromNode.mode)) {\n\t\t\tFS.mkdirTree(toPath);\n\t\t\tconst filenames = FS.readdir(fromPath).filter(\n\t\t\t\t(name: string) => name !== '.' && name !== '..'\n\t\t\t);\n\t\t\tfor (const filename of filenames) {\n\t\t\t\tFSHelpers.copyRecursive(\n\t\t\t\t\tFS,\n\t\t\t\t\tjoinPaths(fromPath, filename),\n\t\t\t\t\tjoinPaths(toPath, filename)\n\t\t\t\t);\n\t\t\t}\n\t\t} else if (FS.isLink(fromNode.mode)) {\n\t\t\tFS.symlink(FS.readlink(fromPath), toPath);\n\t\t} else {\n\t\t\tFS.writeFile(toPath, FS.readFile(fromPath));\n\t\t}\n\t}\n}\n\n// Apply decorators manually until the decorator syntax is supported\n// by Node.js. We do this so we can take advantage of Node.js type stripping\n// in the meantime.\n// TODO: Inline these decorators once Node.js supports it.\nFSHelpers.readFileAsText = rethrowFileSystemError('Could not read \"{path}\"')(\n\tFSHelpers.readFileAsText\n);\nFSHelpers.readFileAsBuffer = rethrowFileSystemError('Could not read \"{path}\"')(\n\tFSHelpers.readFileAsBuffer\n);\nFSHelpers.writeFile = rethrowFileSystemError('Could not write to \"{path}\"')(\n\tFSHelpers.writeFile\n);\nFSHelpers.unlink = rethrowFileSystemError('Could not unlink \"{path}\"')(\n\tFSHelpers.unlink\n);\nFSHelpers.rmdir = rethrowFileSystemError('Could not remove directory \"{path}\"')(\n\tFSHelpers.rmdir\n);\nFSHelpers.listFiles = rethrowFileSystemError(\n\t'Could not list files in \"{path}\"'\n)(FSHelpers.listFiles);\nFSHelpers.isDir = rethrowFileSystemError('Could not stat \"{path}\"')(\n\tFSHelpers.isDir\n);\nFSHelpers.isFile = rethrowFileSystemError('Could not stat \"{path}\"')(\n\tFSHelpers.isFile\n);\nFSHelpers.realpath = rethrowFileSystemError('Could not stat \"{path}\"')(\n\tFSHelpers.realpath\n);\nFSHelpers.fileExists = rethrowFileSystemError('Could not stat \"{path}\"')(\n\tFSHelpers.fileExists\n);\nFSHelpers.mkdir = rethrowFileSystemError('Could not create directory \"{path}\"')(\n\tFSHelpers.mkdir\n);\nFSHelpers.copyRecursive = rethrowFileSystemError(\n\t'Could not copy files from \"{path}\"'\n)(FSHelpers.copyRecursive);\n","import type { EmscriptenDownloadMonitor } from '@php-wasm/progress';\nimport type { ListFilesOptions, RmDirOptions } from './fs-helpers';\nimport type { PHP } from './php';\nimport type { PHPRequestHandler } from './php-request-handler';\nimport type { PHPResponse, StreamedPHPResponse } from './php-response';\nimport type {\n\tMessageListener,\n\tPHPEvent,\n\tPHPRequest,\n\tPHPRunOptions,\n} from './universal-php';\n\nconst _private = new WeakMap<\n\tPHPWorker,\n\t{\n\t\trequestHandler?: PHPRequestHandler;\n\t\tphp?: PHP;\n\t\tmonitor?: EmscriptenDownloadMonitor;\n\t}\n>();\n\nexport type LimitedPHPApi = Pick<\n\tPHP,\n\t| 'request'\n\t| 'defineConstant'\n\t| 'mkdir'\n\t| 'mkdirTree'\n\t| 'readFileAsText'\n\t| 'readFileAsBuffer'\n\t| 'writeFile'\n\t| 'unlink'\n\t| 'mv'\n\t| 'rmdir'\n\t| 'listFiles'\n\t| 'isDir'\n\t| 'fileExists'\n\t| 'chdir'\n\t| 'run'\n\t| 'onMessage'\n> & {\n\tdocumentRoot: PHP['documentRoot'];\n\tabsoluteUrl: PHP['absoluteUrl'];\n\taddEventListener:\n\t\t| PHP['addEventListener']\n\t\t| ((event: string, listener: (event: any) => any) => void);\n\tremoveEventListener:\n\t\t| PHP['removeEventListener']\n\t\t| ((event: string, listener: (event: any) => any) => void);\n};\n\nexport type PHPWorkerEvent = PHPEvent | { type: string };\nexport type PHPWorkerEventListener = (event: PHPWorkerEvent) => void;\n/**\n * A PHP client that can be used to run PHP code in the browser.\n */\nexport class PHPWorker implements LimitedPHPApi, AsyncDisposable {\n\t/** @inheritDoc @php-wasm/universal!RequestHandler.absoluteUrl */\n\tabsoluteUrl = '';\n\t/** @inheritDoc @php-wasm/universal!RequestHandler.documentRoot */\n\tdocumentRoot = '';\n\n\tprivate chroot: string | null = null;\n\n\t#eventListeners: Map<string, Set<PHPWorkerEventListener>> = new Map();\n\n\tonMessageListeners: MessageListener[] = [];\n\t/** @inheritDoc */\n\tconstructor(\n\t\trequestHandler?: PHPRequestHandler,\n\t\tmonitor?: EmscriptenDownloadMonitor\n\t) {\n\t\t/**\n\t\t * Workaround for TypeScript limitation.\n\t\t * Declaring a private field using the EcmaScript syntax like this:\n\t\t *\n\t\t * #php: PHP\n\t\t *\n\t\t * Makes that field a part of the public API of the class. This means\n\t\t * you can no longer assign seemingly compatible objects:\n\t\t *\n\t\t * ```ts\n\t\t * class PrivateEcma {\n\t\t * #privateProp: string = '';\n\t\t * callback() { }\n\t\t * }\n\t\t * interface CompatibleInterface {\n\t\t * callback(): void;\n\t\t * }\n\t\t * const compatObj: CompatibleInterface = {} as any;\n\t\t * const tsObj: PrivateEcma = compatObj;\n\t\t * // Property '#privateProp' is missing in type 'CompatibleInterface' but\n\t\t * // required in type 'PrivateEcma'\n\t\t * ```\n\t\t */\n\t\t_private.set(this, {\n\t\t\tmonitor,\n\t\t});\n\t\tif (requestHandler) {\n\t\t\tthis.__internal_setRequestHandler(requestHandler);\n\t\t}\n\t}\n\n\tpublic __internal_setRequestHandler(requestHandler: PHPRequestHandler) {\n\t\tthis.absoluteUrl = requestHandler.absoluteUrl;\n\t\tthis.documentRoot = requestHandler.documentRoot;\n\t\tthis.chroot = this.documentRoot;\n\t\t_private.set(this, {\n\t\t\t..._private.get(this),\n\t\t\trequestHandler,\n\t\t});\n\t}\n\n\t/**\n\t * @internal\n\t * @deprecated\n\t * Do not use this method directly in the code consuming\n\t * the web API. It will change or even be removed without\n\t * a warning.\n\t */\n\tprotected __internal_getPHP() {\n\t\treturn _private.get(this)!.php;\n\t}\n\n\t/**\n\t * @internal\n\t * @deprecated\n\t * Do not use this method directly in the code consuming\n\t * the web API. It will change or even be removed without\n\t * a warning.\n\t */\n\tprotected __internal_getRequestHandler() {\n\t\treturn _private.get(this)!.requestHandler;\n\t}\n\n\tasync setPrimaryPHP(php: PHP) {\n\t\t_private.set(this, {\n\t\t\t..._private.get(this)!,\n\t\t\tphp,\n\t\t});\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!PHPRequestHandler.pathToInternalUrl */\n\tpathToInternalUrl(path: string): string {\n\t\treturn _private.get(this)!.requestHandler!.pathToInternalUrl(path);\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!PHPRequestHandler.internalUrlToPath */\n\tinternalUrlToPath(internalUrl: string): string {\n\t\treturn _private\n\t\t\t.get(this)!\n\t\t\t.requestHandler!.internalUrlToPath(internalUrl);\n\t}\n\n\t/**\n\t * The onDownloadProgress event listener.\n\t */\n\tasync onDownloadProgress(\n\t\tcallback: (progress: CustomEvent<ProgressEvent>) => void\n\t): Promise<void> {\n\t\treturn _private\n\t\t\t.get(this)!\n\t\t\t.monitor?.addEventListener('progress', callback as any);\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!PHP.mv */\n\tasync mv(fromPath: string, toPath: string) {\n\t\treturn _private.get(this)!.php!.mv(fromPath, toPath);\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!PHP.rmdir */\n\tasync rmdir(path: string, options?: RmDirOptions) {\n\t\treturn _private.get(this)!.php!.rmdir(path, options);\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!PHPRequestHandler.request */\n\tasync request(request: PHPRequest): Promise<PHPResponse> {\n\t\tconst requestHandler = _private.get(this)!.requestHandler!;\n\t\treturn await requestHandler.request(request);\n\t}\n\n\t/**\n\t * Handles a request with streaming support for large responses.\n\t * Returns a StreamedPHPResponse that allows processing the response\n\t * body incrementally without buffering the entire response in memory.\n\t *\n\t * This is useful for large file downloads (>2GB) that would otherwise\n\t * exceed JavaScript's Uint8Array size limits.\n\t *\n\t * @param request - PHP Request data.\n\t */\n\tasync requestStreamed(request: PHPRequest): Promise<StreamedPHPResponse> {\n\t\tconst requestHandler = _private.get(this)!.requestHandler!;\n\t\treturn await requestHandler.requestStreamed(request);\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!/PHP.run */\n\tasync run(request: PHPRunOptions): Promise<PHPResponse> {\n\t\tconst { php, reap } = await this.acquirePHPInstance();\n\t\ttry {\n\t\t\treturn await php.run(request);\n\t\t} finally {\n\t\t\treap();\n\t\t}\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!/PHP.cli */\n\tasync cli(\n\t\targv: string[],\n\t\toptions?: { env?: Record<string, string> }\n\t): Promise<StreamedPHPResponse> {\n\t\tconst { php, reap } = await this.acquirePHPInstance();\n\t\tlet response: StreamedPHPResponse;\n\t\ttry {\n\t\t\tresponse = await php.cli(argv, options);\n\t\t} catch (error) {\n\t\t\treap();\n\t\t\tthrow error;\n\t\t}\n\t\t/**\n\t\t * Register the reap() callback to run asynchronously once\n\t\t * the response is finished.\n\t\t *\n\t\t * We don't await for response.finished here. It is a\n\t\t * `StreamedPHPResponse` instance and the caller may want\n\t\t * to start processing the streamed data immediately.\n\t\t */\n\t\tresponse.finished.finally(reap);\n\t\treturn response;\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!/PHP.chdir */\n\tchdir(path: string): void {\n\t\t// Remember the new chroot for all PHP instances yet to be acquired.\n\t\tthis.chroot = path;\n\t\treturn _private.get(this)!.php!.chdir(path);\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!/PHP.chdir */\n\tcwd(): string {\n\t\treturn _private.get(this)!.php!.cwd();\n\t}\n\n\t/**\n\t * @returns A PHP instance with a consistent chroot.\n\t */\n\tprivate async acquirePHPInstance() {\n\t\tconst { php, reap } = await _private\n\t\t\t.get(this)!\n\t\t\t.requestHandler!.instanceManager.acquirePHPInstance();\n\t\tif (this.chroot !== null) {\n\t\t\tphp.chdir(this.chroot);\n\t\t}\n\t\tthis.registerWorkerListeners(php);\n\t\treturn { php, reap };\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!/PHP.setSapiName */\n\tsetSapiName(newName: string): void {\n\t\t_private.get(this)!.php!.setSapiName(newName);\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!/PHP.mkdir */\n\tmkdir(path: string): void {\n\t\treturn _private.get(this)!.php!.mkdir(path);\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!/PHP.mkdirTree */\n\tmkdirTree(path: string): void {\n\t\treturn _private.get(this)!.php!.mkdirTree(path);\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!/PHP.readFileAsText */\n\treadFileAsText(path: string): string {\n\t\treturn _private.get(this)!.php!.readFileAsText(path);\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!/PHP.readFileAsBuffer */\n\treadFileAsBuffer(path: string): Uint8Array {\n\t\treturn _private.get(this)!.php!.readFileAsBuffer(path);\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!/PHP.writeFile */\n\twriteFile(path: string, data: string | Uint8Array): void {\n\t\treturn _private.get(this)!.php!.writeFile(path, data);\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!/PHP.unlink */\n\tunlink(path: string): void {\n\t\treturn _private.get(this)!.php!.unlink(path);\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!/PHP.listFiles */\n\tlistFiles(path: string, options?: ListFilesOptions): string[] {\n\t\treturn _private.get(this)!.php!.listFiles(path, options);\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!/PHP.isDir */\n\tisDir(path: string): boolean {\n\t\treturn _private.get(this)!.php!.isDir(path);\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!/PHP.isFile */\n\tisFile(path: string): boolean {\n\t\treturn _private.get(this)!.php!.isFile(path);\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!/PHP.fileExists */\n\tfileExists(path: string): boolean {\n\t\treturn _private.get(this)!.php!.fileExists(path);\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!/PHP.onMessage */\n\tonMessage(listener: MessageListener) {\n\t\tthis.onMessageListeners.push(listener);\n\t\treturn async () => {\n\t\t\tthis.onMessageListeners = this.onMessageListeners.filter(\n\t\t\t\t(l) => l !== listener\n\t\t\t);\n\t\t};\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!/PHP.defineConstant */\n\tdefineConstant(key: string, value: string | boolean | number | null): void {\n\t\t_private.get(this)!.php!.defineConstant(key, value);\n\t}\n\n\t/** @inheritDoc @php-wasm/universal!/PHP.addEventListener */\n\taddEventListener(\n\t\teventType: PHPWorkerEvent['type'],\n\t\tlistener: PHPWorkerEventListener\n\t): void {\n\t\tif (!this.#eventListeners.has(eventType)) {\n\t\t\tthis.#eventListeners.set(eventType, new Set());\n\t\t}\n\t\tthis.#eventListeners.get(eventType)!.add(listener);\n\t}\n\n\t/**\n\t * Removes an event listener for a PHP event.\n\t * @param eventType - The type of event to remove the listener from.\n\t * @param listener - The listener function to be removed.\n\t */\n\tremoveEventListener(\n\t\teventType: PHPWorkerEvent['type'],\n\t\tlistener: PHPWorkerEventListener\n\t) {\n\t\tthis.#eventListeners.get(eventType)?.delete(listener);\n\t}\n\n\tprotected dispatchEvent<Event extends PHPWorkerEvent>(event: Event) {\n\t\tconst listeners = this.#eventListeners.get(event.type);\n\t\tif (!listeners) {\n\t\t\treturn;\n\t\t}\n\t\tfor (const listener of listeners) {\n\t\t\tlistener(event);\n\t\t}\n\t}\n\n\tprotected registerWorkerListeners(php: PHP) {\n\t\tphp.addEventListener('*', async (event) => {\n\t\t\tthis.dispatchEvent(event);\n\t\t});\n\t\tphp.onMessage(async (message) => {\n\t\t\tfor (const listener of this.onMessageListeners) {\n\t\t\t\tconst returnData = await listener(message);\n\t\t\t\tif (returnData) {\n\t\t\t\t\treturn returnData;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn '';\n\t\t});\n\t}\n\n\tasync [Symbol.asyncDispose]() {\n\t\tawait _private.get(this)!.requestHandler?.[Symbol.asyncDispose]();\n\t}\n}\n","/**\n * Check if the Emscripten-thrown error is an exit code 0 error.\n *\n * @param e The error to check\n * @returns True if the error appears to represent an exit code or status\n */\nexport function isExitCode(e: any): e is { status: number } {\n\tif (!(e instanceof Error)) {\n\t\treturn false;\n\t}\n\treturn e?.name === 'ExitStatus' && 'status' in e;\n}\n","import { logger } from '@php-wasm/logger';\nimport type { IncomingMessage, Server, ServerResponse } from 'http';\n\nconst RuntimeId = Symbol('RuntimeId');\nconst loadedRuntimes: Map<number, PHPRuntime> = new Map();\nlet lastRuntimeId = 0;\n\n/**\n * Loads the PHP runtime with the given arguments and data dependencies.\n *\n * This function handles the entire PHP initialization pipeline. In particular,\n * it:\n *\n * * Instantiates the Emscripten PHP module\n * * Wires it together with the data dependencies and loads them\n * * Ensures is all happens in a correct order\n * * Waits until the entire loading sequence is finished\n *\n * Basic usage:\n *\n * ```js\n * const phpLoaderModule = await getPHPLoaderModule(\"7.4\");\n * const php = await loadPHPRuntime( phpLoaderModule );\n * console.log(php.run(`<?php echo \"Hello, world!\"; `));\n * // { stdout: ArrayBuffer containing the string \"Hello, world!\", stderr: [''], exitCode: 0 }\n * ```\n *\n * **The PHP loader module:**\n *\n * In the basic usage example, `phpLoaderModule` is **not** a vanilla\n * Emscripten module. Instead, it's an ESM module that wraps the regular\n * Emscripten output and adds some extra functionality. It's generated by the\n * Dockerfile shipped with this repo. Here's the API it provides:\n *\n * ```js\n * // php.wasm size in bytes:\n * export const dependenciesTotalSize = 5644199;\n *\n * // php.wasm filename:\n * export const dependencyFilename = 'php.wasm';\n *\n * // Run Emscripten's generated module:\n * export default function(jsEnv, emscriptenModuleArgs) {}\n * ```\n *\n * **PHP Filesystem:**\n *\n * Once initialized, the PHP has its own filesystem separate from the project\n * files. It's provided by [Emscripten and uses its FS library](https://emscripten.org/docs/api_reference/Filesystem-API.html).\n *\n * The API exposed to you via the PHP class is succinct and abstracts\n * certain unintuitive parts of low-level filesystem interactions.\n *\n * Here's how to use it:\n *\n * ```js\n * // Recursively create a /var/www directory\n * php.mkdirTree('/var/www');\n *\n * console.log(php.fileExists('/var/www/file.txt'));\n * // false\n *\n * php.writeFile('/var/www/file.txt', 'Hello from the filesystem!');\n *\n * console.log(php.fileExists('/var/www/file.txt'));\n * // true\n *\n * console.log(php.readFile('/var/www/file.txt'));\n * // \"Hello from the filesystem!\n *\n * // Delete the file:\n * php.unlink('/var/www/file.txt');\n * ```\n *\n * For more details consult the PHP class directly.\n *\n * **Data dependencies:**\n *\n * Using existing PHP packages by manually recreating them file-by-file would\n * be quite inconvenient. Fortunately, Emscripten provides a \"data dependencies\"\n * feature.\n *\n * Data dependencies consist of a `dependency.data` file and a `dependency.js`\n * loader and can be packaged with the [file_packager.py tool](\n * https://emscripten.org/docs/porting/files/packaging_files.html#packaging-using-the-file-packager-tool).\n * This project requires wrapping the Emscripten-generated `dependency.js` file\n * in an ES module as follows:\n *\n * 1. Prepend `export default function(emscriptenPHPModule) {'; `\n * 2. Prepend `export const dependencyFilename = '<DATA FILE NAME>'; `\n * 3. Prepend `export const dependenciesTotalSize = <DATA FILE SIZE>;`\n * 4. Append `}`\n *\n * Be sure to use the `--export-name=\"emscriptenPHPModule\"` file_packager.py\n * option.\n *\n * You want the final output to look as follows:\n *\n * ```js\n * export const dependenciesTotalSize = 5644199;\n * export const dependencyFilename = 'dependency.data';\n * export default function(emscriptenPHPModule) {\n * // Emscripten-generated code:\n * var Module = typeof emscriptenPHPModule !== 'undefined' ? emscriptenPHPModule : {};\n * // ... the rest of it ...\n * }\n * ```\n *\n * Such a constructions enables loading the `dependency.js` as an ES Module\n * using `import(\"/dependency.js\")`.\n *\n * Once it's ready, you can load PHP and your data dependencies as follows:\n *\n * ```js\n * const [phpLoaderModule, wordPressLoaderModule] = await Promise.all([\n * getPHPLoaderModule(\"7.4\"),\n * import(\"/wp.js\")\n * ]);\n * const php = await loadPHPRuntime(phpLoaderModule, {}, [wordPressLoaderModule]);\n * ```\n *\n * @public\n * @param phpLoaderModule - The ESM-wrapped Emscripten module. Consult the Dockerfile for the build process.\n * @param options - The Emscripten module arguments, see https://emscripten.org/docs/api_reference/module.html#affecting-execution.\n * @returns Loaded runtime id.\n */\n\nexport async function loadPHPRuntime(\n\tphpLoaderModule: PHPLoaderModule,\n\t...options: EmscriptenOptions[]\n): Promise<number> {\n\tconst phpModuleArgs = Object.assign({}, ...options);\n\n\tconst [phpReady, resolvePHP, rejectPHP] = makePromise();\n\n\tconst PHPRuntime = phpLoaderModule.init(currentJsRuntime, {\n\t\tonAbort(reason) {\n\t\t\trejectPHP(reason);\n\t\t\t// This can happen after PHP has been initialized so\n\t\t\t// let's just log it.\n\t\t\tlogger.error(reason);\n\t\t},\n\t\tENV: {},\n\t\t// Emscripten sometimes prepends a '/' to the path, which\n\t\t// breaks vite dev mode. An identity `locateFile` function\n\t\t// fixes it.\n\t\tlocateFile: (path) => path,\n\t\t...phpModuleArgs,\n\t\tnoInitialRun: true,\n\t\tonRuntimeInitialized() {\n\t\t\tif (phpModuleArgs.onRuntimeInitialized) {\n\t\t\t\tphpModuleArgs.onRuntimeInitialized(PHPRuntime);\n\t\t\t}\n\t\t\tresolvePHP();\n\t\t},\n\t});\n\n\tawait phpReady;\n\n\tconst id = ++lastRuntimeId;\n\n\t// TODO: Ask @adamziel why this is here.\n\t// eslint-disable-next-line @typescript-eslint/no-unused-expressions -- why is this here?\n\tPHPRuntime.FS;\n\tPHPRuntime.id = id;\n\tPHPRuntime.originalExit = PHPRuntime._exit;\n\n\tPHPRuntime._exit = function (code: number) {\n\t\tif (PHPRuntime.outboundNetworkProxyServer) {\n\t\t\tPHPRuntime.outboundNetworkProxyServer.close();\n\t\t\tPHPRuntime.outboundNetworkProxyServer.closeAllConnections();\n\t\t}\n\t\tloadedRuntimes.delete(id);\n\t\treturn PHPRuntime.originalExit(code);\n\t};\n\n\tPHPRuntime[RuntimeId] = id;\n\tloadedRuntimes.set(id, PHPRuntime);\n\treturn id;\n}\n\nexport type RuntimeType = 'NODE' | 'WEB' | 'WORKER';\n\ndeclare const self: WindowOrWorkerGlobalScope;\ndeclare const WorkerGlobalScope: object | undefined;\n\nexport type PHPRuntimeId = number;\n\n/**\n * Retrieves a PHP runtime by its ID and removes it from the internal registry.\n *\n * When you call `loadPHPRuntime()`, it creates an Emscripten-based PHP instance and\n * stores it in a module-level Map keyed by a numeric ID. This function is the only\n * way to retrieve that runtime object so you can actually use it.\n *\n * The \"pop\" semantic is intentional: retrieving a runtime also removes it from the\n * registry. This prevents memory leaks since the registry would otherwise hold\n * references to every runtime ever created. Once you pop a runtime, you own it and\n * are responsible for its lifecycle.\n *\n * Typical usage flow:\n * ```ts\n * // 1. Load a PHP runtime (returns just the ID)\n * const runtimeId = await loadPHPRuntime(phpLoaderModule);\n *\n * // 2. Pop the runtime to get the actual Emscripten module\n * const phpRuntime = popLoadedRuntime(runtimeId);\n *\n * // 3. Now you can use phpRuntime to run PHP code, access the filesystem, etc.\n * ```\n *\n * @param id - The numeric ID returned by `loadPHPRuntime()`.\n * @param options.dangerouslyKeepTheRuntimeInTheMap - Test-only escape hatch. When true,\n * retrieves the runtime without removing it from the registry. This violates\n * the function's contract and only works when `process.env.TEST` is set.\n * Never use this in production code.\n * @returns The PHP runtime object (an Emscripten module instance).\n * @throws If no runtime exists with the given ID.\n */\nexport function popLoadedRuntime(\n\tid: PHPRuntimeId,\n\t{\n\t\tdangerouslyKeepTheRuntimeInTheMap = false,\n\t}: { dangerouslyKeepTheRuntimeInTheMap?: boolean } = {}\n): PHPRuntime {\n\tconst runtime = loadedRuntimes.get(id);\n\tif (!runtime) {\n\t\tthrow new Error(`Runtime with id ${id} not found`);\n\t}\n\tif (dangerouslyKeepTheRuntimeInTheMap) {\n\t\tif (!process?.env?.['TEST']) {\n\t\t\tthrow new Error('Cannot pop runtime in non-test environment');\n\t\t}\n\t\treturn runtime;\n\t}\n\n\tloadedRuntimes.delete(id);\n\treturn runtime;\n}\n\nexport const currentJsRuntime = (function () {\n\tif (typeof process !== 'undefined' && process.release?.name === 'node') {\n\t\treturn 'NODE';\n\t} else if (typeof window !== 'undefined') {\n\t\treturn 'WEB';\n\t} else if (\n\t\ttypeof WorkerGlobalScope !== 'undefined' &&\n\t\tself instanceof (WorkerGlobalScope as any)\n\t) {\n\t\treturn 'WORKER';\n\t} else {\n\t\treturn 'NODE';\n\t}\n})();\n\n/**\n * Creates and exposes Promise resolve/reject methods for later use.\n */\nconst makePromise = () => {\n\tconst methods: any = [];\n\n\tconst promise = new Promise((resolve, reject) => {\n\t\tmethods.push(resolve, reject);\n\t});\n\tmethods.unshift(promise);\n\n\treturn methods as [Promise<any>, (v?: any) => void, (e?: any) => void];\n};\n\nexport type PHPRuntime = any;\n\nexport type PHPLoaderModule = {\n\tdependencyFilename: string;\n\tdependenciesTotalSize: number;\n\tinit: (jsRuntime: string, options: EmscriptenOptions) => PHPRuntime;\n};\n\nexport type DataModule = {\n\tdependencyFilename: string;\n\tdependenciesTotalSize: number;\n\tdefault: (phpRuntime: PHPRuntime) => void;\n};\n\nexport type EmscriptenOptions = {\n\tonAbort?: (message: string) => void;\n\t/**\n\t * Set to true for debugging tricky WebAssembly errors.\n\t */\n\tdebug?: boolean;\n\tENV?: Record<string, string>;\n\tlocateFile?: (path: string) => string;\n\tnoInitialRun?: boolean;\n\tprint?: (message: string) => void;\n\tprintErr?: (message: string) => void;\n\tquit?: (status: number, toThrow: any) => void;\n\tonRuntimeInitialized?: (phpRuntime: PHPRuntime) => void;\n\tmonitorRunDependencies?: (left: number) => void;\n\tonMessage?: (listener: EmscriptenMessageListener) => void;\n\toutboundNetworkProxyServer?: Server<\n\t\ttypeof IncomingMessage,\n\t\ttypeof ServerResponse\n\t>;\n\tinstantiateWasm?: (\n\t\tinfo: WebAssembly.Imports,\n\t\treceiveInstance: (\n\t\t\tinstance: WebAssembly.Instance,\n\t\t\tmodule: WebAssembly.Module\n\t\t) => void\n\t) => void;\n} & Record<string, any>;\n\nexport type EmscriptenMessageListener = (type: string, data: string) => void;\n","/*\n * This type is used in Comlink.transferHandlers.set('PHPResponse', { ... })\n * so be sure to update that if you change this type.\n */\nexport interface PHPResponseData {\n\t/**\n\t * Response headers.\n\t */\n\treadonly headers: Record<string, string[]>;\n\n\t/**\n\t * Response body. Contains the output from `echo`,\n\t * `print`, inline HTML etc.\n\t */\n\treadonly bytes: Uint8Array;\n\n\t/**\n\t * Stderr contents, if any.\n\t */\n\treadonly errors: string;\n\n\t/**\n\t * The exit code of the script. `0` is a success, while\n\t * `1` and `2` indicate an error.\n\t */\n\treadonly exitCode: number;\n\n\t/**\n\t * Response HTTP status code, e.g. 200.\n\t */\n\treadonly httpStatusCode: number;\n}\n\nconst responseTexts: Record<number, string> = {\n\t500: 'Internal Server Error',\n\t502: 'Bad Gateway',\n\t404: 'Not Found',\n\t403: 'Forbidden',\n\t401: 'Unauthorized',\n\t400: 'Bad Request',\n\t301: 'Moved Permanently',\n\t302: 'Found',\n\t307: 'Temporary Redirect',\n\t308: 'Permanent Redirect',\n\t204: 'No Content',\n\t201: 'Created',\n\t200: 'OK',\n};\n\nexport class StreamedPHPResponse {\n\t/**\n\t * Response headers stream (internal).\n\t */\n\treadonly #headersStream: ReadableStream<Uint8Array>;\n\n\t/**\n\t * Response body. Contains the output from `echo`,\n\t * `print`, inline HTML etc.\n\t */\n\treadonly stdout: ReadableStream<Uint8Array>;\n\n\t/**\n\t * Stderr contents, if any.\n\t */\n\treadonly stderr: ReadableStream<Uint8Array>;\n\n\t/**\n\t * The exit code of the script. `0` is a success, anything\n\t * else is an error.\n\t */\n\treadonly exitCode: Promise<number>;\n\n\tprivate parsedHeaders: Promise<{\n\t\theaders: Record<string, string[]>;\n\t\thttpStatusCode: number;\n\t}> | null = null;\n\n\tprivate cachedStdoutBytes: Promise<Uint8Array> | null = null;\n\tprivate cachedStderrText: Promise<string> | null = null;\n\n\tconstructor(\n\t\theaders: ReadableStream<Uint8Array>,\n\t\tstdout: ReadableStream<Uint8Array>,\n\t\tstderr: ReadableStream<Uint8Array>,\n\t\texitCode: Promise<number>\n\t) {\n\t\tthis.#headersStream = headers;\n\t\tthis.stdout = stdout;\n\t\tthis.stderr = stderr;\n\t\tthis.exitCode = exitCode;\n\t}\n\n\t/**\n\t * Creates a StreamedPHPResponse from a buffered PHPResponse.\n\t * Useful for unifying response handling when both types may be returned.\n\t */\n\tstatic fromPHPResponse(response: PHPResponse): StreamedPHPResponse {\n\t\t// Create a ReadableStream containing the response bytes\n\t\tconst stdout = new ReadableStream<Uint8Array>({\n\t\t\tstart(controller) {\n\t\t\t\tcontroller.enqueue(response.bytes);\n\t\t\t\tcontroller.close();\n\t\t\t},\n\t\t});\n\n\t\t// Create empty streams for headers and stderr (won't be used since\n\t\t// we set parsedHeaders directly below)\n\t\tconst emptyStream = () =>\n\t\t\tnew ReadableStream<Uint8Array>({\n\t\t\t\tstart(controller) {\n\t\t\t\t\tcontroller.close();\n\t\t\t\t},\n\t\t\t});\n\n\t\tconst streamed = new StreamedPHPResponse(\n\t\t\temptyStream(),\n\t\t\tstdout,\n\t\t\temptyStream(),\n\t\t\tPromise.resolve(response.exitCode)\n\t\t);\n\n\t\t// Set pre-parsed headers to bypass header stream parsing\n\t\tstreamed.parsedHeaders = Promise.resolve({\n\t\t\theaders: response.headers,\n\t\t\thttpStatusCode: response.httpStatusCode,\n\t\t});\n\n\t\treturn streamed;\n\t}\n\n\t/**\n\t * Creates a StreamedPHPResponse for a given HTTP status code.\n\t * Shorthand for `StreamedPHPResponse.fromPHPResponse(PHPResponse.forHttpCode(...))`.\n\t */\n\tstatic forHttpCode(httpStatusCode: number, text = ''): StreamedPHPResponse {\n\t\treturn StreamedPHPResponse.fromPHPResponse(\n\t\t\tPHPResponse.forHttpCode(httpStatusCode, text)\n\t\t);\n\t}\n\n\t/**\n\t * Returns the raw headers stream for serialization purposes.\n\t * For parsed headers, use the `headers` property instead.\n\t */\n\tgetHeadersStream(): ReadableStream<Uint8Array> {\n\t\treturn this.#headersStream;\n\t}\n\n\t/**\n\t * True if the response is successful (HTTP status code 200-399),\n\t * false otherwise.\n\t */\n\tasync ok(): Promise<boolean> {\n\t\ttry {\n\t\t\tconst statusCode = await this.httpStatusCode;\n\t\t\treturn statusCode >= 200 && statusCode < 400;\n\t\t} catch {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Resolves when the response has finished processing – either successfully or not.\n\t */\n\tget finished(): Promise<void> {\n\t\treturn Promise.allSettled([this.exitCode.finally(() => {})]).then(\n\t\t\t() => {}\n\t\t);\n\t}\n\n\t/**\n\t * Resolves once HTTP headers are available.\n\t */\n\tget headers(): Promise<Record<string, string[]>> {\n\t\treturn this.getParsedHeaders().then((headers) => headers.headers);\n\t}\n\n\t/**\n\t * Resolves once HTTP status code is available.\n\t */\n\tget httpStatusCode(): Promise<number> {\n\t\treturn this.getParsedHeaders()\n\t\t\t.then((headers) => headers.httpStatusCode)\n\t\t\t.then((result) => {\n\t\t\t\tif (result !== undefined) {\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\t\t\t\t// If exit code is 0 or not available yet, fall back to parsed headers\n\t\t\t\treturn this.getParsedHeaders().then(\n\t\t\t\t\t(headers) => headers.httpStatusCode,\n\t\t\t\t\t() => 200\n\t\t\t\t);\n\t\t\t})\n\t\t\t.catch(() => 500);\n\t}\n\n\t/**\n\t * Exposes the stdout bytes as they're produced by the PHP instance\n\t */\n\tget stdoutText(): Promise<string> {\n\t\treturn this.stdoutBytes.then((bytes) =>\n\t\t\tnew TextDecoder().decode(bytes)\n\t\t);\n\t}\n\n\t/**\n\t * Exposes the stdout bytes as they're produced by the PHP instance\n\t */\n\tget stdoutBytes(): Promise<Uint8Array> {\n\t\tif (!this.cachedStdoutBytes) {\n\t\t\tthis.cachedStdoutBytes = streamToBytes(this.stdout);\n\t\t}\n\t\treturn this.cachedStdoutBytes;\n\t}\n\n\t/**\n\t * Exposes the stderr bytes as they're produced by the PHP instance\n\t */\n\tget stderrText(): Promise<string> {\n\t\tif (!this.cachedStderrText) {\n\t\t\tthis.cachedStderrText = streamToText(this.stderr);\n\t\t}\n\t\treturn this.cachedStderrText;\n\t}\n\n\tprivate async getParsedHeaders() {\n\t\tif (!this.parsedHeaders) {\n\t\t\tthis.parsedHeaders = parseHeadersStream(this.#headersStream);\n\t\t}\n\t\treturn await this.parsedHeaders;\n\t}\n}\n\nasync function parseHeadersStream(\n\theadersStream: ReadableStream<Uint8Array>\n): Promise<{\n\theaders: Record<string, string[]>;\n\thttpStatusCode: number;\n}> {\n\tconst headersText = await streamToText(headersStream);\n\tlet headersData;\n\ttry {\n\t\theadersData = JSON.parse(headersText);\n\t} catch {\n\t\treturn { headers: {}, httpStatusCode: 200 };\n\t}\n\tconst headers: PHPResponse['headers'] = {};\n\tfor (const line of headersData.headers) {\n\t\t// Skip invalid response headers and the last \"__terminator__\" line.\n\t\t// @TODO: Should we log a warning on an invalid header line?\n\t\t// What's the typical browser behavior when encountering such a line?\n\t\tif (!line.includes(': ')) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst colonIndex = line.indexOf(': ');\n\t\tconst headerName = line.substring(0, colonIndex).toLowerCase();\n\t\tconst headerValue = line.substring(colonIndex + 2);\n\t\tif (!(headerName in headers)) {\n\t\t\theaders[headerName] = [] as string[];\n\t\t}\n\t\theaders[headerName].push(headerValue);\n\t}\n\treturn {\n\t\theaders,\n\t\thttpStatusCode: headersData.status,\n\t};\n}\n\nasync function streamToText(\n\tstream: ReadableStream<Uint8Array>\n): Promise<string> {\n\tconst reader = (stream as ReadableStream<BufferSource>)\n\t\t.pipeThrough(new TextDecoderStream())\n\t\t.getReader();\n\tconst text: string[] = [];\n\twhile (true) {\n\t\tconst { done, value } = await reader.read();\n\t\tif (done) {\n\t\t\treturn text.join('');\n\t\t}\n\t\tif (value) {\n\t\t\ttext.push(value);\n\t\t}\n\t}\n}\n\nasync function streamToBytes(\n\tstream: ReadableStream<Uint8Array>\n): Promise<Uint8Array> {\n\tconst reader = stream.getReader();\n\tconst chunks: Uint8Array[] = [];\n\n\twhile (true) {\n\t\tconst { done, value } = await reader.read();\n\t\tif (done) {\n\t\t\tconst totalLength = chunks.reduce(\n\t\t\t\t(acc, chunk) => acc + chunk.byteLength,\n\t\t\t\t0\n\t\t\t);\n\t\t\tconst result = new Uint8Array(totalLength);\n\t\t\tlet offset = 0;\n\t\t\tfor (const chunk of chunks) {\n\t\t\t\tresult.set(chunk, offset);\n\t\t\t\toffset += chunk.byteLength;\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\t\tif (value) {\n\t\t\tchunks.push(value);\n\t\t}\n\t}\n}\n\n/**\n * PHP response. Body is an `ArrayBuffer` because it can\n * contain binary data.\n *\n * This type is used in Comlink.transferHandlers.set('PHPResponse', \\{ ... \\})\n * so be sure to update that if you change this type.\n */\nexport class PHPResponse implements PHPResponseData {\n\t/** @inheritDoc */\n\treadonly headers: Record<string, string[]>;\n\n\t/** @inheritDoc */\n\treadonly bytes: Uint8Array;\n\n\t/** @inheritDoc */\n\treadonly errors: string;\n\n\t/** @inheritDoc */\n\treadonly exitCode: number;\n\n\t/** @inheritDoc */\n\treadonly httpStatusCode: number;\n\n\tconstructor(\n\t\thttpStatusCode: number,\n\t\theaders: Record<string, string[]>,\n\t\tbody: Uint8Array,\n\t\terrors = '',\n\t\texitCode = 0\n\t) {\n\t\tthis.httpStatusCode = httpStatusCode;\n\t\tthis.headers = headers;\n\t\tthis.bytes = body;\n\t\tthis.exitCode = exitCode;\n\t\tthis.errors = errors;\n\t}\n\n\tstatic forHttpCode(httpStatusCode: number, text = '') {\n\t\treturn new PHPResponse(\n\t\t\thttpStatusCode,\n\t\t\t{},\n\t\t\tnew TextEncoder().encode(\n\t\t\t\ttext || responseTexts[httpStatusCode] || ''\n\t\t\t)\n\t\t);\n\t}\n\n\tstatic fromRawData(data: PHPResponseData): PHPResponse {\n\t\treturn new PHPResponse(\n\t\t\tdata.httpStatusCode,\n\t\t\tdata.headers,\n\t\t\tdata.bytes,\n\t\t\tdata.errors,\n\t\t\tdata.exitCode\n\t\t);\n\t}\n\n\tstatic async fromStreamedResponse(\n\t\tstreamedResponse: StreamedPHPResponse\n\t): Promise<PHPResponse> {\n\t\tawait streamedResponse.finished;\n\t\treturn new PHPResponse(\n\t\t\tawait streamedResponse.httpStatusCode,\n\t\t\tawait streamedResponse.headers,\n\t\t\tawait streamedResponse.stdoutBytes,\n\t\t\tawait streamedResponse.stderrText,\n\t\t\tawait streamedResponse.exitCode\n\t\t);\n\t}\n\n\t/**\n\t * True if the response is successful (HTTP status code 200-399),\n\t * false otherwise.\n\t */\n\tok(): boolean {\n\t\treturn this.httpStatusCode >= 200 && this.httpStatusCode < 400;\n\t}\n\n\ttoRawData(): PHPResponseData {\n\t\treturn {\n\t\t\theaders: this.headers,\n\t\t\tbytes: this.bytes,\n\t\t\terrors: this.errors,\n\t\t\texitCode: this.exitCode,\n\t\t\thttpStatusCode: this.httpStatusCode,\n\t\t};\n\t}\n\n\t/**\n\t * Response body as JSON.\n\t */\n\tget json() {\n\t\treturn JSON.parse(this.text);\n\t}\n\n\t/**\n\t * Response body as text.\n\t */\n\tget text() {\n\t\treturn new TextDecoder().decode(this.bytes);\n\t}\n}\n","/*\n * Node.js Polyfill for ErrorEvent.\n */\n\nconst kError = Symbol('error');\nconst kMessage = Symbol('message');\n\ninterface ErrorEventOptions {\n\t/* The error that generated this event */\n\terror?: Error;\n\t/* The error message */\n\tmessage?: string;\n}\n/**\n * Class representing an error event.\n *\n * @extends Event\n */\nclass ErrorEvent2 extends Event {\n\t[kError]: any;\n\t[kMessage]: any;\n\t/**\n\t * Create a new `ErrorEvent`.\n\t *\n\t * @param type The name of the event\n\t * @param options A dictionary object that allows for setting\n\t * attributes via object members of the same name.\n\t */\n\tconstructor(type: 'error', options: ErrorEventOptions = {}) {\n\t\tsuper(type);\n\n\t\tthis[kError] = options.error === undefined ? null : options.error;\n\t\tthis[kMessage] = options.message === undefined ? '' : options.message;\n\t}\n\n\tget error() {\n\t\treturn this[kError];\n\t}\n\n\tget message() {\n\t\treturn this[kMessage];\n\t}\n}\nObject.defineProperty(ErrorEvent2.prototype, 'error', { enumerable: true });\nObject.defineProperty(ErrorEvent2.prototype, 'message', { enumerable: true });\n\nexport const ErrorEvent =\n\ttypeof globalThis.ErrorEvent === 'function'\n\t\t? globalThis.ErrorEvent\n\t\t: ErrorEvent2;\n","import { ErrorEvent } from './error-event-polyfill';\nimport { isExitCode } from './is-exit-code';\nimport { logger } from '@php-wasm/logger';\n\ntype Runtime = {\n\twasmExports: Record<string, unknown>;\n\tlastAsyncifyStackSource?: Error;\n};\n\nexport class UnhandledRejectionsTarget extends EventTarget {\n\tlistenersCount = 0;\n\toverride addEventListener(\n\t\ttype: unknown,\n\t\tcallback: unknown,\n\t\toptions?: boolean | AddEventListenerOptions\n\t): void {\n\t\t++this.listenersCount;\n\t\tsuper.addEventListener(\n\t\t\ttype as string,\n\t\t\tcallback as EventListener,\n\t\t\toptions\n\t\t);\n\t}\n\toverride removeEventListener(\n\t\ttype: unknown,\n\t\tcallback: unknown,\n\t\toptions?: boolean | EventListenerOptions\n\t): void {\n\t\t--this.listenersCount;\n\t\tsuper.removeEventListener(\n\t\t\ttype as string,\n\t\t\tcallback as EventListener,\n\t\t\toptions\n\t\t);\n\t}\n\thasListeners() {\n\t\treturn this.listenersCount > 0;\n\t}\n}\n\n/**\n * Creates Asyncify errors listener.\n *\n * Emscripten turns Asyncify errors into unhandled rejections by\n * throwing them outside of the context of the original function call.\n *\n * With this listener, we can catch and rethrow them in a proper context,\n * or at least log them in a more readable way.\n *\n * @param runtime\n */\nexport function improveWASMErrorReporting(runtime: Runtime) {\n\tconst target = new UnhandledRejectionsTarget();\n\tfor (const key in runtime.wasmExports) {\n\t\tif (typeof runtime.wasmExports[key] == 'function') {\n\t\t\tconst original = runtime.wasmExports[key] as any;\n\t\t\truntime.wasmExports[key] = function (...args: any[]) {\n\t\t\t\ttry {\n\t\t\t\t\treturn original(...args);\n\t\t\t\t} catch (e) {\n\t\t\t\t\tif (!(e instanceof Error)) {\n\t\t\t\t\t\tthrow e;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (runtime.lastAsyncifyStackSource) {\n\t\t\t\t\t\te.cause = runtime.lastAsyncifyStackSource;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst clearMessage = clarifyErrorMessage(\n\t\t\t\t\t\te,\n\t\t\t\t\t\truntime.lastAsyncifyStackSource?.stack\n\t\t\t\t\t);\n\n\t\t\t\t\tif (target.hasListeners()) {\n\t\t\t\t\t\te.message = clearMessage;\n\t\t\t\t\t\tconst event = new ErrorEvent('error', { error: e });\n\t\t\t\t\t\ttarget.dispatchEvent(event);\n\t\t\t\t\t\tthrow e;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!isExitCode(e) || e.status !== 0) {\n\t\t\t\t\t\tshowCriticalErrorBox(clearMessage);\n\t\t\t\t\t}\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t}\n\treturn target;\n}\n\nlet functionsMaybeMissingFromAsyncify: string[] = [];\nexport function getFunctionsMaybeMissingFromAsyncify() {\n\treturn functionsMaybeMissingFromAsyncify;\n}\n\nexport function clarifyErrorMessage(\n\tcrypticError: Error,\n\tasyncifyStack?: string\n) {\n\tif (crypticError.message === 'unreachable') {\n\t\tlet betterMessage = UNREACHABLE_ERROR;\n\t\tif (!asyncifyStack) {\n\t\t\tbetterMessage +=\n\t\t\t\t`\\n\\nThis stack trace is lacking. For a better one initialize \\n` +\n\t\t\t\t`the PHP runtime with debug: true, e.g. loadNodeRuntime('8.1', { emscriptenOptions: { debug: true } }).\\n\\n`;\n\t\t}\n\n\t\t// Extract all the PHP functions from the entire error chain.\n\t\tconst uniqueFunctions = new Set<string>(\n\t\t\textractPHPFunctionsFromStack(asyncifyStack || '')\n\t\t);\n\t\tlet lastError = crypticError;\n\t\tdo {\n\t\t\tfor (const fn of extractPHPFunctionsFromStack(\n\t\t\t\tlastError.stack || ''\n\t\t\t)) {\n\t\t\t\tuniqueFunctions.add(fn);\n\t\t\t}\n\t\t\tlastError = lastError.cause as Error;\n\t\t} while (lastError);\n\t\tfunctionsMaybeMissingFromAsyncify = Array.from(uniqueFunctions);\n\n\t\tfor (const fn of uniqueFunctions) {\n\t\t\tbetterMessage += ` * ${fn}\\n`;\n\t\t}\n\n\t\tbetterMessage += `Original error message: ${crypticError.message}\\n`;\n\n\t\treturn betterMessage;\n\t}\n\treturn crypticError.message;\n}\n\nconst UNREACHABLE_ERROR = `\n\"unreachable\" WASM instruction executed.\n\nThe typical reason is a PHP function missing from the ASYNCIFY_ONLY\nlist when building PHP.wasm.\n\nYou will need to file a new issue in the WordPress Playground repository\nand paste this error message there:\n\nhttps://github.com/WordPress/wordpress-playground/issues/new\n\nIf you're a core developer, the typical fix is to:\n\n* Isolate a minimal reproduction of the error\n* Add a reproduction of the error to php-asyncify.spec.ts in the WordPress Playground repository\n* Run 'npm run fix-asyncify'\n* Commit the changes, push to the repo, release updated NPM packages\n\nBelow is a list of all the PHP functions found in the stack trace to\nhelp with the minimal reproduction. If they're all already listed in\nthe Dockerfile, you'll need to trigger this error again with long stack\ntraces enabled. In node.js, you can do it using the --stack-trace-limit=100\nCLI option: \\n\\n`;\n\n// ANSI escape codes for CLI colors and formats\nconst redBg = '\\x1b[41m';\nconst bold = '\\x1b[1m';\nconst reset = '\\x1b[0m';\nconst eol = '\\x1B[K';\n\nlet logged = false;\nexport function showCriticalErrorBox(message: string) {\n\tif (logged) {\n\t\treturn;\n\t}\n\tlogged = true;\n\tif (message?.trim().startsWith('Program terminated with exit')) {\n\t\treturn;\n\t}\n\tlogger.log(`${redBg}\\n${eol}\\n${bold} WASM ERROR${reset}${redBg}`);\n\tfor (const line of message.split('\\n')) {\n\t\tlogger.log(`${eol} ${line} `);\n\t}\n\tlogger.log(`${reset}`);\n}\n\nfunction extractPHPFunctionsFromStack(stack: string) {\n\ttry {\n\t\tconst names = stack\n\t\t\t.split('\\n')\n\t\t\t.slice(1)\n\t\t\t.map((line) => {\n\t\t\t\tconst parts = line.trim().substring('at '.length).split(' ');\n\t\t\t\treturn {\n\t\t\t\t\tfn: parts.length >= 2 ? parts[0] : '<unknown>',\n\t\t\t\t\tisWasm: line.includes('wasm:/'),\n\t\t\t\t};\n\t\t\t})\n\t\t\t.filter(\n\t\t\t\t({ fn, isWasm }) =>\n\t\t\t\t\tisWasm &&\n\t\t\t\t\t!fn.startsWith('dynCall_') &&\n\t\t\t\t\t!fn.startsWith('invoke_')\n\t\t\t)\n\t\t\t.map(({ fn }) => fn);\n\t\treturn Array.from(new Set(names));\n\t} catch {\n\t\treturn [];\n\t}\n}\n","import { logger } from '@php-wasm/logger';\nimport {\n\tSemaphore,\n\tbasename,\n\tcreateSpawnHandler,\n\tjoinPaths,\n} from '@php-wasm/util';\nimport type { Emscripten } from './emscripten-types';\nimport type { ListFilesOptions, RmDirOptions } from './fs-helpers';\nimport { FSHelpers } from './fs-helpers';\nimport { isExitCode } from './is-exit-code';\nimport type { PHPRuntimeId } from './load-php-runtime';\nimport { popLoadedRuntime } from './load-php-runtime';\nimport type { PHPRequestHandler } from './php-request-handler';\nimport { PHPResponse, StreamedPHPResponse } from './php-response';\nimport type {\n\tChildProcess,\n\tMessageListener,\n\tPHPEvent,\n\tPHPEventListener,\n\tPHPRequest,\n\tPHPRequestHeaders,\n\tPHPRunOptions,\n\tSpawnHandler,\n} from './universal-php';\nimport type { UnhandledRejectionsTarget } from './wasm-error-reporting';\nimport {\n\tgetFunctionsMaybeMissingFromAsyncify,\n\timproveWASMErrorReporting,\n} from './wasm-error-reporting';\n\nconst STRING = 'string';\nconst NUMBER = 'number';\n\nexport const __private__dont__use = Symbol('__private__dont__use');\n\ntype ErrorSource = 'request' | 'php-wasm';\nexport class PHPExecutionFailureError extends Error {\n\tresponse: PHPResponse;\n\tsource: ErrorSource;\n\n\tconstructor(message: string, response: PHPResponse, source: ErrorSource) {\n\t\tsuper(message);\n\t\tthis.response = response;\n\t\tthis.source = source;\n\t}\n}\n\nexport type UnmountFunction = (() => Promise<any>) | (() => any);\nexport type MountHandler = (\n\tphp: PHP,\n\tFS: Emscripten.RootFS,\n\tvfsMountPoint: string\n) => UnmountFunction | Promise<UnmountFunction>;\n\nexport const PHP_INI_PATH = '/internal/shared/php.ini';\nconst AUTO_PREPEND_SCRIPT = '/internal/shared/auto_prepend_file.php';\n\nexport const USE_OPCACHE = true;\nconst OPCACHE_FILE_FOLDER = '/internal/shared/opcache';\n\ntype MountObject = {\n\tmountHandler: MountHandler;\n\tunmount: () => Promise<any>;\n};\n\n/**\n * An environment-agnostic wrapper around the Emscripten PHP runtime\n * that universals the super low-level API and provides a more convenient\n * higher-level API.\n *\n * It exposes a minimal set of methods to run PHP scripts and to\n * interact with the PHP filesystem.\n */\nexport class PHP implements Disposable {\n\tprotected [__private__dont__use]: any;\n\t#sapiName?: string;\n\t#phpWasmInitCalled = false;\n\t#wasmErrorsTarget: UnhandledRejectionsTarget | null = null;\n\t#eventListeners: Map<string, Set<PHPEventListener>> = new Map([\n\t\t// Listen to all events\n\t\t['*', new Set()],\n\t]);\n\t#messageListeners: MessageListener[] = [];\n\t#mounts: Record<string, MountObject> = {};\n\t#rotationOptions: {\n\t\tenabled: boolean;\n\t\trecreateRuntime: () => Promise<number> | number;\n\t\tneedsRotating: boolean;\n\t\tmaxRequests: number;\n\t\trequestsMade: number;\n\t} = {\n\t\tenabled: false,\n\t\trecreateRuntime: () => 0,\n\t\tneedsRotating: false,\n\t\tmaxRequests: 400,\n\t\trequestsMade: 0,\n\t};\n\n\trequestHandler?: PHPRequestHandler;\n\n\t/**\n\t * An exclusive lock that prevent multiple requests from running at\n\t * the same time.\n\t */\n\tsemaphore: Semaphore;\n\n\t/**\n\t * Initializes a PHP runtime.\n\t *\n\t * @internal\n\t * @param PHPRuntime - Optional. PHP Runtime ID as initialized by loadPHPRuntime.\n\t * @param requestHandlerOptions - Optional. Options for the PHPRequestHandler. If undefined, no request handler will be initialized.\n\t */\n\tconstructor(PHPRuntimeId?: PHPRuntimeId) {\n\t\tthis.semaphore = new Semaphore({ concurrency: 1 });\n\t\tif (PHPRuntimeId !== undefined) {\n\t\t\tthis.initializeRuntime(PHPRuntimeId);\n\t\t}\n\t\t/**\n\t\t * Listen to PHP runtime crashes.\n\t\t *\n\t\t * Registering an actual event listener helps with testing. The\n\t\t * test cases can dispatch synthetic error events and confirm the\n\t\t * PHP runtime is properly rotated.\n\t\t */\n\t\tthis.addEventListener('request.error', (event: any) => {\n\t\t\tif (event.source === 'php-wasm') {\n\t\t\t\tthis.#rotationOptions.needsRotating = true;\n\t\t\t}\n\t\t});\n\t}\n\t/**\n\t * Adds an event listener for a PHP event.\n\t * @param eventType - The type of event to listen for.\n\t * @param listener - The listener function to be called when the event is triggered.\n\t */\n\taddEventListener(\n\t\teventType: PHPEvent['type'] | '*',\n\t\tlistener: PHPEventListener\n\t) {\n\t\tif (!this.#eventListeners.has(eventType)) {\n\t\t\tthis.#eventListeners.set(eventType, new Set());\n\t\t}\n\t\tthis.#eventListeners.get(eventType)!.add(listener);\n\t}\n\n\t/**\n\t * Removes an event listener for a PHP event.\n\t * @param eventType - The type of event to remove the listener from.\n\t * @param listener - The listener function to be removed.\n\t */\n\tremoveEventListener(\n\t\teventType: PHPEvent['type'] | '*',\n\t\tlistener: PHPEventListener\n\t) {\n\t\tthis.#eventListeners.get(eventType)?.delete(listener);\n\t}\n\n\tdispatchEvent<Event extends PHPEvent>(event: Event) {\n\t\tconst listeners = [\n\t\t\t...(this.#eventListeners.get(event.type) || []),\n\t\t\t...(this.#eventListeners.get('*') || []),\n\t\t];\n\t\tif (!listeners) {\n\t\t\treturn;\n\t\t}\n\t\tfor (const listener of listeners) {\n\t\t\tlistener(event);\n\t\t}\n\t}\n\n\t/**\n\t * Listens to message sent by the PHP code.\n\t *\n\t * To dispatch messages, call:\n\t *\n\t * post_message_to_js(string $data)\n\t *\n\t * Arguments:\n\t * $data (string) – Data to pass to JavaScript.\n\t *\n\t * @example\n\t *\n\t * ```ts\n\t * const php = await PHP.load('8.0');\n\t *\n\t * php.onMessage(\n\t * // The data is always passed as a string\n\t * function (data: string) {\n\t * // Let's decode and log the data:\n\t * console.log(JSON.parse(data));\n\t * }\n\t * );\n\t *\n\t * // Now that we have a listener in place, let's\n\t * // dispatch a message:\n\t * await php.run({\n\t * code: `<?php\n\t * post_message_to_js(\n\t * json_encode([\n\t * 'post_id' => '15',\n\t * 'post_title' => 'This is a blog post!'\n\t * ])\n\t * ));\n\t * `,\n\t * });\n\t * ```\n\t *\n\t * @param listener Callback function to handle the message.\n\t */\n\tonMessage(listener: MessageListener) {\n\t\tthis.#messageListeners.push(listener);\n\t\treturn async () => {\n\t\t\tthis.#messageListeners = this.#messageListeners.filter(\n\t\t\t\t(l) => l !== listener\n\t\t\t);\n\t\t};\n\t}\n\n\tasync setSpawnHandler(handler: SpawnHandler | string) {\n\t\tif (typeof handler === 'string') {\n\t\t\t// This workaround is needed because the\n\t\t\t// Comlink messaging library used by Playground\n\t\t\t// has a hard time serializing a composite\n\t\t\t// handler object.\n\t\t\t// @TODO: Don't eval text-based functions here. Instead\n\t\t\t// use a MessagePort to communicate with the\n\t\t\t//\t\t parent context.\n\t\t\t// Perhaps this library would be useful:\n\t\t\t// https://github.com/WebReflection/coincident/\n\t\t\thandler = createSpawnHandler(eval(handler));\n\t\t}\n\t\tthis[__private__dont__use].spawnProcess = handler;\n\t}\n\n\t/** @deprecated Use PHPRequestHandler instead. */\n\tget absoluteUrl() {\n\t\treturn this.requestHandler!.absoluteUrl;\n\t}\n\n\t/** @deprecated Use PHPRequestHandler instead. */\n\tget documentRoot() {\n\t\treturn this.requestHandler!.documentRoot;\n\t}\n\n\t/** @deprecated Use PHPRequestHandler instead. */\n\tpathToInternalUrl(path: string): string {\n\t\treturn this.requestHandler!.pathToInternalUrl(path);\n\t}\n\n\t/** @deprecated Use PHPRequestHandler instead. */\n\tinternalUrlToPath(internalUrl: string): string {\n\t\treturn this.requestHandler!.internalUrlToPath(internalUrl);\n\t}\n\n\tinitializeRuntime(runtimeId: PHPRuntimeId) {\n\t\tif (this[__private__dont__use]) {\n\t\t\tthrow new Error('PHP runtime already initialized.');\n\t\t}\n\t\tconst runtime = popLoadedRuntime(runtimeId);\n\t\tif (!runtime) {\n\t\t\tthrow new Error('Invalid PHP runtime id.');\n\t\t}\n\t\tthis[__private__dont__use] = runtime;\n\t\tthis[__private__dont__use].ccall(\n\t\t\t'wasm_set_phpini_path',\n\t\t\tnull,\n\t\t\t['string'],\n\t\t\t[PHP_INI_PATH]\n\t\t);\n\n\t\tif (!this.fileExists(PHP_INI_PATH)) {\n\t\t\tconst opcacheConfig = USE_OPCACHE\n\t\t\t\t? [\n\t\t\t\t\t\t// OPCache\n\t\t\t\t\t\t'opcache.enable = 1',\n\t\t\t\t\t\t'opcache.enable_cli = 1',\n\t\t\t\t\t\t'opcache.jit = 0',\n\t\t\t\t\t\t'opcache.interned_strings_buffer = 8',\n\t\t\t\t\t\t'opcache.max_accelerated_files = 1000',\n\t\t\t\t\t\t'opcache.memory_consumption = 64',\n\t\t\t\t\t\t'opcache.max_wasted_percentage = 5',\n\t\t\t\t\t\t'opcache.file_cache = ' + OPCACHE_FILE_FOLDER,\n\t\t\t\t\t\t// Always enable the file cache.\n\t\t\t\t\t\t'opcache.file_cache_only = 1',\n\t\t\t\t\t\t'opcache.file_cache_consistency_checks = 1',\n\t\t\t\t\t]\n\t\t\t\t: [];\n\n\t\t\t/*if (\n\t\t\t\tUSE_OPCACHE &&\n\t\t\t\t!(\n\t\t\t\t\truntime.phpVersion.major === 8 &&\n\t\t\t\t\truntime.phpVersion.minor === 4\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\t// Old versions of PHP are RAM hungry. By using the file cache, we can reduce\n\t\t\t\t// the RAM usage during the first caching.\n\t\t\t\topcacheConfig.push(\n\t\t\t\t\t'opcache.file_cache_only = 1',\n\t\t\t\t\t'opcache.file_cache_consistency_checks = 1'\n\t\t\t\t);\n\t\t\t}*/\n\n\t\t\tif (!this.fileExists(OPCACHE_FILE_FOLDER)) {\n\t\t\t\tthis.mkdir(OPCACHE_FILE_FOLDER);\n\t\t\t}\n\n\t\t\tthis.writeFile(\n\t\t\t\tPHP_INI_PATH,\n\t\t\t\t[\n\t\t\t\t\t'auto_prepend_file=' + AUTO_PREPEND_SCRIPT,\n\t\t\t\t\t'memory_limit=256M',\n\t\t\t\t\t'ignore_repeated_errors = 1',\n\t\t\t\t\t'error_reporting = E_ALL',\n\t\t\t\t\t'display_errors = 1',\n\t\t\t\t\t'html_errors = 1',\n\t\t\t\t\t'display_startup_errors = On',\n\t\t\t\t\t'log_errors = 1',\n\t\t\t\t\t'always_populate_raw_post_data = -1',\n\t\t\t\t\t'upload_max_filesize = 2000M',\n\t\t\t\t\t'post_max_size = 2000M',\n\t\t\t\t\t'allow_url_fopen = On',\n\t\t\t\t\t'allow_url_include = Off',\n\t\t\t\t\t'session.save_path = /home/web_user',\n\t\t\t\t\t'implicit_flush = 1',\n\t\t\t\t\t'output_buffering = 0',\n\t\t\t\t\t'max_execution_time = 0',\n\t\t\t\t\t'max_input_time = -1',\n\t\t\t\t\t...opcacheConfig,\n\t\t\t\t].join('\\n')\n\t\t\t);\n\t\t}\n\t\tif (!this.fileExists(AUTO_PREPEND_SCRIPT)) {\n\t\t\tthis.writeFile(\n\t\t\t\tAUTO_PREPEND_SCRIPT,\n\t\t\t\t`<?php\n\t\t\t\t// Define constants set via defineConstant() calls\n\t\t\t\tif(file_exists('/internal/shared/consts.json')) {\n\t\t\t\t\t$consts = json_decode(file_get_contents('/internal/shared/consts.json'), true);\n\t\t\t\t\tforeach ($consts as $const => $value) {\n\t\t\t\t\t\tif (!defined($const) && is_scalar($value)) {\n\t\t\t\t\t\t\tdefine($const, $value);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Preload all the files from /internal/shared/preload\n\t\t\t\tforeach (glob('/internal/shared/preload/*.php') as $file) {\n\t\t\t\t\trequire_once $file;\n\t\t\t\t}\n\t\t\t\t`\n\t\t\t);\n\t\t}\n\n\t\truntime['onMessage'] = async (\n\t\t\tdata: string\n\t\t): Promise<string | Uint8Array> => {\n\t\t\tfor (const listener of this.#messageListeners) {\n\t\t\t\tconst returnData = await listener(data);\n\n\t\t\t\tif (returnData) {\n\t\t\t\t\treturn returnData;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn '';\n\t\t};\n\n\t\tthis.#wasmErrorsTarget = improveWASMErrorReporting(runtime);\n\t\tthis.dispatchEvent({\n\t\t\ttype: 'runtime.initialized',\n\t\t});\n\t}\n\n\t/** @inheritDoc */\n\tasync setSapiName(newName: string) {\n\t\tconst result = this[__private__dont__use].ccall(\n\t\t\t'wasm_set_sapi_name',\n\t\t\tNUMBER,\n\t\t\t[STRING],\n\t\t\t[newName]\n\t\t);\n\t\tif (result !== 0) {\n\t\t\tthrow new Error(\n\t\t\t\t'Could not set SAPI name. This can only be done before the PHP WASM module is initialized.' +\n\t\t\t\t\t'Did you already dispatch any requests?'\n\t\t\t);\n\t\t}\n\t\tthis.#sapiName = newName;\n\t}\n\n\t/**\n\t * Changes the current working directory in the PHP filesystem.\n\t * This is the directory that will be used as the base for relative paths.\n\t * For example, if the current working directory is `/root/php`, and the\n\t * path is `data`, the absolute path will be `/root/php/data`.\n\t *\n\t * @param path - The new working directory.\n\t */\n\tchdir(path: string) {\n\t\tthis[__private__dont__use].FS.chdir(path);\n\t}\n\n\t/**\n\t * Gets the current working directory in the PHP filesystem.\n\t *\n\t * @returns The current working directory.\n\t */\n\tcwd() {\n\t\treturn this[__private__dont__use].FS.cwd();\n\t}\n\n\t/**\n\t * Changes the permissions of a file or directory.\n\t * @param path - The path to the file or directory.\n\t * @param mode - The new permissions.\n\t */\n\tchmod(path: string, mode: number) {\n\t\tthis[__private__dont__use].FS.chmod(path, mode);\n\t}\n\n\t/**\n\t * Do not use. Use new PHPRequestHandler() instead.\n\t * @deprecated\n\t */\n\tasync request(request: PHPRequest): Promise<PHPResponse> {\n\t\tlogger.debug(\n\t\t\t'PHP.request() is deprecated. Please use new PHPRequestHandler() instead.'\n\t\t);\n\t\tif (!this.requestHandler) {\n\t\t\tthrow new Error('No request handler available.');\n\t\t}\n\t\treturn this.requestHandler.request(request);\n\t}\n\n\t/**\n\t * Runs PHP code.\n\t *\n\t * This low-level method directly interacts with the WebAssembly\n\t * PHP interpreter.\n\t *\n\t * Every time you call run(), it prepares the PHP\n\t * environment and:\n\t *\n\t * * Resets the internal PHP state\n\t * * Populates superglobals ($_SERVER, $_GET, etc.)\n\t * * Handles file uploads\n\t * * Populates input streams (stdin, argv, etc.)\n\t * * Sets the current working directory\n\t *\n\t * You can use run() in two primary modes:\n\t *\n\t * ### Code snippet mode\n\t *\n\t * In this mode, you pass a string containing PHP code to run.\n\t *\n\t * ```ts\n\t * const result = await php.run({\n\t * \tcode: `<?php echo \"Hello world!\";`\n\t * });\n\t * // result.text === \"Hello world!\"\n\t * ```\n\t *\n\t * In this mode, information like __DIR__ or __FILE__ isn't very\n\t * useful because the code is not associated with any file.\n\t *\n\t * Under the hood, the PHP snippet is passed to the `zend_eval_string`\n\t * C function.\n\t *\n\t * ### File mode\n\t *\n\t * In the file mode, you pass a scriptPath and PHP executes a file\n\t * found at a that path:\n\t *\n\t * ```ts\n\t * php.writeFile(\n\t * \t\"/www/index.php\",\n\t * \t`<?php echo \"Hello world!\";\"`\n\t * );\n\t * const result = await php.run({\n\t * \tscriptPath: \"/www/index.php\"\n\t * });\n\t * // result.text === \"Hello world!\"\n\t * ```\n\t *\n\t * In this mode, you can rely on path-related information like __DIR__\n\t * or __FILE__.\n\t *\n\t * Under the hood, the PHP file is executed with the `php_execute_script`\n\t * C function.\n\t *\n\t * The `run()` method cannot be used in conjunction with `cli()`.\n\t *\n\t * @example\n\t * ```js\n\t * const result = await php.run({\n\t * \tcode: `<?php\n\t * \t\t$fp = fopen('php://stderr', 'w');\n\t * \t\tfwrite($fp, \"Hello, world!\");\n\t * \t`\n\t * });\n\t * // result.errors === \"Hello, world!\"\n\t * ```\n\t *\n\t * @deprecated Use stream() instead.\n\t * @param request - PHP runtime options.\n\t */\n\tasync run(request: PHPRunOptions): Promise<PHPResponse> {\n\t\tconst streamedResponse = await this.runStream(request);\n\t\tconst syncResponse =\n\t\t\tawait PHPResponse.fromStreamedResponse(streamedResponse);\n\n\t\tif (syncResponse.exitCode !== 0) {\n\t\t\t// Legacy run() behavior: throw if PHP exited with a non-zero exit code.\n\t\t\t// It could be a WASM crash, but it could be a PHP userland error such\n\t\t\t// as \"Fatal error: Uncaught Error: Call to undefined function no_such_function()\".\n\t\t\t//\n\t\t\t// runStream() does not throw just because an exitCode is non-zero.\n\t\t\tthrow new PHPExecutionFailureError(\n\t\t\t\t`PHP.run() failed with exit code ${syncResponse.exitCode}. \\n\\n=== Stdout ===\\n ${syncResponse.text}\\n\\n=== Stderr ===\\n ${syncResponse.errors}`,\n\t\t\t\tsyncResponse,\n\t\t\t\t'request'\n\t\t\t) as PHPExecutionFailureError;\n\t\t}\n\n\t\treturn syncResponse;\n\t}\n\t/**\n\t * Runs PHP code and returns a StreamedPHPResponse object that can be used to\n\t * process the output incrementally.\n\t *\n\t * This low-level method directly interacts with the WebAssembly\n\t * PHP interpreter and provides streaming capabilities for processing\n\t * PHP output as it becomes available.\n\t *\n\t * Every time you call stream(), it prepares the PHP\n\t * environment and:\n\t *\n\t * * Resets the internal PHP state\n\t * * Populates superglobals ($_SERVER, $_GET, etc.)\n\t * * Handles file uploads\n\t * * Populates input streams (stdin, argv, etc.)\n\t * * Sets the current working directory\n\t *\n\t * You can use stream() in two primary modes:\n\t *\n\t * ### Code snippet mode\n\t *\n\t * In this mode, you pass a string containing PHP code to run.\n\t *\n\t * ```ts\n\t * const streamedResponse = await php.stream({\n\t * \tcode: `<?php echo \"Hello world!\";`\n\t * });\n\t * // Process output incrementally\n\t * for await (const chunk of streamedResponse.text) {\n\t * \tconsole.log(chunk);\n\t * }\n\t * ```\n\t *\n\t * In this mode, information like __DIR__ or __FILE__ isn't very\n\t * useful because the code is not associated with any file.\n\t *\n\t * Under the hood, the PHP snippet is passed to the `zend_eval_string`\n\t * C function.\n\t *\n\t * ### File mode\n\t *\n\t * In the file mode, you pass a scriptPath and PHP executes a file\n\t * found at that path:\n\t *\n\t * ```ts\n\t * php.writeFile(\n\t * \t\"/www/index.php\",\n\t * \t`<?php echo \"Hello world!\";\"`\n\t * );\n\t * const streamedResponse = await php.stream({\n\t * \tscriptPath: \"/www/index.php\"\n\t * });\n\t * // Process output incrementally\n\t * for await (const chunk of streamedResponse.text) {\n\t * \tconsole.log(chunk);\n\t * }\n\t * ```\n\t *\n\t * In this mode, you can rely on path-related information like __DIR__\n\t * or __FILE__.\n\t *\n\t * Under the hood, the PHP file is executed with the `php_execute_script`\n\t * C function.\n\t *\n\t * The `stream()` method cannot be used in conjunction with `cli()`.\n\t *\n\t * @example\n\t * ```js\n\t * const streamedResponse = await php.stream({\n\t * \tcode: `<?php\n\t * \t\tfor ($i = 0; $i < 5; $i++) {\n\t * \t\t\techo \"Line $i\\n\";\n\t * \t\t\tflush();\n\t * \t\t}\n\t * \t`\n\t * });\n\t *\n\t * // Process output as it becomes available\n\t * for await (const chunk of streamedResponse.text) {\n\t * \tconsole.log('Received:', chunk);\n\t * }\n\t *\n\t * // Get the final exit code\n\t * const exitCode = await streamedResponse.exitCode;\n\t * console.log('Exit code:', exitCode);\n\t * ```\n\t *\n\t * @see run() – a synchronous version of this method.\n\t * @param request - PHP runtime options.\n\t * @returns A StreamedPHPResponse object.\n\t */\n\tasync runStream(request: PHPRunOptions): Promise<StreamedPHPResponse> {\n\t\t/*\n\t\t * Prevent multiple requests from running at the same time.\n\t\t * For example, if a request is made to a PHP file that\n\t\t * requests another PHP file, the second request may\n\t\t * be dispatched before the first one is finished.\n\t\t */\n\t\tconst release = await this.semaphore.acquire();\n\t\tlet heapBodyPointer: number | undefined;\n\t\tconst streamedResponsePromise = this.#executeWithErrorHandling(\n\t\t\tasync () => {\n\t\t\t\tif (!this.#phpWasmInitCalled) {\n\t\t\t\t\tawait this[__private__dont__use].ccall(\n\t\t\t\t\t\t'php_wasm_init',\n\t\t\t\t\t\tnull,\n\t\t\t\t\t\t[],\n\t\t\t\t\t\t[],\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tisAsync: true,\n\t\t\t\t\t\t}\n\t\t\t\t\t);\n\t\t\t\t\tthis.#phpWasmInitCalled = true;\n\t\t\t\t}\n\t\t\t\tif (\n\t\t\t\t\trequest.scriptPath &&\n\t\t\t\t\t!this.fileExists(request.scriptPath)\n\t\t\t\t) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`The script path \"${request.scriptPath}\" does not exist.`\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tthis.#setRelativeRequestUri(request.relativeUri || '');\n\t\t\t\tthis.#setRequestMethod(request.method || 'GET');\n\t\t\t\tconst requestHeaders = normalizeHeaders(request.headers || {});\n\t\t\t\tconst host = requestHeaders['host'] || 'example.com:443';\n\n\t\t\t\tconst port = this.#inferPortFromHostAndProtocol(\n\t\t\t\t\thost,\n\t\t\t\t\trequest.protocol || 'http'\n\t\t\t\t);\n\t\t\t\tthis.#setRequestHost(host);\n\t\t\t\tthis.#setRequestPort(port);\n\t\t\t\tthis.#setRequestHeaders(requestHeaders);\n\t\t\t\tif (request.body) {\n\t\t\t\t\theapBodyPointer = this.#setRequestBody(request.body);\n\t\t\t\t}\n\t\t\t\tif (typeof request.code === 'string') {\n\t\t\t\t\tthis.writeFile('/internal/eval.php', request.code);\n\t\t\t\t\tthis.#setScriptPath('/internal/eval.php');\n\t\t\t\t} else if (typeof request.scriptPath === 'string') {\n\t\t\t\t\tthis.#setScriptPath(request.scriptPath || '');\n\t\t\t\t} else {\n\t\t\t\t\tthrow new TypeError(\n\t\t\t\t\t\t'The request object must have either a `code` or a ' +\n\t\t\t\t\t\t\t'`scriptPath` property.'\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tconst $_SERVER = this.#prepareServerEntries(\n\t\t\t\t\trequest.$_SERVER,\n\t\t\t\t\trequestHeaders,\n\t\t\t\t\tport\n\t\t\t\t);\n\n\t\t\t\tfor (const key in $_SERVER) {\n\t\t\t\t\tthis.#setServerGlobalEntry(key, $_SERVER[key]);\n\t\t\t\t}\n\n\t\t\t\tconst env = request.env || {};\n\t\t\t\tfor (const key in env) {\n\t\t\t\t\tthis.#setEnv(key, env[key]);\n\t\t\t\t}\n\n\t\t\t\treturn await this[__private__dont__use].ccall(\n\t\t\t\t\t'wasm_sapi_handle_request',\n\t\t\t\t\tNUMBER,\n\t\t\t\t\t[],\n\t\t\t\t\t[],\n\t\t\t\t\t{ async: true }\n\t\t\t\t);\n\t\t\t}\n\t\t);\n\n\t\tconst cleanup = () => {\n\t\t\tif (heapBodyPointer) {\n\t\t\t\ttry {\n\t\t\t\t\tthis[__private__dont__use].free(heapBodyPointer);\n\t\t\t\t} catch (e) {\n\t\t\t\t\tlogger.error(e);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Release the \"request in progress\" semaphore.\n\t\t\trelease();\n\n\t\t\t/**\n\t\t\t * Notify the filesystem journal (and any other listeners) that the request has ended.\n\t\t\t */\n\t\t\tthis.dispatchEvent({\n\t\t\t\ttype: 'request.end',\n\t\t\t});\n\t\t};\n\n\t\t// Free up resources once the request is fully handled.\n\t\treturn streamedResponsePromise.then(\n\t\t\t(streamedResponse) => {\n\t\t\t\tstreamedResponse.finished.finally(cleanup);\n\t\t\t\treturn streamedResponse;\n\t\t\t},\n\t\t\t(error) => {\n\t\t\t\ttry {\n\t\t\t\t\tcleanup();\n\t\t\t\t} catch {\n\t\t\t\t\t// ... do nothing, just rethrow the original error in the finally section belos ...\n\t\t\t\t} finally {\n\t\t\t\t\t// eslint-disable-next-line no-unsafe-finally\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t}\n\n\t/**\n\t * Prepares the $_SERVER entries for the PHP runtime.\n\t *\n\t * @param defaults Default entries to include in $_SERVER.\n\t * @param headers HTTP headers to include in $_SERVER (as HTTP_ prefixed entries).\n\t * @param port HTTP port, used to determine infer $_SERVER['HTTPS'] value if none\n\t * was provided.\n\t * @returns Computed $_SERVER entries.\n\t */\n\t#prepareServerEntries(\n\t\tdefaults: Record<string, string> | undefined,\n\t\theaders: PHPRequestHeaders,\n\t\tport: number\n\t): Record<string, string> {\n\t\tconst $_SERVER = {\n\t\t\t...(defaults || {}),\n\t\t};\n\t\t$_SERVER['HTTPS'] = $_SERVER['HTTPS'] || port === 443 ? 'on' : 'off';\n\t\tfor (const name in headers) {\n\t\t\tlet HTTP_prefix = 'HTTP_';\n\t\t\t/**\n\t\t\t * Some headers are special and don't have the HTTP_ prefix.\n\t\t\t */\n\t\t\tif (\n\t\t\t\t['content-type', 'content-length'].includes(name.toLowerCase())\n\t\t\t) {\n\t\t\t\tHTTP_prefix = '';\n\t\t\t}\n\t\t\t$_SERVER[`${HTTP_prefix}${name.toUpperCase().replace(/-/g, '_')}`] =\n\t\t\t\theaders[name];\n\t\t}\n\t\treturn $_SERVER;\n\t}\n\n\t#setRelativeRequestUri(uri: string) {\n\t\tthis[__private__dont__use].ccall(\n\t\t\t'wasm_set_request_uri',\n\t\t\tnull,\n\t\t\t[STRING],\n\t\t\t[uri]\n\t\t);\n\t\tlet queryString = '';\n\t\tif (uri.includes('?')) {\n\t\t\tqueryString = uri.substring(uri.indexOf('?') + 1);\n\t\t}\n\t\tthis[__private__dont__use].ccall(\n\t\t\t'wasm_set_query_string',\n\t\t\tnull,\n\t\t\t[STRING],\n\t\t\t[queryString]\n\t\t);\n\t}\n\n\t#setRequestHost(host: string) {\n\t\tthis[__private__dont__use].ccall(\n\t\t\t'wasm_set_request_host',\n\t\t\tnull,\n\t\t\t[STRING],\n\t\t\t[host]\n\t\t);\n\t}\n\n\t#setRequestPort(port: number) {\n\t\tthis[__private__dont__use].ccall(\n\t\t\t'wasm_set_request_port',\n\t\t\tnull,\n\t\t\t[NUMBER],\n\t\t\t[port]\n\t\t);\n\t}\n\n\t#inferPortFromHostAndProtocol(host: string, protocol: string) {\n\t\tlet port;\n\t\ttry {\n\t\t\tport = parseInt(new URL(host).port, 10);\n\t\t} catch {\n\t\t\t// ignore\n\t\t}\n\n\t\tif (!port || isNaN(port) || port === 80) {\n\t\t\tport = protocol === 'https' ? 443 : 80;\n\t\t}\n\t\treturn port;\n\t}\n\n\t#setRequestMethod(method: string) {\n\t\tthis[__private__dont__use].ccall(\n\t\t\t'wasm_set_request_method',\n\t\t\tnull,\n\t\t\t[STRING],\n\t\t\t[method]\n\t\t);\n\t}\n\n\t#setRequestHeaders(headers: PHPRequestHeaders) {\n\t\tif (headers['cookie']) {\n\t\t\tthis[__private__dont__use].ccall(\n\t\t\t\t'wasm_set_cookies',\n\t\t\t\tnull,\n\t\t\t\t[STRING],\n\t\t\t\t[headers['cookie']]\n\t\t\t);\n\t\t}\n\t\tif (headers['content-type']) {\n\t\t\tthis[__private__dont__use].ccall(\n\t\t\t\t'wasm_set_content_type',\n\t\t\t\tnull,\n\t\t\t\t[STRING],\n\t\t\t\t[headers['content-type']]\n\t\t\t);\n\t\t}\n\t\tif (headers['content-length']) {\n\t\t\tthis[__private__dont__use].ccall(\n\t\t\t\t'wasm_set_content_length',\n\t\t\t\tnull,\n\t\t\t\t[NUMBER],\n\t\t\t\t[parseInt(headers['content-length'], 10)]\n\t\t\t);\n\t\t}\n\t}\n\n\t#setRequestBody(body: string | Uint8Array) {\n\t\tlet size, contentLength;\n\t\tif (typeof body === 'string') {\n\t\t\tlogger.warn(\n\t\t\t\t'Passing a string as the request body is deprecated. Please use a Uint8Array instead. See ' +\n\t\t\t\t\t'https://github.com/WordPress/wordpress-playground/issues/997 for more details'\n\t\t\t);\n\t\t\tcontentLength = this[__private__dont__use].lengthBytesUTF8(body);\n\t\t\tsize = contentLength + 1;\n\t\t} else {\n\t\t\tcontentLength = body.byteLength;\n\t\t\tsize = body.byteLength;\n\t\t}\n\n\t\tconst heapBodyPointer = this[__private__dont__use].malloc(size);\n\t\tif (!heapBodyPointer) {\n\t\t\tthrow new Error('Could not allocate memory for the request body.');\n\t\t}\n\n\t\t// Write the string to the WASM memory\n\t\tif (typeof body === 'string') {\n\t\t\tthis[__private__dont__use].stringToUTF8(\n\t\t\t\tbody,\n\t\t\t\theapBodyPointer,\n\t\t\t\tsize + 1\n\t\t\t);\n\t\t} else {\n\t\t\tthis[__private__dont__use].HEAPU8.set(body, heapBodyPointer);\n\t\t}\n\n\t\tthis[__private__dont__use].ccall(\n\t\t\t'wasm_set_request_body',\n\t\t\tnull,\n\t\t\t[NUMBER],\n\t\t\t[heapBodyPointer]\n\t\t);\n\t\tthis[__private__dont__use].ccall(\n\t\t\t'wasm_set_content_length',\n\t\t\tnull,\n\t\t\t[NUMBER],\n\t\t\t[contentLength]\n\t\t);\n\t\treturn heapBodyPointer;\n\t}\n\n\t#setScriptPath(path: string) {\n\t\tthis[__private__dont__use].ccall(\n\t\t\t'wasm_set_path_translated',\n\t\t\tnull,\n\t\t\t[STRING],\n\t\t\t[path]\n\t\t);\n\t}\n\n\t#setServerGlobalEntry(key: string, value: string) {\n\t\tthis[__private__dont__use].ccall(\n\t\t\t'wasm_add_SERVER_entry',\n\t\t\tnull,\n\t\t\t[STRING, STRING],\n\t\t\t[key, value]\n\t\t);\n\t}\n\n\t#setEnv(name: string, value: string) {\n\t\tthis[__private__dont__use].ccall(\n\t\t\t'wasm_add_ENV_entry',\n\t\t\tnull,\n\t\t\t[STRING, STRING],\n\t\t\t[name, value]\n\t\t);\n\t}\n\n\t/**\n\t * Defines a constant in the PHP runtime.\n\t * @param key - The name of the constant.\n\t * @param value - The value of the constant.\n\t */\n\tdefineConstant(key: string, value: string | boolean | number | null) {\n\t\tlet consts = {};\n\t\ttry {\n\t\t\tconsts = JSON.parse(\n\t\t\t\tthis.fileExists('/internal/shared/consts.json')\n\t\t\t\t\t? this.readFileAsText('/internal/shared/consts.json') ||\n\t\t\t\t\t\t\t'{}'\n\t\t\t\t\t: '{}'\n\t\t\t);\n\t\t} catch {\n\t\t\t// ignore\n\t\t}\n\t\tthis.writeFile(\n\t\t\t'/internal/shared/consts.json',\n\t\t\tJSON.stringify({\n\t\t\t\t...consts,\n\t\t\t\t[key]: value,\n\t\t\t})\n\t\t);\n\t}\n\n\t/**\n\t * Executes a PHP runtime function with proper error handling and streaming setup.\n\t * Sets up streaming infrastructure and returns a StreamedPHPResponse.\n\t *\n\t * @param executionFn - Function that returns the exit code or a promise of exit code\n\t * @returns Promise that resolves to a StreamedPHPResponse\n\t */\n\tasync #executeWithErrorHandling(\n\t\texecutionFn: () => any\n\t): Promise<StreamedPHPResponse> {\n\t\tif (\n\t\t\tthis.#rotationOptions.enabled &&\n\t\t\tthis.#rotationOptions.needsRotating\n\t\t) {\n\t\t\tawait this.rotateRuntime();\n\t\t}\n\t\t++this.#rotationOptions.requestsMade;\n\t\tif (\n\t\t\tthis.#rotationOptions.requestsMade >=\n\t\t\tthis.#rotationOptions.maxRequests\n\t\t) {\n\t\t\tthis.#rotationOptions.needsRotating = true;\n\t\t}\n\n\t\tconst emscriptenModule = this[__private__dont__use];\n\n\t\tconst headers = await createInvertedReadableStream<Uint8Array>();\n\t\temscriptenModule.onHeaders = (chunk: Uint8Array) => {\n\t\t\tif (streamsClosed || headersClosed) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// slice() chunk to clone the data and preserve it for the reader later on.\n\t\t\t// We need that because the ArrayBuffer underlying `chunk` may change\n\t\t\t// after this callback return. Without cloning, the reader would read\n\t\t\t// whatever bytes are available in the ArrayBuffer at the time of the read.\n\t\t\theaders.controller.enqueue(chunk.slice());\n\t\t};\n\t\tlet headersClosed = false;\n\t\tconst closeHeadersStream = () => {\n\t\t\tif (!headersClosed) {\n\t\t\t\theadersClosed = true;\n\t\t\t\theaders.controller.close();\n\t\t\t}\n\t\t};\n\n\t\tconst stdout = await createInvertedReadableStream<Uint8Array>();\n\t\temscriptenModule.onStdout = (chunk: Uint8Array) => {\n\t\t\tcloseHeadersStream();\n\t\t\tif (streamsClosed) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstdout.controller.enqueue(chunk.slice());\n\t\t};\n\n\t\tconst stderr = await createInvertedReadableStream<Uint8Array>();\n\t\temscriptenModule.onStderr = (chunk: Uint8Array) => {\n\t\t\tif (streamsClosed) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstderr.controller.enqueue(chunk.slice());\n\t\t};\n\n\t\tlet streamsClosed = false;\n\n\t\tlet errorListener: any;\n\n\t\tconst runExecutionFunction = async () => {\n\t\t\ttry {\n\t\t\t\t/*\n\t\t\t\t * Emscripten throws WASM failures outside of the promise chain so we need\n\t\t\t\t * to listen for them here and rethrow in the correct context. Otherwise we\n\t\t\t\t * get crashes and unhandled promise rejections without any useful error\n\t\t\t\t * messages or meaningful stack traces.\n\t\t\t\t */\n\t\t\t\tconst exitCode = await Promise.race([\n\t\t\t\t\texecutionFn(),\n\t\t\t\t\tnew Promise((_, reject) => {\n\t\t\t\t\t\terrorListener = (e: ErrorEvent) => {\n\t\t\t\t\t\t\tif (!isExitCode(e.error)) {\n\t\t\t\t\t\t\t\treject(e.error);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t\tthis.#wasmErrorsTarget?.addEventListener(\n\t\t\t\t\t\t\t'error',\n\t\t\t\t\t\t\terrorListener,\n\t\t\t\t\t\t\t{ once: true }\n\t\t\t\t\t\t);\n\t\t\t\t\t}),\n\t\t\t\t]);\n\t\t\t\treturn exitCode;\n\t\t\t} catch (e) {\n\t\t\t\t/**\n\t\t\t\t * Emscripten sometimes communicates program exit as an error. Let's\n\t\t\t\t * turn exit code errors into integers again.\n\t\t\t\t */\n\t\t\t\tif (isExitCode(e)) {\n\t\t\t\t\treturn e.status;\n\t\t\t\t}\n\n\t\t\t\t// Non-exit-code errors indicate a WASM runtime crash. Let's clean up and throw.\n\t\t\t\tstdout.controller.error(e);\n\t\t\t\tstderr.controller.error(e);\n\t\t\t\theaders.controller.error(e);\n\t\t\t\tstreamsClosed = true;\n\n\t\t\t\t/**\n\t\t\t\t * A non-exit-code error means an irrecoverable crash. Let's make\n\t\t\t\t * it very clear to the consumers of this API – every method\n\t\t\t\t * call on this PHP instance will throw an error from now on.\n\t\t\t\t */\n\t\t\t\tfor (const name in this) {\n\t\t\t\t\tif (typeof this[name] === 'function') {\n\t\t\t\t\t\t(this as any)[name] = () => {\n\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t`PHP runtime has crashed – see the earlier error for details.`\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t(this as any).functionsMaybeMissingFromAsyncify =\n\t\t\t\t\tgetFunctionsMaybeMissingFromAsyncify();\n\n\t\t\t\tthrow e;\n\t\t\t} finally {\n\t\t\t\tif (!streamsClosed) {\n\t\t\t\t\tstdout.controller.close();\n\t\t\t\t\tstderr.controller.close();\n\t\t\t\t\tcloseHeadersStream();\n\t\t\t\t\tstreamsClosed = true;\n\t\t\t\t}\n\t\t\t\tthis.#wasmErrorsTarget?.removeEventListener(\n\t\t\t\t\t'error',\n\t\t\t\t\terrorListener\n\t\t\t\t);\n\t\t\t}\n\t\t};\n\n\t\t/**\n\t\t * Dispatch a request.error event for any global crash handlers. For example,\n\t\t * Playground web uses this to automatically display a \"Report crash\" modal.\n\t\t */\n\t\tconst exitCodePromise = runExecutionFunction().then(\n\t\t\t(exitCode) => {\n\t\t\t\t/**\n\t\t\t\t * Emit errors related to PHP script failures (exit code other than 0)\n\t\t\t\t */\n\t\t\t\tif (exitCode !== 0) {\n\t\t\t\t\tthis.dispatchEvent({\n\t\t\t\t\t\ttype: 'request.error',\n\t\t\t\t\t\terror: new Error(\n\t\t\t\t\t\t\t`PHP.run() failed with exit code ${exitCode}.`\n\t\t\t\t\t\t),\n\t\t\t\t\t\t// Distinguish between PHP request and PHP-wasm errors\n\t\t\t\t\t\tsource: 'php-wasm',\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn exitCode;\n\t\t\t},\n\t\t\t(error) => {\n\t\t\t\t/**\n\t\t\t\t * Emit all other errors.\n\t\t\t\t */\n\t\t\t\t// Distinguish between PHP request and PHP-wasm errors\n\t\t\t\tconst source = (error as any).source ?? 'php-wasm';\n\t\t\t\tthis.dispatchEvent({\n\t\t\t\t\ttype: 'request.error',\n\t\t\t\t\terror: error as any as Error,\n\t\t\t\t\tsource,\n\t\t\t\t});\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t);\n\n\t\treturn new StreamedPHPResponse(\n\t\t\theaders.stream,\n\t\t\tstdout.stream,\n\t\t\tstderr.stream,\n\t\t\texitCodePromise\n\t\t);\n\t}\n\n\t/**\n\t * Recursively creates a directory with the given path in the PHP filesystem.\n\t * For example, if the path is `/root/php/data`, and `/root` already exists,\n\t * it will create the directories `/root/php` and `/root/php/data`.\n\t *\n\t * @param path - The directory path to create.\n\t */\n\tmkdir(path: string) {\n\t\tconst result = FSHelpers.mkdir(this[__private__dont__use].FS, path);\n\t\tthis.dispatchEvent({ type: 'filesystem.write' });\n\t\treturn result;\n\t}\n\n\t/**\n\t * @deprecated Use mkdir instead.\n\t */\n\tmkdirTree(path: string) {\n\t\treturn FSHelpers.mkdir(this[__private__dont__use].FS, path);\n\t}\n\n\t/**\n\t * Reads a file from the PHP filesystem and returns it as a string.\n\t *\n\t * @throws {@link @php-wasm/universal:ErrnoError} – If the file doesn't exist.\n\t * @param path - The file path to read.\n\t * @returns The file contents.\n\t */\n\treadFileAsText(path: string) {\n\t\treturn FSHelpers.readFileAsText(this[__private__dont__use].FS, path);\n\t}\n\n\t/**\n\t * Reads a file from the PHP filesystem and returns it as an array buffer.\n\t *\n\t * @throws {@link @php-wasm/universal:ErrnoError} – If the file doesn't exist.\n\t * @param path - The file path to read.\n\t * @returns The file contents.\n\t */\n\treadFileAsBuffer(path: string): Uint8Array {\n\t\treturn FSHelpers.readFileAsBuffer(this[__private__dont__use].FS, path);\n\t}\n\n\t/**\n\t * Overwrites data in a file in the PHP filesystem.\n\t * Creates a new file if one doesn't exist yet.\n\t *\n\t * @param path - The file path to write to.\n\t * @param data - The data to write to the file.\n\t */\n\twriteFile(path: string, data: string | Uint8Array | Buffer) {\n\t\tconst result = FSHelpers.writeFile(\n\t\t\tthis[__private__dont__use].FS,\n\t\t\tpath,\n\t\t\tdata\n\t\t);\n\t\tthis.dispatchEvent({ type: 'filesystem.write' });\n\t\treturn result;\n\t}\n\n\t/**\n\t * Removes a file from the PHP filesystem.\n\t *\n\t * @throws {@link @php-wasm/universal:ErrnoError} – If the file doesn't exist.\n\t * @param path - The file path to remove.\n\t */\n\tunlink(path: string) {\n\t\tconst result = FSHelpers.unlink(this[__private__dont__use].FS, path);\n\t\tthis.dispatchEvent({ type: 'filesystem.write' });\n\t\treturn result;\n\t}\n\n\t/**\n\t * Moves a file or directory in the PHP filesystem to a\n\t * new location.\n\t *\n\t * @param oldPath The path to rename.\n\t * @param newPath The new path.\n\t */\n\tmv(fromPath: string, toPath: string) {\n\t\tconst result = FSHelpers.mv(\n\t\t\tthis[__private__dont__use].FS,\n\t\t\tfromPath,\n\t\t\ttoPath\n\t\t);\n\t\tthis.dispatchEvent({ type: 'filesystem.write' });\n\t\treturn result;\n\t}\n\n\t/**\n\t * Removes a directory from the PHP filesystem.\n\t *\n\t * @param path The directory path to remove.\n\t * @param options Options for the removal.\n\t */\n\trmdir(path: string, options: RmDirOptions = { recursive: true }) {\n\t\tconst result = FSHelpers.rmdir(\n\t\t\tthis[__private__dont__use].FS,\n\t\t\tpath,\n\t\t\toptions\n\t\t);\n\t\tthis.dispatchEvent({ type: 'filesystem.write' });\n\t\treturn result;\n\t}\n\n\t/**\n\t * Lists the files and directories in the given directory.\n\t *\n\t * @param path - The directory path to list.\n\t * @param options - Options for the listing.\n\t * @returns The list of files and directories in the given directory.\n\t */\n\tlistFiles(\n\t\tpath: string,\n\t\toptions: ListFilesOptions = { prependPath: false }\n\t) {\n\t\treturn FSHelpers.listFiles(\n\t\t\tthis[__private__dont__use].FS,\n\t\t\tpath,\n\t\t\toptions\n\t\t);\n\t}\n\n\t/**\n\t * Checks if a directory exists in the PHP filesystem.\n\t *\n\t * @param path – The path to check.\n\t * @returns True if the path is a directory, false otherwise.\n\t */\n\tisDir(path: string) {\n\t\treturn FSHelpers.isDir(this[__private__dont__use].FS, path);\n\t}\n\n\t/**\n\t * Checks if a file exists in the PHP filesystem.\n\t *\n\t * @param path – The path to check.\n\t * @returns True if the path is a file, false otherwise.\n\t */\n\tisFile(path: string) {\n\t\treturn FSHelpers.isFile(this[__private__dont__use].FS, path);\n\t}\n\n\t/**\n\t * Creates a symlink in the PHP filesystem.\n\t * @param target\n\t * @param path\n\t */\n\tsymlink(target: string, path: string) {\n\t\treturn FSHelpers.symlink(this[__private__dont__use].FS, target, path);\n\t}\n\n\t/**\n\t * Checks if a path is a symlink in the PHP filesystem.\n\t *\n\t * @param path\n\t * @returns True if the path is a symlink, false otherwise.\n\t */\n\tisSymlink(path: string) {\n\t\treturn FSHelpers.isSymlink(this[__private__dont__use].FS, path);\n\t}\n\n\t/**\n\t * Reads the target of a symlink in the PHP filesystem.\n\t *\n\t * @param path\n\t * @returns The target of the symlink.\n\t */\n\treadlink(path: string) {\n\t\treturn FSHelpers.readlink(this[__private__dont__use].FS, path);\n\t}\n\n\t/**\n\t * Resolves the real path of a file in the PHP filesystem.\n\t * @param path\n\t * @returns The real path of the file.\n\t */\n\trealpath(path: string) {\n\t\treturn FSHelpers.realpath(this[__private__dont__use].FS, path);\n\t}\n\n\t/**\n\t * Checks if a file (or a directory) exists in the PHP filesystem.\n\t *\n\t * @param path - The file path to check.\n\t * @returns True if the file exists, false otherwise.\n\t */\n\tfileExists(path: string) {\n\t\treturn FSHelpers.fileExists(this[__private__dont__use].FS, path);\n\t}\n\n\t/**\n\t * Enables inline PHP runtime rotation after a certain number of requests\n\t * or an internal crash.\n\t */\n\tenableRuntimeRotation(options: {\n\t\trecreateRuntime: () => Promise<number> | number;\n\t\tmaxRequests?: number;\n\t}) {\n\t\tthis.#rotationOptions = {\n\t\t\t...this.#rotationOptions,\n\t\t\tenabled: true,\n\t\t\trecreateRuntime: options.recreateRuntime,\n\t\t\tmaxRequests: options.maxRequests ?? 400,\n\t\t};\n\t}\n\n\tprivate async rotateRuntime() {\n\t\tif (!this.#rotationOptions.enabled) {\n\t\t\tthrow new Error(\n\t\t\t\t'Runtime rotation is not enabled. Call enableRuntimeRotation() first.'\n\t\t\t);\n\t\t}\n\t\tawait this.hotSwapPHPRuntime(\n\t\t\tawait this.#rotationOptions.recreateRuntime()\n\t\t);\n\t\tthis.#rotationOptions.requestsMade = 0;\n\t\tthis.#rotationOptions.needsRotating = false;\n\t}\n\n\t/**\n\t * Hot-swaps the PHP runtime for a new one without\n\t * interrupting the operations of this PHP instance.\n\t *\n\t * @param runtime\n\t */\n\tasync hotSwapPHPRuntime(runtime: number) {\n\t\t// Once we secure the lock and have the new runtime ready,\n\t\t// the rest of the swap handler is synchronous to make sure\n\t\t// no other operations acts on the old runtime or FS.\n\t\t// If there was await anywhere here, we'd risk applyng\n\t\t// asynchronous changes to either the filesystem or the\n\t\t// old PHP runtime without propagating them to the new\n\t\t// runtime.\n\n\t\tconst oldFS = this[__private__dont__use].FS;\n\t\tconst oldRootLevelPaths = this.listFiles('/').map((file) => `/${file}`);\n\t\tconst oldSpawnProcess = this[__private__dont__use].spawnProcess;\n\n\t\t// Temporarily set CWD to / and restore it at the end of this method.\n\t\t//\n\t\t// There's a chance cleaning up old mounts via mount.unmount()\n\t\t// will attempt removing the CWD. Normally, this would throw\n\t\t// FS.ErrnoError(10) EBUSY and interrupt the PHP runtime rotation,\n\t\t// leaving us in a broken state.\n\t\t//\n\t\t// Even though removing the CWD directory is not allowed by the\n\t\t// filesystem, we don't care that much here – we're merely freeing\n\t\t// all the resources allocated by the old filesystem before it's\n\t\t// garbage collected. We are about to recreate the same filesystem\n\t\t// structure and mounts in another PHP runtime.\n\t\t//\n\t\t// Therefore, let's suspend the strict EBUSY check by setting the CWD\n\t\t// to / for the cleanup purposes. We'll attempt to restore the original\n\t\t// CWD on the new runtime once we re-apply all the mounts there. We'll\n\t\t// only have a real reason to throw an error if the CWD path does not\n\t\t// exist in the new filesystem after the rotation.\n\t\tconst oldCWD = oldFS.cwd();\n\t\toldFS.chdir('/');\n\n\t\t// Remember mounts to apply to new runtime\n\t\tconst mountHandlersToReapplyInOrder = Object.entries(this.#mounts).map(\n\t\t\t([vfsPath, mount]) => ({\n\t\t\t\tmountHandler: mount.mountHandler,\n\t\t\t\tvfsPath,\n\t\t\t})\n\t\t);\n\n\t\t// Unmount all the mount handlers in reverse order because each nested\n\t\t// mount depends upon the parent mount which preceded it.\n\t\tconst mountsToUnmountInReverseOrder = Object.values(\n\t\t\tthis.#mounts\n\t\t).reverse();\n\t\tfor (const mount of mountsToUnmountInReverseOrder) {\n\t\t\tawait mount.unmount();\n\t\t}\n\n\t\t// Kill the current runtime\n\t\ttry {\n\t\t\tthis.exit();\n\t\t} catch {\n\t\t\t// Ignore the exit-related exception\n\t\t}\n\n\t\t// Initialize the new runtime\n\t\tthis.initializeRuntime(runtime);\n\n\t\tif (oldSpawnProcess) {\n\t\t\tthis[__private__dont__use].spawnProcess = oldSpawnProcess;\n\t\t}\n\n\t\tif (this.#sapiName) {\n\t\t\tthis.setSapiName(this.#sapiName);\n\t\t}\n\n\t\t/**\n\t\t * Ensure the new PHP instance has the same file structure as the old one.\n\t\t *\n\t\t * Catch: The underlying filesystems may be completely separate but they may be\n\t\t * partially shared via NODEFS or PROXYFS mounts. We need to be careful and only\n\t\t * recreate the MEMFS directories that aren't already shared – otherwise we'll\n\t\t * write data to shared paths that other, concurrent workers may be using.\n\t\t */\n\t\tconst newFs = this[__private__dont__use].FS;\n\t\tfor (const path of oldRootLevelPaths) {\n\t\t\t// The /request directory holds per-request state that is isolated to a\n\t\t\t// single PHP instance. Let's not copy it.\n\t\t\tif (path && path !== '/request') {\n\t\t\t\tcopyMEMFSNodes(oldFS, newFs, path);\n\t\t\t}\n\t\t}\n\n\t\t// Re-mount all the mount handlers in order\n\t\tfor (const { mountHandler, vfsPath } of mountHandlersToReapplyInOrder) {\n\t\t\tthis.mkdir(vfsPath);\n\t\t\tawait this.mount(vfsPath, mountHandler);\n\t\t}\n\t\ttry {\n\t\t\tnewFs.chdir(oldCWD);\n\t\t} catch (e) {\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to restore CWD to ${oldCWD} after PHP runtime rotation.`,\n\t\t\t\t{\n\t\t\t\t\tcause: e,\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Mounts a filesystem to a given path in the PHP filesystem.\n\t *\n\t * @param virtualFSPath - Where to mount it in the PHP virtual filesystem.\n\t * @param mountHandler - The mount handler to use.\n\t * @return Unmount function to unmount the filesystem.\n\t */\n\tasync mount(\n\t\tvirtualFSPath: string,\n\t\tmountHandler: MountHandler\n\t): Promise<UnmountFunction> {\n\t\tconst unmountCallback = await mountHandler(\n\t\t\tthis,\n\t\t\tthis[__private__dont__use].FS,\n\t\t\tvirtualFSPath\n\t\t);\n\t\tconst mountObject = {\n\t\t\tmountHandler,\n\t\t\tunmount: async () => {\n\t\t\t\tawait unmountCallback();\n\t\t\t\tdelete this.#mounts[virtualFSPath];\n\t\t\t},\n\t\t};\n\t\tthis.#mounts[virtualFSPath] = mountObject;\n\t\treturn () => {\n\t\t\tmountObject.unmount();\n\t\t};\n\t}\n\n\t/**\n\t * Starts a PHP CLI session with given arguments.\n\t *\n\t * This method can only be used when PHP was compiled with the CLI SAPI\n\t * and it cannot be used in conjunction with `run()`.\n\t *\n\t * Once this method finishes running, the PHP instance is no\n\t * longer usable and should be discarded. This is because PHP\n\t * internally cleans up all the resources and calls exit().\n\t *\n\t * @param argv - The arguments to pass to the CLI.\n\t * @returns The exit code of the CLI session.\n\t */\n\tasync cli(\n\t\targv: string[],\n\t\toptions: { env?: Record<string, string>; cwd?: string } = {}\n\t): Promise<StreamedPHPResponse> {\n\t\tif (basename(argv[0] ?? '') !== 'php') {\n\t\t\treturn this.subProcess(argv, options);\n\t\t}\n\n\t\tif (this.#phpWasmInitCalled) {\n\t\t\tthis.#rotationOptions.needsRotating = true;\n\t\t}\n\n\t\tconst release = await this.semaphore.acquire();\n\n\t\treturn await this.#executeWithErrorHandling(() => {\n\t\t\tconst env = options.env || {};\n\t\t\tfor (const [key, value] of Object.entries(env)) {\n\t\t\t\tthis.#setEnv(key, value);\n\t\t\t}\n\t\t\t// Enforce the use of the internal php.ini file.\n\t\t\targv = [argv[0], '-c', PHP_INI_PATH, ...argv.slice(1)];\n\t\t\tfor (const arg of argv) {\n\t\t\t\tthis[__private__dont__use].ccall(\n\t\t\t\t\t'wasm_add_cli_arg',\n\t\t\t\t\tnull,\n\t\t\t\t\t[STRING],\n\t\t\t\t\t[arg]\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn this[__private__dont__use].ccall('run_cli', null, [], [], {\n\t\t\t\tasync: true,\n\t\t\t});\n\t\t})\n\t\t\t.then((response) => {\n\t\t\t\tresponse.exitCode.finally(release);\n\t\t\t\treturn response;\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\tthis.#rotationOptions.needsRotating = true;\n\t\t\t});\n\t}\n\n\t/**\n\t * Runs an arbitrary CLI command using the spawn handler associated\n\t * with this PHP instance.\n\t *\n\t * @param argv\n\t * @param options\n\t * @returns StreamedPHPResponse.\n\t */\n\tprivate async subProcess(\n\t\targv: string[],\n\t\toptions: { env?: Record<string, string>; cwd?: string } = {}\n\t): Promise<StreamedPHPResponse> {\n\t\tconst process = this[__private__dont__use].spawnProcess(\n\t\t\targv[0],\n\t\t\targv.slice(1),\n\t\t\t{\n\t\t\t\tenv: options.env,\n\t\t\t\tcwd: options.cwd ?? this.cwd(),\n\t\t\t}\n\t\t) as ChildProcess;\n\n\t\tconst stderrStream = await createInvertedReadableStream<Uint8Array>();\n\t\tprocess.on('error', (error) => {\n\t\t\tstderrStream.controller.error(error);\n\t\t});\n\t\tprocess.stderr.on('data', (data) => {\n\t\t\tstderrStream.controller.enqueue(data);\n\t\t});\n\n\t\tconst stdoutStream = await createInvertedReadableStream<Uint8Array>();\n\t\tprocess.stdout.on('data', (data) => {\n\t\t\tstdoutStream.controller.enqueue(data);\n\t\t});\n\n\t\tprocess.on('exit', () => {\n\t\t\t// Delay until next tick to ensure we don't close the streams before\n\t\t\t// emitting the error event on the stderrStream.\n\t\t\tsetTimeout(() => {\n\t\t\t\t/**\n\t\t\t\t * Ignore any close() errors, e.g. \"stream already closed\". We just\n\t\t\t\t * need to try to call close() and forget about this subprocess.\n\t\t\t\t */\n\t\t\t\ttry {\n\t\t\t\t\tstderrStream.controller.close();\n\t\t\t\t} catch {\n\t\t\t\t\t// Ignore error\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tstdoutStream.controller.close();\n\t\t\t\t} catch {\n\t\t\t\t\t// Ignore error\n\t\t\t\t}\n\t\t\t}, 0);\n\t\t});\n\n\t\treturn new StreamedPHPResponse(\n\t\t\t// Headers stream\n\t\t\tnew ReadableStream({\n\t\t\t\tstart(controller) {\n\t\t\t\t\tcontroller.close();\n\t\t\t\t},\n\t\t\t}),\n\t\t\tstdoutStream.stream,\n\t\t\tstderrStream.stream,\n\t\t\t// Exit code\n\t\t\tnew Promise((resolve) => {\n\t\t\t\tprocess.on('exit', (code) => {\n\t\t\t\t\tresolve(code);\n\t\t\t\t});\n\t\t\t})\n\t\t);\n\t}\n\n\tsetSkipShebang(shouldSkip: boolean) {\n\t\tthis[__private__dont__use].ccall(\n\t\t\t'wasm_set_skip_shebang',\n\t\t\tnull,\n\t\t\t[NUMBER],\n\t\t\t[shouldSkip ? 1 : 0]\n\t\t);\n\t}\n\n\texit(code = 0) {\n\t\tthis.dispatchEvent({\n\t\t\ttype: 'runtime.beforeExit',\n\t\t});\n\t\ttry {\n\t\t\tthis[__private__dont__use]._exit(code);\n\t\t} catch {\n\t\t\t// ignore the exit error\n\t\t}\n\n\t\t// Clean up any initialized state\n\t\tthis.#phpWasmInitCalled = false;\n\n\t\t// Delete any links between this PHP instance and the runtime\n\t\tthis.#wasmErrorsTarget = null;\n\n\t\tif (this[__private__dont__use]) {\n\t\t\tdelete this[__private__dont__use]['onMessage'];\n\t\t\tdelete this[__private__dont__use];\n\t\t}\n\t}\n\n\t[Symbol.dispose]() {\n\t\tthis.exit(0);\n\t}\n}\n\nexport function normalizeHeaders(\n\theaders: PHPRequestHeaders\n): PHPRequestHeaders {\n\tconst normalized: PHPRequestHeaders = {};\n\tfor (const key in headers) {\n\t\tnormalized[key.toLowerCase()] = headers[key];\n\t}\n\treturn normalized;\n}\n\n/**\n * Copies the MEMFS directory structure from one FS in another FS.\n * Non-MEMFS nodes are ignored.\n */\nfunction copyMEMFSNodes(\n\tsource: Emscripten.FileSystemInstance,\n\ttarget: Emscripten.FileSystemInstance,\n\tpath: string\n) {\n\tif (\n\t\tgetNodeType(source, path) !== 'memfs' ||\n\t\t!['memfs', 'missing'].includes(getNodeType(target, path))\n\t) {\n\t\treturn;\n\t}\n\n\tconst oldNode = source.lookupPath(path);\n\tif (!source.isDir(oldNode.node.mode)) {\n\t\ttarget.writeFile(path, source.readFile(path));\n\t\treturn;\n\t}\n\n\ttarget.mkdirTree(path);\n\tconst filenames = source\n\t\t.readdir(path)\n\t\t.filter((name: string) => name !== '.' && name !== '..');\n\tfor (const filename of filenames) {\n\t\tcopyMEMFSNodes(source, target, joinPaths(path, filename));\n\t}\n}\n\n/**\n * Creates a readable stream with inverted control flow,\n * based on the specified underlying source.\n *\n * In this case, inverting control flow means exposing the controller\n * so the consumer can insert data into the stream.\n *\n * @param source - The underlying source to use.\n * @returns The resulting stream and its associated controller.\n */\nasync function createInvertedReadableStream<T = BufferSource>(\n\tsource: UnderlyingSource<T> = {}\n): Promise<{\n\tstream: ReadableStream<T>;\n\tcontroller: ReadableStreamDefaultController<T>;\n}> {\n\tlet controllerResolve: (\n\t\tcontroller: ReadableStreamDefaultController<T>\n\t) => void;\n\tconst controllerPromise = new Promise<ReadableStreamDefaultController<T>>(\n\t\t(resolve) => {\n\t\t\tcontrollerResolve = resolve;\n\t\t}\n\t);\n\n\tconst stream = new ReadableStream<T>({\n\t\t...source,\n\t\tstart(controller) {\n\t\t\t// Type assertion to handle the controller type mismatch\n\t\t\tcontrollerResolve(controller as ReadableStreamDefaultController<T>);\n\t\t\tif (source.start) {\n\t\t\t\treturn source.start(controller);\n\t\t\t}\n\t\t\treturn undefined;\n\t\t},\n\t});\n\n\tconst controller = await controllerPromise;\n\n\treturn {\n\t\tstream,\n\t\tcontroller,\n\t};\n}\n\nconst getNodeType = (fs: Emscripten.FileSystemInstance, path: string) => {\n\ttry {\n\t\tconst target = fs.lookupPath(path, { follow: true });\n\t\treturn 'contents' in target.node\n\t\t\t? 'memfs'\n\t\t\t: /**\n\t\t\t\t * Could be NODEFS, PROXYFS, etc.\n\t\t\t\t */\n\t\t\t\t'not-memfs';\n\t} catch {\n\t\treturn 'missing';\n\t}\n};\n","import { PHP_INI_PATH } from './php';\nimport type { UniversalPHP } from './universal-php';\nimport { stringify, parse } from 'ini';\n\n/**\n * Reads the php.ini file and returns its entries.\n *\n * @param php The PHP instance.\n * @param entries Optional. If provided, only the specified entries will be returned.\n * @returns The php.ini entries.\n */\nexport async function getPhpIniEntries(php: UniversalPHP, entries?: string[]) {\n\tconst ini = parse(await php.readFileAsText(PHP_INI_PATH));\n\tif (entries === undefined) {\n\t\treturn ini;\n\t}\n\tconst result: Record<string, unknown> = {};\n\tfor (const key of entries) {\n\t\tresult[key] = ini[key];\n\t}\n\treturn result;\n}\n\n/**\n * Rewrites the php.ini file with the given entries.\n *\n * @param php The PHP instance.\n * @param entries The entries to write to the php.ini file.\n */\nexport async function setPhpIniEntries(\n\tphp: UniversalPHP,\n\tentries: Record<string, unknown>\n) {\n\tconst ini = parse(await php.readFileAsText(PHP_INI_PATH));\n\tfor (const [key, value] of Object.entries(entries)) {\n\t\tif (value === undefined || value === null) {\n\t\t\tdelete ini[key];\n\t\t} else {\n\t\t\tini[key] = value;\n\t\t}\n\t}\n\tawait php.writeFile(PHP_INI_PATH, stringify(ini));\n}\n\n/**\n * Sets php.ini values to the given values, executes a callback,\n * and restores the original php.ini values. This is useful for\n * running code with temporary php.ini values, such as when\n * disabling network-related PHP functions just to run WordPress\n * installer.\n *\n * @example\n * ```ts\n *\tawait withPHPIniValues(\n *\t\tphp,\n *\t\t{\n *\t\t\tdisable_functions: 'fsockopen',\n *\t\t\tallow_url_fopen: '0',\n *\t\t},\n *\t\tasync () => await runWpInstallationWizard(php, {\n *\t\t\toptions: {},\n *\t\t})\n *\t);\n *\t```\n *\n * @param php The PHP instance.\n * @param phpIniValues The php.ini values to set.\n * @param callback The callback to execute.\n * @returns The result of the callback.\n */\nexport async function withPHPIniValues(\n\tphp: UniversalPHP,\n\tphpIniValues: Record<string, string>,\n\tcallback: () => Promise<any>\n) {\n\tconst iniBefore = await php.readFileAsText(PHP_INI_PATH);\n\ttry {\n\t\tawait setPhpIniEntries(php, phpIniValues);\n\t\treturn await callback();\n\t} finally {\n\t\tawait php.writeFile(PHP_INI_PATH, iniBefore);\n\t}\n}\n","import type { StreamedPHPResponse } from './php-response';\nimport { PHPResponse } from './php-response';\n\nexport async function printDebugDetails(\n\te: any,\n\tstreamedResponse?: StreamedPHPResponse\n) {\n\tif (streamedResponse) {\n\t\tprintResponseDebugDetails(\n\t\t\tawait PHPResponse.fromStreamedResponse(streamedResponse)\n\t\t);\n\t}\n\tawait prettyPrintFullStackTrace(e);\n}\n\n/**\n * Pretty prints the full stack trace of the error and all its causes.\n * Includes debug details for each error in the chain.\n * This is needed\n *\n * @param e\n */\nexport async function prettyPrintFullStackTrace(e: any) {\n\tlet current = e;\n\tlet isFirst = true;\n\twhile (current) {\n\t\tif (!isFirst) {\n\t\t\tprocess.stderr.write('\\nCaused by:\\n\\n');\n\t\t}\n\n\t\tprocess.stderr.write(current.originalErrorClassName ?? current.name);\n\t\tprocess.stderr.write(': ' + current.message + '\\n');\n\t\tprocess.stderr.write(\n\t\t\t(current.stack + '').split('\\n').slice(1).join('\\n')\n\t\t);\n\t\tprocess.stderr.write(`\\n`);\n\t\tif (current.response) {\n\t\t\tprintResponseDebugDetails(current.response);\n\t\t}\n\t\tif (current.phpLogs) {\n\t\t\tprocess.stderr.write(`\\n\\n==== PHP error log ====\\n\\n`);\n\t\t\tprocess.stderr.write(current.phpLogs);\n\t\t}\n\t\tcurrent = current.cause;\n\t\tisFirst = false;\n\t}\n\tprocess.stderr.write('\\n');\n}\n\nexport function printResponseDebugDetails(response: PHPResponse) {\n\t// Print a short summary of what we have:\n\tprocess.stderr.write(\n\t\t`\\n exitCode=${response.exitCode} httpStatusCode=${response.httpStatusCode} `\n\t);\n\tconst hasHeaders =\n\t\tresponse.headers && Object.keys(response.headers).length > 0;\n\tif (!hasHeaders) {\n\t\tprocess.stderr.write(`responseHeaders=(empty) `);\n\t}\n\tif (!response.text) {\n\t\tprocess.stderr.write(`stdout=(empty) `);\n\t}\n\tif (!response.errors) {\n\t\tprocess.stderr.write(`stderr=(empty) `);\n\t}\n\tprocess.stderr.write(`\\n`);\n\n\t// Print all the extended information in a separate section:\n\tif (hasHeaders) {\n\t\tprocess.stderr.write(\n\t\t\t`\\n==== PHP response headers ====\\n\\n${JSON.stringify(\n\t\t\t\tresponse.headers,\n\t\t\t\tnull,\n\t\t\t\t2\n\t\t\t)}\\n\\n`\n\t\t);\n\t}\n\n\tif (response.text) {\n\t\tprocess.stderr.write(`\\n==== PHP stdout ====\\n\\n`);\n\t\tprocess.stderr.write(response.text);\n\t}\n\n\tif (response.errors) {\n\t\tprocess.stderr.write(`\\n==== PHP stderr ====\\n\\n`);\n\t\tprocess.stderr.write(response.errors);\n\t}\n\tprocess.stderr.write(`\\n`);\n}\n","import { logger } from '@php-wasm/logger';\nimport type { CookieStore } from './php-request-handler';\n/**\n * @public\n */\nexport class HttpCookieStore implements CookieStore {\n\tcookies: Record<string, string> = {};\n\n\trememberCookiesFromResponseHeaders(headers: Record<string, string[]>) {\n\t\tif (!headers?.['set-cookie']) {\n\t\t\treturn;\n\t\t}\n\t\tfor (const setCookie of headers['set-cookie']) {\n\t\t\ttry {\n\t\t\t\tif (!setCookie.includes('=')) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst equalsIndex = setCookie.indexOf('=');\n\t\t\t\tconst name = setCookie.substring(0, equalsIndex);\n\t\t\t\tconst value = setCookie\n\t\t\t\t\t.substring(equalsIndex + 1)\n\t\t\t\t\t.split(';')[0];\n\t\t\t\tthis.cookies[name] = value;\n\t\t\t} catch (e) {\n\t\t\t\tlogger.error(e);\n\t\t\t}\n\t\t}\n\t}\n\n\tgetCookieRequestHeader() {\n\t\tconst cookiesArray: string[] = [];\n\t\tfor (const name in this.cookies) {\n\t\t\tcookiesArray.push(`${name}=${this.cookies[name]}`);\n\t\t}\n\t\treturn cookiesArray.join('; ');\n\t}\n}\n","import type { UniversalPHP } from './universal-php';\n\n/**\n * Reads a file from PHP filesystem using a stream.\n */\nexport function streamReadFileFromPHP(php: UniversalPHP, path: string) {\n\treturn new ReadableStream({\n\t\tasync pull(controller) {\n\t\t\tconst buffer = await php.readFileAsBuffer(path);\n\t\t\tcontroller.enqueue(buffer);\n\t\t\tcontroller.close();\n\t\t},\n\t});\n}\n","import { joinPaths, normalizePath } from '@php-wasm/util';\nimport { StreamedFile } from '@php-wasm/stream-compression';\nimport type { UniversalPHP } from './universal-php';\nimport { streamReadFileFromPHP } from './stream-read-file-from-php';\n\nexport type IteratePhpFilesOptions = {\n\t/**\n\t * Should yield paths relative to the root directory?\n\t * If false, all paths will be absolute.\n\t */\n\trelativePaths?: boolean;\n\n\t/**\n\t * A prefix to add to all paths.\n\t * Only used if `relativePaths` is true.\n\t */\n\tpathPrefix?: string;\n\n\t/**\n\t * A list of paths to exclude from the results.\n\t */\n\texceptPaths?: string[];\n};\n\n/**\n * Iterates over all files in a php directory and its subdirectories.\n *\n * @param php - The PHP instance.\n * @param root - The root directory to start iterating from.\n * @param options - Optional configuration.\n * @returns All files found in the tree.\n */\nexport async function* iteratePhpFiles(\n\tphp: UniversalPHP,\n\troot: string,\n\t{\n\t\trelativePaths = true,\n\t\tpathPrefix,\n\t\texceptPaths = [],\n\t}: IteratePhpFilesOptions = {}\n): AsyncGenerator<File> {\n\troot = normalizePath(root);\n\tconst stack: string[] = [root];\n\twhile (stack.length) {\n\t\tconst currentParent = stack.pop();\n\t\tif (!currentParent) {\n\t\t\treturn;\n\t\t}\n\t\tconst files = await php.listFiles(currentParent);\n\t\tfor (const file of files) {\n\t\t\tconst absPath = `${currentParent}/${file}`;\n\t\t\tif (exceptPaths.includes(absPath.substring(root.length + 1))) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst isDir = await php.isDir(absPath);\n\t\t\tif (isDir) {\n\t\t\t\tstack.push(absPath);\n\t\t\t} else {\n\t\t\t\tyield new StreamedFile(\n\t\t\t\t\tstreamReadFileFromPHP(php, absPath),\n\t\t\t\t\trelativePaths\n\t\t\t\t\t\t? joinPaths(\n\t\t\t\t\t\t\t\tpathPrefix || '',\n\t\t\t\t\t\t\t\tabsPath.substring(root.length + 1)\n\t\t\t\t\t\t )\n\t\t\t\t\t\t: absPath\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n}\n","import { dirname, joinPaths } from '@php-wasm/util';\nimport type { UniversalPHP } from './universal-php';\n\n/**\n * Writes streamed files to PHP filesystem.\n */\nexport function writeFilesStreamToPhp(php: UniversalPHP, root: string) {\n\treturn new WritableStream({\n\t\tasync write(file: File) {\n\t\t\tconst filePath = joinPaths(root, file.name);\n\t\t\tif (file.type === 'directory') {\n\t\t\t\tawait php.mkdir(filePath);\n\t\t\t} else {\n\t\t\t\tawait php.mkdir(dirname(filePath));\n\t\t\t\tawait php.writeFile(\n\t\t\t\t\tfilePath,\n\t\t\t\t\tnew Uint8Array(await file.arrayBuffer())\n\t\t\t\t);\n\t\t\t}\n\t\t},\n\t});\n}\n","import type { PHP } from './php';\nimport type { PHPInstanceManager, AcquiredPHP } from './php-instance-manager';\n\nexport interface SinglePHPInstanceManagerOptions {\n\t/**\n\t * Either provide an existing PHP instance...\n\t */\n\tphp?: PHP;\n\t/**\n\t * ...or a factory to create one on demand.\n\t */\n\tphpFactory?: () => Promise<PHP>;\n}\n\n/**\n * A minimal PHP instance manager that manages a single PHP instance.\n *\n * Unlike PHPProcessManager, this does not maintain a pool of instances\n * or implement concurrency control. It simply returns the same PHP\n * instance for every request.\n *\n * This is suitable for CLI contexts where:\n * - Only one PHP instance is needed\n * - Runtime rotation is handled separately via php.enableRuntimeRotation()\n * - Concurrency is not a concern (each worker has its own instance)\n */\nexport class SinglePHPInstanceManager implements PHPInstanceManager {\n\tprivate php: PHP | undefined;\n\tprivate phpPromise: Promise<PHP> | undefined;\n\tprivate phpFactory?: () => Promise<PHP>;\n\tprivate isAcquired = false;\n\n\tconstructor(options: SinglePHPInstanceManagerOptions) {\n\t\tif (!options.php && !options.phpFactory) {\n\t\t\tthrow new Error(\n\t\t\t\t'SinglePHPInstanceManager requires either php or phpFactory'\n\t\t\t);\n\t\t}\n\t\tthis.php = options.php;\n\t\tthis.phpFactory = options.phpFactory;\n\t}\n\n\tasync getPrimaryPhp(): Promise<PHP> {\n\t\tif (!this.php) {\n\t\t\tif (!this.phpPromise) {\n\t\t\t\tthis.phpPromise = this.phpFactory!().then((php) => {\n\t\t\t\t\tthis.php = php;\n\t\t\t\t\tthis.phpPromise = undefined;\n\t\t\t\t\treturn php;\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn this.phpPromise;\n\t\t}\n\t\treturn this.php;\n\t}\n\n\tasync acquirePHPInstance(): Promise<AcquiredPHP> {\n\t\tif (this.isAcquired) {\n\t\t\tthrow new Error(\n\t\t\t\t'The PHP instance already acquired. SinglePHPInstanceManager cannot spawn another PHP instance since, by definition, it only manages a single PHP instance.'\n\t\t\t);\n\t\t}\n\t\tconst php = await this.getPrimaryPhp();\n\t\tthis.isAcquired = true;\n\t\treturn {\n\t\t\tphp,\n\t\t\treap: () => {\n\t\t\t\t// For single-instance manager, reap is a no-op.\n\t\t\t\t// The instance is reused for all requests.\n\t\t\t\tthis.isAcquired = false;\n\t\t\t},\n\t\t};\n\t}\n\n\tasync [Symbol.asyncDispose](): Promise<void> {\n\t\tif (this.php) {\n\t\t\tthis.php.exit();\n\t\t}\n\t}\n}\n","import { AcquireTimeoutError, Semaphore } from '@php-wasm/util';\nimport type { PHP } from './php';\nimport type { PHPInstanceManager, AcquiredPHP } from './php-instance-manager';\n\nexport type PHPFactoryOptions = {\n\tisPrimary: boolean;\n};\n\nexport type PHPFactory = (options: PHPFactoryOptions) => Promise<PHP>;\n\nexport interface ProcessManagerOptions {\n\t/**\n\t * The maximum number of PHP instances that can be in use at\n\t * the same time.\n\t */\n\tmaxPhpInstances?: number;\n\t/**\n\t * The number of milliseconds to wait for a PHP instance when\n\t * all instances are busy. If the timeout is reached, we assume\n\t * all the PHP instances are deadlocked and throw MaxPhpInstancesError.\n\t *\n\t * Default: 30000\n\t */\n\ttimeout?: number;\n\t/**\n\t * A factory function used for spawning new PHP instances.\n\t */\n\tphpFactory?: PHPFactory;\n}\n\nexport class MaxPhpInstancesError extends Error {\n\tconstructor(limit: number) {\n\t\tsuper(\n\t\t\t`Requested more concurrent PHP instances than the limit (${limit}).`\n\t\t);\n\t\tthis.name = this.constructor.name;\n\t}\n}\n\n/**\n * A PHP Process manager that maintains a pool of reusable PHP instances.\n *\n * Instances are spawned on demand up to `maxPhpInstances` and reused across\n * requests. The first instance spawned is the \"primary\" instance which\n * contains the reference filesystem used by all other instances.\n *\n * The semaphore controls how many requests can be processed concurrently.\n * When all instances are busy, new requests wait in a queue until an\n * instance becomes available or the timeout is reached.\n */\nexport class PHPProcessManager implements PHPInstanceManager {\n\t/** All PHP instances that have been spawned. */\n\tprivate instances: PHP[] = [];\n\n\t/** Instances that are currently idle and available for use. */\n\tprivate idleInstances: PHP[] = [];\n\n\t/** Maximum number of concurrent PHP instances allowed. */\n\tprivate maxPhpInstances: number;\n\n\t/** Factory function for creating new PHP instances. */\n\tprivate phpFactory?: PHPFactory;\n\n\t/** Controls concurrent access to PHP instances. */\n\tprivate semaphore: Semaphore;\n\n\t/** Prevents spawning duplicate primary instances during concurrent calls. */\n\tprivate primaryPhpPromise?: Promise<PHP>;\n\n\tconstructor(options?: ProcessManagerOptions) {\n\t\tthis.maxPhpInstances = options?.maxPhpInstances ?? 2;\n\t\tthis.phpFactory = options?.phpFactory;\n\t\tthis.semaphore = new Semaphore({\n\t\t\tconcurrency: this.maxPhpInstances,\n\t\t\ttimeout: options?.timeout || 30000,\n\t\t});\n\t}\n\n\t/**\n\t * Get the primary PHP instance (the first one spawned).\n\t * If no instance exists yet, one will be spawned and marked as idle.\n\t */\n\tasync getPrimaryPhp(): Promise<PHP> {\n\t\tif (this.instances.length > 0) {\n\t\t\treturn this.instances[0];\n\t\t}\n\n\t\tif (!this.primaryPhpPromise) {\n\t\t\tthis.primaryPhpPromise = this.spawnInstance(true);\n\t\t}\n\t\ttry {\n\t\t\treturn await this.primaryPhpPromise;\n\t\t} finally {\n\t\t\tthis.primaryPhpPromise = undefined;\n\t\t}\n\t}\n\n\t/**\n\t * Acquire a PHP instance for processing a request.\n\t *\n\t * Returns an idle instance from the pool, or spawns a new one if\n\t * the pool isn't at capacity. If all instances are busy, waits\n\t * until one becomes available.\n\t *\n\t * @throws {MaxPhpInstancesError} when the timeout is reached waiting\n\t * for an available instance.\n\t */\n\tasync acquirePHPInstance(): Promise<AcquiredPHP> {\n\t\tlet releaseSemaphore: () => void;\n\t\ttry {\n\t\t\treleaseSemaphore = await this.semaphore.acquire();\n\t\t} catch (error) {\n\t\t\tif (error instanceof AcquireTimeoutError) {\n\t\t\t\tthrow new MaxPhpInstancesError(this.maxPhpInstances);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\n\t\tconst php = await this.getOrSpawnInstance();\n\t\treturn {\n\t\t\tphp,\n\t\t\treap: () => {\n\t\t\t\tthis.idleInstances.push(php);\n\t\t\t\treleaseSemaphore();\n\t\t\t},\n\t\t};\n\t}\n\n\t/**\n\t * Get an idle instance or spawn a new one.\n\t */\n\tprivate async getOrSpawnInstance(): Promise<PHP> {\n\t\tif (this.instances.length === 0) {\n\t\t\tawait this.getPrimaryPhp();\n\t\t}\n\t\tif (this.idleInstances.length === 0) {\n\t\t\tawait this.spawnInstance(false);\n\t\t}\n\t\treturn this.idleInstances.pop()!;\n\t}\n\n\t/**\n\t * Spawn a new PHP instance.\n\t */\n\tprivate async spawnInstance(isPrimary: boolean): Promise<PHP> {\n\t\tif (!this.phpFactory) {\n\t\t\tthrow new Error(\n\t\t\t\t'phpFactory must be set before spawning instances.'\n\t\t\t);\n\t\t}\n\t\tconst php = await this.phpFactory({ isPrimary });\n\t\tthis.instances.push(php);\n\t\tthis.idleInstances.push(php);\n\t\treturn php;\n\t}\n\n\tasync [Symbol.asyncDispose]() {\n\t\tfor (const php of this.instances) {\n\t\t\tphp.exit();\n\t\t}\n\t\tthis.instances = [];\n\t\tthis.idleInstances = [];\n\t}\n}\n","export const SupportedPHPVersions = [\n\t'8.5',\n\t'8.4',\n\t'8.3',\n\t'8.2',\n\t'8.1',\n\t'8.0',\n\t'7.4',\n] as const;\nexport const LatestSupportedPHPVersion = SupportedPHPVersions[0];\nexport const SupportedPHPVersionsList = SupportedPHPVersions as any as string[];\nexport type SupportedPHPVersion = (typeof SupportedPHPVersions)[number];\n","/**\n * The default base used to convert a path into the URL object.\n */\nexport const DEFAULT_BASE_URL = 'http://example.com';\n\n/**\n * Returns a string representing the path, query, and\n * fragment of the given URL.\n *\n * @example\n * ```js\n * const url = new URL('http://example.com/foo/bar?baz=qux#quux');\n * toRelativeUrl(url); // '/foo/bar?baz=qux#quux'\n * ```\n *\n * @param url The URL.\n * @returns The path, query, and fragment.\n */\nexport function toRelativeUrl(url: URL): string {\n\t/**\n\t * The origin of an about:blank URL is a string \"null\". The URL is not\n\t * relative, but there's also nothing we can do to make it \"more relative\"\n\t * so let's just bale out and return the URL as is.\n\t *\n\t * @see https://html.spec.whatwg.org/multipage/browsers.html#concept-origin (Opaque origins)\n\t */\n\tif (url.origin === 'null') {\n\t\treturn url.toString();\n\t}\n\treturn url.toString().substring(url.origin.length);\n}\n\n/**\n * Removes the given prefix from the given path.\n *\n * @example\n * ```js\n * removePathPrefix('/foo/bar', '/foo'); // '/bar'\n * removePathPrefix('/bar', '/foo'); // '/bar'\n * ```\n *\n * @param path The path to remove the prefix from.\n * @param prefix The prefix to remove.\n * @returns Path with the prefix removed.\n */\nexport function removePathPrefix(path: string, prefix: string): string {\n\tif (!prefix || !path.startsWith(prefix)) {\n\t\treturn path;\n\t}\n\treturn path.substring(prefix.length);\n}\n\n/**\n * Ensures the given path has the given prefix.\n *\n * @example\n * ```js\n * ensurePathPrefix('/bar', '/foo'); // '/foo/bar'\n * ensurePathPrefix('/foo/bar', '/foo'); // '/foo/bar'\n * ```\n *\n * @param path\n * @param prefix\n * @returns Path with the prefix added.\n */\nexport function ensurePathPrefix(path: string, prefix: string): string {\n\tif (!prefix || path.startsWith(prefix)) {\n\t\treturn path;\n\t}\n\treturn prefix + path;\n}\n","/**\n * Encodes a multipart/form-data request body.\n *\n * @param data - The form data to encode.\n * @returns The encoded body and a correctly formatted content type header.\n */\nexport async function encodeAsMultipart(\n\tdata: Record<string, string | Uint8Array | File>\n) {\n\tconst boundary = `----${Math.random().toString(36).slice(2)}`;\n\tconst contentType = `multipart/form-data; boundary=${boundary}`;\n\n\tconst textEncoder = new TextEncoder();\n\tconst parts: (string | Uint8Array)[] = [];\n\tfor (const [name, value] of Object.entries(data)) {\n\t\tparts.push(`--${boundary}\\r\\n`);\n\t\tparts.push(`Content-Disposition: form-data; name=\"${name}\"`);\n\t\tif (value instanceof File) {\n\t\t\tparts.push(`; filename=\"${value.name}\"`);\n\t\t}\n\t\tparts.push(`\\r\\n`);\n\t\tif (value instanceof File) {\n\t\t\tparts.push(`Content-Type: application/octet-stream`);\n\t\t\tparts.push(`\\r\\n`);\n\t\t}\n\t\tparts.push(`\\r\\n`);\n\t\tif (value instanceof File) {\n\t\t\tparts.push(await fileToUint8Array(value));\n\t\t} else {\n\t\t\tparts.push(value);\n\t\t}\n\t\tparts.push(`\\r\\n`);\n\t}\n\tparts.push(`--${boundary}--\\r\\n`);\n\n\tconst length = parts.reduce((acc, part) => acc + part.length, 0);\n\tconst bytes = new Uint8Array(length);\n\tlet offset = 0;\n\tfor (const part of parts) {\n\t\tbytes.set(\n\t\t\ttypeof part === 'string' ? textEncoder.encode(part) : part,\n\t\t\toffset\n\t\t);\n\t\toffset += part.length;\n\t}\n\treturn { bytes, contentType };\n}\n\nfunction fileToUint8Array(file: File): Promise<Uint8Array> {\n\t/**\n\t * @mbuella: Use File.arrayBuffer() to get a Uint8Array from a file, avoiding FileReader\n\t * which is browser-specific. This method is supported in major browsers and NodeJS/Deno runtimes.\n\t */\n\treturn file.arrayBuffer().then((fileBuffer) => new Uint8Array(fileBuffer));\n}\n","import { dirname, joinPaths } from '@php-wasm/util';\nimport {\n\tensurePathPrefix,\n\ttoRelativeUrl,\n\tremovePathPrefix,\n\tDEFAULT_BASE_URL,\n} from './urls';\nimport type { PHP } from './php';\nimport { normalizeHeaders } from './php';\nimport { PHPResponse, StreamedPHPResponse } from './php-response';\nimport type { PHPRequest, PHPRunOptions } from './universal-php';\nimport { encodeAsMultipart } from './encode-as-multipart';\nimport type { PHPFactoryOptions } from './php-process-manager';\nimport { MaxPhpInstancesError, PHPProcessManager } from './php-process-manager';\nimport type { PHPInstanceManager, AcquiredPHP } from './php-instance-manager';\nimport { SinglePHPInstanceManager } from './single-php-instance-manager';\nimport { HttpCookieStore } from './http-cookie-store';\nimport mimeTypes from './mime-types.json';\n\nexport type RewriteRule = {\n\tmatch: RegExp;\n\treplacement: string;\n};\n\nexport type FileNotFoundToResponse = {\n\ttype: 'response';\n\tresponse: PHPResponse;\n};\nexport type FileNotFoundToInternalRedirect = {\n\ttype: 'internal-redirect';\n\turi: string;\n};\nexport type FileNotFoundTo404 = { type: '404' };\n\nexport type FileNotFoundAction =\n\t| FileNotFoundToResponse\n\t| FileNotFoundToInternalRedirect\n\t| FileNotFoundTo404;\n\nexport type FileNotFoundGetActionCallback = (\n\trelativePath: string\n) => FileNotFoundAction;\n\n/**\n * Interface for cookie storage implementations.\n * This allows different cookie handling strategies to be used with the PHP request handler.\n */\nexport interface CookieStore {\n\t/**\n\t * Processes and stores cookies from response headers\n\t * @param headers Response headers containing Set-Cookie directives\n\t */\n\trememberCookiesFromResponseHeaders(headers: Record<string, string[]>): void;\n\n\t/**\n\t * Gets the cookie header string for the next request\n\t * @returns Formatted cookie header string\n\t */\n\tgetCookieRequestHeader(): string;\n}\n\n/**\n * Maps a URL path prefix to an absolute filesystem path.\n * Similar to Nginx's `alias` directive or Apache's `Alias` directive.\n *\n * @example\n * ```ts\n * // Requests to /phpmyadmin/* will be served from /tools/phpmyadmin/*\n * { urlPrefix: '/phpmyadmin', fsPath: '/tools/phpmyadmin' }\n * ```\n */\nexport type PathAlias = {\n\t/**\n\t * The URL path prefix to match (e.g., '/phpmyadmin').\n\t */\n\turlPrefix: string;\n\n\t/**\n\t * The absolute filesystem path to serve files from.\n\t */\n\tfsPath: string;\n};\n\ninterface BaseConfiguration {\n\t/**\n\t * The directory in the PHP filesystem where the server will look\n\t * for the files to serve. Default: `/var/www`.\n\t */\n\tdocumentRoot?: string;\n\t/**\n\t * Request Handler URL. Used to populate $_SERVER details like HTTP_HOST.\n\t */\n\tabsoluteUrl?: string;\n\n\t/**\n\t * Rewrite rules\n\t */\n\trewriteRules?: RewriteRule[];\n\n\t/**\n\t * Path aliases that map URL prefixes to filesystem paths outside\n\t * the document root. Similar to Nginx's `alias` directive.\n\t *\n\t * @example\n\t * ```ts\n\t * pathAliases: [\n\t * { urlPrefix: '/phpmyadmin', fsPath: '/tools/phpmyadmin' }\n\t * ]\n\t * ```\n\t */\n\tpathAliases?: PathAlias[];\n\n\t/**\n\t * A callback that decides how to handle a file-not-found condition for a\n\t * given request URI.\n\t */\n\tgetFileNotFoundAction?: FileNotFoundGetActionCallback;\n}\n\nexport type PHPRequestHandlerFactoryArgs = PHPFactoryOptions & {\n\trequestHandler: PHPRequestHandler;\n};\n\nexport type PHPRequestHandlerConfiguration = BaseConfiguration & {\n\tcookieStore?: CookieStore | false;\n\n\t// One of the following must be provided:\n\n\t/**\n\t * Provide a single PHP instance directly.\n\t * PHPRequestHandler will create a SinglePHPInstanceManager internally.\n\t * This is the simplest option for CLI contexts with a single PHP instance.\n\t */\n\tphp?: PHP;\n\n\t/**\n\t * Provide a factory function to create PHP instances.\n\t * PHPRequestHandler will create a PHPProcessManager internally.\n\t */\n\tphpFactory?: (requestHandler: PHPRequestHandlerFactoryArgs) => Promise<PHP>;\n\n\t/**\n\t * The maximum number of PHP instances that can exist at\n\t * the same time. Only used when phpFactory is provided.\n\t */\n\tmaxPhpInstances?: number;\n};\n\n/**\n * Handles HTTP requests using PHP runtime as a backend.\n *\n * @public\n * @example Use PHPRequestHandler implicitly with a new PHP instance:\n * ```js\n * import { PHP } from '@php-wasm/web';\n *\n * const php = await PHP.load( '7.4', {\n * requestHandler: {\n * // PHP FS path to serve the files from:\n * documentRoot: '/www',\n *\n * // Used to populate $_SERVER['SERVER_NAME'] etc.:\n * absoluteUrl: 'http://127.0.0.1'\n * }\n * } );\n *\n * php.mkdirTree('/www');\n * php.writeFile('/www/index.php', '<?php echo \"Hi from PHP!\"; ');\n *\n * const response = await php.request({ path: '/index.php' });\n * console.log(response.text);\n * // \"Hi from PHP!\"\n * ```\n *\n * @example Explicitly create a PHPRequestHandler instance and run a PHP script:\n * ```js\n * import {\n * loadPHPRuntime,\n * PHP,\n * PHPRequestHandler,\n * getPHPLoaderModule,\n * } from '@php-wasm/web';\n *\n * const runtime = await loadPHPRuntime( await getPHPLoaderModule('7.4') );\n * const php = new PHP( runtime );\n *\n * php.mkdirTree('/www');\n * php.writeFile('/www/index.php', '<?php echo \"Hi from PHP!\"; ');\n *\n * const server = new PHPRequestHandler(php, {\n * // PHP FS path to serve the files from:\n * documentRoot: '/www',\n *\n * // Used to populate $_SERVER['SERVER_NAME'] etc.:\n * absoluteUrl: 'http://127.0.0.1'\n * });\n *\n * const response = server.request({ path: '/index.php' });\n * console.log(response.text);\n * // \"Hi from PHP!\"\n * ```\n */\nexport class PHPRequestHandler implements AsyncDisposable {\n\t#DOCROOT: string;\n\t#PROTOCOL: string;\n\t#HOSTNAME: string;\n\t#PORT: number;\n\t#HOST: string;\n\t#PATHNAME: string;\n\t#ABSOLUTE_URL: string;\n\t#cookieStore: CookieStore | false;\n\t#pathAliases: PathAlias[];\n\trewriteRules: RewriteRule[];\n\t/**\n\t * The instance manager used for PHP instance lifecycle.\n\t * This is either a provided instanceManager or a PHPProcessManager\n\t * created from the phpFactory.\n\t */\n\tinstanceManager: PHPInstanceManager;\n\tgetFileNotFoundAction: FileNotFoundGetActionCallback;\n\n\t/**\n\t * The request handler needs to decide whether to serve a static asset or\n\t * run the PHP interpreter. For static assets it should just reuse the primary\n\t * PHP even if there's 50 concurrent requests to serve. However, for\n\t * dynamic PHP requests, it needs to grab an available interpreter.\n\t * Therefore, it cannot just accept PHP as an argument as serving requests\n\t * requires access to ProcessManager.\n\t *\n\t * @param php - The PHP instance.\n\t * @param config - Request Handler configuration.\n\t */\n\tconstructor(config: PHPRequestHandlerConfiguration) {\n\t\tconst {\n\t\t\tdocumentRoot = '/www/',\n\t\t\tabsoluteUrl = typeof location === 'object'\n\t\t\t\t? location.href\n\t\t\t\t: DEFAULT_BASE_URL,\n\t\t\trewriteRules = [],\n\t\t\tpathAliases = [],\n\t\t\tgetFileNotFoundAction = () => ({ type: '404' }),\n\t\t} = config;\n\n\t\tconst setChroot = (php: PHP) => {\n\t\t\t// Always set managed PHP's cwd to the document root.\n\t\t\tif (!php.isDir(documentRoot)) {\n\t\t\t\tphp.mkdir(documentRoot);\n\t\t\t}\n\t\t\tphp.chdir(documentRoot);\n\n\t\t\t// @TODO: Decouple PHP and request handler\n\t\t\t(php as any).requestHandler = this;\n\t\t};\n\n\t\tif (config.php) {\n\t\t\tsetChroot(config.php);\n\t\t\tthis.instanceManager = new SinglePHPInstanceManager({\n\t\t\t\tphp: config.php,\n\t\t\t});\n\t\t} else if (config.phpFactory) {\n\t\t\tthis.instanceManager = new PHPProcessManager({\n\t\t\t\tphpFactory: async (info) => {\n\t\t\t\t\tconst php = await config.phpFactory!({\n\t\t\t\t\t\t...info,\n\t\t\t\t\t\trequestHandler: this,\n\t\t\t\t\t});\n\t\t\t\t\tsetChroot(php);\n\t\t\t\t\treturn php;\n\t\t\t\t},\n\t\t\t\tmaxPhpInstances: config.maxPhpInstances,\n\t\t\t});\n\t\t} else {\n\t\t\tthrow new Error(\n\t\t\t\t'Either php or phpFactory must be provided in the configuration.'\n\t\t\t);\n\t\t}\n\n\t\t/**\n\t\t * By default, config.cookieStore is undefined, so we use the\n\t\t * HttpCookieStore implementation, otherwise we use the one\n\t\t * provided in the config.\n\t\t *\n\t\t * By explicitly checking for `undefined` we allow the user to pass\n\t\t * `null` as config.cookieStore and disable the cookie store.\n\t\t */\n\t\tthis.#cookieStore =\n\t\t\tconfig.cookieStore === undefined\n\t\t\t\t? new HttpCookieStore()\n\t\t\t\t: config.cookieStore;\n\t\tthis.#DOCROOT = documentRoot;\n\n\t\tconst url = new URL(absoluteUrl);\n\t\tthis.#HOSTNAME = url.hostname;\n\t\tthis.#PORT = url.port\n\t\t\t? Number(url.port)\n\t\t\t: url.protocol === 'https:'\n\t\t\t\t? 443\n\t\t\t\t: 80;\n\t\tthis.#PROTOCOL = (url.protocol || '').replace(':', '');\n\t\tconst isNonStandardPort = this.#PORT !== 443 && this.#PORT !== 80;\n\t\tthis.#HOST = [\n\t\t\tthis.#HOSTNAME,\n\t\t\tisNonStandardPort ? `:${this.#PORT}` : '',\n\t\t].join('');\n\t\tthis.#PATHNAME = url.pathname.replace(/\\/+$/, '');\n\t\tthis.#ABSOLUTE_URL = [\n\t\t\t`${this.#PROTOCOL}://`,\n\t\t\tthis.#HOST,\n\t\t\tthis.#PATHNAME,\n\t\t].join('');\n\t\tthis.rewriteRules = rewriteRules;\n\t\tthis.#pathAliases = pathAliases;\n\t\tthis.getFileNotFoundAction = getFileNotFoundAction;\n\t}\n\n\tasync getPrimaryPhp() {\n\t\treturn await this.instanceManager.getPrimaryPhp();\n\t}\n\n\t/**\n\t * Converts a path to an absolute URL based at the PHPRequestHandler\n\t * root.\n\t *\n\t * @param path The server path to convert to an absolute URL.\n\t * @returns The absolute URL.\n\t */\n\tpathToInternalUrl(path: string): string {\n\t\tif (!path.startsWith('/')) {\n\t\t\tpath = `/${path}`;\n\t\t}\n\t\treturn `${this.absoluteUrl}${path}`;\n\t}\n\n\t/**\n\t * Converts an absolute URL based at the PHPRequestHandler to a relative path\n\t * without the server pathname and scope.\n\t *\n\t * @param internalUrl An absolute URL based at the PHPRequestHandler root.\n\t * @returns The relative path.\n\t */\n\tinternalUrlToPath(internalUrl: string): string {\n\t\tconst url = new URL(internalUrl, 'https://playground.internal');\n\t\tif (url.pathname.startsWith(this.#PATHNAME)) {\n\t\t\turl.pathname = url.pathname.slice(this.#PATHNAME.length);\n\t\t}\n\t\treturn toRelativeUrl(url);\n\t}\n\n\t/**\n\t * The absolute URL of this PHPRequestHandler instance.\n\t */\n\tget absoluteUrl() {\n\t\treturn this.#ABSOLUTE_URL;\n\t}\n\n\t/**\n\t * The directory in the PHP filesystem where the server will look\n\t * for the files to serve. Default: `/var/www`.\n\t */\n\tget documentRoot() {\n\t\treturn this.#DOCROOT;\n\t}\n\n\t/**\n\t * Serves the request – either by serving a static file, or by\n\t * dispatching it to the PHP runtime.\n\t *\n\t * The request() method mode behaves like a web server and only works if\n\t * the PHP was initialized with a `requestHandler` option (which the online\n\t * version of WordPress Playground does by default).\n\t *\n\t * In the request mode, you pass an object containing the request information\n\t * (method, headers, body, etc.) and the path to the PHP file to run:\n\t *\n\t * ```ts\n\t * const php = PHP.load('7.4', {\n\t * \trequestHandler: {\n\t * \t\tdocumentRoot: \"/www\"\n\t * \t}\n\t * })\n\t * php.writeFile(\"/www/index.php\", `<?php echo file_get_contents(\"php://input\");`);\n\t * const result = await php.request({\n\t * \tmethod: \"GET\",\n\t * \theaders: {\n\t * \t\t\"Content-Type\": \"text/plain\"\n\t * \t},\n\t * \tbody: \"Hello world!\",\n\t * \tpath: \"/www/index.php\"\n\t * });\n\t * // result.text === \"Hello world!\"\n\t * ```\n\t *\n\t * The `request()` method cannot be used in conjunction with `cli()`.\n\t *\n\t * @example\n\t * ```js\n\t * const output = await php.request({\n\t * \tmethod: 'GET',\n\t * \turl: '/index.php',\n\t * \theaders: {\n\t * \t\t'X-foo': 'bar',\n\t * \t},\n\t * \tbody: {\n\t * \t\tfoo: 'bar',\n\t * \t},\n\t * });\n\t * console.log(output.stdout); // \"Hello world!\"\n\t * ```\n\t *\n\t * @param request - PHP Request data.\n\t */\n\tasync request(request: PHPRequest): Promise<PHPResponse> {\n\t\tconst streamedResponse = await this.requestStreamed(request);\n\n\t\t// Convert StreamedPHPResponse to buffered PHPResponse\n\t\tconst response =\n\t\t\tawait PHPResponse.fromStreamedResponse(streamedResponse);\n\n\t\t/**\n\t\t * If the response is successful but the exit code is non-zero, let's rewrite the\n\t\t * HTTP status code as 500. We're acting as a HTTP server here and\n\t\t * this behavior is in line with what Nginx and Apache do.\n\t\t *\n\t\t * Note: This check is only done for buffered responses. For streaming responses,\n\t\t * headers are already sent before we know the exit code.\n\t\t */\n\t\tif (response.ok() && response.exitCode !== 0) {\n\t\t\treturn new PHPResponse(\n\t\t\t\t500,\n\t\t\t\tresponse.headers,\n\t\t\t\tresponse.bytes,\n\t\t\t\tresponse.errors,\n\t\t\t\tresponse.exitCode\n\t\t\t);\n\t\t}\n\t\treturn response;\n\t}\n\n\t/**\n\t * Serves the request with streaming support – returns a StreamedPHPResponse\n\t * that allows processing the response body incrementally without buffering\n\t * the entire response in memory.\n\t *\n\t * This is useful for large file downloads (>2GB) that would otherwise\n\t * exceed JavaScript's Uint8Array size limits.\n\t *\n\t * @param request - PHP Request data.\n\t * @returns A StreamedPHPResponse.\n\t */\n\tasync requestStreamed(request: PHPRequest): Promise<StreamedPHPResponse> {\n\t\tconst isAbsolute = looksLikeAbsoluteUrl(request.url);\n\t\tconst originalRequestUrl = new URL(\n\t\t\t// Remove the hash part of the URL as it's not meant for the server.\n\t\t\trequest.url.split('#')[0],\n\t\t\tisAbsolute ? undefined : DEFAULT_BASE_URL\n\t\t);\n\n\t\tconst rewrittenRequestUrl = this.#applyRewriteRules(originalRequestUrl);\n\t\tconst primaryPhp = await this.getPrimaryPhp();\n\t\t/**\n\t\t * Turn a URL such as `https://playground/scope:my-site/wp-admin/index.php`\n\t\t * into a site-relative path, such as `/wp-admin/index.php`.\n\t\t */\n\t\tconst siteRelativePath = removePathPrefix(\n\t\t\t/**\n\t\t\t * URL.pathname returns a URL-encoded path. We need to decode it\n\t\t\t * before using it as a filesystem path.\n\t\t\t */\n\t\t\tdecodeURIComponent(rewrittenRequestUrl.pathname),\n\t\t\tthis.#PATHNAME\n\t\t);\n\t\tlet fsPath = this.#resolveToFsPath(siteRelativePath);\n\t\tif (primaryPhp.isDir(fsPath)) {\n\t\t\t// Ensure directory URIs have a trailing slash. Otherwise,\n\t\t\t// relative URIs in index.php or index.html files are relative\n\t\t\t// to the next directory up.\n\t\t\t//\n\t\t\t// Example:\n\t\t\t// For an index page served for URI \"/settings\", we naturally expect\n\t\t\t// links to be relative to \"/settings\", but without the trailing\n\t\t\t// slash, a relative link \"edit.php\" resolves to \"/edit.php\"\n\t\t\t// rather than \"/settings/edit.php\".\n\t\t\t//\n\t\t\t// This treatment of relative links is correct behavior for the browser:\n\t\t\t// https://www.rfc-editor.org/rfc/rfc3986#section-5.2.3\n\t\t\t//\n\t\t\t// But user intent for `/settings/index.php` is that its relative\n\t\t\t// URIs are relative to `/settings/`. So we redirect to add a\n\t\t\t// trailing slash to directory URIs to meet this expecatation.\n\t\t\t//\n\t\t\t// This behavior is also necessary for WordPress to function properly.\n\t\t\t// Otherwise, when viewing the WP admin dashboard at `/wp-admin`,\n\t\t\t// links to other admin pages like `edit.php` will incorrectly\n\t\t\t// resolve to `/edit.php` rather than `/wp-admin/edit.php`.\n\t\t\tif (!siteRelativePath.endsWith('/')) {\n\t\t\t\treturn StreamedPHPResponse.fromPHPResponse(\n\t\t\t\t\tnew PHPResponse(\n\t\t\t\t\t\t301,\n\t\t\t\t\t\t{ Location: [`${rewrittenRequestUrl.pathname}/`] },\n\t\t\t\t\t\tnew Uint8Array(0)\n\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// We can only satisfy requests for directories with a default file\n\t\t\t// so let's first resolve to a default path when available.\n\t\t\tfor (const possibleIndexFile of ['index.php', 'index.html']) {\n\t\t\t\tconst possibleIndexPath = joinPaths(fsPath, possibleIndexFile);\n\t\t\t\tif (primaryPhp.isFile(possibleIndexPath)) {\n\t\t\t\t\tfsPath = possibleIndexPath;\n\n\t\t\t\t\t// Include the resolved index file in the final rewritten request URL.\n\t\t\t\t\trewrittenRequestUrl.pathname = joinPaths(\n\t\t\t\t\t\trewrittenRequestUrl.pathname,\n\t\t\t\t\t\tpossibleIndexFile\n\t\t\t\t\t);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (!primaryPhp.isFile(fsPath)) {\n\t\t\t/**\n\t\t\t * Try resolving a partial path.\n\t\t\t *\n\t\t\t * Example:\n\t\t\t *\n\t\t\t * – Request URL: /file.php/index.php\n\t\t\t * – Document Root: /var/www\n\t\t\t *\n\t\t\t * If /var/www/file.php/index.php does not exist, but /var/www/file.php does,\n\t\t\t * use /var/www/file.php. This is also what Apache and PHP Dev Server do.\n\t\t\t */\n\t\t\tlet pathToTry = siteRelativePath;\n\t\t\twhile (\n\t\t\t\tpathToTry.startsWith('/') &&\n\t\t\t\tpathToTry !== dirname(pathToTry)\n\t\t\t) {\n\t\t\t\tpathToTry = dirname(pathToTry);\n\t\t\t\tconst resolvedPathToTry = this.#resolveToFsPath(pathToTry);\n\t\t\t\tif (\n\t\t\t\t\tprimaryPhp.isFile(resolvedPathToTry) &&\n\t\t\t\t\t// Only run partial path resolution for PHP files.\n\t\t\t\t\tresolvedPathToTry.endsWith('.php')\n\t\t\t\t) {\n\t\t\t\t\tfsPath = this.#resolveToFsPath(pathToTry);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (!primaryPhp.isFile(fsPath)) {\n\t\t\tconst fileNotFoundAction = this.getFileNotFoundAction(\n\t\t\t\trewrittenRequestUrl.pathname\n\t\t\t);\n\t\t\tswitch (fileNotFoundAction.type) {\n\t\t\t\tcase 'response':\n\t\t\t\t\treturn StreamedPHPResponse.fromPHPResponse(\n\t\t\t\t\t\tfileNotFoundAction.response\n\t\t\t\t\t);\n\t\t\t\tcase 'internal-redirect':\n\t\t\t\t\tfsPath = joinPaths(this.#DOCROOT, fileNotFoundAction.uri);\n\t\t\t\t\tbreak;\n\t\t\t\tcase '404':\n\t\t\t\t\treturn StreamedPHPResponse.forHttpCode(404);\n\t\t\t\tdefault:\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t'Unsupported file-not-found action type: ' +\n\t\t\t\t\t\t\t// Cast because TS asserts the remaining possibility is `never`\n\t\t\t\t\t\t\t`'${\n\t\t\t\t\t\t\t\t(fileNotFoundAction as FileNotFoundAction).type\n\t\t\t\t\t\t\t}'`\n\t\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\t// We need to confirm that the current target file exists because\n\t\t// file-not-found fallback actions may redirect to non-existent files.\n\t\tif (primaryPhp.isFile(fsPath)) {\n\t\t\tif (fsPath.endsWith('.php')) {\n\t\t\t\treturn await this.#spawnPHPAndDispatchRequest(\n\t\t\t\t\trequest,\n\t\t\t\t\toriginalRequestUrl,\n\t\t\t\t\trewrittenRequestUrl,\n\t\t\t\t\tfsPath\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\treturn StreamedPHPResponse.fromPHPResponse(\n\t\t\t\t\tthis.#serveStaticFile(primaryPhp, fsPath)\n\t\t\t\t);\n\t\t\t}\n\t\t} else {\n\t\t\treturn StreamedPHPResponse.forHttpCode(404);\n\t\t}\n\t}\n\n\t/**\n\t * Apply the rewrite rules to the original request URL.\n\t *\n\t * @param originalRequestUrl - The original request URL.\n\t * @returns The rewritten request URL.\n\t */\n\t#applyRewriteRules(originalRequestUrl: URL): URL {\n\t\tconst siteRelativePath = removePathPrefix(\n\t\t\tdecodeURIComponent(originalRequestUrl.pathname),\n\t\t\tthis.#PATHNAME\n\t\t);\n\t\tconst rewrittenRequestPath = applyRewriteRules(\n\t\t\tsiteRelativePath,\n\t\t\tthis.rewriteRules\n\t\t);\n\t\tconst rewrittenRequestUrl = new URL(\n\t\t\tjoinPaths(this.#PATHNAME, rewrittenRequestPath),\n\t\t\toriginalRequestUrl.toString()\n\t\t);\n\t\t// Merge the query string parameters from the original request URL.\n\t\tfor (const [key, value] of originalRequestUrl.searchParams.entries()) {\n\t\t\trewrittenRequestUrl.searchParams.append(key, value);\n\t\t}\n\t\treturn rewrittenRequestUrl;\n\t}\n\n\t/**\n\t * Resolves a URL path to a filesystem path, checking path aliases first.\n\t *\n\t * If the URL path matches a configured alias prefix, the alias's\n\t * filesystem path is used instead of the document root.\n\t *\n\t * @param urlPath - The URL path to resolve (e.g., '/phpmyadmin/index.php')\n\t * @returns The resolved filesystem path\n\t */\n\t#resolveToFsPath(urlPath: string): string {\n\t\t// Check if the URL path matches any alias\n\t\tfor (const alias of this.#pathAliases) {\n\t\t\tif (\n\t\t\t\turlPath === alias.urlPrefix ||\n\t\t\t\turlPath.startsWith(alias.urlPrefix + '/')\n\t\t\t) {\n\t\t\t\t// Replace the URL prefix with the filesystem path\n\t\t\t\tconst relativePath = urlPath.slice(alias.urlPrefix.length);\n\t\t\t\treturn joinPaths(alias.fsPath, relativePath);\n\t\t\t}\n\t\t}\n\t\t// No alias matched, use the document root\n\t\treturn joinPaths(this.#DOCROOT, urlPath);\n\t}\n\n\t/**\n\t * Serves a static file from the PHP filesystem.\n\t *\n\t * @param fsPath - Absolute path of the static file to serve.\n\t * @returns The response.\n\t */\n\t#serveStaticFile(php: PHP, fsPath: string): PHPResponse {\n\t\tconst arrayBuffer = php.readFileAsBuffer(fsPath);\n\t\treturn new PHPResponse(\n\t\t\t200,\n\t\t\t{\n\t\t\t\t'content-length': [`${arrayBuffer.byteLength}`],\n\t\t\t\t// @TODO: Infer the content-type from the arrayBuffer instead of the\n\t\t\t\t// file path. The code below won't return the correct mime-type if the\n\t\t\t\t// extension was tampered with.\n\t\t\t\t'content-type': [inferMimeType(fsPath)],\n\t\t\t\t'accept-ranges': ['bytes'],\n\t\t\t\t'cache-control': ['public, max-age=0'],\n\t\t\t},\n\t\t\tarrayBuffer\n\t\t);\n\t}\n\n\t/**\n\t * Spawns a new PHP instance and dispatches a request to it.\n\t */\n\tasync #spawnPHPAndDispatchRequest(\n\t\trequest: PHPRequest,\n\t\toriginalRequestUrl: URL,\n\t\trewrittenRequestUrl: URL,\n\t\tscriptPath: string\n\t): Promise<StreamedPHPResponse> {\n\t\tlet spawnedPHP: AcquiredPHP | undefined = undefined;\n\t\ttry {\n\t\t\tspawnedPHP = await this.instanceManager!.acquirePHPInstance();\n\t\t} catch (e) {\n\t\t\tif (e instanceof MaxPhpInstancesError) {\n\t\t\t\treturn StreamedPHPResponse.forHttpCode(502);\n\t\t\t} else {\n\t\t\t\treturn StreamedPHPResponse.forHttpCode(500);\n\t\t\t}\n\t\t}\n\n\t\tlet response: StreamedPHPResponse;\n\t\ttry {\n\t\t\tresponse = await this.#dispatchToPHP(\n\t\t\t\tspawnedPHP.php,\n\t\t\t\trequest,\n\t\t\t\toriginalRequestUrl,\n\t\t\t\trewrittenRequestUrl,\n\t\t\t\tscriptPath\n\t\t\t);\n\t\t} catch (e) {\n\t\t\t// Release the PHP instance if dispatch fails\n\t\t\tspawnedPHP.reap();\n\t\t\tthrow e;\n\t\t}\n\n\t\t// Release the PHP instance when the response stream is finished\n\t\tresponse.finished.finally(() => {\n\t\t\tspawnedPHP?.reap();\n\t\t});\n\n\t\treturn response;\n\t}\n\n\t/**\n\t * Runs the requested PHP file with all the request and $_SERVER\n\t * superglobals populated.\n\t *\n\t * @param request - The request.\n\t * @returns The response.\n\t */\n\tasync #dispatchToPHP(\n\t\tphp: PHP,\n\t\trequest: PHPRequest,\n\t\toriginalRequestUrl: URL,\n\t\trewrittenRequestUrl: URL,\n\t\tscriptPath: string\n\t): Promise<StreamedPHPResponse> {\n\t\tlet preferredMethod: PHPRunOptions['method'] = 'GET';\n\n\t\tconst headers: Record<string, string> = {\n\t\t\thost: this.#HOST,\n\t\t\t...normalizeHeaders(request.headers || {}),\n\t\t};\n\t\tif (this.#cookieStore) {\n\t\t\theaders['cookie'] = this.#cookieStore.getCookieRequestHeader();\n\t\t}\n\n\t\tlet body = request.body;\n\t\tif (typeof body === 'object' && !(body instanceof Uint8Array)) {\n\t\t\tpreferredMethod = 'POST';\n\t\t\tconst { bytes, contentType } = await encodeAsMultipart(body);\n\t\t\tbody = bytes;\n\t\t\theaders['content-type'] = contentType;\n\t\t}\n\n\t\tconst response = await php.runStream({\n\t\t\trelativeUri: ensurePathPrefix(\n\t\t\t\ttoRelativeUrl(new URL(rewrittenRequestUrl.toString())),\n\t\t\t\tthis.#PATHNAME\n\t\t\t),\n\t\t\tprotocol: this.#PROTOCOL,\n\t\t\tmethod: request.method || preferredMethod,\n\t\t\t$_SERVER: this.prepare_$_SERVER_superglobal(\n\t\t\t\toriginalRequestUrl,\n\t\t\t\trewrittenRequestUrl,\n\t\t\t\tscriptPath\n\t\t\t),\n\t\t\tbody,\n\t\t\tscriptPath,\n\t\t\theaders,\n\t\t});\n\n\t\t// Handle cookies from streaming response\n\t\tif (this.#cookieStore) {\n\t\t\tconst cookieStore = this.#cookieStore;\n\t\t\tresponse.headers.then((responseHeaders) => {\n\t\t\t\tcookieStore.rememberCookiesFromResponseHeaders(responseHeaders);\n\t\t\t});\n\t\t}\n\n\t\treturn response;\n\t}\n\n\t/**\n\t * Computes the essential $_SERVER entries for a request.\n\t *\n\t * php_wasm.c sets some defaults, assuming it runs as a CLI script.\n\t * This function overrides them with the values correct in the request\n\t * context.\n\t *\n\t * @TODO: Consolidate the $_SERVER setting logic into a single place instead\n\t * of splitting it between the C SAPI and the TypeScript code. The PHP\n\t * class has a `.cli()` method that could take care of the CLI-specific\n\t * $_SERVER values.\n\t *\n\t * Path and URL-related $_SERVER entries are theoretically documented\n\t * at https://www.php.net/manual/en/reserved.variables.server.php,\n\t * but that page is not very helpful in practice. Here are tables derived\n\t * by interacting with PHP servers:\n\t *\n\t * ## PHP Dev Server\n\t *\n\t * Setup:\n\t * – `/home/adam/subdir/script.php` file contains `<?php phpinfo(); ?>`\n\t * – `php -S 127.0.0.1:8041` running in `/home/adam` directory\n\t * – A request is sent to `http://127.0.0.1:8041/subdir/script.php/b.php/c.php`\n\t *\n\t * Results:\n\t *\n\t * $_SERVER['REQUEST_URI'] | `/subdir/script.php/b.php/c.php`\n\t * $_SERVER['SCRIPT_NAME'] | `/subdir/script.php`\n\t * $_SERVER['SCRIPT_FILENAME']| `/home/adam/subdir/script.php`\n\t * $_SERVER['PATH_INFO'] | `/b.php/c.php`\n\t * $_SERVER['PHP_SELF'] | `/subdir/script.php/b.php/c.php`\n\t *\n\t * ## Apache – rewriting rules\n\t *\n\t * Setup:\n\t * – `/var/www/html/subdir/script.php` file contains `<?php phpinfo(); ?>`\n\t * – Apache is listening on port 8041\n\t * – The document root is `/var/www/html`\n\t * – A request is sent to `http://127.0.0.1:8041/api/v1/user/123`\n\t *\n\t * .htaccess file:\n\t *\n\t * ```apache\n\t * RewriteEngine On\n\t * RewriteRule ^api/v1/user/([0-9]+)$ /subdir/script.php?endpoint=user&id=$1 [L,QSA]\n\t * ```\n\t *\n\t * Results:\n\t *\n\t * ```\n\t * $_SERVER['REQUEST_URI'] | /api/v1/user/123\n\t * $_SERVER['SCRIPT_NAME'] | /subdir/script.php\n\t * $_SERVER['SCRIPT_FILENAME'] | /var/www/html/subdir/script.php\n\t * $_SERVER['PATH_INFO'] | (key not set)\n\t * $_SERVER['PHP_SELF'] | /subdir/script.php\n\t * $_SERVER['QUERY_STRING'] | endpoint=user&id=123\n\t * $_SERVER['REDIRECT_STATUS'] | 200\n\t * $_SERVER['REDIRECT_URL'] | /api/v1/user/123\n\t * $_SERVER['REDIRECT_QUERY_STRING'] | endpoint=user&id=123\n\t * === $_GET Variables ===\n\t * $_GET['endpoint'] | user\n\t * $_GET['id'] | 123\n\t * ```\n\t *\n\t * ## Apache – vanilla request\n\t *\n\t * Setup:\n\t * – The same as above.\n\t * – A request sent http://localhost:8041/subdir/script.php?param=value\n\t *\n\t * Results:\n\t *\n\t * ```\n\t * $_SERVER['REQUEST_URI'] | /subdir/script.php?param=value\n\t * $_SERVER['SCRIPT_NAME'] | /subdir/script.php\n\t * $_SERVER['SCRIPT_FILENAME'] | /var/www/html/subdir/script.php\n\t * $_SERVER['PATH_INFO'] | (key not set)\n\t * $_SERVER['PHP_SELF'] | /subdir/script.php\n\t * $_SERVER['REDIRECT_URL'] | (key not set)\n\t * $_SERVER['REDIRECT_STATUS'] | (key not set)\n\t * $_SERVER['QUERY_STRING'] | param=value\n\t * $_SERVER['REQUEST_METHOD'] | GET\n\t * $_SERVER['DOCUMENT_ROOT'] | /var/www/html\n\t *\n\t * === $_GET Variables ===\n\t * $_GET['param'] | value\n\t * ```\n\t */\n\tprivate prepare_$_SERVER_superglobal(\n\t\toriginalRequestUrl: URL,\n\t\trewrittenRequestUrl: URL,\n\t\tresolvedScriptPath: string\n\t): Record<string, string> {\n\t\tconst $_SERVER: Record<string, string> = {\n\t\t\tREMOTE_ADDR: '127.0.0.1',\n\t\t\tDOCUMENT_ROOT: this.#DOCROOT,\n\t\t\tHTTPS: this.#ABSOLUTE_URL.startsWith('https://') ? 'on' : '',\n\t\t};\n\n\t\t/**\n\t\t * REQUEST_URI\n\t\t *\n\t\t * The original path + query string extracted from the requested URL\n\t\t * **before** applying any URL rewriting.\n\t\t */\n\t\t$_SERVER['REQUEST_URI'] =\n\t\t\toriginalRequestUrl.pathname + originalRequestUrl.search;\n\n\t\tif (resolvedScriptPath.startsWith(this.#DOCROOT)) {\n\t\t\t/**\n\t\t\t * SCRIPT_NAME\n\t\t\t *\n\t\t\t * > Contains the current script's path. This is useful for pages\n\t\t\t * > which need to point to themselves.\n\t\t\t *\n\t\t\t * Filesystem path of the script relative to the document root.\n\t\t\t * Note this is a filesystem path so URL rewriting is not applicable here.\n\t\t\t */\n\t\t\t$_SERVER['SCRIPT_NAME'] = resolvedScriptPath.substring(\n\t\t\t\tthis.#DOCROOT.length\n\t\t\t);\n\n\t\t\t/**\n\t\t\t * PHP_SELF – the path sourced from the final **request URL** after the\n\t\t\t * rewrite rules have been applied.\n\t\t\t *\n\t\t\t * php.net documentation is very misleading on this one:\n\t\t\t *\n\t\t\t * > The filename of the currently executing script, relative\n\t\t\t * > to the document root. For instance, $_SERVER['PHP_SELF']\n\t\t\t * > in a script at the address http://example.com/foo/bar.php\n\t\t\t * > would be /foo/bar.php.\n\t\t\t *\n\t\t\t * @see https://www.php.net/manual/en/reserved.variables.server.php#:~:text=PHP_SELF\n\t\t\t *\n\t\t\t * This is not what Apache, nor what the PHP dev server do:\n\t\t\t *\n\t\t\t * – Document Root: /var/www\n\t\t\t * – Script file: /var/www/subdir/script.php\n\t\t\t * – Requesting /subdir/script.php/b.php/c.php\n\t\t\t *\n\t\t\t * $_SERVER['PHP_SELF'] = \"/subdir/script.php/b.php/c.php\"\n\t\t\t *\n\t\t\t * So, in that regard, it is a URL path, not a filesystem path.\n\t\t\t *\n\t\t\t * When URL rewriting is involved, it's the same.\n\t\t\t *\n\t\t\t * Consider this Apache example from above:\n\t\t\t *\n\t\t\t * – Document Root: /var/www/html\n\t\t\t * – Script file: /var/www/html/subdir/script.php\n\t\t\t * – Rewrite rule: ^api/v1/user/([0-9]+)$ /subdir/script.php?endpoint=user&id=$1 [L,QSA]\n\t\t\t * – Requesting /api/v1/user/123\n\t\t\t *\n\t\t\t * $_SERVER['PHP_SELF'] = \"/subdir/script.php\"\n\t\t\t *\n\t\t\t * So, on the face value, this is a filesystem path. However, see\n\t\t\t * what happens if we slightly modify that rewrite rule to:\n\t\t\t *\n\t\t\t * – Rewrite rule: ^api/v1/user/([0-9]+)$ /subdir/script.php/next.php\n\t\t\t * ^^^^^^^^^\n\t\t\t * – Requesting /api/v1/user/123\n\t\t\t *\n\t\t\t * $_SERVER['PHP_SELF'] = \"/subdir/script.php/next.php\"\n\t\t\t *\n\t\t\t * So:\n\t\t\t * * PHP_SELF is not sourced from the filesystem path.\n\t\t\t * * PHP_SELF is sourced from the final request URL after the\n\t\t\t * rewrite rules have been applied.\n\t\t\t */\n\t\t\t$_SERVER['PHP_SELF'] = rewrittenRequestUrl.pathname;\n\n\t\t\t/**\n\t\t\t * PATH_INFO\n\t\t\t *\n\t\t\t * > Contains any client-provided pathname information trailing the actual\n\t\t\t * > script filename but preceding the query string, if available. For instance,\n\t\t\t * > if the current script was accessed via the URI http://www.example.com/php/path_info.php/some/stuff?foo=bar,\n\t\t\t * > then $_SERVER['PATH_INFO'] would contain /some/stuff.\n\t\t\t *\n\t\t\t * This **does not** include the query string.\n\t\t\t *\n\t\t\t * @see https://www.php.net/manual/en/reserved.variables.server.php#:~:text=PATH_INFO\n\t\t\t */\n\t\t\tif ($_SERVER['REQUEST_URI'].startsWith($_SERVER['SCRIPT_NAME'])) {\n\t\t\t\t$_SERVER['PATH_INFO'] = $_SERVER['REQUEST_URI'].substring(\n\t\t\t\t\t$_SERVER['SCRIPT_NAME'].length\n\t\t\t\t);\n\t\t\t\t// Remove the query string if present.\n\t\t\t\tif ($_SERVER['PATH_INFO'].includes('?')) {\n\t\t\t\t\t$_SERVER['PATH_INFO'] = $_SERVER['PATH_INFO'].substring(\n\t\t\t\t\t\t0,\n\t\t\t\t\t\t$_SERVER['PATH_INFO'].indexOf('?')\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * QUERY_STRING\n\t\t *\n\t\t * The query string from the original and rewritten request URLs.\n\t\t * Does not include the leading question mark.\n\t\t *\n\t\t * Note it contains all the query parameters from the original\n\t\t * URL merged with the new parameters from the rewritten request URLs.\n\t\t *\n\t\t * Example:\n\t\t * – Original request URL: /pretty/url?foo=bar&page=different-value\n\t\t * – Rewritten request URL: /pretty/url?page=pretty\n\t\t * – QUERY_STRING: page=pretty&foo=bar&page=different-value\n\t\t */\n\t\t$_SERVER['QUERY_STRING'] = rewrittenRequestUrl.search.substring(1);\n\n\t\t/**\n\t\t * There's a few relevant entries we are NOT setting here:\n\t\t *\n\t\t * – SCRIPT_FILENAME: Absolute path to the script file. It is set by\n\t\t * php_wasm.c.\n\t\t * – REDIRECT_STATUS: Apache sets it, but it's optional so we skip it.\n\t\t * – REDIRECT_URL: Apache sets it, but it's optional so we skip it.\n\t\t * – REDIRECT_QUERY_STRING: Apache sets it, but it's optional so we skip it.\n\t\t */\n\t\treturn $_SERVER;\n\t}\n\n\tasync [Symbol.asyncDispose]() {\n\t\tawait this.instanceManager[Symbol.asyncDispose]();\n\t}\n}\n\n/**\n * Naively infer a file mime type from its path.\n *\n * @todo Infer the mime type based on the file contents.\n * A naive function like this one can be inaccurate\n * and potentially have negative security consequences.\n *\n * @param path - The file path\n * @returns The inferred mime type.\n */\nexport function inferMimeType(path: string): string {\n\tconst extension = path.split('.').pop() as keyof typeof mimeTypes;\n\t// @TODO: Consider not sending a default mime type to let the browser guess\n\treturn mimeTypes[extension] || mimeTypes['_default'];\n}\n\n/**\n * Applies the given rewrite rules to the given path.\n *\n * @param path The path to apply the rules to.\n * @param rules The rules to apply.\n * @returns The path with the rules applied.\n */\nexport function applyRewriteRules(path: string, rules: RewriteRule[]): string {\n\tfor (const rule of rules) {\n\t\tif (new RegExp(rule.match).test(path)) {\n\t\t\tpath = path.replace(rule.match, rule.replacement);\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn path;\n}\n\n/**\n * Checks if the given URL looks like an absolute URL.\n *\n * @param url - The URL to check.\n * @returns `true` if the URL looks like an absolute URL, `false` otherwise.\n */\nfunction looksLikeAbsoluteUrl(url: string): boolean {\n\ttry {\n\t\t// NOTE: We could just use URL.canParse() but are avoiding it here\n\t\t// because we've seen users with older Safari versions that don't support it.\n\t\t// Maybe Playground will break in other ways for them,\n\t\t// but since this is an easy, low-risk change, let's give it a try.\n\t\tnew URL(url);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n","import type { PHP } from './php';\n\nexport interface RotateOptions {\n\tphp: PHP;\n\tcwd?: string;\n\trecreateRuntime: () => Promise<number> | number;\n\tmaxRequests?: number;\n}\n\n/**\n * Configures inline runtime rotation on the provided PHP instance.\n * Returns a cleanup function that disables rotation.\n *\n * @deprecated Use `php.enableRuntimeRotation()` instead.\n */\nexport function rotatePHPRuntime({\n\tphp,\n\trecreateRuntime,\n\tmaxRequests = 400,\n}: RotateOptions) {\n\treturn php.enableRuntimeRotation({\n\t\trecreateRuntime,\n\t\tmaxRequests,\n\t});\n}\n","import { dirname, joinPaths } from '@php-wasm/util';\nimport type { UniversalPHP } from './universal-php';\n\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface FileTree\n\textends Record<string, Uint8Array | string | FileTree> {}\n\nexport interface WriteFilesOptions {\n\t/**\n\t * Whether to wipe out the contents of the\n\t * root directory before writing the new files.\n\t */\n\trmRoot?: boolean;\n}\n\n/**\n * Writes multiple files to a specified directory in the Playground\n * filesystem.\n *\n * @example ```ts\n * await writeFiles(php, '/test', {\n * \t'file.txt': 'file',\n * \t'sub/file.txt': 'file',\n * \t'sub1/sub2/file.txt': 'file',\n * });\n * ```\n *\n * @param php\n * @param root\n * @param newFiles\n * @param options\n */\nexport async function writeFiles(\n\tphp: UniversalPHP,\n\troot: string,\n\tnewFiles: FileTree,\n\t{ rmRoot = false }: WriteFilesOptions = {}\n) {\n\tif (rmRoot) {\n\t\tif (await php.isDir(root)) {\n\t\t\tawait php.rmdir(root, { recursive: true });\n\t\t}\n\t}\n\tfor (const [relativePath, content] of Object.entries(newFiles)) {\n\t\tconst filePath = joinPaths(root, relativePath);\n\t\tif (!(await php.fileExists(dirname(filePath)))) {\n\t\t\tawait php.mkdir(dirname(filePath));\n\t\t}\n\t\tif (content instanceof Uint8Array || typeof content === 'string') {\n\t\t\tawait php.writeFile(filePath, content);\n\t\t} else {\n\t\t\tawait writeFiles(php, filePath, content);\n\t\t}\n\t}\n}\n","import type { PHP } from './php';\n\n/**\n * Adds mmap support to PROXYFS for memory-mapping files across PHP instances.\n *\n * Without mmap, libraries like ICU fail when accessing data files through PROXYFS.\n * ICU calls mmap to load icudt74l.dat when initializing Intl classes like Collator\n * and NumberFormatter. PROXYFS has no mmap implementation by default, causing these\n * calls to fail even when the data file exists in the proxied filesystem.\n *\n * This patches PROXYFS.stream_ops to add mmap and msync methods. The mmap implementation\n * allocates memory, reads the file through PROXYFS's existing read operations, and\n * returns a pointer to the allocated buffer—matching the behavior of POSIX mmap.\n *\n * @param phpInstance - The PHP instance whose PROXYFS should be patched\n */\nfunction ensureProxyFSHasMmapSupport(phpInstance: PHP) {\n\tconst __private__symbol = Object.getOwnPropertySymbols(phpInstance)[0];\n\t// @ts-ignore\n\tconst runtime = phpInstance[__private__symbol];\n\tconst PROXYFS = runtime.PROXYFS;\n\tconst FS = runtime.FS;\n\n\t// Skip if mmap is already defined\n\tif (PROXYFS.stream_ops.mmap) {\n\t\treturn;\n\t}\n\n\t/**\n\t * Maps a file into memory by allocating a buffer and reading the file contents into it.\n\t *\n\t * PROXYFS has no direct access to the underlying file buffer, so we simulate mmap\n\t * by allocating memory with malloc and copying the file contents through read operations.\n\t *\n\t * @param stream - The file stream to map\n\t * @param length - Number of bytes to map (may be incorrect for non-.dat files in PHP 7.4)\n\t * @param position - File offset to start mapping from (must be 0)\n\t * @param prot - Memory protection flags (unused, we always allocate read/write)\n\t * @param flags - Mapping flags (unused)\n\t * @returns Object with ptr (pointer to allocated memory) and allocated flag\n\t */\n\t/* eslint-disable @typescript-eslint/no-unused-vars */\n\tPROXYFS.stream_ops.mmap = function (\n\t\tstream: any,\n\t\tlength: number,\n\t\tposition: number,\n\t\tprot: number,\n\t\tflags: number\n\t) {\n\t\t/* eslint-enable @typescript-eslint/no-unused-vars */\n\t\t// Only files can be memory-mapped\n\t\tif (!FS.isFile(stream.node.mode)) {\n\t\t\tthrow new FS.ErrnoError(19); // ENODEV\n\t\t}\n\n\t\t// ICU only maps files from offset 0, so we don't support partial mapping\n\t\tif (position !== 0) {\n\t\t\tthrow new FS.ErrnoError(22); // EINVAL\n\t\t}\n\n\t\tconst ptr = runtime.malloc(length);\n\t\tif (!ptr) {\n\t\t\tthrow new FS.ErrnoError(48); // ENOMEM\n\t\t}\n\n\t\t// Read the file into the allocated memory. Create a subarray view of the heap\n\t\t// so read operations write directly to the correct memory location without\n\t\t// needing offset calculations.\n\t\tconst heap = runtime.HEAPU8.subarray(ptr, ptr + length);\n\t\tlet totalBytesRead = 0;\n\n\t\twhile (totalBytesRead < length) {\n\t\t\tconst bytesRead = stream.stream_ops.read(\n\t\t\t\tstream,\n\t\t\t\theap,\n\t\t\t\ttotalBytesRead,\n\t\t\t\tlength - totalBytesRead,\n\t\t\t\ttotalBytesRead\n\t\t\t);\n\n\t\t\tif (bytesRead <= 0) break;\n\t\t\ttotalBytesRead += bytesRead;\n\t\t}\n\n\t\t// Partial reads indicate I/O errors or premature EOF\n\t\tif (totalBytesRead !== length) {\n\t\t\truntime.free(ptr);\n\t\t\tthrow new FS.ErrnoError(5); // EIO\n\t\t}\n\n\t\treturn { ptr: ptr, allocated: true };\n\t};\n\n\t/**\n\t * Writes memory-mapped changes back to the file when the mapping is shared.\n\t *\n\t * Called by munmap to persist changes made to the mapped memory region.\n\t * MAP_PRIVATE mappings (flag bit 2) keep changes in memory only, while\n\t * MAP_SHARED mappings write changes back to the underlying file.\n\t *\n\t * ICU only reads from its data files, so this rarely gets called in practice.\n\t *\n\t * @param stream - The file stream\n\t * @param buffer - The memory buffer containing changes\n\t * @param offset - Offset in the buffer\n\t * @param length - Number of bytes to sync\n\t * @param mmapFlags - Flags from the original mmap call\n\t * @returns 0 on success\n\t */\n\tPROXYFS.stream_ops.msync = function (\n\t\tstream: any,\n\t\tbuffer: Uint8Array,\n\t\toffset: number,\n\t\tlength: number,\n\t\tmmapFlags: number\n\t) {\n\t\t// MAP_PRIVATE (flag bit 2) means changes stay in memory\n\t\tif (!(mmapFlags & 2)) {\n\t\t\tstream.stream_ops.write(\n\t\t\t\tstream,\n\t\t\t\tbuffer,\n\t\t\t\toffset,\n\t\t\t\tlength,\n\t\t\t\toffset,\n\t\t\t\tfalse\n\t\t\t);\n\t\t}\n\t\treturn 0;\n\t};\n}\n\n/**\n * Mounts directories from one PHP instance's filesystem into another using PROXYFS.\n *\n * This enables file sharing between PHP instances without duplicating the files in memory.\n * For example, mounting /wordpress from the parent instance into a child worker allows\n * both to access the same WordPress installation without copying the entire directory.\n *\n * The function automatically patches PROXYFS with mmap support before mounting, ensuring\n * libraries like ICU can memory-map data files through the proxied filesystem.\n *\n * @param sourceOfTruth - The PHP instance containing the original files\n * @param replica - The PHP instance that will access files through PROXYFS\n * @param paths - Absolute paths to mount (e.g., ['/wordpress', '/internal/shared'])\n */\nexport function proxyFileSystem(\n\tsourceOfTruth: PHP,\n\treplica: PHP,\n\tpaths: string[]\n) {\n\tensureProxyFSHasMmapSupport(replica);\n\n\t// We can't just import the symbol from the library because\n\t// Playground CLI is built as ESM and php-wasm-node is built as\n\t// CJS and the imported symbols will differ in the production build.\n\t// Get symbols from both instances to ensure correct property access.\n\tconst replicaSymbol = Object.getOwnPropertySymbols(replica)[0];\n\tconst sourceSymbol = Object.getOwnPropertySymbols(sourceOfTruth)[0];\n\tfor (const path of paths) {\n\t\tif (!replica.fileExists(path)) {\n\t\t\treplica.mkdir(path);\n\t\t}\n\t\tif (!sourceOfTruth.fileExists(path)) {\n\t\t\tsourceOfTruth.mkdir(path);\n\t\t}\n\t\t// @ts-ignore\n\t\treplica[replicaSymbol].FS.mount(\n\t\t\t// @ts-ignore\n\t\t\treplica[replicaSymbol].PROXYFS,\n\t\t\t{\n\t\t\t\troot: path,\n\t\t\t\t// @ts-ignore\n\t\t\t\tfs: sourceOfTruth[sourceSymbol].FS,\n\t\t\t},\n\t\t\tpath\n\t\t);\n\t}\n}\n\n/**\n * Answers whether the given path is to a shared filesystem.\n *\n * @param sourceOfTruth - The PHP instance that is the source of truth.\n * @param path - The path to check.\n * @returns True if the path is to a shared filesystem, false otherwise.\n */\nexport function isPathToSharedFS(sourceOfTruth: PHP, path: string) {\n\t// We can't just import the symbol from the library because\n\t// Playground CLI is built as ESM and php-wasm-node is built as\n\t// CJS and the imported symbols will different in the production build.\n\tconst __private__symbol = Object.getOwnPropertySymbols(sourceOfTruth)[0];\n\n\t// @ts-ignore\n\tconst FS = sourceOfTruth[__private__symbol].FS;\n\n\tconst fsResult = FS.lookupPath(path, { noent_okay: true });\n\treturn fsResult?.node?.isSharedFS ?? false;\n}\n","import { createSpawnHandler, splitShellCommand } from '@php-wasm/util';\nimport type { PHP } from './php';\nimport type { PHPWorker } from './php-worker';\nimport type { Remote } from './comlink-sync';\nimport { logger } from '@php-wasm/logger';\n\n/**\n * An isomorphic proc_open() handler that implements typical shell in TypeScript\n * without relying on a server runtime. It can be used in the browser and Node.js\n * alike whenever you need to spawn a PHP subprocess, query the terminal size, etc.\n * It is open for future expansion if more shell or busybox calls are needed, but\n * advanced shell features such as piping, stream redirection etc. are outside of\n * the scope of this minimal handler. If they become vital at any point, let's\n * explore bringing in an actual shell implementation or at least a proper command\n * parser.\n */\nexport function sandboxedSpawnHandlerFactory(\n\tgetPHPInstance?: () => Promise<{\n\t\tphp: PHP | Remote<PHPWorker>;\n\t\treap: () => void;\n\t}>\n) {\n\treturn createSpawnHandler(async function (args, processApi, options) {\n\t\tprocessApi.notifySpawn();\n\t\t/**\n\t\t * Blueprints v2 spawn through the Symfony Process class, which wraps the command in\n\t\t *\n\t\t * `/bin/sh -c \"exec ...\"`\n\t\t *\n\t\t * We need to unwrap it.\n\t\t *\n\t\t * We can't just call the /bin/sh binary because we're running a sandboxed shell handler with\n\t\t * no access to OS binaries. The OS binaries wouldn't be able to resolve PHP VFS paths anyway.\n\t\t */\n\t\tif (\n\t\t\targs?.[0] === '/bin/sh' &&\n\t\t\targs?.[1] === '-c' &&\n\t\t\ttypeof args[2] === 'string'\n\t\t) {\n\t\t\targs = splitShellCommand(args[2]);\n\t\t}\n\n\t\tif (args[0] === 'exec') {\n\t\t\targs.shift();\n\t\t}\n\n\t\tif (args[0].endsWith('.php') || args[0].endsWith('.phar')) {\n\t\t\targs.unshift('php');\n\t\t}\n\n\t\tconst binaryName = args[0].split('/').pop();\n\n\t\t// Mock programs required by wp-cli:\n\t\tif (\n\t\t\targs[0] === '/usr/bin/env' &&\n\t\t\targs[1] === 'stty' &&\n\t\t\targs[2] === 'size'\n\t\t) {\n\t\t\t// These numbers are hardcoded because this\n\t\t\t// spawnHandler is transmitted as a string to\n\t\t\t// the PHP backend and has no access to local\n\t\t\t// scope. It would be nice to find a way to\n\t\t\t// transfer / proxy a live object instead.\n\t\t\t// @TODO: Do not hardcode this\n\t\t\tprocessApi.stdout(`18 140`);\n\t\t\tprocessApi.exit(0);\n\t\t} else if (binaryName === 'tput' && args[1] === 'cols') {\n\t\t\tprocessApi.stdout(`140`);\n\t\t\tprocessApi.exit(0);\n\t\t} else if (binaryName === 'less') {\n\t\t\tprocessApi.on('stdin', (data) => {\n\t\t\t\tprocessApi.stdout(data);\n\t\t\t});\n\t\t\t// Exit after the stdin stream is exhausted.\n\t\t\tawait new Promise((resolve) => {\n\t\t\t\tprocessApi.childProcess.stdin.on('finish', () => {\n\t\t\t\t\tresolve(true);\n\t\t\t\t});\n\t\t\t});\n\t\t\tprocessApi.exit(0);\n\t\t\treturn;\n\t\t}\n\n\t\tif (!['php', 'ls', 'pwd'].includes(binaryName ?? '')) {\n\t\t\t// 127 is the exit code \"for command not found\".\n\t\t\tprocessApi.exit(127);\n\t\t\treturn;\n\t\t}\n\n\t\tif (!getPHPInstance) {\n\t\t\tlogger.warn(\n\t\t\t\t'Tried to spawn a PHP subprocess, but the sandboxed spawn handler was created without a getPHPInstance function.'\n\t\t\t);\n\t\t\tprocessApi.exit(127);\n\t\t\treturn;\n\t\t}\n\n\t\tconst { php, reap } = await getPHPInstance();\n\n\t\ttry {\n\t\t\tif (options.cwd) {\n\t\t\t\tawait php.chdir(options.cwd as string);\n\t\t\t}\n\n\t\t\tconst cwd = await php.cwd();\n\t\t\tswitch (binaryName) {\n\t\t\t\tcase 'php': {\n\t\t\t\t\t// Figure out more about setting env, putenv(), etc.\n\t\t\t\t\tconst result = await php.cli(args, {\n\t\t\t\t\t\tenv: {\n\t\t\t\t\t\t\t...options.env,\n\t\t\t\t\t\t\tSCRIPT_PATH: args[1],\n\t\t\t\t\t\t\t// Set SHELL_PIPE to 0 to ensure WP-CLI formats\n\t\t\t\t\t\t\t// the output as ASCII tables.\n\t\t\t\t\t\t\t// @see https://github.com/wp-cli/wp-cli/issues/1102\n\t\t\t\t\t\t\tSHELL_PIPE: '0',\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\n\t\t\t\t\tresult.stdout.pipeTo(\n\t\t\t\t\t\tnew WritableStream({\n\t\t\t\t\t\t\twrite(chunk) {\n\t\t\t\t\t\t\t\tprocessApi.stdout(chunk as any as ArrayBuffer);\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\t\t\t\t\tresult.stderr.pipeTo(\n\t\t\t\t\t\tnew WritableStream({\n\t\t\t\t\t\t\twrite(chunk) {\n\t\t\t\t\t\t\t\tprocessApi.stderr(chunk as any as ArrayBuffer);\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t})\n\t\t\t\t\t);\n\t\t\t\t\tprocessApi.exit(await result.exitCode);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'ls': {\n\t\t\t\t\tconst files = await php.listFiles(args[1] ?? cwd);\n\t\t\t\t\tfor (const file of files) {\n\t\t\t\t\t\tprocessApi.stdout(file + '\\n');\n\t\t\t\t\t}\n\t\t\t\t\t// Technical limitation of subprocesses – we need to\n\t\t\t\t\t// wait before exiting to give consumer a chance to read\n\t\t\t\t\t// the output.\n\t\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, 10));\n\t\t\t\t\tprocessApi.exit(0);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'pwd': {\n\t\t\t\t\tprocessApi.stdout(cwd + '\\n');\n\t\t\t\t\t// Technical limitation of subprocesses – we need to\n\t\t\t\t\t// wait before exiting to give consumer a chance to read\n\t\t\t\t\t// the output.\n\t\t\t\t\tawait new Promise((resolve) => setTimeout(resolve, 10));\n\t\t\t\t\tprocessApi.exit(0);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (e) {\n\t\t\t// An exception here means the PHP runtime has crashed.\n\t\t\tprocessApi.exit(1);\n\t\t\tthrow e;\n\t\t} finally {\n\t\t\treap();\n\t\t}\n\t});\n}\n","/* eslint-disable @typescript-eslint/no-unsafe-function-type */\n/* eslint-disable @typescript-eslint/no-misused-new */\n/* eslint-disable @typescript-eslint/no-empty-object-type */\nimport type { MessagePort as NodeMessagePort } from 'worker_threads';\n\n/**\n * Comlink library protocol extension to use synchronous messaging.\n *\n * Debugging Asyncify is too much of a burden. This extension enables exchanging\n * messages between threads synchronously so that we don't need to rely on Asyncify.\n *\n * Upsides:\n *\n * * Saves dozens-to-hundreds of hours on debugging Asyncify issues\n * * Increased reliability\n * * Useful stack traces when errors do happen.\n *\n * Downsides:\n *\n * * Fragmentation: Both synchronous and asynchronous handlers exist to get the best our of both\n * Asyncify and JSPI. * Node.js-only: This extension does not implement a Safari-friendly\n * transport. SharedArrayBuffer is an option, but\n * it requires more restrictive CORP+COEP headers which breaks, e.g., YouTube\n * embeds. Synchronous XHR might work if we really need Safari support for one of\n * the new asynchronous features, but other than that let's just skip adding new\n * asynchronous WASM features to Safari until WebKit supports stack switching.\n * * Message passing between workers is slow. Avoid using synchronous messaging for syscalls that\n * are invoked frequently and\n * handled asynchronously in the same worker.\n *\n * @see https://github.com/adamziel/js-synchronous-messaging for additional ideas.\n * @see https://github.com/WordPress/wordpress-playground/blob/9a9262cc62cc161d220a9992706b9ed2817f2eb5/packages/docs/site/docs/developers/23-architecture/07-wasm-asyncify.md\n */\ninterface SyncMessage {\n\t/** original Comlink envelope */\n\tid?: string;\n\ttype: MessageType;\n\t/** existing Comlink fields … */\n\t[k: string]: any;\n\t/** new part that carries the latch */\n\tnotifyBuffer?: SharedArrayBuffer;\n}\n\ninterface SyncTransport {\n\tafterResponseSent(ev: MessageEvent): void;\n\tsend(\n\t\tep: IsomorphicMessagePort,\n\t\tmsg: Omit<SyncMessage, 'id' | 'notifyBuffer'>,\n\t\ttransferables?: Transferable[]\n\t): WireValue;\n}\n\nexport function exposeSync(\n\tobj: any,\n\tep: Endpoint,\n\ttransport: SyncTransport,\n\tallowedOrigins: (string | RegExp)[] = ['*']\n) {\n\treturn expose(obj, ep, allowedOrigins, transport.afterResponseSent);\n}\n\n//////////////////////////////\n// 3. Consumer side //\n//////////////////////////////\n\nfunction createSyncProxy<T>(\n\tep: IsomorphicMessagePort,\n\tpath: (string | number | symbol)[] = [],\n\ttransport: SyncTransport\n): T {\n\treturn new Proxy(() => {}, {\n\t\tget(_t, prop) {\n\t\t\tif (prop === 'then') {\n\t\t\t\t// allow await‑usage without deadlocking\n\t\t\t\tif (!path.length)\n\t\t\t\t\treturn {\n\t\t\t\t\t\tthen: (_: any, res: any) =>\n\t\t\t\t\t\t\tres(createSyncProxy(ep, [], transport)),\n\t\t\t\t\t};\n\t\t\t}\n\t\t\treturn createSyncProxy(ep, [...path, prop], transport);\n\t\t},\n\n\t\tset(_t, prop, value) {\n\t\t\tconst [v, xfer] = toWireValue(value);\n\t\t\ttransport.send(\n\t\t\t\tep,\n\t\t\t\t{\n\t\t\t\t\ttype: MessageType.SET,\n\t\t\t\t\tpath: [...path, prop].map(String),\n\t\t\t\t\tvalue: v,\n\t\t\t\t},\n\t\t\t\txfer\n\t\t\t);\n\t\t\treturn true;\n\t\t},\n\n\t\tapply(_t, _thisArg, rawArgs) {\n\t\t\t// Special cases\n\t\t\tconst last = path.at(-1);\n\t\t\tif (last === 'bind')\n\t\t\t\treturn createSyncProxy(ep, path.slice(0, -1), transport);\n\n\t\t\tconst [argList, xfer] = processArguments(rawArgs);\n\t\t\tconst wire = transport.send(\n\t\t\t\tep,\n\t\t\t\t{\n\t\t\t\t\ttype: MessageType.APPLY,\n\t\t\t\t\tpath: path.map(String),\n\t\t\t\t\targumentList: argList,\n\t\t\t\t},\n\t\t\t\txfer\n\t\t\t);\n\n\t\t\treturn fromWireValue(wire);\n\t\t},\n\n\t\tconstruct(_t, rawArgs) {\n\t\t\tconst [argList, xfer] = processArguments(rawArgs);\n\t\t\tconst wire = transport.send(\n\t\t\t\tep,\n\t\t\t\t{\n\t\t\t\t\ttype: MessageType.CONSTRUCT,\n\t\t\t\t\tpath: path.map(String),\n\t\t\t\t\targumentList: argList,\n\t\t\t\t},\n\t\t\t\txfer\n\t\t\t);\n\t\t\treturn fromWireValue(wire);\n\t\t},\n\t}) as unknown as T;\n}\n\nexport function wrapSync<T>(\n\tep: IsomorphicMessagePort,\n\ttransport: SyncTransport\n): T {\n\treturn createSyncProxy<T>(ep, [], transport);\n}\n\n/// Transport ///\n\nexport type IsomorphicMessagePort = MessagePort | NodeMessagePort;\n\nexport class NodeSABSyncReceiveMessageTransport {\n\tprivate static receiveMessageOnPort: any;\n\n\tstatic async create() {\n\t\tif (!NodeSABSyncReceiveMessageTransport.receiveMessageOnPort) {\n\t\t\ttry {\n\t\t\t\tNodeSABSyncReceiveMessageTransport.receiveMessageOnPort =\n\t\t\t\t\trequire('worker_threads').receiveMessageOnPort;\n\t\t\t} catch {\n\t\t\t\tNodeSABSyncReceiveMessageTransport.receiveMessageOnPort =\n\t\t\t\t\tawait import('worker_threads').then(\n\t\t\t\t\t\t(m) => m.receiveMessageOnPort\n\t\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\treturn new NodeSABSyncReceiveMessageTransport();\n\t}\n\n\tprivate constructor() {}\n\n\tafterResponseSent(ev: MessageEvent) {\n\t\tconst { notifyBuffer } = ev.data as SyncMessage;\n\t\tif (notifyBuffer) {\n\t\t\tconst view = new Int32Array(notifyBuffer);\n\t\t\tview[0] = 1;\n\t\t\tAtomics.notify(view, 0);\n\t\t}\n\t}\n\tsend(\n\t\tep: IsomorphicMessagePort,\n\t\tmsg: Omit<SyncMessage, 'id' | 'notifyBuffer'>,\n\t\ttransferables?: Transferable[]\n\t): WireValue {\n\t\t// SharedArrayBuffer = one 32‑bit cell that starts at 0.\n\t\t// The other worker will set this to 1 when it has sent the response.\n\t\tconst latch = new SharedArrayBuffer(4);\n\t\tconst view = new Int32Array(latch);\n\t\tview[0] = 0;\n\n\t\tconst id = generateUUID();\n\t\tep.postMessage(\n\t\t\t{ ...msg, id, notifyBuffer: latch },\n\t\t\ttransferables as any\n\t\t);\n\n\t\t// Synchronous pull; Node.js-only. Browsers don't support receiveMessageOnPort.\n\t\tconst timeoutMs = 5000;\n\t\tconst result = Atomics.wait(view, 0, 0, timeoutMs);\n\t\tif (result === 'timed-out') {\n\t\t\tthrow new Error('Timeout waiting for response');\n\t\t}\n\t\twhile (true) {\n\t\t\tconst res =\n\t\t\t\tNodeSABSyncReceiveMessageTransport.receiveMessageOnPort(ep);\n\t\t\tif (res.message?.id === id) {\n\t\t\t\treturn res.message;\n\t\t\t} else if (!res) {\n\t\t\t\tthrow new Error('No response received');\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Original, unmodified Comlink library from Google:\n *\n * @license\n * Copyright 2019 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nexport const proxyMarker = Symbol('Comlink.proxy');\nexport const createEndpoint = Symbol('Comlink.endpoint');\nexport const releaseProxy = Symbol('Comlink.releaseProxy');\nexport const finalizer = Symbol('Comlink.finalizer');\n\nconst throwMarker = Symbol('Comlink.thrown');\n\n/**\n * @license\n * Copyright 2019 Google LLC\n * SPDX-License-Identifier: Apache-2.0\n */\n\nexport interface EventSource {\n\taddEventListener(\n\t\ttype: string,\n\t\tlistener: EventListenerOrEventListenerObject,\n\t\toptions?: object\n\t): void;\n\n\tremoveEventListener(\n\t\ttype: string,\n\t\tlistener: EventListenerOrEventListenerObject,\n\t\toptions?: object\n\t): void;\n}\n\nexport interface PostMessageWithOrigin {\n\tpostMessage(\n\t\tmessage: any,\n\t\ttargetOrigin: string,\n\t\ttransfer?: Transferable[]\n\t): void;\n}\n\nexport interface Endpoint extends EventSource {\n\tpostMessage(message: any, transfer?: Transferable[]): void;\n\n\tstart?: () => void;\n}\n\nexport const WireValueType = {\n\tRAW: 'RAW',\n\tPROXY: 'PROXY',\n\tTHROW: 'THROW',\n\tHANDLER: 'HANDLER',\n} as const;\n\nexport type WireValueType = typeof WireValueType;\n\nexport interface RawWireValue {\n\tid?: string;\n\ttype: WireValueType['RAW'];\n\tvalue: any;\n}\n\nexport interface HandlerWireValue {\n\tid?: string;\n\ttype: WireValueType['HANDLER'];\n\tname: string;\n\tvalue: unknown;\n}\n\nexport type WireValue = RawWireValue | HandlerWireValue;\n\nexport type MessageID = string;\n\nexport const MessageType = {\n\tGET: 'GET',\n\tSET: 'SET',\n\tAPPLY: 'APPLY',\n\tCONSTRUCT: 'CONSTRUCT',\n\tENDPOINT: 'ENDPOINT',\n\tRELEASE: 'RELEASE',\n} as const;\nexport type MessageType = typeof MessageType;\n\nexport interface GetMessage {\n\tid?: MessageID;\n\ttype: MessageType['GET'];\n\tpath: string[];\n}\n\nexport interface SetMessage {\n\tid?: MessageID;\n\ttype: MessageType['SET'];\n\tpath: string[];\n\tvalue: WireValue;\n}\n\nexport interface ApplyMessage {\n\tid?: MessageID;\n\ttype: MessageType['APPLY'];\n\tpath: string[];\n\targumentList: WireValue[];\n}\n\nexport interface ConstructMessage {\n\tid?: MessageID;\n\ttype: MessageType['CONSTRUCT'];\n\tpath: string[];\n\targumentList: WireValue[];\n}\n\nexport interface EndpointMessage {\n\tid?: MessageID;\n\ttype: MessageType['ENDPOINT'];\n}\n\nexport interface ReleaseMessage {\n\tid?: MessageID;\n\ttype: MessageType['RELEASE'];\n}\n\nexport type Message =\n\t| GetMessage\n\t| SetMessage\n\t| ApplyMessage\n\t| ConstructMessage\n\t| EndpointMessage\n\t| ReleaseMessage;\n\n/**\n * Interface of values that were marked to be proxied with `comlink.proxy()`.\n * Can also be implemented by classes.\n */\nexport interface ProxyMarked {\n\t[proxyMarker]: true;\n}\n\n/**\n * Takes a type and wraps it in a Promise, if it not already is one.\n * This is to avoid `Promise<Promise<T>>`.\n *\n * This is the inverse of `Unpromisify<T>`.\n */\ntype Promisify<T> = T extends Promise<unknown> ? T : Promise<T>;\n/**\n * Takes a type that may be Promise and unwraps the Promise type.\n * If `P` is not a Promise, it returns `P`.\n *\n * This is the inverse of `Promisify<T>`.\n */\ntype Unpromisify<P> = P extends Promise<infer T> ? T : P;\n\n/**\n * Takes the raw type of a remote property and returns the type that is visible to the local thread\n * on the proxy.\n *\n * Note: This needs to be its own type alias, otherwise it will not distribute over unions.\n * See https://www.typescriptlang.org/docs/handbook/advanced-types.html#distributive-conditional-types\n */\ntype RemoteProperty<T> =\n\t// If the value is a method, comlink will proxy it automatically.\n\t// Objects are only proxied if they are marked to be proxied.\n\t// Otherwise, the property is converted to a Promise that resolves the cloned value.\n\tT extends Function | ProxyMarked ? Remote<T> : Promisify<T>;\n\n/**\n * Takes the raw type of a property as a remote thread would see it through a proxy (e.g. when\n * passed in as a function argument) and returns the type that the local thread has to supply.\n *\n * This is the inverse of `RemoteProperty<T>`.\n *\n * Note: This needs to be its own type alias, otherwise it will not distribute over unions. See\n * https://www.typescriptlang.org/docs/handbook/advanced-types.html#distributive-conditional-types\n */\ntype LocalProperty<T> = T extends Function | ProxyMarked\n\t? Local<T>\n\t: Unpromisify<T>;\n\n/**\n * Proxies `T` if it is a `ProxyMarked`, clones it otherwise (as handled by structured cloning and\n * transfer handlers).\n */\nexport type ProxyOrClone<T> = T extends ProxyMarked ? Remote<T> : T;\n/**\n * Inverse of `ProxyOrClone<T>`.\n */\nexport type UnproxyOrClone<T> = T extends RemoteObject<ProxyMarked>\n\t? Local<T>\n\t: T;\n\n/**\n * Takes the raw type of a remote object in the other thread and returns the type as it is visible\n * to the local thread when proxied with `Comlink.proxy()`.\n *\n * This does not handle call signatures, which is handled by the more general `Remote<T>` type.\n *\n * @template T The raw type of a remote object as seen in the other thread.\n */\nexport type RemoteObject<T> = { [P in keyof T]: RemoteProperty<T[P]> };\n/**\n * Takes the type of an object as a remote thread would see it through a proxy (e.g. when passed in\n * as a function argument) and returns the type that the local thread has to supply.\n *\n * This does not handle call signatures, which is handled by the more general `Local<T>` type.\n *\n * This is the inverse of `RemoteObject<T>`.\n *\n * @template T The type of a proxied object.\n */\nexport type LocalObject<T> = { [P in keyof T]: LocalProperty<T[P]> };\n\n/**\n * Additional special comlink methods available on each proxy returned by `Comlink.wrap()`.\n */\nexport interface ProxyMethods {\n\t[createEndpoint]: () => Promise<MessagePort>;\n\t[releaseProxy]: () => void;\n}\n\n/**\n * Takes the raw type of a remote object, function or class in the other thread and returns the\n * type as it is visible to the local thread from the proxy return value of `Comlink.wrap()` or\n * `Comlink.proxy()`.\n */\nexport type Remote<T> =\n\t// Handle properties\n\tRemoteObject<T> &\n\t\t// Handle call signature (if present)\n\t\t(T extends (...args: infer TArguments) => infer TReturn\n\t\t\t? (\n\t\t\t\t\t...args: {\n\t\t\t\t\t\t[I in keyof TArguments]: UnproxyOrClone<TArguments[I]>;\n\t\t\t\t\t}\n\t\t\t ) => Promisify<ProxyOrClone<Unpromisify<TReturn>>>\n\t\t\t: unknown) &\n\t\t// Handle construct signature (if present)\n\t\t// The return of construct signatures is always proxied (whether marked or not)\n\t\t(T extends { new (...args: infer TArguments): infer TInstance }\n\t\t\t? {\n\t\t\t\t\tnew (\n\t\t\t\t\t\t...args: {\n\t\t\t\t\t\t\t[I in keyof TArguments]: UnproxyOrClone<\n\t\t\t\t\t\t\t\tTArguments[I]\n\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t}\n\t\t\t\t\t): Promisify<Remote<TInstance>>;\n\t\t\t }\n\t\t\t: unknown) &\n\t\t// Include additional special comlink methods available on the proxy.\n\t\tProxyMethods;\n\n/**\n * Expresses that a type can be either a sync or async.\n */\ntype MaybePromise<T> = Promise<T> | T;\n\n/**\n * Takes the raw type of a remote object, function or class as a remote thread would see it through\n * a proxy (e.g. when passed in as a function argument) and returns the type the local thread has\n * to supply.\n *\n * This is the inverse of `Remote<T>`. It takes a `Remote<T>` and returns its original input `T`.\n */\nexport type Local<T> =\n\t// Omit the special proxy methods (they don't need to be supplied, comlink adds them)\n\tOmit<LocalObject<T>, keyof ProxyMethods> &\n\t\t// Handle call signatures (if present)\n\t\t(T extends (...args: infer TArguments) => infer TReturn\n\t\t\t? (\n\t\t\t\t\t...args: {\n\t\t\t\t\t\t[I in keyof TArguments]: ProxyOrClone<TArguments[I]>;\n\t\t\t\t\t}\n\t\t\t ) => // The raw function could either be sync or async, but is always proxied automatically\n\t\t\t MaybePromise<UnproxyOrClone<Unpromisify<TReturn>>>\n\t\t\t: unknown) &\n\t\t// Handle construct signature (if present)\n\t\t// The return of construct signatures is always proxied (whether marked or not)\n\t\t(T extends { new (...args: infer TArguments): infer TInstance }\n\t\t\t? {\n\t\t\t\t\tnew (\n\t\t\t\t\t\t...args: {\n\t\t\t\t\t\t\t[I in keyof TArguments]: ProxyOrClone<\n\t\t\t\t\t\t\t\tTArguments[I]\n\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t}\n\t\t\t\t\t): // The raw constructor could either be sync or async, but is always proxied automatically\n\t\t\t\t\tMaybePromise<Local<Unpromisify<TInstance>>>;\n\t\t\t }\n\t\t\t: unknown);\n\nconst isObject = (val: unknown): val is object =>\n\t(typeof val === 'object' && val !== null) || typeof val === 'function';\n\n/**\n * Customizes the serialization of certain values as determined by `canHandle()`.\n *\n * @template T The input type being handled by this transfer handler.\n * @template S The serialized type sent over the wire.\n */\nexport interface TransferHandler<T, S> {\n\t/**\n\t * Gets called for every value to determine whether this transfer handler\n\t * should serialize the value, which includes checking that it is of the right\n\t * type (but can perform checks beyond that as well).\n\t */\n\tcanHandle(value: unknown): value is T;\n\n\t/**\n\t * Gets called with the value if `canHandle()` returned `true` to produce a\n\t * value that can be sent in a message, consisting of structured-cloneable\n\t * values and/or transferrable objects.\n\t */\n\tserialize(value: T): [S, Transferable[]];\n\n\t/**\n\t * Gets called to deserialize an incoming value that was serialized in the\n\t * other thread with this transfer handler (known through the name it was\n\t * registered under).\n\t */\n\tdeserialize(value: S): T;\n}\n\n/**\n * Internal transfer handle to handle objects marked to proxy.\n */\nconst proxyTransferHandler: TransferHandler<object, MessagePort> = {\n\tcanHandle: (val): val is ProxyMarked =>\n\t\tisObject(val) && (val as ProxyMarked)[proxyMarker],\n\tserialize(obj) {\n\t\tconst { port1, port2 } = new MessageChannel();\n\t\texpose(obj, port1);\n\t\treturn [port2, [port2]];\n\t},\n\tdeserialize(port) {\n\t\tport.start();\n\t\treturn wrap(port);\n\t},\n};\n\ninterface ThrownValue {\n\t[throwMarker]: unknown; // just needs to be present\n\tvalue: unknown;\n}\ntype SerializedThrownValue =\n\t| { isError: true; value: Error }\n\t| { isError: false; value: unknown };\ntype PendingListenersMap = Map<\n\tstring,\n\t(value: WireValue | PromiseLike<WireValue>) => void\n>;\n\n/**\n * Internal transfer handler to handle thrown exceptions.\n */\nconst throwTransferHandler: TransferHandler<\n\tThrownValue,\n\tSerializedThrownValue\n> = {\n\tcanHandle: (value): value is ThrownValue =>\n\t\tisObject(value) && throwMarker in value,\n\tserialize({ value }) {\n\t\tlet serialized: SerializedThrownValue;\n\t\tif (value instanceof Error) {\n\t\t\tserialized = {\n\t\t\t\tisError: true,\n\t\t\t\tvalue: {\n\t\t\t\t\tmessage: value.message,\n\t\t\t\t\tname: value.name,\n\t\t\t\t\tstack: value.stack,\n\t\t\t\t},\n\t\t\t};\n\t\t} else {\n\t\t\tserialized = { isError: false, value };\n\t\t}\n\t\treturn [serialized, []];\n\t},\n\tdeserialize(serialized) {\n\t\tif (serialized.isError) {\n\t\t\tthrow Object.assign(\n\t\t\t\tnew Error(serialized.value.message),\n\t\t\t\tserialized.value\n\t\t\t);\n\t\t}\n\t\tthrow serialized.value;\n\t},\n};\n\n/**\n * Allows customizing the serialization of certain values.\n */\nexport const transferHandlers = new Map<\n\tstring,\n\tTransferHandler<unknown, unknown>\n>([\n\t['proxy', proxyTransferHandler],\n\t['throw', throwTransferHandler],\n]);\n\nfunction isAllowedOrigin(\n\tallowedOrigins: (string | RegExp)[],\n\torigin: string\n): boolean {\n\tfor (const allowedOrigin of allowedOrigins) {\n\t\tif (origin === allowedOrigin || allowedOrigin === '*') {\n\t\t\treturn true;\n\t\t}\n\t\tif (allowedOrigin instanceof RegExp && allowedOrigin.test(origin)) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\nexport function expose(\n\tobj: any,\n\tep: Endpoint = globalThis as any,\n\tallowedOrigins: (string | RegExp)[] = ['*'],\n\tafterResponseSent?: (ev: MessageEvent) => void\n) {\n\tep.addEventListener('message', function callback(ev: MessageEvent) {\n\t\tif (!ev || !ev.data) {\n\t\t\treturn;\n\t\t}\n\t\tif (!isAllowedOrigin(allowedOrigins, ev.origin)) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.warn(`Invalid origin '${ev.origin}' for comlink proxy`);\n\t\t\treturn;\n\t\t}\n\t\tconst { id, type, path } = {\n\t\t\tpath: [] as string[],\n\t\t\t...(ev.data as Message),\n\t\t};\n\t\tconst argumentList = (ev.data.argumentList || []).map(fromWireValue);\n\t\tlet returnValue;\n\t\ttry {\n\t\t\tconst parent = path\n\t\t\t\t.slice(0, -1)\n\t\t\t\t.reduce((obj, prop) => obj[prop], obj);\n\t\t\tconst rawValue = path.reduce((obj, prop) => obj[prop], obj);\n\t\t\tswitch (type) {\n\t\t\t\tcase MessageType.GET:\n\t\t\t\t\t{\n\t\t\t\t\t\treturnValue = rawValue;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase MessageType.SET:\n\t\t\t\t\t{\n\t\t\t\t\t\tparent[path.slice(-1)[0]] = fromWireValue(\n\t\t\t\t\t\t\tev.data.value\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturnValue = true;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase MessageType.APPLY:\n\t\t\t\t\t{\n\t\t\t\t\t\treturnValue = rawValue.apply(parent, argumentList);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase MessageType.CONSTRUCT:\n\t\t\t\t\t{\n\t\t\t\t\t\tconst value = new rawValue(...argumentList);\n\t\t\t\t\t\treturnValue = proxy(value);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase MessageType.ENDPOINT:\n\t\t\t\t\t{\n\t\t\t\t\t\tconst { port1, port2 } = new MessageChannel();\n\t\t\t\t\t\texpose(obj, port2);\n\t\t\t\t\t\treturnValue = transfer(port1, [port1]);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase MessageType.RELEASE:\n\t\t\t\t\t{\n\t\t\t\t\t\treturnValue = undefined;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\treturn;\n\t\t\t}\n\t\t} catch (value) {\n\t\t\treturnValue = { value, [throwMarker]: 0 };\n\t\t}\n\t\tPromise.resolve(returnValue)\n\t\t\t.catch((value) => {\n\t\t\t\treturn { value, [throwMarker]: 0 };\n\t\t\t})\n\t\t\t.then((returnValue) => {\n\t\t\t\tconst [wireValue, transferables] = toWireValue(returnValue);\n\t\t\t\tep.postMessage({ ...wireValue, id }, transferables);\n\t\t\t\tif (type === MessageType.RELEASE) {\n\t\t\t\t\t// detach and deactive after sending release response above.\n\t\t\t\t\tep.removeEventListener('message', callback as any);\n\t\t\t\t\tcloseEndPoint(ep);\n\t\t\t\t\tif (\n\t\t\t\t\t\tfinalizer in obj &&\n\t\t\t\t\t\ttypeof obj[finalizer] === 'function'\n\t\t\t\t\t) {\n\t\t\t\t\t\tobj[finalizer]();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})\n\t\t\t.catch(() => {\n\t\t\t\t// Send Serialization Error To Caller\n\t\t\t\tconst [wireValue, transferables] = toWireValue({\n\t\t\t\t\tvalue: new TypeError('Unserializable return value'),\n\t\t\t\t\t[throwMarker]: 0,\n\t\t\t\t});\n\t\t\t\tep.postMessage({ ...wireValue, id }, transferables);\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\tafterResponseSent?.(ev);\n\t\t\t});\n\t} as any);\n\tif (ep.start) {\n\t\tep.start();\n\t}\n}\n\nfunction isMessagePort(endpoint: Endpoint): endpoint is MessagePort {\n\treturn endpoint.constructor.name === 'MessagePort';\n}\n\nfunction closeEndPoint(endpoint: Endpoint) {\n\tif (isMessagePort(endpoint)) endpoint.close();\n}\n\nexport function wrap<T>(ep: Endpoint, target?: any): Remote<T> {\n\tconst pendingListeners: PendingListenersMap = new Map();\n\n\tep.addEventListener('message', function handleMessage(ev: Event) {\n\t\tconst { data } = ev as MessageEvent;\n\t\tif (!data || !data.id) {\n\t\t\treturn;\n\t\t}\n\t\tconst resolver = pendingListeners.get(data.id);\n\t\tif (!resolver) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tresolver(data);\n\t\t} finally {\n\t\t\tpendingListeners.delete(data.id);\n\t\t}\n\t});\n\n\treturn createProxy<T>(ep, pendingListeners, [], target) as any;\n}\n\nfunction throwIfProxyReleased(isReleased: boolean) {\n\tif (isReleased) {\n\t\tthrow new Error('Proxy has been released and is not useable');\n\t}\n}\n\nfunction releaseEndpoint(ep: Endpoint) {\n\treturn requestResponseMessage(ep, new Map(), {\n\t\ttype: MessageType.RELEASE,\n\t}).then(() => {\n\t\tcloseEndPoint(ep);\n\t});\n}\n\ninterface FinalizationRegistry<T> {\n\t// @ts-ignore\n\tnew (cb: (heldValue: T) => void): FinalizationRegistry<T>;\n\tregister(\n\t\tweakItem: object,\n\t\theldValue: T,\n\t\tunregisterToken?: object | undefined\n\t): void;\n\tunregister(unregisterToken: object): void;\n}\ndeclare const FinalizationRegistry: FinalizationRegistry<Endpoint>;\n\nconst proxyCounter = new WeakMap<Endpoint, number>();\nconst proxyFinalizers =\n\t'FinalizationRegistry' in globalThis &&\n\tnew FinalizationRegistry((ep: Endpoint) => {\n\t\tconst newCount = (proxyCounter.get(ep) || 0) - 1;\n\t\tproxyCounter.set(ep, newCount);\n\t\tif (newCount === 0) {\n\t\t\treleaseEndpoint(ep);\n\t\t}\n\t});\n\nfunction registerProxy(proxy: object, ep: Endpoint) {\n\tconst newCount = (proxyCounter.get(ep) || 0) + 1;\n\tproxyCounter.set(ep, newCount);\n\tif (proxyFinalizers) {\n\t\tproxyFinalizers.register(proxy, ep, proxy);\n\t}\n}\n\nfunction unregisterProxy(proxy: object) {\n\tif (proxyFinalizers) {\n\t\tproxyFinalizers.unregister(proxy);\n\t}\n}\n\nfunction createProxy<T>(\n\tep: Endpoint,\n\tpendingListeners: PendingListenersMap,\n\tpath: (string | number | symbol)[] = [],\n\ttarget: object = function () {}\n): Remote<T> {\n\tlet isProxyReleased = false;\n\tconst proxy = new Proxy(target, {\n\t\tget(_target, prop) {\n\t\t\tthrowIfProxyReleased(isProxyReleased);\n\t\t\tif (prop === releaseProxy) {\n\t\t\t\treturn () => {\n\t\t\t\t\tunregisterProxy(proxy);\n\t\t\t\t\treleaseEndpoint(ep);\n\t\t\t\t\tpendingListeners.clear();\n\t\t\t\t\tisProxyReleased = true;\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (prop === 'then') {\n\t\t\t\tif (path.length === 0) {\n\t\t\t\t\treturn { then: () => proxy };\n\t\t\t\t}\n\t\t\t\tconst r = requestResponseMessage(ep, pendingListeners, {\n\t\t\t\t\ttype: MessageType.GET,\n\t\t\t\t\tpath: path.map((p) => p.toString()),\n\t\t\t\t}).then(fromWireValue);\n\t\t\t\treturn r.then.bind(r);\n\t\t\t}\n\t\t\treturn createProxy(ep, pendingListeners, [...path, prop]);\n\t\t},\n\t\tset(_target, prop, rawValue) {\n\t\t\tthrowIfProxyReleased(isProxyReleased);\n\t\t\t// FIXME: ES6 Proxy Handler `set` methods are supposed to return a\n\t\t\t// boolean. To show good will, we return true asynchronously ¯\\_(ツ)_/¯\n\t\t\tconst [value, transferables] = toWireValue(rawValue);\n\t\t\treturn requestResponseMessage(\n\t\t\t\tep,\n\t\t\t\tpendingListeners,\n\t\t\t\t{\n\t\t\t\t\ttype: MessageType.SET,\n\t\t\t\t\tpath: [...path, prop].map((p) => p.toString()),\n\t\t\t\t\tvalue,\n\t\t\t\t},\n\t\t\t\ttransferables\n\t\t\t).then(fromWireValue) as any;\n\t\t},\n\t\tapply(_target, _thisArg, rawArgumentList) {\n\t\t\tthrowIfProxyReleased(isProxyReleased);\n\t\t\tconst last = path[path.length - 1];\n\t\t\tif ((last as any) === createEndpoint) {\n\t\t\t\treturn requestResponseMessage(ep, pendingListeners, {\n\t\t\t\t\ttype: MessageType.ENDPOINT,\n\t\t\t\t}).then(fromWireValue);\n\t\t\t}\n\t\t\t// We just pretend that `bind()` didn’t happen.\n\t\t\tif (last === 'bind') {\n\t\t\t\treturn createProxy(ep, pendingListeners, path.slice(0, -1));\n\t\t\t}\n\t\t\tconst [argumentList, transferables] =\n\t\t\t\tprocessArguments(rawArgumentList);\n\t\t\treturn requestResponseMessage(\n\t\t\t\tep,\n\t\t\t\tpendingListeners,\n\t\t\t\t{\n\t\t\t\t\ttype: MessageType.APPLY,\n\t\t\t\t\tpath: path.map((p) => p.toString()),\n\t\t\t\t\targumentList,\n\t\t\t\t},\n\t\t\t\ttransferables\n\t\t\t).then(fromWireValue);\n\t\t},\n\t\tconstruct(_target, rawArgumentList) {\n\t\t\tthrowIfProxyReleased(isProxyReleased);\n\t\t\tconst [argumentList, transferables] =\n\t\t\t\tprocessArguments(rawArgumentList);\n\t\t\treturn requestResponseMessage(\n\t\t\t\tep,\n\t\t\t\tpendingListeners,\n\t\t\t\t{\n\t\t\t\t\ttype: MessageType.CONSTRUCT,\n\t\t\t\t\tpath: path.map((p) => p.toString()),\n\t\t\t\t\targumentList,\n\t\t\t\t},\n\t\t\t\ttransferables\n\t\t\t).then(fromWireValue);\n\t\t},\n\t});\n\tregisterProxy(proxy, ep);\n\treturn proxy as any;\n}\n\nfunction myFlat<T>(arr: (T | T[])[]): T[] {\n\treturn Array.prototype.concat.apply([], arr);\n}\n\nfunction processArguments(argumentList: any[]): [WireValue[], Transferable[]] {\n\tconst processed = argumentList.map(toWireValue);\n\treturn [processed.map((v) => v[0]), myFlat(processed.map((v) => v[1]))];\n}\n\nconst transferCache = new WeakMap<any, Transferable[]>();\nexport function transfer<T>(obj: T, transfers: Transferable[]): T {\n\ttransferCache.set(obj, transfers);\n\treturn obj;\n}\n\nexport function proxy<T extends object>(obj: T): T & ProxyMarked {\n\treturn Object.assign(obj, { [proxyMarker]: true }) as any;\n}\n\nexport function windowEndpoint(\n\tw: PostMessageWithOrigin,\n\tcontext: EventSource = globalThis,\n\ttargetOrigin = '*'\n): Endpoint {\n\treturn {\n\t\tpostMessage: (msg: any, transferables: Transferable[]) =>\n\t\t\tw.postMessage(msg, targetOrigin, transferables),\n\t\taddEventListener: context.addEventListener.bind(context),\n\t\tremoveEventListener: context.removeEventListener.bind(context),\n\t};\n}\n\nfunction toWireValue(value: any): [WireValue, Transferable[]] {\n\tfor (const [name, handler] of transferHandlers) {\n\t\tif (handler.canHandle(value)) {\n\t\t\tconst [serializedValue, transferables] = handler.serialize(value);\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\ttype: WireValueType.HANDLER,\n\t\t\t\t\tname,\n\t\t\t\t\tvalue: serializedValue,\n\t\t\t\t},\n\t\t\t\ttransferables,\n\t\t\t];\n\t\t}\n\t}\n\treturn [\n\t\t{\n\t\t\ttype: WireValueType.RAW,\n\t\t\tvalue,\n\t\t},\n\t\ttransferCache.get(value) || [],\n\t];\n}\n\nfunction fromWireValue(value: WireValue): any {\n\tswitch (value.type) {\n\t\tcase WireValueType.HANDLER:\n\t\t\treturn transferHandlers.get(value.name)!.deserialize(value.value);\n\t\tcase WireValueType.RAW:\n\t\t\treturn value.value;\n\t}\n}\n\nfunction requestResponseMessage(\n\tep: Endpoint,\n\tpendingListeners: PendingListenersMap,\n\tmsg: Message,\n\ttransfers?: Transferable[]\n): Promise<WireValue> {\n\treturn new Promise((resolve) => {\n\t\tconst id = generateUUID();\n\t\tpendingListeners.set(id, resolve);\n\t\tif (ep.start) {\n\t\t\tep.start();\n\t\t}\n\t\tep.postMessage({ id, ...msg }, transfers);\n\t});\n}\n\nfunction generateUUID(): string {\n\treturn new Array(4)\n\t\t.fill(0)\n\t\t.map(() =>\n\t\t\tMath.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16)\n\t\t)\n\t\t.join('-');\n}\n\n// node-adapter.ts:\n\nexport interface NodeEndpoint {\n\tpostMessage(message: any, transfer?: any[]): void;\n\ton(\n\t\ttype: string,\n\t\tlistener: EventListenerOrEventListenerObject,\n\t\toptions?: object\n\t): void;\n\toff(\n\t\ttype: string,\n\t\tlistener: EventListenerOrEventListenerObject,\n\t\toptions?: object\n\t): void;\n\tstart?: () => void;\n}\n\nexport function nodeEndpoint(nep: NodeEndpoint): Endpoint {\n\tconst listeners = new WeakMap();\n\treturn {\n\t\tpostMessage: nep.postMessage.bind(nep),\n\t\taddEventListener: (_, eh) => {\n\t\t\tconst l = (data: any) => {\n\t\t\t\tif ('handleEvent' in eh) {\n\t\t\t\t\teh.handleEvent({ data } as MessageEvent);\n\t\t\t\t} else {\n\t\t\t\t\teh({ data } as MessageEvent);\n\t\t\t\t}\n\t\t\t};\n\t\t\tnep.on('message', l);\n\t\t\tlisteners.set(eh, l);\n\t\t},\n\t\tremoveEventListener: (_, eh) => {\n\t\t\tconst l = listeners.get(eh);\n\t\t\tif (!l) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tnep.off('message', l);\n\t\t\tlisteners.delete(eh);\n\t\t},\n\t\tstart: nep.start && nep.start.bind(nep),\n\t};\n}\n","import type { Endpoint } from './comlink-sync';\nimport type { EventEmitter } from 'events';\n\n// Handle the difference between EventEmitter (Node) and EventTarget (web).\nconst proxyByListener: WeakMap<\n\tEventListenerOrEventListenerObject,\n\t(...args: any[]) => void\n> = new WeakMap();\n\ntype EventEmitterWithSend = Pick<\n\tEventEmitter,\n\t'addListener' | 'removeListener'\n> & {\n\tsend?: (...args: any[]) => unknown;\n};\n\nexport interface NodeProcess {\n\tsend: (...args: any[]) => unknown;\n\taddListener: (\n\t\ttype: string,\n\t\tlistener: EventListenerOrEventListenerObject\n\t) => void;\n\tremoveListener: (\n\t\ttype: string,\n\t\tlistener: EventListenerOrEventListenerObject\n\t) => void;\n}\n\nexport function nodeProcessEndpoint(worker?: NodeProcess): Endpoint {\n\tconst emitter = (worker || process) as EventEmitter;\n\tif (typeof (emitter as EventEmitterWithSend).send !== 'function') {\n\t\tthrow new Error(\n\t\t\t'IPC channel is not available. Did you forget to fork the process?'\n\t\t);\n\t}\n\tconst emitterWithSend = emitter as EventEmitterWithSend;\n\n\treturn {\n\t\tpostMessage(message: unknown, _transferList?: Transferable[]) {\n\t\t\tif (_transferList && _transferList.length > 0) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t'Transferable objects are not supported for nodeProcessEndpoint'\n\t\t\t\t);\n\t\t\t}\n\t\t\temitterWithSend.send?.(message);\n\t\t},\n\n\t\taddEventListener(\n\t\t\ttype: string,\n\t\t\tlistener: EventListenerOrEventListenerObject\n\t\t) {\n\t\t\tconst proxy =\n\t\t\t\ttypeof listener === 'function'\n\t\t\t\t\t? (data: unknown) => listener({ data } as MessageEvent)\n\t\t\t\t\t: (data: unknown) =>\n\t\t\t\t\t\t\tlistener.handleEvent({ data } as MessageEvent);\n\t\t\tproxyByListener.set(listener, proxy);\n\t\t\temitterWithSend.addListener(type, proxy);\n\t\t},\n\n\t\tremoveEventListener(\n\t\t\ttype: string,\n\t\t\tlistener: EventListenerOrEventListenerObject\n\t\t) {\n\t\t\tconst proxy = proxyByListener.get(listener);\n\t\t\tif (!proxy) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tproxyByListener.delete(listener);\n\t\t\temitterWithSend.removeListener(type, proxy);\n\t\t},\n\n\t\tstart() {\n\t\t\t// EventEmitter-based endpoints do not need explicit start logic.\n\t\t},\n\t};\n}\n","/**\n * `serialize-error` package wrapped as a single file for compatibility\n * with both CJS and ESM.\n *\n * @see https://github.com/sindresorhus/serialize-error\n */\nconst list = [\n\t// Native ES errors https://262.ecma-international.org/12.0/#sec-well-known-intrinsic-objects\n\tError,\n\tEvalError,\n\tRangeError,\n\tReferenceError,\n\tSyntaxError,\n\tTypeError,\n\tURIError,\n\tAggregateError,\n\n\t// Built-in errors\n\tglobalThis.DOMException,\n\n\t// Node-specific errors\n\t// https://nodejs.org/api/errors.html\n\t(globalThis as any).AssertionError,\n\t(globalThis as any).SystemError,\n]\n\t// Non-native Errors are used with `globalThis` because they might be missing. This filter drops\n\t// them when undefined.\n\t.filter(Boolean)\n\t.map((constructor) => [constructor.name, constructor]);\n\nexport type ErrorObject = {\n\tname?: string;\n\tmessage?: string;\n\tstack?: string;\n\tcause?: unknown;\n\tcode?: string;\n} & Record<string, unknown>;\n\nexport const errorConstructors = new Map(list as any);\n\nexport function addKnownErrorConstructor(constructor: any) {\n\tconst { name } = constructor;\n\tif (errorConstructors.has(name)) {\n\t\tthrow new Error(`The error constructor \"${name}\" is already known.`);\n\t}\n\n\ttry {\n\t\t// eslint-disable-next-line no-new -- It just needs to be verified\n\t\tnew constructor();\n\t} catch (error) {\n\t\tthrow new Error(`The error constructor \"${name}\" is not compatible`, {\n\t\t\tcause: error,\n\t\t});\n\t}\n\n\terrorConstructors.set(name, constructor);\n}\n\nexport class NonError extends Error {\n\toverride name = 'NonError';\n\n\tconstructor(message: any) {\n\t\tsuper(NonError._prepareSuperMessage(message));\n\t}\n\n\tstatic _prepareSuperMessage(message: any) {\n\t\ttry {\n\t\t\treturn JSON.stringify(message);\n\t\t} catch {\n\t\t\treturn String(message);\n\t\t}\n\t}\n}\n\nconst errorProperties = [\n\t{\n\t\tproperty: 'name',\n\t\tenumerable: false,\n\t},\n\t{\n\t\tproperty: 'message',\n\t\tenumerable: false,\n\t},\n\t{\n\t\tproperty: 'stack',\n\t\tenumerable: false,\n\t},\n\t{\n\t\tproperty: 'code',\n\t\tenumerable: true,\n\t},\n\t{\n\t\tproperty: 'cause',\n\t\tenumerable: false,\n\t},\n\t{\n\t\tproperty: 'errors',\n\t\tenumerable: false,\n\t},\n];\n\nconst toJsonWasCalled = new WeakSet();\n\nconst toJSON = (from: any) => {\n\ttoJsonWasCalled.add(from);\n\tconst json = from.toJSON();\n\ttoJsonWasCalled.delete(from);\n\treturn json;\n};\n\nconst newError = (name: any) => {\n\tconst ErrorConstructor = errorConstructors.get(name) ?? (Error as any);\n\treturn ErrorConstructor === AggregateError\n\t\t? new ErrorConstructor([])\n\t\t: new ErrorConstructor();\n};\n\n// eslint-disable-next-line complexity\nconst destroyCircular = ({\n\tfrom,\n\tseen,\n\tto,\n\tforceEnumerable,\n\tmaxDepth,\n\tdepth,\n\tuseToJSON,\n\tserialize,\n}: {\n\tfrom?: any;\n\tseen: any[];\n\tto?: any;\n\tforceEnumerable: boolean;\n\tmaxDepth: number;\n\tdepth: number;\n\tuseToJSON: boolean;\n\tserialize: boolean;\n}) => {\n\tif (!to) {\n\t\tif (Array.isArray(from)) {\n\t\t\tto = [];\n\t\t} else if (!serialize && isErrorLike(from)) {\n\t\t\tto = newError(from.name);\n\t\t} else {\n\t\t\tto = {};\n\t\t}\n\t}\n\n\tseen.push(from);\n\n\tif (depth >= maxDepth) {\n\t\treturn to;\n\t}\n\n\tif (\n\t\tuseToJSON &&\n\t\ttypeof from.toJSON === 'function' &&\n\t\t!toJsonWasCalled.has(from)\n\t) {\n\t\treturn toJSON(from);\n\t}\n\n\tconst continueDestroyCircular = (value: any) =>\n\t\tdestroyCircular({\n\t\t\tfrom: value,\n\t\t\tseen: [...seen],\n\t\t\tforceEnumerable,\n\t\t\tmaxDepth,\n\t\t\tdepth,\n\t\t\tuseToJSON,\n\t\t\tserialize,\n\t\t});\n\n\tfor (const [key, value] of Object.entries(from)) {\n\t\tif (\n\t\t\tvalue &&\n\t\t\tvalue instanceof Uint8Array &&\n\t\t\tvalue.constructor.name === 'Buffer'\n\t\t) {\n\t\t\tto[key] = '[object Buffer]';\n\t\t\tcontinue;\n\t\t}\n\n\t\t// TODO: Use `stream.isReadable()` when targeting Node.js 18.\n\t\tif (\n\t\t\tvalue !== null &&\n\t\t\ttypeof value === 'object' &&\n\t\t\ttypeof (value as any).pipe === 'function'\n\t\t) {\n\t\t\tto[key] = '[object Stream]';\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (typeof value === 'function') {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (!value || typeof value !== 'object') {\n\t\t\t// Gracefully handle non-configurable errors like `DOMException`.\n\t\t\ttry {\n\t\t\t\tto[key] = value;\n\t\t\t} catch {\n\t\t\t\t// ignore\n\t\t\t}\n\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (!seen.includes(from[key])) {\n\t\t\tdepth++;\n\t\t\tto[key] = continueDestroyCircular(from[key]);\n\n\t\t\tcontinue;\n\t\t}\n\n\t\tto[key] = '[Circular]';\n\t}\n\n\tif (serialize || to instanceof Error) {\n\t\tfor (const { property, enumerable } of errorProperties) {\n\t\t\tif (from[property] !== undefined && from[property] !== null) {\n\t\t\t\tObject.defineProperty(to, property, {\n\t\t\t\t\tvalue:\n\t\t\t\t\t\tisErrorLike(from[property]) ||\n\t\t\t\t\t\tArray.isArray(from[property])\n\t\t\t\t\t\t\t? continueDestroyCircular(from[property])\n\t\t\t\t\t\t\t: from[property],\n\t\t\t\t\tenumerable: forceEnumerable ? true : enumerable,\n\t\t\t\t\tconfigurable: true,\n\t\t\t\t\twritable: true,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn to;\n};\n\nexport function serializeError(value: any, options: any = {}) {\n\tconst { maxDepth = Number.POSITIVE_INFINITY, useToJSON = true } = options;\n\n\tif (typeof value === 'object' && value !== null) {\n\t\treturn destroyCircular({\n\t\t\tfrom: value,\n\t\t\tseen: [],\n\t\t\tforceEnumerable: true,\n\t\t\tmaxDepth,\n\t\t\tdepth: 0,\n\t\t\tuseToJSON,\n\t\t\tserialize: true,\n\t\t});\n\t}\n\n\t// People sometimes throw things besides Error objects…\n\tif (typeof value === 'function') {\n\t\t// `JSON.stringify()` discards functions. We do too, unless a function is thrown directly.\n\t\t// We intentionally use `||` because `.name` is an empty string for anonymous functions.\n\t\treturn `[Function: ${value.name || 'anonymous'}]`;\n\t}\n\n\treturn value;\n}\n\nexport function deserializeError(value: any, options: any = {}) {\n\tconst { maxDepth = Number.POSITIVE_INFINITY } = options;\n\n\tif (value instanceof Error) {\n\t\treturn value;\n\t}\n\n\tif (isMinimumViableSerializedError(value)) {\n\t\treturn destroyCircular({\n\t\t\tfrom: value,\n\t\t\tseen: [],\n\t\t\tto: newError(value.name),\n\t\t\tmaxDepth,\n\t\t\tdepth: 0,\n\t\t\tserialize: false,\n\t\t} as any);\n\t}\n\n\treturn new NonError(value);\n}\n\nexport function isErrorLike(value: any) {\n\treturn (\n\t\tBoolean(value) &&\n\t\ttypeof value === 'object' &&\n\t\ttypeof value.name === 'string' &&\n\t\ttypeof value.message === 'string' &&\n\t\ttypeof value.stack === 'string'\n\t);\n}\n\n// Used as a weak check for immediately-passed objects, whereas `isErrorLike` is used for nested\n// values to avoid bad detection\nfunction isMinimumViableSerializedError(value: any) {\n\t// @ts-ignore\n\treturn (\n\t\tBoolean(value) &&\n\t\ttypeof value === 'object' &&\n\t\ttypeof value.message === 'string' &&\n\t\t!Array.isArray(value)\n\t);\n}\n","import type { PHPResponseData } from './php-response';\nimport { PHPResponse, StreamedPHPResponse } from './php-response';\nimport * as Comlink from './comlink-sync';\nimport {\n\tNodeSABSyncReceiveMessageTransport,\n\tnodeEndpoint as nodeWorkerEndpoint,\n\treleaseProxy,\n\ttype NodeEndpoint as NodeWorker,\n\ttype Remote,\n\ttype Endpoint,\n\ttype IsomorphicMessagePort,\n\ttype ProxyMethods,\n} from './comlink-sync';\nimport {\n\ttype NodeProcess,\n\tnodeProcessEndpoint,\n} from './comlink-node-process-adapter';\nimport * as ErrorSerializer from './serialize-error';\n\n// NOTE: It seems like we wouldn't have to explicitly specify\n// symbol type here, but it seems to resolve some type errors.\nexport const releaseApiProxy: typeof releaseProxy = releaseProxy;\n\nexport type WithAPIState = {\n\t/**\n\t * Resolves to true when the remote API is ready for\n\t * Comlink communication, but not necessarily fully initialized yet.\n\t */\n\tisConnected: () => Promise<void>;\n\t/**\n\t * Resolves to true when the remote API is declares it's\n\t * fully loaded and ready to be used.\n\t */\n\tisReady: () => Promise<void>;\n};\nexport type RemoteAPI<T> = Remote<T> & ProxyMethods & WithAPIState;\n\nexport async function consumeAPISync<APIType>(\n\tremote: IsomorphicMessagePort\n): Promise<APIType> {\n\tsetupTransferHandlers();\n\tconst transport = await NodeSABSyncReceiveMessageTransport.create();\n\treturn Comlink.wrapSync<APIType>(remote, transport);\n}\n\nexport function consumeAPI<APIType>(\n\tremote: Worker | Window | NodeWorker | NodeProcess,\n\tcontext: undefined | EventTarget = undefined\n): RemoteAPI<APIType> {\n\tsetupTransferHandlers();\n\n\tlet endpoint;\n\t/**\n\t * Previously we assumed we were running in a Node.js environment\n\t * when `import.meta.url` started with `file://`. But this assumption breaks\n\t * with webpack which emits file URLs for `import.meta.url`.\n\t * https://webpack.js.org/api/module-variables/#importmetaurl\n\t * \n\t * We replaced this with a more explicit check for `process.versions.node`.\n\t * See https://github.com/WordPress/wordpress-playground/pull/3248\n\t */\n\tconst appearsToBeNodeEnvironment =\n\t\ttypeof process !== 'undefined' &&\n\t\ttypeof process.versions !== 'undefined' &&\n\t\ttypeof process.versions.node !== 'undefined';\n\tif (appearsToBeNodeEnvironment) {\n\t\tif ('postMessage' in remote) {\n\t\t\tendpoint = nodeWorkerEndpoint(remote as NodeWorker);\n\t\t} else if ('send' in remote && 'addListener' in remote) {\n\t\t\tendpoint = nodeProcessEndpoint(remote as NodeProcess);\n\t\t} else {\n\t\t\tthrow new Error(\n\t\t\t\t'consumeAPI: remote does not look like a Worker, MessagePort, or Process'\n\t\t\t);\n\t\t}\n\t} else {\n\t\tendpoint =\n\t\t\tremote instanceof Worker\n\t\t\t\t? remote\n\t\t\t\t: Comlink.windowEndpoint(remote as Window, context);\n\t}\n\n\t/**\n\t * This shouldn't be necessary, but Comlink doesn't seem to\n\t * handle the initial isConnected() call correctly unless it's\n\t * explicitly provided here. This is especially weird\n\t * since the only thing this proxy does is to call the\n\t * isConnected() method on the remote API.\n\t *\n\t * @TODO: Remove this workaround.\n\t */\n\tconst api = Comlink.wrap<APIType & WithAPIState>(endpoint);\n\tconst methods = proxyClone(api);\n\treturn new Proxy(methods, {\n\t\tget: (target, prop) => {\n\t\t\tif (prop === 'isConnected') {\n\t\t\t\treturn async () => {\n\t\t\t\t\t// Keep retrying until the remote API confirms it's connected.\n\t\t\t\t\twhile (true) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tawait runWithTimeout(api.isConnected(), 200);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t// Timeout exceeded, try again. We can't just use a single\n\t\t\t\t\t\t\t// `runWithTimeout` call because it won't reach the remote API\n\t\t\t\t\t\t\t// if it's not connected yet. Instead, we need to keep retrying\n\t\t\t\t\t\t\t// until the remote API is connected and registers a handler\n\t\t\t\t\t\t\t// for the `isConnected` method.\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn (api as any)[prop];\n\t\t},\n\t}) as unknown as RemoteAPI<APIType>;\n}\n\nasync function runWithTimeout<T>(\n\tpromise: Promise<T>,\n\ttimeout: number\n): Promise<T> {\n\treturn new Promise<T>((resolve, reject) => {\n\t\tsetTimeout(reject, timeout);\n\t\tpromise.then(resolve);\n\t});\n}\n\nexport type PublicAPI<Methods, PipedAPI = unknown> = RemoteAPI<\n\tMethods & PipedAPI\n>;\n\nexport function exposeAPI<Methods, PipedAPI>(\n\tapiMethods?: Methods,\n\tpipedApi?: PipedAPI,\n\ttargetWorker?: MessagePort | NodeWorker | NodeProcess\n): [() => void, (e: Error) => void, PublicAPI<Methods, PipedAPI>] {\n\tconst { setReady, setFailed, exposedApi } = prepareForExpose(\n\t\tapiMethods,\n\t\tpipedApi\n\t);\n\tlet endpoint: Endpoint | undefined;\n\tif (targetWorker) {\n\t\tif ('addEventListener' in targetWorker) {\n\t\t\t// TODO: MessagePort satisfies Endpoint at runtime but its\n\t\t\t// addEventListener overloads don't exactly match EventSource.\n\t\t\tendpoint = targetWorker as Endpoint;\n\t\t} else if ('postMessage' in targetWorker) {\n\t\t\tendpoint = nodeWorkerEndpoint(targetWorker);\n\t\t} else if ('send' in targetWorker && 'addListener' in targetWorker) {\n\t\t\tendpoint = nodeProcessEndpoint(targetWorker);\n\t\t} else {\n\t\t\tthrow new Error(\n\t\t\t\t'exposeAPI: targetWorker does not look like a Worker, MessagePort, or Process'\n\t\t\t);\n\t\t}\n\t} else {\n\t\tendpoint =\n\t\t\ttypeof window !== 'undefined'\n\t\t\t\t? Comlink.windowEndpoint(self.parent)\n\t\t\t\t: undefined;\n\t}\n\tComlink.expose(exposedApi, endpoint);\n\treturn [setReady, setFailed, exposedApi as PublicAPI<Methods, PipedAPI>];\n}\n\nexport async function exposeSyncAPI<Methods>(\n\tapiMethods: Methods,\n\tport: IsomorphicMessagePort\n): Promise<[() => void, (e: Error) => void, Methods]> {\n\tconst { setReady, setFailed, exposedApi } = prepareForExpose(apiMethods);\n\tconst transport = await NodeSABSyncReceiveMessageTransport.create();\n\tconst endpoint = nodeWorkerEndpoint(port as any);\n\tComlink.exposeSync(exposedApi, endpoint, transport);\n\treturn [setReady, setFailed, exposedApi as Methods];\n}\n\nfunction prepareForExpose<Methods, PipedAPI>(\n\tapiMethods?: Methods,\n\tpipedApi?: PipedAPI\n) {\n\tsetupTransferHandlers();\n\n\tconst connected = Promise.resolve();\n\n\tlet setReady: any;\n\tlet setFailed: any;\n\tconst ready = new Promise((resolve, reject) => {\n\t\tsetReady = resolve;\n\t\tsetFailed = reject;\n\t});\n\n\tconst methods = proxyClone(apiMethods);\n\tconst exposedApi = new Proxy(methods, {\n\t\tget: (target, prop) => {\n\t\t\tif (prop === 'isConnected') {\n\t\t\t\treturn () => connected;\n\t\t\t} else if (prop === 'isReady') {\n\t\t\t\treturn () => ready;\n\t\t\t} else if (prop in target) {\n\t\t\t\treturn target[prop];\n\t\t\t}\n\t\t\treturn (pipedApi as any)?.[prop];\n\t\t},\n\t}) as unknown as PublicAPI<Methods, PipedAPI>;\n\n\treturn { setReady, setFailed, exposedApi };\n}\n\nlet isTransferHandlersSetup = false;\nfunction setupTransferHandlers() {\n\tif (isTransferHandlersSetup) {\n\t\treturn;\n\t}\n\tisTransferHandlersSetup = true;\n\tComlink.transferHandlers.set('EVENT', {\n\t\tcanHandle: (obj): obj is CustomEvent => obj instanceof CustomEvent,\n\t\tserialize: (ev: CustomEvent) => {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tdetail: ev.detail,\n\t\t\t\t},\n\t\t\t\t[],\n\t\t\t];\n\t\t},\n\t\tdeserialize: (obj) => obj,\n\t});\n\tComlink.transferHandlers.set('FUNCTION', {\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n\t\tcanHandle: (obj: unknown): obj is Function => typeof obj === 'function',\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n\t\tserialize(obj: Function) {\n\t\t\tconst { port1, port2 } = new MessageChannel();\n\t\t\tComlink.expose(obj, port1);\n\t\t\treturn [port2, [port2]];\n\t\t},\n\t\tdeserialize(port: any) {\n\t\t\tport.start();\n\t\t\treturn Comlink.wrap(port);\n\t\t},\n\t});\n\tComlink.transferHandlers.set('MESSAGE_PORT', {\n\t\tcanHandle: (obj: unknown): obj is MessagePort =>\n\t\t\tobj instanceof MessagePort,\n\t\tserialize(port: MessagePort): [MessagePort, Transferable[]] {\n\t\t\treturn [port, [port]];\n\t\t},\n\t\tdeserialize(port: MessagePort): MessagePort {\n\t\t\treturn port;\n\t\t},\n\t});\n\tComlink.transferHandlers.set('PHPResponse', {\n\t\tcanHandle: (obj: unknown): obj is PHPResponseData =>\n\t\t\ttypeof obj === 'object' &&\n\t\t\tobj !== null &&\n\t\t\t'headers' in obj &&\n\t\t\t'bytes' in obj &&\n\t\t\t'errors' in obj &&\n\t\t\t'exitCode' in obj &&\n\t\t\t'httpStatusCode' in obj,\n\t\tserialize(obj: PHPResponse): [PHPResponseData, Transferable[]] {\n\t\t\tconst data = obj.toRawData();\n\t\t\t// Transfer the ArrayBuffer instead of cloning it to avoid\n\t\t\t// \"could not be cloned\" errors when the buffer is detached\n\t\t\tconst transferables: Transferable[] = [];\n\t\t\tif (data.bytes.buffer.byteLength > 0) {\n\t\t\t\ttransferables.push(data.bytes.buffer);\n\t\t\t}\n\t\t\treturn [data, transferables];\n\t\t},\n\t\tdeserialize(responseData: PHPResponseData): PHPResponse {\n\t\t\treturn PHPResponse.fromRawData(responseData);\n\t\t},\n\t});\n\t// Augment Comlink's throw handler to include Error the response and source\n\t// information in the serialized error object. BasePHP may throw\n\t// PHPExecutionFailureError which includes those information and we'll want to\n\t// display them for the user.\n\tconst throwHandler = Comlink.transferHandlers.get('throw')!;\n\tconst originalSerialize = throwHandler?.serialize;\n\tthrowHandler.serialize = ({ value }: any) => {\n\t\tconst serialized = originalSerialize({ value }) as any;\n\t\tif (value.response) {\n\t\t\tserialized[0].value.response = value.response;\n\t\t}\n\t\tif (value.source) {\n\t\t\tserialized[0].value.source = value.source;\n\t\t}\n\t\treturn serialized;\n\t};\n\n\tComlink.transferHandlers.set('StreamedPHPResponse', {\n\t\tcanHandle: (obj: unknown): obj is StreamedPHPResponse =>\n\t\t\tobj instanceof StreamedPHPResponse,\n\t\tserialize(obj: StreamedPHPResponse): [any, Transferable[]] {\n\t\t\tconst supportsStreams = supportsTransferableStreams();\n\t\t\tconst exitCodePort = promiseToPort(obj.exitCode);\n\t\t\tconst headersStream = obj.getHeadersStream();\n\t\t\tif (supportsStreams) {\n\t\t\t\tconst payload = {\n\t\t\t\t\t__type: 'StreamedPHPResponse',\n\t\t\t\t\theaders: headersStream,\n\t\t\t\t\tstdout: obj.stdout,\n\t\t\t\t\tstderr: obj.stderr,\n\t\t\t\t\texitCodePort,\n\t\t\t\t};\n\t\t\t\t// ReadableStreams must be explicitly transferred\n\t\t\t\treturn [\n\t\t\t\t\tpayload,\n\t\t\t\t\t[\n\t\t\t\t\t\theadersStream as unknown as Transferable,\n\t\t\t\t\t\tobj.stdout as unknown as Transferable,\n\t\t\t\t\t\tobj.stderr as unknown as Transferable,\n\t\t\t\t\t\texitCodePort,\n\t\t\t\t\t],\n\t\t\t\t];\n\t\t\t}\n\t\t\t// Fallback: bridge streams via MessagePorts\n\t\t\tconst headersPort = streamToPort(headersStream);\n\t\t\tconst stdoutPort = streamToPort(obj.stdout);\n\t\t\tconst stderrPort = streamToPort(obj.stderr);\n\t\t\tconst payload = {\n\t\t\t\t__type: 'StreamedPHPResponse',\n\t\t\t\theadersPort,\n\t\t\t\tstdoutPort,\n\t\t\t\tstderrPort,\n\t\t\t\texitCodePort,\n\t\t\t};\n\t\t\treturn [\n\t\t\t\tpayload,\n\t\t\t\t[headersPort, stdoutPort, stderrPort, exitCodePort],\n\t\t\t];\n\t\t},\n\t\tdeserialize(data: any): StreamedPHPResponse {\n\t\t\tif (data.headers && data.stdout && data.stderr) {\n\t\t\t\tconst exitCode = portToPromise(\n\t\t\t\t\tdata.exitCodePort as MessagePort\n\t\t\t\t);\n\t\t\t\treturn new StreamedPHPResponse(\n\t\t\t\t\tdata.headers as ReadableStream<Uint8Array>,\n\t\t\t\t\tdata.stdout as ReadableStream<Uint8Array>,\n\t\t\t\t\tdata.stderr as ReadableStream<Uint8Array>,\n\t\t\t\t\texitCode\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst headers = portToStream(data.headersPort as MessagePort);\n\t\t\tconst stdout = portToStream(data.stdoutPort as MessagePort);\n\t\t\tconst stderr = portToStream(data.stderrPort as MessagePort);\n\t\t\tconst exitCode = portToPromise(data.exitCodePort as MessagePort);\n\t\t\treturn new StreamedPHPResponse(headers, stdout, stderr, exitCode);\n\t\t},\n\t});\n}\n\n// Utilities for transferring ReadableStreams and Promises via MessagePorts:\n\n/**\n * Safari does not support transferable streams, so we need to fallback to\n * MessagePorts.\n * Feature-detects whether this runtime supports transferring ReadableStreams\n * directly through postMessage (aka \"transferable streams\"). When false,\n * we must fall back to port-bridged streaming.\n */\nfunction supportsTransferableStreams(): boolean {\n\ttry {\n\t\tif (typeof ReadableStream === 'undefined') return false;\n\t\tconst { port1 } = new MessageChannel();\n\t\tconst rs = new ReadableStream();\n\t\tport1.postMessage(rs as any);\n\t\ttry {\n\t\t\tport1.close();\n\t\t} catch (_e) {\n\t\t\tvoid _e;\n\t\t}\n\t\treturn true;\n\t} catch (_e) {\n\t\tvoid _e;\n\t\treturn false;\n\t}\n}\n\n/**\n * Bridges a ReadableStream to a MessagePort by reading chunks and posting\n * messages to the port. Used as a fallback when transferable streams are not\n * supported (e.g., Safari).\n *\n * Protocol of the returned MessagePort:\n *\n * { t: 'chunk', b: ArrayBuffer } – next binary chunk\n * { t: 'close' } – end of stream\n * { t: 'error', m: string } – terminal error\n */\nfunction streamToPort(stream: ReadableStream<Uint8Array>): MessagePort {\n\tconst { port1, port2 } = new MessageChannel();\n\t(async () => {\n\t\tconst reader = stream.getReader();\n\t\ttry {\n\t\t\twhile (true) {\n\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\tif (done) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tport1.postMessage({ t: 'close' });\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Ignore error\n\t\t\t\t\t}\n\t\t\t\t\ttry {\n\t\t\t\t\t\tport1.close();\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Ignore error\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif (value) {\n\t\t\t\t\t// Ensure we transfer an owned buffer\n\t\t\t\t\tconst owned =\n\t\t\t\t\t\tvalue.byteOffset === 0 &&\n\t\t\t\t\t\tvalue.byteLength === value.buffer.byteLength\n\t\t\t\t\t\t\t? value\n\t\t\t\t\t\t\t: value.slice();\n\t\t\t\t\tconst buf = owned.buffer;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tport1.postMessage({ t: 'chunk', b: buf }, [\n\t\t\t\t\t\t\tbuf as unknown as Transferable,\n\t\t\t\t\t\t]);\n\t\t\t\t\t} catch {\n\t\t\t\t\t\tport1.postMessage({\n\t\t\t\t\t\t\tt: 'chunk',\n\t\t\t\t\t\t\tb: owned.buffer.slice(0),\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (e: any) {\n\t\t\ttry {\n\t\t\t\tport1.postMessage({ t: 'error', m: e?.message || String(e) });\n\t\t\t} catch {\n\t\t\t\t// Ignore error\n\t\t\t}\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tport1.close();\n\t\t\t} catch {\n\t\t\t\t// Ignore error\n\t\t\t}\n\t\t}\n\t})();\n\treturn port2;\n}\n\n/**\n * Reconstructs a ReadableStream from a MessagePort using the inverse of the\n * streamToPort protocol. Each message enqueues data, closes, or errors.\n */\nfunction portToStream(port: MessagePort): ReadableStream<Uint8Array> {\n\treturn new ReadableStream<Uint8Array>({\n\t\tstart(controller) {\n\t\t\tconst onMessage = (ev: MessageEvent) => {\n\t\t\t\tconst data: any = (ev as any).data;\n\t\t\t\tif (!data) return;\n\t\t\t\tswitch (data.t) {\n\t\t\t\t\tcase 'chunk':\n\t\t\t\t\t\tcontroller.enqueue(new Uint8Array(data.b));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'close':\n\t\t\t\t\t\tcontroller.close();\n\t\t\t\t\t\tcleanup();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'error':\n\t\t\t\t\t\tcontroller.error(new Error(data.m || 'Stream error'));\n\t\t\t\t\t\tcleanup();\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t};\n\t\t\tconst cleanup = () => {\n\t\t\t\ttry {\n\t\t\t\t\tport.removeEventListener?.('message', onMessage as any);\n\t\t\t\t} catch {\n\t\t\t\t\t// Ignore error\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tport.onmessage = null;\n\t\t\t\t} catch {\n\t\t\t\t\t// Ignore error\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tport.close();\n\t\t\t\t} catch {\n\t\t\t\t\t// Ignore error\n\t\t\t\t}\n\t\t\t};\n\t\t\tif (port.addEventListener) {\n\t\t\t\tport.addEventListener('message', onMessage as any);\n\t\t\t} else if ((port as any).on) {\n\t\t\t\t(port as any).on('message', (data: any) =>\n\t\t\t\t\tonMessage({ data } as any)\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tport.onmessage = onMessage as any;\n\t\t\t}\n\t\t\tif (typeof port.start === 'function') {\n\t\t\t\tport.start();\n\t\t\t}\n\t\t},\n\t\tcancel() {\n\t\t\ttry {\n\t\t\t\tport.close();\n\t\t\t} catch {\n\t\t\t\t// Ignore error\n\t\t\t}\n\t\t},\n\t});\n}\n\n/**\n * Bridges a Promise to a MessagePort so it can be delivered across threads.\n *\n * Protocol of the returned MessagePort:\n *\n * { t: 'resolve', v: any } – promise resolved with value v\n * { t: 'reject', m: str } – promise rejected with message m\n */\nfunction promiseToPort(promise: Promise<any>): MessagePort {\n\tconst { port1, port2 } = new MessageChannel();\n\tpromise\n\t\t.then((value) => {\n\t\t\ttry {\n\t\t\t\tport1.postMessage({ t: 'resolve', v: value });\n\t\t\t} catch {\n\t\t\t\t// Ignore error\n\t\t\t}\n\t\t})\n\t\t.catch((err) => {\n\t\t\ttry {\n\t\t\t\tport1.postMessage({\n\t\t\t\t\tt: 'reject',\n\t\t\t\t\tm: (err as any)?.message || String(err),\n\t\t\t\t});\n\t\t\t} catch {\n\t\t\t\t// Ignore error\n\t\t\t}\n\t\t})\n\t\t.finally(() => {\n\t\t\ttry {\n\t\t\t\tport1.close();\n\t\t\t} catch {\n\t\t\t\t// Ignore error\n\t\t\t}\n\t\t});\n\treturn port2;\n}\n\n/**\n * Reconstructs a Promise from a MessagePort using the inverse of\n * promiseToPort. Resolves or rejects when the corresponding message arrives.\n */\nfunction portToPromise(port: MessagePort): Promise<any> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst onMessage = (ev: MessageEvent) => {\n\t\t\tconst data: any = (ev as any).data;\n\t\t\tif (!data) return;\n\t\t\tif (data.t === 'resolve') {\n\t\t\t\tcleanup();\n\t\t\t\tresolve(data.v);\n\t\t\t} else if (data.t === 'reject') {\n\t\t\t\tcleanup();\n\t\t\t\treject(new Error(data.m || ''));\n\t\t\t}\n\t\t};\n\t\tconst cleanup = () => {\n\t\t\ttry {\n\t\t\t\tport.removeEventListener?.('message', onMessage as any);\n\t\t\t} catch {\n\t\t\t\t// Ignore error\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tport.onmessage = null;\n\t\t\t} catch {\n\t\t\t\t// Ignore error\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tport.close();\n\t\t\t} catch {\n\t\t\t\t// Ignore error\n\t\t\t}\n\t\t};\n\t\tif (port.addEventListener) {\n\t\t\tport.addEventListener('message', onMessage as any);\n\t\t} else if ((port as any).on) {\n\t\t\t(port as any).on('message', (data: any) =>\n\t\t\t\tonMessage({ data } as any)\n\t\t\t);\n\t\t} else {\n\t\t\tport.onmessage = onMessage as any;\n\t\t}\n\t\tif (typeof port.start === 'function') {\n\t\t\tport.start();\n\t\t}\n\t});\n}\n\n// Augment Comlink's throw handler to include all the information carried by\n// the thrown object, including the cause, additional properties, etc.\ninterface UnserializedError {\n\tvalue: unknown;\n}\ntype SerializedError =\n\t| { isError: true; value: ErrorSerializer.ErrorObject }\n\t| { isError: false; value: unknown };\n\nconst throwTransferHandler = Comlink.transferHandlers.get(\n\t'throw'\n) as Comlink.TransferHandler<UnserializedError, SerializedError>;\n\nconst throwTransferHandlerCustom: Comlink.TransferHandler<\n\tUnserializedError,\n\tSerializedError\n> = {\n\tcanHandle: throwTransferHandler.canHandle,\n\tserialize: ({ value }) => {\n\t\tlet serialized: SerializedError;\n\t\tif (value instanceof Error) {\n\t\t\tserialized = {\n\t\t\t\tisError: true,\n\t\t\t\tvalue: ErrorSerializer.serializeError(value),\n\t\t\t};\n\t\t\t// The error class name is not serialized by serialize-error, let's add it manually.\n\t\t\tserialized.value['originalErrorClassName'] = value.constructor.name;\n\t\t} else {\n\t\t\tserialized = { isError: false, value };\n\t\t}\n\t\treturn [serialized, []];\n\t},\n\tdeserialize: (serialized) => {\n\t\tif (serialized.isError) {\n\t\t\tconst error = ErrorSerializer.deserializeError(serialized.value);\n\t\t\t/**\n\t\t\t * The original error from the web worker does not include any call\n\t\t\t * stack from the Playground web app. Let's include that information\n\t\t\t * in the error chain.\n\t\t\t *\n\t\t\t * We'll place it at the bottom of the error chain. This way the API\n\t\t\t * consumer gets the original error object and not an opaque\n\t\t\t * \"Comlink method call failed\" error, but they can still inspect\n\t\t\t * it further to see the full call stack.\n\t\t\t */\n\t\t\tconst additionalCallStack = new Error('Comlink method call failed');\n\t\t\tlet deepestError = error;\n\t\t\twhile (deepestError.cause) {\n\t\t\t\tdeepestError = deepestError.cause;\n\t\t\t}\n\t\t\tdeepestError.cause = additionalCallStack;\n\t\t\tthrow error;\n\t\t}\n\t\tthrow serialized.value;\n\t},\n};\n\nComlink.transferHandlers.set('throw', throwTransferHandlerCustom);\n\nfunction proxyClone(object: any): any {\n\treturn new Proxy(object, {\n\t\tget(target, prop) {\n\t\t\tswitch (typeof target[prop]) {\n\t\t\t\tcase 'function':\n\t\t\t\t\treturn (...args: any[]) => target[prop](...args);\n\t\t\t\tcase 'object':\n\t\t\t\t\tif (target[prop] === null) {\n\t\t\t\t\t\treturn target[prop];\n\t\t\t\t\t}\n\t\t\t\t\treturn proxyClone(target[prop]);\n\t\t\t\tcase 'undefined':\n\t\t\t\tcase 'number':\n\t\t\t\tcase 'string':\n\t\t\t\t\treturn target[prop];\n\t\t\t\tdefault:\n\t\t\t\t\treturn Comlink.proxy(target[prop]);\n\t\t\t}\n\t\t},\n\t});\n}\n","export const MAX_ADDRESSABLE_FILE_OFFSET = BigInt(Number.MAX_SAFE_INTEGER);\n// TODO: Use this BigInt once the native fs-ext-extra-prebuilt package supports it.\n//BigInt(2n ** 64n - 1n);\n\n/*\n * NOTE: These types are not important structurally,\n * but it helps clarity to use these aliases when making\n * data structures based on them.\n *\n * For example, the type\n * `Map<Path, Map<Pid, Map<Fd, WholeFileLockOp>>>`\n * conveys more intention to a reader than\n * `Map<string, Map<number, Map<number, WholeFileLockOp>>>`.\n */\nexport type Path = string;\nexport type Pid = number;\nexport type Fd = number;\n\n/**\n * This is an interface used to abstract byte range locking like fcntl()\n * and whole-file locking like flock().\n */\nexport type FileLockManager = {\n\t/**\n\t * Update the lock on the whole file.\n\t *\n\t * This method is for updating the lock on the whole file with the F_SETLKW fcntl() command.\n\t * https://sourceware.org/glibc/manual/2.41/html_node/File-Locks.html#index-F_005fSETLKW-1\n\t *\n\t * @param path - The path of the file to lock. This should be the path of the file in the\n\t * underlying filesystem.\n\t * @param op - The operation to perform, including 'shared', 'exclusive', or 'unlock'.\n\t * @returns A promise for a boolean value.\n\t */\n\tlockWholeFile: (path: Path, op: WholeFileLockOp) => boolean;\n\n\t/**\n\t * Update the lock on a byte range of a file.\n\t *\n\t * This method is for locking with the F_SETLK fcntl() command.\n\t * https://sourceware.org/glibc/manual/2.41/html_node/File-Locks.html#index-F_005fSETLK-1\n\t *\n\t * @param path - The path of the file to lock. This should be the path of the file in the\n\t * underlying filesystem.\n\t * @param requestedLock - The lock to request, including start, end, type, and pid.\n\t * @param waitForLock - Whether to block until the lock is acquired.\n\t * @returns A promise for a boolean value.\n\t * When locking: True if the lock was acquired, false if it was not.\n\t * When unlocking: Always true.\n\t */\n\tlockFileByteRange: (\n\t\tpath: Path,\n\t\trequestedLock: RequestedRangeLock,\n\t\twaitForLock: boolean\n\t) => boolean;\n\n\t/**\n\t * Get the first lock that would conflict with the specified lock.\n\t *\n\t * This method is meant to satisfy the needs of the F_GETLK fcntl() command.\n\t * https://sourceware.org/glibc/manual/2.41/html_node/File-Locks.html#index-F_005fGETLK-1\n\t *\n\t * @param path - The path of the file to check for conflicts. This should be the path\n\t * of the file in the underlying filesystem.\n\t * @param desiredLock - The lock to check for conflicts.\n\t * @returns A promise for the first conflicting lock,\n\t * or undefined if there is no conflict.\n\t */\n\tfindFirstConflictingByteRangeLock: (\n\t\tpath: Path,\n\t\tdesiredLock: RequestedRangeLock\n\t) => Omit<RequestedRangeLock, 'fd'> | undefined;\n\n\t/**\n\t * Release all locks for a given process.\n\t *\n\t * Used when a process exits or is otherwise terminated.\n\t *\n\t * @param pid - The PID of the process that wants to release the locks.\n\t */\n\treleaseLocksForProcess: (pid: number) => void;\n\n\t/**\n\t * Release all locks for the given process and file descriptor.\n\t *\n\t * @param pid The process ID to release locks for.\n\t * @param fd The file descriptor to release locks for.\n\t * @param path The path to the file to release locks for. This should be the path\n\t * of the file in the underlying filesystem.\n\t */\n\treleaseLocksOnFdClose: (pid: number, fd: number, path: Path) => void;\n};\n\nexport type ByteRange = {\n\tstart: bigint;\n\t// TODO: How to support special treatment of Infinity?\n\tend: bigint;\n};\n\nexport type RequestedRangeLock = ByteRange & {\n\t/**\n\t * The type of lock request\n\t */\n\ttype: 'shared' | 'exclusive' | 'unlocked';\n\t/**\n\t * The file descriptor to use. This should be the native file descriptor,\n\t * not the Emscripten file descriptor because it may be used to lock the file\n\t * using native OS file locking APIs.\n\t */\n\tfd: Fd;\n\t/** The process ID that owns this lock */\n\tpid: Pid;\n};\n\nexport type LockedRange = RequestedRangeLock & {\n\ttype: Exclude<RequestedRangeLock['type'], 'unlocked'>;\n};\n\nexport type ConflictingLockedRange = Omit<LockedRange, 'fd'>;\n\nexport type WholeFileLock = Readonly<\n\tWholeFileLock_Exclusive | WholeFileLock_Shared | WholeFileLock_Unlocked\n>;\n\nexport type WholeFileLock_Exclusive = {\n\ttype: 'exclusive';\n\tpid: Pid;\n\tfd: Fd;\n};\nexport type WholeFileLock_Shared = {\n\ttype: 'shared';\n\t/**\n\t * NOTE: flock() locks are associated with open file descriptors and duplicated file descriptors.\n\t * We do not currently recognize duplicate file descriptors.\n\t */\n\tpidFds: Map<Pid, Set<Fd>>;\n};\nexport type WholeFileLock_Unlocked = {\n\ttype: 'unlocked';\n};\n\nexport type WholeFileLockOp =\n\t| {\n\t\t\tpid: number;\n\t\t\tfd: number;\n\t\t\ttype: 'shared' | 'exclusive';\n\t\t\t/** Whether to block until the lock is acquired. */\n\t\t\twaitForLock: boolean;\n\t }\n\t| {\n\t\t\tpid: number;\n\t\t\tfd: number;\n\t\t\ttype: 'unlock';\n\t };\n","import type {\n\tByteRange,\n\tLockedRange,\n\tRequestedRangeLock,\n} from './file-lock-manager';\n\nclass IntervalNode {\n\trange: LockedRange;\n\tmax: bigint;\n\tleft: IntervalNode | null = null;\n\tright: IntervalNode | null = null;\n\n\tconstructor(range: LockedRange) {\n\t\tthis.range = range;\n\t\tthis.max = range.end;\n\t}\n}\n\nexport class FileLockIntervalTree {\n\tprivate root: IntervalNode | null = null;\n\n\tisEmpty() {\n\t\treturn this.root === null;\n\t}\n\n\t/**\n\t * Insert a new locked range into the tree\n\t */\n\tinsert(range: LockedRange): void {\n\t\tthis.root = this.insertNode(this.root, range);\n\t}\n\n\t/**\n\t * Find all ranges that overlap with the given range\n\t */\n\tfindOverlapping(range: ByteRange): LockedRange[] {\n\t\tconst result: LockedRange[] = [];\n\t\tthis.findOverlappingRanges(this.root, range, result);\n\t\treturn result;\n\t}\n\n\t/**\n\t * Remove a lock range from the tree\n\t */\n\tremove(range: RequestedRangeLock): void {\n\t\tthis.root = this.removeNode(this.root, range);\n\t}\n\n\t/**\n\t * Find all ranges locked by the given process.\n\t *\n\t * @param pid The process ID to find locks for.\n\t * @returns All locked ranges for the given process.\n\t */\n\tfindLocksForProcess(pid: number): RequestedRangeLock[] {\n\t\tconst result: RequestedRangeLock[] = [];\n\t\tthis.findLocksForProcessInNode(this.root, pid, result);\n\t\treturn result;\n\t}\n\n\t/**\n\t * Find the strictest existing lock type in the range lock tree.\n\t *\n\t * @returns The strictest existing lock type, or 'unlocked' if no locks exist.\n\t */\n\tfindStrictestExistingLockType(): RequestedRangeLock['type'] {\n\t\tlet maxType: RequestedRangeLock['type'] = 'unlocked';\n\n\t\tconst traverse = (node: IntervalNode | null) => {\n\t\t\tif (!node) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (node.range.type === 'exclusive') {\n\t\t\t\tmaxType = 'exclusive';\n\t\t\t\treturn; // Can stop early since exclusive is highest\n\t\t\t}\n\t\t\tif (node.range.type === 'shared') {\n\t\t\t\tmaxType = 'shared';\n\t\t\t}\n\t\t\ttraverse(node.left);\n\t\t\ttraverse(node.right);\n\t\t};\n\t\ttraverse(this.root);\n\n\t\treturn maxType;\n\t}\n\n\tprivate insertNode(\n\t\tnode: IntervalNode | null,\n\t\trange: LockedRange\n\t): IntervalNode {\n\t\tif (!node) {\n\t\t\treturn new IntervalNode(range);\n\t\t}\n\n\t\t// Insert to left subtree if start is less than node's start\n\t\tif (range.start < node.range.start) {\n\t\t\tnode.left = this.insertNode(node.left, range);\n\t\t} else {\n\t\t\tnode.right = this.insertNode(node.right, range);\n\t\t}\n\n\t\t// Update max value\n\t\tnode.max = this.bigintMax(node.max, range.end);\n\t\treturn node;\n\t}\n\n\tprivate bigintMax(...args: bigint[]): bigint {\n\t\treturn args.reduce((max, current) => {\n\t\t\treturn current > max ? current : max;\n\t\t}, args[0]);\n\t}\n\n\tprivate findOverlappingRanges(\n\t\tnode: IntervalNode | null,\n\t\trange: ByteRange,\n\t\tresult: LockedRange[]\n\t): void {\n\t\tif (!node) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Check if current node overlaps\n\t\tif (this.doRangesOverlap(node.range, range)) {\n\t\t\tresult.push(node.range);\n\t\t}\n\n\t\t// If left child exists and its max is greater than range start, search left\n\t\tif (node.left && node.left.max >= range.start) {\n\t\t\tthis.findOverlappingRanges(node.left, range, result);\n\t\t}\n\n\t\t// Search right if it could contain overlapping intervals\n\t\tif (node.right && node.range.start <= range.end) {\n\t\t\tthis.findOverlappingRanges(node.right, range, result);\n\t\t}\n\t}\n\n\tprivate doRangesOverlap(a: ByteRange, b: ByteRange): boolean {\n\t\treturn a.start < b.end && b.start < a.end;\n\t}\n\n\tprivate removeNode(\n\t\tnode: IntervalNode | null,\n\t\trange: RequestedRangeLock\n\t): IntervalNode | null {\n\t\tif (!node) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Check if current node is the one to remove\n\t\tif (this.areRangesEqual(node.range, range)) {\n\t\t\t// Handle cases of no children or one child\n\t\t\tif (!node.left) {\n\t\t\t\treturn node.right;\n\t\t\t}\n\t\t\tif (!node.right) {\n\t\t\t\treturn node.left;\n\t\t\t}\n\n\t\t\t// Node has two children - find successor\n\t\t\tconst successor = this.findMin(node.right);\n\t\t\tnode.range = successor.range;\n\t\t\tnode.right = this.removeNode(node.right, successor.range);\n\t\t} else if (range.start < node.range.start) {\n\t\t\tnode.left = this.removeNode(node.left, range);\n\t\t} else {\n\t\t\tnode.right = this.removeNode(node.right, range);\n\t\t}\n\n\t\t// Update max value\n\t\tnode.max = node.range.end;\n\t\tif (node.left) {\n\t\t\tnode.max = this.bigintMax(node.max, node.left.max);\n\t\t}\n\t\tif (node.right) {\n\t\t\tnode.max = this.bigintMax(node.max, node.right.max);\n\t\t}\n\n\t\treturn node;\n\t}\n\n\tprivate findMin(node: IntervalNode): IntervalNode {\n\t\tlet current = node;\n\t\twhile (current.left) {\n\t\t\tcurrent = current.left;\n\t\t}\n\t\treturn current;\n\t}\n\n\tprivate areRangesEqual(\n\t\ta: RequestedRangeLock,\n\t\tb: RequestedRangeLock\n\t): boolean {\n\t\treturn (\n\t\t\ta.start === b.start &&\n\t\t\ta.end === b.end &&\n\t\t\ta.pid === b.pid &&\n\t\t\ta.fd === b.fd\n\t\t);\n\t}\n\n\tprivate findLocksForProcessInNode(\n\t\tnode: IntervalNode | null,\n\t\tpid: number,\n\t\tresult: RequestedRangeLock[]\n\t): void {\n\t\tif (!node) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (node.range.pid === pid) {\n\t\t\tresult.push(node.range);\n\t\t}\n\n\t\tthis.findLocksForProcessInNode(node.left, pid, result);\n\t\tthis.findLocksForProcessInNode(node.right, pid, result);\n\t}\n}\n","import type {\n\tFileLockManager,\n\tRequestedRangeLock,\n\tWholeFileLock,\n\tWholeFileLockOp,\n\tPid,\n\tFd,\n} from './file-lock-manager';\nimport {\n\tMAX_ADDRESSABLE_FILE_OFFSET,\n\ttype LockedRange,\n} from './file-lock-manager';\nimport { FileLockIntervalTree } from './file-lock-interval-tree';\n\n/**\n * This is the file lock manager for use within JS runtimes like Node.js.\n *\n * A FileLockManagerInMemory is a wrapper around a Map of FileLock instances.\n * It provides methods for locking and unlocking files, as well as finding conflicting locks.\n */\nexport class FileLockManagerInMemory implements FileLockManager {\n\tlocks: Map<string, FileLock>;\n\n\t/**\n\t * Create a new FileLockManagerInMemory instance.\n\t *\n\t * @param nativeFlockSync A synchronous flock() function to lock files via the host OS.\n\t */\n\tconstructor() {\n\t\tthis.locks = new Map();\n\t}\n\n\t/**\n\t * Lock the whole file.\n\t *\n\t * @param path The path to the file to lock. This should be the path\n\t * of the file in the native filesystem.\n\t * @param op The whole file lock operation to perform.\n\t * @returns True if the lock was granted, false otherwise.\n\t */\n\tlockWholeFile(\n\t\tpath: string,\n\t\t/**\n\t\t * NOTE: FileLockManagerInMemory does not support waiting for a lock\n\t\t * because it is intended to be used with a native file lock manager\n\t\t * which does support waiting.\n\t\t */\n\t\top: Omit<WholeFileLockOp, 'waitForLock'>\n\t): boolean {\n\t\tif (this.locks.get(path) === undefined) {\n\t\t\tif (op.type === 'unlock') {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tthis.locks.set(path, new FileLock());\n\t\t}\n\n\t\tconst lock = this.locks.get(path)!;\n\t\tconst result = lock.lockWholeFile(op);\n\t\tthis.forgetPathIfUnlocked(path);\n\t\treturn result;\n\t}\n\n\t/**\n\t * Lock a byte range.\n\t *\n\t * @param path The path to the file to lock. This should be the path\n\t * of the file in the native filesystem.\n\t * @param requestedLock The byte range lock to perform.\n\t * @returns True if the lock was granted, false otherwise.\n\t */\n\tlockFileByteRange(\n\t\tpath: string,\n\t\t/**\n\t\t * NOTE: fcntl()-style F_SETLK/F_GETLK do not associate\n\t\t * resulting locks with a file descrtiptor, so we ignore fd here.\n\t\t */\n\t\trequestedLock: Omit<RequestedRangeLock, 'fd'>\n\t\t/**\n\t\t * NOTE: FileLockManagerInMemory does not support waiting for a lock\n\t\t * because it is intended to be used with a native file lock manager\n\t\t * which does support waiting.\n\t\t */\n\t\t// waitForLock: boolean,\n\t): boolean {\n\t\tif (!this.locks.has(path)) {\n\t\t\tif (requestedLock.type === 'unlocked') {\n\t\t\t\t// There is no existing lock. This is a no-op.\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tthis.locks.set(path, new FileLock());\n\t\t}\n\t\tconst lock = this.locks.get(path)!;\n\t\treturn lock.lockFileByteRange(requestedLock);\n\t}\n\n\t/**\n\t * Find the first conflicting byte range lock.\n\t *\n\t * @param path The path to the file to find the conflicting lock for.\n\t * @param desiredLock The desired byte range lock.\n\t * @returns The first conflicting byte range lock, or undefined if no conflicting lock exists.\n\t */\n\tfindFirstConflictingByteRangeLock(\n\t\tpath: string,\n\t\t/**\n\t\t * NOTE: fcntl()-style F_SETLK/F_GETLK do not associate\n\t\t * resulting locks with a file descrtiptor, so we ignore fd here.\n\t\t */\n\t\tdesiredLock: Omit<RequestedRangeLock, 'fd'>\n\t): Omit<RequestedRangeLock, 'fd'> | undefined {\n\t\tconst lock = this.locks.get(path);\n\t\tif (lock === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn lock.findFirstConflictingByteRangeLock(desiredLock);\n\t}\n\n\t/**\n\t * Release all locks for the given process.\n\t *\n\t * @param pid The process ID to release locks for.\n\t */\n\treleaseLocksForProcess(pid: number) {\n\t\t//logger.log('releaseLocksForProcess', pid);\n\t\tfor (const [path, lock] of this.locks.entries()) {\n\t\t\tlock.releaseLocksForProcess(pid);\n\t\t\tthis.forgetPathIfUnlocked(path);\n\t\t}\n\t}\n\n\t/**\n\t * Release all locks for the given process and file descriptor.\n\t *\n\t * @param pid The process ID to release locks for.\n\t * @param fd The file descriptor to release locks for.\n\t * @param path The path to the file to release locks for.\n\t */\n\treleaseLocksOnFdClose(pid: number, fd: number, nativePath: string) {\n\t\tconst lock = this.locks.get(nativePath);\n\t\tif (!lock) {\n\t\t\treturn;\n\t\t}\n\t\tlock.releaseLocksOnFdClose(pid, fd);\n\t\tthis.forgetPathIfUnlocked(nativePath);\n\t}\n\n\t/**\n\t * Forget the path if it is unlocked.\n\t *\n\t * @param path The path to the file to forget.\n\t */\n\tprivate forgetPathIfUnlocked(path: string) {\n\t\tconst lock = this.locks.get(path);\n\t\tif (!lock) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (lock.isUnlocked()) {\n\t\t\tthis.locks.delete(path);\n\t\t}\n\t}\n}\n\n/**\n * A FileLock instance encapsulates a native whole-file lock and file locking between\n * php-wasm processes.\n *\n * A FileLock supports php-wasm whole-file locks and byte range locks.\n * Before granting a php-wasm lock, a FileLock ensures that it first holds a compatible\n * native lock. If a compatible native lock cannot be acquired, the php-wasm lock is\n * not granted.\n */\nexport class FileLock {\n\tprivate wholeFileLock: WholeFileLock;\n\tprivate rangeLocks: FileLockIntervalTree;\n\n\tconstructor() {\n\t\tthis.rangeLocks = new FileLockIntervalTree();\n\t\tthis.wholeFileLock = { type: 'unlocked' };\n\t}\n\n\t/**\n\t * Lock the whole file.\n\t *\n\t * This method corresponds to the flock() function.\n\t *\n\t * @param op The whole file lock operation to perform.\n\t * @returns True if the lock was granted, false otherwise.\n\t */\n\tlockWholeFile(op: Omit<WholeFileLockOp, 'waitForLock'>): boolean {\n\t\tif (op.type === 'unlock') {\n\t\t\tconst originalType = this.wholeFileLock.type;\n\t\t\tif (originalType === 'unlocked') {\n\t\t\t\t// Do nothing because the whole file is already unlocked.\n\t\t\t} else if (\n\t\t\t\tthis.wholeFileLock.type === 'exclusive' &&\n\t\t\t\tthis.wholeFileLock.pid === op.pid &&\n\t\t\t\tthis.wholeFileLock.fd === op.fd\n\t\t\t) {\n\t\t\t\tthis.wholeFileLock = { type: 'unlocked' };\n\t\t\t} else if (\n\t\t\t\tthis.wholeFileLock.type === 'shared' &&\n\t\t\t\tthis.wholeFileLock.pidFds.has(op.pid) &&\n\t\t\t\tthis.wholeFileLock.pidFds.get(op.pid)!.has(op.fd)\n\t\t\t) {\n\t\t\t\tthis.wholeFileLock.pidFds.get(op.pid)!.delete(op.fd);\n\t\t\t\tif (this.wholeFileLock.pidFds.get(op.pid)!.size === 0) {\n\t\t\t\t\tthis.wholeFileLock.pidFds.delete(op.pid);\n\t\t\t\t}\n\n\t\t\t\tif (this.wholeFileLock.pidFds.size === 0) {\n\t\t\t\t\tthis.wholeFileLock = { type: 'unlocked' };\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tif (this.isThereAConflictWithRequestedWholeFileLock(op)) {\n\t\t\t// The requested lock conflicts with an existing lock.\n\t\t\treturn false;\n\t\t}\n\n\t\tif (op.type === 'exclusive') {\n\t\t\tthis.wholeFileLock = {\n\t\t\t\ttype: 'exclusive',\n\t\t\t\tpid: op.pid,\n\t\t\t\tfd: op.fd,\n\t\t\t};\n\n\t\t\treturn true;\n\t\t}\n\n\t\tif (op.type === 'shared') {\n\t\t\tif (this.wholeFileLock.type !== 'shared') {\n\t\t\t\tthis.wholeFileLock = {\n\t\t\t\t\ttype: 'shared',\n\t\t\t\t\tpidFds: new Map(),\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst sharedLock = this.wholeFileLock;\n\t\t\tif (!sharedLock.pidFds.has(op.pid)) {\n\t\t\t\tsharedLock.pidFds.set(op.pid, new Set());\n\t\t\t}\n\t\t\tsharedLock.pidFds.get(op.pid)!.add(op.fd);\n\n\t\t\treturn true;\n\t\t}\n\n\t\tthrow new Error(`Unexpected wholeFileLock() op: '${op.type}'`);\n\t}\n\n\t/**\n\t * Lock a byte range.\n\t *\n\t * This method corresponds to the fcntl() F_SETLK command.\n\t *\n\t * @param requestedLock The byte range lock to perform.\n\t * @returns True if the lock was granted, false otherwise.\n\t */\n\tlockFileByteRange(\n\t\trequestedLock: Omit<RequestedRangeLock, 'fd' | 'waitForLock'>\n\t): boolean {\n\t\tif (requestedLock.start === requestedLock.end) {\n\t\t\t/*\n\t\t\t * Treat a range with zero length as covering the entire remaining range.\n\t\t\t * POSIX Ref: https://pubs.opengroup.org/onlinepubs/9799919799/functions/fcntl.html\n\t\t\t * \"A lock shall be set to extend to the largest possible value of the file offset\n\t\t\t * for that file by setting l_len to 0.\"\n\t\t\t */\n\t\t\trequestedLock = {\n\t\t\t\t...requestedLock,\n\t\t\t\tend: MAX_ADDRESSABLE_FILE_OFFSET,\n\t\t\t};\n\t\t}\n\n\t\tif (requestedLock.type === 'unlocked') {\n\t\t\tconst overlappingLocksBySameProcess = this.rangeLocks\n\t\t\t\t.findOverlapping(requestedLock)\n\t\t\t\t.filter((lock) => lock.pid === requestedLock.pid);\n\n\t\t\tfor (const overlappingLock of overlappingLocksBySameProcess) {\n\t\t\t\tthis.rangeLocks.remove(overlappingLock);\n\n\t\t\t\tif (overlappingLock.start < requestedLock.start) {\n\t\t\t\t\t// This lock precedes our unlock range.\n\t\t\t\t\t// Preserve the part that does not overlap.\n\t\t\t\t\tthis.rangeLocks.insert({\n\t\t\t\t\t\t...overlappingLock,\n\t\t\t\t\t\tend: requestedLock.start,\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tif (overlappingLock.end > requestedLock.end) {\n\t\t\t\t\t// This lock extends past our unlock range.\n\t\t\t\t\t// Preserve the part that does not overlap.\n\t\t\t\t\tthis.rangeLocks.insert({\n\t\t\t\t\t\t...overlappingLock,\n\t\t\t\t\t\tstart: requestedLock.end,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn true;\n\t\t}\n\n\t\tif (this.isThereAConflictWithRequestedRangeLock(requestedLock)) {\n\t\t\t// A conflicting lock exists.\n\t\t\treturn false;\n\t\t}\n\n\t\tconst overlappingLocksFromSameProcess = this.rangeLocks\n\t\t\t.findOverlapping(requestedLock)\n\t\t\t.filter((lock) => lock.pid === requestedLock.pid);\n\n\t\tlet minStart = requestedLock.start;\n\t\tlet maxEnd = requestedLock.end;\n\t\tfor (const overlappingLock of overlappingLocksFromSameProcess) {\n\t\t\t// Remove overlapping locks from the same process because the requested\n\t\t\t// lock replaces them.\n\t\t\tthis.rangeLocks.remove(overlappingLock);\n\n\t\t\tif (overlappingLock.start < minStart) {\n\t\t\t\tminStart = overlappingLock.start;\n\t\t\t}\n\t\t\tif (overlappingLock.end > maxEnd) {\n\t\t\t\tmaxEnd = overlappingLock.end;\n\t\t\t}\n\t\t}\n\n\t\t// Overlapping locks from the same process are merged into a single lock of the requested type.\n\t\tconst mergedLock: LockedRange = {\n\t\t\t...(requestedLock as LockedRange),\n\t\t\tstart: minStart,\n\t\t\tend: maxEnd,\n\t\t};\n\t\tthis.rangeLocks.insert(mergedLock);\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Find the first conflicting byte range lock.\n\t *\n\t * This method corresponds to the fcntl() F_GETLK command.\n\t *\n\t * @param desiredLock The desired byte range lock.\n\t * @returns The first conflicting byte range lock, or undefined if no conflicting lock exists.\n\t */\n\tfindFirstConflictingByteRangeLock(\n\t\t/**\n\t\t * NOTE: fcntl()-style F_SETLK/F_GETLK do not associate\n\t\t * resulting locks with a file descrtiptor, so we ignore fd here.\n\t\t */\n\t\tdesiredLock: Omit<RequestedRangeLock, 'fd'>\n\t) {\n\t\tif (desiredLock.start === desiredLock.end) {\n\t\t\t/*\n\t\t\t * Treat a range with zero length as covering the entire remaining range.\n\t\t\t * POSIX Ref: https://pubs.opengroup.org/onlinepubs/9799919799/functions/fcntl.html\n\t\t\t * \"A lock shall be set to extend to the largest possible value of the file offset\n\t\t\t * for that file by setting l_len to 0.\"\n\t\t\t */\n\t\t\tdesiredLock = {\n\t\t\t\t...desiredLock,\n\t\t\t\tend: MAX_ADDRESSABLE_FILE_OFFSET,\n\t\t\t};\n\t\t}\n\t\tconst overlappingLocks = this.rangeLocks.findOverlapping(desiredLock);\n\t\tconst firstConflictingRangeLock = overlappingLocks.find(\n\t\t\t(lock) =>\n\t\t\t\tlock.pid !== desiredLock.pid &&\n\t\t\t\t(desiredLock.type === 'exclusive' || lock.type === 'exclusive')\n\t\t);\n\n\t\tif (firstConflictingRangeLock) {\n\t\t\treturn firstConflictingRangeLock;\n\t\t}\n\n\t\tif (this.wholeFileLock.type === 'unlocked') {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst wfl = this.wholeFileLock;\n\t\tif (wfl.type === 'exclusive' || desiredLock.type === 'exclusive') {\n\t\t\t// An exclusive lock conflicts with any other exclusive lock.\n\t\t\treturn {\n\t\t\t\ttype: this.wholeFileLock.type,\n\t\t\t\tstart: 0n,\n\t\t\t\tend: 0n,\n\t\t\t\tpid: -1,\n\t\t\t};\n\t\t}\n\n\t\t// Shared locks do not conflict with each other.\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Release all locks for the given process.\n\t *\n\t * @param pid The process ID to release locks for.\n\t */\n\treleaseLocksForProcess(pid: Pid) {\n\t\tfor (const rangeLock of this.rangeLocks.findLocksForProcess(pid)) {\n\t\t\tthis.lockFileByteRange({\n\t\t\t\t...rangeLock,\n\t\t\t\ttype: 'unlocked',\n\t\t\t});\n\t\t}\n\n\t\tif (\n\t\t\tthis.wholeFileLock.type === 'exclusive' &&\n\t\t\tthis.wholeFileLock.pid === pid\n\t\t) {\n\t\t\tthis.lockWholeFile({\n\t\t\t\tpid,\n\t\t\t\tfd: this.wholeFileLock.fd,\n\t\t\t\ttype: 'unlock',\n\t\t\t});\n\t\t} else if (\n\t\t\tthis.wholeFileLock.type === 'shared' &&\n\t\t\tthis.wholeFileLock.pidFds.has(pid)\n\t\t) {\n\t\t\tfor (const fd of this.wholeFileLock.pidFds.get(pid)!) {\n\t\t\t\tthis.lockWholeFile({\n\t\t\t\t\tpid,\n\t\t\t\t\tfd,\n\t\t\t\t\ttype: 'unlock',\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Release all locks for the given process and file descriptor.\n\t *\n\t * @param pid The process ID to release locks for.\n\t * @param fd The file descriptor to release locks for.\n\t */\n\treleaseLocksOnFdClose(pid: Pid, fd: Fd) {\n\t\t// Closing an fd for a file releases all fcntl locks for that file by the process.\n\t\t// POSIX Ref: https://pubs.opengroup.org/onlinepubs/9799919799/functions/fcntl.html\n\t\t// \"Closing a file descriptor shall release all locks held by the process on the file\n\t\t// associated with that file descriptor.\"\n\t\tfor (const rangeLock of this.rangeLocks.findLocksForProcess(pid)) {\n\t\t\tthis.lockFileByteRange({\n\t\t\t\t...rangeLock,\n\t\t\t\ttype: 'unlocked',\n\t\t\t});\n\t\t}\n\n\t\tthis.lockWholeFile({\n\t\t\tpid,\n\t\t\tfd,\n\t\t\ttype: 'unlock',\n\t\t});\n\t}\n\n\t/**\n\t * Check if the file lock is unlocked.\n\t *\n\t * @returns True if the file lock is unlocked, false otherwise.\n\t */\n\tisUnlocked(): boolean {\n\t\treturn (\n\t\t\tthis.wholeFileLock.type === 'unlocked' && this.rangeLocks.isEmpty()\n\t\t);\n\t}\n\n\t/**\n\t * Check if a lock exists that conflicts with the requested range lock.\n\t *\n\t * @param requestedLock The desired byte range lock.\n\t * @returns True if a conflicting lock exists, false otherwise.\n\t */\n\tprivate isThereAConflictWithRequestedRangeLock(\n\t\trequestedLock: Omit<RequestedRangeLock, 'fd' | 'waitForLock'>\n\t) {\n\t\treturn (\n\t\t\tthis.findFirstConflictingByteRangeLock(requestedLock) !== undefined\n\t\t);\n\t}\n\n\t/**\n\t * Check if a lock exists that conflicts with the requested whole-file lock.\n\t *\n\t * @param requestedLock The desired whole-file lock.\n\t * @returns True if a conflicting lock exists, false otherwise.\n\t */\n\tprivate isThereAConflictWithRequestedWholeFileLock(\n\t\trequestedLock: Omit<WholeFileLockOp, 'waitForLock'>\n\t) {\n\t\tif (requestedLock.type === 'exclusive') {\n\t\t\tif (\n\t\t\t\tthis.wholeFileLock.type === 'exclusive' &&\n\t\t\t\t(this.wholeFileLock.fd !== requestedLock.fd ||\n\t\t\t\t\tthis.wholeFileLock.pid !== requestedLock.pid)\n\t\t\t) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (\n\t\t\t\tthis.wholeFileLock.type === 'shared' &&\n\t\t\t\tArray.from(this.wholeFileLock.pidFds).some(\n\t\t\t\t\t([pid]) => pid !== requestedLock.pid\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tconst overlappingLocks = this.rangeLocks.findOverlapping({\n\t\t\t\tstart: 0n,\n\t\t\t\tend: MAX_ADDRESSABLE_FILE_OFFSET,\n\t\t\t});\n\t\t\tif (overlappingLocks.length > 0) {\n\t\t\t\t// Any range lock, including one by the same process,\n\t\t\t\t// conflict with an exclusive whole-file lock.\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\tif (requestedLock.type === 'shared') {\n\t\t\tif (\n\t\t\t\tthis.wholeFileLock.type === 'exclusive' &&\n\t\t\t\tthis.wholeFileLock.pid !== requestedLock.pid\n\t\t\t) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tconst overlappingLocks = this.rangeLocks.findOverlapping({\n\t\t\t\tstart: 0n,\n\t\t\t\tend: MAX_ADDRESSABLE_FILE_OFFSET,\n\t\t\t});\n\t\t\tconst exclusiveRangeLocks = overlappingLocks.filter(\n\t\t\t\t(lock) => lock.type === 'exclusive'\n\t\t\t);\n\t\t\tif (exclusiveRangeLocks.length > 0) {\n\t\t\t\t// Any exclusive range lock, including one by the same process,\n\t\t\t\t// conflict with a shared whole-file lock.\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\treturn false;\n\t}\n}\n","import {\n\ttype Path,\n\ttype RequestedRangeLock,\n\ttype WholeFileLockOp,\n\ttype FileLockManager,\n} from './file-lock-manager';\nimport { logger } from '@php-wasm/logger';\n\n// TODO: Add optional granular tracing\nexport class FileLockManagerComposite implements FileLockManager {\n\tnativeLockManager: FileLockManager;\n\twasmLockManager: FileLockManager;\n\n\tconstructor({\n\t\tnativeLockManager,\n\t\twasmLockManager,\n\t}: {\n\t\tnativeLockManager: FileLockManager;\n\t\twasmLockManager: FileLockManager;\n\t}) {\n\t\tthis.nativeLockManager = nativeLockManager;\n\t\tthis.wasmLockManager = wasmLockManager;\n\t}\n\n\tlockWholeFile(path: Path, op: WholeFileLockOp): boolean {\n\t\tif (op.type !== 'unlock') {\n\t\t\t/**\n\t\t\t * We lock starting with the outside and moving to the inside.\n\t\t\t * - OS locking comes first as the highest authority.\n\t\t\t * - WASM locking comes next as our in-house authority.\n\t\t\t *\n\t\t\t * This ensures that we only offer locks to WASM instances when\n\t\t\t * the OS has granted a native lock to our process.\n\t\t\t */\n\t\t\tlet nativeResult;\n\t\t\tlet wasmResult;\n\t\t\ttry {\n\t\t\t\tnativeResult = this.nativeLockManager.lockWholeFile(path, op);\n\t\t\t\tif (!nativeResult) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\twasmResult = this.wasmLockManager.lockWholeFile(path, op);\n\t\t\t} catch (e) {\n\t\t\t\tlogger.error('Unexpected error in lockWholeFile()', e);\n\t\t\t} finally {\n\t\t\t\t// Rollback the native lock if the wasm lock throws\n\t\t\t\t// (e.g. comlink-sync timeout). Without this, the native\n\t\t\t\t// lock would be held indefinitely, blocking all other\n\t\t\t\t// workers.\n\t\t\t\tif (nativeResult && !wasmResult) {\n\t\t\t\t\t// Rollback the native lock if the wasm lock fails.\n\t\t\t\t\tthis.nativeLockManager.lockWholeFile(path, {\n\t\t\t\t\t\t...op,\n\t\t\t\t\t\ttype: 'unlock',\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn !!nativeResult && !!wasmResult;\n\t\t}\n\n\t\t/**\n\t\t * We unlock starting with the inside and moving to the outside.\n\t\t * - WASM locking comes first as our in-house authority.\n\t\t * - OS locking comes last as we return locks to the highest authority.\n\t\t *\n\t\t * This ensures that other OS processes cannot contend with WASM instances\n\t\t * for locks while WASM instances believe they still hold a lock.\n\t\t */\n\t\ttry {\n\t\t\tthis.wasmLockManager.lockWholeFile(path, op);\n\t\t} catch (e) {\n\t\t\tlogger.error(\n\t\t\t\t'Unexpected error unlocking whole file with in-memory lock manager',\n\t\t\t\te\n\t\t\t);\n\t\t}\n\t\ttry {\n\t\t\tthis.nativeLockManager.lockWholeFile(path, op);\n\t\t} catch (e) {\n\t\t\tlogger.error(\n\t\t\t\t'Unexpected error unlocking whole file with native lock manager',\n\t\t\t\te\n\t\t\t);\n\t\t}\n\t\treturn true;\n\t}\n\n\tlockFileByteRange(\n\t\tpath: Path,\n\t\trequestedLock: RequestedRangeLock,\n\t\twaitForLock: boolean\n\t): boolean {\n\t\tif (requestedLock.type !== 'unlocked') {\n\t\t\t/**\n\t\t\t * We lock starting with the outside and moving to the inside.\n\t\t\t * - OS locking comes first as the highest authority.\n\t\t\t * - WASM locking comes next as our in-house authority.\n\t\t\t *\n\t\t\t * This ensures that we only offer locks to WASM instances when\n\t\t\t * the OS has granted a native lock to our process.\n\t\t\t */\n\t\t\tlet nativeResult;\n\t\t\tlet wasmResult;\n\t\t\ttry {\n\t\t\t\tnativeResult = this.nativeLockManager.lockFileByteRange(\n\t\t\t\t\tpath,\n\t\t\t\t\trequestedLock,\n\t\t\t\t\twaitForLock\n\t\t\t\t);\n\t\t\t\tif (!nativeResult) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\twasmResult = this.wasmLockManager.lockFileByteRange(\n\t\t\t\t\tpath,\n\t\t\t\t\trequestedLock,\n\t\t\t\t\twaitForLock\n\t\t\t\t);\n\t\t\t} catch (e) {\n\t\t\t\tlogger.error('Unexpected error in lockFileByteRange()', e);\n\t\t\t} finally {\n\t\t\t\tif (nativeResult && !wasmResult) {\n\t\t\t\t\t// Rollback the native lock if the wasm lock fails.\n\t\t\t\t\tthis.nativeLockManager.lockFileByteRange(\n\t\t\t\t\t\tpath,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t...requestedLock,\n\t\t\t\t\t\t\ttype: 'unlocked',\n\t\t\t\t\t\t},\n\t\t\t\t\t\tfalse\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn !!nativeResult && !!wasmResult;\n\t\t}\n\n\t\t/**\n\t\t * We unlock starting with the inside and moving to the outside.\n\t\t * - WASM locking comes first as our in-house authority.\n\t\t * - OS locking comes last as we return locks to the highest authority.\n\t\t *\n\t\t * This ensures that other OS processes cannot contend with WASM instances\n\t\t * for locks while WASM instances believe they still hold a lock.\n\t\t */\n\t\ttry {\n\t\t\tthis.wasmLockManager.lockFileByteRange(\n\t\t\t\tpath,\n\t\t\t\trequestedLock,\n\t\t\t\twaitForLock\n\t\t\t);\n\t\t} catch (e) {\n\t\t\tlogger.error(\n\t\t\t\t'Unexpected error unlocking byte range with in-memory lock manager',\n\t\t\t\te\n\t\t\t);\n\t\t}\n\t\ttry {\n\t\t\tthis.nativeLockManager.lockFileByteRange(\n\t\t\t\tpath,\n\t\t\t\trequestedLock,\n\t\t\t\twaitForLock\n\t\t\t);\n\t\t} catch (e) {\n\t\t\tlogger.error(\n\t\t\t\t'Unexpected error unlocking byte range with native lock manager',\n\t\t\t\te\n\t\t\t);\n\t\t}\n\t\treturn true;\n\t}\n\n\tfindFirstConflictingByteRangeLock(\n\t\tpath: Path,\n\t\tdesiredLock: RequestedRangeLock\n\t): Omit<RequestedRangeLock, 'fd'> | undefined {\n\t\ttry {\n\t\t\t// Check native lock manager first, then wasm lock manager.\n\t\t\t// Return the first conflict found from either.\n\t\t\tconst nativeConflict =\n\t\t\t\tthis.nativeLockManager.findFirstConflictingByteRangeLock(\n\t\t\t\t\tpath,\n\t\t\t\t\tdesiredLock\n\t\t\t\t);\n\t\t\tif (nativeConflict) {\n\t\t\t\treturn nativeConflict;\n\t\t\t}\n\n\t\t\tconst wasmConflict =\n\t\t\t\tthis.wasmLockManager.findFirstConflictingByteRangeLock(\n\t\t\t\t\tpath,\n\t\t\t\t\tdesiredLock\n\t\t\t\t);\n\t\t\treturn wasmConflict;\n\t\t} catch (e) {\n\t\t\tlogger.error(\n\t\t\t\t'Unexpected error in findFirstConflictingByteRangeLock()',\n\t\t\t\te\n\t\t\t);\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\treleaseLocksForProcess(pid: number): void {\n\t\t/**\n\t\t * We unlock starting with the inside and moving to the outside.\n\t\t * - WASM locking comes first as our in-house authority.\n\t\t * - OS locking comes last as we return locks to the highest authority.\n\t\t *\n\t\t * This ensures that other OS processes cannot contend with WASM instances\n\t\t * for locks while WASM instances believe they still hold a lock.\n\t\t */\n\t\ttry {\n\t\t\tthis.wasmLockManager.releaseLocksForProcess(pid);\n\t\t} catch (e) {\n\t\t\tlogger.error(\n\t\t\t\t'Unexpected error in wasmLockManager.releaseLocksForProcess()',\n\t\t\t\te\n\t\t\t);\n\t\t}\n\n\t\ttry {\n\t\t\tthis.nativeLockManager.releaseLocksForProcess(pid);\n\t\t} catch (e) {\n\t\t\tlogger.error(\n\t\t\t\t'Unexpected error in nativeLockManager.releaseLocksForProcess()',\n\t\t\t\te\n\t\t\t);\n\t\t}\n\t}\n\n\treleaseLocksOnFdClose(pid: number, fd: number, path: Path): void {\n\t\t/**\n\t\t * We unlock starting with the inside and moving to the outside.\n\t\t * - WASM locking comes first as our in-house authority.\n\t\t * - OS locking comes last as we return locks to the highest authority.\n\t\t *\n\t\t * This ensures that other OS processes cannot contend with WASM instances\n\t\t * for locks while WASM instances believe they still hold a lock.\n\t\t */\n\t\ttry {\n\t\t\tthis.wasmLockManager.releaseLocksOnFdClose(pid, fd, path);\n\t\t} catch (e) {\n\t\t\tlogger.error(\n\t\t\t\t'Unexpected error in wasmLockManager.releaseLocksOnFdClose()',\n\t\t\t\te\n\t\t\t);\n\t\t}\n\n\t\ttry {\n\t\t\tthis.nativeLockManager.releaseLocksOnFdClose(pid, fd, path);\n\t\t} catch (e) {\n\t\t\tlogger.error(\n\t\t\t\t'Unexpected error in nativeLockManager.releaseLocksOnFdClose()',\n\t\t\t\te\n\t\t\t);\n\t\t}\n\t}\n}\n","/**\n * Converts an object type to a promisified version where:\n * - Methods return `Promise<Awaited<ReturnType>>` (no double-wrapping)\n * - Properties become `Promise<Awaited<PropertyType>>`\n */\ntype Promisified<T extends object> = {\n\t[K in keyof T]: T[K] extends (...args: infer A) => infer R\n\t\t? (...args: A) => Promise<Awaited<R>>\n\t\t: Promise<Awaited<T[K]>>;\n};\n\n/**\n * The type returned by `createObjectPoolProxy`. All method calls and\n * property accesses are wrapped in promises because acquiring a free\n * pool instance is inherently async.\n *\n * Dispose/asyncDispose symbols are omitted because the pool proxy\n * forwards calls to a single random instance — disposing one\n * instance out of the pool is never the intended behavior. Pool\n * lifecycle should be managed by the code that created the pool.\n */\nexport type Pooled<T extends object> = Omit<\n\tPromisified<T>,\n\ttypeof Symbol.dispose | typeof Symbol.asyncDispose\n>;\n\n/**\n * Creates a proxy that distributes method calls and property accesses\n * across a pool of object instances. Only one ongoing access per\n * instance is allowed at a time. If all instances are busy, accesses\n * wait until one becomes free.\n *\n * The returned proxy provides a promisified version of the original\n * interface: method calls and property accesses all return promises.\n */\nexport function createObjectPoolProxy<T extends object>(\n\tinstances: T[]\n): Pooled<T> {\n\tif (instances.length === 0) {\n\t\tthrow new Error('At least one instance is required');\n\t}\n\n\tconst freeInstances: T[] = [...instances];\n\tconst waitQueue: Array<(instance: T) => void> = [];\n\n\tfunction acquire(): Promise<T> {\n\t\tconst free = freeInstances.shift();\n\t\tif (free !== undefined) {\n\t\t\treturn Promise.resolve(free);\n\t\t}\n\t\treturn new Promise<T>((resolve) => {\n\t\t\twaitQueue.push(resolve);\n\t\t});\n\t}\n\n\tfunction release(instance: T): void {\n\t\tconst waiter = waitQueue.shift();\n\t\tif (waiter) {\n\t\t\twaiter(instance);\n\t\t} else {\n\t\t\tfreeInstances.push(instance);\n\t\t}\n\t}\n\n\tfunction withInstance<R>(fn: (instance: T) => R | Promise<R>): Promise<R> {\n\t\treturn acquire().then((instance) => {\n\t\t\tlet result: R | Promise<R>;\n\t\t\ttry {\n\t\t\t\tresult = fn(instance);\n\t\t\t} catch (e) {\n\t\t\t\trelease(instance);\n\t\t\t\tthrow e;\n\t\t\t}\n\t\t\tif (result != null && typeof (result as any).then === 'function') {\n\t\t\t\treturn (result as Promise<R>).then(\n\t\t\t\t\t(val) => {\n\t\t\t\t\t\trelease(instance);\n\t\t\t\t\t\treturn val;\n\t\t\t\t\t},\n\t\t\t\t\t(err) => {\n\t\t\t\t\t\trelease(instance);\n\t\t\t\t\t\tthrow err;\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t}\n\t\t\trelease(instance);\n\t\t\treturn result as R;\n\t\t});\n\t}\n\n\treturn new Proxy({} as Pooled<T>, {\n\t\tget(_target, prop: string | symbol) {\n\t\t\t// Support returning assigned target properties.\n\t\t\t// The main reason for this is to allow us to override methods\n\t\t\t// for testing purposes.\n\t\t\t// TODO: Add test for this feature?\n\t\t\tif (prop in _target) {\n\t\t\t\treturn (_target as any)[prop];\n\t\t\t}\n\n\t\t\t// Prevent the proxy from being treated as a thenable,\n\t\t\t// which would interfere with Promise resolution.\n\t\t\tif (prop === 'then') {\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\t// Return a dual-purpose proxy that works as both a method call\n\t\t\t// and a property access. This mirrors how comlink proxies handle\n\t\t\t// the ambiguity — the call site determines the behavior:\n\t\t\t// - playground.run(opts) → apply trap → method call\n\t\t\t// - await playground.docroot → .then accessed → property get\n\t\t\t//\n\t\t\t// We can't sample typeof on the instance to decide, because\n\t\t\t// comlink proxies are always functions regardless of whether\n\t\t\t// the remote value is a method or a property.\n\t\t\treturn new Proxy(function () {}, {\n\t\t\t\tapply(_target, _thisArg, args: any[]) {\n\t\t\t\t\treturn withInstance((inst) => (inst as any)[prop](...args));\n\t\t\t\t},\n\t\t\t\tget(_target, innerProp) {\n\t\t\t\t\tif (innerProp === 'then') {\n\t\t\t\t\t\treturn (resolve: any, reject: any) =>\n\t\t\t\t\t\t\twithInstance((inst) => (inst as any)[prop]).then(\n\t\t\t\t\t\t\t\tresolve,\n\t\t\t\t\t\t\t\treject\n\t\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\treturn undefined;\n\t\t\t\t},\n\t\t\t});\n\t\t},\n\t});\n}\n"],"names":["errno","message","options","e","messagePrefix","value","args","errmsg","path","formattedPrefix","FS","data","fromPath","toPath","fromMount","toMount","dirname","mountPoint","file","filePath","joinPaths","files","name","prepend","logger","target","link","fromNode","filenames","filename","requestHandler","monitor","__privateAdd","_eventListeners","__privateSet","php","internalUrl","callback","_a","request","reap","argv","response","error","newName","listener","l","key","eventType","__privateGet","event","listeners","returnData","phpLoaderModule","phpModuleArgs","phpReady","resolvePHP","rejectPHP","PHPRuntime","reason","id","code","dangerouslyKeepTheRuntimeInTheMap","runtime","methods","promise","resolve","reject","_StreamedPHPResponse","headers","stdout","stderr","exitCode","_headersStream","controller","emptyStream","streamed","httpStatusCode","text","statusCode","result","bytes","headersStream","headersText","headersData","line","colonIndex","headerName","headerValue","stream","reader","done","chunks","totalLength","acc","chunk","offset","body","errors","streamedResponse","type","original","clearMessage","crypticError","asyncifyStack","betterMessage","uniqueFunctions","lastError","fn","stack","names","parts","isWasm","source","PHPRuntimeId","_PHP_instances","_sapiName","_phpWasmInitCalled","_wasmErrorsTarget","_messageListeners","_mounts","_rotationOptions","Semaphore","createSpawnHandler","runtimeId","opcacheConfig","mode","syncResponse","release","heapBodyPointer","streamedResponsePromise","__privateMethod","executeWithErrorHandling_fn","setRelativeRequestUri_fn","setRequestMethod_fn","requestHeaders","host","port","inferPortFromHostAndProtocol_fn","setRequestHost_fn","setRequestPort_fn","setRequestHeaders_fn","setRequestBody_fn","setScriptPath_fn","$_SERVER","prepareServerEntries_fn","setServerGlobalEntry_fn","env","setEnv_fn","cleanup","consts","oldFS","oldRootLevelPaths","oldSpawnProcess","oldCWD","mountHandlersToReapplyInOrder","vfsPath","mount","mountsToUnmountInReverseOrder","newFs","mountHandler","virtualFSPath","unmountCallback","mountObject","basename","arg","process","stderrStream","stdoutStream","shouldSkip","defaults","HTTP_prefix","uri","queryString","protocol","method","size","contentLength","executionFn","emscriptenModule","streamsClosed","headersClosed","closeHeadersStream","errorListener","exitCodePromise","normalized","oldNode","controllerResolve","controllerPromise","fs","entries","ini","parse","stringify","phpIniValues","iniBefore","current","isFirst","hasHeaders","setCookie","equalsIndex","cookiesArray","buffer","root","relativePaths","pathPrefix","exceptPaths","normalizePath","currentParent","absPath","StreamedFile","limit","releaseSemaphore","AcquireTimeoutError","isPrimary","url","prefix","boundary","contentType","textEncoder","length","part","fileBuffer","config","_PHPRequestHandler_instances","_DOCROOT","_PROTOCOL","_HOSTNAME","_PORT","_HOST","_PATHNAME","_ABSOLUTE_URL","_cookieStore","_pathAliases","documentRoot","absoluteUrl","rewriteRules","pathAliases","getFileNotFoundAction","setChroot","info","isNonStandardPort","isAbsolute","originalRequestUrl","rewrittenRequestUrl","applyRewriteRules_fn","primaryPhp","siteRelativePath","fsPath","resolveToFsPath_fn","possibleIndexFile","possibleIndexPath","pathToTry","resolvedPathToTry","fileNotFoundAction","spawnPHPAndDispatchRequest_fn","serveStaticFile_fn","resolvedScriptPath","rewrittenRequestPath","urlPath","alias","relativePath","arrayBuffer","scriptPath","spawnedPHP","dispatchToPHP_fn","preferredMethod","cookieStore","responseHeaders","extension","rules","rule","recreateRuntime","maxRequests","newFiles","rmRoot","content","phpInstance","__private__symbol","PROXYFS","position","prot","flags","ptr","heap","totalBytesRead","bytesRead","mmapFlags","sourceOfTruth","replica","paths","replicaSymbol","sourceSymbol","fsResult","getPHPInstance","processApi","splitShellCommand","binaryName","cwd","obj","ep","transport","allowedOrigins","_t","prop","_","res","v","xfer","_thisArg","rawArgs","argList","wire","m","ev","notifyBuffer","view","msg","transferables","latch","val","port1","port2","throwTransferHandler","serialized","origin","allowedOrigin","afterResponseSent","argumentList","returnValue","parent","rawValue","wireValue","endpoint","pendingListeners","resolver","isReleased","newCount","proxy","isProxyReleased","_target","r","p","rawArgumentList","last","arr","processed","transfers","w","context","targetOrigin","handler","serializedValue","nep","eh","worker","emitter","emitterWithSend","_transferList","constructor","from","json","ErrorConstructor","seen","to","forceEnumerable","maxDepth","depth","useToJSON","serialize","continueDestroyCircular","property","enumerable","remote","Comlink.wrapSync","nodeWorkerEndpoint","Comlink.windowEndpoint","api","Comlink.wrap","timeout","apiMethods","pipedApi","targetWorker","setReady","setFailed","exposedApi","Comlink.expose","Comlink.exposeSync","connected","ready","Comlink.transferHandlers","responseData","throwHandler","originalSerialize","supportsStreams","exitCodePort","headersPort","stdoutPort","stderrPort","rs","owned","buf","onMessage","err","ErrorSerializer.serializeError","ErrorSerializer.deserializeError","additionalCallStack","deepestError","object","Comlink.proxy","range","pid","maxType","traverse","node","max","a","b","successor","op","requestedLock","desiredLock","lock","fd","nativePath","sharedLock","overlappingLocksBySameProcess","overlappingLock","overlappingLocksFromSameProcess","minStart","maxEnd","mergedLock","firstConflictingRangeLock","rangeLock","nativeLockManager","wasmLockManager","nativeResult","wasmResult","waitForLock","nativeConflict","instances","freeInstances","waitQueue","acquire","free","instance","waiter","withInstance","inst","innerProp"],"mappings":"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"}