@wp-playground/cli 1.2.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/README.md +3 -0
  2. package/blueprints-BQYAZ9gc.js +9 -0
  3. package/blueprints-BQYAZ9gc.js.map +1 -0
  4. package/blueprints-DLntJtVr.js +9 -0
  5. package/blueprints-DLntJtVr.js.map +1 -0
  6. package/blueprints-ZBrY1bvK.cjs +2 -0
  7. package/blueprints-ZBrY1bvK.cjs.map +1 -0
  8. package/blueprints-v1/blueprints-v1-handler.d.ts +31 -0
  9. package/{worker-thread.d.ts → blueprints-v1/worker-thread-v1.d.ts} +5 -3
  10. package/blueprints-v2/blueprint-v2-declaration.d.ts +10 -0
  11. package/blueprints-v2/blueprints-v2-handler.d.ts +31 -0
  12. package/blueprints-v2/get-v2-runner.d.ts +1 -0
  13. package/blueprints-v2/run-blueprint-v2.d.ts +35 -0
  14. package/blueprints-v2/worker-thread-v2.d.ts +49 -0
  15. package/blueprints.phar +0 -0
  16. package/cli.cjs +1 -1
  17. package/cli.cjs.map +1 -1
  18. package/cli.js +2 -4
  19. package/cli.js.map +1 -1
  20. package/index.cjs +1 -1
  21. package/index.js +1 -1
  22. package/load-balancer.d.ts +3 -1
  23. package/mounts-B-Qdcyyt.js +124 -0
  24. package/mounts-B-Qdcyyt.js.map +1 -0
  25. package/mounts-D7bhhGq3.cjs +15 -0
  26. package/mounts-D7bhhGq3.cjs.map +1 -0
  27. package/{mount.d.ts → mounts.d.ts} +10 -1
  28. package/package.json +11 -11
  29. package/run-cli-CY1lYIJH.js +674 -0
  30. package/run-cli-CY1lYIJH.js.map +1 -0
  31. package/run-cli-opqDVXKw.cjs +27 -0
  32. package/run-cli-opqDVXKw.cjs.map +1 -0
  33. package/run-cli.d.ts +30 -6
  34. package/worker-thread-v1-BTJIbQLy.js +133 -0
  35. package/worker-thread-v1-BTJIbQLy.js.map +1 -0
  36. package/worker-thread-v1.cjs +3 -0
  37. package/worker-thread-v1.cjs.map +1 -0
  38. package/worker-thread-v1.js +128 -0
  39. package/worker-thread-v1.js.map +1 -0
  40. package/worker-thread-v2-Pfv6UYF4.js +429 -0
  41. package/worker-thread-v2-Pfv6UYF4.js.map +1 -0
  42. package/worker-thread-v2.cjs +92 -0
  43. package/worker-thread-v2.cjs.map +1 -0
  44. package/worker-thread-v2.js +432 -0
  45. package/worker-thread-v2.js.map +1 -0
  46. package/cli-auto-mount.d.ts +0 -19
  47. package/index-CddYZc1x.js +0 -5
  48. package/index-CddYZc1x.js.map +0 -1
  49. package/index-CyPmrjJv.cjs +0 -2
  50. package/index-CyPmrjJv.cjs.map +0 -1
  51. package/reportable-error.d.ts +0 -5
  52. package/run-cli-Bon3Rz_F.cjs +0 -43
  53. package/run-cli-Bon3Rz_F.cjs.map +0 -1
  54. package/run-cli-DyJ6_Vj8.js +0 -8449
  55. package/run-cli-DyJ6_Vj8.js.map +0 -1
  56. package/worker-thread-CQBM_bGk.js +0 -171
  57. package/worker-thread-CQBM_bGk.js.map +0 -1
  58. package/worker-thread.cjs +0 -3
  59. package/worker-thread.cjs.map +0 -1
  60. package/worker-thread.js +0 -124
  61. package/worker-thread.js.map +0 -1
  62. /package/{download.d.ts → blueprints-v1/download.d.ts} +0 -0
  63. /package/{server.d.ts → start-server.d.ts} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker-thread-v1-BTJIbQLy.js","sources":["packages/playground/cli/src/mounts.ts","packages/playground/cli/src/blueprints-v1/worker-thread-v1.ts"],"sourcesContent":["import { createNodeFsMountHandler } from '@php-wasm/node';\nimport type { PHP } from '@php-wasm/universal';\nimport fs, { existsSync } from 'fs';\nimport path, { basename, join } from 'path';\nimport type { RunCLIArgs } from './run-cli';\n\nexport interface Mount {\n\thostPath: string;\n\tvfsPath: string;\n}\n\n/**\n * Parse an array of mount argument strings where the host path and VFS path\n * are separated by a colon.\n *\n * Example:\n * parseMountWithDelimiterArguments( [ '/host/path:/vfs/path', '/host/path:/vfs/path' ] )\n * // returns:\n * [\n * { hostPath: '/host/path', vfsPath: '/vfs/path' },\n * { hostPath: '/host/path', vfsPath: '/vfs/path' }\n * ]\n *\n * @param mounts - An array of mount argument strings separated by a colon.\n * @returns An array of Mount objects.\n */\nexport function parseMountWithDelimiterArguments(mounts: string[]): Mount[] {\n\tconst parsedMounts = [];\n\tfor (const mount of mounts) {\n\t\tconst mountParts = mount.split(':');\n\t\tif (mountParts.length !== 2) {\n\t\t\tthrow new Error(`Invalid mount format: ${mount}.\n\t\t\t\tExpected format: /host/path:/vfs/path.\n\t\t\t\tIf your path contains a colon, e.g. C:\\\\myplugin, use the --mount-dir option instead.\n\t\t\t\tExample: --mount-dir C:\\\\my-plugin /wordpress/wp-content/plugins/my-plugin`);\n\t\t}\n\t\tconst [hostPath, vfsPath] = mountParts;\n\t\tif (!existsSync(hostPath)) {\n\t\t\tthrow new Error(`Host path does not exist: ${hostPath}`);\n\t\t}\n\t\tparsedMounts.push({ hostPath, vfsPath });\n\t}\n\treturn parsedMounts;\n}\n\n/**\n * Parse an array of mount argument strings where each odd array element is a host path\n * and each even element is the VFS path.\n * e.g. [ '/host/path', '/vfs/path', '/host/path2', '/vfs/path2' ]\n *\n * The result will be an array of Mount objects for each host path the\n * following element is it's VFS path.\n * e.g. [\n * { hostPath: '/host/path', vfsPath: '/vfs/path' },\n * { hostPath: '/host/path2', vfsPath: '/vfs/path2' }\n * ]\n *\n * @param mounts - An array of paths\n * @returns An array of Mount objects.\n */\nexport function parseMountDirArguments(mounts: string[]): Mount[] {\n\tif (mounts.length % 2 !== 0) {\n\t\tthrow new Error('Invalid mount format. Expected: /host/path /vfs/path');\n\t}\n\n\tconst parsedMounts = [];\n\tfor (let i = 0; i < mounts.length; i += 2) {\n\t\tconst source = mounts[i];\n\t\tconst vfsPath = mounts[i + 1];\n\t\tif (!existsSync(source)) {\n\t\t\tthrow new Error(`Host path does not exist: ${source}`);\n\t\t}\n\t\tparsedMounts.push({\n\t\t\thostPath: path.resolve(process.cwd(), source),\n\t\t\tvfsPath,\n\t\t});\n\t}\n\treturn parsedMounts;\n}\n\nexport async function mountResources(php: PHP, mounts: Mount[]) {\n\tfor (const mount of mounts) {\n\t\tawait php.mount(\n\t\t\tmount.vfsPath,\n\t\t\tcreateNodeFsMountHandler(mount.hostPath)\n\t\t);\n\t}\n}\n\nconst ACTIVATE_FIRST_THEME_STEP = {\n\tstep: 'runPHP',\n\tcode: {\n\t\tfilename: 'activate-theme.php',\n\t\tcontent: `<?php\n\t\t\trequire_once getenv('DOCROOT') . '/wp-load.php';\n\t\t\t$theme = wp_get_theme();\n\t\t\tif (!$theme->exists()) {\n\t\t\t\t$themes = wp_get_themes();\n\t\t\t\tif (count($themes) > 0) {\n\t\t\t\t\t$themeName = array_keys($themes)[0];\n\t\t\t\t\tswitch_theme($themeName);\n\t\t\t\t}\n\t\t\t}\n\t\t`,\n\t},\n};\n\n/**\n * Auto-mounts resolution logic:\n */\nexport function expandAutoMounts(args: RunCLIArgs): RunCLIArgs {\n\tconst path = process.cwd();\n\n\tconst mount = [...(args.mount || [])];\n\tconst mountBeforeInstall = [...(args['mount-before-install'] || [])];\n\n\tconst newArgs = {\n\t\t...args,\n\t\tmount,\n\t\t'mount-before-install': mountBeforeInstall,\n\t\t'additional-blueprint-steps': [\n\t\t\t...((args as any)['additional-blueprint-steps'] || []),\n\t\t],\n\t};\n\n\tif (isPluginFilename(path)) {\n\t\tconst pluginName = basename(path);\n\t\tmount.push({\n\t\t\thostPath: path,\n\t\t\tvfsPath: `/wordpress/wp-content/plugins/${pluginName}`,\n\t\t});\n\t\tnewArgs['additional-blueprint-steps'].push({\n\t\t\tstep: 'activatePlugin',\n\t\t\tpluginPath: `/wordpress/wp-content/plugins/${basename(path)}`,\n\t\t});\n\t} else if (isThemeDirectory(path)) {\n\t\tconst themeName = basename(path);\n\t\tmount.push({\n\t\t\thostPath: path,\n\t\t\tvfsPath: `/wordpress/wp-content/themes/${themeName}`,\n\t\t});\n\t\tnewArgs['additional-blueprint-steps'].push({\n\t\t\tstep: 'activateTheme',\n\t\t\tthemeDirectoryName: themeName,\n\t\t});\n\t} else if (containsWpContentDirectories(path)) {\n\t\t/**\n\t\t * Mount each wp-content file and directory individually.\n\t\t */\n\t\tconst files = fs.readdirSync(path);\n\t\tfor (const file of files) {\n\t\t\t/**\n\t\t\t * WordPress already ships with the wp-content/index.php file\n\t\t\t * and Playground does not support overriding existing VFS files\n\t\t\t * with mounts.\n\t\t\t */\n\t\t\tif (file === 'index.php') {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tmount.push({\n\t\t\t\thostPath: `${path}/${file}`,\n\t\t\t\tvfsPath: `/wordpress/wp-content/${file}`,\n\t\t\t});\n\t\t}\n\t\tnewArgs['additional-blueprint-steps'].push(ACTIVATE_FIRST_THEME_STEP);\n\t} else if (containsFullWordPressInstallation(path)) {\n\t\tmountBeforeInstall.push({ hostPath: path, vfsPath: '/wordpress' });\n\t\t// @TODO: Uncomment when merging Blueprints v2 support\n\t\t// newArgs.mode = 'apply-to-existing-site';\n\t\tnewArgs['additional-blueprint-steps'].push(ACTIVATE_FIRST_THEME_STEP);\n\t} else {\n\t\t/**\n\t\t * By default, mount the current working directory as the Playground root.\n\t\t * This allows users to run and PHP or HTML files using the Playground CLI.\n\t\t */\n\t\tmount.push({ hostPath: path, vfsPath: '/wordpress' });\n\t\t// @TODO: Uncomment when merging Blueprints v2 support\n\t\t// newArgs.mode = 'mount-only';\n\t}\n\n\treturn newArgs as RunCLIArgs;\n}\n\nexport function containsFullWordPressInstallation(path: string): boolean {\n\tconst files = fs.readdirSync(path);\n\treturn (\n\t\tfiles.includes('wp-admin') &&\n\t\tfiles.includes('wp-includes') &&\n\t\tfiles.includes('wp-content')\n\t);\n}\n\nexport function containsWpContentDirectories(path: string): boolean {\n\tconst files = fs.readdirSync(path);\n\treturn (\n\t\tfiles.includes('themes') ||\n\t\tfiles.includes('plugins') ||\n\t\tfiles.includes('mu-plugins') ||\n\t\tfiles.includes('uploads')\n\t);\n}\n\nexport function isThemeDirectory(path: string): boolean {\n\tconst files = fs.readdirSync(path);\n\tif (!files.includes('style.css')) {\n\t\treturn false;\n\t}\n\tconst styleCssContent = fs.readFileSync(join(path, 'style.css'), 'utf8');\n\tconst themeNameRegex = /^(?:[ \\t]*<\\?php)?[ \\t/*#@]*Theme Name:(.*)$/im;\n\treturn !!themeNameRegex.exec(styleCssContent);\n}\n\nexport function isPluginFilename(path: string): boolean {\n\tconst files = fs.readdirSync(path);\n\tconst pluginNameRegex = /^(?:[ \\t]*<\\?php)?[ \\t/*#@]*Plugin Name:(.*)$/im;\n\tconst pluginNameMatch = files\n\t\t.filter((file) => file.endsWith('.php'))\n\t\t.find((file) => {\n\t\t\tconst fileContent = fs.readFileSync(join(path, file), 'utf8');\n\t\t\treturn !!pluginNameRegex.exec(fileContent);\n\t\t});\n\treturn !!pluginNameMatch;\n}\n","import type { FileLockManager } from '@php-wasm/node';\nimport { loadNodeRuntime } from '@php-wasm/node';\nimport { EmscriptenDownloadMonitor } from '@php-wasm/progress';\nimport type { RemoteAPI, SupportedPHPVersion } from '@php-wasm/universal';\nimport {\n\tPHPWorker,\n\tconsumeAPI,\n\tconsumeAPISync,\n\texposeAPI,\n\tsandboxedSpawnHandlerFactory,\n} from '@php-wasm/universal';\nimport { sprintf } from '@php-wasm/util';\nimport { RecommendedPHPVersion } from '@wp-playground/common';\nimport { bootWordPress } from '@wp-playground/wordpress';\nimport { rootCertificates } from 'tls';\nimport { jspi } from 'wasm-feature-detect';\nimport { MessageChannel, type MessagePort, parentPort } from 'worker_threads';\nimport { mountResources } from '../mounts';\n\nexport interface Mount {\n\thostPath: string;\n\tvfsPath: string;\n}\n\nexport type WorkerBootOptions = {\n\twpVersion?: string;\n\tphpVersion?: SupportedPHPVersion;\n\tabsoluteUrl: string;\n\tmountsBeforeWpInstall: Array<Mount>;\n\tmountsAfterWpInstall: Array<Mount>;\n\twordPressZip?: ArrayBuffer;\n\tsqliteIntegrationPluginZip?: ArrayBuffer;\n\tfirstProcessId: number;\n\tprocessIdSpaceLength: number;\n\tdataSqlPath?: string;\n\tfollowSymlinks: boolean;\n\ttrace: boolean;\n\t/**\n\t * When true, Playground will not send cookies to the client but will manage\n\t * them internally. This can be useful in environments that can't store cookies,\n\t * e.g. VS Code WebView.\n\t *\n\t * Default: false.\n\t */\n\tinternalCookieStore?: boolean;\n\twithXdebug?: boolean;\n};\n\n/**\n * Print trace messages from PHP-WASM.\n *\n * @param {number} processId - The process ID.\n * @param {string} format - The format string.\n * @param {...any} args - The arguments.\n */\nfunction tracePhpWasm(processId: number, format: string, ...args: any[]) {\n\t// eslint-disable-next-line no-console\n\tconsole.log(\n\t\tperformance.now().toFixed(6).padStart(15, '0'),\n\t\tprocessId.toString().padStart(16, '0'),\n\t\tsprintf(format, ...args)\n\t);\n}\n\nexport class PlaygroundCliBlueprintV1Worker extends PHPWorker {\n\tbooted = false;\n\tfileLockManager: RemoteAPI<FileLockManager> | FileLockManager | undefined;\n\n\tconstructor(monitor: EmscriptenDownloadMonitor) {\n\t\tsuper(undefined, monitor);\n\t}\n\n\t/**\n\t * Call this method before boot() to use file locking.\n\t *\n\t * This method is separate from boot() to simplify the related Comlink.transferHandlers\n\t * setup – if an argument is a MessagePort, we're transferring it, not copying it.\n\t *\n\t * @see comlink-sync.ts\n\t * @see phpwasm-emscripten-library-file-locking-for-node.js\n\t */\n\tasync useFileLockManager(port: MessagePort) {\n\t\tif (await jspi()) {\n\t\t\t/**\n\t\t\t * If JSPI is available, php.js supports both synchronous and asynchronous locking syscalls.\n\t\t\t * Web browsers, however, only support asynchronous message passing so let's use the\n\t\t\t * asynchronous API. Every method call will return a promise.\n\t\t\t *\n\t\t\t * @see comlink-sync.ts\n\t\t\t * @see phpwasm-emscripten-library-file-locking-for-node.js\n\t\t\t */\n\t\t\tthis.fileLockManager = consumeAPI<FileLockManager>(port);\n\t\t} else {\n\t\t\t/**\n\t\t\t * If JSPI is not available, php.js only supports synchronous locking syscalls.\n\t\t\t * Let's use the synchronous API. Every method call will block this thread\n\t\t\t * until the result is available.\n\t\t\t *\n\t\t\t * @see comlink-sync.ts\n\t\t\t * @see phpwasm-emscripten-library-file-locking-for-node.js\n\t\t\t */\n\t\t\tthis.fileLockManager = await consumeAPISync<FileLockManager>(port);\n\t\t}\n\t}\n\n\tasync bootAsPrimaryWorker({\n\t\tabsoluteUrl,\n\t\tmountsBeforeWpInstall,\n\t\tmountsAfterWpInstall,\n\t\tphpVersion = RecommendedPHPVersion,\n\t\twordPressZip,\n\t\tsqliteIntegrationPluginZip,\n\t\tfirstProcessId,\n\t\tprocessIdSpaceLength,\n\t\tdataSqlPath,\n\t\tfollowSymlinks,\n\t\ttrace,\n\t\tinternalCookieStore,\n\t\twithXdebug,\n\t}: WorkerBootOptions) {\n\t\tif (this.booted) {\n\t\t\tthrow new Error('Playground already booted');\n\t\t}\n\t\tthis.booted = true;\n\n\t\tlet nextProcessId = firstProcessId;\n\t\tconst lastProcessId = firstProcessId + processIdSpaceLength - 1;\n\n\t\ttry {\n\t\t\tconst constants: Record<string, string | number | boolean | null> =\n\t\t\t\t{\n\t\t\t\t\tWP_DEBUG: true,\n\t\t\t\t\tWP_DEBUG_LOG: true,\n\t\t\t\t\tWP_DEBUG_DISPLAY: false,\n\t\t\t\t};\n\n\t\t\tconst requestHandler = await bootWordPress({\n\t\t\t\tsiteUrl: absoluteUrl,\n\t\t\t\tcreatePhpRuntime: async () => {\n\t\t\t\t\tconst processId = nextProcessId;\n\n\t\t\t\t\tif (nextProcessId < lastProcessId) {\n\t\t\t\t\t\tnextProcessId++;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// We've reached the end of the process ID space. Start over.\n\t\t\t\t\t\tnextProcessId = firstProcessId;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn await loadNodeRuntime(phpVersion, {\n\t\t\t\t\t\temscriptenOptions: {\n\t\t\t\t\t\t\tfileLockManager: this.fileLockManager!,\n\t\t\t\t\t\t\tprocessId,\n\t\t\t\t\t\t\ttrace: trace ? tracePhpWasm : undefined,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tfollowSymlinks,\n\t\t\t\t\t\twithXdebug,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\twordPressZip:\n\t\t\t\t\twordPressZip !== undefined\n\t\t\t\t\t\t? new File([wordPressZip], 'wordpress.zip')\n\t\t\t\t\t\t: undefined,\n\t\t\t\tsqliteIntegrationPluginZip:\n\t\t\t\t\tsqliteIntegrationPluginZip !== undefined\n\t\t\t\t\t\t? new File(\n\t\t\t\t\t\t\t\t[sqliteIntegrationPluginZip],\n\t\t\t\t\t\t\t\t'sqlite-integration-plugin.zip'\n\t\t\t\t\t\t )\n\t\t\t\t\t\t: undefined,\n\t\t\t\tsapiName: 'cli',\n\t\t\t\tcreateFiles: {\n\t\t\t\t\t'/internal/shared/ca-bundle.crt':\n\t\t\t\t\t\trootCertificates.join('\\n'),\n\t\t\t\t},\n\t\t\t\tconstants,\n\t\t\t\tphpIniEntries: {\n\t\t\t\t\t'openssl.cafile': '/internal/shared/ca-bundle.crt',\n\t\t\t\t\tallow_url_fopen: '1',\n\t\t\t\t\tdisable_functions: '',\n\t\t\t\t},\n\t\t\t\thooks: {\n\t\t\t\t\tasync beforeWordPressFiles(php) {\n\t\t\t\t\t\tmountResources(php, mountsBeforeWpInstall);\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tcookieStore: internalCookieStore ? undefined : false,\n\t\t\t\tdataSqlPath,\n\t\t\t\tspawnHandler: sandboxedSpawnHandlerFactory,\n\t\t\t});\n\t\t\tthis.__internal_setRequestHandler(requestHandler);\n\n\t\t\tconst primaryPhp = await requestHandler.getPrimaryPhp();\n\t\t\tawait this.setPrimaryPHP(primaryPhp);\n\n\t\t\tmountResources(primaryPhp, mountsAfterWpInstall);\n\n\t\t\tsetApiReady();\n\t\t} catch (e) {\n\t\t\tsetAPIError(e as Error);\n\t\t\tthrow e;\n\t\t}\n\t}\n\n\tasync bootAsSecondaryWorker(args: WorkerBootOptions) {\n\t\treturn this.bootAsPrimaryWorker(args);\n\t}\n\n\t// Provide a named disposal method that can be invoked via comlink.\n\tasync dispose() {\n\t\tawait this[Symbol.asyncDispose]();\n\t}\n}\n\nconst phpChannel = new MessageChannel();\n\nconst [setApiReady, setAPIError] = exposeAPI(\n\tnew PlaygroundCliBlueprintV1Worker(new EmscriptenDownloadMonitor()),\n\tundefined,\n\tphpChannel.port1\n);\n\nparentPort!.postMessage(\n\t{\n\t\tcommand: 'worker-script-initialized',\n\t\tphpPort: phpChannel.port2,\n\t},\n\t[phpChannel.port2 as any]\n);\n"],"names":["mountResources","php","mounts","mount","createNodeFsMountHandler","tracePhpWasm","processId","format","args","sprintf","PlaygroundCliBlueprintV1Worker","PHPWorker","monitor","port","jspi","consumeAPI","consumeAPISync","absoluteUrl","mountsBeforeWpInstall","mountsAfterWpInstall","phpVersion","RecommendedPHPVersion","wordPressZip","sqliteIntegrationPluginZip","firstProcessId","processIdSpaceLength","dataSqlPath","followSymlinks","trace","internalCookieStore","withXdebug","nextProcessId","lastProcessId","constants","requestHandler","bootWordPress","loadNodeRuntime","rootCertificates","sandboxedSpawnHandlerFactory","primaryPhp","setApiReady","e","setAPIError","phpChannel","MessageChannel","exposeAPI","EmscriptenDownloadMonitor","parentPort"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const S=require("@php-wasm/node"),v=require("@php-wasm/progress"),r=require("@php-wasm/universal"),A=require("@php-wasm/util"),M=require("@wp-playground/common"),F=require("@wp-playground/wordpress"),D=require("tls"),E=require("wasm-feature-detect"),h=require("worker_threads"),P=require("./mounts-D7bhhGq3.cjs");function H(c,e,...s){console.log(performance.now().toFixed(6).padStart(15,"0"),c.toString().padStart(16,"0"),A.sprintf(e,...s))}class m extends r.PHPWorker{constructor(e){super(void 0,e),this.booted=!1}async useFileLockManager(e){await E.jspi()?this.fileLockManager=r.consumeAPI(e):this.fileLockManager=await r.consumeAPISync(e)}async bootAsPrimaryWorker({absoluteUrl:e,mountsBeforeWpInstall:s,mountsAfterWpInstall:w,phpVersion:y=M.RecommendedPHPVersion,wordPressZip:l,sqliteIntegrationPluginZip:d,firstProcessId:n,processIdSpaceLength:g,dataSqlPath:f,followSymlinks:b,trace:k,internalCookieStore:q,withXdebug:W}){if(this.booted)throw new Error("Playground already booted");this.booted=!0;let o=n;const _=n+g-1;try{const t={WP_DEBUG:!0,WP_DEBUG_LOG:!0,WP_DEBUG_DISPLAY:!1},u=await F.bootWordPress({siteUrl:e,createPhpRuntime:async()=>{const i=o;return o<_?o++:o=n,await S.loadNodeRuntime(y,{emscriptenOptions:{fileLockManager:this.fileLockManager,processId:i,trace:k?H:void 0},followSymlinks:b,withXdebug:W})},wordPressZip:l!==void 0?new File([l],"wordpress.zip"):void 0,sqliteIntegrationPluginZip:d!==void 0?new File([d],"sqlite-integration-plugin.zip"):void 0,sapiName:"cli",createFiles:{"/internal/shared/ca-bundle.crt":D.rootCertificates.join(`
2
+ `)},constants:t,phpIniEntries:{"openssl.cafile":"/internal/shared/ca-bundle.crt",allow_url_fopen:"1",disable_functions:""},hooks:{async beforeWordPressFiles(i){P.mountResources(i,s)}},cookieStore:q?void 0:!1,dataSqlPath:f,spawnHandler:r.sandboxedSpawnHandlerFactory});this.__internal_setRequestHandler(u);const p=await u.getPrimaryPhp();await this.setPrimaryPHP(p),P.mountResources(p,w),I()}catch(t){throw L(t),t}}async bootAsSecondaryWorker(e){return this.bootAsPrimaryWorker(e)}async dispose(){await this[Symbol.asyncDispose]()}}const a=new h.MessageChannel,[I,L]=r.exposeAPI(new m(new v.EmscriptenDownloadMonitor),void 0,a.port1);h.parentPort.postMessage({command:"worker-script-initialized",phpPort:a.port2},[a.port2]);exports.PlaygroundCliBlueprintV1Worker=m;
3
+ //# sourceMappingURL=worker-thread-v1.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker-thread-v1.cjs","sources":["../../../../packages/playground/cli/src/blueprints-v1/worker-thread-v1.ts"],"sourcesContent":["import type { FileLockManager } from '@php-wasm/node';\nimport { loadNodeRuntime } from '@php-wasm/node';\nimport { EmscriptenDownloadMonitor } from '@php-wasm/progress';\nimport type { RemoteAPI, SupportedPHPVersion } from '@php-wasm/universal';\nimport {\n\tPHPWorker,\n\tconsumeAPI,\n\tconsumeAPISync,\n\texposeAPI,\n\tsandboxedSpawnHandlerFactory,\n} from '@php-wasm/universal';\nimport { sprintf } from '@php-wasm/util';\nimport { RecommendedPHPVersion } from '@wp-playground/common';\nimport { bootWordPress } from '@wp-playground/wordpress';\nimport { rootCertificates } from 'tls';\nimport { jspi } from 'wasm-feature-detect';\nimport { MessageChannel, type MessagePort, parentPort } from 'worker_threads';\nimport { mountResources } from '../mounts';\n\nexport interface Mount {\n\thostPath: string;\n\tvfsPath: string;\n}\n\nexport type WorkerBootOptions = {\n\twpVersion?: string;\n\tphpVersion?: SupportedPHPVersion;\n\tabsoluteUrl: string;\n\tmountsBeforeWpInstall: Array<Mount>;\n\tmountsAfterWpInstall: Array<Mount>;\n\twordPressZip?: ArrayBuffer;\n\tsqliteIntegrationPluginZip?: ArrayBuffer;\n\tfirstProcessId: number;\n\tprocessIdSpaceLength: number;\n\tdataSqlPath?: string;\n\tfollowSymlinks: boolean;\n\ttrace: boolean;\n\t/**\n\t * When true, Playground will not send cookies to the client but will manage\n\t * them internally. This can be useful in environments that can't store cookies,\n\t * e.g. VS Code WebView.\n\t *\n\t * Default: false.\n\t */\n\tinternalCookieStore?: boolean;\n\twithXdebug?: boolean;\n};\n\n/**\n * Print trace messages from PHP-WASM.\n *\n * @param {number} processId - The process ID.\n * @param {string} format - The format string.\n * @param {...any} args - The arguments.\n */\nfunction tracePhpWasm(processId: number, format: string, ...args: any[]) {\n\t// eslint-disable-next-line no-console\n\tconsole.log(\n\t\tperformance.now().toFixed(6).padStart(15, '0'),\n\t\tprocessId.toString().padStart(16, '0'),\n\t\tsprintf(format, ...args)\n\t);\n}\n\nexport class PlaygroundCliBlueprintV1Worker extends PHPWorker {\n\tbooted = false;\n\tfileLockManager: RemoteAPI<FileLockManager> | FileLockManager | undefined;\n\n\tconstructor(monitor: EmscriptenDownloadMonitor) {\n\t\tsuper(undefined, monitor);\n\t}\n\n\t/**\n\t * Call this method before boot() to use file locking.\n\t *\n\t * This method is separate from boot() to simplify the related Comlink.transferHandlers\n\t * setup – if an argument is a MessagePort, we're transferring it, not copying it.\n\t *\n\t * @see comlink-sync.ts\n\t * @see phpwasm-emscripten-library-file-locking-for-node.js\n\t */\n\tasync useFileLockManager(port: MessagePort) {\n\t\tif (await jspi()) {\n\t\t\t/**\n\t\t\t * If JSPI is available, php.js supports both synchronous and asynchronous locking syscalls.\n\t\t\t * Web browsers, however, only support asynchronous message passing so let's use the\n\t\t\t * asynchronous API. Every method call will return a promise.\n\t\t\t *\n\t\t\t * @see comlink-sync.ts\n\t\t\t * @see phpwasm-emscripten-library-file-locking-for-node.js\n\t\t\t */\n\t\t\tthis.fileLockManager = consumeAPI<FileLockManager>(port);\n\t\t} else {\n\t\t\t/**\n\t\t\t * If JSPI is not available, php.js only supports synchronous locking syscalls.\n\t\t\t * Let's use the synchronous API. Every method call will block this thread\n\t\t\t * until the result is available.\n\t\t\t *\n\t\t\t * @see comlink-sync.ts\n\t\t\t * @see phpwasm-emscripten-library-file-locking-for-node.js\n\t\t\t */\n\t\t\tthis.fileLockManager = await consumeAPISync<FileLockManager>(port);\n\t\t}\n\t}\n\n\tasync bootAsPrimaryWorker({\n\t\tabsoluteUrl,\n\t\tmountsBeforeWpInstall,\n\t\tmountsAfterWpInstall,\n\t\tphpVersion = RecommendedPHPVersion,\n\t\twordPressZip,\n\t\tsqliteIntegrationPluginZip,\n\t\tfirstProcessId,\n\t\tprocessIdSpaceLength,\n\t\tdataSqlPath,\n\t\tfollowSymlinks,\n\t\ttrace,\n\t\tinternalCookieStore,\n\t\twithXdebug,\n\t}: WorkerBootOptions) {\n\t\tif (this.booted) {\n\t\t\tthrow new Error('Playground already booted');\n\t\t}\n\t\tthis.booted = true;\n\n\t\tlet nextProcessId = firstProcessId;\n\t\tconst lastProcessId = firstProcessId + processIdSpaceLength - 1;\n\n\t\ttry {\n\t\t\tconst constants: Record<string, string | number | boolean | null> =\n\t\t\t\t{\n\t\t\t\t\tWP_DEBUG: true,\n\t\t\t\t\tWP_DEBUG_LOG: true,\n\t\t\t\t\tWP_DEBUG_DISPLAY: false,\n\t\t\t\t};\n\n\t\t\tconst requestHandler = await bootWordPress({\n\t\t\t\tsiteUrl: absoluteUrl,\n\t\t\t\tcreatePhpRuntime: async () => {\n\t\t\t\t\tconst processId = nextProcessId;\n\n\t\t\t\t\tif (nextProcessId < lastProcessId) {\n\t\t\t\t\t\tnextProcessId++;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// We've reached the end of the process ID space. Start over.\n\t\t\t\t\t\tnextProcessId = firstProcessId;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn await loadNodeRuntime(phpVersion, {\n\t\t\t\t\t\temscriptenOptions: {\n\t\t\t\t\t\t\tfileLockManager: this.fileLockManager!,\n\t\t\t\t\t\t\tprocessId,\n\t\t\t\t\t\t\ttrace: trace ? tracePhpWasm : undefined,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tfollowSymlinks,\n\t\t\t\t\t\twithXdebug,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\twordPressZip:\n\t\t\t\t\twordPressZip !== undefined\n\t\t\t\t\t\t? new File([wordPressZip], 'wordpress.zip')\n\t\t\t\t\t\t: undefined,\n\t\t\t\tsqliteIntegrationPluginZip:\n\t\t\t\t\tsqliteIntegrationPluginZip !== undefined\n\t\t\t\t\t\t? new File(\n\t\t\t\t\t\t\t\t[sqliteIntegrationPluginZip],\n\t\t\t\t\t\t\t\t'sqlite-integration-plugin.zip'\n\t\t\t\t\t\t )\n\t\t\t\t\t\t: undefined,\n\t\t\t\tsapiName: 'cli',\n\t\t\t\tcreateFiles: {\n\t\t\t\t\t'/internal/shared/ca-bundle.crt':\n\t\t\t\t\t\trootCertificates.join('\\n'),\n\t\t\t\t},\n\t\t\t\tconstants,\n\t\t\t\tphpIniEntries: {\n\t\t\t\t\t'openssl.cafile': '/internal/shared/ca-bundle.crt',\n\t\t\t\t\tallow_url_fopen: '1',\n\t\t\t\t\tdisable_functions: '',\n\t\t\t\t},\n\t\t\t\thooks: {\n\t\t\t\t\tasync beforeWordPressFiles(php) {\n\t\t\t\t\t\tmountResources(php, mountsBeforeWpInstall);\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tcookieStore: internalCookieStore ? undefined : false,\n\t\t\t\tdataSqlPath,\n\t\t\t\tspawnHandler: sandboxedSpawnHandlerFactory,\n\t\t\t});\n\t\t\tthis.__internal_setRequestHandler(requestHandler);\n\n\t\t\tconst primaryPhp = await requestHandler.getPrimaryPhp();\n\t\t\tawait this.setPrimaryPHP(primaryPhp);\n\n\t\t\tmountResources(primaryPhp, mountsAfterWpInstall);\n\n\t\t\tsetApiReady();\n\t\t} catch (e) {\n\t\t\tsetAPIError(e as Error);\n\t\t\tthrow e;\n\t\t}\n\t}\n\n\tasync bootAsSecondaryWorker(args: WorkerBootOptions) {\n\t\treturn this.bootAsPrimaryWorker(args);\n\t}\n\n\t// Provide a named disposal method that can be invoked via comlink.\n\tasync dispose() {\n\t\tawait this[Symbol.asyncDispose]();\n\t}\n}\n\nconst phpChannel = new MessageChannel();\n\nconst [setApiReady, setAPIError] = exposeAPI(\n\tnew PlaygroundCliBlueprintV1Worker(new EmscriptenDownloadMonitor()),\n\tundefined,\n\tphpChannel.port1\n);\n\nparentPort!.postMessage(\n\t{\n\t\tcommand: 'worker-script-initialized',\n\t\tphpPort: phpChannel.port2,\n\t},\n\t[phpChannel.port2 as any]\n);\n"],"names":["tracePhpWasm","processId","format","args","sprintf","PlaygroundCliBlueprintV1Worker","PHPWorker","monitor","port","jspi","consumeAPI","consumeAPISync","absoluteUrl","mountsBeforeWpInstall","mountsAfterWpInstall","phpVersion","RecommendedPHPVersion","wordPressZip","sqliteIntegrationPluginZip","firstProcessId","processIdSpaceLength","dataSqlPath","followSymlinks","trace","internalCookieStore","withXdebug","nextProcessId","lastProcessId","constants","requestHandler","bootWordPress","loadNodeRuntime","rootCertificates","php","mountResources","sandboxedSpawnHandlerFactory","primaryPhp","setApiReady","e","setAPIError","phpChannel","MessageChannel","exposeAPI","EmscriptenDownloadMonitor","parentPort"],"mappings":"yYAuDA,SAASA,EAAaC,EAAmBC,KAAmBC,EAAa,CAEhE,QAAA,IACP,YAAY,MAAM,QAAQ,CAAC,EAAE,SAAS,GAAI,GAAG,EAC7CF,EAAU,SAAW,EAAA,SAAS,GAAI,GAAG,EACrCG,EAAA,QAAQF,EAAQ,GAAGC,CAAI,CACxB,CACD,CAEO,MAAME,UAAuCC,EAAAA,SAAU,CAI7D,YAAYC,EAAoC,CAC/C,MAAM,OAAWA,CAAO,EAJhB,KAAA,OAAA,EAAA,CAgBT,MAAM,mBAAmBC,EAAmB,CACvC,MAAMC,SASJ,KAAA,gBAAkBC,aAA4BF,CAAI,EAUlD,KAAA,gBAAkB,MAAMG,EAAA,eAAgCH,CAAI,CAClE,CAGD,MAAM,oBAAoB,CACzB,YAAAI,EACA,sBAAAC,EACA,qBAAAC,EACA,WAAAC,EAAaC,EAAA,sBACb,aAAAC,EACA,2BAAAC,EACA,eAAAC,EACA,qBAAAC,EACA,YAAAC,EACA,eAAAC,EACA,MAAAC,EACA,oBAAAC,EACA,WAAAC,CAAA,EACqB,CACrB,GAAI,KAAK,OACF,MAAA,IAAI,MAAM,2BAA2B,EAE5C,KAAK,OAAS,GAEd,IAAIC,EAAgBP,EACd,MAAAQ,EAAgBR,EAAiBC,EAAuB,EAE1D,GAAA,CACH,MAAMQ,EACL,CACC,SAAU,GACV,aAAc,GACd,iBAAkB,EACnB,EAEKC,EAAiB,MAAMC,gBAAc,CAC1C,QAASlB,EACT,iBAAkB,SAAY,CAC7B,MAAMX,EAAYyB,EAElB,OAAIA,EAAgBC,EACnBD,IAGgBA,EAAAP,EAGV,MAAMY,kBAAgBhB,EAAY,CACxC,kBAAmB,CAClB,gBAAiB,KAAK,gBACtB,UAAAd,EACA,MAAOsB,EAAQvB,EAAe,MAC/B,EACA,eAAAsB,EACA,WAAAG,CAAA,CACA,CACF,EACA,aACCR,IAAiB,OACd,IAAI,KAAK,CAACA,CAAY,EAAG,eAAe,EACxC,OACJ,2BACCC,IAA+B,OAC5B,IAAI,KACJ,CAACA,CAA0B,EAC3B,+BAEA,EAAA,OACJ,SAAU,MACV,YAAa,CACZ,iCACCc,EAAAA,iBAAiB,KAAK;AAAA,CAAI,CAC5B,EACA,UAAAJ,EACA,cAAe,CACd,iBAAkB,iCAClB,gBAAiB,IACjB,kBAAmB,EACpB,EACA,MAAO,CACN,MAAM,qBAAqBK,EAAK,CAC/BC,EAAA,eAAeD,EAAKpB,CAAqB,CAAA,CAE3C,EACA,YAAaW,EAAsB,OAAY,GAC/C,YAAAH,EACA,aAAcc,EAAAA,4BAAA,CACd,EACD,KAAK,6BAA6BN,CAAc,EAE1C,MAAAO,EAAa,MAAMP,EAAe,cAAc,EAChD,MAAA,KAAK,cAAcO,CAAU,EAEnCF,EAAA,eAAeE,EAAYtB,CAAoB,EAEnCuB,EAAA,QACJC,EAAG,CACX,MAAAC,EAAYD,CAAU,EAChBA,CAAA,CACP,CAGD,MAAM,sBAAsBnC,EAAyB,CAC7C,OAAA,KAAK,oBAAoBA,CAAI,CAAA,CAIrC,MAAM,SAAU,CACT,MAAA,KAAK,OAAO,YAAY,EAAE,CAAA,CAElC,CAEA,MAAMqC,EAAa,IAAIC,EAAAA,eAEjB,CAACJ,EAAaE,CAAW,EAAIG,EAAA,UAClC,IAAIrC,EAA+B,IAAIsC,EAAAA,yBAA2B,EAClE,OACAH,EAAW,KACZ,EAEAI,EAAAA,WAAY,YACX,CACC,QAAS,4BACT,QAASJ,EAAW,KACrB,EACA,CAACA,EAAW,KAAY,CACzB"}
@@ -0,0 +1,128 @@
1
+ import { loadNodeRuntime as W } from "@php-wasm/node";
2
+ import { EmscriptenDownloadMonitor as _ } from "@php-wasm/progress";
3
+ import { exposeAPI as A, PHPWorker as S, consumeAPI as v, consumeAPISync as M, sandboxedSpawnHandlerFactory as E } from "@php-wasm/universal";
4
+ import { sprintf as F } from "@php-wasm/util";
5
+ import { RecommendedPHPVersion as H } from "@wp-playground/common";
6
+ import { bootWordPress as I } from "@wp-playground/wordpress";
7
+ import { rootCertificates as L } from "tls";
8
+ import { jspi as x } from "wasm-feature-detect";
9
+ import { MessageChannel as D, parentPort as R } from "worker_threads";
10
+ import { m } from "./mounts-B-Qdcyyt.js";
11
+ function B(n, e, ...t) {
12
+ console.log(
13
+ performance.now().toFixed(6).padStart(15, "0"),
14
+ n.toString().padStart(16, "0"),
15
+ F(e, ...t)
16
+ );
17
+ }
18
+ class C extends S {
19
+ constructor(e) {
20
+ super(void 0, e), this.booted = !1;
21
+ }
22
+ /**
23
+ * Call this method before boot() to use file locking.
24
+ *
25
+ * This method is separate from boot() to simplify the related Comlink.transferHandlers
26
+ * setup – if an argument is a MessagePort, we're transferring it, not copying it.
27
+ *
28
+ * @see comlink-sync.ts
29
+ * @see phpwasm-emscripten-library-file-locking-for-node.js
30
+ */
31
+ async useFileLockManager(e) {
32
+ await x() ? this.fileLockManager = v(e) : this.fileLockManager = await M(e);
33
+ }
34
+ async bootAsPrimaryWorker({
35
+ absoluteUrl: e,
36
+ mountsBeforeWpInstall: t,
37
+ mountsAfterWpInstall: P,
38
+ phpVersion: f = H,
39
+ wordPressZip: c,
40
+ sqliteIntegrationPluginZip: p,
41
+ firstProcessId: i,
42
+ processIdSpaceLength: h,
43
+ dataSqlPath: u,
44
+ followSymlinks: w,
45
+ trace: y,
46
+ internalCookieStore: b,
47
+ withXdebug: g
48
+ }) {
49
+ if (this.booted)
50
+ throw new Error("Playground already booted");
51
+ this.booted = !0;
52
+ let o = i;
53
+ const k = i + h - 1;
54
+ try {
55
+ const r = {
56
+ WP_DEBUG: !0,
57
+ WP_DEBUG_LOG: !0,
58
+ WP_DEBUG_DISPLAY: !1
59
+ }, l = await I({
60
+ siteUrl: e,
61
+ createPhpRuntime: async () => {
62
+ const s = o;
63
+ return o < k ? o++ : o = i, await W(f, {
64
+ emscriptenOptions: {
65
+ fileLockManager: this.fileLockManager,
66
+ processId: s,
67
+ trace: y ? B : void 0
68
+ },
69
+ followSymlinks: w,
70
+ withXdebug: g
71
+ });
72
+ },
73
+ wordPressZip: c !== void 0 ? new File([c], "wordpress.zip") : void 0,
74
+ sqliteIntegrationPluginZip: p !== void 0 ? new File(
75
+ [p],
76
+ "sqlite-integration-plugin.zip"
77
+ ) : void 0,
78
+ sapiName: "cli",
79
+ createFiles: {
80
+ "/internal/shared/ca-bundle.crt": L.join(`
81
+ `)
82
+ },
83
+ constants: r,
84
+ phpIniEntries: {
85
+ "openssl.cafile": "/internal/shared/ca-bundle.crt",
86
+ allow_url_fopen: "1",
87
+ disable_functions: ""
88
+ },
89
+ hooks: {
90
+ async beforeWordPressFiles(s) {
91
+ m(s, t);
92
+ }
93
+ },
94
+ cookieStore: b ? void 0 : !1,
95
+ dataSqlPath: u,
96
+ spawnHandler: E
97
+ });
98
+ this.__internal_setRequestHandler(l);
99
+ const d = await l.getPrimaryPhp();
100
+ await this.setPrimaryPHP(d), m(d, P), G();
101
+ } catch (r) {
102
+ throw U(r), r;
103
+ }
104
+ }
105
+ async bootAsSecondaryWorker(e) {
106
+ return this.bootAsPrimaryWorker(e);
107
+ }
108
+ // Provide a named disposal method that can be invoked via comlink.
109
+ async dispose() {
110
+ await this[Symbol.asyncDispose]();
111
+ }
112
+ }
113
+ const a = new D(), [G, U] = A(
114
+ new C(new _()),
115
+ void 0,
116
+ a.port1
117
+ );
118
+ R.postMessage(
119
+ {
120
+ command: "worker-script-initialized",
121
+ phpPort: a.port2
122
+ },
123
+ [a.port2]
124
+ );
125
+ export {
126
+ C as PlaygroundCliBlueprintV1Worker
127
+ };
128
+ //# sourceMappingURL=worker-thread-v1.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker-thread-v1.js","sources":["../../../../packages/playground/cli/src/blueprints-v1/worker-thread-v1.ts"],"sourcesContent":["import type { FileLockManager } from '@php-wasm/node';\nimport { loadNodeRuntime } from '@php-wasm/node';\nimport { EmscriptenDownloadMonitor } from '@php-wasm/progress';\nimport type { RemoteAPI, SupportedPHPVersion } from '@php-wasm/universal';\nimport {\n\tPHPWorker,\n\tconsumeAPI,\n\tconsumeAPISync,\n\texposeAPI,\n\tsandboxedSpawnHandlerFactory,\n} from '@php-wasm/universal';\nimport { sprintf } from '@php-wasm/util';\nimport { RecommendedPHPVersion } from '@wp-playground/common';\nimport { bootWordPress } from '@wp-playground/wordpress';\nimport { rootCertificates } from 'tls';\nimport { jspi } from 'wasm-feature-detect';\nimport { MessageChannel, type MessagePort, parentPort } from 'worker_threads';\nimport { mountResources } from '../mounts';\n\nexport interface Mount {\n\thostPath: string;\n\tvfsPath: string;\n}\n\nexport type WorkerBootOptions = {\n\twpVersion?: string;\n\tphpVersion?: SupportedPHPVersion;\n\tabsoluteUrl: string;\n\tmountsBeforeWpInstall: Array<Mount>;\n\tmountsAfterWpInstall: Array<Mount>;\n\twordPressZip?: ArrayBuffer;\n\tsqliteIntegrationPluginZip?: ArrayBuffer;\n\tfirstProcessId: number;\n\tprocessIdSpaceLength: number;\n\tdataSqlPath?: string;\n\tfollowSymlinks: boolean;\n\ttrace: boolean;\n\t/**\n\t * When true, Playground will not send cookies to the client but will manage\n\t * them internally. This can be useful in environments that can't store cookies,\n\t * e.g. VS Code WebView.\n\t *\n\t * Default: false.\n\t */\n\tinternalCookieStore?: boolean;\n\twithXdebug?: boolean;\n};\n\n/**\n * Print trace messages from PHP-WASM.\n *\n * @param {number} processId - The process ID.\n * @param {string} format - The format string.\n * @param {...any} args - The arguments.\n */\nfunction tracePhpWasm(processId: number, format: string, ...args: any[]) {\n\t// eslint-disable-next-line no-console\n\tconsole.log(\n\t\tperformance.now().toFixed(6).padStart(15, '0'),\n\t\tprocessId.toString().padStart(16, '0'),\n\t\tsprintf(format, ...args)\n\t);\n}\n\nexport class PlaygroundCliBlueprintV1Worker extends PHPWorker {\n\tbooted = false;\n\tfileLockManager: RemoteAPI<FileLockManager> | FileLockManager | undefined;\n\n\tconstructor(monitor: EmscriptenDownloadMonitor) {\n\t\tsuper(undefined, monitor);\n\t}\n\n\t/**\n\t * Call this method before boot() to use file locking.\n\t *\n\t * This method is separate from boot() to simplify the related Comlink.transferHandlers\n\t * setup – if an argument is a MessagePort, we're transferring it, not copying it.\n\t *\n\t * @see comlink-sync.ts\n\t * @see phpwasm-emscripten-library-file-locking-for-node.js\n\t */\n\tasync useFileLockManager(port: MessagePort) {\n\t\tif (await jspi()) {\n\t\t\t/**\n\t\t\t * If JSPI is available, php.js supports both synchronous and asynchronous locking syscalls.\n\t\t\t * Web browsers, however, only support asynchronous message passing so let's use the\n\t\t\t * asynchronous API. Every method call will return a promise.\n\t\t\t *\n\t\t\t * @see comlink-sync.ts\n\t\t\t * @see phpwasm-emscripten-library-file-locking-for-node.js\n\t\t\t */\n\t\t\tthis.fileLockManager = consumeAPI<FileLockManager>(port);\n\t\t} else {\n\t\t\t/**\n\t\t\t * If JSPI is not available, php.js only supports synchronous locking syscalls.\n\t\t\t * Let's use the synchronous API. Every method call will block this thread\n\t\t\t * until the result is available.\n\t\t\t *\n\t\t\t * @see comlink-sync.ts\n\t\t\t * @see phpwasm-emscripten-library-file-locking-for-node.js\n\t\t\t */\n\t\t\tthis.fileLockManager = await consumeAPISync<FileLockManager>(port);\n\t\t}\n\t}\n\n\tasync bootAsPrimaryWorker({\n\t\tabsoluteUrl,\n\t\tmountsBeforeWpInstall,\n\t\tmountsAfterWpInstall,\n\t\tphpVersion = RecommendedPHPVersion,\n\t\twordPressZip,\n\t\tsqliteIntegrationPluginZip,\n\t\tfirstProcessId,\n\t\tprocessIdSpaceLength,\n\t\tdataSqlPath,\n\t\tfollowSymlinks,\n\t\ttrace,\n\t\tinternalCookieStore,\n\t\twithXdebug,\n\t}: WorkerBootOptions) {\n\t\tif (this.booted) {\n\t\t\tthrow new Error('Playground already booted');\n\t\t}\n\t\tthis.booted = true;\n\n\t\tlet nextProcessId = firstProcessId;\n\t\tconst lastProcessId = firstProcessId + processIdSpaceLength - 1;\n\n\t\ttry {\n\t\t\tconst constants: Record<string, string | number | boolean | null> =\n\t\t\t\t{\n\t\t\t\t\tWP_DEBUG: true,\n\t\t\t\t\tWP_DEBUG_LOG: true,\n\t\t\t\t\tWP_DEBUG_DISPLAY: false,\n\t\t\t\t};\n\n\t\t\tconst requestHandler = await bootWordPress({\n\t\t\t\tsiteUrl: absoluteUrl,\n\t\t\t\tcreatePhpRuntime: async () => {\n\t\t\t\t\tconst processId = nextProcessId;\n\n\t\t\t\t\tif (nextProcessId < lastProcessId) {\n\t\t\t\t\t\tnextProcessId++;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// We've reached the end of the process ID space. Start over.\n\t\t\t\t\t\tnextProcessId = firstProcessId;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn await loadNodeRuntime(phpVersion, {\n\t\t\t\t\t\temscriptenOptions: {\n\t\t\t\t\t\t\tfileLockManager: this.fileLockManager!,\n\t\t\t\t\t\t\tprocessId,\n\t\t\t\t\t\t\ttrace: trace ? tracePhpWasm : undefined,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tfollowSymlinks,\n\t\t\t\t\t\twithXdebug,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\twordPressZip:\n\t\t\t\t\twordPressZip !== undefined\n\t\t\t\t\t\t? new File([wordPressZip], 'wordpress.zip')\n\t\t\t\t\t\t: undefined,\n\t\t\t\tsqliteIntegrationPluginZip:\n\t\t\t\t\tsqliteIntegrationPluginZip !== undefined\n\t\t\t\t\t\t? new File(\n\t\t\t\t\t\t\t\t[sqliteIntegrationPluginZip],\n\t\t\t\t\t\t\t\t'sqlite-integration-plugin.zip'\n\t\t\t\t\t\t )\n\t\t\t\t\t\t: undefined,\n\t\t\t\tsapiName: 'cli',\n\t\t\t\tcreateFiles: {\n\t\t\t\t\t'/internal/shared/ca-bundle.crt':\n\t\t\t\t\t\trootCertificates.join('\\n'),\n\t\t\t\t},\n\t\t\t\tconstants,\n\t\t\t\tphpIniEntries: {\n\t\t\t\t\t'openssl.cafile': '/internal/shared/ca-bundle.crt',\n\t\t\t\t\tallow_url_fopen: '1',\n\t\t\t\t\tdisable_functions: '',\n\t\t\t\t},\n\t\t\t\thooks: {\n\t\t\t\t\tasync beforeWordPressFiles(php) {\n\t\t\t\t\t\tmountResources(php, mountsBeforeWpInstall);\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tcookieStore: internalCookieStore ? undefined : false,\n\t\t\t\tdataSqlPath,\n\t\t\t\tspawnHandler: sandboxedSpawnHandlerFactory,\n\t\t\t});\n\t\t\tthis.__internal_setRequestHandler(requestHandler);\n\n\t\t\tconst primaryPhp = await requestHandler.getPrimaryPhp();\n\t\t\tawait this.setPrimaryPHP(primaryPhp);\n\n\t\t\tmountResources(primaryPhp, mountsAfterWpInstall);\n\n\t\t\tsetApiReady();\n\t\t} catch (e) {\n\t\t\tsetAPIError(e as Error);\n\t\t\tthrow e;\n\t\t}\n\t}\n\n\tasync bootAsSecondaryWorker(args: WorkerBootOptions) {\n\t\treturn this.bootAsPrimaryWorker(args);\n\t}\n\n\t// Provide a named disposal method that can be invoked via comlink.\n\tasync dispose() {\n\t\tawait this[Symbol.asyncDispose]();\n\t}\n}\n\nconst phpChannel = new MessageChannel();\n\nconst [setApiReady, setAPIError] = exposeAPI(\n\tnew PlaygroundCliBlueprintV1Worker(new EmscriptenDownloadMonitor()),\n\tundefined,\n\tphpChannel.port1\n);\n\nparentPort!.postMessage(\n\t{\n\t\tcommand: 'worker-script-initialized',\n\t\tphpPort: phpChannel.port2,\n\t},\n\t[phpChannel.port2 as any]\n);\n"],"names":["tracePhpWasm","processId","format","args","sprintf","PlaygroundCliBlueprintV1Worker","PHPWorker","monitor","port","jspi","consumeAPI","consumeAPISync","absoluteUrl","mountsBeforeWpInstall","mountsAfterWpInstall","phpVersion","RecommendedPHPVersion","wordPressZip","sqliteIntegrationPluginZip","firstProcessId","processIdSpaceLength","dataSqlPath","followSymlinks","trace","internalCookieStore","withXdebug","nextProcessId","lastProcessId","constants","requestHandler","bootWordPress","loadNodeRuntime","rootCertificates","php","mountResources","sandboxedSpawnHandlerFactory","primaryPhp","setApiReady","e","setAPIError","phpChannel","MessageChannel","exposeAPI","EmscriptenDownloadMonitor","parentPort"],"mappings":"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"}
@@ -0,0 +1,429 @@
1
+ import { logger as P, errorLogPath as $ } from "@php-wasm/logger";
2
+ import { createNodeFsMountHandler as _, loadNodeRuntime as v } from "@php-wasm/node";
3
+ import { EmscriptenDownloadMonitor as x } from "@php-wasm/progress";
4
+ import { exposeAPI as W, PHPWorker as S, consumeAPI as k, consumeAPISync as M, PHPResponse as R, PHPExecutionFailureError as H, sandboxedSpawnHandlerFactory as A } from "@php-wasm/universal";
5
+ import { phpVar as y, sprintf as B } from "@php-wasm/util";
6
+ import { bootRequestHandler as E } from "@wp-playground/wordpress";
7
+ import { existsSync as T } from "fs";
8
+ import w from "path";
9
+ import { rootCertificates as F } from "tls";
10
+ import { MessageChannel as O, parentPort as j } from "worker_threads";
11
+ import { jspi as C } from "wasm-feature-detect";
12
+ async function L() {
13
+ let t = null;
14
+ const e = (await import("./blueprints-DLntJtVr.js")).default;
15
+ if (typeof process < "u" && process.versions?.node) {
16
+ let s = e;
17
+ s.startsWith("/@fs/") && (s = s.slice(4)), s.startsWith("file://") && (s = s.slice(7));
18
+ const { readFile: o } = await import("node:fs/promises");
19
+ t = await o(s);
20
+ } else
21
+ t = await (await fetch(e)).blob();
22
+ return new File([t], "blueprints.phar", {
23
+ type: "application/zip"
24
+ });
25
+ }
26
+ function q(t) {
27
+ if (typeof t == "object" && "type" in t && ["inline-file", "file-reference"].includes(t.type))
28
+ return t;
29
+ if (!t)
30
+ return {
31
+ type: "inline-file",
32
+ contents: "{}"
33
+ };
34
+ if (typeof t != "string")
35
+ return {
36
+ type: "inline-file",
37
+ contents: JSON.stringify(t)
38
+ };
39
+ try {
40
+ return JSON.parse(t), {
41
+ type: "inline-file",
42
+ contents: t
43
+ };
44
+ } catch {
45
+ return {
46
+ type: "file-reference",
47
+ reference: t
48
+ };
49
+ }
50
+ }
51
+ async function D(t) {
52
+ const e = t.cliArgs || [];
53
+ for (const i of e)
54
+ if (i.startsWith("--site-path="))
55
+ throw new Error(
56
+ "The --site-path CLI argument must not be provided. In Playground, it is always set to /wordpress."
57
+ );
58
+ e.push("--site-path=/wordpress"), e.find((i) => i.startsWith("--db-engine=")) || e.push("--db-engine=sqlite");
59
+ const o = t.php, u = t?.onMessage || (() => {
60
+ }), f = await L();
61
+ o.writeFile(
62
+ "/tmp/blueprints.phar",
63
+ new Uint8Array(await f.arrayBuffer())
64
+ );
65
+ const c = q(
66
+ t.blueprint
67
+ );
68
+ let n = "";
69
+ switch (c.type) {
70
+ case "inline-file":
71
+ o.writeFile(
72
+ "/tmp/blueprint.json",
73
+ c.contents
74
+ ), n = "/tmp/blueprint.json";
75
+ break;
76
+ case "file-reference":
77
+ n = c.reference;
78
+ break;
79
+ }
80
+ const l = await o.onMessage(async (i) => {
81
+ try {
82
+ const r = typeof i == "string" ? JSON.parse(i) : i;
83
+ if (!r)
84
+ return;
85
+ await new Promise((d) => setTimeout(d, 0)), r.type.startsWith("blueprint.") && await u(r);
86
+ } catch (r) {
87
+ P.warn("Failed to parse message as JSON:", i, r);
88
+ }
89
+ });
90
+ await o?.writeFile(
91
+ "/tmp/run-blueprints.php",
92
+ `<?php
93
+ function playground_http_client_factory() {
94
+ return new WordPress\\HttpClient\\Client([
95
+ // sockets transport is somehow faster than curl in Playground. Maybe
96
+ // it uses a larger chunk size?
97
+ 'transport' => 'sockets',
98
+ ]);
99
+ }
100
+ playground_add_filter('blueprint.http_client', 'playground_http_client_factory');
101
+
102
+ function playground_on_blueprint_target_resolved() {
103
+ post_message_to_js(json_encode([
104
+ 'type' => 'blueprint.target_resolved',
105
+ ]));
106
+ }
107
+ playground_add_filter('blueprint.target_resolved', 'playground_on_blueprint_target_resolved');
108
+
109
+ playground_add_filter('blueprint.resolved', 'playground_on_blueprint_resolved');
110
+ function playground_on_blueprint_resolved($blueprint) {
111
+ $additional_blueprint_steps = json_decode(${y(
112
+ JSON.stringify(t.blueprintOverrides?.additionalSteps || [])
113
+ )}, true);
114
+ if(count($additional_blueprint_steps) > 0) {
115
+ $blueprint['additionalStepsAfterExecution'] = array_merge(
116
+ $blueprint['additionalStepsAfterExecution'] ?? [],
117
+ $additional_blueprint_steps
118
+ );
119
+ }
120
+
121
+ $wp_version_override = json_decode(${y(
122
+ JSON.stringify(t.blueprintOverrides?.wordpressVersion || null)
123
+ )}, true);
124
+ if($wp_version_override) {
125
+ $blueprint['wordpressVersion'] = $wp_version_override;
126
+ }
127
+ return $blueprint;
128
+ }
129
+
130
+ function playground_progress_reporter() {
131
+ class PlaygroundProgressReporter implements ProgressReporter {
132
+
133
+ public function reportProgress(float $progress, string $caption): void {
134
+ $this->writeJsonMessage([
135
+ 'type' => 'blueprint.progress',
136
+ 'progress' => round($progress, 2),
137
+ 'caption' => $caption
138
+ ]);
139
+ }
140
+
141
+ public function reportError(string $message, ?Throwable $exception = null): void {
142
+ $errorData = [
143
+ 'type' => 'blueprint.error',
144
+ 'message' => $message
145
+ ];
146
+
147
+ if ($exception) {
148
+ $errorData['details'] = [
149
+ 'exception' => get_class($exception),
150
+ 'message' => $exception->getMessage(),
151
+ 'file' => $exception->getFile(),
152
+ 'line' => $exception->getLine(),
153
+ 'trace' => $exception->getTraceAsString()
154
+ ];
155
+ }
156
+
157
+ $this->writeJsonMessage($errorData);
158
+ }
159
+
160
+ public function reportCompletion(string $message): void {
161
+ $this->writeJsonMessage([
162
+ 'type' => 'blueprint.completion',
163
+ 'message' => $message
164
+ ]);
165
+ }
166
+
167
+ public function close(): void {}
168
+
169
+ private function writeJsonMessage(array $data): void {
170
+ post_message_to_js(json_encode($data));
171
+ }
172
+ }
173
+ return new PlaygroundProgressReporter();
174
+ }
175
+ playground_add_filter('blueprint.progress_reporter', 'playground_progress_reporter');
176
+ require( "/tmp/blueprints.phar" );
177
+ `
178
+ );
179
+ const a = await o.cli([
180
+ "/internal/shared/bin/php",
181
+ "/tmp/run-blueprints.php",
182
+ "exec",
183
+ n,
184
+ ...e
185
+ ]);
186
+ return a.finished.finally(l), a;
187
+ }
188
+ async function h(t, e) {
189
+ for (const s of e)
190
+ try {
191
+ t.mkdir(s.vfsPath), await t.mount(
192
+ s.vfsPath,
193
+ _(s.hostPath)
194
+ );
195
+ } catch {
196
+ p.stderr(
197
+ `\x1B[31m\x1B[1mError mounting path ${s.hostPath} at ${s.vfsPath}\x1B[0m
198
+ `
199
+ ), process.exit(1);
200
+ }
201
+ }
202
+ function I(t, e, ...s) {
203
+ console.log(
204
+ performance.now().toFixed(6).padStart(15, "0"),
205
+ t.toString().padStart(16, "0"),
206
+ B(e, ...s)
207
+ );
208
+ }
209
+ Object.defineProperty(process.stdout, "isTTY", { value: !0 });
210
+ Object.defineProperty(process.stderr, "isTTY", { value: !0 });
211
+ const p = {
212
+ lastWriteWasProgress: !1,
213
+ progress(t) {
214
+ process.stdout.isTTY ? (p.lastWriteWasProgress || process.stdout.write(`
215
+ `), process.stdout.write("\r\x1B[K" + t), p.lastWriteWasProgress = !0) : console.log(t);
216
+ },
217
+ stdout(t) {
218
+ p.lastWriteWasProgress && (process.stdout.write(`
219
+ `), p.lastWriteWasProgress = !1), process.stdout.write(t);
220
+ },
221
+ stderr(t) {
222
+ p.lastWriteWasProgress && (process.stdout.write(`
223
+ `), p.lastWriteWasProgress = !1), process.stderr.write(t);
224
+ }
225
+ };
226
+ class J extends S {
227
+ constructor(e) {
228
+ super(void 0, e), this.booted = !1;
229
+ }
230
+ /**
231
+ * Call this method before boot() to use file locking.
232
+ *
233
+ * This method is separate from boot() to simplify the related Comlink.transferHandlers
234
+ * setup – if an argument is a MessagePort, we're transferring it, not copying it.
235
+ *
236
+ * @see comlink-sync.ts
237
+ * @see phpwasm-emscripten-library-file-locking-for-node.js
238
+ */
239
+ async useFileLockManager(e) {
240
+ await C() ? this.fileLockManager = k(e) : this.fileLockManager = await M(e);
241
+ }
242
+ async bootAsPrimaryWorker(e) {
243
+ await this.bootRequestHandler(e);
244
+ const s = this.__internal_getPHP();
245
+ if (await h(s, e["mount-before-install"] || []), e.mode === "mount-only") {
246
+ await h(s, e.mount || []);
247
+ return;
248
+ }
249
+ await this.runBlueprintV2(e);
250
+ }
251
+ async bootAsSecondaryWorker(e) {
252
+ await this.bootRequestHandler(e);
253
+ const s = this.__internal_getPHP();
254
+ await h(s, e["mount-before-install"] || []), await h(s, e.mount || []);
255
+ }
256
+ async runBlueprintV2(e) {
257
+ const s = this.__internal_getRequestHandler(), { php: o, reap: u } = await s.processManager.acquirePHPInstance({
258
+ considerPrimary: !1
259
+ }), f = this.__internal_getPHP();
260
+ let c = () => {
261
+ };
262
+ if (typeof e.blueprint == "string") {
263
+ const n = w.resolve(process.cwd(), e.blueprint);
264
+ T(n) && (f.mkdir("/internal/shared/cwd"), c = await f.mount(
265
+ "/internal/shared/cwd",
266
+ _(w.dirname(n))
267
+ ), e.blueprint = w.join(
268
+ "/internal/shared/cwd",
269
+ w.basename(e.blueprint)
270
+ ));
271
+ }
272
+ try {
273
+ const l = [
274
+ "mode",
275
+ "db-engine",
276
+ "db-host",
277
+ "db-user",
278
+ "db-pass",
279
+ "db-name",
280
+ "db-path",
281
+ "truncate-new-site-directory",
282
+ "allow"
283
+ ].filter((r) => r in e).map((r) => `--${r}=${e[r]}`);
284
+ l.push(`--site-url=${e.siteUrl}`);
285
+ let a = !1;
286
+ const i = await D({
287
+ php: o,
288
+ blueprint: e.blueprint,
289
+ blueprintOverrides: {
290
+ additionalSteps: e["additional-blueprint-steps"],
291
+ wordpressVersion: e.wp
292
+ },
293
+ cliArgs: l,
294
+ onMessage: async (r) => {
295
+ switch (r.type) {
296
+ case "blueprint.target_resolved": {
297
+ a || (await h(
298
+ f,
299
+ e.mount || []
300
+ ), a = !0);
301
+ break;
302
+ }
303
+ case "blueprint.progress": {
304
+ const d = `${r.caption.trim()} – ${r.progress.toFixed(
305
+ 2
306
+ )}%`;
307
+ p.progress(d);
308
+ break;
309
+ }
310
+ case "blueprint.error": {
311
+ const d = "\x1B[31m", g = "\x1B[1m", m = "\x1B[0m";
312
+ e.debug && r.details ? p.stderr(
313
+ `${d}${g}Fatal error:${m} Uncaught ${r.details.exception}: ${r.details.message}
314
+ at ${r.details.file}:${r.details.line}
315
+ ` + (r.details.trace ? r.details.trace + `
316
+ ` : "")
317
+ ) : p.stderr(
318
+ `${d}${g}Error:${m} ${r.message}
319
+ `
320
+ );
321
+ break;
322
+ }
323
+ }
324
+ }
325
+ });
326
+ if (e.debug && (i.stdout.pipeTo(
327
+ new WritableStream({
328
+ write(r) {
329
+ process.stdout.write(r);
330
+ }
331
+ })
332
+ ), i.stderr.pipeTo(
333
+ new WritableStream({
334
+ write(r) {
335
+ process.stderr.write(r);
336
+ }
337
+ })
338
+ )), await i.finished, await i.exitCode !== 0) {
339
+ const r = await R.fromStreamedResponse(
340
+ i
341
+ );
342
+ throw new H(
343
+ `PHP.run() failed with exit code ${r.exitCode}.`,
344
+ r,
345
+ "request"
346
+ );
347
+ }
348
+ } catch (n) {
349
+ let l = "";
350
+ try {
351
+ l = o.readFileAsText($);
352
+ } catch {
353
+ }
354
+ throw n.phpLogs = l, n;
355
+ } finally {
356
+ u(), c();
357
+ }
358
+ }
359
+ async bootRequestHandler({
360
+ siteUrl: e,
361
+ allow: s,
362
+ php: o,
363
+ firstProcessId: u,
364
+ processIdSpaceLength: f,
365
+ trace: c
366
+ }) {
367
+ if (this.booted)
368
+ throw new Error("Playground already booted");
369
+ this.booted = !0;
370
+ let n = u;
371
+ const l = u + f - 1;
372
+ try {
373
+ const a = {
374
+ WP_DEBUG: !0,
375
+ WP_DEBUG_LOG: !0,
376
+ WP_DEBUG_DISPLAY: !1
377
+ }, i = await E({
378
+ siteUrl: e,
379
+ createPhpRuntime: async () => {
380
+ const d = n;
381
+ return n < l ? n++ : n = u, await v(o, {
382
+ emscriptenOptions: {
383
+ fileLockManager: this.fileLockManager,
384
+ processId: d,
385
+ trace: c ? I : void 0,
386
+ ENV: {
387
+ DOCROOT: "/wordpress"
388
+ }
389
+ },
390
+ followSymlinks: s?.includes("follow-symlinks")
391
+ });
392
+ },
393
+ sapiName: "cli",
394
+ createFiles: {
395
+ "/internal/shared/ca-bundle.crt": F.join(`
396
+ `)
397
+ },
398
+ constants: a,
399
+ phpIniEntries: {
400
+ "openssl.cafile": "/internal/shared/ca-bundle.crt"
401
+ },
402
+ cookieStore: !1,
403
+ spawnHandler: A
404
+ });
405
+ this.__internal_setRequestHandler(i);
406
+ const r = await i.getPrimaryPhp();
407
+ await this.setPrimaryPHP(r), N();
408
+ } catch (a) {
409
+ throw V(a), a;
410
+ }
411
+ }
412
+ // Provide a named disposal method that can be invoked via comlink.
413
+ async dispose() {
414
+ await this[Symbol.asyncDispose]();
415
+ }
416
+ }
417
+ const b = new O(), [N, V] = W(
418
+ new J(new x()),
419
+ void 0,
420
+ b.port1
421
+ );
422
+ j.postMessage(
423
+ {
424
+ command: "worker-script-initialized",
425
+ phpPort: b.port2
426
+ },
427
+ [b.port2]
428
+ );
429
+ //# sourceMappingURL=worker-thread-v2-Pfv6UYF4.js.map