@wp-playground/cli 3.0.4 → 3.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +12 -12
- package/worker-thread-v1.cjs +2 -2
- package/worker-thread-v1.cjs.map +1 -1
- package/worker-thread-v1.js +60 -56
- package/worker-thread-v1.js.map +1 -1
- package/worker-thread-v2.cjs +3 -3
- package/worker-thread-v2.cjs.map +1 -1
- package/worker-thread-v2.js +35 -32
- package/worker-thread-v2.js.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wp-playground/cli",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.5",
|
|
4
4
|
"description": "WordPress Playground CLI",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"bin": {
|
|
35
35
|
"wp-playground-cli": "wp-playground.js"
|
|
36
36
|
},
|
|
37
|
-
"gitHead": "
|
|
37
|
+
"gitHead": "25f366144172f93d8500031c612bf197638fe78c",
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"@zip.js/zip.js": "2.7.57",
|
|
40
40
|
"ajv": "8.12.0",
|
|
@@ -59,16 +59,16 @@
|
|
|
59
59
|
"ws": "8.18.1",
|
|
60
60
|
"xml2js": "0.6.2",
|
|
61
61
|
"yargs": "17.7.2",
|
|
62
|
-
"@php-wasm/logger": "3.0.
|
|
63
|
-
"@php-wasm/progress": "3.0.
|
|
64
|
-
"@php-wasm/universal": "3.0.
|
|
65
|
-
"@wp-playground/blueprints": "3.0.
|
|
66
|
-
"@wp-playground/common": "3.0.
|
|
67
|
-
"@wp-playground/wordpress": "3.0.
|
|
68
|
-
"@php-wasm/node": "3.0.
|
|
69
|
-
"@php-wasm/util": "3.0.
|
|
70
|
-
"@wp-playground/storage": "3.0.
|
|
71
|
-
"@php-wasm/xdebug-bridge": "3.0.
|
|
62
|
+
"@php-wasm/logger": "3.0.5",
|
|
63
|
+
"@php-wasm/progress": "3.0.5",
|
|
64
|
+
"@php-wasm/universal": "3.0.5",
|
|
65
|
+
"@wp-playground/blueprints": "3.0.5",
|
|
66
|
+
"@wp-playground/common": "3.0.5",
|
|
67
|
+
"@wp-playground/wordpress": "3.0.5",
|
|
68
|
+
"@php-wasm/node": "3.0.5",
|
|
69
|
+
"@php-wasm/util": "3.0.5",
|
|
70
|
+
"@wp-playground/storage": "3.0.5",
|
|
71
|
+
"@php-wasm/xdebug-bridge": "3.0.5"
|
|
72
72
|
},
|
|
73
73
|
"overrides": {
|
|
74
74
|
"rollup": "^4.34.6",
|
package/worker-thread-v1.cjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
2
|
-
`)},constants:
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const H=require("@php-wasm/node"),E=require("@php-wasm/progress"),s=require("@php-wasm/universal"),O=require("@php-wasm/util"),A=require("@wp-playground/common"),_=require("@wp-playground/wordpress"),C=require("tls"),D=require("wasm-feature-detect"),I=require("worker_threads"),c=require("./mounts-BJFrPHGW.cjs"),F=require("@php-wasm/logger");function S(l,e,...n){console.log(performance.now().toFixed(6).padStart(15,"0"),l.toString().padStart(16,"0"),O.sprintf(e,...n))}class M extends s.PHPWorker{constructor(e){super(void 0,e),this.booted=!1}async useFileLockManager(e){await D.jspi()?this.fileLockManager=s.consumeAPI(e):this.fileLockManager=await s.consumeAPISync(e)}async bootAsPrimaryWorker({siteUrl:e,mountsBeforeWpInstall:n,mountsAfterWpInstall:d,phpVersion:a=A.RecommendedPHPVersion,wordPressZip:u,sqliteIntegrationPluginZip:p,firstProcessId:i,processIdSpaceLength:m,dataSqlPath:y,followSymlinks:o,trace:g,internalCookieStore:t,withXdebug:f,nativeInternalDirPath:r}){if(this.booted)throw new Error("Playground already booted");this.booted=!0;let w=i;const L=i+m-1;try{const P={WP_DEBUG:!0,WP_DEBUG_LOG:!0,WP_DEBUG_DISPLAY:!1};let q=!1;const k=await _.bootWordPressAndRequestHandler({siteUrl:e,createPhpRuntime:async()=>{const h=w;return w<L?w++:w=i,await H.loadNodeRuntime(a,{emscriptenOptions:{fileLockManager:this.fileLockManager,processId:h,trace:g?S:void 0,phpWasmInitOptions:{nativeInternalDirPath:r}},followSymlinks:o,withXdebug:f})},wordPressZip:u!==void 0?new File([u],"wordpress.zip"):void 0,sqliteIntegrationPluginZip:p!==void 0?new File([p],"sqlite-integration-plugin.zip"):void 0,sapiName:"cli",createFiles:{"/internal/shared/ca-bundle.crt":C.rootCertificates.join(`
|
|
2
|
+
`)},constants:P,phpIniEntries:{"openssl.cafile":"/internal/shared/ca-bundle.crt",allow_url_fopen:"1",disable_functions:""},cookieStore:t?void 0:!1,dataSqlPath:y,spawnHandler:s.sandboxedSpawnHandlerFactory,async onPHPInstanceCreated(h){await c.mountResources(h,n),q&&await c.mountResources(h,d)}});this.__internal_setRequestHandler(k),q=!0;const R=await k.getPrimaryPhp();await this.setPrimaryPHP(R),await c.mountResources(R,d),W()}catch(P){throw v(P),P}}async bootAsSecondaryWorker(e){await this.bootRequestHandler(e)}async bootRequestHandler({siteUrl:e,allow:n,phpVersion:d,firstProcessId:a,processIdSpaceLength:u,trace:p,nativeInternalDirPath:i,mountsBeforeWpInstall:m,mountsAfterWpInstall:y}){if(this.booted)throw new Error("Playground already booted");this.booted=!0;let o=a;const g=a+u-1;try{const t=await _.bootRequestHandler({siteUrl:e,createPhpRuntime:async()=>{const r=o;return o<g?o++:o=a,await H.loadNodeRuntime(d,{emscriptenOptions:{fileLockManager:this.fileLockManager,processId:r,trace:p?S:void 0,ENV:{DOCROOT:"/wordpress"},phpWasmInitOptions:{nativeInternalDirPath:i}},followSymlinks:n?.includes("follow-symlinks")})},onPHPInstanceCreated:async r=>{this.registerWorkerListeners(r),await c.mountResources(r,m),await c.mountResources(r,y)},sapiName:"cli",cookieStore:!1,spawnHandler:s.sandboxedSpawnHandlerFactory});this.__internal_setRequestHandler(t);const f=await t.getPrimaryPhp();await this.setPrimaryPHP(f),W()}catch(t){throw v(t),t}}async dispose(){await this[Symbol.asyncDispose]()}}process.on("unhandledRejection",l=>{F.logger.error("Unhandled rejection:",l)});const b=new I.MessageChannel,[W,v]=s.exposeAPI(new M(new E.EmscriptenDownloadMonitor),void 0,b.port1);I.parentPort?.postMessage({command:"worker-script-initialized",phpPort:b.port2},[b.port2]);exports.PlaygroundCliBlueprintV1Worker=M;
|
|
3
3
|
//# sourceMappingURL=worker-thread-v1.cjs.map
|
package/worker-thread-v1.cjs.map
CHANGED
|
@@ -1 +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 {\n\tbootRequestHandler,\n\tbootWordPressAndRequestHandler,\n} 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\tphpVersion: SupportedPHPVersion;\n\tsiteUrl: string;\n\tmountsBeforeWpInstall: Array<Mount>;\n\tmountsAfterWpInstall: Array<Mount>;\n\tfirstProcessId: number;\n\tprocessIdSpaceLength: number;\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\tnativeInternalDirPath: string;\n};\n\nexport type PrimaryWorkerBootOptions = WorkerBootOptions & {\n\twpVersion?: string;\n\twordPressZip?: ArrayBuffer;\n\tsqliteIntegrationPluginZip?: ArrayBuffer;\n\tdataSqlPath?: string;\n};\n\ninterface WorkerBootRequestHandlerOptions {\n\tsiteUrl: string;\n\tallow?: string;\n\tphpVersion: SupportedPHPVersion;\n\tfirstProcessId: number;\n\tprocessIdSpaceLength: number;\n\ttrace: boolean;\n\tnativeInternalDirPath: string;\n\tmountsBeforeWpInstall: Array<Mount>;\n\tmountsAfterWpInstall: Array<Mount>;\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\tsiteUrl,\n\t\tmountsBeforeWpInstall,\n\t\tmountsAfterWpInstall,\n\t\tphpVersion: php = 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\tnativeInternalDirPath,\n\t}: PrimaryWorkerBootOptions) {\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\t\t\tlet wordpressBooted = false;\n\t\t\tconst requestHandler = await bootWordPressAndRequestHandler({\n\t\t\t\tsiteUrl,\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(php, {\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\tphpWasmInitOptions: { nativeInternalDirPath },\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\tcookieStore: internalCookieStore ? undefined : false,\n\t\t\t\tdataSqlPath,\n\t\t\t\tspawnHandler: sandboxedSpawnHandlerFactory,\n\t\t\t\tasync onPHPInstanceCreated(php) {\n\t\t\t\t\tawait mountResources(php, mountsBeforeWpInstall);\n\t\t\t\t\tif (wordpressBooted) {\n\t\t\t\t\t\tawait mountResources(php, mountsAfterWpInstall);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t});\n\t\t\tthis.__internal_setRequestHandler(requestHandler);\n\t\t\twordpressBooted = true;\n\n\t\t\tconst primaryPhp = await requestHandler.getPrimaryPhp();\n\t\t\tawait this.setPrimaryPHP(primaryPhp);\n\n\t\t\t// The primary PHP instance is persistent, so we need to apply\n\t\t\t// post-install mounts now that WordPress has been booted.\n\t\t\t// All secondary PHP instances created after WP boot will get\n\t\t\t// these mounts automatically.\n\t\t\tawait mountResources(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\tawait this.bootRequestHandler(args);\n\t}\n\n\tasync bootRequestHandler({\n\t\tsiteUrl,\n\t\tallow,\n\t\tphpVersion,\n\t\tfirstProcessId,\n\t\tprocessIdSpaceLength,\n\t\ttrace,\n\t\tnativeInternalDirPath,\n\t\tmountsBeforeWpInstall,\n\t\tmountsAfterWpInstall,\n\t}: WorkerBootRequestHandlerOptions) {\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 requestHandler = await bootRequestHandler({\n\t\t\t\tsiteUrl,\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\tENV: {\n\t\t\t\t\t\t\t\tDOCROOT: '/wordpress',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tphpWasmInitOptions: { nativeInternalDirPath },\n\t\t\t\t\t\t},\n\t\t\t\t\t\tfollowSymlinks: allow?.includes('follow-symlinks'),\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\tonPHPInstanceCreated: async (php) => {\n\t\t\t\t\tthis.registerWorkerListeners(php);\n\t\t\t\t\tawait mountResources(php, mountsBeforeWpInstall);\n\t\t\t\t\tawait mountResources(php, mountsAfterWpInstall);\n\t\t\t\t},\n\t\t\t\tsapiName: 'cli',\n\t\t\t\tcookieStore: false,\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\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\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","siteUrl","mountsBeforeWpInstall","mountsAfterWpInstall","php","RecommendedPHPVersion","wordPressZip","sqliteIntegrationPluginZip","firstProcessId","processIdSpaceLength","dataSqlPath","followSymlinks","trace","internalCookieStore","withXdebug","nativeInternalDirPath","nextProcessId","lastProcessId","constants","wordpressBooted","requestHandler","bootWordPressAndRequestHandler","loadNodeRuntime","rootCertificates","sandboxedSpawnHandlerFactory","mountResources","primaryPhp","setApiReady","e","setAPIError","allow","phpVersion","bootRequestHandler","phpChannel","MessageChannel","exposeAPI","EmscriptenDownloadMonitor","parentPort"],"mappings":"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"}
|
|
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 {\n\tbootRequestHandler,\n\tbootWordPressAndRequestHandler,\n} 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';\nimport { logger } from '@php-wasm/logger';\n\nexport interface Mount {\n\thostPath: string;\n\tvfsPath: string;\n}\n\nexport type WorkerBootOptions = {\n\tphpVersion: SupportedPHPVersion;\n\tsiteUrl: string;\n\tmountsBeforeWpInstall: Array<Mount>;\n\tmountsAfterWpInstall: Array<Mount>;\n\tfirstProcessId: number;\n\tprocessIdSpaceLength: number;\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\tnativeInternalDirPath: string;\n};\n\nexport type PrimaryWorkerBootOptions = WorkerBootOptions & {\n\twpVersion?: string;\n\twordPressZip?: ArrayBuffer;\n\tsqliteIntegrationPluginZip?: ArrayBuffer;\n\tdataSqlPath?: string;\n};\n\ninterface WorkerBootRequestHandlerOptions {\n\tsiteUrl: string;\n\tallow?: string;\n\tphpVersion: SupportedPHPVersion;\n\tfirstProcessId: number;\n\tprocessIdSpaceLength: number;\n\ttrace: boolean;\n\tnativeInternalDirPath: string;\n\tmountsBeforeWpInstall: Array<Mount>;\n\tmountsAfterWpInstall: Array<Mount>;\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\tsiteUrl,\n\t\tmountsBeforeWpInstall,\n\t\tmountsAfterWpInstall,\n\t\tphpVersion: php = 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\tnativeInternalDirPath,\n\t}: PrimaryWorkerBootOptions) {\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\t\t\tlet wordpressBooted = false;\n\t\t\tconst requestHandler = await bootWordPressAndRequestHandler({\n\t\t\t\tsiteUrl,\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(php, {\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\tphpWasmInitOptions: { nativeInternalDirPath },\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\tcookieStore: internalCookieStore ? undefined : false,\n\t\t\t\tdataSqlPath,\n\t\t\t\tspawnHandler: sandboxedSpawnHandlerFactory,\n\t\t\t\tasync onPHPInstanceCreated(php) {\n\t\t\t\t\tawait mountResources(php, mountsBeforeWpInstall);\n\t\t\t\t\tif (wordpressBooted) {\n\t\t\t\t\t\tawait mountResources(php, mountsAfterWpInstall);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t});\n\t\t\tthis.__internal_setRequestHandler(requestHandler);\n\t\t\twordpressBooted = true;\n\n\t\t\tconst primaryPhp = await requestHandler.getPrimaryPhp();\n\t\t\tawait this.setPrimaryPHP(primaryPhp);\n\n\t\t\t// The primary PHP instance is persistent, so we need to apply\n\t\t\t// post-install mounts now that WordPress has been booted.\n\t\t\t// All secondary PHP instances created after WP boot will get\n\t\t\t// these mounts automatically.\n\t\t\tawait mountResources(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\tawait this.bootRequestHandler(args);\n\t}\n\n\tasync bootRequestHandler({\n\t\tsiteUrl,\n\t\tallow,\n\t\tphpVersion,\n\t\tfirstProcessId,\n\t\tprocessIdSpaceLength,\n\t\ttrace,\n\t\tnativeInternalDirPath,\n\t\tmountsBeforeWpInstall,\n\t\tmountsAfterWpInstall,\n\t}: WorkerBootRequestHandlerOptions) {\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 requestHandler = await bootRequestHandler({\n\t\t\t\tsiteUrl,\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\tENV: {\n\t\t\t\t\t\t\t\tDOCROOT: '/wordpress',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tphpWasmInitOptions: { nativeInternalDirPath },\n\t\t\t\t\t\t},\n\t\t\t\t\t\tfollowSymlinks: allow?.includes('follow-symlinks'),\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\tonPHPInstanceCreated: async (php) => {\n\t\t\t\t\tthis.registerWorkerListeners(php);\n\t\t\t\t\tawait mountResources(php, mountsBeforeWpInstall);\n\t\t\t\t\tawait mountResources(php, mountsAfterWpInstall);\n\t\t\t\t},\n\t\t\t\tsapiName: 'cli',\n\t\t\t\tcookieStore: false,\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\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\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\nprocess.on('unhandledRejection', (e: any) => {\n\tlogger.error('Unhandled rejection:', e);\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","siteUrl","mountsBeforeWpInstall","mountsAfterWpInstall","php","RecommendedPHPVersion","wordPressZip","sqliteIntegrationPluginZip","firstProcessId","processIdSpaceLength","dataSqlPath","followSymlinks","trace","internalCookieStore","withXdebug","nativeInternalDirPath","nextProcessId","lastProcessId","constants","wordpressBooted","requestHandler","bootWordPressAndRequestHandler","loadNodeRuntime","rootCertificates","sandboxedSpawnHandlerFactory","mountResources","primaryPhp","setApiReady","e","setAPIError","allow","phpVersion","bootRequestHandler","logger","phpChannel","MessageChannel","exposeAPI","EmscriptenDownloadMonitor","parentPort"],"mappings":"uaA2EA,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,QAAAI,EACA,sBAAAC,EACA,qBAAAC,EACA,WAAYC,EAAMC,EAAA,sBAClB,aAAAC,EACA,2BAAAC,EACA,eAAAC,EACA,qBAAAC,EACA,YAAAC,EACA,eAAAC,EACA,MAAAC,EACA,oBAAAC,EACA,WAAAC,EACA,sBAAAC,CAAA,EAC4B,CAC5B,GAAI,KAAK,OACF,MAAA,IAAI,MAAM,2BAA2B,EAE5C,KAAK,OAAS,GAEd,IAAIC,EAAgBR,EACd,MAAAS,EAAgBT,EAAiBC,EAAuB,EAE1D,GAAA,CACH,MAAMS,EACL,CACC,SAAU,GACV,aAAc,GACd,iBAAkB,EACnB,EACD,IAAIC,EAAkB,GAChB,MAAAC,EAAiB,MAAMC,iCAA+B,CAC3D,QAAApB,EACA,iBAAkB,SAAY,CAC7B,MAAMX,EAAY0B,EAElB,OAAIA,EAAgBC,EACnBD,IAGgBA,EAAAR,EAGV,MAAMc,kBAAgBlB,EAAK,CACjC,kBAAmB,CAClB,gBAAiB,KAAK,gBACtB,UAAAd,EACA,MAAOsB,EAAQvB,EAAe,OAC9B,mBAAoB,CAAE,sBAAA0B,CAAsB,CAC7C,EACA,eAAAJ,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,iCACCgB,EAAAA,iBAAiB,KAAK;AAAA,CAAI,CAC5B,EACA,UAAAL,EACA,cAAe,CACd,iBAAkB,iCAClB,gBAAiB,IACjB,kBAAmB,EACpB,EACA,YAAaL,EAAsB,OAAY,GAC/C,YAAAH,EACA,aAAcc,EAAA,6BACd,MAAM,qBAAqBpB,EAAK,CACzB,MAAAqB,EAAA,eAAerB,EAAKF,CAAqB,EAC3CiB,GACG,MAAAM,EAAA,eAAerB,EAAKD,CAAoB,CAC/C,CACD,CACA,EACD,KAAK,6BAA6BiB,CAAc,EAC9BD,EAAA,GAEZ,MAAAO,EAAa,MAAMN,EAAe,cAAc,EAChD,MAAA,KAAK,cAAcM,CAAU,EAM7B,MAAAD,EAAA,eAAeC,EAAYvB,CAAoB,EAEzCwB,EAAA,QACJC,EAAG,CACX,MAAAC,EAAYD,CAAU,EAChBA,CAAA,CACP,CAGD,MAAM,sBAAsBpC,EAAyB,CAC9C,MAAA,KAAK,mBAAmBA,CAAI,CAAA,CAGnC,MAAM,mBAAmB,CACxB,QAAAS,EACA,MAAA6B,EACA,WAAAC,EACA,eAAAvB,EACA,qBAAAC,EACA,MAAAG,EACA,sBAAAG,EACA,sBAAAb,EACA,qBAAAC,CAAA,EACmC,CACnC,GAAI,KAAK,OACF,MAAA,IAAI,MAAM,2BAA2B,EAE5C,KAAK,OAAS,GAEd,IAAIa,EAAgBR,EACd,MAAAS,EAAgBT,EAAiBC,EAAuB,EAE1D,GAAA,CACG,MAAAW,EAAiB,MAAMY,qBAAmB,CAC/C,QAAA/B,EACA,iBAAkB,SAAY,CAC7B,MAAMX,EAAY0B,EAElB,OAAIA,EAAgBC,EACnBD,IAGgBA,EAAAR,EAGV,MAAMc,kBAAgBS,EAAY,CACxC,kBAAmB,CAClB,gBAAiB,KAAK,gBACtB,UAAAzC,EACA,MAAOsB,EAAQvB,EAAe,OAC9B,IAAK,CACJ,QAAS,YACV,EACA,mBAAoB,CAAE,sBAAA0B,CAAsB,CAC7C,EACA,eAAgBe,GAAO,SAAS,iBAAiB,CAAA,CACjD,CACF,EACA,qBAAsB,MAAO1B,GAAQ,CACpC,KAAK,wBAAwBA,CAAG,EAC1B,MAAAqB,EAAA,eAAerB,EAAKF,CAAqB,EACzC,MAAAuB,EAAA,eAAerB,EAAKD,CAAoB,CAC/C,EACA,SAAU,MACV,YAAa,GACb,aAAcqB,EAAAA,4BAAA,CACd,EACD,KAAK,6BAA6BJ,CAAc,EAE1C,MAAAM,EAAa,MAAMN,EAAe,cAAc,EAChD,MAAA,KAAK,cAAcM,CAAU,EAEvBC,EAAA,QACJC,EAAG,CACX,MAAAC,EAAYD,CAAU,EAChBA,CAAA,CACP,CAID,MAAM,SAAU,CACT,MAAA,KAAK,OAAO,YAAY,EAAE,CAAA,CAElC,CAEA,QAAQ,GAAG,qBAAuBA,GAAW,CACrCK,SAAA,MAAM,uBAAwBL,CAAC,CACvC,CAAC,EAED,MAAMM,EAAa,IAAIC,EAAAA,eAEjB,CAACR,EAAaE,CAAW,EAAIO,EAAA,UAClC,IAAI1C,EAA+B,IAAI2C,EAAAA,yBAA2B,EAClE,OACAH,EAAW,KACZ,EAEAI,EAAAA,YAAY,YACX,CACC,QAAS,4BACT,QAASJ,EAAW,KACrB,EACA,CAACA,EAAW,KAAY,CACzB"}
|
package/worker-thread-v1.js
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
|
-
import { loadNodeRuntime as
|
|
1
|
+
import { loadNodeRuntime as R } from "@php-wasm/node";
|
|
2
2
|
import { EmscriptenDownloadMonitor as M } from "@php-wasm/progress";
|
|
3
|
-
import { exposeAPI as q, PHPWorker as v, consumeAPI as E, consumeAPISync as A, sandboxedSpawnHandlerFactory as
|
|
3
|
+
import { exposeAPI as q, PHPWorker as v, consumeAPI as E, consumeAPISync as A, sandboxedSpawnHandlerFactory as _ } from "@php-wasm/universal";
|
|
4
4
|
import { sprintf as O } from "@php-wasm/util";
|
|
5
5
|
import { RecommendedPHPVersion as x } from "@wp-playground/common";
|
|
6
6
|
import { bootWordPressAndRequestHandler as C, bootRequestHandler as D } from "@wp-playground/wordpress";
|
|
7
7
|
import { rootCertificates as F } from "tls";
|
|
8
8
|
import { jspi as B } from "wasm-feature-detect";
|
|
9
|
-
import { MessageChannel as
|
|
10
|
-
import { m as
|
|
11
|
-
|
|
9
|
+
import { MessageChannel as j, parentPort as G } from "worker_threads";
|
|
10
|
+
import { m as i } from "./mounts-D1_eXSTw.js";
|
|
11
|
+
import { logger as N } from "@php-wasm/logger";
|
|
12
|
+
function I(c, e, ...a) {
|
|
12
13
|
console.log(
|
|
13
14
|
performance.now().toFixed(6).padStart(15, "0"),
|
|
14
|
-
|
|
15
|
+
c.toString().padStart(16, "0"),
|
|
15
16
|
O(e, ...a)
|
|
16
17
|
);
|
|
17
18
|
}
|
|
18
|
-
class
|
|
19
|
+
class U extends v {
|
|
19
20
|
constructor(e) {
|
|
20
21
|
super(void 0, e), this.booted = !1;
|
|
21
22
|
}
|
|
@@ -34,26 +35,26 @@ class V extends v {
|
|
|
34
35
|
async bootAsPrimaryWorker({
|
|
35
36
|
siteUrl: e,
|
|
36
37
|
mountsBeforeWpInstall: a,
|
|
37
|
-
mountsAfterWpInstall:
|
|
38
|
-
phpVersion:
|
|
39
|
-
wordPressZip:
|
|
40
|
-
sqliteIntegrationPluginZip:
|
|
41
|
-
firstProcessId:
|
|
38
|
+
mountsAfterWpInstall: l,
|
|
39
|
+
phpVersion: n = x,
|
|
40
|
+
wordPressZip: d,
|
|
41
|
+
sqliteIntegrationPluginZip: p,
|
|
42
|
+
firstProcessId: s,
|
|
42
43
|
processIdSpaceLength: P,
|
|
43
|
-
dataSqlPath:
|
|
44
|
+
dataSqlPath: u,
|
|
44
45
|
followSymlinks: r,
|
|
45
|
-
trace:
|
|
46
|
+
trace: f,
|
|
46
47
|
internalCookieStore: t,
|
|
47
|
-
withXdebug:
|
|
48
|
+
withXdebug: y,
|
|
48
49
|
nativeInternalDirPath: o
|
|
49
50
|
}) {
|
|
50
51
|
if (this.booted)
|
|
51
52
|
throw new Error("Playground already booted");
|
|
52
53
|
this.booted = !0;
|
|
53
|
-
let
|
|
54
|
-
const L =
|
|
54
|
+
let m = s;
|
|
55
|
+
const L = s + P - 1;
|
|
55
56
|
try {
|
|
56
|
-
const
|
|
57
|
+
const w = {
|
|
57
58
|
WP_DEBUG: !0,
|
|
58
59
|
WP_DEBUG_LOG: !0,
|
|
59
60
|
WP_DEBUG_DISPLAY: !1
|
|
@@ -62,21 +63,21 @@ class V extends v {
|
|
|
62
63
|
const k = await C({
|
|
63
64
|
siteUrl: e,
|
|
64
65
|
createPhpRuntime: async () => {
|
|
65
|
-
const
|
|
66
|
-
return
|
|
66
|
+
const h = m;
|
|
67
|
+
return m < L ? m++ : m = s, await R(n, {
|
|
67
68
|
emscriptenOptions: {
|
|
68
69
|
fileLockManager: this.fileLockManager,
|
|
69
|
-
processId:
|
|
70
|
-
trace:
|
|
70
|
+
processId: h,
|
|
71
|
+
trace: f ? I : void 0,
|
|
71
72
|
phpWasmInitOptions: { nativeInternalDirPath: o }
|
|
72
73
|
},
|
|
73
74
|
followSymlinks: r,
|
|
74
|
-
withXdebug:
|
|
75
|
+
withXdebug: y
|
|
75
76
|
});
|
|
76
77
|
},
|
|
77
|
-
wordPressZip:
|
|
78
|
-
sqliteIntegrationPluginZip:
|
|
79
|
-
[
|
|
78
|
+
wordPressZip: d !== void 0 ? new File([d], "wordpress.zip") : void 0,
|
|
79
|
+
sqliteIntegrationPluginZip: p !== void 0 ? new File(
|
|
80
|
+
[p],
|
|
80
81
|
"sqlite-integration-plugin.zip"
|
|
81
82
|
) : void 0,
|
|
82
83
|
sapiName: "cli",
|
|
@@ -84,24 +85,24 @@ class V extends v {
|
|
|
84
85
|
"/internal/shared/ca-bundle.crt": F.join(`
|
|
85
86
|
`)
|
|
86
87
|
},
|
|
87
|
-
constants:
|
|
88
|
+
constants: w,
|
|
88
89
|
phpIniEntries: {
|
|
89
90
|
"openssl.cafile": "/internal/shared/ca-bundle.crt",
|
|
90
91
|
allow_url_fopen: "1",
|
|
91
92
|
disable_functions: ""
|
|
92
93
|
},
|
|
93
94
|
cookieStore: t ? void 0 : !1,
|
|
94
|
-
dataSqlPath:
|
|
95
|
-
spawnHandler:
|
|
96
|
-
async onPHPInstanceCreated(
|
|
97
|
-
await
|
|
95
|
+
dataSqlPath: u,
|
|
96
|
+
spawnHandler: _,
|
|
97
|
+
async onPHPInstanceCreated(h) {
|
|
98
|
+
await i(h, a), b && await i(h, l);
|
|
98
99
|
}
|
|
99
100
|
});
|
|
100
101
|
this.__internal_setRequestHandler(k), b = !0;
|
|
101
102
|
const H = await k.getPrimaryPhp();
|
|
102
|
-
await this.setPrimaryPHP(H), await
|
|
103
|
-
} catch (
|
|
104
|
-
throw W(
|
|
103
|
+
await this.setPrimaryPHP(H), await i(H, l), S();
|
|
104
|
+
} catch (w) {
|
|
105
|
+
throw W(w), w;
|
|
105
106
|
}
|
|
106
107
|
}
|
|
107
108
|
async bootAsSecondaryWorker(e) {
|
|
@@ -110,47 +111,47 @@ class V extends v {
|
|
|
110
111
|
async bootRequestHandler({
|
|
111
112
|
siteUrl: e,
|
|
112
113
|
allow: a,
|
|
113
|
-
phpVersion:
|
|
114
|
-
firstProcessId:
|
|
115
|
-
processIdSpaceLength:
|
|
116
|
-
trace:
|
|
117
|
-
nativeInternalDirPath:
|
|
114
|
+
phpVersion: l,
|
|
115
|
+
firstProcessId: n,
|
|
116
|
+
processIdSpaceLength: d,
|
|
117
|
+
trace: p,
|
|
118
|
+
nativeInternalDirPath: s,
|
|
118
119
|
mountsBeforeWpInstall: P,
|
|
119
|
-
mountsAfterWpInstall:
|
|
120
|
+
mountsAfterWpInstall: u
|
|
120
121
|
}) {
|
|
121
122
|
if (this.booted)
|
|
122
123
|
throw new Error("Playground already booted");
|
|
123
124
|
this.booted = !0;
|
|
124
|
-
let r =
|
|
125
|
-
const
|
|
125
|
+
let r = n;
|
|
126
|
+
const f = n + d - 1;
|
|
126
127
|
try {
|
|
127
128
|
const t = await D({
|
|
128
129
|
siteUrl: e,
|
|
129
130
|
createPhpRuntime: async () => {
|
|
130
131
|
const o = r;
|
|
131
|
-
return r <
|
|
132
|
+
return r < f ? r++ : r = n, await R(l, {
|
|
132
133
|
emscriptenOptions: {
|
|
133
134
|
fileLockManager: this.fileLockManager,
|
|
134
135
|
processId: o,
|
|
135
|
-
trace:
|
|
136
|
+
trace: p ? I : void 0,
|
|
136
137
|
ENV: {
|
|
137
138
|
DOCROOT: "/wordpress"
|
|
138
139
|
},
|
|
139
|
-
phpWasmInitOptions: { nativeInternalDirPath:
|
|
140
|
+
phpWasmInitOptions: { nativeInternalDirPath: s }
|
|
140
141
|
},
|
|
141
142
|
followSymlinks: a?.includes("follow-symlinks")
|
|
142
143
|
});
|
|
143
144
|
},
|
|
144
145
|
onPHPInstanceCreated: async (o) => {
|
|
145
|
-
this.registerWorkerListeners(o), await
|
|
146
|
+
this.registerWorkerListeners(o), await i(o, P), await i(o, u);
|
|
146
147
|
},
|
|
147
148
|
sapiName: "cli",
|
|
148
149
|
cookieStore: !1,
|
|
149
|
-
spawnHandler:
|
|
150
|
+
spawnHandler: _
|
|
150
151
|
});
|
|
151
152
|
this.__internal_setRequestHandler(t);
|
|
152
|
-
const
|
|
153
|
-
await this.setPrimaryPHP(
|
|
153
|
+
const y = await t.getPrimaryPhp();
|
|
154
|
+
await this.setPrimaryPHP(y), S();
|
|
154
155
|
} catch (t) {
|
|
155
156
|
throw W(t), t;
|
|
156
157
|
}
|
|
@@ -160,19 +161,22 @@ class V extends v {
|
|
|
160
161
|
await this[Symbol.asyncDispose]();
|
|
161
162
|
}
|
|
162
163
|
}
|
|
163
|
-
|
|
164
|
-
|
|
164
|
+
process.on("unhandledRejection", (c) => {
|
|
165
|
+
N.error("Unhandled rejection:", c);
|
|
166
|
+
});
|
|
167
|
+
const g = new j(), [S, W] = q(
|
|
168
|
+
new U(new M()),
|
|
165
169
|
void 0,
|
|
166
|
-
|
|
170
|
+
g.port1
|
|
167
171
|
);
|
|
168
|
-
|
|
172
|
+
G?.postMessage(
|
|
169
173
|
{
|
|
170
174
|
command: "worker-script-initialized",
|
|
171
|
-
phpPort:
|
|
175
|
+
phpPort: g.port2
|
|
172
176
|
},
|
|
173
|
-
[
|
|
177
|
+
[g.port2]
|
|
174
178
|
);
|
|
175
179
|
export {
|
|
176
|
-
|
|
180
|
+
U as PlaygroundCliBlueprintV1Worker
|
|
177
181
|
};
|
|
178
182
|
//# sourceMappingURL=worker-thread-v1.js.map
|
package/worker-thread-v1.js.map
CHANGED
|
@@ -1 +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 {\n\tbootRequestHandler,\n\tbootWordPressAndRequestHandler,\n} 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\tphpVersion: SupportedPHPVersion;\n\tsiteUrl: string;\n\tmountsBeforeWpInstall: Array<Mount>;\n\tmountsAfterWpInstall: Array<Mount>;\n\tfirstProcessId: number;\n\tprocessIdSpaceLength: number;\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\tnativeInternalDirPath: string;\n};\n\nexport type PrimaryWorkerBootOptions = WorkerBootOptions & {\n\twpVersion?: string;\n\twordPressZip?: ArrayBuffer;\n\tsqliteIntegrationPluginZip?: ArrayBuffer;\n\tdataSqlPath?: string;\n};\n\ninterface WorkerBootRequestHandlerOptions {\n\tsiteUrl: string;\n\tallow?: string;\n\tphpVersion: SupportedPHPVersion;\n\tfirstProcessId: number;\n\tprocessIdSpaceLength: number;\n\ttrace: boolean;\n\tnativeInternalDirPath: string;\n\tmountsBeforeWpInstall: Array<Mount>;\n\tmountsAfterWpInstall: Array<Mount>;\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\tsiteUrl,\n\t\tmountsBeforeWpInstall,\n\t\tmountsAfterWpInstall,\n\t\tphpVersion: php = 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\tnativeInternalDirPath,\n\t}: PrimaryWorkerBootOptions) {\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\t\t\tlet wordpressBooted = false;\n\t\t\tconst requestHandler = await bootWordPressAndRequestHandler({\n\t\t\t\tsiteUrl,\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(php, {\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\tphpWasmInitOptions: { nativeInternalDirPath },\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\tcookieStore: internalCookieStore ? undefined : false,\n\t\t\t\tdataSqlPath,\n\t\t\t\tspawnHandler: sandboxedSpawnHandlerFactory,\n\t\t\t\tasync onPHPInstanceCreated(php) {\n\t\t\t\t\tawait mountResources(php, mountsBeforeWpInstall);\n\t\t\t\t\tif (wordpressBooted) {\n\t\t\t\t\t\tawait mountResources(php, mountsAfterWpInstall);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t});\n\t\t\tthis.__internal_setRequestHandler(requestHandler);\n\t\t\twordpressBooted = true;\n\n\t\t\tconst primaryPhp = await requestHandler.getPrimaryPhp();\n\t\t\tawait this.setPrimaryPHP(primaryPhp);\n\n\t\t\t// The primary PHP instance is persistent, so we need to apply\n\t\t\t// post-install mounts now that WordPress has been booted.\n\t\t\t// All secondary PHP instances created after WP boot will get\n\t\t\t// these mounts automatically.\n\t\t\tawait mountResources(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\tawait this.bootRequestHandler(args);\n\t}\n\n\tasync bootRequestHandler({\n\t\tsiteUrl,\n\t\tallow,\n\t\tphpVersion,\n\t\tfirstProcessId,\n\t\tprocessIdSpaceLength,\n\t\ttrace,\n\t\tnativeInternalDirPath,\n\t\tmountsBeforeWpInstall,\n\t\tmountsAfterWpInstall,\n\t}: WorkerBootRequestHandlerOptions) {\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 requestHandler = await bootRequestHandler({\n\t\t\t\tsiteUrl,\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\tENV: {\n\t\t\t\t\t\t\t\tDOCROOT: '/wordpress',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tphpWasmInitOptions: { nativeInternalDirPath },\n\t\t\t\t\t\t},\n\t\t\t\t\t\tfollowSymlinks: allow?.includes('follow-symlinks'),\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\tonPHPInstanceCreated: async (php) => {\n\t\t\t\t\tthis.registerWorkerListeners(php);\n\t\t\t\t\tawait mountResources(php, mountsBeforeWpInstall);\n\t\t\t\t\tawait mountResources(php, mountsAfterWpInstall);\n\t\t\t\t},\n\t\t\t\tsapiName: 'cli',\n\t\t\t\tcookieStore: false,\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\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\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","siteUrl","mountsBeforeWpInstall","mountsAfterWpInstall","php","RecommendedPHPVersion","wordPressZip","sqliteIntegrationPluginZip","firstProcessId","processIdSpaceLength","dataSqlPath","followSymlinks","trace","internalCookieStore","withXdebug","nativeInternalDirPath","nextProcessId","lastProcessId","constants","wordpressBooted","requestHandler","bootWordPressAndRequestHandler","loadNodeRuntime","rootCertificates","sandboxedSpawnHandlerFactory","mountResources","primaryPhp","setApiReady","e","setAPIError","allow","phpVersion","bootRequestHandler","phpChannel","MessageChannel","exposeAPI","EmscriptenDownloadMonitor","parentPort"],"mappings":"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"}
|
|
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 {\n\tbootRequestHandler,\n\tbootWordPressAndRequestHandler,\n} 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';\nimport { logger } from '@php-wasm/logger';\n\nexport interface Mount {\n\thostPath: string;\n\tvfsPath: string;\n}\n\nexport type WorkerBootOptions = {\n\tphpVersion: SupportedPHPVersion;\n\tsiteUrl: string;\n\tmountsBeforeWpInstall: Array<Mount>;\n\tmountsAfterWpInstall: Array<Mount>;\n\tfirstProcessId: number;\n\tprocessIdSpaceLength: number;\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\tnativeInternalDirPath: string;\n};\n\nexport type PrimaryWorkerBootOptions = WorkerBootOptions & {\n\twpVersion?: string;\n\twordPressZip?: ArrayBuffer;\n\tsqliteIntegrationPluginZip?: ArrayBuffer;\n\tdataSqlPath?: string;\n};\n\ninterface WorkerBootRequestHandlerOptions {\n\tsiteUrl: string;\n\tallow?: string;\n\tphpVersion: SupportedPHPVersion;\n\tfirstProcessId: number;\n\tprocessIdSpaceLength: number;\n\ttrace: boolean;\n\tnativeInternalDirPath: string;\n\tmountsBeforeWpInstall: Array<Mount>;\n\tmountsAfterWpInstall: Array<Mount>;\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\tsiteUrl,\n\t\tmountsBeforeWpInstall,\n\t\tmountsAfterWpInstall,\n\t\tphpVersion: php = 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\tnativeInternalDirPath,\n\t}: PrimaryWorkerBootOptions) {\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\t\t\tlet wordpressBooted = false;\n\t\t\tconst requestHandler = await bootWordPressAndRequestHandler({\n\t\t\t\tsiteUrl,\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(php, {\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\tphpWasmInitOptions: { nativeInternalDirPath },\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\tcookieStore: internalCookieStore ? undefined : false,\n\t\t\t\tdataSqlPath,\n\t\t\t\tspawnHandler: sandboxedSpawnHandlerFactory,\n\t\t\t\tasync onPHPInstanceCreated(php) {\n\t\t\t\t\tawait mountResources(php, mountsBeforeWpInstall);\n\t\t\t\t\tif (wordpressBooted) {\n\t\t\t\t\t\tawait mountResources(php, mountsAfterWpInstall);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t});\n\t\t\tthis.__internal_setRequestHandler(requestHandler);\n\t\t\twordpressBooted = true;\n\n\t\t\tconst primaryPhp = await requestHandler.getPrimaryPhp();\n\t\t\tawait this.setPrimaryPHP(primaryPhp);\n\n\t\t\t// The primary PHP instance is persistent, so we need to apply\n\t\t\t// post-install mounts now that WordPress has been booted.\n\t\t\t// All secondary PHP instances created after WP boot will get\n\t\t\t// these mounts automatically.\n\t\t\tawait mountResources(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\tawait this.bootRequestHandler(args);\n\t}\n\n\tasync bootRequestHandler({\n\t\tsiteUrl,\n\t\tallow,\n\t\tphpVersion,\n\t\tfirstProcessId,\n\t\tprocessIdSpaceLength,\n\t\ttrace,\n\t\tnativeInternalDirPath,\n\t\tmountsBeforeWpInstall,\n\t\tmountsAfterWpInstall,\n\t}: WorkerBootRequestHandlerOptions) {\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 requestHandler = await bootRequestHandler({\n\t\t\t\tsiteUrl,\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\tENV: {\n\t\t\t\t\t\t\t\tDOCROOT: '/wordpress',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tphpWasmInitOptions: { nativeInternalDirPath },\n\t\t\t\t\t\t},\n\t\t\t\t\t\tfollowSymlinks: allow?.includes('follow-symlinks'),\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\tonPHPInstanceCreated: async (php) => {\n\t\t\t\t\tthis.registerWorkerListeners(php);\n\t\t\t\t\tawait mountResources(php, mountsBeforeWpInstall);\n\t\t\t\t\tawait mountResources(php, mountsAfterWpInstall);\n\t\t\t\t},\n\t\t\t\tsapiName: 'cli',\n\t\t\t\tcookieStore: false,\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\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\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\nprocess.on('unhandledRejection', (e: any) => {\n\tlogger.error('Unhandled rejection:', e);\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","siteUrl","mountsBeforeWpInstall","mountsAfterWpInstall","php","RecommendedPHPVersion","wordPressZip","sqliteIntegrationPluginZip","firstProcessId","processIdSpaceLength","dataSqlPath","followSymlinks","trace","internalCookieStore","withXdebug","nativeInternalDirPath","nextProcessId","lastProcessId","constants","wordpressBooted","requestHandler","bootWordPressAndRequestHandler","loadNodeRuntime","rootCertificates","sandboxedSpawnHandlerFactory","mountResources","primaryPhp","setApiReady","e","setAPIError","allow","phpVersion","bootRequestHandler","logger","phpChannel","MessageChannel","exposeAPI","EmscriptenDownloadMonitor","parentPort"],"mappings":"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"}
|
package/worker-thread-v2.cjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const W=require("@php-wasm/logger"),y=require("@php-wasm/node"),x=require("@php-wasm/progress"),u=require("@php-wasm/universal"),k=require("@php-wasm/util"),M=require("@wp-playground/blueprints"),_=require("@wp-playground/wordpress"),$=require("fs"),m=require("path"),A=require("tls"),T=require("worker_threads"),I=require("wasm-feature-detect");async function h(s,e){for(const r of e)try{s.mkdir(r.vfsPath),await s.mount(r.vfsPath,y.createNodeFsMountHandler(r.hostPath))}catch{i.stderr(`\x1B[31m\x1B[1mError mounting path ${r.hostPath} at ${r.vfsPath}\x1B[0m
|
|
2
2
|
`),process.exit(1)}}function S(s,e,...r){console.log(performance.now().toFixed(6).padStart(15,"0"),s.toString().padStart(16,"0"),k.sprintf(e,...r))}Object.defineProperty(process.stdout,"isTTY",{value:!0});Object.defineProperty(process.stderr,"isTTY",{value:!0});const i={lastWriteWasProgress:!1,progress(s){process.stdout.isTTY?(i.lastWriteWasProgress||process.stdout.write(`
|
|
3
3
|
`),process.stdout.write("\r\x1B[K"+s),i.lastWriteWasProgress=!0):console.log(s)},stdout(s){i.lastWriteWasProgress&&(process.stdout.write(`
|
|
4
4
|
`),i.lastWriteWasProgress=!1),process.stdout.write(s)},stderr(s){i.lastWriteWasProgress&&(process.stdout.write(`
|
|
5
|
-
`),i.lastWriteWasProgress=!1),process.stderr.write(s)}};class
|
|
5
|
+
`),i.lastWriteWasProgress=!1),process.stderr.write(s)}};class R extends u.PHPWorker{constructor(e){super(void 0,e),this.booted=!1,this.blueprintTargetResolved=!1,this.phpInstancesThatNeedMountsAfterTargetResolved=new Set}async useFileLockManager(e){await I.jspi()?this.fileLockManager=u.consumeAPI(e):this.fileLockManager=await u.consumeAPISync(e)}async bootAsPrimaryWorker(e){const r={WP_DEBUG:!0,WP_DEBUG_LOG:!0,WP_DEBUG_DISPLAY:!1},p={...e,createFiles:{"/internal/shared/ca-bundle.crt":A.rootCertificates.join(`
|
|
6
6
|
`)},constants:r,phpIniEntries:{"openssl.cafile":"/internal/shared/ca-bundle.crt"},onPHPInstanceCreated:async o=>{this.registerWorkerListeners(o),await h(o,e["mount-before-install"]||[]),this.blueprintTargetResolved?await h(o,e.mount||[]):(this.phpInstancesThatNeedMountsAfterTargetResolved.add(o),o.addEventListener("runtime.beforeExit",()=>{this.phpInstancesThatNeedMountsAfterTargetResolved.delete(o)}))}};await this.bootRequestHandler(p);const w=this.__internal_getPHP();if(e.mode==="mount-only"){await h(w,e.mount||[]);return}await this.runBlueprintV2(e)}async bootAsSecondaryWorker(e){await this.bootRequestHandler({...e,onPHPInstanceCreated:async r=>{await h(r,e.mountsBeforeWpInstall||[]),await h(r,e.mountsAfterWpInstall||[])}})}async runBlueprintV2(e){const r=this.__internal_getRequestHandler(),{php:p,reap:w}=await r.processManager.acquirePHPInstance({considerPrimary:!1}),o=this.__internal_getPHP();let f=()=>{};if(typeof e.blueprint=="string"){const n=m.resolve(process.cwd(),e.blueprint);$.existsSync(n)&&(o.mkdir("/internal/shared/cwd"),f=await o.mount("/internal/shared/cwd",y.createNodeFsMountHandler(m.dirname(n))),e.blueprint=m.join("/internal/shared/cwd",m.basename(e.blueprint)))}try{const l=["mode","db-engine","db-host","db-user","db-pass","db-name","db-path","truncate-new-site-directory","allow"].filter(t=>t in e).map(t=>`--${t}=${e[t]}`);l.push(`--site-url=${e.siteUrl}`);const c=await M.runBlueprintV2({php:p,blueprint:e.blueprint,blueprintOverrides:{additionalSteps:e["additional-blueprint-steps"],wordpressVersion:e.wp},cliArgs:l,onMessage:async t=>{switch(t.type){case"blueprint.target_resolved":{if(!this.blueprintTargetResolved){this.blueprintTargetResolved=!0;for(const a of this.phpInstancesThatNeedMountsAfterTargetResolved)this.phpInstancesThatNeedMountsAfterTargetResolved.delete(a),await h(a,e.mount||[])}break}case"blueprint.progress":{const a=`${t.caption.trim()} – ${t.progress.toFixed(2)}%`;i.progress(a);break}case"blueprint.error":{const a="\x1B[31m",b="\x1B[1m",d="\x1B[0m";e.debug&&t.details?i.stderr(`${a}${b}Fatal error:${d} Uncaught ${t.details.exception}: ${t.details.message}
|
|
7
7
|
at ${t.details.file}:${t.details.line}
|
|
8
8
|
`+(t.details.trace?t.details.trace+`
|
|
9
9
|
`:"")):i.stderr(`${a}${b}Error:${d} ${t.message}
|
|
10
|
-
`);break}}}});if(e.debug&&(c.stdout.pipeTo(new WritableStream({write(t){process.stdout.write(t)}})),c.stderr.pipeTo(new WritableStream({write(t){process.stderr.write(t)}}))),await c.finished,await c.exitCode!==0){const t=await u.PHPResponse.fromStreamedResponse(c);throw new u.PHPExecutionFailureError(`PHP.run() failed with exit code ${t.exitCode}.`,t,"request")}}catch(n){let l="";try{l=p.readFileAsText(
|
|
10
|
+
`);break}}}});if(e.debug&&(c.stdout.pipeTo(new WritableStream({write(t){process.stdout.write(t)}})),c.stderr.pipeTo(new WritableStream({write(t){process.stderr.write(t)}}))),await c.finished,await c.exitCode!==0){const t=await u.PHPResponse.fromStreamedResponse(c);throw new u.PHPExecutionFailureError(`PHP.run() failed with exit code ${t.exitCode}.`,t,"request")}}catch(n){let l="";try{l=p.readFileAsText(W.errorLogPath)}catch{}throw n.phpLogs=l,n}finally{w(),f()}}async bootRequestHandler({siteUrl:e,allow:r,phpVersion:p,createFiles:w,constants:o,phpIniEntries:f,firstProcessId:n,processIdSpaceLength:l,trace:c,nativeInternalDirPath:t,withXdebug:a,onPHPInstanceCreated:b}){if(this.booted)throw new Error("Playground already booted");this.booted=!0;let d=n;const q=n+l-1;try{const P=await _.bootRequestHandler({siteUrl:e,createPhpRuntime:async()=>{const H=d;return d<q?d++:d=n,await y.loadNodeRuntime(p,{emscriptenOptions:{fileLockManager:this.fileLockManager,processId:H,trace:c?S:void 0,ENV:{DOCROOT:"/wordpress"},phpWasmInitOptions:{nativeInternalDirPath:t}},followSymlinks:r?.includes("follow-symlinks"),withXdebug:a})},onPHPInstanceCreated:b,sapiName:"cli",createFiles:w,constants:o,phpIniEntries:f,cookieStore:!1,spawnHandler:u.sandboxedSpawnHandlerFactory});this.__internal_setRequestHandler(P);const v=await P.getPrimaryPhp();await this.setPrimaryPHP(v),B()}catch(P){throw E(P),P}}async dispose(){await this[Symbol.asyncDispose]()}}process.on("unhandledRejection",s=>{W.logger.error("Unhandled rejection:",s)});const g=new T.MessageChannel,[B,E]=u.exposeAPI(new R(new x.EmscriptenDownloadMonitor),void 0,g.port1);T.parentPort?.postMessage({command:"worker-script-initialized",phpPort:g.port2},[g.port2]);exports.PlaygroundCliBlueprintV2Worker=R;
|
|
11
11
|
//# sourceMappingURL=worker-thread-v2.cjs.map
|
package/worker-thread-v2.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker-thread-v2.cjs","sources":["../../../../packages/playground/cli/src/blueprints-v2/worker-thread-v2.ts"],"sourcesContent":["import { errorLogPath } from '@php-wasm/logger';\nimport type { FileLockManager } from '@php-wasm/node';\nimport { createNodeFsMountHandler, loadNodeRuntime } from '@php-wasm/node';\nimport { EmscriptenDownloadMonitor } from '@php-wasm/progress';\nimport type {\n\tPHP,\n\tFileTree,\n\tRemoteAPI,\n\tSupportedPHPVersion,\n} from '@php-wasm/universal';\nimport {\n\tPHPExecutionFailureError,\n\tPHPResponse,\n\tPHPWorker,\n\tconsumeAPI,\n\tconsumeAPISync,\n\texposeAPI,\n\tsandboxedSpawnHandlerFactory,\n} from '@php-wasm/universal';\nimport { sprintf } from '@php-wasm/util';\nimport {\n\ttype BlueprintMessage,\n\trunBlueprintV2,\n\ttype BlueprintV1Declaration,\n} from '@wp-playground/blueprints';\nimport {\n\ttype ParsedBlueprintV2String,\n\ttype RawBlueprintV2Data,\n} from '@wp-playground/blueprints';\nimport { bootRequestHandler } from '@wp-playground/wordpress';\nimport { existsSync } from 'fs';\nimport path from 'path';\nimport { rootCertificates } from 'tls';\nimport { MessageChannel, type MessagePort, parentPort } from 'worker_threads';\nimport type { Mount } from '../mounts';\nimport { jspi } from 'wasm-feature-detect';\nimport { type RunCLIArgs } from '../run-cli';\nimport type {\n\tPhpIniOptions,\n\tPHPInstanceCreatedHook,\n} from '@wp-playground/wordpress';\n\nasync function mountResources(php: PHP, mounts: Mount[]) {\n\tfor (const mount of mounts) {\n\t\ttry {\n\t\t\tphp.mkdir(mount.vfsPath);\n\t\t\tawait php.mount(\n\t\t\t\tmount.vfsPath,\n\t\t\t\tcreateNodeFsMountHandler(mount.hostPath)\n\t\t\t);\n\t\t} catch {\n\t\t\toutput.stderr(\n\t\t\t\t`\\x1b[31m\\x1b[1mError mounting path ${mount.hostPath} at ${mount.vfsPath}\\x1b[0m\\n`\n\t\t\t);\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\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\n/**\n * Force TTY status to preserve ANSI control codes in the output.\n *\n * This script is spawned as `new Worker()` and process.stdout and process.stderr are\n * WritableWorkerStdio objects. By default, they strip ANSI control codes from the output\n * causing every progress bar update to be printed in a new line instead of updating the\n * same line.\n */\nObject.defineProperty(process.stdout, 'isTTY', { value: true });\nObject.defineProperty(process.stderr, 'isTTY', { value: true });\n\n/**\n * Output writer that ensures that progress bars are not printed on the same line as other output.\n */\nconst output = {\n\tlastWriteWasProgress: false,\n\tprogress(data: string) {\n\t\tif (!process.stdout.isTTY) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.log(data);\n\t\t} else {\n\t\t\tif (!output.lastWriteWasProgress) {\n\t\t\t\tprocess.stdout.write('\\n');\n\t\t\t}\n\t\t\tprocess.stdout.write('\\r\\x1b[K' + data);\n\t\t\toutput.lastWriteWasProgress = true;\n\t\t}\n\t},\n\tstdout(data: string) {\n\t\tif (output.lastWriteWasProgress) {\n\t\t\tprocess.stdout.write('\\n');\n\t\t\toutput.lastWriteWasProgress = false;\n\t\t}\n\t\tprocess.stdout.write(data);\n\t},\n\tstderr(data: string) {\n\t\tif (output.lastWriteWasProgress) {\n\t\t\tprocess.stdout.write('\\n');\n\t\t\toutput.lastWriteWasProgress = false;\n\t\t}\n\t\tprocess.stderr.write(data);\n\t},\n};\n\nexport type PrimaryWorkerBootArgs = RunCLIArgs & {\n\tphpVersion: SupportedPHPVersion;\n\tsiteUrl: string;\n\tfirstProcessId: number;\n\tprocessIdSpaceLength: number;\n\ttrace: boolean;\n\tblueprint:\n\t\t| RawBlueprintV2Data\n\t\t| ParsedBlueprintV2String\n\t\t| BlueprintV1Declaration;\n\tnativeInternalDirPath: string;\n};\n\ntype WorkerRunBlueprintArgs = RunCLIArgs & {\n\tsiteUrl: string;\n\tblueprint:\n\t\t| RawBlueprintV2Data\n\t\t| ParsedBlueprintV2String\n\t\t| BlueprintV1Declaration;\n};\n\nexport type SecondaryWorkerBootArgs = {\n\tsiteUrl: string;\n\tallow?: string;\n\tphpVersion: SupportedPHPVersion;\n\tphpIniEntries?: PhpIniOptions;\n\tconstants?: Record<string, string | number | boolean | null>;\n\tcreateFiles?: FileTree;\n\tfirstProcessId: number;\n\tprocessIdSpaceLength: number;\n\ttrace: boolean;\n\tnativeInternalDirPath: string;\n\twithXdebug?: boolean;\n\tmountsBeforeWpInstall?: Array<Mount>;\n\tmountsAfterWpInstall?: Array<Mount>;\n};\n\nexport type WorkerBootRequestHandlerOptions = Omit<\n\tSecondaryWorkerBootArgs,\n\t'mountsBeforeWpInstall' | 'mountsAfterWpInstall'\n> & {\n\tonPHPInstanceCreated: PHPInstanceCreatedHook;\n};\n\nexport class PlaygroundCliBlueprintV2Worker extends PHPWorker {\n\tbooted = false;\n\tblueprintTargetResolved = false;\n\tphpInstancesThatNeedMountsAfterTargetResolved = new Set<PHP>();\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(args: PrimaryWorkerBootArgs) {\n\t\tconst constants = {\n\t\t\tWP_DEBUG: true,\n\t\t\tWP_DEBUG_LOG: true,\n\t\t\tWP_DEBUG_DISPLAY: false,\n\t\t};\n\t\tconst requestHandlerOptions: WorkerBootRequestHandlerOptions = {\n\t\t\t...args,\n\t\t\tcreateFiles: {\n\t\t\t\t'/internal/shared/ca-bundle.crt': rootCertificates.join('\\n'),\n\t\t\t},\n\t\t\tconstants,\n\t\t\tphpIniEntries: {\n\t\t\t\t'openssl.cafile': '/internal/shared/ca-bundle.crt',\n\t\t\t},\n\t\t\tonPHPInstanceCreated: async (php: PHP) => {\n\t\t\t\tthis.registerWorkerListeners(php);\n\t\t\t\tawait mountResources(php, args['mount-before-install'] || []);\n\t\t\t\tif (this.blueprintTargetResolved) {\n\t\t\t\t\tawait mountResources(php, args.mount || []);\n\t\t\t\t} else {\n\t\t\t\t\t// NOTE: Today (2025-09-11), during boot with a plugin auto-mount,\n\t\t\t\t\t// the Blueprint runner fails unless post-resolution mounts are\n\t\t\t\t\t// added to existing PHP instances. So we track them here so they\n\t\t\t\t\t// can be mounted at the necessary time.\n\t\t\t\t\t// Only plugin auto-mounts seem to need this, so perhaps there\n\t\t\t\t\t// is a change we can make to the Blueprint runner so such\n\t\t\t\t\t// a dance is unnecessary.\n\t\t\t\t\tthis.phpInstancesThatNeedMountsAfterTargetResolved.add(php);\n\t\t\t\t\tphp.addEventListener('runtime.beforeExit', () => {\n\t\t\t\t\t\tthis.phpInstancesThatNeedMountsAfterTargetResolved.delete(\n\t\t\t\t\t\t\tphp\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};\n\t\tawait this.bootRequestHandler(requestHandlerOptions);\n\n\t\tconst primaryPhp = this.__internal_getPHP()!;\n\n\t\tif (args.mode === 'mount-only') {\n\t\t\tawait mountResources(primaryPhp, args.mount || []);\n\t\t\treturn;\n\t\t}\n\n\t\tawait this.runBlueprintV2(args);\n\t}\n\n\tasync bootAsSecondaryWorker(args: SecondaryWorkerBootArgs) {\n\t\tawait this.bootRequestHandler({\n\t\t\t...args,\n\t\t\tonPHPInstanceCreated: async (php: PHP) => {\n\t\t\t\tawait mountResources(php, args.mountsBeforeWpInstall || []);\n\t\t\t\tawait mountResources(php, args.mountsAfterWpInstall || []);\n\t\t\t},\n\t\t});\n\t}\n\n\tasync runBlueprintV2(args: WorkerRunBlueprintArgs) {\n\t\tconst requestHandler = this.__internal_getRequestHandler()!;\n\t\tconst { php, reap } =\n\t\t\tawait requestHandler.processManager.acquirePHPInstance({\n\t\t\t\tconsiderPrimary: false,\n\t\t\t});\n\n\t\t// Mount the current working directory to the PHP runtime for the purposes of\n\t\t// Blueprint resolution.\n\t\tconst primaryPhp = this.__internal_getPHP()!;\n\t\tlet unmountCwd = () => {};\n\t\tif (typeof args.blueprint === 'string') {\n\t\t\tconst blueprintPath = path.resolve(process.cwd(), args.blueprint);\n\t\t\tif (existsSync(blueprintPath)) {\n\t\t\t\tprimaryPhp.mkdir('/internal/shared/cwd');\n\t\t\t\tunmountCwd = await primaryPhp.mount(\n\t\t\t\t\t'/internal/shared/cwd',\n\t\t\t\t\tcreateNodeFsMountHandler(path.dirname(blueprintPath))\n\t\t\t\t);\n\t\t\t\targs.blueprint = path.join(\n\t\t\t\t\t'/internal/shared/cwd',\n\t\t\t\t\tpath.basename(args.blueprint)\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\t\t\tconst cliArgsToPass: (keyof WorkerRunBlueprintArgs)[] = [\n\t\t\t\t'mode',\n\t\t\t\t'db-engine',\n\t\t\t\t'db-host',\n\t\t\t\t'db-user',\n\t\t\t\t'db-pass',\n\t\t\t\t'db-name',\n\t\t\t\t'db-path',\n\t\t\t\t'truncate-new-site-directory',\n\t\t\t\t'allow',\n\t\t\t];\n\t\t\tconst cliArgs = cliArgsToPass\n\t\t\t\t.filter((arg) => arg in args)\n\t\t\t\t.map((arg) => `--${arg}=${args[arg]}`);\n\t\t\tcliArgs.push(`--site-url=${args.siteUrl}`);\n\n\t\t\tconst streamedResponse = await runBlueprintV2({\n\t\t\t\tphp,\n\t\t\t\tblueprint: args.blueprint,\n\t\t\t\tblueprintOverrides: {\n\t\t\t\t\tadditionalSteps: args['additional-blueprint-steps'],\n\t\t\t\t\twordpressVersion: args.wp,\n\t\t\t\t},\n\t\t\t\tcliArgs,\n\t\t\t\tonMessage: async (message: BlueprintMessage) => {\n\t\t\t\t\tswitch (message.type) {\n\t\t\t\t\t\tcase 'blueprint.target_resolved': {\n\t\t\t\t\t\t\tif (!this.blueprintTargetResolved) {\n\t\t\t\t\t\t\t\tthis.blueprintTargetResolved = true;\n\t\t\t\t\t\t\t\tfor (const php of this\n\t\t\t\t\t\t\t\t\t.phpInstancesThatNeedMountsAfterTargetResolved) {\n\t\t\t\t\t\t\t\t\t// console.log('mounting resources for php', php);\n\t\t\t\t\t\t\t\t\tthis.phpInstancesThatNeedMountsAfterTargetResolved.delete(\n\t\t\t\t\t\t\t\t\t\tphp\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\tawait mountResources(php, args.mount || []);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcase 'blueprint.progress': {\n\t\t\t\t\t\t\tconst progressMessage = `${message.caption.trim()} – ${message.progress.toFixed(\n\t\t\t\t\t\t\t\t2\n\t\t\t\t\t\t\t)}%`;\n\t\t\t\t\t\t\toutput.progress(progressMessage);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcase 'blueprint.error': {\n\t\t\t\t\t\t\tconst red = '\\x1b[31m';\n\t\t\t\t\t\t\tconst bold = '\\x1b[1m';\n\t\t\t\t\t\t\tconst reset = '\\x1b[0m';\n\t\t\t\t\t\t\tif (args.debug && message.details) {\n\t\t\t\t\t\t\t\toutput.stderr(\n\t\t\t\t\t\t\t\t\t`${red}${bold}Fatal error:${reset} Uncaught ${message.details.exception}: ${message.details.message}\\n` +\n\t\t\t\t\t\t\t\t\t\t` at ${message.details.file}:${message.details.line}\\n` +\n\t\t\t\t\t\t\t\t\t\t(message.details.trace\n\t\t\t\t\t\t\t\t\t\t\t? message.details.trace + '\\n'\n\t\t\t\t\t\t\t\t\t\t\t: '')\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\toutput.stderr(\n\t\t\t\t\t\t\t\t\t`${red}${bold}Error:${reset} ${message.message}\\n`\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\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\t/**\n\t\t\t * When we're debugging, every bit of information matters – let's immediately output\n\t\t\t * everything we get from the PHP output streams.\n\t\t\t */\n\t\t\tif (args.debug) {\n\t\t\t\tstreamedResponse!.stdout.pipeTo(\n\t\t\t\t\tnew WritableStream({\n\t\t\t\t\t\twrite(chunk) {\n\t\t\t\t\t\t\tprocess.stdout.write(chunk);\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t);\n\t\t\t\tstreamedResponse!.stderr.pipeTo(\n\t\t\t\t\tnew WritableStream({\n\t\t\t\t\t\twrite(chunk) {\n\t\t\t\t\t\t\tprocess.stderr.write(chunk);\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\tawait streamedResponse!.finished;\n\t\t\tif ((await streamedResponse!.exitCode) !== 0) {\n\t\t\t\t// exitCode != 1 means the blueprint execution failed. Let's throw an error.\n\t\t\t\t// and clean up.\n\t\t\t\tconst syncResponse = await PHPResponse.fromStreamedResponse(\n\t\t\t\t\tstreamedResponse\n\t\t\t\t);\n\t\t\t\tthrow new PHPExecutionFailureError(\n\t\t\t\t\t`PHP.run() failed with exit code ${syncResponse.exitCode}.`,\n\t\t\t\t\tsyncResponse,\n\t\t\t\t\t'request'\n\t\t\t\t);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// Capture the PHP error log details to provide more context for debugging.\n\t\t\tlet phpLogs = '';\n\t\t\ttry {\n\t\t\t\t// @TODO: Don't assume errorLogPath starts with /wordpress/\n\t\t\t\t// ...or maybe we can assume that in Playground CLI?\n\t\t\t\tphpLogs = php.readFileAsText(errorLogPath);\n\t\t\t} catch {\n\t\t\t\t// Ignore errors reading the PHP error log.\n\t\t\t}\n\t\t\t(error as any).phpLogs = phpLogs;\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\treap();\n\t\t\tunmountCwd();\n\t\t}\n\t}\n\n\tasync bootRequestHandler({\n\t\tsiteUrl,\n\t\tallow,\n\t\tphpVersion,\n\t\tcreateFiles,\n\t\tconstants,\n\t\tphpIniEntries,\n\t\tfirstProcessId,\n\t\tprocessIdSpaceLength,\n\t\ttrace,\n\t\tnativeInternalDirPath,\n\t\twithXdebug,\n\t\tonPHPInstanceCreated,\n\t}: WorkerBootRequestHandlerOptions) {\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 requestHandler = await bootRequestHandler({\n\t\t\t\tsiteUrl,\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\tENV: {\n\t\t\t\t\t\t\t\tDOCROOT: '/wordpress',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tphpWasmInitOptions: { nativeInternalDirPath },\n\t\t\t\t\t\t},\n\t\t\t\t\t\tfollowSymlinks: allow?.includes('follow-symlinks'),\n\t\t\t\t\t\twithXdebug,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\tonPHPInstanceCreated,\n\t\t\t\tsapiName: 'cli',\n\t\t\t\tcreateFiles,\n\t\t\t\tconstants,\n\t\t\t\tphpIniEntries,\n\t\t\t\tcookieStore: false,\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\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\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 PlaygroundCliBlueprintV2Worker(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","output","tracePhpWasm","processId","format","args","sprintf","data","PlaygroundCliBlueprintV2Worker","PHPWorker","monitor","port","jspi","consumeAPI","consumeAPISync","constants","requestHandlerOptions","rootCertificates","primaryPhp","requestHandler","reap","unmountCwd","blueprintPath","path","existsSync","cliArgs","arg","streamedResponse","runBlueprintV2","message","progressMessage","red","bold","reset","chunk","syncResponse","PHPResponse","PHPExecutionFailureError","error","phpLogs","errorLogPath","siteUrl","allow","phpVersion","createFiles","phpIniEntries","firstProcessId","processIdSpaceLength","trace","nativeInternalDirPath","withXdebug","onPHPInstanceCreated","nextProcessId","lastProcessId","bootRequestHandler","loadNodeRuntime","sandboxedSpawnHandlerFactory","setApiReady","e","setAPIError","phpChannel","MessageChannel","exposeAPI","EmscriptenDownloadMonitor","parentPort"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"worker-thread-v2.cjs","sources":["../../../../packages/playground/cli/src/blueprints-v2/worker-thread-v2.ts"],"sourcesContent":["import { errorLogPath, logger } from '@php-wasm/logger';\nimport type { FileLockManager } from '@php-wasm/node';\nimport { createNodeFsMountHandler, loadNodeRuntime } from '@php-wasm/node';\nimport { EmscriptenDownloadMonitor } from '@php-wasm/progress';\nimport type {\n\tPHP,\n\tFileTree,\n\tRemoteAPI,\n\tSupportedPHPVersion,\n} from '@php-wasm/universal';\nimport {\n\tPHPExecutionFailureError,\n\tPHPResponse,\n\tPHPWorker,\n\tconsumeAPI,\n\tconsumeAPISync,\n\texposeAPI,\n\tsandboxedSpawnHandlerFactory,\n} from '@php-wasm/universal';\nimport { sprintf } from '@php-wasm/util';\nimport {\n\ttype BlueprintMessage,\n\trunBlueprintV2,\n\ttype BlueprintV1Declaration,\n} from '@wp-playground/blueprints';\nimport {\n\ttype ParsedBlueprintV2String,\n\ttype RawBlueprintV2Data,\n} from '@wp-playground/blueprints';\nimport { bootRequestHandler } from '@wp-playground/wordpress';\nimport { existsSync } from 'fs';\nimport path from 'path';\nimport { rootCertificates } from 'tls';\nimport { MessageChannel, type MessagePort, parentPort } from 'worker_threads';\nimport type { Mount } from '../mounts';\nimport { jspi } from 'wasm-feature-detect';\nimport { type RunCLIArgs } from '../run-cli';\nimport type {\n\tPhpIniOptions,\n\tPHPInstanceCreatedHook,\n} from '@wp-playground/wordpress';\n\nasync function mountResources(php: PHP, mounts: Mount[]) {\n\tfor (const mount of mounts) {\n\t\ttry {\n\t\t\tphp.mkdir(mount.vfsPath);\n\t\t\tawait php.mount(\n\t\t\t\tmount.vfsPath,\n\t\t\t\tcreateNodeFsMountHandler(mount.hostPath)\n\t\t\t);\n\t\t} catch {\n\t\t\toutput.stderr(\n\t\t\t\t`\\x1b[31m\\x1b[1mError mounting path ${mount.hostPath} at ${mount.vfsPath}\\x1b[0m\\n`\n\t\t\t);\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\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\n/**\n * Force TTY status to preserve ANSI control codes in the output.\n *\n * This script is spawned as `new Worker()` and process.stdout and process.stderr are\n * WritableWorkerStdio objects. By default, they strip ANSI control codes from the output\n * causing every progress bar update to be printed in a new line instead of updating the\n * same line.\n */\nObject.defineProperty(process.stdout, 'isTTY', { value: true });\nObject.defineProperty(process.stderr, 'isTTY', { value: true });\n\n/**\n * Output writer that ensures that progress bars are not printed on the same line as other output.\n */\nconst output = {\n\tlastWriteWasProgress: false,\n\tprogress(data: string) {\n\t\tif (!process.stdout.isTTY) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.log(data);\n\t\t} else {\n\t\t\tif (!output.lastWriteWasProgress) {\n\t\t\t\tprocess.stdout.write('\\n');\n\t\t\t}\n\t\t\tprocess.stdout.write('\\r\\x1b[K' + data);\n\t\t\toutput.lastWriteWasProgress = true;\n\t\t}\n\t},\n\tstdout(data: string) {\n\t\tif (output.lastWriteWasProgress) {\n\t\t\tprocess.stdout.write('\\n');\n\t\t\toutput.lastWriteWasProgress = false;\n\t\t}\n\t\tprocess.stdout.write(data);\n\t},\n\tstderr(data: string) {\n\t\tif (output.lastWriteWasProgress) {\n\t\t\tprocess.stdout.write('\\n');\n\t\t\toutput.lastWriteWasProgress = false;\n\t\t}\n\t\tprocess.stderr.write(data);\n\t},\n};\n\nexport type PrimaryWorkerBootArgs = RunCLIArgs & {\n\tphpVersion: SupportedPHPVersion;\n\tsiteUrl: string;\n\tfirstProcessId: number;\n\tprocessIdSpaceLength: number;\n\ttrace: boolean;\n\tblueprint:\n\t\t| RawBlueprintV2Data\n\t\t| ParsedBlueprintV2String\n\t\t| BlueprintV1Declaration;\n\tnativeInternalDirPath: string;\n};\n\ntype WorkerRunBlueprintArgs = RunCLIArgs & {\n\tsiteUrl: string;\n\tblueprint:\n\t\t| RawBlueprintV2Data\n\t\t| ParsedBlueprintV2String\n\t\t| BlueprintV1Declaration;\n};\n\nexport type SecondaryWorkerBootArgs = {\n\tsiteUrl: string;\n\tallow?: string;\n\tphpVersion: SupportedPHPVersion;\n\tphpIniEntries?: PhpIniOptions;\n\tconstants?: Record<string, string | number | boolean | null>;\n\tcreateFiles?: FileTree;\n\tfirstProcessId: number;\n\tprocessIdSpaceLength: number;\n\ttrace: boolean;\n\tnativeInternalDirPath: string;\n\twithXdebug?: boolean;\n\tmountsBeforeWpInstall?: Array<Mount>;\n\tmountsAfterWpInstall?: Array<Mount>;\n};\n\nexport type WorkerBootRequestHandlerOptions = Omit<\n\tSecondaryWorkerBootArgs,\n\t'mountsBeforeWpInstall' | 'mountsAfterWpInstall'\n> & {\n\tonPHPInstanceCreated: PHPInstanceCreatedHook;\n};\n\nexport class PlaygroundCliBlueprintV2Worker extends PHPWorker {\n\tbooted = false;\n\tblueprintTargetResolved = false;\n\tphpInstancesThatNeedMountsAfterTargetResolved = new Set<PHP>();\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(args: PrimaryWorkerBootArgs) {\n\t\tconst constants = {\n\t\t\tWP_DEBUG: true,\n\t\t\tWP_DEBUG_LOG: true,\n\t\t\tWP_DEBUG_DISPLAY: false,\n\t\t};\n\t\tconst requestHandlerOptions: WorkerBootRequestHandlerOptions = {\n\t\t\t...args,\n\t\t\tcreateFiles: {\n\t\t\t\t'/internal/shared/ca-bundle.crt': rootCertificates.join('\\n'),\n\t\t\t},\n\t\t\tconstants,\n\t\t\tphpIniEntries: {\n\t\t\t\t'openssl.cafile': '/internal/shared/ca-bundle.crt',\n\t\t\t},\n\t\t\tonPHPInstanceCreated: async (php: PHP) => {\n\t\t\t\tthis.registerWorkerListeners(php);\n\t\t\t\tawait mountResources(php, args['mount-before-install'] || []);\n\t\t\t\tif (this.blueprintTargetResolved) {\n\t\t\t\t\tawait mountResources(php, args.mount || []);\n\t\t\t\t} else {\n\t\t\t\t\t// NOTE: Today (2025-09-11), during boot with a plugin auto-mount,\n\t\t\t\t\t// the Blueprint runner fails unless post-resolution mounts are\n\t\t\t\t\t// added to existing PHP instances. So we track them here so they\n\t\t\t\t\t// can be mounted at the necessary time.\n\t\t\t\t\t// Only plugin auto-mounts seem to need this, so perhaps there\n\t\t\t\t\t// is a change we can make to the Blueprint runner so such\n\t\t\t\t\t// a dance is unnecessary.\n\t\t\t\t\tthis.phpInstancesThatNeedMountsAfterTargetResolved.add(php);\n\t\t\t\t\tphp.addEventListener('runtime.beforeExit', () => {\n\t\t\t\t\t\tthis.phpInstancesThatNeedMountsAfterTargetResolved.delete(\n\t\t\t\t\t\t\tphp\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};\n\t\tawait this.bootRequestHandler(requestHandlerOptions);\n\n\t\tconst primaryPhp = this.__internal_getPHP()!;\n\n\t\tif (args.mode === 'mount-only') {\n\t\t\tawait mountResources(primaryPhp, args.mount || []);\n\t\t\treturn;\n\t\t}\n\n\t\tawait this.runBlueprintV2(args);\n\t}\n\n\tasync bootAsSecondaryWorker(args: SecondaryWorkerBootArgs) {\n\t\tawait this.bootRequestHandler({\n\t\t\t...args,\n\t\t\tonPHPInstanceCreated: async (php: PHP) => {\n\t\t\t\tawait mountResources(php, args.mountsBeforeWpInstall || []);\n\t\t\t\tawait mountResources(php, args.mountsAfterWpInstall || []);\n\t\t\t},\n\t\t});\n\t}\n\n\tasync runBlueprintV2(args: WorkerRunBlueprintArgs) {\n\t\tconst requestHandler = this.__internal_getRequestHandler()!;\n\t\tconst { php, reap } =\n\t\t\tawait requestHandler.processManager.acquirePHPInstance({\n\t\t\t\tconsiderPrimary: false,\n\t\t\t});\n\n\t\t// Mount the current working directory to the PHP runtime for the purposes of\n\t\t// Blueprint resolution.\n\t\tconst primaryPhp = this.__internal_getPHP()!;\n\t\tlet unmountCwd = () => {};\n\t\tif (typeof args.blueprint === 'string') {\n\t\t\tconst blueprintPath = path.resolve(process.cwd(), args.blueprint);\n\t\t\tif (existsSync(blueprintPath)) {\n\t\t\t\tprimaryPhp.mkdir('/internal/shared/cwd');\n\t\t\t\tunmountCwd = await primaryPhp.mount(\n\t\t\t\t\t'/internal/shared/cwd',\n\t\t\t\t\tcreateNodeFsMountHandler(path.dirname(blueprintPath))\n\t\t\t\t);\n\t\t\t\targs.blueprint = path.join(\n\t\t\t\t\t'/internal/shared/cwd',\n\t\t\t\t\tpath.basename(args.blueprint)\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\t\t\tconst cliArgsToPass: (keyof WorkerRunBlueprintArgs)[] = [\n\t\t\t\t'mode',\n\t\t\t\t'db-engine',\n\t\t\t\t'db-host',\n\t\t\t\t'db-user',\n\t\t\t\t'db-pass',\n\t\t\t\t'db-name',\n\t\t\t\t'db-path',\n\t\t\t\t'truncate-new-site-directory',\n\t\t\t\t'allow',\n\t\t\t];\n\t\t\tconst cliArgs = cliArgsToPass\n\t\t\t\t.filter((arg) => arg in args)\n\t\t\t\t.map((arg) => `--${arg}=${args[arg]}`);\n\t\t\tcliArgs.push(`--site-url=${args.siteUrl}`);\n\n\t\t\tconst streamedResponse = await runBlueprintV2({\n\t\t\t\tphp,\n\t\t\t\tblueprint: args.blueprint,\n\t\t\t\tblueprintOverrides: {\n\t\t\t\t\tadditionalSteps: args['additional-blueprint-steps'],\n\t\t\t\t\twordpressVersion: args.wp,\n\t\t\t\t},\n\t\t\t\tcliArgs,\n\t\t\t\tonMessage: async (message: BlueprintMessage) => {\n\t\t\t\t\tswitch (message.type) {\n\t\t\t\t\t\tcase 'blueprint.target_resolved': {\n\t\t\t\t\t\t\tif (!this.blueprintTargetResolved) {\n\t\t\t\t\t\t\t\tthis.blueprintTargetResolved = true;\n\t\t\t\t\t\t\t\tfor (const php of this\n\t\t\t\t\t\t\t\t\t.phpInstancesThatNeedMountsAfterTargetResolved) {\n\t\t\t\t\t\t\t\t\t// console.log('mounting resources for php', php);\n\t\t\t\t\t\t\t\t\tthis.phpInstancesThatNeedMountsAfterTargetResolved.delete(\n\t\t\t\t\t\t\t\t\t\tphp\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\tawait mountResources(php, args.mount || []);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcase 'blueprint.progress': {\n\t\t\t\t\t\t\tconst progressMessage = `${message.caption.trim()} – ${message.progress.toFixed(\n\t\t\t\t\t\t\t\t2\n\t\t\t\t\t\t\t)}%`;\n\t\t\t\t\t\t\toutput.progress(progressMessage);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcase 'blueprint.error': {\n\t\t\t\t\t\t\tconst red = '\\x1b[31m';\n\t\t\t\t\t\t\tconst bold = '\\x1b[1m';\n\t\t\t\t\t\t\tconst reset = '\\x1b[0m';\n\t\t\t\t\t\t\tif (args.debug && message.details) {\n\t\t\t\t\t\t\t\toutput.stderr(\n\t\t\t\t\t\t\t\t\t`${red}${bold}Fatal error:${reset} Uncaught ${message.details.exception}: ${message.details.message}\\n` +\n\t\t\t\t\t\t\t\t\t\t` at ${message.details.file}:${message.details.line}\\n` +\n\t\t\t\t\t\t\t\t\t\t(message.details.trace\n\t\t\t\t\t\t\t\t\t\t\t? message.details.trace + '\\n'\n\t\t\t\t\t\t\t\t\t\t\t: '')\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\toutput.stderr(\n\t\t\t\t\t\t\t\t\t`${red}${bold}Error:${reset} ${message.message}\\n`\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\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\t/**\n\t\t\t * When we're debugging, every bit of information matters – let's immediately output\n\t\t\t * everything we get from the PHP output streams.\n\t\t\t */\n\t\t\tif (args.debug) {\n\t\t\t\tstreamedResponse!.stdout.pipeTo(\n\t\t\t\t\tnew WritableStream({\n\t\t\t\t\t\twrite(chunk) {\n\t\t\t\t\t\t\tprocess.stdout.write(chunk);\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t);\n\t\t\t\tstreamedResponse!.stderr.pipeTo(\n\t\t\t\t\tnew WritableStream({\n\t\t\t\t\t\twrite(chunk) {\n\t\t\t\t\t\t\tprocess.stderr.write(chunk);\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\tawait streamedResponse!.finished;\n\t\t\tif ((await streamedResponse!.exitCode) !== 0) {\n\t\t\t\t// exitCode != 1 means the blueprint execution failed. Let's throw an error.\n\t\t\t\t// and clean up.\n\t\t\t\tconst syncResponse = await PHPResponse.fromStreamedResponse(\n\t\t\t\t\tstreamedResponse\n\t\t\t\t);\n\t\t\t\tthrow new PHPExecutionFailureError(\n\t\t\t\t\t`PHP.run() failed with exit code ${syncResponse.exitCode}.`,\n\t\t\t\t\tsyncResponse,\n\t\t\t\t\t'request'\n\t\t\t\t);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// Capture the PHP error log details to provide more context for debugging.\n\t\t\tlet phpLogs = '';\n\t\t\ttry {\n\t\t\t\t// @TODO: Don't assume errorLogPath starts with /wordpress/\n\t\t\t\t// ...or maybe we can assume that in Playground CLI?\n\t\t\t\tphpLogs = php.readFileAsText(errorLogPath);\n\t\t\t} catch {\n\t\t\t\t// Ignore errors reading the PHP error log.\n\t\t\t}\n\t\t\t(error as any).phpLogs = phpLogs;\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\treap();\n\t\t\tunmountCwd();\n\t\t}\n\t}\n\n\tasync bootRequestHandler({\n\t\tsiteUrl,\n\t\tallow,\n\t\tphpVersion,\n\t\tcreateFiles,\n\t\tconstants,\n\t\tphpIniEntries,\n\t\tfirstProcessId,\n\t\tprocessIdSpaceLength,\n\t\ttrace,\n\t\tnativeInternalDirPath,\n\t\twithXdebug,\n\t\tonPHPInstanceCreated,\n\t}: WorkerBootRequestHandlerOptions) {\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 requestHandler = await bootRequestHandler({\n\t\t\t\tsiteUrl,\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\tENV: {\n\t\t\t\t\t\t\t\tDOCROOT: '/wordpress',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tphpWasmInitOptions: { nativeInternalDirPath },\n\t\t\t\t\t\t},\n\t\t\t\t\t\tfollowSymlinks: allow?.includes('follow-symlinks'),\n\t\t\t\t\t\twithXdebug,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\tonPHPInstanceCreated,\n\t\t\t\tsapiName: 'cli',\n\t\t\t\tcreateFiles,\n\t\t\t\tconstants,\n\t\t\t\tphpIniEntries,\n\t\t\t\tcookieStore: false,\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\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\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\nprocess.on('unhandledRejection', (e: any) => {\n\tlogger.error('Unhandled rejection:', e);\n});\n\nconst phpChannel = new MessageChannel();\n\nconst [setApiReady, setAPIError] = exposeAPI(\n\tnew PlaygroundCliBlueprintV2Worker(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","output","tracePhpWasm","processId","format","args","sprintf","data","PlaygroundCliBlueprintV2Worker","PHPWorker","monitor","port","jspi","consumeAPI","consumeAPISync","constants","requestHandlerOptions","rootCertificates","primaryPhp","requestHandler","reap","unmountCwd","blueprintPath","path","existsSync","cliArgs","arg","streamedResponse","runBlueprintV2","message","progressMessage","red","bold","reset","chunk","syncResponse","PHPResponse","PHPExecutionFailureError","error","phpLogs","errorLogPath","siteUrl","allow","phpVersion","createFiles","phpIniEntries","firstProcessId","processIdSpaceLength","trace","nativeInternalDirPath","withXdebug","onPHPInstanceCreated","nextProcessId","lastProcessId","bootRequestHandler","loadNodeRuntime","sandboxedSpawnHandlerFactory","setApiReady","e","setAPIError","logger","phpChannel","MessageChannel","exposeAPI","EmscriptenDownloadMonitor","parentPort"],"mappings":"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"}
|
package/worker-thread-v2.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { createNodeFsMountHandler as y, loadNodeRuntime as
|
|
3
|
-
import { EmscriptenDownloadMonitor as
|
|
4
|
-
import { exposeAPI as
|
|
5
|
-
import { sprintf as
|
|
6
|
-
import { runBlueprintV2 as
|
|
7
|
-
import { bootRequestHandler as
|
|
8
|
-
import { existsSync as
|
|
1
|
+
import { logger as R, errorLogPath as x } from "@php-wasm/logger";
|
|
2
|
+
import { createNodeFsMountHandler as y, loadNodeRuntime as H } from "@php-wasm/node";
|
|
3
|
+
import { EmscriptenDownloadMonitor as v } from "@php-wasm/progress";
|
|
4
|
+
import { exposeAPI as k, PHPWorker as $, consumeAPI as A, consumeAPISync as I, PHPResponse as _, PHPExecutionFailureError as M, sandboxedSpawnHandlerFactory as S } from "@php-wasm/universal";
|
|
5
|
+
import { sprintf as B } from "@php-wasm/util";
|
|
6
|
+
import { runBlueprintV2 as E } from "@wp-playground/blueprints";
|
|
7
|
+
import { bootRequestHandler as L } from "@wp-playground/wordpress";
|
|
8
|
+
import { existsSync as q } from "fs";
|
|
9
9
|
import P from "path";
|
|
10
|
-
import { rootCertificates as
|
|
11
|
-
import { MessageChannel as
|
|
12
|
-
import { jspi as
|
|
10
|
+
import { rootCertificates as C } from "tls";
|
|
11
|
+
import { MessageChannel as O, parentPort as F } from "worker_threads";
|
|
12
|
+
import { jspi as N } from "wasm-feature-detect";
|
|
13
13
|
async function u(s, e) {
|
|
14
14
|
for (const r of e)
|
|
15
15
|
try {
|
|
@@ -24,11 +24,11 @@ async function u(s, e) {
|
|
|
24
24
|
), process.exit(1);
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
-
function
|
|
27
|
+
function j(s, e, ...r) {
|
|
28
28
|
console.log(
|
|
29
29
|
performance.now().toFixed(6).padStart(15, "0"),
|
|
30
30
|
s.toString().padStart(16, "0"),
|
|
31
|
-
|
|
31
|
+
B(e, ...r)
|
|
32
32
|
);
|
|
33
33
|
}
|
|
34
34
|
Object.defineProperty(process.stdout, "isTTY", { value: !0 });
|
|
@@ -48,7 +48,7 @@ const i = {
|
|
|
48
48
|
`), i.lastWriteWasProgress = !1), process.stderr.write(s);
|
|
49
49
|
}
|
|
50
50
|
};
|
|
51
|
-
class D extends
|
|
51
|
+
class D extends $ {
|
|
52
52
|
constructor(e) {
|
|
53
53
|
super(void 0, e), this.booted = !1, this.blueprintTargetResolved = !1, this.phpInstancesThatNeedMountsAfterTargetResolved = /* @__PURE__ */ new Set();
|
|
54
54
|
}
|
|
@@ -62,7 +62,7 @@ class D extends k {
|
|
|
62
62
|
* @see phpwasm-emscripten-library-file-locking-for-node.js
|
|
63
63
|
*/
|
|
64
64
|
async useFileLockManager(e) {
|
|
65
|
-
await
|
|
65
|
+
await N() ? this.fileLockManager = A(e) : this.fileLockManager = await I(e);
|
|
66
66
|
}
|
|
67
67
|
async bootAsPrimaryWorker(e) {
|
|
68
68
|
const r = {
|
|
@@ -72,7 +72,7 @@ class D extends k {
|
|
|
72
72
|
}, p = {
|
|
73
73
|
...e,
|
|
74
74
|
createFiles: {
|
|
75
|
-
"/internal/shared/ca-bundle.crt":
|
|
75
|
+
"/internal/shared/ca-bundle.crt": C.join(`
|
|
76
76
|
`)
|
|
77
77
|
},
|
|
78
78
|
constants: r,
|
|
@@ -111,7 +111,7 @@ class D extends k {
|
|
|
111
111
|
};
|
|
112
112
|
if (typeof e.blueprint == "string") {
|
|
113
113
|
const n = P.resolve(process.cwd(), e.blueprint);
|
|
114
|
-
|
|
114
|
+
q(n) && (o.mkdir("/internal/shared/cwd"), f = await o.mount(
|
|
115
115
|
"/internal/shared/cwd",
|
|
116
116
|
y(P.dirname(n))
|
|
117
117
|
), e.blueprint = P.join(
|
|
@@ -132,7 +132,7 @@ class D extends k {
|
|
|
132
132
|
"allow"
|
|
133
133
|
].filter((t) => t in e).map((t) => `--${t}=${e[t]}`);
|
|
134
134
|
l.push(`--site-url=${e.siteUrl}`);
|
|
135
|
-
const d = await
|
|
135
|
+
const d = await E({
|
|
136
136
|
php: p,
|
|
137
137
|
blueprint: e.blueprint,
|
|
138
138
|
blueprintOverrides: {
|
|
@@ -188,10 +188,10 @@ class D extends k {
|
|
|
188
188
|
}
|
|
189
189
|
})
|
|
190
190
|
)), await d.finished, await d.exitCode !== 0) {
|
|
191
|
-
const t = await
|
|
191
|
+
const t = await _.fromStreamedResponse(
|
|
192
192
|
d
|
|
193
193
|
);
|
|
194
|
-
throw new
|
|
194
|
+
throw new M(
|
|
195
195
|
`PHP.run() failed with exit code ${t.exitCode}.`,
|
|
196
196
|
t,
|
|
197
197
|
"request"
|
|
@@ -200,7 +200,7 @@ class D extends k {
|
|
|
200
200
|
} catch (n) {
|
|
201
201
|
let l = "";
|
|
202
202
|
try {
|
|
203
|
-
l = p.readFileAsText(
|
|
203
|
+
l = p.readFileAsText(x);
|
|
204
204
|
} catch {
|
|
205
205
|
}
|
|
206
206
|
throw n.phpLogs = l, n;
|
|
@@ -226,17 +226,17 @@ class D extends k {
|
|
|
226
226
|
throw new Error("Playground already booted");
|
|
227
227
|
this.booted = !0;
|
|
228
228
|
let c = n;
|
|
229
|
-
const
|
|
229
|
+
const g = n + l - 1;
|
|
230
230
|
try {
|
|
231
|
-
const m = await
|
|
231
|
+
const m = await L({
|
|
232
232
|
siteUrl: e,
|
|
233
233
|
createPhpRuntime: async () => {
|
|
234
234
|
const T = c;
|
|
235
|
-
return c <
|
|
235
|
+
return c < g ? c++ : c = n, await H(p, {
|
|
236
236
|
emscriptenOptions: {
|
|
237
237
|
fileLockManager: this.fileLockManager,
|
|
238
238
|
processId: T,
|
|
239
|
-
trace: d ?
|
|
239
|
+
trace: d ? j : void 0,
|
|
240
240
|
ENV: {
|
|
241
241
|
DOCROOT: "/wordpress"
|
|
242
242
|
},
|
|
@@ -252,13 +252,13 @@ class D extends k {
|
|
|
252
252
|
constants: o,
|
|
253
253
|
phpIniEntries: f,
|
|
254
254
|
cookieStore: !1,
|
|
255
|
-
spawnHandler:
|
|
255
|
+
spawnHandler: S
|
|
256
256
|
});
|
|
257
257
|
this.__internal_setRequestHandler(m);
|
|
258
|
-
const
|
|
259
|
-
await this.setPrimaryPHP(
|
|
258
|
+
const W = await m.getPrimaryPhp();
|
|
259
|
+
await this.setPrimaryPHP(W), U();
|
|
260
260
|
} catch (m) {
|
|
261
|
-
throw
|
|
261
|
+
throw V(m), m;
|
|
262
262
|
}
|
|
263
263
|
}
|
|
264
264
|
// Provide a named disposal method that can be invoked via comlink.
|
|
@@ -266,12 +266,15 @@ class D extends k {
|
|
|
266
266
|
await this[Symbol.asyncDispose]();
|
|
267
267
|
}
|
|
268
268
|
}
|
|
269
|
-
|
|
270
|
-
|
|
269
|
+
process.on("unhandledRejection", (s) => {
|
|
270
|
+
R.error("Unhandled rejection:", s);
|
|
271
|
+
});
|
|
272
|
+
const b = new O(), [U, V] = k(
|
|
273
|
+
new D(new v()),
|
|
271
274
|
void 0,
|
|
272
275
|
b.port1
|
|
273
276
|
);
|
|
274
|
-
|
|
277
|
+
F?.postMessage(
|
|
275
278
|
{
|
|
276
279
|
command: "worker-script-initialized",
|
|
277
280
|
phpPort: b.port2
|
package/worker-thread-v2.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker-thread-v2.js","sources":["../../../../packages/playground/cli/src/blueprints-v2/worker-thread-v2.ts"],"sourcesContent":["import { errorLogPath } from '@php-wasm/logger';\nimport type { FileLockManager } from '@php-wasm/node';\nimport { createNodeFsMountHandler, loadNodeRuntime } from '@php-wasm/node';\nimport { EmscriptenDownloadMonitor } from '@php-wasm/progress';\nimport type {\n\tPHP,\n\tFileTree,\n\tRemoteAPI,\n\tSupportedPHPVersion,\n} from '@php-wasm/universal';\nimport {\n\tPHPExecutionFailureError,\n\tPHPResponse,\n\tPHPWorker,\n\tconsumeAPI,\n\tconsumeAPISync,\n\texposeAPI,\n\tsandboxedSpawnHandlerFactory,\n} from '@php-wasm/universal';\nimport { sprintf } from '@php-wasm/util';\nimport {\n\ttype BlueprintMessage,\n\trunBlueprintV2,\n\ttype BlueprintV1Declaration,\n} from '@wp-playground/blueprints';\nimport {\n\ttype ParsedBlueprintV2String,\n\ttype RawBlueprintV2Data,\n} from '@wp-playground/blueprints';\nimport { bootRequestHandler } from '@wp-playground/wordpress';\nimport { existsSync } from 'fs';\nimport path from 'path';\nimport { rootCertificates } from 'tls';\nimport { MessageChannel, type MessagePort, parentPort } from 'worker_threads';\nimport type { Mount } from '../mounts';\nimport { jspi } from 'wasm-feature-detect';\nimport { type RunCLIArgs } from '../run-cli';\nimport type {\n\tPhpIniOptions,\n\tPHPInstanceCreatedHook,\n} from '@wp-playground/wordpress';\n\nasync function mountResources(php: PHP, mounts: Mount[]) {\n\tfor (const mount of mounts) {\n\t\ttry {\n\t\t\tphp.mkdir(mount.vfsPath);\n\t\t\tawait php.mount(\n\t\t\t\tmount.vfsPath,\n\t\t\t\tcreateNodeFsMountHandler(mount.hostPath)\n\t\t\t);\n\t\t} catch {\n\t\t\toutput.stderr(\n\t\t\t\t`\\x1b[31m\\x1b[1mError mounting path ${mount.hostPath} at ${mount.vfsPath}\\x1b[0m\\n`\n\t\t\t);\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\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\n/**\n * Force TTY status to preserve ANSI control codes in the output.\n *\n * This script is spawned as `new Worker()` and process.stdout and process.stderr are\n * WritableWorkerStdio objects. By default, they strip ANSI control codes from the output\n * causing every progress bar update to be printed in a new line instead of updating the\n * same line.\n */\nObject.defineProperty(process.stdout, 'isTTY', { value: true });\nObject.defineProperty(process.stderr, 'isTTY', { value: true });\n\n/**\n * Output writer that ensures that progress bars are not printed on the same line as other output.\n */\nconst output = {\n\tlastWriteWasProgress: false,\n\tprogress(data: string) {\n\t\tif (!process.stdout.isTTY) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.log(data);\n\t\t} else {\n\t\t\tif (!output.lastWriteWasProgress) {\n\t\t\t\tprocess.stdout.write('\\n');\n\t\t\t}\n\t\t\tprocess.stdout.write('\\r\\x1b[K' + data);\n\t\t\toutput.lastWriteWasProgress = true;\n\t\t}\n\t},\n\tstdout(data: string) {\n\t\tif (output.lastWriteWasProgress) {\n\t\t\tprocess.stdout.write('\\n');\n\t\t\toutput.lastWriteWasProgress = false;\n\t\t}\n\t\tprocess.stdout.write(data);\n\t},\n\tstderr(data: string) {\n\t\tif (output.lastWriteWasProgress) {\n\t\t\tprocess.stdout.write('\\n');\n\t\t\toutput.lastWriteWasProgress = false;\n\t\t}\n\t\tprocess.stderr.write(data);\n\t},\n};\n\nexport type PrimaryWorkerBootArgs = RunCLIArgs & {\n\tphpVersion: SupportedPHPVersion;\n\tsiteUrl: string;\n\tfirstProcessId: number;\n\tprocessIdSpaceLength: number;\n\ttrace: boolean;\n\tblueprint:\n\t\t| RawBlueprintV2Data\n\t\t| ParsedBlueprintV2String\n\t\t| BlueprintV1Declaration;\n\tnativeInternalDirPath: string;\n};\n\ntype WorkerRunBlueprintArgs = RunCLIArgs & {\n\tsiteUrl: string;\n\tblueprint:\n\t\t| RawBlueprintV2Data\n\t\t| ParsedBlueprintV2String\n\t\t| BlueprintV1Declaration;\n};\n\nexport type SecondaryWorkerBootArgs = {\n\tsiteUrl: string;\n\tallow?: string;\n\tphpVersion: SupportedPHPVersion;\n\tphpIniEntries?: PhpIniOptions;\n\tconstants?: Record<string, string | number | boolean | null>;\n\tcreateFiles?: FileTree;\n\tfirstProcessId: number;\n\tprocessIdSpaceLength: number;\n\ttrace: boolean;\n\tnativeInternalDirPath: string;\n\twithXdebug?: boolean;\n\tmountsBeforeWpInstall?: Array<Mount>;\n\tmountsAfterWpInstall?: Array<Mount>;\n};\n\nexport type WorkerBootRequestHandlerOptions = Omit<\n\tSecondaryWorkerBootArgs,\n\t'mountsBeforeWpInstall' | 'mountsAfterWpInstall'\n> & {\n\tonPHPInstanceCreated: PHPInstanceCreatedHook;\n};\n\nexport class PlaygroundCliBlueprintV2Worker extends PHPWorker {\n\tbooted = false;\n\tblueprintTargetResolved = false;\n\tphpInstancesThatNeedMountsAfterTargetResolved = new Set<PHP>();\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(args: PrimaryWorkerBootArgs) {\n\t\tconst constants = {\n\t\t\tWP_DEBUG: true,\n\t\t\tWP_DEBUG_LOG: true,\n\t\t\tWP_DEBUG_DISPLAY: false,\n\t\t};\n\t\tconst requestHandlerOptions: WorkerBootRequestHandlerOptions = {\n\t\t\t...args,\n\t\t\tcreateFiles: {\n\t\t\t\t'/internal/shared/ca-bundle.crt': rootCertificates.join('\\n'),\n\t\t\t},\n\t\t\tconstants,\n\t\t\tphpIniEntries: {\n\t\t\t\t'openssl.cafile': '/internal/shared/ca-bundle.crt',\n\t\t\t},\n\t\t\tonPHPInstanceCreated: async (php: PHP) => {\n\t\t\t\tthis.registerWorkerListeners(php);\n\t\t\t\tawait mountResources(php, args['mount-before-install'] || []);\n\t\t\t\tif (this.blueprintTargetResolved) {\n\t\t\t\t\tawait mountResources(php, args.mount || []);\n\t\t\t\t} else {\n\t\t\t\t\t// NOTE: Today (2025-09-11), during boot with a plugin auto-mount,\n\t\t\t\t\t// the Blueprint runner fails unless post-resolution mounts are\n\t\t\t\t\t// added to existing PHP instances. So we track them here so they\n\t\t\t\t\t// can be mounted at the necessary time.\n\t\t\t\t\t// Only plugin auto-mounts seem to need this, so perhaps there\n\t\t\t\t\t// is a change we can make to the Blueprint runner so such\n\t\t\t\t\t// a dance is unnecessary.\n\t\t\t\t\tthis.phpInstancesThatNeedMountsAfterTargetResolved.add(php);\n\t\t\t\t\tphp.addEventListener('runtime.beforeExit', () => {\n\t\t\t\t\t\tthis.phpInstancesThatNeedMountsAfterTargetResolved.delete(\n\t\t\t\t\t\t\tphp\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};\n\t\tawait this.bootRequestHandler(requestHandlerOptions);\n\n\t\tconst primaryPhp = this.__internal_getPHP()!;\n\n\t\tif (args.mode === 'mount-only') {\n\t\t\tawait mountResources(primaryPhp, args.mount || []);\n\t\t\treturn;\n\t\t}\n\n\t\tawait this.runBlueprintV2(args);\n\t}\n\n\tasync bootAsSecondaryWorker(args: SecondaryWorkerBootArgs) {\n\t\tawait this.bootRequestHandler({\n\t\t\t...args,\n\t\t\tonPHPInstanceCreated: async (php: PHP) => {\n\t\t\t\tawait mountResources(php, args.mountsBeforeWpInstall || []);\n\t\t\t\tawait mountResources(php, args.mountsAfterWpInstall || []);\n\t\t\t},\n\t\t});\n\t}\n\n\tasync runBlueprintV2(args: WorkerRunBlueprintArgs) {\n\t\tconst requestHandler = this.__internal_getRequestHandler()!;\n\t\tconst { php, reap } =\n\t\t\tawait requestHandler.processManager.acquirePHPInstance({\n\t\t\t\tconsiderPrimary: false,\n\t\t\t});\n\n\t\t// Mount the current working directory to the PHP runtime for the purposes of\n\t\t// Blueprint resolution.\n\t\tconst primaryPhp = this.__internal_getPHP()!;\n\t\tlet unmountCwd = () => {};\n\t\tif (typeof args.blueprint === 'string') {\n\t\t\tconst blueprintPath = path.resolve(process.cwd(), args.blueprint);\n\t\t\tif (existsSync(blueprintPath)) {\n\t\t\t\tprimaryPhp.mkdir('/internal/shared/cwd');\n\t\t\t\tunmountCwd = await primaryPhp.mount(\n\t\t\t\t\t'/internal/shared/cwd',\n\t\t\t\t\tcreateNodeFsMountHandler(path.dirname(blueprintPath))\n\t\t\t\t);\n\t\t\t\targs.blueprint = path.join(\n\t\t\t\t\t'/internal/shared/cwd',\n\t\t\t\t\tpath.basename(args.blueprint)\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\t\t\tconst cliArgsToPass: (keyof WorkerRunBlueprintArgs)[] = [\n\t\t\t\t'mode',\n\t\t\t\t'db-engine',\n\t\t\t\t'db-host',\n\t\t\t\t'db-user',\n\t\t\t\t'db-pass',\n\t\t\t\t'db-name',\n\t\t\t\t'db-path',\n\t\t\t\t'truncate-new-site-directory',\n\t\t\t\t'allow',\n\t\t\t];\n\t\t\tconst cliArgs = cliArgsToPass\n\t\t\t\t.filter((arg) => arg in args)\n\t\t\t\t.map((arg) => `--${arg}=${args[arg]}`);\n\t\t\tcliArgs.push(`--site-url=${args.siteUrl}`);\n\n\t\t\tconst streamedResponse = await runBlueprintV2({\n\t\t\t\tphp,\n\t\t\t\tblueprint: args.blueprint,\n\t\t\t\tblueprintOverrides: {\n\t\t\t\t\tadditionalSteps: args['additional-blueprint-steps'],\n\t\t\t\t\twordpressVersion: args.wp,\n\t\t\t\t},\n\t\t\t\tcliArgs,\n\t\t\t\tonMessage: async (message: BlueprintMessage) => {\n\t\t\t\t\tswitch (message.type) {\n\t\t\t\t\t\tcase 'blueprint.target_resolved': {\n\t\t\t\t\t\t\tif (!this.blueprintTargetResolved) {\n\t\t\t\t\t\t\t\tthis.blueprintTargetResolved = true;\n\t\t\t\t\t\t\t\tfor (const php of this\n\t\t\t\t\t\t\t\t\t.phpInstancesThatNeedMountsAfterTargetResolved) {\n\t\t\t\t\t\t\t\t\t// console.log('mounting resources for php', php);\n\t\t\t\t\t\t\t\t\tthis.phpInstancesThatNeedMountsAfterTargetResolved.delete(\n\t\t\t\t\t\t\t\t\t\tphp\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\tawait mountResources(php, args.mount || []);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcase 'blueprint.progress': {\n\t\t\t\t\t\t\tconst progressMessage = `${message.caption.trim()} – ${message.progress.toFixed(\n\t\t\t\t\t\t\t\t2\n\t\t\t\t\t\t\t)}%`;\n\t\t\t\t\t\t\toutput.progress(progressMessage);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcase 'blueprint.error': {\n\t\t\t\t\t\t\tconst red = '\\x1b[31m';\n\t\t\t\t\t\t\tconst bold = '\\x1b[1m';\n\t\t\t\t\t\t\tconst reset = '\\x1b[0m';\n\t\t\t\t\t\t\tif (args.debug && message.details) {\n\t\t\t\t\t\t\t\toutput.stderr(\n\t\t\t\t\t\t\t\t\t`${red}${bold}Fatal error:${reset} Uncaught ${message.details.exception}: ${message.details.message}\\n` +\n\t\t\t\t\t\t\t\t\t\t` at ${message.details.file}:${message.details.line}\\n` +\n\t\t\t\t\t\t\t\t\t\t(message.details.trace\n\t\t\t\t\t\t\t\t\t\t\t? message.details.trace + '\\n'\n\t\t\t\t\t\t\t\t\t\t\t: '')\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\toutput.stderr(\n\t\t\t\t\t\t\t\t\t`${red}${bold}Error:${reset} ${message.message}\\n`\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\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\t/**\n\t\t\t * When we're debugging, every bit of information matters – let's immediately output\n\t\t\t * everything we get from the PHP output streams.\n\t\t\t */\n\t\t\tif (args.debug) {\n\t\t\t\tstreamedResponse!.stdout.pipeTo(\n\t\t\t\t\tnew WritableStream({\n\t\t\t\t\t\twrite(chunk) {\n\t\t\t\t\t\t\tprocess.stdout.write(chunk);\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t);\n\t\t\t\tstreamedResponse!.stderr.pipeTo(\n\t\t\t\t\tnew WritableStream({\n\t\t\t\t\t\twrite(chunk) {\n\t\t\t\t\t\t\tprocess.stderr.write(chunk);\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\tawait streamedResponse!.finished;\n\t\t\tif ((await streamedResponse!.exitCode) !== 0) {\n\t\t\t\t// exitCode != 1 means the blueprint execution failed. Let's throw an error.\n\t\t\t\t// and clean up.\n\t\t\t\tconst syncResponse = await PHPResponse.fromStreamedResponse(\n\t\t\t\t\tstreamedResponse\n\t\t\t\t);\n\t\t\t\tthrow new PHPExecutionFailureError(\n\t\t\t\t\t`PHP.run() failed with exit code ${syncResponse.exitCode}.`,\n\t\t\t\t\tsyncResponse,\n\t\t\t\t\t'request'\n\t\t\t\t);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// Capture the PHP error log details to provide more context for debugging.\n\t\t\tlet phpLogs = '';\n\t\t\ttry {\n\t\t\t\t// @TODO: Don't assume errorLogPath starts with /wordpress/\n\t\t\t\t// ...or maybe we can assume that in Playground CLI?\n\t\t\t\tphpLogs = php.readFileAsText(errorLogPath);\n\t\t\t} catch {\n\t\t\t\t// Ignore errors reading the PHP error log.\n\t\t\t}\n\t\t\t(error as any).phpLogs = phpLogs;\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\treap();\n\t\t\tunmountCwd();\n\t\t}\n\t}\n\n\tasync bootRequestHandler({\n\t\tsiteUrl,\n\t\tallow,\n\t\tphpVersion,\n\t\tcreateFiles,\n\t\tconstants,\n\t\tphpIniEntries,\n\t\tfirstProcessId,\n\t\tprocessIdSpaceLength,\n\t\ttrace,\n\t\tnativeInternalDirPath,\n\t\twithXdebug,\n\t\tonPHPInstanceCreated,\n\t}: WorkerBootRequestHandlerOptions) {\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 requestHandler = await bootRequestHandler({\n\t\t\t\tsiteUrl,\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\tENV: {\n\t\t\t\t\t\t\t\tDOCROOT: '/wordpress',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tphpWasmInitOptions: { nativeInternalDirPath },\n\t\t\t\t\t\t},\n\t\t\t\t\t\tfollowSymlinks: allow?.includes('follow-symlinks'),\n\t\t\t\t\t\twithXdebug,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\tonPHPInstanceCreated,\n\t\t\t\tsapiName: 'cli',\n\t\t\t\tcreateFiles,\n\t\t\t\tconstants,\n\t\t\t\tphpIniEntries,\n\t\t\t\tcookieStore: false,\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\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\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 PlaygroundCliBlueprintV2Worker(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","output","tracePhpWasm","processId","format","args","sprintf","data","PlaygroundCliBlueprintV2Worker","PHPWorker","monitor","port","jspi","consumeAPI","consumeAPISync","constants","requestHandlerOptions","rootCertificates","primaryPhp","requestHandler","reap","unmountCwd","blueprintPath","path","existsSync","cliArgs","arg","streamedResponse","runBlueprintV2","message","progressMessage","red","bold","reset","chunk","syncResponse","PHPResponse","PHPExecutionFailureError","error","phpLogs","errorLogPath","siteUrl","allow","phpVersion","createFiles","phpIniEntries","firstProcessId","processIdSpaceLength","trace","nativeInternalDirPath","withXdebug","onPHPInstanceCreated","nextProcessId","lastProcessId","bootRequestHandler","loadNodeRuntime","sandboxedSpawnHandlerFactory","setApiReady","e","setAPIError","phpChannel","MessageChannel","exposeAPI","EmscriptenDownloadMonitor","parentPort"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"worker-thread-v2.js","sources":["../../../../packages/playground/cli/src/blueprints-v2/worker-thread-v2.ts"],"sourcesContent":["import { errorLogPath, logger } from '@php-wasm/logger';\nimport type { FileLockManager } from '@php-wasm/node';\nimport { createNodeFsMountHandler, loadNodeRuntime } from '@php-wasm/node';\nimport { EmscriptenDownloadMonitor } from '@php-wasm/progress';\nimport type {\n\tPHP,\n\tFileTree,\n\tRemoteAPI,\n\tSupportedPHPVersion,\n} from '@php-wasm/universal';\nimport {\n\tPHPExecutionFailureError,\n\tPHPResponse,\n\tPHPWorker,\n\tconsumeAPI,\n\tconsumeAPISync,\n\texposeAPI,\n\tsandboxedSpawnHandlerFactory,\n} from '@php-wasm/universal';\nimport { sprintf } from '@php-wasm/util';\nimport {\n\ttype BlueprintMessage,\n\trunBlueprintV2,\n\ttype BlueprintV1Declaration,\n} from '@wp-playground/blueprints';\nimport {\n\ttype ParsedBlueprintV2String,\n\ttype RawBlueprintV2Data,\n} from '@wp-playground/blueprints';\nimport { bootRequestHandler } from '@wp-playground/wordpress';\nimport { existsSync } from 'fs';\nimport path from 'path';\nimport { rootCertificates } from 'tls';\nimport { MessageChannel, type MessagePort, parentPort } from 'worker_threads';\nimport type { Mount } from '../mounts';\nimport { jspi } from 'wasm-feature-detect';\nimport { type RunCLIArgs } from '../run-cli';\nimport type {\n\tPhpIniOptions,\n\tPHPInstanceCreatedHook,\n} from '@wp-playground/wordpress';\n\nasync function mountResources(php: PHP, mounts: Mount[]) {\n\tfor (const mount of mounts) {\n\t\ttry {\n\t\t\tphp.mkdir(mount.vfsPath);\n\t\t\tawait php.mount(\n\t\t\t\tmount.vfsPath,\n\t\t\t\tcreateNodeFsMountHandler(mount.hostPath)\n\t\t\t);\n\t\t} catch {\n\t\t\toutput.stderr(\n\t\t\t\t`\\x1b[31m\\x1b[1mError mounting path ${mount.hostPath} at ${mount.vfsPath}\\x1b[0m\\n`\n\t\t\t);\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\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\n/**\n * Force TTY status to preserve ANSI control codes in the output.\n *\n * This script is spawned as `new Worker()` and process.stdout and process.stderr are\n * WritableWorkerStdio objects. By default, they strip ANSI control codes from the output\n * causing every progress bar update to be printed in a new line instead of updating the\n * same line.\n */\nObject.defineProperty(process.stdout, 'isTTY', { value: true });\nObject.defineProperty(process.stderr, 'isTTY', { value: true });\n\n/**\n * Output writer that ensures that progress bars are not printed on the same line as other output.\n */\nconst output = {\n\tlastWriteWasProgress: false,\n\tprogress(data: string) {\n\t\tif (!process.stdout.isTTY) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.log(data);\n\t\t} else {\n\t\t\tif (!output.lastWriteWasProgress) {\n\t\t\t\tprocess.stdout.write('\\n');\n\t\t\t}\n\t\t\tprocess.stdout.write('\\r\\x1b[K' + data);\n\t\t\toutput.lastWriteWasProgress = true;\n\t\t}\n\t},\n\tstdout(data: string) {\n\t\tif (output.lastWriteWasProgress) {\n\t\t\tprocess.stdout.write('\\n');\n\t\t\toutput.lastWriteWasProgress = false;\n\t\t}\n\t\tprocess.stdout.write(data);\n\t},\n\tstderr(data: string) {\n\t\tif (output.lastWriteWasProgress) {\n\t\t\tprocess.stdout.write('\\n');\n\t\t\toutput.lastWriteWasProgress = false;\n\t\t}\n\t\tprocess.stderr.write(data);\n\t},\n};\n\nexport type PrimaryWorkerBootArgs = RunCLIArgs & {\n\tphpVersion: SupportedPHPVersion;\n\tsiteUrl: string;\n\tfirstProcessId: number;\n\tprocessIdSpaceLength: number;\n\ttrace: boolean;\n\tblueprint:\n\t\t| RawBlueprintV2Data\n\t\t| ParsedBlueprintV2String\n\t\t| BlueprintV1Declaration;\n\tnativeInternalDirPath: string;\n};\n\ntype WorkerRunBlueprintArgs = RunCLIArgs & {\n\tsiteUrl: string;\n\tblueprint:\n\t\t| RawBlueprintV2Data\n\t\t| ParsedBlueprintV2String\n\t\t| BlueprintV1Declaration;\n};\n\nexport type SecondaryWorkerBootArgs = {\n\tsiteUrl: string;\n\tallow?: string;\n\tphpVersion: SupportedPHPVersion;\n\tphpIniEntries?: PhpIniOptions;\n\tconstants?: Record<string, string | number | boolean | null>;\n\tcreateFiles?: FileTree;\n\tfirstProcessId: number;\n\tprocessIdSpaceLength: number;\n\ttrace: boolean;\n\tnativeInternalDirPath: string;\n\twithXdebug?: boolean;\n\tmountsBeforeWpInstall?: Array<Mount>;\n\tmountsAfterWpInstall?: Array<Mount>;\n};\n\nexport type WorkerBootRequestHandlerOptions = Omit<\n\tSecondaryWorkerBootArgs,\n\t'mountsBeforeWpInstall' | 'mountsAfterWpInstall'\n> & {\n\tonPHPInstanceCreated: PHPInstanceCreatedHook;\n};\n\nexport class PlaygroundCliBlueprintV2Worker extends PHPWorker {\n\tbooted = false;\n\tblueprintTargetResolved = false;\n\tphpInstancesThatNeedMountsAfterTargetResolved = new Set<PHP>();\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(args: PrimaryWorkerBootArgs) {\n\t\tconst constants = {\n\t\t\tWP_DEBUG: true,\n\t\t\tWP_DEBUG_LOG: true,\n\t\t\tWP_DEBUG_DISPLAY: false,\n\t\t};\n\t\tconst requestHandlerOptions: WorkerBootRequestHandlerOptions = {\n\t\t\t...args,\n\t\t\tcreateFiles: {\n\t\t\t\t'/internal/shared/ca-bundle.crt': rootCertificates.join('\\n'),\n\t\t\t},\n\t\t\tconstants,\n\t\t\tphpIniEntries: {\n\t\t\t\t'openssl.cafile': '/internal/shared/ca-bundle.crt',\n\t\t\t},\n\t\t\tonPHPInstanceCreated: async (php: PHP) => {\n\t\t\t\tthis.registerWorkerListeners(php);\n\t\t\t\tawait mountResources(php, args['mount-before-install'] || []);\n\t\t\t\tif (this.blueprintTargetResolved) {\n\t\t\t\t\tawait mountResources(php, args.mount || []);\n\t\t\t\t} else {\n\t\t\t\t\t// NOTE: Today (2025-09-11), during boot with a plugin auto-mount,\n\t\t\t\t\t// the Blueprint runner fails unless post-resolution mounts are\n\t\t\t\t\t// added to existing PHP instances. So we track them here so they\n\t\t\t\t\t// can be mounted at the necessary time.\n\t\t\t\t\t// Only plugin auto-mounts seem to need this, so perhaps there\n\t\t\t\t\t// is a change we can make to the Blueprint runner so such\n\t\t\t\t\t// a dance is unnecessary.\n\t\t\t\t\tthis.phpInstancesThatNeedMountsAfterTargetResolved.add(php);\n\t\t\t\t\tphp.addEventListener('runtime.beforeExit', () => {\n\t\t\t\t\t\tthis.phpInstancesThatNeedMountsAfterTargetResolved.delete(\n\t\t\t\t\t\t\tphp\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};\n\t\tawait this.bootRequestHandler(requestHandlerOptions);\n\n\t\tconst primaryPhp = this.__internal_getPHP()!;\n\n\t\tif (args.mode === 'mount-only') {\n\t\t\tawait mountResources(primaryPhp, args.mount || []);\n\t\t\treturn;\n\t\t}\n\n\t\tawait this.runBlueprintV2(args);\n\t}\n\n\tasync bootAsSecondaryWorker(args: SecondaryWorkerBootArgs) {\n\t\tawait this.bootRequestHandler({\n\t\t\t...args,\n\t\t\tonPHPInstanceCreated: async (php: PHP) => {\n\t\t\t\tawait mountResources(php, args.mountsBeforeWpInstall || []);\n\t\t\t\tawait mountResources(php, args.mountsAfterWpInstall || []);\n\t\t\t},\n\t\t});\n\t}\n\n\tasync runBlueprintV2(args: WorkerRunBlueprintArgs) {\n\t\tconst requestHandler = this.__internal_getRequestHandler()!;\n\t\tconst { php, reap } =\n\t\t\tawait requestHandler.processManager.acquirePHPInstance({\n\t\t\t\tconsiderPrimary: false,\n\t\t\t});\n\n\t\t// Mount the current working directory to the PHP runtime for the purposes of\n\t\t// Blueprint resolution.\n\t\tconst primaryPhp = this.__internal_getPHP()!;\n\t\tlet unmountCwd = () => {};\n\t\tif (typeof args.blueprint === 'string') {\n\t\t\tconst blueprintPath = path.resolve(process.cwd(), args.blueprint);\n\t\t\tif (existsSync(blueprintPath)) {\n\t\t\t\tprimaryPhp.mkdir('/internal/shared/cwd');\n\t\t\t\tunmountCwd = await primaryPhp.mount(\n\t\t\t\t\t'/internal/shared/cwd',\n\t\t\t\t\tcreateNodeFsMountHandler(path.dirname(blueprintPath))\n\t\t\t\t);\n\t\t\t\targs.blueprint = path.join(\n\t\t\t\t\t'/internal/shared/cwd',\n\t\t\t\t\tpath.basename(args.blueprint)\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\t\t\tconst cliArgsToPass: (keyof WorkerRunBlueprintArgs)[] = [\n\t\t\t\t'mode',\n\t\t\t\t'db-engine',\n\t\t\t\t'db-host',\n\t\t\t\t'db-user',\n\t\t\t\t'db-pass',\n\t\t\t\t'db-name',\n\t\t\t\t'db-path',\n\t\t\t\t'truncate-new-site-directory',\n\t\t\t\t'allow',\n\t\t\t];\n\t\t\tconst cliArgs = cliArgsToPass\n\t\t\t\t.filter((arg) => arg in args)\n\t\t\t\t.map((arg) => `--${arg}=${args[arg]}`);\n\t\t\tcliArgs.push(`--site-url=${args.siteUrl}`);\n\n\t\t\tconst streamedResponse = await runBlueprintV2({\n\t\t\t\tphp,\n\t\t\t\tblueprint: args.blueprint,\n\t\t\t\tblueprintOverrides: {\n\t\t\t\t\tadditionalSteps: args['additional-blueprint-steps'],\n\t\t\t\t\twordpressVersion: args.wp,\n\t\t\t\t},\n\t\t\t\tcliArgs,\n\t\t\t\tonMessage: async (message: BlueprintMessage) => {\n\t\t\t\t\tswitch (message.type) {\n\t\t\t\t\t\tcase 'blueprint.target_resolved': {\n\t\t\t\t\t\t\tif (!this.blueprintTargetResolved) {\n\t\t\t\t\t\t\t\tthis.blueprintTargetResolved = true;\n\t\t\t\t\t\t\t\tfor (const php of this\n\t\t\t\t\t\t\t\t\t.phpInstancesThatNeedMountsAfterTargetResolved) {\n\t\t\t\t\t\t\t\t\t// console.log('mounting resources for php', php);\n\t\t\t\t\t\t\t\t\tthis.phpInstancesThatNeedMountsAfterTargetResolved.delete(\n\t\t\t\t\t\t\t\t\t\tphp\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\tawait mountResources(php, args.mount || []);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcase 'blueprint.progress': {\n\t\t\t\t\t\t\tconst progressMessage = `${message.caption.trim()} – ${message.progress.toFixed(\n\t\t\t\t\t\t\t\t2\n\t\t\t\t\t\t\t)}%`;\n\t\t\t\t\t\t\toutput.progress(progressMessage);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcase 'blueprint.error': {\n\t\t\t\t\t\t\tconst red = '\\x1b[31m';\n\t\t\t\t\t\t\tconst bold = '\\x1b[1m';\n\t\t\t\t\t\t\tconst reset = '\\x1b[0m';\n\t\t\t\t\t\t\tif (args.debug && message.details) {\n\t\t\t\t\t\t\t\toutput.stderr(\n\t\t\t\t\t\t\t\t\t`${red}${bold}Fatal error:${reset} Uncaught ${message.details.exception}: ${message.details.message}\\n` +\n\t\t\t\t\t\t\t\t\t\t` at ${message.details.file}:${message.details.line}\\n` +\n\t\t\t\t\t\t\t\t\t\t(message.details.trace\n\t\t\t\t\t\t\t\t\t\t\t? message.details.trace + '\\n'\n\t\t\t\t\t\t\t\t\t\t\t: '')\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\toutput.stderr(\n\t\t\t\t\t\t\t\t\t`${red}${bold}Error:${reset} ${message.message}\\n`\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\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\t/**\n\t\t\t * When we're debugging, every bit of information matters – let's immediately output\n\t\t\t * everything we get from the PHP output streams.\n\t\t\t */\n\t\t\tif (args.debug) {\n\t\t\t\tstreamedResponse!.stdout.pipeTo(\n\t\t\t\t\tnew WritableStream({\n\t\t\t\t\t\twrite(chunk) {\n\t\t\t\t\t\t\tprocess.stdout.write(chunk);\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t);\n\t\t\t\tstreamedResponse!.stderr.pipeTo(\n\t\t\t\t\tnew WritableStream({\n\t\t\t\t\t\twrite(chunk) {\n\t\t\t\t\t\t\tprocess.stderr.write(chunk);\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\tawait streamedResponse!.finished;\n\t\t\tif ((await streamedResponse!.exitCode) !== 0) {\n\t\t\t\t// exitCode != 1 means the blueprint execution failed. Let's throw an error.\n\t\t\t\t// and clean up.\n\t\t\t\tconst syncResponse = await PHPResponse.fromStreamedResponse(\n\t\t\t\t\tstreamedResponse\n\t\t\t\t);\n\t\t\t\tthrow new PHPExecutionFailureError(\n\t\t\t\t\t`PHP.run() failed with exit code ${syncResponse.exitCode}.`,\n\t\t\t\t\tsyncResponse,\n\t\t\t\t\t'request'\n\t\t\t\t);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\t// Capture the PHP error log details to provide more context for debugging.\n\t\t\tlet phpLogs = '';\n\t\t\ttry {\n\t\t\t\t// @TODO: Don't assume errorLogPath starts with /wordpress/\n\t\t\t\t// ...or maybe we can assume that in Playground CLI?\n\t\t\t\tphpLogs = php.readFileAsText(errorLogPath);\n\t\t\t} catch {\n\t\t\t\t// Ignore errors reading the PHP error log.\n\t\t\t}\n\t\t\t(error as any).phpLogs = phpLogs;\n\t\t\tthrow error;\n\t\t} finally {\n\t\t\treap();\n\t\t\tunmountCwd();\n\t\t}\n\t}\n\n\tasync bootRequestHandler({\n\t\tsiteUrl,\n\t\tallow,\n\t\tphpVersion,\n\t\tcreateFiles,\n\t\tconstants,\n\t\tphpIniEntries,\n\t\tfirstProcessId,\n\t\tprocessIdSpaceLength,\n\t\ttrace,\n\t\tnativeInternalDirPath,\n\t\twithXdebug,\n\t\tonPHPInstanceCreated,\n\t}: WorkerBootRequestHandlerOptions) {\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 requestHandler = await bootRequestHandler({\n\t\t\t\tsiteUrl,\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\tENV: {\n\t\t\t\t\t\t\t\tDOCROOT: '/wordpress',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tphpWasmInitOptions: { nativeInternalDirPath },\n\t\t\t\t\t\t},\n\t\t\t\t\t\tfollowSymlinks: allow?.includes('follow-symlinks'),\n\t\t\t\t\t\twithXdebug,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\tonPHPInstanceCreated,\n\t\t\t\tsapiName: 'cli',\n\t\t\t\tcreateFiles,\n\t\t\t\tconstants,\n\t\t\t\tphpIniEntries,\n\t\t\t\tcookieStore: false,\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\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\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\nprocess.on('unhandledRejection', (e: any) => {\n\tlogger.error('Unhandled rejection:', e);\n});\n\nconst phpChannel = new MessageChannel();\n\nconst [setApiReady, setAPIError] = exposeAPI(\n\tnew PlaygroundCliBlueprintV2Worker(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","output","tracePhpWasm","processId","format","args","sprintf","data","PlaygroundCliBlueprintV2Worker","PHPWorker","monitor","port","jspi","consumeAPI","consumeAPISync","constants","requestHandlerOptions","rootCertificates","primaryPhp","requestHandler","reap","unmountCwd","blueprintPath","path","existsSync","cliArgs","arg","streamedResponse","runBlueprintV2","message","progressMessage","red","bold","reset","chunk","syncResponse","PHPResponse","PHPExecutionFailureError","error","phpLogs","errorLogPath","siteUrl","allow","phpVersion","createFiles","phpIniEntries","firstProcessId","processIdSpaceLength","trace","nativeInternalDirPath","withXdebug","onPHPInstanceCreated","nextProcessId","lastProcessId","bootRequestHandler","loadNodeRuntime","sandboxedSpawnHandlerFactory","setApiReady","e","setAPIError","logger","phpChannel","MessageChannel","exposeAPI","EmscriptenDownloadMonitor","parentPort"],"mappings":"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"}
|