@wp-playground/cli 3.1.20 → 3.1.21

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/run-cli.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /// <reference types="node" />
2
2
  /// <reference types="node" />
3
- import { type Pooled, type PathAlias, type SupportedPHPVersion } from '@php-wasm/universal';
3
+ import { type Pooled, type PathAlias, type AllPHPVersion } from '@php-wasm/universal';
4
4
  import type { BlueprintBundle, BlueprintV1Declaration, BlueprintV2Declaration } from '@wp-playground/blueprints';
5
5
  import type { Server } from 'http';
6
6
  import { Worker } from 'worker_threads';
@@ -46,6 +46,14 @@ export declare function parseOptionsAndRunCLI(argsToParse: string[]): Promise<{
46
46
  cliServer: RunCLIServer;
47
47
  };
48
48
  }>;
49
+ /**
50
+ * Resolve the --workers flag into a concrete worker count.
51
+ *
52
+ * The Math.max(1, ...) guard covers single-core hosts and restricted
53
+ * environments where `os.cpus()` can return an empty array — without it
54
+ * the default would drop to 0 and no workers would be spawned.
55
+ */
56
+ export declare function resolveWorkerCount(value: number | 'auto' | undefined): number;
49
57
  export interface RunCLIArgs {
50
58
  /**
51
59
  * `_` holds positional tokens in the order they appeared.
@@ -59,13 +67,19 @@ export interface RunCLIArgs {
59
67
  mount?: Mount[];
60
68
  'mount-before-install'?: Mount[];
61
69
  outfile?: string;
62
- php?: SupportedPHPVersion;
70
+ php?: AllPHPVersion;
63
71
  port?: number;
64
72
  'site-url'?: string;
65
73
  quiet?: boolean;
66
74
  verbosity?: LogVerbosity;
67
75
  wp?: string;
68
- autoMount?: string;
76
+ /**
77
+ * For the `server` command (and other long-form commands), this is the
78
+ * host path to auto-detect and mount. For the `start` command, this is a
79
+ * boolean toggle: `true` (default) enables auto-detection on the
80
+ * `--path` directory; `false` (i.e. `--no-auto-mount`) disables it.
81
+ */
82
+ autoMount?: string | boolean;
69
83
  pathAliases?: PathAlias[];
70
84
  experimentalTrace?: boolean;
71
85
  internalCookieStore?: boolean;
@@ -78,6 +92,8 @@ export interface RunCLIArgs {
78
92
  experimentalUnsafeIdeIntegration?: string[];
79
93
  experimentalDevtools?: boolean;
80
94
  'experimental-blueprints-v2-runner'?: boolean;
95
+ workers?: number | 'auto';
96
+ 'experimental-multi-worker'?: number;
81
97
  wordpressInstallMode?: WordPressInstallMode;
82
98
  /**
83
99
  * PHP string constants defined via --define flag.
@@ -108,7 +124,6 @@ export interface RunCLIArgs {
108
124
  allow?: string;
109
125
  path?: string;
110
126
  skipBrowser?: boolean;
111
- noAutoMount?: boolean;
112
127
  reset?: boolean;
113
128
  }
114
129
  export type PlaygroundCliWorker = PlaygroundCliBlueprintV1Worker | PlaygroundCliBlueprintV2Worker;
Binary file
@@ -1,3 +1,3 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const g=require("@php-wasm/node"),f=require("@php-wasm/progress"),n=require("@php-wasm/universal"),b=require("@php-wasm/util"),I=require("@wp-playground/common"),u=require("@wp-playground/wordpress"),q=require("tls"),P=require("worker_threads"),i=require("./run-cli-B6Dm34vQ.cjs"),W=require("@php-wasm/logger");function R(r,e,...t){console.log(performance.now().toFixed(6).padStart(15,"0"),r.toString().padStart(16,"0"),b.sprintf(e,...t))}class w extends n.PHPWorker{constructor(e){super(void 0,e),this.bootedRequestHandler=!1,this.bootedWordPress=!1}async useFileLockManager(e){this.fileLockManager=await n.consumeAPISync(e)}async bootWordPress(e,t){if(this.bootedWordPress)throw new Error("WordPress already booted");this.bootedWordPress=!0;const{siteUrl:s,wordpressInstallMode:o,wordPressZip:c,sqliteIntegrationPluginZip:d,dataSqlPath:m,constants:y}=e;try{await u.bootWordPress(this.__internal_getRequestHandler(),{siteUrl:s,wordpressInstallMode:o,wordPressZip:c!==void 0?new File([c],"wordpress.zip"):void 0,sqliteIntegrationPluginZip:d!==void 0?new File([d],"sqlite-integration-plugin.zip"):void 0,createFiles:{"/internal/shared/ca-bundle.crt":q.rootCertificates.join(`
2
- `)},phpIniEntries:{"openssl.cafile":"/internal/shared/ca-bundle.crt",allow_url_fopen:"1",disable_functions:""},dataSqlPath:m,constants:y});const a=n.consumeAPI(t);await a.applyPostInstallMountsToAllWorkers(),a[n.releaseApiProxy](),h()}catch(a){throw p(a),a}}async bootRequestHandler(e){if(this.bootedRequestHandler)throw new Error("Playground already booted");this.bootedRequestHandler=!0;try{const t=await u.bootRequestHandler({siteUrl:e.siteUrl,maxPhpInstances:1,createPhpRuntime:k(e,this.fileLockManager),onPHPInstanceCreated:async o=>{await i.mountResources(o,e.mountsBeforeWpInstall),this.bootedWordPress&&await i.mountResources(o,e.mountsAfterWpInstall)},sapiName:"cli",cookieStore:!1,pathAliases:e.pathAliases,spawnHandler:()=>n.sandboxedSpawnHandlerFactory(()=>{let o=e;return this.bootedWordPress||(o={...e,mountsAfterWpInstall:[]}),H(o,this.fileLockManager)})});this.__internal_setRequestHandler(t);const s=await t.getPrimaryPhp();await this.setPrimaryPHP(s),h()}catch(t){throw p(t),t}}async mountAfterWordPressInstall(e){this.bootedWordPress=!0,await i.mountResources(this.__internal_getPHP(),e)}async dispose(){await this[Symbol.asyncDispose]()}}function k(r,e){return async()=>await g.loadNodeRuntime(r.phpVersion||I.RecommendedPHPVersion,{fileLockManager:e,emscriptenOptions:{processId:r.processId,trace:r.trace?R:void 0,nativeInternalDirPath:r.nativeInternalDirPath},followSymlinks:r.followSymlinks,withIntl:r.withIntl,withRedis:r.withRedis,withMemcached:r.withMemcached,withXdebug:r.withXdebug})}async function H(r,e){const t=await i.spawnWorkerThread("v1"),s=n.consumeAPI(t.phpPort);return s.useFileLockManager(e),await s.bootRequestHandler({...r,processId:t.processId}),{php:s,reap:()=>{try{s.dispose()}catch{}try{t.worker.terminate()}catch{}}}}process.on("unhandledRejection",r=>{W.logger.error("Unhandled rejection:",r)});const l=new P.MessageChannel,[h,p]=n.exposeAPI(new w(new f.EmscriptenDownloadMonitor),void 0,l.port1);P.parentPort?.postMessage({command:"worker-script-initialized",phpPort:l.port2},[l.port2]);exports.PlaygroundCliBlueprintV1Worker=w;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const f=require("@php-wasm/node"),b=require("@php-wasm/progress"),n=require("@php-wasm/universal"),I=require("@php-wasm/util"),q=require("@wp-playground/common"),u=require("@wp-playground/wordpress"),W=require("tls"),P=require("worker_threads"),i=require("./run-cli-vtAjdYXb.cjs"),R=require("@php-wasm/logger");function k(r,e,...t){console.log(performance.now().toFixed(6).padStart(15,"0"),r.toString().padStart(16,"0"),I.sprintf(e,...t))}class w extends n.PHPWorker{constructor(e){super(void 0,e),this.bootedRequestHandler=!1,this.bootedWordPress=!1}async useFileLockManager(e){this.fileLockManager=await n.consumeAPISync(e)}async bootWordPress(e,t){if(this.bootedWordPress)throw new Error("WordPress already booted");this.bootedWordPress=!0;const{siteUrl:s,phpVersion:o,wordpressInstallMode:m,wordPressZip:c,sqliteIntegrationPluginZip:d,dataSqlPath:y,constants:g}=e;try{await u.bootWordPress(this.__internal_getRequestHandler(),{siteUrl:s,phpVersion:o,wordpressInstallMode:m,wordPressZip:c!==void 0?new File([c],"wordpress.zip"):void 0,sqliteIntegrationPluginZip:d!==void 0?new File([d],"sqlite-integration-plugin.zip"):void 0,createFiles:{"/internal/shared/ca-bundle.crt":W.rootCertificates.join(`
2
+ `)},phpIniEntries:{"openssl.cafile":"/internal/shared/ca-bundle.crt",allow_url_fopen:"1",disable_functions:""},dataSqlPath:y,constants:g});const a=n.consumeAPI(t);await a.applyPostInstallMountsToAllWorkers(),a[n.releaseApiProxy](),p()}catch(a){throw h(a),a}}async bootRequestHandler(e){if(this.bootedRequestHandler)throw new Error("Playground already booted");this.bootedRequestHandler=!0;try{const t=await u.bootRequestHandler({siteUrl:e.siteUrl,phpVersion:e.phpVersion,maxPhpInstances:1,createPhpRuntime:H(e,this.fileLockManager),onPHPInstanceCreated:async o=>{await i.mountResources(o,e.mountsBeforeWpInstall),this.bootedWordPress&&await i.mountResources(o,e.mountsAfterWpInstall)},sapiName:"cli",cookieStore:!1,pathAliases:e.pathAliases,spawnHandler:()=>n.sandboxedSpawnHandlerFactory(()=>{let o=e;return this.bootedWordPress||(o={...e,mountsAfterWpInstall:[]}),v(o,this.fileLockManager)})});this.__internal_setRequestHandler(t);const s=await t.getPrimaryPhp();await this.setPrimaryPHP(s),p()}catch(t){throw h(t),t}}async mountAfterWordPressInstall(e){this.bootedWordPress=!0,await i.mountResources(this.__internal_getPHP(),e)}async dispose(){await this[Symbol.asyncDispose]()}}function H(r,e){return async()=>await f.loadNodeRuntime(r.phpVersion||q.RecommendedPHPVersion,{fileLockManager:e,emscriptenOptions:{processId:r.processId,trace:r.trace?k:void 0,nativeInternalDirPath:r.nativeInternalDirPath},followSymlinks:r.followSymlinks,withIntl:r.withIntl,withRedis:r.withRedis,withMemcached:r.withMemcached,withXdebug:r.withXdebug})}async function v(r,e){const t=await i.spawnWorkerThread("v1"),s=n.consumeAPI(t.phpPort);return s.useFileLockManager(e),await s.bootRequestHandler({...r,processId:t.processId}),{php:s,reap:()=>{try{s.dispose()}catch{}try{t.worker.terminate()}catch{}}}}process.on("unhandledRejection",r=>{R.logger.error("Unhandled rejection:",r)});const l=new P.MessageChannel,[p,h]=n.exposeAPI(new w(new b.EmscriptenDownloadMonitor),void 0,l.port1);P.parentPort?.postMessage({command:"worker-script-initialized",phpPort:l.port2},[l.port2]);exports.PlaygroundCliBlueprintV1Worker=w;
3
3
  //# sourceMappingURL=worker-thread-v1.cjs.map
@@ -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/universal';\nimport { loadNodeRuntime } from '@php-wasm/node';\nimport { EmscriptenDownloadMonitor } from '@php-wasm/progress';\nimport type { PathAlias, SupportedPHPVersion } from '@php-wasm/universal';\nimport {\n\tPHPWorker,\n\treleaseApiProxy,\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\ttype WordPressInstallMode,\n\tbootRequestHandler,\n\tbootWordPress,\n} from '@wp-playground/wordpress';\nimport { rootCertificates } from 'tls';\nimport { MessageChannel, type MessagePort, parentPort } from 'worker_threads';\nimport { mountResources } from '../mounts';\nimport { logger } from '@php-wasm/logger';\nimport { spawnWorkerThread } from '../run-cli';\n\nimport type { Mount } from '@php-wasm/cli-util';\n\nexport type WorkerBootWordPressOptions = {\n\tsiteUrl: string;\n\twpVersion?: string;\n\twordpressInstallMode: WordPressInstallMode;\n\twordPressZip?: ArrayBuffer;\n\tsqliteIntegrationPluginZip?: ArrayBuffer;\n\tdataSqlPath?: string;\n\t/**\n\t * PHP constants to define via php.defineConstant().\n\t */\n\tconstants?: Record<string, string | number | boolean>;\n};\n\ninterface WorkerBootRequestHandlerOptions {\n\tsiteUrl: string;\n\tphpVersion: SupportedPHPVersion;\n\tprocessId: number;\n\ttrace: boolean;\n\tnativeInternalDirPath: string;\n\tmountsBeforeWpInstall: Array<Mount>;\n\tmountsAfterWpInstall: Array<Mount>;\n\tfollowSymlinks: boolean;\n\twithIntl?: boolean;\n\twithRedis?: boolean;\n\twithMemcached?: boolean;\n\twithXdebug?: boolean;\n\tpathAliases?: PathAlias[];\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\tbootedRequestHandler = false;\n\tbootedWordPress = false;\n\tfileLockManager: 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\tthis.fileLockManager = await consumeAPISync<FileLockManager>(port);\n\t}\n\n\tasync bootWordPress(\n\t\toptions: WorkerBootWordPressOptions,\n\t\tworkerPostInstallMountsPort: MessagePort\n\t) {\n\t\tif (this.bootedWordPress) {\n\t\t\tthrow new Error('WordPress already booted');\n\t\t}\n\t\tthis.bootedWordPress = true;\n\t\tconst {\n\t\t\tsiteUrl,\n\t\t\twordpressInstallMode,\n\t\t\twordPressZip,\n\t\t\tsqliteIntegrationPluginZip,\n\t\t\tdataSqlPath,\n\t\t\tconstants,\n\t\t} = options;\n\n\t\ttry {\n\t\t\tawait bootWordPress(this.__internal_getRequestHandler()!, {\n\t\t\t\tsiteUrl,\n\t\t\t\twordpressInstallMode,\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\t)\n\t\t\t\t\t\t: undefined,\n\t\t\t\t// TODO: Are these redundant creations?\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\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\tdataSqlPath,\n\t\t\t\tconstants,\n\t\t\t});\n\n\t\t\t// Notify all workers to apply post-install mounts.\n\t\t\tconst postInstall = consumeAPI<{\n\t\t\t\tapplyPostInstallMountsToAllWorkers: () => Promise<void>;\n\t\t\t}>(workerPostInstallMountsPort);\n\t\t\tawait postInstall.applyPostInstallMountsToAllWorkers();\n\t\t\tpostInstall[releaseApiProxy]();\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 bootRequestHandler(options: WorkerBootRequestHandlerOptions) {\n\t\tif (this.bootedRequestHandler) {\n\t\t\tthrow new Error('Playground already booted');\n\t\t}\n\t\tthis.bootedRequestHandler = true;\n\n\t\ttry {\n\t\t\tconst requestHandler = await bootRequestHandler({\n\t\t\t\tsiteUrl: options.siteUrl,\n\t\t\t\tmaxPhpInstances: 1,\n\t\t\t\tcreatePhpRuntime: createPhpRuntimeFactory(\n\t\t\t\t\toptions,\n\t\t\t\t\tthis.fileLockManager!\n\t\t\t\t),\n\t\t\t\tonPHPInstanceCreated: async (php) => {\n\t\t\t\t\tawait mountResources(php, options.mountsBeforeWpInstall);\n\n\t\t\t\t\t// NOTE: We currently create all request workers up front\n\t\t\t\t\t// and apply post-install mounts to all the workers immediately\n\t\t\t\t\t// following WordPress install. But if we start creating\n\t\t\t\t\t// request-handling workers on-demand, we will to apply post-install\n\t\t\t\t\t// mounts here.\n\t\t\t\t\tif (this.bootedWordPress) {\n\t\t\t\t\t\tawait mountResources(php, options.mountsAfterWpInstall);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tsapiName: 'cli',\n\t\t\t\tcookieStore: false,\n\t\t\t\tpathAliases: options.pathAliases,\n\t\t\t\tspawnHandler: () =>\n\t\t\t\t\tsandboxedSpawnHandlerFactory(() => {\n\t\t\t\t\t\tlet effectiveOptions = options;\n\t\t\t\t\t\tif (!this.bootedWordPress) {\n\t\t\t\t\t\t\t// WordPress is not yet booted so skip the post-install mounts.\n\t\t\t\t\t\t\teffectiveOptions = {\n\t\t\t\t\t\t\t\t...options,\n\t\t\t\t\t\t\t\tmountsAfterWpInstall: [],\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn createPHPWorker(\n\t\t\t\t\t\t\teffectiveOptions,\n\t\t\t\t\t\t\tthis.fileLockManager!\n\t\t\t\t\t\t);\n\t\t\t\t\t}),\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\tasync mountAfterWordPressInstall(mounts: Array<Mount>) {\n\t\t// Make sure workers not involved in the WordPress install\n\t\t// process know whether WordPress booted so they can\n\t\t// apply post-install mounts when spawning new PHP workers.\n\t\tthis.bootedWordPress = true;\n\t\tawait mountResources(this.__internal_getPHP()!, mounts);\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\n/**\n * Returns a factory function that starts a new PHP runtime in the currently\n * running process. This is used for rotating the PHP runtime periodically.\n */\nfunction createPhpRuntimeFactory(\n\toptions: WorkerBootRequestHandlerOptions,\n\tfileLockManager: FileLockManager\n) {\n\treturn async () => {\n\t\treturn await loadNodeRuntime(\n\t\t\toptions.phpVersion || RecommendedPHPVersion,\n\t\t\t{\n\t\t\t\tfileLockManager,\n\t\t\t\temscriptenOptions: {\n\t\t\t\t\tprocessId: options.processId,\n\t\t\t\t\ttrace: options.trace ? tracePhpWasm : undefined,\n\t\t\t\t\tnativeInternalDirPath: options.nativeInternalDirPath,\n\t\t\t\t},\n\t\t\t\tfollowSymlinks: options.followSymlinks,\n\t\t\t\twithIntl: options.withIntl,\n\t\t\t\twithRedis: options.withRedis,\n\t\t\t\twithMemcached: options.withMemcached,\n\t\t\t\twithXdebug: options.withXdebug,\n\t\t\t}\n\t\t);\n\t};\n}\n\n/**\n * Spawns a new PHP process to be used in the PHP spawn handler (in proc_open() etc. calls).\n * It boots from this worker-thread-v1.ts file, but is a separate process.\n *\n * We explicitly avoid using PHPProcessManager.acquirePHPInstance() here.\n *\n * Why?\n *\n * Because each PHP instance acquires actual OS-level file locks via fcntl() and LockFileEx()\n * syscalls. Running multiple PHP instances from the same OS process would allow them to\n * acquire overlapping locks. Running every PHP instance in a separate OS process ensures\n * any locks that overlap between PHP instances conflict with each other as expected.\n *\n * @param options - The options for the worker.\n * @param fileLockManager - The file lock manager to use.\n * @returns A promise that resolves to the PHP worker.\n */\nasync function createPHPWorker(\n\t// NOTE: We explicitly remove processId from the options\n\t// type so the type system will catch if we try to reuse\n\t// our parent's process ID.\n\toptions: Omit<WorkerBootRequestHandlerOptions, 'processId'>,\n\tfileLockManager: FileLockManager\n) {\n\tconst spawnedWorker = await spawnWorkerThread('v1');\n\n\tconst handler = consumeAPI<PlaygroundCliBlueprintV1Worker>(\n\t\tspawnedWorker.phpPort\n\t);\n\thandler.useFileLockManager(fileLockManager as any);\n\tawait handler.bootRequestHandler({\n\t\t...options,\n\t\tprocessId: spawnedWorker.processId,\n\t});\n\n\treturn {\n\t\tphp: handler,\n\t\treap: () => {\n\t\t\ttry {\n\t\t\t\thandler.dispose();\n\t\t\t} catch {\n\t\t\t\t/** */\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tspawnedWorker.worker.terminate();\n\t\t\t} catch {\n\t\t\t\t/** */\n\t\t\t}\n\t\t},\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","consumeAPISync","options","workerPostInstallMountsPort","siteUrl","wordpressInstallMode","wordPressZip","sqliteIntegrationPluginZip","dataSqlPath","constants","bootWordPress","rootCertificates","postInstall","consumeAPI","releaseApiProxy","setApiReady","e","setAPIError","requestHandler","bootRequestHandler","createPhpRuntimeFactory","php","mountResources","sandboxedSpawnHandlerFactory","effectiveOptions","createPHPWorker","primaryPhp","mounts","fileLockManager","loadNodeRuntime","RecommendedPHPVersion","spawnedWorker","spawnWorkerThread","handler","logger","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/universal';\nimport { loadNodeRuntime } from '@php-wasm/node';\nimport { EmscriptenDownloadMonitor } from '@php-wasm/progress';\nimport type { AllPHPVersion, PathAlias } from '@php-wasm/universal';\nimport {\n\tPHPWorker,\n\treleaseApiProxy,\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\ttype WordPressInstallMode,\n\tbootRequestHandler,\n\tbootWordPress,\n} from '@wp-playground/wordpress';\nimport { rootCertificates } from 'tls';\nimport { MessageChannel, type MessagePort, parentPort } from 'worker_threads';\nimport { mountResources } from '../mounts';\nimport { logger } from '@php-wasm/logger';\nimport { spawnWorkerThread } from '../run-cli';\n\nimport type { Mount } from '@php-wasm/cli-util';\n\nexport type WorkerBootWordPressOptions = {\n\tsiteUrl: string;\n\tphpVersion?: string;\n\twpVersion?: string;\n\twordpressInstallMode: WordPressInstallMode;\n\twordPressZip?: ArrayBuffer;\n\tsqliteIntegrationPluginZip?: ArrayBuffer;\n\tdataSqlPath?: string;\n\t/**\n\t * PHP constants to define via php.defineConstant().\n\t */\n\tconstants?: Record<string, string | number | boolean>;\n};\n\ninterface WorkerBootRequestHandlerOptions {\n\tsiteUrl: string;\n\tphpVersion: AllPHPVersion;\n\tprocessId: number;\n\ttrace: boolean;\n\tnativeInternalDirPath: string;\n\tmountsBeforeWpInstall: Array<Mount>;\n\tmountsAfterWpInstall: Array<Mount>;\n\tfollowSymlinks: boolean;\n\twithIntl?: boolean;\n\twithRedis?: boolean;\n\twithMemcached?: boolean;\n\twithXdebug?: boolean;\n\tpathAliases?: PathAlias[];\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\tbootedRequestHandler = false;\n\tbootedWordPress = false;\n\tfileLockManager: 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\tthis.fileLockManager = await consumeAPISync<FileLockManager>(port);\n\t}\n\n\tasync bootWordPress(\n\t\toptions: WorkerBootWordPressOptions,\n\t\tworkerPostInstallMountsPort: MessagePort\n\t) {\n\t\tif (this.bootedWordPress) {\n\t\t\tthrow new Error('WordPress already booted');\n\t\t}\n\t\tthis.bootedWordPress = true;\n\t\tconst {\n\t\t\tsiteUrl,\n\t\t\tphpVersion,\n\t\t\twordpressInstallMode,\n\t\t\twordPressZip,\n\t\t\tsqliteIntegrationPluginZip,\n\t\t\tdataSqlPath,\n\t\t\tconstants,\n\t\t} = options;\n\n\t\ttry {\n\t\t\tawait bootWordPress(this.__internal_getRequestHandler()!, {\n\t\t\t\tsiteUrl,\n\t\t\t\tphpVersion,\n\t\t\t\twordpressInstallMode,\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\t)\n\t\t\t\t\t\t: undefined,\n\t\t\t\t// TODO: Are these redundant creations?\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\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\tdataSqlPath,\n\t\t\t\tconstants,\n\t\t\t});\n\n\t\t\t// Notify all workers to apply post-install mounts.\n\t\t\tconst postInstall = consumeAPI<{\n\t\t\t\tapplyPostInstallMountsToAllWorkers: () => Promise<void>;\n\t\t\t}>(workerPostInstallMountsPort);\n\t\t\tawait postInstall.applyPostInstallMountsToAllWorkers();\n\t\t\tpostInstall[releaseApiProxy]();\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 bootRequestHandler(options: WorkerBootRequestHandlerOptions) {\n\t\tif (this.bootedRequestHandler) {\n\t\t\tthrow new Error('Playground already booted');\n\t\t}\n\t\tthis.bootedRequestHandler = true;\n\n\t\ttry {\n\t\t\tconst requestHandler = await bootRequestHandler({\n\t\t\t\tsiteUrl: options.siteUrl,\n\t\t\t\tphpVersion: options.phpVersion,\n\t\t\t\tmaxPhpInstances: 1,\n\t\t\t\tcreatePhpRuntime: createPhpRuntimeFactory(\n\t\t\t\t\toptions,\n\t\t\t\t\tthis.fileLockManager!\n\t\t\t\t),\n\t\t\t\tonPHPInstanceCreated: async (php) => {\n\t\t\t\t\tawait mountResources(php, options.mountsBeforeWpInstall);\n\n\t\t\t\t\t// NOTE: We currently create all request workers up front\n\t\t\t\t\t// and apply post-install mounts to all the workers immediately\n\t\t\t\t\t// following WordPress install. But if we start creating\n\t\t\t\t\t// request-handling workers on-demand, we will to apply post-install\n\t\t\t\t\t// mounts here.\n\t\t\t\t\tif (this.bootedWordPress) {\n\t\t\t\t\t\tawait mountResources(php, options.mountsAfterWpInstall);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tsapiName: 'cli',\n\t\t\t\tcookieStore: false,\n\t\t\t\tpathAliases: options.pathAliases,\n\t\t\t\tspawnHandler: () =>\n\t\t\t\t\tsandboxedSpawnHandlerFactory(() => {\n\t\t\t\t\t\tlet effectiveOptions = options;\n\t\t\t\t\t\tif (!this.bootedWordPress) {\n\t\t\t\t\t\t\t// WordPress is not yet booted so skip the post-install mounts.\n\t\t\t\t\t\t\teffectiveOptions = {\n\t\t\t\t\t\t\t\t...options,\n\t\t\t\t\t\t\t\tmountsAfterWpInstall: [],\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn createPHPWorker(\n\t\t\t\t\t\t\teffectiveOptions,\n\t\t\t\t\t\t\tthis.fileLockManager!\n\t\t\t\t\t\t);\n\t\t\t\t\t}),\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\tasync mountAfterWordPressInstall(mounts: Array<Mount>) {\n\t\t// Make sure workers not involved in the WordPress install\n\t\t// process know whether WordPress booted so they can\n\t\t// apply post-install mounts when spawning new PHP workers.\n\t\tthis.bootedWordPress = true;\n\t\tawait mountResources(this.__internal_getPHP()!, mounts);\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\n/**\n * Returns a factory function that starts a new PHP runtime in the currently\n * running process. This is used for rotating the PHP runtime periodically.\n */\nfunction createPhpRuntimeFactory(\n\toptions: WorkerBootRequestHandlerOptions,\n\tfileLockManager: FileLockManager\n) {\n\treturn async () => {\n\t\treturn await loadNodeRuntime(\n\t\t\toptions.phpVersion || RecommendedPHPVersion,\n\t\t\t{\n\t\t\t\tfileLockManager,\n\t\t\t\temscriptenOptions: {\n\t\t\t\t\tprocessId: options.processId,\n\t\t\t\t\ttrace: options.trace ? tracePhpWasm : undefined,\n\t\t\t\t\tnativeInternalDirPath: options.nativeInternalDirPath,\n\t\t\t\t},\n\t\t\t\tfollowSymlinks: options.followSymlinks,\n\t\t\t\twithIntl: options.withIntl,\n\t\t\t\twithRedis: options.withRedis,\n\t\t\t\twithMemcached: options.withMemcached,\n\t\t\t\twithXdebug: options.withXdebug,\n\t\t\t}\n\t\t);\n\t};\n}\n\n/**\n * Spawns a new PHP process to be used in the PHP spawn handler (in proc_open() etc. calls).\n * It boots from this worker-thread-v1.ts file, but is a separate process.\n *\n * We explicitly avoid using PHPProcessManager.acquirePHPInstance() here.\n *\n * Why?\n *\n * Because each PHP instance acquires actual OS-level file locks via fcntl() and LockFileEx()\n * syscalls. Running multiple PHP instances from the same OS process would allow them to\n * acquire overlapping locks. Running every PHP instance in a separate OS process ensures\n * any locks that overlap between PHP instances conflict with each other as expected.\n *\n * @param options - The options for the worker.\n * @param fileLockManager - The file lock manager to use.\n * @returns A promise that resolves to the PHP worker.\n */\nasync function createPHPWorker(\n\t// NOTE: We explicitly remove processId from the options\n\t// type so the type system will catch if we try to reuse\n\t// our parent's process ID.\n\toptions: Omit<WorkerBootRequestHandlerOptions, 'processId'>,\n\tfileLockManager: FileLockManager\n) {\n\tconst spawnedWorker = await spawnWorkerThread('v1');\n\n\tconst handler = consumeAPI<PlaygroundCliBlueprintV1Worker>(\n\t\tspawnedWorker.phpPort\n\t);\n\thandler.useFileLockManager(fileLockManager as any);\n\tawait handler.bootRequestHandler({\n\t\t...options,\n\t\tprocessId: spawnedWorker.processId,\n\t});\n\n\treturn {\n\t\tphp: handler,\n\t\treap: () => {\n\t\t\ttry {\n\t\t\t\thandler.dispose();\n\t\t\t} catch {\n\t\t\t\t/** */\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tspawnedWorker.worker.terminate();\n\t\t\t} catch {\n\t\t\t\t/** */\n\t\t\t}\n\t\t},\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","consumeAPISync","options","workerPostInstallMountsPort","siteUrl","phpVersion","wordpressInstallMode","wordPressZip","sqliteIntegrationPluginZip","dataSqlPath","constants","bootWordPress","rootCertificates","postInstall","consumeAPI","releaseApiProxy","setApiReady","e","setAPIError","requestHandler","bootRequestHandler","createPhpRuntimeFactory","php","mountResources","sandboxedSpawnHandlerFactory","effectiveOptions","createPHPWorker","primaryPhp","mounts","fileLockManager","loadNodeRuntime","RecommendedPHPVersion","spawnedWorker","spawnWorkerThread","handler","logger","phpChannel","MessageChannel","exposeAPI","EmscriptenDownloadMonitor","parentPort"],"mappings":"uYAgEA,SAASA,EAAaC,EAAmBC,KAAmBC,EAAa,CAExE,QAAQ,IACP,YAAY,MAAM,QAAQ,CAAC,EAAE,SAAS,GAAI,GAAG,EAC7CF,EAAU,SAAA,EAAW,SAAS,GAAI,GAAG,EACrCG,EAAAA,QAAQF,EAAQ,GAAGC,CAAI,CAAA,CAEzB,CAEO,MAAME,UAAuCC,EAAAA,SAAU,CAK7D,YAAYC,EAAoC,CAC/C,MAAM,OAAWA,CAAO,EALzB,KAAA,qBAAuB,GACvB,KAAA,gBAAkB,EAKlB,CAWA,MAAM,mBAAmBC,EAAmB,CAC3C,KAAK,gBAAkB,MAAMC,EAAAA,eAAgCD,CAAI,CAClE,CAEA,MAAM,cACLE,EACAC,EACC,CACD,GAAI,KAAK,gBACR,MAAM,IAAI,MAAM,0BAA0B,EAE3C,KAAK,gBAAkB,GACvB,KAAM,CACL,QAAAC,EACA,WAAAC,EACA,qBAAAC,EACA,aAAAC,EACA,2BAAAC,EACA,YAAAC,EACA,UAAAC,CAAA,EACGR,EAEJ,GAAI,CACH,MAAMS,EAAAA,cAAc,KAAK,+BAAiC,CACzD,QAAAP,EACA,WAAAC,EACA,qBAAAC,EACA,aACCC,IAAiB,OACd,IAAI,KAAK,CAACA,CAAY,EAAG,eAAe,EACxC,OACJ,2BACCC,IAA+B,OAC5B,IAAI,KACJ,CAACA,CAA0B,EAC3B,+BAAA,EAEA,OAEJ,YAAa,CACZ,iCACCI,EAAAA,iBAAiB,KAAK;AAAA,CAAI,CAAA,EAE5B,cAAe,CACd,iBAAkB,iCAClB,gBAAiB,IACjB,kBAAmB,EAAA,EAEpB,YAAAH,EACA,UAAAC,CAAA,CACA,EAGD,MAAMG,EAAcC,EAAAA,WAEjBX,CAA2B,EAC9B,MAAMU,EAAY,mCAAA,EAClBA,EAAYE,EAAAA,eAAe,EAAA,EAE3BC,EAAA,CACD,OAASC,EAAG,CACX,MAAAC,EAAYD,CAAU,EAChBA,CACP,CACD,CAEA,MAAM,mBAAmBf,EAA0C,CAClE,GAAI,KAAK,qBACR,MAAM,IAAI,MAAM,2BAA2B,EAE5C,KAAK,qBAAuB,GAE5B,GAAI,CACH,MAAMiB,EAAiB,MAAMC,qBAAmB,CAC/C,QAASlB,EAAQ,QACjB,WAAYA,EAAQ,WACpB,gBAAiB,EACjB,iBAAkBmB,EACjBnB,EACA,KAAK,eAAA,EAEN,qBAAsB,MAAOoB,GAAQ,CACpC,MAAMC,iBAAeD,EAAKpB,EAAQ,qBAAqB,EAOnD,KAAK,iBACR,MAAMqB,iBAAeD,EAAKpB,EAAQ,oBAAoB,CAExD,EACA,SAAU,MACV,YAAa,GACb,YAAaA,EAAQ,YACrB,aAAc,IACbsB,EAAAA,6BAA6B,IAAM,CAClC,IAAIC,EAAmBvB,EACvB,OAAK,KAAK,kBAETuB,EAAmB,CAClB,GAAGvB,EACH,qBAAsB,CAAA,CAAC,GAIlBwB,EACND,EACA,KAAK,eAAA,CAEP,CAAC,CAAA,CACF,EACD,KAAK,6BAA6BN,CAAc,EAEhD,MAAMQ,EAAa,MAAMR,EAAe,cAAA,EACxC,MAAM,KAAK,cAAcQ,CAAU,EAEnCX,EAAA,CACD,OAASC,EAAG,CACX,MAAAC,EAAYD,CAAU,EAChBA,CACP,CACD,CAEA,MAAM,2BAA2BW,EAAsB,CAItD,KAAK,gBAAkB,GACvB,MAAML,iBAAe,KAAK,kBAAA,EAAsBK,CAAM,CACvD,CAGA,MAAM,SAAU,CACf,MAAM,KAAK,OAAO,YAAY,EAAA,CAC/B,CACD,CAMA,SAASP,EACRnB,EACA2B,EACC,CACD,MAAO,UACC,MAAMC,EAAAA,gBACZ5B,EAAQ,YAAc6B,EAAAA,sBACtB,CACC,gBAAAF,EACA,kBAAmB,CAClB,UAAW3B,EAAQ,UACnB,MAAOA,EAAQ,MAAQV,EAAe,OACtC,sBAAuBU,EAAQ,qBAAA,EAEhC,eAAgBA,EAAQ,eACxB,SAAUA,EAAQ,SAClB,UAAWA,EAAQ,UACnB,cAAeA,EAAQ,cACvB,WAAYA,EAAQ,UAAA,CACrB,CAGH,CAmBA,eAAewB,EAIdxB,EACA2B,EACC,CACD,MAAMG,EAAgB,MAAMC,EAAAA,kBAAkB,IAAI,EAE5CC,EAAUpB,EAAAA,WACfkB,EAAc,OAAA,EAEf,OAAAE,EAAQ,mBAAmBL,CAAsB,EACjD,MAAMK,EAAQ,mBAAmB,CAChC,GAAGhC,EACH,UAAW8B,EAAc,SAAA,CACzB,EAEM,CACN,IAAKE,EACL,KAAM,IAAM,CACX,GAAI,CACHA,EAAQ,QAAA,CACT,MAAQ,CAER,CACA,GAAI,CACHF,EAAc,OAAO,UAAA,CACtB,MAAQ,CAER,CACD,CAAA,CAEF,CAEA,QAAQ,GAAG,qBAAuBf,GAAW,CAC5CkB,SAAO,MAAM,uBAAwBlB,CAAC,CACvC,CAAC,EAED,MAAMmB,EAAa,IAAIC,EAAAA,eAEjB,CAACrB,EAAaE,CAAW,EAAIoB,EAAAA,UAClC,IAAIzC,EAA+B,IAAI0C,EAAAA,yBAA2B,EAClE,OACAH,EAAW,KACZ,EAEAI,EAAAA,YAAY,YACX,CACC,QAAS,4BACT,QAASJ,EAAW,KAAA,EAErB,CAACA,EAAW,KAAY,CACzB"}
@@ -1,21 +1,21 @@
1
- import { loadNodeRuntime as P } from "@php-wasm/node";
2
- import { EmscriptenDownloadMonitor as w } from "@php-wasm/progress";
3
- import { exposeAPI as f, PHPWorker as y, consumeAPISync as g, consumeAPI as h, releaseApiProxy as I, sandboxedSpawnHandlerFactory as b } from "@php-wasm/universal";
4
- import { sprintf as W } from "@php-wasm/util";
5
- import { RecommendedPHPVersion as H } from "@wp-playground/common";
6
- import { bootWordPress as R, bootRequestHandler as k } from "@wp-playground/wordpress";
7
- import { rootCertificates as q } from "tls";
8
- import { MessageChannel as A, parentPort as M } from "worker_threads";
9
- import { a as n, s as _ } from "./run-cli-B9kBDU12.js";
10
- import { logger as v } from "@php-wasm/logger";
11
- function S(t, e, ...r) {
1
+ import { loadNodeRuntime as w } from "@php-wasm/node";
2
+ import { EmscriptenDownloadMonitor as f } from "@php-wasm/progress";
3
+ import { exposeAPI as y, PHPWorker as b, consumeAPISync as g, consumeAPI as h, releaseApiProxy as I, sandboxedSpawnHandlerFactory as W } from "@php-wasm/universal";
4
+ import { sprintf as H } from "@php-wasm/util";
5
+ import { RecommendedPHPVersion as R } from "@wp-playground/common";
6
+ import { bootWordPress as k, bootRequestHandler as q } from "@wp-playground/wordpress";
7
+ import { rootCertificates as A } from "tls";
8
+ import { MessageChannel as M, parentPort as _ } from "worker_threads";
9
+ import { b as n, s as v } from "./run-cli-C2bV7mIt.js";
10
+ import { logger as S } from "@php-wasm/logger";
11
+ function F(r, e, ...t) {
12
12
  console.log(
13
13
  performance.now().toFixed(6).padStart(15, "0"),
14
- t.toString().padStart(16, "0"),
15
- W(e, ...r)
14
+ r.toString().padStart(16, "0"),
15
+ H(e, ...t)
16
16
  );
17
17
  }
18
- class F extends y {
18
+ class x extends b {
19
19
  constructor(e) {
20
20
  super(void 0, e), this.bootedRequestHandler = !1, this.bootedWordPress = !1;
21
21
  }
@@ -31,22 +31,24 @@ class F extends y {
31
31
  async useFileLockManager(e) {
32
32
  this.fileLockManager = await g(e);
33
33
  }
34
- async bootWordPress(e, r) {
34
+ async bootWordPress(e, t) {
35
35
  if (this.bootedWordPress)
36
36
  throw new Error("WordPress already booted");
37
37
  this.bootedWordPress = !0;
38
38
  const {
39
- siteUrl: a,
40
- wordpressInstallMode: o,
39
+ siteUrl: o,
40
+ phpVersion: s,
41
+ wordpressInstallMode: m,
41
42
  wordPressZip: l,
42
43
  sqliteIntegrationPluginZip: d,
43
- dataSqlPath: m,
44
- constants: u
44
+ dataSqlPath: u,
45
+ constants: P
45
46
  } = e;
46
47
  try {
47
- await R(this.__internal_getRequestHandler(), {
48
- siteUrl: a,
49
- wordpressInstallMode: o,
48
+ await k(this.__internal_getRequestHandler(), {
49
+ siteUrl: o,
50
+ phpVersion: s,
51
+ wordpressInstallMode: m,
50
52
  wordPressZip: l !== void 0 ? new File([l], "wordpress.zip") : void 0,
51
53
  sqliteIntegrationPluginZip: d !== void 0 ? new File(
52
54
  [d],
@@ -54,7 +56,7 @@ class F extends y {
54
56
  ) : void 0,
55
57
  // TODO: Are these redundant creations?
56
58
  createFiles: {
57
- "/internal/shared/ca-bundle.crt": q.join(`
59
+ "/internal/shared/ca-bundle.crt": A.join(`
58
60
  `)
59
61
  },
60
62
  phpIniEntries: {
@@ -62,13 +64,13 @@ class F extends y {
62
64
  allow_url_fopen: "1",
63
65
  disable_functions: ""
64
66
  },
65
- dataSqlPath: m,
66
- constants: u
67
+ dataSqlPath: u,
68
+ constants: P
67
69
  });
68
- const s = h(r);
69
- await s.applyPostInstallMountsToAllWorkers(), s[I](), c();
70
- } catch (s) {
71
- throw p(s), s;
70
+ const a = h(t);
71
+ await a.applyPostInstallMountsToAllWorkers(), a[I](), c();
72
+ } catch (a) {
73
+ throw p(a), a;
72
74
  }
73
75
  }
74
76
  async bootRequestHandler(e) {
@@ -76,35 +78,36 @@ class F extends y {
76
78
  throw new Error("Playground already booted");
77
79
  this.bootedRequestHandler = !0;
78
80
  try {
79
- const r = await k({
81
+ const t = await q({
80
82
  siteUrl: e.siteUrl,
83
+ phpVersion: e.phpVersion,
81
84
  maxPhpInstances: 1,
82
- createPhpRuntime: x(
85
+ createPhpRuntime: V(
83
86
  e,
84
87
  this.fileLockManager
85
88
  ),
86
- onPHPInstanceCreated: async (o) => {
87
- await n(o, e.mountsBeforeWpInstall), this.bootedWordPress && await n(o, e.mountsAfterWpInstall);
89
+ onPHPInstanceCreated: async (s) => {
90
+ await n(s, e.mountsBeforeWpInstall), this.bootedWordPress && await n(s, e.mountsAfterWpInstall);
88
91
  },
89
92
  sapiName: "cli",
90
93
  cookieStore: !1,
91
94
  pathAliases: e.pathAliases,
92
- spawnHandler: () => b(() => {
93
- let o = e;
94
- return this.bootedWordPress || (o = {
95
+ spawnHandler: () => W(() => {
96
+ let s = e;
97
+ return this.bootedWordPress || (s = {
95
98
  ...e,
96
99
  mountsAfterWpInstall: []
97
100
  }), C(
98
- o,
101
+ s,
99
102
  this.fileLockManager
100
103
  );
101
104
  })
102
105
  });
103
- this.__internal_setRequestHandler(r);
104
- const a = await r.getPrimaryPhp();
105
- await this.setPrimaryPHP(a), c();
106
- } catch (r) {
107
- throw p(r), r;
106
+ this.__internal_setRequestHandler(t);
107
+ const o = await t.getPrimaryPhp();
108
+ await this.setPrimaryPHP(o), c();
109
+ } catch (t) {
110
+ throw p(t), t;
108
111
  }
109
112
  }
110
113
  async mountAfterWordPressInstall(e) {
@@ -115,54 +118,54 @@ class F extends y {
115
118
  await this[Symbol.asyncDispose]();
116
119
  }
117
120
  }
118
- function x(t, e) {
119
- return async () => await P(
120
- t.phpVersion || H,
121
+ function V(r, e) {
122
+ return async () => await w(
123
+ r.phpVersion || R,
121
124
  {
122
125
  fileLockManager: e,
123
126
  emscriptenOptions: {
124
- processId: t.processId,
125
- trace: t.trace ? S : void 0,
126
- nativeInternalDirPath: t.nativeInternalDirPath
127
+ processId: r.processId,
128
+ trace: r.trace ? F : void 0,
129
+ nativeInternalDirPath: r.nativeInternalDirPath
127
130
  },
128
- followSymlinks: t.followSymlinks,
129
- withIntl: t.withIntl,
130
- withRedis: t.withRedis,
131
- withMemcached: t.withMemcached,
132
- withXdebug: t.withXdebug
131
+ followSymlinks: r.followSymlinks,
132
+ withIntl: r.withIntl,
133
+ withRedis: r.withRedis,
134
+ withMemcached: r.withMemcached,
135
+ withXdebug: r.withXdebug
133
136
  }
134
137
  );
135
138
  }
136
- async function C(t, e) {
137
- const r = await _("v1"), a = h(
138
- r.phpPort
139
+ async function C(r, e) {
140
+ const t = await v("v1"), o = h(
141
+ t.phpPort
139
142
  );
140
- return a.useFileLockManager(e), await a.bootRequestHandler({
141
- ...t,
142
- processId: r.processId
143
+ return o.useFileLockManager(e), await o.bootRequestHandler({
144
+ ...r,
145
+ processId: t.processId
143
146
  }), {
144
- php: a,
147
+ php: o,
145
148
  reap: () => {
146
149
  try {
147
- a.dispose();
150
+ o.dispose();
148
151
  } catch {
149
152
  }
150
153
  try {
151
- r.worker.terminate();
154
+ t.worker.terminate();
152
155
  } catch {
153
156
  }
154
157
  }
155
158
  };
156
159
  }
157
- process.on("unhandledRejection", (t) => {
158
- v.error("Unhandled rejection:", t);
160
+ process.on("unhandledRejection", (r) => {
161
+ S.error("Unhandled rejection:", r);
159
162
  });
160
- const i = new A(), [c, p] = f(
161
- new F(new w()),
163
+ const i = new M(), [c, p] = y(
164
+ new x(new f()),
162
165
  void 0,
163
166
  i.port1
164
167
  );
165
- M?.postMessage(
168
+ _?.postMessage(
166
169
  {
167
170
  command: "worker-script-initialized",
168
171
  phpPort: i.port2
@@ -170,6 +173,6 @@ M?.postMessage(
170
173
  [i.port2]
171
174
  );
172
175
  export {
173
- F as PlaygroundCliBlueprintV1Worker
176
+ x as PlaygroundCliBlueprintV1Worker
174
177
  };
175
178
  //# sourceMappingURL=worker-thread-v1.js.map
@@ -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/universal';\nimport { loadNodeRuntime } from '@php-wasm/node';\nimport { EmscriptenDownloadMonitor } from '@php-wasm/progress';\nimport type { PathAlias, SupportedPHPVersion } from '@php-wasm/universal';\nimport {\n\tPHPWorker,\n\treleaseApiProxy,\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\ttype WordPressInstallMode,\n\tbootRequestHandler,\n\tbootWordPress,\n} from '@wp-playground/wordpress';\nimport { rootCertificates } from 'tls';\nimport { MessageChannel, type MessagePort, parentPort } from 'worker_threads';\nimport { mountResources } from '../mounts';\nimport { logger } from '@php-wasm/logger';\nimport { spawnWorkerThread } from '../run-cli';\n\nimport type { Mount } from '@php-wasm/cli-util';\n\nexport type WorkerBootWordPressOptions = {\n\tsiteUrl: string;\n\twpVersion?: string;\n\twordpressInstallMode: WordPressInstallMode;\n\twordPressZip?: ArrayBuffer;\n\tsqliteIntegrationPluginZip?: ArrayBuffer;\n\tdataSqlPath?: string;\n\t/**\n\t * PHP constants to define via php.defineConstant().\n\t */\n\tconstants?: Record<string, string | number | boolean>;\n};\n\ninterface WorkerBootRequestHandlerOptions {\n\tsiteUrl: string;\n\tphpVersion: SupportedPHPVersion;\n\tprocessId: number;\n\ttrace: boolean;\n\tnativeInternalDirPath: string;\n\tmountsBeforeWpInstall: Array<Mount>;\n\tmountsAfterWpInstall: Array<Mount>;\n\tfollowSymlinks: boolean;\n\twithIntl?: boolean;\n\twithRedis?: boolean;\n\twithMemcached?: boolean;\n\twithXdebug?: boolean;\n\tpathAliases?: PathAlias[];\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\tbootedRequestHandler = false;\n\tbootedWordPress = false;\n\tfileLockManager: 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\tthis.fileLockManager = await consumeAPISync<FileLockManager>(port);\n\t}\n\n\tasync bootWordPress(\n\t\toptions: WorkerBootWordPressOptions,\n\t\tworkerPostInstallMountsPort: MessagePort\n\t) {\n\t\tif (this.bootedWordPress) {\n\t\t\tthrow new Error('WordPress already booted');\n\t\t}\n\t\tthis.bootedWordPress = true;\n\t\tconst {\n\t\t\tsiteUrl,\n\t\t\twordpressInstallMode,\n\t\t\twordPressZip,\n\t\t\tsqliteIntegrationPluginZip,\n\t\t\tdataSqlPath,\n\t\t\tconstants,\n\t\t} = options;\n\n\t\ttry {\n\t\t\tawait bootWordPress(this.__internal_getRequestHandler()!, {\n\t\t\t\tsiteUrl,\n\t\t\t\twordpressInstallMode,\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\t)\n\t\t\t\t\t\t: undefined,\n\t\t\t\t// TODO: Are these redundant creations?\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\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\tdataSqlPath,\n\t\t\t\tconstants,\n\t\t\t});\n\n\t\t\t// Notify all workers to apply post-install mounts.\n\t\t\tconst postInstall = consumeAPI<{\n\t\t\t\tapplyPostInstallMountsToAllWorkers: () => Promise<void>;\n\t\t\t}>(workerPostInstallMountsPort);\n\t\t\tawait postInstall.applyPostInstallMountsToAllWorkers();\n\t\t\tpostInstall[releaseApiProxy]();\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 bootRequestHandler(options: WorkerBootRequestHandlerOptions) {\n\t\tif (this.bootedRequestHandler) {\n\t\t\tthrow new Error('Playground already booted');\n\t\t}\n\t\tthis.bootedRequestHandler = true;\n\n\t\ttry {\n\t\t\tconst requestHandler = await bootRequestHandler({\n\t\t\t\tsiteUrl: options.siteUrl,\n\t\t\t\tmaxPhpInstances: 1,\n\t\t\t\tcreatePhpRuntime: createPhpRuntimeFactory(\n\t\t\t\t\toptions,\n\t\t\t\t\tthis.fileLockManager!\n\t\t\t\t),\n\t\t\t\tonPHPInstanceCreated: async (php) => {\n\t\t\t\t\tawait mountResources(php, options.mountsBeforeWpInstall);\n\n\t\t\t\t\t// NOTE: We currently create all request workers up front\n\t\t\t\t\t// and apply post-install mounts to all the workers immediately\n\t\t\t\t\t// following WordPress install. But if we start creating\n\t\t\t\t\t// request-handling workers on-demand, we will to apply post-install\n\t\t\t\t\t// mounts here.\n\t\t\t\t\tif (this.bootedWordPress) {\n\t\t\t\t\t\tawait mountResources(php, options.mountsAfterWpInstall);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tsapiName: 'cli',\n\t\t\t\tcookieStore: false,\n\t\t\t\tpathAliases: options.pathAliases,\n\t\t\t\tspawnHandler: () =>\n\t\t\t\t\tsandboxedSpawnHandlerFactory(() => {\n\t\t\t\t\t\tlet effectiveOptions = options;\n\t\t\t\t\t\tif (!this.bootedWordPress) {\n\t\t\t\t\t\t\t// WordPress is not yet booted so skip the post-install mounts.\n\t\t\t\t\t\t\teffectiveOptions = {\n\t\t\t\t\t\t\t\t...options,\n\t\t\t\t\t\t\t\tmountsAfterWpInstall: [],\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn createPHPWorker(\n\t\t\t\t\t\t\teffectiveOptions,\n\t\t\t\t\t\t\tthis.fileLockManager!\n\t\t\t\t\t\t);\n\t\t\t\t\t}),\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\tasync mountAfterWordPressInstall(mounts: Array<Mount>) {\n\t\t// Make sure workers not involved in the WordPress install\n\t\t// process know whether WordPress booted so they can\n\t\t// apply post-install mounts when spawning new PHP workers.\n\t\tthis.bootedWordPress = true;\n\t\tawait mountResources(this.__internal_getPHP()!, mounts);\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\n/**\n * Returns a factory function that starts a new PHP runtime in the currently\n * running process. This is used for rotating the PHP runtime periodically.\n */\nfunction createPhpRuntimeFactory(\n\toptions: WorkerBootRequestHandlerOptions,\n\tfileLockManager: FileLockManager\n) {\n\treturn async () => {\n\t\treturn await loadNodeRuntime(\n\t\t\toptions.phpVersion || RecommendedPHPVersion,\n\t\t\t{\n\t\t\t\tfileLockManager,\n\t\t\t\temscriptenOptions: {\n\t\t\t\t\tprocessId: options.processId,\n\t\t\t\t\ttrace: options.trace ? tracePhpWasm : undefined,\n\t\t\t\t\tnativeInternalDirPath: options.nativeInternalDirPath,\n\t\t\t\t},\n\t\t\t\tfollowSymlinks: options.followSymlinks,\n\t\t\t\twithIntl: options.withIntl,\n\t\t\t\twithRedis: options.withRedis,\n\t\t\t\twithMemcached: options.withMemcached,\n\t\t\t\twithXdebug: options.withXdebug,\n\t\t\t}\n\t\t);\n\t};\n}\n\n/**\n * Spawns a new PHP process to be used in the PHP spawn handler (in proc_open() etc. calls).\n * It boots from this worker-thread-v1.ts file, but is a separate process.\n *\n * We explicitly avoid using PHPProcessManager.acquirePHPInstance() here.\n *\n * Why?\n *\n * Because each PHP instance acquires actual OS-level file locks via fcntl() and LockFileEx()\n * syscalls. Running multiple PHP instances from the same OS process would allow them to\n * acquire overlapping locks. Running every PHP instance in a separate OS process ensures\n * any locks that overlap between PHP instances conflict with each other as expected.\n *\n * @param options - The options for the worker.\n * @param fileLockManager - The file lock manager to use.\n * @returns A promise that resolves to the PHP worker.\n */\nasync function createPHPWorker(\n\t// NOTE: We explicitly remove processId from the options\n\t// type so the type system will catch if we try to reuse\n\t// our parent's process ID.\n\toptions: Omit<WorkerBootRequestHandlerOptions, 'processId'>,\n\tfileLockManager: FileLockManager\n) {\n\tconst spawnedWorker = await spawnWorkerThread('v1');\n\n\tconst handler = consumeAPI<PlaygroundCliBlueprintV1Worker>(\n\t\tspawnedWorker.phpPort\n\t);\n\thandler.useFileLockManager(fileLockManager as any);\n\tawait handler.bootRequestHandler({\n\t\t...options,\n\t\tprocessId: spawnedWorker.processId,\n\t});\n\n\treturn {\n\t\tphp: handler,\n\t\treap: () => {\n\t\t\ttry {\n\t\t\t\thandler.dispose();\n\t\t\t} catch {\n\t\t\t\t/** */\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tspawnedWorker.worker.terminate();\n\t\t\t} catch {\n\t\t\t\t/** */\n\t\t\t}\n\t\t},\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","consumeAPISync","options","workerPostInstallMountsPort","siteUrl","wordpressInstallMode","wordPressZip","sqliteIntegrationPluginZip","dataSqlPath","constants","bootWordPress","rootCertificates","postInstall","consumeAPI","releaseApiProxy","setApiReady","e","setAPIError","requestHandler","bootRequestHandler","createPhpRuntimeFactory","php","mountResources","sandboxedSpawnHandlerFactory","effectiveOptions","createPHPWorker","primaryPhp","mounts","fileLockManager","loadNodeRuntime","RecommendedPHPVersion","spawnedWorker","spawnWorkerThread","handler","logger","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/universal';\nimport { loadNodeRuntime } from '@php-wasm/node';\nimport { EmscriptenDownloadMonitor } from '@php-wasm/progress';\nimport type { AllPHPVersion, PathAlias } from '@php-wasm/universal';\nimport {\n\tPHPWorker,\n\treleaseApiProxy,\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\ttype WordPressInstallMode,\n\tbootRequestHandler,\n\tbootWordPress,\n} from '@wp-playground/wordpress';\nimport { rootCertificates } from 'tls';\nimport { MessageChannel, type MessagePort, parentPort } from 'worker_threads';\nimport { mountResources } from '../mounts';\nimport { logger } from '@php-wasm/logger';\nimport { spawnWorkerThread } from '../run-cli';\n\nimport type { Mount } from '@php-wasm/cli-util';\n\nexport type WorkerBootWordPressOptions = {\n\tsiteUrl: string;\n\tphpVersion?: string;\n\twpVersion?: string;\n\twordpressInstallMode: WordPressInstallMode;\n\twordPressZip?: ArrayBuffer;\n\tsqliteIntegrationPluginZip?: ArrayBuffer;\n\tdataSqlPath?: string;\n\t/**\n\t * PHP constants to define via php.defineConstant().\n\t */\n\tconstants?: Record<string, string | number | boolean>;\n};\n\ninterface WorkerBootRequestHandlerOptions {\n\tsiteUrl: string;\n\tphpVersion: AllPHPVersion;\n\tprocessId: number;\n\ttrace: boolean;\n\tnativeInternalDirPath: string;\n\tmountsBeforeWpInstall: Array<Mount>;\n\tmountsAfterWpInstall: Array<Mount>;\n\tfollowSymlinks: boolean;\n\twithIntl?: boolean;\n\twithRedis?: boolean;\n\twithMemcached?: boolean;\n\twithXdebug?: boolean;\n\tpathAliases?: PathAlias[];\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\tbootedRequestHandler = false;\n\tbootedWordPress = false;\n\tfileLockManager: 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\tthis.fileLockManager = await consumeAPISync<FileLockManager>(port);\n\t}\n\n\tasync bootWordPress(\n\t\toptions: WorkerBootWordPressOptions,\n\t\tworkerPostInstallMountsPort: MessagePort\n\t) {\n\t\tif (this.bootedWordPress) {\n\t\t\tthrow new Error('WordPress already booted');\n\t\t}\n\t\tthis.bootedWordPress = true;\n\t\tconst {\n\t\t\tsiteUrl,\n\t\t\tphpVersion,\n\t\t\twordpressInstallMode,\n\t\t\twordPressZip,\n\t\t\tsqliteIntegrationPluginZip,\n\t\t\tdataSqlPath,\n\t\t\tconstants,\n\t\t} = options;\n\n\t\ttry {\n\t\t\tawait bootWordPress(this.__internal_getRequestHandler()!, {\n\t\t\t\tsiteUrl,\n\t\t\t\tphpVersion,\n\t\t\t\twordpressInstallMode,\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\t)\n\t\t\t\t\t\t: undefined,\n\t\t\t\t// TODO: Are these redundant creations?\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\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\tdataSqlPath,\n\t\t\t\tconstants,\n\t\t\t});\n\n\t\t\t// Notify all workers to apply post-install mounts.\n\t\t\tconst postInstall = consumeAPI<{\n\t\t\t\tapplyPostInstallMountsToAllWorkers: () => Promise<void>;\n\t\t\t}>(workerPostInstallMountsPort);\n\t\t\tawait postInstall.applyPostInstallMountsToAllWorkers();\n\t\t\tpostInstall[releaseApiProxy]();\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 bootRequestHandler(options: WorkerBootRequestHandlerOptions) {\n\t\tif (this.bootedRequestHandler) {\n\t\t\tthrow new Error('Playground already booted');\n\t\t}\n\t\tthis.bootedRequestHandler = true;\n\n\t\ttry {\n\t\t\tconst requestHandler = await bootRequestHandler({\n\t\t\t\tsiteUrl: options.siteUrl,\n\t\t\t\tphpVersion: options.phpVersion,\n\t\t\t\tmaxPhpInstances: 1,\n\t\t\t\tcreatePhpRuntime: createPhpRuntimeFactory(\n\t\t\t\t\toptions,\n\t\t\t\t\tthis.fileLockManager!\n\t\t\t\t),\n\t\t\t\tonPHPInstanceCreated: async (php) => {\n\t\t\t\t\tawait mountResources(php, options.mountsBeforeWpInstall);\n\n\t\t\t\t\t// NOTE: We currently create all request workers up front\n\t\t\t\t\t// and apply post-install mounts to all the workers immediately\n\t\t\t\t\t// following WordPress install. But if we start creating\n\t\t\t\t\t// request-handling workers on-demand, we will to apply post-install\n\t\t\t\t\t// mounts here.\n\t\t\t\t\tif (this.bootedWordPress) {\n\t\t\t\t\t\tawait mountResources(php, options.mountsAfterWpInstall);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tsapiName: 'cli',\n\t\t\t\tcookieStore: false,\n\t\t\t\tpathAliases: options.pathAliases,\n\t\t\t\tspawnHandler: () =>\n\t\t\t\t\tsandboxedSpawnHandlerFactory(() => {\n\t\t\t\t\t\tlet effectiveOptions = options;\n\t\t\t\t\t\tif (!this.bootedWordPress) {\n\t\t\t\t\t\t\t// WordPress is not yet booted so skip the post-install mounts.\n\t\t\t\t\t\t\teffectiveOptions = {\n\t\t\t\t\t\t\t\t...options,\n\t\t\t\t\t\t\t\tmountsAfterWpInstall: [],\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn createPHPWorker(\n\t\t\t\t\t\t\teffectiveOptions,\n\t\t\t\t\t\t\tthis.fileLockManager!\n\t\t\t\t\t\t);\n\t\t\t\t\t}),\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\tasync mountAfterWordPressInstall(mounts: Array<Mount>) {\n\t\t// Make sure workers not involved in the WordPress install\n\t\t// process know whether WordPress booted so they can\n\t\t// apply post-install mounts when spawning new PHP workers.\n\t\tthis.bootedWordPress = true;\n\t\tawait mountResources(this.__internal_getPHP()!, mounts);\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\n/**\n * Returns a factory function that starts a new PHP runtime in the currently\n * running process. This is used for rotating the PHP runtime periodically.\n */\nfunction createPhpRuntimeFactory(\n\toptions: WorkerBootRequestHandlerOptions,\n\tfileLockManager: FileLockManager\n) {\n\treturn async () => {\n\t\treturn await loadNodeRuntime(\n\t\t\toptions.phpVersion || RecommendedPHPVersion,\n\t\t\t{\n\t\t\t\tfileLockManager,\n\t\t\t\temscriptenOptions: {\n\t\t\t\t\tprocessId: options.processId,\n\t\t\t\t\ttrace: options.trace ? tracePhpWasm : undefined,\n\t\t\t\t\tnativeInternalDirPath: options.nativeInternalDirPath,\n\t\t\t\t},\n\t\t\t\tfollowSymlinks: options.followSymlinks,\n\t\t\t\twithIntl: options.withIntl,\n\t\t\t\twithRedis: options.withRedis,\n\t\t\t\twithMemcached: options.withMemcached,\n\t\t\t\twithXdebug: options.withXdebug,\n\t\t\t}\n\t\t);\n\t};\n}\n\n/**\n * Spawns a new PHP process to be used in the PHP spawn handler (in proc_open() etc. calls).\n * It boots from this worker-thread-v1.ts file, but is a separate process.\n *\n * We explicitly avoid using PHPProcessManager.acquirePHPInstance() here.\n *\n * Why?\n *\n * Because each PHP instance acquires actual OS-level file locks via fcntl() and LockFileEx()\n * syscalls. Running multiple PHP instances from the same OS process would allow them to\n * acquire overlapping locks. Running every PHP instance in a separate OS process ensures\n * any locks that overlap between PHP instances conflict with each other as expected.\n *\n * @param options - The options for the worker.\n * @param fileLockManager - The file lock manager to use.\n * @returns A promise that resolves to the PHP worker.\n */\nasync function createPHPWorker(\n\t// NOTE: We explicitly remove processId from the options\n\t// type so the type system will catch if we try to reuse\n\t// our parent's process ID.\n\toptions: Omit<WorkerBootRequestHandlerOptions, 'processId'>,\n\tfileLockManager: FileLockManager\n) {\n\tconst spawnedWorker = await spawnWorkerThread('v1');\n\n\tconst handler = consumeAPI<PlaygroundCliBlueprintV1Worker>(\n\t\tspawnedWorker.phpPort\n\t);\n\thandler.useFileLockManager(fileLockManager as any);\n\tawait handler.bootRequestHandler({\n\t\t...options,\n\t\tprocessId: spawnedWorker.processId,\n\t});\n\n\treturn {\n\t\tphp: handler,\n\t\treap: () => {\n\t\t\ttry {\n\t\t\t\thandler.dispose();\n\t\t\t} catch {\n\t\t\t\t/** */\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tspawnedWorker.worker.terminate();\n\t\t\t} catch {\n\t\t\t\t/** */\n\t\t\t}\n\t\t},\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","consumeAPISync","options","workerPostInstallMountsPort","siteUrl","phpVersion","wordpressInstallMode","wordPressZip","sqliteIntegrationPluginZip","dataSqlPath","constants","bootWordPress","rootCertificates","postInstall","consumeAPI","releaseApiProxy","setApiReady","e","setAPIError","requestHandler","bootRequestHandler","createPhpRuntimeFactory","php","mountResources","sandboxedSpawnHandlerFactory","effectiveOptions","createPHPWorker","primaryPhp","mounts","fileLockManager","loadNodeRuntime","RecommendedPHPVersion","spawnedWorker","spawnWorkerThread","handler","logger","phpChannel","MessageChannel","exposeAPI","EmscriptenDownloadMonitor","parentPort"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const _=require("@php-wasm/logger"),m=require("@php-wasm/node"),$=require("@php-wasm/progress"),n=require("@php-wasm/universal"),x=require("@php-wasm/util"),S=require("@wp-playground/blueprints"),W=require("@wp-playground/wordpress"),A=require("fs"),y=require("path"),B=require("tls"),R=require("worker_threads"),T=require("./run-cli-B6Dm34vQ.cjs");async function g(s,e){for(const t of e)try{s.mkdir(t.vfsPath),await s.mount(t.vfsPath,m.createNodeFsMountHandler(t.hostPath))}catch{i.stderr(`\x1B[31m\x1B[1mError mounting path ${t.hostPath} at ${t.vfsPath}\x1B[0m
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const _=require("@php-wasm/logger"),m=require("@php-wasm/node"),$=require("@php-wasm/progress"),n=require("@php-wasm/universal"),x=require("@php-wasm/util"),S=require("@wp-playground/blueprints"),W=require("@wp-playground/wordpress"),A=require("fs"),y=require("path"),B=require("tls"),R=require("worker_threads"),T=require("./run-cli-vtAjdYXb.cjs");async function g(s,e){for(const t of e)try{s.mkdir(t.vfsPath),await s.mount(t.vfsPath,m.createNodeFsMountHandler(t.hostPath))}catch{i.stderr(`\x1B[31m\x1B[1mError mounting path ${t.hostPath} at ${t.vfsPath}\x1B[0m
2
2
  `),process.exit(1)}}function C(s,e,...t){console.log(performance.now().toFixed(6).padStart(15,"0"),s.toString().padStart(16,"0"),x.sprintf(e,...t))}Object.defineProperty(process.stdout,"isTTY",{value:!0});Object.defineProperty(process.stderr,"isTTY",{value:!0});const i={lastWriteWasProgress:!1,progress(s){T.shouldRenderProgress(process.stdout)&&(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){process.stdout.write(`
4
4
 
@@ -9,7 +9,7 @@ import { existsSync as G } from "fs";
9
9
  import m from "path";
10
10
  import { rootCertificates as Y } from "tls";
11
11
  import { MessageChannel as z, parentPort as K } from "worker_threads";
12
- import { s as J, b as Q } from "./run-cli-B9kBDU12.js";
12
+ import { s as J, c as Q } from "./run-cli-C2bV7mIt.js";
13
13
  async function b(s, e) {
14
14
  for (const t of e)
15
15
  try {