@wp-playground/cli 3.0.19 → 3.0.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/README.md CHANGED
@@ -91,7 +91,7 @@ The `server` command supports the following optional arguments:
91
91
  - `--blueprint=<path>`: The path to a JSON Blueprint file to execute.
92
92
  - `--blueprint-may-read-adjacent-files`: Consent flag: Allow "bundled" resources in a local blueprint to read files in the same directory as the blueprint file.
93
93
  - `--login`: Automatically log the user in as an administrator.
94
- - `--skip-wordpress-setup`: Do not download or install WordPress. Useful if you are mounting a full WordPress directory.
94
+ - `--wordpress-install-mode <mode>`: Control how Playground prepares WordPress before booting. Defaults to `download-and-install`. Other options: `install-from-existing-files` (install using files you've mounted), `install-from-existing-files-if-needed` (same, but skip setup when an existing site is detected), and `do-not-attempt-installing` (never download or install WordPress).
95
95
  - `--skip-sqlite-setup`: Do not set up the SQLite database integration.
96
96
  - `--verbosity`: Output logs and progress messages (choices: "quiet", "normal", "debug"). Defaults to "normal".
97
97
 
@@ -3,6 +3,7 @@ import type { FileLockManager } from '@php-wasm/node';
3
3
  import { EmscriptenDownloadMonitor } from '@php-wasm/progress';
4
4
  import type { RemoteAPI, SupportedPHPVersion } from '@php-wasm/universal';
5
5
  import { PHPWorker } from '@php-wasm/universal';
6
+ import { type WordPressInstallMode } from '@wp-playground/wordpress';
6
7
  import { type MessagePort } from 'worker_threads';
7
8
  export interface Mount {
8
9
  hostPath: string;
@@ -29,6 +30,7 @@ export type WorkerBootOptions = {
29
30
  nativeInternalDirPath: string;
30
31
  };
31
32
  export type PrimaryWorkerBootOptions = WorkerBootOptions & {
33
+ wordpressInstallMode: WordPressInstallMode;
32
34
  wpVersion?: string;
33
35
  wordPressZip?: ArrayBuffer;
34
36
  sqliteIntegrationPluginZip?: ArrayBuffer;
@@ -60,7 +62,7 @@ export declare class PlaygroundCliBlueprintV1Worker extends PHPWorker {
60
62
  * @see phpwasm-emscripten-library-file-locking-for-node.js
61
63
  */
62
64
  useFileLockManager(port: MessagePort): Promise<void>;
63
- bootAndSetUpInitialWorker({ siteUrl, mountsBeforeWpInstall, mountsAfterWpInstall, phpVersion: php, wordPressZip, sqliteIntegrationPluginZip, firstProcessId, processIdSpaceLength, dataSqlPath, followSymlinks, trace, internalCookieStore, withXdebug, nativeInternalDirPath, }: PrimaryWorkerBootOptions): Promise<void>;
65
+ bootAndSetUpInitialWorker({ siteUrl, mountsBeforeWpInstall, mountsAfterWpInstall, phpVersion: php, wordpressInstallMode, wordPressZip, sqliteIntegrationPluginZip, firstProcessId, processIdSpaceLength, dataSqlPath, followSymlinks, trace, internalCookieStore, withXdebug, nativeInternalDirPath, }: PrimaryWorkerBootOptions): Promise<void>;
64
66
  bootWorker(args: WorkerBootOptions): Promise<void>;
65
67
  bootRequestHandler({ siteUrl, followSymlinks, phpVersion, firstProcessId, processIdSpaceLength, trace, nativeInternalDirPath, mountsBeforeWpInstall, mountsAfterWpInstall, withXdebug, }: WorkerBootRequestHandlerOptions): Promise<void>;
66
68
  dispose(): Promise<void>;
package/cli.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";const n=require("./run-cli-4UcAoCNX.cjs");n.parseOptionsAndRunCLI();
1
+ "use strict";const n=require("./run-cli-DJ9bUpjg.cjs");n.parseOptionsAndRunCLI();
2
2
  //# sourceMappingURL=cli.cjs.map
package/cli.js CHANGED
@@ -1,3 +1,3 @@
1
- import { p } from "./run-cli-fhMEvo2X.js";
1
+ import { p } from "./run-cli-g3_uJkf5.js";
2
2
  p();
3
3
  //# sourceMappingURL=cli.js.map
package/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./run-cli-4UcAoCNX.cjs");exports.LogVerbosity=e.LogVerbosity;exports.parseOptionsAndRunCLI=e.parseOptionsAndRunCLI;exports.runCLI=e.runCLI;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./run-cli-DJ9bUpjg.cjs");exports.LogVerbosity=e.LogVerbosity;exports.parseOptionsAndRunCLI=e.parseOptionsAndRunCLI;exports.runCLI=e.runCLI;
2
2
  //# sourceMappingURL=index.cjs.map
package/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { L as o, p as a, r as n } from "./run-cli-fhMEvo2X.js";
1
+ import { L as o, p as a, r as n } from "./run-cli-g3_uJkf5.js";
2
2
  export {
3
3
  o as LogVerbosity,
4
4
  a as parseOptionsAndRunCLI,
@@ -1,9 +1,9 @@
1
- import { createNodeFsMountHandler as l } from "@php-wasm/node";
2
- import r, { existsSync as c } from "fs";
3
- import m, { basename as p, join as h } from "path";
4
- function $(e) {
5
- const t = [];
6
- for (const n of e) {
1
+ import { createNodeFsMountHandler as h } from "@php-wasm/node";
2
+ import r, { existsSync as l } from "fs";
3
+ import d, { basename as p, join as c } from "path";
4
+ function $(t) {
5
+ const e = [];
6
+ for (const n of t) {
7
7
  const o = n.split(":");
8
8
  if (o.length !== 2)
9
9
  throw new Error(`Invalid mount format: ${n}.
@@ -11,32 +11,32 @@ function $(e) {
11
11
  If your path contains a colon, e.g. C:\\myplugin, use the --mount-dir option instead.
12
12
  Example: --mount-dir C:\\my-plugin /wordpress/wp-content/plugins/my-plugin`);
13
13
  const [s, i] = o;
14
- if (!c(s))
14
+ if (!l(s))
15
15
  throw new Error(`Host path does not exist: ${s}`);
16
- t.push({ hostPath: s, vfsPath: i });
16
+ e.push({ hostPath: s, vfsPath: i });
17
17
  }
18
- return t;
18
+ return e;
19
19
  }
20
- function x(e) {
21
- if (e.length % 2 !== 0)
20
+ function x(t) {
21
+ if (t.length % 2 !== 0)
22
22
  throw new Error("Invalid mount format. Expected: /host/path /vfs/path");
23
- const t = [];
24
- for (let n = 0; n < e.length; n += 2) {
25
- const o = e[n], s = e[n + 1];
26
- if (!c(o))
23
+ const e = [];
24
+ for (let n = 0; n < t.length; n += 2) {
25
+ const o = t[n], s = t[n + 1];
26
+ if (!l(o))
27
27
  throw new Error(`Host path does not exist: ${o}`);
28
- t.push({
29
- hostPath: m.resolve(process.cwd(), o),
28
+ e.push({
29
+ hostPath: d.resolve(process.cwd(), o),
30
30
  vfsPath: s
31
31
  });
32
32
  }
33
- return t;
33
+ return e;
34
34
  }
35
- async function N(e, t) {
36
- for (const n of t)
37
- await e.mount(
35
+ async function N(t, e) {
36
+ for (const n of e)
37
+ await t.mount(
38
38
  n.vfsPath,
39
- l(n.hostPath)
39
+ h(n.hostPath)
40
40
  );
41
41
  }
42
42
  const u = {
@@ -58,31 +58,31 @@ const u = {
58
58
  `
59
59
  }
60
60
  };
61
- function E(e) {
62
- const t = e.autoMount, n = [...e.mount || []], o = [...e["mount-before-install"] || []], s = {
63
- ...e,
61
+ function M(t) {
62
+ const e = t.autoMount, n = [...t.mount || []], o = [...t["mount-before-install"] || []], s = {
63
+ ...t,
64
64
  mount: n,
65
65
  "mount-before-install": o,
66
66
  "additional-blueprint-steps": [
67
- ...e["additional-blueprint-steps"] || []
67
+ ...t["additional-blueprint-steps"] || []
68
68
  ]
69
69
  };
70
- if (g(t)) {
71
- const i = p(t);
70
+ if (g(e)) {
71
+ const i = p(e);
72
72
  n.push({
73
- hostPath: t,
73
+ hostPath: e,
74
74
  vfsPath: `/wordpress/wp-content/plugins/${i}`
75
75
  }), s["additional-blueprint-steps"].push({
76
76
  step: "activatePlugin",
77
- pluginPath: `/wordpress/wp-content/plugins/${p(t)}`
77
+ pluginPath: `/wordpress/wp-content/plugins/${p(e)}`
78
78
  });
79
- } else if (w(t)) {
80
- const i = p(t);
79
+ } else if (w(e)) {
80
+ const i = p(e);
81
81
  n.push({
82
- hostPath: t,
82
+ hostPath: e,
83
83
  vfsPath: `/wordpress/wp-content/themes/${i}`
84
84
  }), s["additional-blueprint-steps"].push(
85
- e["experimental-blueprints-v2-runner"] ? {
85
+ t["experimental-blueprints-v2-runner"] ? {
86
86
  step: "activateTheme",
87
87
  themeDirectoryName: i
88
88
  } : {
@@ -90,42 +90,42 @@ function E(e) {
90
90
  themeFolderName: i
91
91
  }
92
92
  );
93
- } else if (f(t)) {
94
- const i = r.readdirSync(t);
93
+ } else if (f(e)) {
94
+ const i = r.readdirSync(e);
95
95
  for (const a of i)
96
96
  a !== "index.php" && n.push({
97
- hostPath: `${t}/${a}`,
97
+ hostPath: `${e}/${a}`,
98
98
  vfsPath: `/wordpress/wp-content/${a}`
99
99
  });
100
100
  s["additional-blueprint-steps"].push(u);
101
- } else d(t) ? (o.push({ hostPath: t, vfsPath: "/wordpress" }), s.mode = "apply-to-existing-site", s["additional-blueprint-steps"].push(u)) : (n.push({ hostPath: t, vfsPath: "/wordpress" }), s.mode = "mount-only");
101
+ } else m(e) ? (o.push({ hostPath: e, vfsPath: "/wordpress" }), s.mode = "apply-to-existing-site", s["additional-blueprint-steps"].push(u), s.wordpressInstallMode || (s.wordpressInstallMode = "install-from-existing-files-if-needed")) : (n.push({ hostPath: e, vfsPath: "/wordpress" }), s.mode = "mount-only");
102
102
  return s;
103
103
  }
104
- function d(e) {
105
- const t = r.readdirSync(e);
106
- return t.includes("wp-admin") && t.includes("wp-includes") && t.includes("wp-content");
104
+ function m(t) {
105
+ const e = r.readdirSync(t);
106
+ return e.includes("wp-admin") && e.includes("wp-includes") && e.includes("wp-content");
107
107
  }
108
- function f(e) {
109
- const t = r.readdirSync(e);
110
- return t.includes("themes") || t.includes("plugins") || t.includes("mu-plugins") || t.includes("uploads");
108
+ function f(t) {
109
+ const e = r.readdirSync(t);
110
+ return e.includes("themes") || e.includes("plugins") || e.includes("mu-plugins") || e.includes("uploads");
111
111
  }
112
- function w(e) {
113
- if (!r.readdirSync(e).includes("style.css"))
112
+ function w(t) {
113
+ if (!r.readdirSync(t).includes("style.css"))
114
114
  return !1;
115
- const n = r.readFileSync(h(e, "style.css"), "utf8");
115
+ const n = r.readFileSync(c(t, "style.css"), "utf8");
116
116
  return !!/^(?:[ \t]*<\?php)?[ \t/*#@]*Theme Name:(.*)$/im.exec(n);
117
117
  }
118
- function g(e) {
119
- const t = r.readdirSync(e), n = /^(?:[ \t]*<\?php)?[ \t/*#@]*Plugin Name:(.*)$/im;
120
- return !!t.filter((s) => s.endsWith(".php")).find((s) => {
121
- const i = r.readFileSync(h(e, s), "utf8");
118
+ function g(t) {
119
+ const e = r.readdirSync(t), n = /^(?:[ \t]*<\?php)?[ \t/*#@]*Plugin Name:(.*)$/im;
120
+ return !!e.filter((s) => s.endsWith(".php")).find((s) => {
121
+ const i = r.readFileSync(c(t, s), "utf8");
122
122
  return !!n.exec(i);
123
123
  });
124
124
  }
125
125
  export {
126
126
  x as a,
127
- E as e,
127
+ M as e,
128
128
  N as m,
129
129
  $ as p
130
130
  };
131
- //# sourceMappingURL=mounts-D1_eXSTw.js.map
131
+ //# sourceMappingURL=mounts-ChxECdbN.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mounts-D1_eXSTw.js","sources":["../../../../packages/playground/cli/src/mounts.ts"],"sourcesContent":["import { createNodeFsMountHandler } from '@php-wasm/node';\nimport type { PHP } from '@php-wasm/universal';\nimport fs, { existsSync } from 'fs';\nimport path, { basename, join } from 'path';\nimport type { RunCLIArgs } from './run-cli';\n\nexport interface Mount {\n\thostPath: string;\n\tvfsPath: string;\n}\n\n/**\n * Parse an array of mount argument strings where the host path and VFS path\n * are separated by a colon.\n *\n * Example:\n * parseMountWithDelimiterArguments( [ '/host/path:/vfs/path', '/host/path:/vfs/path' ] )\n * // returns:\n * [\n * { hostPath: '/host/path', vfsPath: '/vfs/path' },\n * { hostPath: '/host/path', vfsPath: '/vfs/path' }\n * ]\n *\n * @param mounts - An array of mount argument strings separated by a colon.\n * @returns An array of Mount objects.\n */\nexport function parseMountWithDelimiterArguments(mounts: string[]): Mount[] {\n\tconst parsedMounts = [];\n\tfor (const mount of mounts) {\n\t\tconst mountParts = mount.split(':');\n\t\tif (mountParts.length !== 2) {\n\t\t\tthrow new Error(`Invalid mount format: ${mount}.\n\t\t\t\tExpected format: /host/path:/vfs/path.\n\t\t\t\tIf your path contains a colon, e.g. C:\\\\myplugin, use the --mount-dir option instead.\n\t\t\t\tExample: --mount-dir C:\\\\my-plugin /wordpress/wp-content/plugins/my-plugin`);\n\t\t}\n\t\tconst [hostPath, vfsPath] = mountParts;\n\t\tif (!existsSync(hostPath)) {\n\t\t\tthrow new Error(`Host path does not exist: ${hostPath}`);\n\t\t}\n\t\tparsedMounts.push({ hostPath, vfsPath });\n\t}\n\treturn parsedMounts;\n}\n\n/**\n * Parse an array of mount argument strings where each odd array element is a host path\n * and each even element is the VFS path.\n * e.g. [ '/host/path', '/vfs/path', '/host/path2', '/vfs/path2' ]\n *\n * The result will be an array of Mount objects for each host path the\n * following element is it's VFS path.\n * e.g. [\n * { hostPath: '/host/path', vfsPath: '/vfs/path' },\n * { hostPath: '/host/path2', vfsPath: '/vfs/path2' }\n * ]\n *\n * @param mounts - An array of paths\n * @returns An array of Mount objects.\n */\nexport function parseMountDirArguments(mounts: string[]): Mount[] {\n\tif (mounts.length % 2 !== 0) {\n\t\tthrow new Error('Invalid mount format. Expected: /host/path /vfs/path');\n\t}\n\n\tconst parsedMounts = [];\n\tfor (let i = 0; i < mounts.length; i += 2) {\n\t\tconst source = mounts[i];\n\t\tconst vfsPath = mounts[i + 1];\n\t\tif (!existsSync(source)) {\n\t\t\tthrow new Error(`Host path does not exist: ${source}`);\n\t\t}\n\t\tparsedMounts.push({\n\t\t\thostPath: path.resolve(process.cwd(), source),\n\t\t\tvfsPath,\n\t\t});\n\t}\n\treturn parsedMounts;\n}\n\nexport async function mountResources(php: PHP, mounts: Mount[]) {\n\tfor (const mount of mounts) {\n\t\tawait php.mount(\n\t\t\tmount.vfsPath,\n\t\t\tcreateNodeFsMountHandler(mount.hostPath)\n\t\t);\n\t}\n}\n\nconst ACTIVATE_FIRST_THEME_STEP = {\n\tstep: 'runPHP',\n\tcode: {\n\t\tfilename: 'activate-theme.php',\n\t\t// @TODO: Remove DOCROOT check after moving totally to Blueprints v2.\n\t\tcontent: `<?php\n\t\t\t$docroot = getenv('DOCROOT') ? getenv('DOCROOT') : '/wordpress';\n\t\t\trequire_once \"$docroot/wp-load.php\";\n\t\t\t$theme = wp_get_theme();\n\t\t\tif (!$theme->exists()) {\n\t\t\t\t$themes = wp_get_themes();\n\t\t\t\tif (count($themes) > 0) {\n\t\t\t\t\t$themeName = array_keys($themes)[0];\n\t\t\t\t\tswitch_theme($themeName);\n\t\t\t\t}\n\t\t\t}\n\t\t`,\n\t},\n};\n\n/**\n * Auto-mounts resolution logic:\n */\nexport function expandAutoMounts(args: RunCLIArgs): RunCLIArgs {\n\tconst path = args.autoMount!;\n\n\tconst mount = [...(args.mount || [])];\n\tconst mountBeforeInstall = [...(args['mount-before-install'] || [])];\n\n\tconst newArgs = {\n\t\t...args,\n\t\tmount,\n\t\t'mount-before-install': mountBeforeInstall,\n\t\t'additional-blueprint-steps': [\n\t\t\t...((args as any)['additional-blueprint-steps'] || []),\n\t\t],\n\t};\n\n\tif (isPluginFilename(path)) {\n\t\tconst pluginName = basename(path);\n\t\tmount.push({\n\t\t\thostPath: path,\n\t\t\tvfsPath: `/wordpress/wp-content/plugins/${pluginName}`,\n\t\t});\n\t\tnewArgs['additional-blueprint-steps'].push({\n\t\t\tstep: 'activatePlugin',\n\t\t\tpluginPath: `/wordpress/wp-content/plugins/${basename(path)}`,\n\t\t});\n\t} else if (isThemeDirectory(path)) {\n\t\tconst themeName = basename(path);\n\t\tmount.push({\n\t\t\thostPath: path,\n\t\t\tvfsPath: `/wordpress/wp-content/themes/${themeName}`,\n\t\t});\n\t\tnewArgs['additional-blueprint-steps'].push(\n\t\t\targs['experimental-blueprints-v2-runner']\n\t\t\t\t? {\n\t\t\t\t\t\tstep: 'activateTheme',\n\t\t\t\t\t\tthemeDirectoryName: themeName,\n\t\t\t\t }\n\t\t\t\t: {\n\t\t\t\t\t\tstep: 'activateTheme',\n\t\t\t\t\t\tthemeFolderName: themeName,\n\t\t\t\t }\n\t\t);\n\t} else if (containsWpContentDirectories(path)) {\n\t\t/**\n\t\t * Mount each wp-content file and directory individually.\n\t\t */\n\t\tconst files = fs.readdirSync(path);\n\t\tfor (const file of files) {\n\t\t\t/**\n\t\t\t * WordPress already ships with the wp-content/index.php file\n\t\t\t * and Playground does not support overriding existing VFS files\n\t\t\t * with mounts.\n\t\t\t */\n\t\t\tif (file === 'index.php') {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tmount.push({\n\t\t\t\thostPath: `${path}/${file}`,\n\t\t\t\tvfsPath: `/wordpress/wp-content/${file}`,\n\t\t\t});\n\t\t}\n\t\tnewArgs['additional-blueprint-steps'].push(ACTIVATE_FIRST_THEME_STEP);\n\t} else if (containsFullWordPressInstallation(path)) {\n\t\tmountBeforeInstall.push({ hostPath: path, vfsPath: '/wordpress' });\n\t\t// @TODO: If overriding another mode, throw an error or print a warning.\n\t\tnewArgs.mode = 'apply-to-existing-site';\n\t\tnewArgs['additional-blueprint-steps'].push(ACTIVATE_FIRST_THEME_STEP);\n\t} else {\n\t\t/**\n\t\t * By default, mount the current working directory as the Playground root.\n\t\t * This allows users to run and PHP or HTML files using the Playground CLI.\n\t\t */\n\t\tmount.push({ hostPath: path, vfsPath: '/wordpress' });\n\t\t// @TODO: If overriding another mode, throw an error or print a warning.\n\t\tnewArgs.mode = 'mount-only';\n\t}\n\n\treturn newArgs as RunCLIArgs;\n}\n\nexport function containsFullWordPressInstallation(path: string): boolean {\n\tconst files = fs.readdirSync(path);\n\treturn (\n\t\tfiles.includes('wp-admin') &&\n\t\tfiles.includes('wp-includes') &&\n\t\tfiles.includes('wp-content')\n\t);\n}\n\nexport function containsWpContentDirectories(path: string): boolean {\n\tconst files = fs.readdirSync(path);\n\treturn (\n\t\tfiles.includes('themes') ||\n\t\tfiles.includes('plugins') ||\n\t\tfiles.includes('mu-plugins') ||\n\t\tfiles.includes('uploads')\n\t);\n}\n\nexport function isThemeDirectory(path: string): boolean {\n\tconst files = fs.readdirSync(path);\n\tif (!files.includes('style.css')) {\n\t\treturn false;\n\t}\n\tconst styleCssContent = fs.readFileSync(join(path, 'style.css'), 'utf8');\n\tconst themeNameRegex = /^(?:[ \\t]*<\\?php)?[ \\t/*#@]*Theme Name:(.*)$/im;\n\treturn !!themeNameRegex.exec(styleCssContent);\n}\n\nexport function isPluginFilename(path: string): boolean {\n\tconst files = fs.readdirSync(path);\n\tconst pluginNameRegex = /^(?:[ \\t]*<\\?php)?[ \\t/*#@]*Plugin Name:(.*)$/im;\n\tconst pluginNameMatch = files\n\t\t.filter((file) => file.endsWith('.php'))\n\t\t.find((file) => {\n\t\t\tconst fileContent = fs.readFileSync(join(path, file), 'utf8');\n\t\t\treturn !!pluginNameRegex.exec(fileContent);\n\t\t});\n\treturn !!pluginNameMatch;\n}\n"],"names":["parseMountWithDelimiterArguments","mounts","parsedMounts","mount","mountParts","hostPath","vfsPath","existsSync","parseMountDirArguments","i","source","path","mountResources","php","createNodeFsMountHandler","ACTIVATE_FIRST_THEME_STEP","expandAutoMounts","args","mountBeforeInstall","newArgs","isPluginFilename","pluginName","basename","isThemeDirectory","themeName","containsWpContentDirectories","files","fs","file","containsFullWordPressInstallation","styleCssContent","join","pluginNameRegex","fileContent"],"mappings":"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"}
1
+ {"version":3,"file":"mounts-ChxECdbN.js","sources":["../../../../packages/playground/cli/src/mounts.ts"],"sourcesContent":["import { createNodeFsMountHandler } from '@php-wasm/node';\nimport type { PHP } from '@php-wasm/universal';\nimport fs, { existsSync } from 'fs';\nimport path, { basename, join } from 'path';\nimport type { RunCLIArgs } from './run-cli';\n\nexport interface Mount {\n\thostPath: string;\n\tvfsPath: string;\n}\n\n/**\n * Parse an array of mount argument strings where the host path and VFS path\n * are separated by a colon.\n *\n * Example:\n * parseMountWithDelimiterArguments( [ '/host/path:/vfs/path', '/host/path:/vfs/path' ] )\n * // returns:\n * [\n * { hostPath: '/host/path', vfsPath: '/vfs/path' },\n * { hostPath: '/host/path', vfsPath: '/vfs/path' }\n * ]\n *\n * @param mounts - An array of mount argument strings separated by a colon.\n * @returns An array of Mount objects.\n */\nexport function parseMountWithDelimiterArguments(mounts: string[]): Mount[] {\n\tconst parsedMounts = [];\n\tfor (const mount of mounts) {\n\t\tconst mountParts = mount.split(':');\n\t\tif (mountParts.length !== 2) {\n\t\t\tthrow new Error(`Invalid mount format: ${mount}.\n\t\t\t\tExpected format: /host/path:/vfs/path.\n\t\t\t\tIf your path contains a colon, e.g. C:\\\\myplugin, use the --mount-dir option instead.\n\t\t\t\tExample: --mount-dir C:\\\\my-plugin /wordpress/wp-content/plugins/my-plugin`);\n\t\t}\n\t\tconst [hostPath, vfsPath] = mountParts;\n\t\tif (!existsSync(hostPath)) {\n\t\t\tthrow new Error(`Host path does not exist: ${hostPath}`);\n\t\t}\n\t\tparsedMounts.push({ hostPath, vfsPath });\n\t}\n\treturn parsedMounts;\n}\n\n/**\n * Parse an array of mount argument strings where each odd array element is a host path\n * and each even element is the VFS path.\n * e.g. [ '/host/path', '/vfs/path', '/host/path2', '/vfs/path2' ]\n *\n * The result will be an array of Mount objects for each host path the\n * following element is it's VFS path.\n * e.g. [\n * { hostPath: '/host/path', vfsPath: '/vfs/path' },\n * { hostPath: '/host/path2', vfsPath: '/vfs/path2' }\n * ]\n *\n * @param mounts - An array of paths\n * @returns An array of Mount objects.\n */\nexport function parseMountDirArguments(mounts: string[]): Mount[] {\n\tif (mounts.length % 2 !== 0) {\n\t\tthrow new Error('Invalid mount format. Expected: /host/path /vfs/path');\n\t}\n\n\tconst parsedMounts = [];\n\tfor (let i = 0; i < mounts.length; i += 2) {\n\t\tconst source = mounts[i];\n\t\tconst vfsPath = mounts[i + 1];\n\t\tif (!existsSync(source)) {\n\t\t\tthrow new Error(`Host path does not exist: ${source}`);\n\t\t}\n\t\tparsedMounts.push({\n\t\t\thostPath: path.resolve(process.cwd(), source),\n\t\t\tvfsPath,\n\t\t});\n\t}\n\treturn parsedMounts;\n}\n\nexport async function mountResources(php: PHP, mounts: Mount[]) {\n\tfor (const mount of mounts) {\n\t\tawait php.mount(\n\t\t\tmount.vfsPath,\n\t\t\tcreateNodeFsMountHandler(mount.hostPath)\n\t\t);\n\t}\n}\n\nconst ACTIVATE_FIRST_THEME_STEP = {\n\tstep: 'runPHP',\n\tcode: {\n\t\tfilename: 'activate-theme.php',\n\t\t// @TODO: Remove DOCROOT check after moving totally to Blueprints v2.\n\t\tcontent: `<?php\n\t\t\t$docroot = getenv('DOCROOT') ? getenv('DOCROOT') : '/wordpress';\n\t\t\trequire_once \"$docroot/wp-load.php\";\n\t\t\t$theme = wp_get_theme();\n\t\t\tif (!$theme->exists()) {\n\t\t\t\t$themes = wp_get_themes();\n\t\t\t\tif (count($themes) > 0) {\n\t\t\t\t\t$themeName = array_keys($themes)[0];\n\t\t\t\t\tswitch_theme($themeName);\n\t\t\t\t}\n\t\t\t}\n\t\t`,\n\t},\n};\n\n/**\n * Auto-mounts resolution logic:\n */\nexport function expandAutoMounts(args: RunCLIArgs): RunCLIArgs {\n\tconst path = args.autoMount!;\n\n\tconst mount = [...(args.mount || [])];\n\tconst mountBeforeInstall = [...(args['mount-before-install'] || [])];\n\n\tconst newArgs = {\n\t\t...args,\n\t\tmount,\n\t\t'mount-before-install': mountBeforeInstall,\n\t\t'additional-blueprint-steps': [\n\t\t\t...((args as any)['additional-blueprint-steps'] || []),\n\t\t],\n\t};\n\n\tif (isPluginFilename(path)) {\n\t\tconst pluginName = basename(path);\n\t\tmount.push({\n\t\t\thostPath: path,\n\t\t\tvfsPath: `/wordpress/wp-content/plugins/${pluginName}`,\n\t\t});\n\t\tnewArgs['additional-blueprint-steps'].push({\n\t\t\tstep: 'activatePlugin',\n\t\t\tpluginPath: `/wordpress/wp-content/plugins/${basename(path)}`,\n\t\t});\n\t} else if (isThemeDirectory(path)) {\n\t\tconst themeName = basename(path);\n\t\tmount.push({\n\t\t\thostPath: path,\n\t\t\tvfsPath: `/wordpress/wp-content/themes/${themeName}`,\n\t\t});\n\t\tnewArgs['additional-blueprint-steps'].push(\n\t\t\targs['experimental-blueprints-v2-runner']\n\t\t\t\t? {\n\t\t\t\t\t\tstep: 'activateTheme',\n\t\t\t\t\t\tthemeDirectoryName: themeName,\n\t\t\t\t }\n\t\t\t\t: {\n\t\t\t\t\t\tstep: 'activateTheme',\n\t\t\t\t\t\tthemeFolderName: themeName,\n\t\t\t\t }\n\t\t);\n\t} else if (containsWpContentDirectories(path)) {\n\t\t/**\n\t\t * Mount each wp-content file and directory individually.\n\t\t */\n\t\tconst files = fs.readdirSync(path);\n\t\tfor (const file of files) {\n\t\t\t/**\n\t\t\t * WordPress already ships with the wp-content/index.php file\n\t\t\t * and Playground does not support overriding existing VFS files\n\t\t\t * with mounts.\n\t\t\t */\n\t\t\tif (file === 'index.php') {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tmount.push({\n\t\t\t\thostPath: `${path}/${file}`,\n\t\t\t\tvfsPath: `/wordpress/wp-content/${file}`,\n\t\t\t});\n\t\t}\n\t\tnewArgs['additional-blueprint-steps'].push(ACTIVATE_FIRST_THEME_STEP);\n\t} else if (containsFullWordPressInstallation(path)) {\n\t\tmountBeforeInstall.push({ hostPath: path, vfsPath: '/wordpress' });\n\t\t// @TODO: If overriding another mode, throw an error or print a warning.\n\t\tnewArgs.mode = 'apply-to-existing-site';\n\t\tnewArgs['additional-blueprint-steps'].push(ACTIVATE_FIRST_THEME_STEP);\n\t\tif (!newArgs.wordpressInstallMode) {\n\t\t\tnewArgs.wordpressInstallMode =\n\t\t\t\t'install-from-existing-files-if-needed';\n\t\t}\n\t} else {\n\t\t/**\n\t\t * By default, mount the current working directory as the Playground root.\n\t\t * This allows users to run and PHP or HTML files using the Playground CLI.\n\t\t */\n\t\tmount.push({ hostPath: path, vfsPath: '/wordpress' });\n\t\t// @TODO: If overriding another mode, throw an error or print a warning.\n\t\tnewArgs.mode = 'mount-only';\n\t}\n\n\treturn newArgs as RunCLIArgs;\n}\n\nexport function containsFullWordPressInstallation(path: string): boolean {\n\tconst files = fs.readdirSync(path);\n\treturn (\n\t\tfiles.includes('wp-admin') &&\n\t\tfiles.includes('wp-includes') &&\n\t\tfiles.includes('wp-content')\n\t);\n}\n\nexport function containsWpContentDirectories(path: string): boolean {\n\tconst files = fs.readdirSync(path);\n\treturn (\n\t\tfiles.includes('themes') ||\n\t\tfiles.includes('plugins') ||\n\t\tfiles.includes('mu-plugins') ||\n\t\tfiles.includes('uploads')\n\t);\n}\n\nexport function isThemeDirectory(path: string): boolean {\n\tconst files = fs.readdirSync(path);\n\tif (!files.includes('style.css')) {\n\t\treturn false;\n\t}\n\tconst styleCssContent = fs.readFileSync(join(path, 'style.css'), 'utf8');\n\tconst themeNameRegex = /^(?:[ \\t]*<\\?php)?[ \\t/*#@]*Theme Name:(.*)$/im;\n\treturn !!themeNameRegex.exec(styleCssContent);\n}\n\nexport function isPluginFilename(path: string): boolean {\n\tconst files = fs.readdirSync(path);\n\tconst pluginNameRegex = /^(?:[ \\t]*<\\?php)?[ \\t/*#@]*Plugin Name:(.*)$/im;\n\tconst pluginNameMatch = files\n\t\t.filter((file) => file.endsWith('.php'))\n\t\t.find((file) => {\n\t\t\tconst fileContent = fs.readFileSync(join(path, file), 'utf8');\n\t\t\treturn !!pluginNameRegex.exec(fileContent);\n\t\t});\n\treturn !!pluginNameMatch;\n}\n"],"names":["parseMountWithDelimiterArguments","mounts","parsedMounts","mount","mountParts","hostPath","vfsPath","existsSync","parseMountDirArguments","i","source","path","mountResources","php","createNodeFsMountHandler","ACTIVATE_FIRST_THEME_STEP","expandAutoMounts","args","mountBeforeInstall","newArgs","isPluginFilename","pluginName","basename","isThemeDirectory","themeName","containsWpContentDirectories","files","fs","file","containsFullWordPressInstallation","styleCssContent","join","pluginNameRegex","fileContent"],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ "use strict";const c=require("@php-wasm/node"),r=require("fs"),a=require("path");function l(t){const e=[];for(const n of t){const o=n.split(":");if(o.length!==2)throw new Error(`Invalid mount format: ${n}.
2
+ Expected format: /host/path:/vfs/path.
3
+ If your path contains a colon, e.g. C:\\myplugin, use the --mount-dir option instead.
4
+ Example: --mount-dir C:\\my-plugin /wordpress/wp-content/plugins/my-plugin`);const[s,i]=o;if(!r.existsSync(s))throw new Error(`Host path does not exist: ${s}`);e.push({hostPath:s,vfsPath:i})}return e}function h(t){if(t.length%2!==0)throw new Error("Invalid mount format. Expected: /host/path /vfs/path");const e=[];for(let n=0;n<t.length;n+=2){const o=t[n],s=t[n+1];if(!r.existsSync(o))throw new Error(`Host path does not exist: ${o}`);e.push({hostPath:a.resolve(process.cwd(),o),vfsPath:s})}return e}async function d(t,e){for(const n of e)await t.mount(n.vfsPath,c.createNodeFsMountHandler(n.hostPath))}const p={step:"runPHP",code:{filename:"activate-theme.php",content:`<?php
5
+ $docroot = getenv('DOCROOT') ? getenv('DOCROOT') : '/wordpress';
6
+ require_once "$docroot/wp-load.php";
7
+ $theme = wp_get_theme();
8
+ if (!$theme->exists()) {
9
+ $themes = wp_get_themes();
10
+ if (count($themes) > 0) {
11
+ $themeName = array_keys($themes)[0];
12
+ switch_theme($themeName);
13
+ }
14
+ }
15
+ `}};function m(t){const e=t.autoMount,n=[...t.mount||[]],o=[...t["mount-before-install"]||[]],s={...t,mount:n,"mount-before-install":o,"additional-blueprint-steps":[...t["additional-blueprint-steps"]||[]]};if(P(e)){const i=a.basename(e);n.push({hostPath:e,vfsPath:`/wordpress/wp-content/plugins/${i}`}),s["additional-blueprint-steps"].push({step:"activatePlugin",pluginPath:`/wordpress/wp-content/plugins/${a.basename(e)}`})}else if(g(e)){const i=a.basename(e);n.push({hostPath:e,vfsPath:`/wordpress/wp-content/themes/${i}`}),s["additional-blueprint-steps"].push(t["experimental-blueprints-v2-runner"]?{step:"activateTheme",themeDirectoryName:i}:{step:"activateTheme",themeFolderName:i})}else if(w(e)){const i=r.readdirSync(e);for(const u of i)u!=="index.php"&&n.push({hostPath:`${e}/${u}`,vfsPath:`/wordpress/wp-content/${u}`});s["additional-blueprint-steps"].push(p)}else f(e)?(o.push({hostPath:e,vfsPath:"/wordpress"}),s.mode="apply-to-existing-site",s["additional-blueprint-steps"].push(p),s.wordpressInstallMode||(s.wordpressInstallMode="install-from-existing-files-if-needed")):(n.push({hostPath:e,vfsPath:"/wordpress"}),s.mode="mount-only");return s}function f(t){const e=r.readdirSync(t);return e.includes("wp-admin")&&e.includes("wp-includes")&&e.includes("wp-content")}function w(t){const e=r.readdirSync(t);return e.includes("themes")||e.includes("plugins")||e.includes("mu-plugins")||e.includes("uploads")}function g(t){if(!r.readdirSync(t).includes("style.css"))return!1;const n=r.readFileSync(a.join(t,"style.css"),"utf8");return!!/^(?:[ \t]*<\?php)?[ \t/*#@]*Theme Name:(.*)$/im.exec(n)}function P(t){const e=r.readdirSync(t),n=/^(?:[ \t]*<\?php)?[ \t/*#@]*Plugin Name:(.*)$/im;return!!e.filter(s=>s.endsWith(".php")).find(s=>{const i=r.readFileSync(a.join(t,s),"utf8");return!!n.exec(i)})}exports.expandAutoMounts=m;exports.mountResources=d;exports.parseMountDirArguments=h;exports.parseMountWithDelimiterArguments=l;
16
+ //# sourceMappingURL=mounts-R4uHe-O-.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"mounts-BJFrPHGW.cjs","sources":["../../../../packages/playground/cli/src/mounts.ts"],"sourcesContent":["import { createNodeFsMountHandler } from '@php-wasm/node';\nimport type { PHP } from '@php-wasm/universal';\nimport fs, { existsSync } from 'fs';\nimport path, { basename, join } from 'path';\nimport type { RunCLIArgs } from './run-cli';\n\nexport interface Mount {\n\thostPath: string;\n\tvfsPath: string;\n}\n\n/**\n * Parse an array of mount argument strings where the host path and VFS path\n * are separated by a colon.\n *\n * Example:\n * parseMountWithDelimiterArguments( [ '/host/path:/vfs/path', '/host/path:/vfs/path' ] )\n * // returns:\n * [\n * { hostPath: '/host/path', vfsPath: '/vfs/path' },\n * { hostPath: '/host/path', vfsPath: '/vfs/path' }\n * ]\n *\n * @param mounts - An array of mount argument strings separated by a colon.\n * @returns An array of Mount objects.\n */\nexport function parseMountWithDelimiterArguments(mounts: string[]): Mount[] {\n\tconst parsedMounts = [];\n\tfor (const mount of mounts) {\n\t\tconst mountParts = mount.split(':');\n\t\tif (mountParts.length !== 2) {\n\t\t\tthrow new Error(`Invalid mount format: ${mount}.\n\t\t\t\tExpected format: /host/path:/vfs/path.\n\t\t\t\tIf your path contains a colon, e.g. C:\\\\myplugin, use the --mount-dir option instead.\n\t\t\t\tExample: --mount-dir C:\\\\my-plugin /wordpress/wp-content/plugins/my-plugin`);\n\t\t}\n\t\tconst [hostPath, vfsPath] = mountParts;\n\t\tif (!existsSync(hostPath)) {\n\t\t\tthrow new Error(`Host path does not exist: ${hostPath}`);\n\t\t}\n\t\tparsedMounts.push({ hostPath, vfsPath });\n\t}\n\treturn parsedMounts;\n}\n\n/**\n * Parse an array of mount argument strings where each odd array element is a host path\n * and each even element is the VFS path.\n * e.g. [ '/host/path', '/vfs/path', '/host/path2', '/vfs/path2' ]\n *\n * The result will be an array of Mount objects for each host path the\n * following element is it's VFS path.\n * e.g. [\n * { hostPath: '/host/path', vfsPath: '/vfs/path' },\n * { hostPath: '/host/path2', vfsPath: '/vfs/path2' }\n * ]\n *\n * @param mounts - An array of paths\n * @returns An array of Mount objects.\n */\nexport function parseMountDirArguments(mounts: string[]): Mount[] {\n\tif (mounts.length % 2 !== 0) {\n\t\tthrow new Error('Invalid mount format. Expected: /host/path /vfs/path');\n\t}\n\n\tconst parsedMounts = [];\n\tfor (let i = 0; i < mounts.length; i += 2) {\n\t\tconst source = mounts[i];\n\t\tconst vfsPath = mounts[i + 1];\n\t\tif (!existsSync(source)) {\n\t\t\tthrow new Error(`Host path does not exist: ${source}`);\n\t\t}\n\t\tparsedMounts.push({\n\t\t\thostPath: path.resolve(process.cwd(), source),\n\t\t\tvfsPath,\n\t\t});\n\t}\n\treturn parsedMounts;\n}\n\nexport async function mountResources(php: PHP, mounts: Mount[]) {\n\tfor (const mount of mounts) {\n\t\tawait php.mount(\n\t\t\tmount.vfsPath,\n\t\t\tcreateNodeFsMountHandler(mount.hostPath)\n\t\t);\n\t}\n}\n\nconst ACTIVATE_FIRST_THEME_STEP = {\n\tstep: 'runPHP',\n\tcode: {\n\t\tfilename: 'activate-theme.php',\n\t\t// @TODO: Remove DOCROOT check after moving totally to Blueprints v2.\n\t\tcontent: `<?php\n\t\t\t$docroot = getenv('DOCROOT') ? getenv('DOCROOT') : '/wordpress';\n\t\t\trequire_once \"$docroot/wp-load.php\";\n\t\t\t$theme = wp_get_theme();\n\t\t\tif (!$theme->exists()) {\n\t\t\t\t$themes = wp_get_themes();\n\t\t\t\tif (count($themes) > 0) {\n\t\t\t\t\t$themeName = array_keys($themes)[0];\n\t\t\t\t\tswitch_theme($themeName);\n\t\t\t\t}\n\t\t\t}\n\t\t`,\n\t},\n};\n\n/**\n * Auto-mounts resolution logic:\n */\nexport function expandAutoMounts(args: RunCLIArgs): RunCLIArgs {\n\tconst path = args.autoMount!;\n\n\tconst mount = [...(args.mount || [])];\n\tconst mountBeforeInstall = [...(args['mount-before-install'] || [])];\n\n\tconst newArgs = {\n\t\t...args,\n\t\tmount,\n\t\t'mount-before-install': mountBeforeInstall,\n\t\t'additional-blueprint-steps': [\n\t\t\t...((args as any)['additional-blueprint-steps'] || []),\n\t\t],\n\t};\n\n\tif (isPluginFilename(path)) {\n\t\tconst pluginName = basename(path);\n\t\tmount.push({\n\t\t\thostPath: path,\n\t\t\tvfsPath: `/wordpress/wp-content/plugins/${pluginName}`,\n\t\t});\n\t\tnewArgs['additional-blueprint-steps'].push({\n\t\t\tstep: 'activatePlugin',\n\t\t\tpluginPath: `/wordpress/wp-content/plugins/${basename(path)}`,\n\t\t});\n\t} else if (isThemeDirectory(path)) {\n\t\tconst themeName = basename(path);\n\t\tmount.push({\n\t\t\thostPath: path,\n\t\t\tvfsPath: `/wordpress/wp-content/themes/${themeName}`,\n\t\t});\n\t\tnewArgs['additional-blueprint-steps'].push(\n\t\t\targs['experimental-blueprints-v2-runner']\n\t\t\t\t? {\n\t\t\t\t\t\tstep: 'activateTheme',\n\t\t\t\t\t\tthemeDirectoryName: themeName,\n\t\t\t\t }\n\t\t\t\t: {\n\t\t\t\t\t\tstep: 'activateTheme',\n\t\t\t\t\t\tthemeFolderName: themeName,\n\t\t\t\t }\n\t\t);\n\t} else if (containsWpContentDirectories(path)) {\n\t\t/**\n\t\t * Mount each wp-content file and directory individually.\n\t\t */\n\t\tconst files = fs.readdirSync(path);\n\t\tfor (const file of files) {\n\t\t\t/**\n\t\t\t * WordPress already ships with the wp-content/index.php file\n\t\t\t * and Playground does not support overriding existing VFS files\n\t\t\t * with mounts.\n\t\t\t */\n\t\t\tif (file === 'index.php') {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tmount.push({\n\t\t\t\thostPath: `${path}/${file}`,\n\t\t\t\tvfsPath: `/wordpress/wp-content/${file}`,\n\t\t\t});\n\t\t}\n\t\tnewArgs['additional-blueprint-steps'].push(ACTIVATE_FIRST_THEME_STEP);\n\t} else if (containsFullWordPressInstallation(path)) {\n\t\tmountBeforeInstall.push({ hostPath: path, vfsPath: '/wordpress' });\n\t\t// @TODO: If overriding another mode, throw an error or print a warning.\n\t\tnewArgs.mode = 'apply-to-existing-site';\n\t\tnewArgs['additional-blueprint-steps'].push(ACTIVATE_FIRST_THEME_STEP);\n\t} else {\n\t\t/**\n\t\t * By default, mount the current working directory as the Playground root.\n\t\t * This allows users to run and PHP or HTML files using the Playground CLI.\n\t\t */\n\t\tmount.push({ hostPath: path, vfsPath: '/wordpress' });\n\t\t// @TODO: If overriding another mode, throw an error or print a warning.\n\t\tnewArgs.mode = 'mount-only';\n\t}\n\n\treturn newArgs as RunCLIArgs;\n}\n\nexport function containsFullWordPressInstallation(path: string): boolean {\n\tconst files = fs.readdirSync(path);\n\treturn (\n\t\tfiles.includes('wp-admin') &&\n\t\tfiles.includes('wp-includes') &&\n\t\tfiles.includes('wp-content')\n\t);\n}\n\nexport function containsWpContentDirectories(path: string): boolean {\n\tconst files = fs.readdirSync(path);\n\treturn (\n\t\tfiles.includes('themes') ||\n\t\tfiles.includes('plugins') ||\n\t\tfiles.includes('mu-plugins') ||\n\t\tfiles.includes('uploads')\n\t);\n}\n\nexport function isThemeDirectory(path: string): boolean {\n\tconst files = fs.readdirSync(path);\n\tif (!files.includes('style.css')) {\n\t\treturn false;\n\t}\n\tconst styleCssContent = fs.readFileSync(join(path, 'style.css'), 'utf8');\n\tconst themeNameRegex = /^(?:[ \\t]*<\\?php)?[ \\t/*#@]*Theme Name:(.*)$/im;\n\treturn !!themeNameRegex.exec(styleCssContent);\n}\n\nexport function isPluginFilename(path: string): boolean {\n\tconst files = fs.readdirSync(path);\n\tconst pluginNameRegex = /^(?:[ \\t]*<\\?php)?[ \\t/*#@]*Plugin Name:(.*)$/im;\n\tconst pluginNameMatch = files\n\t\t.filter((file) => file.endsWith('.php'))\n\t\t.find((file) => {\n\t\t\tconst fileContent = fs.readFileSync(join(path, file), 'utf8');\n\t\t\treturn !!pluginNameRegex.exec(fileContent);\n\t\t});\n\treturn !!pluginNameMatch;\n}\n"],"names":["parseMountWithDelimiterArguments","mounts","parsedMounts","mount","mountParts","hostPath","vfsPath","existsSync","parseMountDirArguments","i","source","path","mountResources","php","createNodeFsMountHandler","ACTIVATE_FIRST_THEME_STEP","expandAutoMounts","args","mountBeforeInstall","newArgs","isPluginFilename","pluginName","basename","isThemeDirectory","themeName","containsWpContentDirectories","files","fs","file","containsFullWordPressInstallation","styleCssContent","join","pluginNameRegex","fileContent"],"mappings":"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"}
1
+ {"version":3,"file":"mounts-R4uHe-O-.cjs","sources":["../../../../packages/playground/cli/src/mounts.ts"],"sourcesContent":["import { createNodeFsMountHandler } from '@php-wasm/node';\nimport type { PHP } from '@php-wasm/universal';\nimport fs, { existsSync } from 'fs';\nimport path, { basename, join } from 'path';\nimport type { RunCLIArgs } from './run-cli';\n\nexport interface Mount {\n\thostPath: string;\n\tvfsPath: string;\n}\n\n/**\n * Parse an array of mount argument strings where the host path and VFS path\n * are separated by a colon.\n *\n * Example:\n * parseMountWithDelimiterArguments( [ '/host/path:/vfs/path', '/host/path:/vfs/path' ] )\n * // returns:\n * [\n * { hostPath: '/host/path', vfsPath: '/vfs/path' },\n * { hostPath: '/host/path', vfsPath: '/vfs/path' }\n * ]\n *\n * @param mounts - An array of mount argument strings separated by a colon.\n * @returns An array of Mount objects.\n */\nexport function parseMountWithDelimiterArguments(mounts: string[]): Mount[] {\n\tconst parsedMounts = [];\n\tfor (const mount of mounts) {\n\t\tconst mountParts = mount.split(':');\n\t\tif (mountParts.length !== 2) {\n\t\t\tthrow new Error(`Invalid mount format: ${mount}.\n\t\t\t\tExpected format: /host/path:/vfs/path.\n\t\t\t\tIf your path contains a colon, e.g. C:\\\\myplugin, use the --mount-dir option instead.\n\t\t\t\tExample: --mount-dir C:\\\\my-plugin /wordpress/wp-content/plugins/my-plugin`);\n\t\t}\n\t\tconst [hostPath, vfsPath] = mountParts;\n\t\tif (!existsSync(hostPath)) {\n\t\t\tthrow new Error(`Host path does not exist: ${hostPath}`);\n\t\t}\n\t\tparsedMounts.push({ hostPath, vfsPath });\n\t}\n\treturn parsedMounts;\n}\n\n/**\n * Parse an array of mount argument strings where each odd array element is a host path\n * and each even element is the VFS path.\n * e.g. [ '/host/path', '/vfs/path', '/host/path2', '/vfs/path2' ]\n *\n * The result will be an array of Mount objects for each host path the\n * following element is it's VFS path.\n * e.g. [\n * { hostPath: '/host/path', vfsPath: '/vfs/path' },\n * { hostPath: '/host/path2', vfsPath: '/vfs/path2' }\n * ]\n *\n * @param mounts - An array of paths\n * @returns An array of Mount objects.\n */\nexport function parseMountDirArguments(mounts: string[]): Mount[] {\n\tif (mounts.length % 2 !== 0) {\n\t\tthrow new Error('Invalid mount format. Expected: /host/path /vfs/path');\n\t}\n\n\tconst parsedMounts = [];\n\tfor (let i = 0; i < mounts.length; i += 2) {\n\t\tconst source = mounts[i];\n\t\tconst vfsPath = mounts[i + 1];\n\t\tif (!existsSync(source)) {\n\t\t\tthrow new Error(`Host path does not exist: ${source}`);\n\t\t}\n\t\tparsedMounts.push({\n\t\t\thostPath: path.resolve(process.cwd(), source),\n\t\t\tvfsPath,\n\t\t});\n\t}\n\treturn parsedMounts;\n}\n\nexport async function mountResources(php: PHP, mounts: Mount[]) {\n\tfor (const mount of mounts) {\n\t\tawait php.mount(\n\t\t\tmount.vfsPath,\n\t\t\tcreateNodeFsMountHandler(mount.hostPath)\n\t\t);\n\t}\n}\n\nconst ACTIVATE_FIRST_THEME_STEP = {\n\tstep: 'runPHP',\n\tcode: {\n\t\tfilename: 'activate-theme.php',\n\t\t// @TODO: Remove DOCROOT check after moving totally to Blueprints v2.\n\t\tcontent: `<?php\n\t\t\t$docroot = getenv('DOCROOT') ? getenv('DOCROOT') : '/wordpress';\n\t\t\trequire_once \"$docroot/wp-load.php\";\n\t\t\t$theme = wp_get_theme();\n\t\t\tif (!$theme->exists()) {\n\t\t\t\t$themes = wp_get_themes();\n\t\t\t\tif (count($themes) > 0) {\n\t\t\t\t\t$themeName = array_keys($themes)[0];\n\t\t\t\t\tswitch_theme($themeName);\n\t\t\t\t}\n\t\t\t}\n\t\t`,\n\t},\n};\n\n/**\n * Auto-mounts resolution logic:\n */\nexport function expandAutoMounts(args: RunCLIArgs): RunCLIArgs {\n\tconst path = args.autoMount!;\n\n\tconst mount = [...(args.mount || [])];\n\tconst mountBeforeInstall = [...(args['mount-before-install'] || [])];\n\n\tconst newArgs = {\n\t\t...args,\n\t\tmount,\n\t\t'mount-before-install': mountBeforeInstall,\n\t\t'additional-blueprint-steps': [\n\t\t\t...((args as any)['additional-blueprint-steps'] || []),\n\t\t],\n\t};\n\n\tif (isPluginFilename(path)) {\n\t\tconst pluginName = basename(path);\n\t\tmount.push({\n\t\t\thostPath: path,\n\t\t\tvfsPath: `/wordpress/wp-content/plugins/${pluginName}`,\n\t\t});\n\t\tnewArgs['additional-blueprint-steps'].push({\n\t\t\tstep: 'activatePlugin',\n\t\t\tpluginPath: `/wordpress/wp-content/plugins/${basename(path)}`,\n\t\t});\n\t} else if (isThemeDirectory(path)) {\n\t\tconst themeName = basename(path);\n\t\tmount.push({\n\t\t\thostPath: path,\n\t\t\tvfsPath: `/wordpress/wp-content/themes/${themeName}`,\n\t\t});\n\t\tnewArgs['additional-blueprint-steps'].push(\n\t\t\targs['experimental-blueprints-v2-runner']\n\t\t\t\t? {\n\t\t\t\t\t\tstep: 'activateTheme',\n\t\t\t\t\t\tthemeDirectoryName: themeName,\n\t\t\t\t }\n\t\t\t\t: {\n\t\t\t\t\t\tstep: 'activateTheme',\n\t\t\t\t\t\tthemeFolderName: themeName,\n\t\t\t\t }\n\t\t);\n\t} else if (containsWpContentDirectories(path)) {\n\t\t/**\n\t\t * Mount each wp-content file and directory individually.\n\t\t */\n\t\tconst files = fs.readdirSync(path);\n\t\tfor (const file of files) {\n\t\t\t/**\n\t\t\t * WordPress already ships with the wp-content/index.php file\n\t\t\t * and Playground does not support overriding existing VFS files\n\t\t\t * with mounts.\n\t\t\t */\n\t\t\tif (file === 'index.php') {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tmount.push({\n\t\t\t\thostPath: `${path}/${file}`,\n\t\t\t\tvfsPath: `/wordpress/wp-content/${file}`,\n\t\t\t});\n\t\t}\n\t\tnewArgs['additional-blueprint-steps'].push(ACTIVATE_FIRST_THEME_STEP);\n\t} else if (containsFullWordPressInstallation(path)) {\n\t\tmountBeforeInstall.push({ hostPath: path, vfsPath: '/wordpress' });\n\t\t// @TODO: If overriding another mode, throw an error or print a warning.\n\t\tnewArgs.mode = 'apply-to-existing-site';\n\t\tnewArgs['additional-blueprint-steps'].push(ACTIVATE_FIRST_THEME_STEP);\n\t\tif (!newArgs.wordpressInstallMode) {\n\t\t\tnewArgs.wordpressInstallMode =\n\t\t\t\t'install-from-existing-files-if-needed';\n\t\t}\n\t} else {\n\t\t/**\n\t\t * By default, mount the current working directory as the Playground root.\n\t\t * This allows users to run and PHP or HTML files using the Playground CLI.\n\t\t */\n\t\tmount.push({ hostPath: path, vfsPath: '/wordpress' });\n\t\t// @TODO: If overriding another mode, throw an error or print a warning.\n\t\tnewArgs.mode = 'mount-only';\n\t}\n\n\treturn newArgs as RunCLIArgs;\n}\n\nexport function containsFullWordPressInstallation(path: string): boolean {\n\tconst files = fs.readdirSync(path);\n\treturn (\n\t\tfiles.includes('wp-admin') &&\n\t\tfiles.includes('wp-includes') &&\n\t\tfiles.includes('wp-content')\n\t);\n}\n\nexport function containsWpContentDirectories(path: string): boolean {\n\tconst files = fs.readdirSync(path);\n\treturn (\n\t\tfiles.includes('themes') ||\n\t\tfiles.includes('plugins') ||\n\t\tfiles.includes('mu-plugins') ||\n\t\tfiles.includes('uploads')\n\t);\n}\n\nexport function isThemeDirectory(path: string): boolean {\n\tconst files = fs.readdirSync(path);\n\tif (!files.includes('style.css')) {\n\t\treturn false;\n\t}\n\tconst styleCssContent = fs.readFileSync(join(path, 'style.css'), 'utf8');\n\tconst themeNameRegex = /^(?:[ \\t]*<\\?php)?[ \\t/*#@]*Theme Name:(.*)$/im;\n\treturn !!themeNameRegex.exec(styleCssContent);\n}\n\nexport function isPluginFilename(path: string): boolean {\n\tconst files = fs.readdirSync(path);\n\tconst pluginNameRegex = /^(?:[ \\t]*<\\?php)?[ \\t/*#@]*Plugin Name:(.*)$/im;\n\tconst pluginNameMatch = files\n\t\t.filter((file) => file.endsWith('.php'))\n\t\t.find((file) => {\n\t\t\tconst fileContent = fs.readFileSync(join(path, file), 'utf8');\n\t\t\treturn !!pluginNameRegex.exec(fileContent);\n\t\t});\n\treturn !!pluginNameMatch;\n}\n"],"names":["parseMountWithDelimiterArguments","mounts","parsedMounts","mount","mountParts","hostPath","vfsPath","existsSync","parseMountDirArguments","i","source","path","mountResources","php","createNodeFsMountHandler","ACTIVATE_FIRST_THEME_STEP","expandAutoMounts","args","mountBeforeInstall","newArgs","isPluginFilename","pluginName","basename","isThemeDirectory","themeName","containsWpContentDirectories","files","fs","file","containsFullWordPressInstallation","styleCssContent","join","pluginNameRegex","fileContent"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wp-playground/cli",
3
- "version": "3.0.19",
3
+ "version": "3.0.21",
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": "5d6cbf03fb33b4c58c587c43a4a7793d4b050885",
37
+ "gitHead": "8d3a2da8f91ca792ba8f6fe7e92fdb658f4075ee",
38
38
  "dependencies": {
39
39
  "@zip.js/zip.js": "2.7.57",
40
40
  "ajv": "8.12.0",
@@ -61,16 +61,16 @@
61
61
  "ws": "8.18.3",
62
62
  "xml2js": "0.6.2",
63
63
  "yargs": "17.7.2",
64
- "@php-wasm/logger": "3.0.19",
65
- "@php-wasm/progress": "3.0.19",
66
- "@php-wasm/universal": "3.0.19",
67
- "@wp-playground/blueprints": "3.0.19",
68
- "@wp-playground/common": "3.0.19",
69
- "@wp-playground/wordpress": "3.0.19",
70
- "@php-wasm/node": "3.0.19",
71
- "@php-wasm/util": "3.0.19",
72
- "@wp-playground/storage": "3.0.19",
73
- "@php-wasm/xdebug-bridge": "3.0.19"
64
+ "@php-wasm/logger": "3.0.21",
65
+ "@php-wasm/progress": "3.0.21",
66
+ "@php-wasm/universal": "3.0.21",
67
+ "@wp-playground/blueprints": "3.0.21",
68
+ "@wp-playground/common": "3.0.21",
69
+ "@wp-playground/wordpress": "3.0.21",
70
+ "@php-wasm/node": "3.0.21",
71
+ "@php-wasm/util": "3.0.21",
72
+ "@wp-playground/storage": "3.0.21",
73
+ "@php-wasm/xdebug-bridge": "3.0.21"
74
74
  },
75
75
  "packageManager": "npm@10.9.2",
76
76
  "overrides": {
@@ -0,0 +1,46 @@
1
+ "use strict";var he=Object.create;var K=Object.defineProperty;var me=Object.getOwnPropertyDescriptor;var ge=Object.getOwnPropertyNames;var we=Object.getPrototypeOf,ye=Object.prototype.hasOwnProperty;var be=(e,o,t,i)=>{if(o&&typeof o=="object"||typeof o=="function")for(let s of ge(o))!ye.call(e,s)&&s!==t&&K(e,s,{get:()=>o[s],enumerable:!(i=me(o,s))||i.enumerable});return e};var ve=(e,o,t)=>(t=e!=null?he(we(e)):{},be(o||!e||!e.__esModule?K(t,"default",{value:e,enumerable:!0}):t,e));const m=require("@php-wasm/logger"),k=require("@php-wasm/universal"),M=require("@wp-playground/blueprints"),z=require("@wp-playground/common"),u=require("fs"),J=require("worker_threads"),D=require("./mounts-R4uHe-O-.cjs"),Pe=require("express"),Se=require("@php-wasm/node"),Y=require("os"),xe=require("wasm-feature-detect"),ke=require("yargs"),h=require("path"),A=require("@wp-playground/storage"),Q=require("@php-wasm/progress"),Ie=require("@wp-playground/wordpress"),j=require("fs-extra"),Ee=require("@php-wasm/xdebug-bridge"),ee=require("tmp-promise"),Ce=require("ps-man"),U=require("fast-xml-parser"),v=require("jsonc-parser");var $=typeof document<"u"?document.currentScript:null;async function Le(e){const o=Pe(),t=await new Promise((n,r)=>{const a=o.listen(e.port,()=>{const l=a.address();l===null||typeof l=="string"?r(new Error("Server address is not available")):n(a)})});o.use("/",async(n,r)=>{let a;try{a=await e.handleRequest({url:n.url,headers:Te(n),method:n.method,body:await Re(n)})}catch(l){m.logger.error(l),a=k.PHPResponse.forHttpCode(500)}r.statusCode=a.httpStatusCode;for(const l in a.headers)r.setHeader(l,a.headers[l]);r.end(a.bytes)});const s=t.address().port;return await e.onBind(t,s)}const Re=async e=>await new Promise(o=>{const t=[];e.on("data",i=>{t.push(i)}),e.on("end",()=>{o(new Uint8Array(Buffer.concat(t)))})}),Te=e=>{const o={};if(e.rawHeaders&&e.rawHeaders.length)for(let t=0;t<e.rawHeaders.length;t+=2)o[e.rawHeaders[t].toLowerCase()]=e.rawHeaders[t+1];return o};class $e{constructor(o){this.workerLoads=[],this.addWorker(o)}addWorker(o){this.workerLoads.push({worker:o,activeRequests:new Set})}async removeWorker(o){const t=this.workerLoads.findIndex(s=>s.worker===o);if(t===-1)return;const[i]=this.workerLoads.splice(t,1);await Promise.allSettled(i.activeRequests)}async handleRequest(o){let t=this.workerLoads[0];for(let s=1;s<this.workerLoads.length;s++){const n=this.workerLoads[s];n.activeRequests.size<t.activeRequests.size&&(t=n)}const i=t.worker.request(o);return t.activeRequests.add(i),i.url=o.url,i.finally(()=>{t.activeRequests.delete(i)})}}function Me(e){return/^latest$|^trunk$|^nightly$|^(?:(\d+)\.(\d+)(?:\.(\d+))?)((?:-beta(?:\d+)?)|(?:-RC(?:\d+)?))?$/.test(e)}async function je({sourceString:e,blueprintMayReadAdjacentFiles:o}){if(!e)return;if(e.startsWith("http://")||e.startsWith("https://"))return await M.resolveRemoteBlueprint(e);let t=h.resolve(process.cwd(),e);if(!u.existsSync(t))throw new Error(`Blueprint file does not exist: ${t}`);const i=u.statSync(t);if(i.isDirectory()&&(t=h.join(t,"blueprint.json")),!i.isFile()&&i.isSymbolicLink())throw new Error(`Blueprint path is neither a file nor a directory: ${t}`);const s=h.extname(t);switch(s){case".zip":return A.ZipFilesystem.fromArrayBuffer(u.readFileSync(t).buffer);case".json":{const n=u.readFileSync(t,"utf-8");try{JSON.parse(n)}catch{throw new Error(`Blueprint file at ${t} is not a valid JSON file`)}const r=h.dirname(t),a=new A.NodeJsFilesystem(r);return new A.OverlayFilesystem([new A.InMemoryFilesystem({"blueprint.json":n}),{read(l){if(!o)throw new Error(`Error: Blueprint contained tried to read a local file at path "${l}" (via a resource of type "bundled"). Playground restricts access to local resources by default as a security measure.
2
+
3
+ You can allow this Blueprint to read files from the same parent directory by explicitly adding the --blueprint-may-read-adjacent-files option to your command.`);return a.read(l)}}])}default:throw new Error(`Unsupported blueprint file extension: ${s}. Only .zip and .json files are supported.`)}}class Be{constructor(o,t){this.lastProgressMessage="",this.args=o,this.siteUrl=t.siteUrl,this.processIdSpaceLength=t.processIdSpaceLength,this.phpVersion=o.php}getWorkerType(){return"v2"}async bootAndSetUpInitialPlayground(o,t,i){const s=k.consumeAPI(o);await s.useFileLockManager(t);const n={...this.args,phpVersion:this.phpVersion,siteUrl:this.siteUrl,firstProcessId:1,processIdSpaceLength:this.processIdSpaceLength,trace:this.args.debug||!1,blueprint:this.args.blueprint,withXdebug:!1,xdebug:void 0,nativeInternalDirPath:i};return await s.bootAndSetUpInitialWorker(n),s}async bootPlayground({worker:o,fileLockManagerPort:t,firstProcessId:i,nativeInternalDirPath:s}){const n=k.consumeAPI(o.phpPort);await n.useFileLockManager(t);const r={...this.args,phpVersion:this.phpVersion,siteUrl:this.siteUrl,firstProcessId:i,processIdSpaceLength:this.processIdSpaceLength,trace:this.args.debug||!1,withXdebug:!!this.args.xdebug,nativeInternalDirPath:s,mountsBeforeWpInstall:this.args["mount-before-install"]||[],mountsAfterWpInstall:this.args.mount||[]};return await n.bootWorker(r),n}writeProgressUpdate(o,t,i){t!==this.lastProgressMessage&&(this.lastProgressMessage=t,o.isTTY?(o.cursorTo(0),o.write(t),o.clearLine(1),i&&o.write(`
4
+ `)):o.write(`${t}
5
+ `))}}const Z=h.join(Y.homedir(),".wordpress-playground");async function Fe(e){return await re("https://github.com/WordPress/sqlite-database-integration/archive/refs/heads/develop.zip","sqlite.zip",e)}async function re(e,o,t){const i=h.join(Z,o);return j.existsSync(i)||(j.ensureDirSync(Z),await We(e,i,t)),ne(i)}async function We(e,o,t){const s=(await t.monitorFetch(fetch(e))).body.getReader(),n=`${o}.partial`,r=j.createWriteStream(n);for(;;){const{done:a,value:l}=await s.read();if(l&&r.write(l),a)break}r.close(),r.closed||await new Promise((a,l)=>{r.on("finish",()=>{j.renameSync(n,o),a(null)}),r.on("error",d=>{j.removeSync(n),l(d)})})}function ne(e,o){return new File([j.readFileSync(e)],h.basename(e))}class De{constructor(o,t){this.lastProgressMessage="",this.args=o,this.siteUrl=t.siteUrl,this.processIdSpaceLength=t.processIdSpaceLength}getWorkerType(){return"v1"}async bootAndSetUpInitialPlayground(o,t,i){let s,n,r;const a=new Q.EmscriptenDownloadMonitor;if(this.args.wordpressInstallMode==="download-and-install"){let I=!1;a.addEventListener("progress",B=>{if(I)return;const{loaded:x,total:f}=B.detail,F=Math.floor(Math.min(100,100*x/f));I=F===100,this.writeProgressUpdate(process.stdout,`Downloading WordPress ${F}%...`,I)}),s=await Ie.resolveWordPressRelease(this.args.wp),r=h.join(Z,`prebuilt-wp-content-for-wp-${s.version}.zip`),n=u.existsSync(r)?ne(r):await re(s.releaseUrl,`${s.version}.zip`,a),m.logger.log(`Resolved WordPress release URL: ${s?.releaseUrl}`)}m.logger.log("Fetching SQLite integration plugin...");const l=this.args.skipSqliteSetup?void 0:await Fe(a),d=this.args.followSymlinks===!0,c=this.args.experimentalTrace===!0,p=this.args["mount-before-install"]||[],g=this.args.mount||[],b=k.consumeAPI(o);await b.isConnected(),m.logger.log("Booting WordPress...");const S=await M.resolveRuntimeConfiguration(this.getEffectiveBlueprint());return await b.useFileLockManager(t),await b.bootAndSetUpInitialWorker({phpVersion:S.phpVersion,wpVersion:S.wpVersion,siteUrl:this.siteUrl,mountsBeforeWpInstall:p,mountsAfterWpInstall:g,wordpressInstallMode:this.args.wordpressInstallMode||"download-and-install",wordPressZip:n&&await n.arrayBuffer(),sqliteIntegrationPluginZip:await l?.arrayBuffer(),firstProcessId:0,processIdSpaceLength:this.processIdSpaceLength,followSymlinks:d,trace:c,internalCookieStore:this.args.internalCookieStore,withXdebug:!1,nativeInternalDirPath:i}),r&&!this.args["mount-before-install"]&&!u.existsSync(r)&&(m.logger.log("Caching preinstalled WordPress for the next boot..."),u.writeFileSync(r,await z.zipDirectory(b,"/wordpress")),m.logger.log("Cached!")),b}async bootPlayground({worker:o,fileLockManagerPort:t,firstProcessId:i,nativeInternalDirPath:s}){const n=k.consumeAPI(o.phpPort);await n.isConnected();const r=await M.resolveRuntimeConfiguration(this.getEffectiveBlueprint());return await n.useFileLockManager(t),await n.bootWorker({phpVersion:r.phpVersion,siteUrl:this.siteUrl,mountsBeforeWpInstall:this.args["mount-before-install"]||[],mountsAfterWpInstall:this.args.mount||[],firstProcessId:i,processIdSpaceLength:this.processIdSpaceLength,followSymlinks:this.args.followSymlinks===!0,trace:this.args.experimentalTrace===!0,internalCookieStore:this.args.internalCookieStore,withXdebug:!!this.args.xdebug,nativeInternalDirPath:s}),await n.isReady(),n}async compileInputBlueprint(o){const t=this.getEffectiveBlueprint(),i=new Q.ProgressTracker;let s="",n=!1;return i.addEventListener("progress",r=>{if(n)return;n=r.detail.progress===100;const a=Math.floor(r.detail.progress);s=r.detail.caption||s||"Running the Blueprint";const l=`${s.trim()} – ${a}%`;this.writeProgressUpdate(process.stdout,l,n)}),await M.compileBlueprintV1(t,{progress:i,additionalSteps:o})}getEffectiveBlueprint(){const o=this.args.blueprint;return M.isBlueprintBundle(o)?o:{login:this.args.login,...o||{},preferredVersions:{php:this.args.php??o?.preferredVersions?.php??z.RecommendedPHPVersion,wp:this.args.wp??o?.preferredVersions?.wp??"latest",...o?.preferredVersions||{}}}}writeProgressUpdate(o,t,i){this.args.verbosity!==N.Quiet.name&&t!==this.lastProgressMessage&&(this.lastProgressMessage=t,o.isTTY?(o.cursorTo(0),o.write(t),o.clearLine(1),i&&o.write(`
6
+ `)):o.write(`${t}
7
+ `))}}async function Ae(e,o=!0){const i=`${h.basename(process.argv0)}${e}${process.pid}-`,s=await ee.dir({prefix:i,unsafeCleanup:!0});return o&&ee.setGracefulCleanup(),s}async function Ue(e,o,t){const s=(await qe(e,o,t)).map(n=>new Promise(r=>{u.rm(n,{recursive:!0},a=>{a?m.logger.warn(`Failed to delete stale Playground temp dir: ${n}`,a):m.logger.info(`Deleted stale Playground temp dir: ${n}`),r()})}));await Promise.all(s)}async function qe(e,o,t){try{const i=u.readdirSync(t).map(n=>h.join(t,n)),s=[];for(const n of i)await Ne(e,o,n)&&s.push(n);return s}catch(i){return m.logger.warn(`Failed to find stale Playground temp dirs: ${i}`),[]}}async function Ne(e,o,t){if(!u.lstatSync(t).isDirectory())return!1;const s=h.basename(t);if(!s.includes(e))return!1;const n=s.match(new RegExp(`^(.+)${e}(\\d+)-`));if(!n)return!1;const r={executableName:n[1],pid:n[2]};if(await Ve(r.pid,r.executableName))return!1;const a=Date.now()-o;return u.statSync(t).mtime.getTime()<a}async function Ve(e,o){const[t]=await new Promise((i,s)=>{Ce.list({pid:e,name:o,clean:!0},(n,r)=>{n?s(n):i(r)})});return!!t&&t.pid===e&&t.command===o}async function _e(e,o,t){const i=t==="win32"?"junction":"dir";u.symlinkSync(e,o,i)}async function Oe(e){try{u.lstatSync(e).isSymbolicLink()&&u.unlinkSync(e)}catch{}}function He(e,o){return o.filter(t=>{const i=h.resolve(t.hostPath),s=h.join(e,h.sep);return i===e||i.startsWith(s)})}const C={ignoreAttributes:!1,attributeNamePrefix:"",preserveOrder:!0,cdataPropName:"__cdata",commentPropName:"__xmlComment",allowBooleanAttributes:!0,trimValues:!0},ie={ignoreAttributes:C.ignoreAttributes,attributeNamePrefix:C.attributeNamePrefix,preserveOrder:C.preserveOrder,cdataPropName:C.cdataPropName,commentPropName:C.commentPropName,suppressBooleanAttributes:!C.allowBooleanAttributes,format:!0,indentBy:" "},q={allowEmptyContent:!0,allowTrailingComma:!0};function Xe(e,o){const{name:t,host:i,port:s,mappings:n,ideKey:r}=o,a=new U.XMLParser(C),l=(()=>{try{return a.parse(e,!0)}catch{throw new Error("PhpStorm configuration file is not valid XML.")}})(),d={server:[{path_mappings:n.map(f=>({mapping:[],":@":{"local-root":`$PROJECT_DIR$/${ae(h.relative(o.projectDir,f.hostPath))}`,"remote-root":f.vfsPath}}))}],":@":{name:t,host:`${i}:${s}`,use_path_mappings:"true"}};let c=l?.find(f=>!!f?.project);if(c){const f=c[":@"]?.version;if(f===void 0)throw new Error('PhpStorm IDE integration only supports <project version="4"> in workspace.xml, but the <project> configuration has no version number.');if(f!=="4")throw new Error(`PhpStorm IDE integration only supports <project version="4"> in workspace.xml, but we found a <project> configuration with version "${f}".`)}c===void 0&&(c={project:[],":@":{version:"4"}},l.push(c));let p=c.project?.find(f=>!!f?.component&&f?.[":@"]?.name==="PhpServers");p===void 0&&(p={component:[],":@":{name:"PhpServers"}},c.project===void 0&&(c.project=[]),c.project.push(p));let g=p.component?.find(f=>!!f?.servers);g===void 0&&(g={servers:[]},p.component===void 0&&(p.component=[]),p.component.push(g));const b=g.servers?.findIndex(f=>!!f?.server&&f?.[":@"]?.name===t);(b===void 0||b<0)&&(g.servers===void 0&&(g.servers=[]),g.servers.push(d));let S=c.project?.find(f=>!!f?.component&&f?.[":@"]?.name==="RunManager");if(S===void 0&&(S={component:[],":@":{name:"RunManager"}},c.project===void 0&&(c.project=[]),c.project.push(S)),(S.component?.findIndex(f=>!!f?.configuration&&f?.[":@"]?.name===t)??-1)<0){const f={configuration:[{method:[],":@":{v:"2"}}],":@":{name:t,type:"PhpRemoteDebugRunConfigurationType",factoryName:"PHP Remote Debug",filter_connections:"FILTER",server_name:t,session_id:r}};S.component===void 0&&(S.component=[]),S.component.push(f)}const x=new U.XMLBuilder(ie).build(l);try{a.parse(x,!0)}catch{throw new Error("The resulting PhpStorm configuration file is not valid XML.")}return x}function ze(e,o){const{name:t,mappings:i}=o,s=[];let n=e,r=v.parseTree(n,s,q);if(r===void 0||s.length)throw new Error("VS Code configuration file is not valid JSON.");let a=v.findNodeAtLocation(r,["configurations"]);if(a===void 0||a.children===void 0){const d=v.modify(n,["configurations"],[],{});n=v.applyEdits(n,d),r=v.parseTree(n,[],q),a=v.findNodeAtLocation(r,["configurations"])}const l=a?.children?.findIndex(d=>v.findNodeAtLocation(d,["name"])?.value===t);if(l===void 0||l<0){const d={name:t,type:"php",request:"launch",port:9003,pathMappings:i.reduce((g,b)=>(g[b.vfsPath]=`\${workspaceFolder}/${ae(h.relative(o.workspaceDir,b.hostPath))}`,g),{})},c=a?.children?.length||0,p=v.modify(n,["configurations",c],d,{formattingOptions:{insertSpaces:!0,tabSize:4,eol:`
8
+ `}});n=se(n,p)}return n}async function Je({name:e,ides:o,host:t,port:i,cwd:s,mounts:n,ideKey:r="PLAYGROUNDCLI"}){const a=He(s,n),l=[];if(o.includes("phpstorm")){const d=".idea/workspace.xml",c=h.join(s,d);if(!u.existsSync(c)){if(u.existsSync(h.dirname(c)))u.writeFileSync(c,`<?xml version="1.0" encoding="UTF-8"?>
9
+ <project version="4">
10
+ </project>`);else if(o.length==1)throw new Error("PhpStorm IDE integration requested, but no '.idea' directory was found in the current working directory.")}if(u.existsSync(c)){const p=u.readFileSync(c,"utf8"),g=Xe(p,{name:e,host:t,port:i,projectDir:s,mappings:a,ideKey:r});u.writeFileSync(c,g)}l.push(d)}if(o.includes("vscode")){const d=".vscode/launch.json",c=h.join(s,d);if(!u.existsSync(c)){if(u.existsSync(h.dirname(c)))u.writeFileSync(c,`{
11
+ "configurations": []
12
+ }`);else if(o.length==1)throw new Error("VS Code IDE integration requested, but no '.vscode' directory was found in the current working directory.")}if(u.existsSync(c)){const p=u.readFileSync(c,"utf-8"),g=ze(p,{name:e,workspaceDir:s,mappings:a});g!==p&&(u.writeFileSync(c,g),l.push(d))}}return l}async function Ze(e,o){const t=h.join(o,".idea/workspace.xml");if(u.existsSync(t)){const s=u.readFileSync(t,"utf8"),n=new U.XMLParser(C),r=(()=>{try{return n.parse(s,!0)}catch{throw new Error("PhpStorm configuration file is not valid XML.")}})(),d=r.find(p=>!!p?.project)?.project?.find(p=>!!p?.component&&p?.[":@"]?.name==="PhpServers")?.component?.find(p=>!!p?.servers),c=d?.servers?.findIndex(p=>!!p?.server&&p?.[":@"]?.name===e);if(c!==void 0&&c>=0){d.servers.splice(c,1);const g=new U.XMLBuilder(ie).build(r);try{n.parse(g,!0)}catch{throw new Error("The resulting PhpStorm configuration file is not valid XML.")}g===`<?xml version="1.0" encoding="UTF-8"?>
13
+ <project version="4">
14
+ <component name="PhpServers">
15
+ <servers></servers>
16
+ </component>
17
+ </project>`?u.unlinkSync(t):u.writeFileSync(t,g)}}const i=h.join(o,".vscode/launch.json");if(u.existsSync(i)){const s=[],n=u.readFileSync(i,"utf-8"),r=v.parseTree(n,s,q);if(r===void 0||s.length)throw new Error("VS Code configuration file is not valid JSON.");const l=v.findNodeAtLocation(r,["configurations"])?.children?.findIndex(d=>v.findNodeAtLocation(d,["name"])?.value===e);if(l!==void 0&&l>=0){const d=v.modify(n,["configurations",l],void 0,{formattingOptions:{insertSpaces:!0,tabSize:4,eol:`
18
+ `}}),c=se(n,d);c===`{
19
+ "configurations": []
20
+ }`?u.unlinkSync(i):u.writeFileSync(i,c)}}}function se(e,o){const t=[],i=v.applyEdits(e,o);if(t.length=0,v.parseTree(i,t,q),t.length){const s=t.map(r=>({message:v.printParseErrorCode(r.error),offset:r.offset,length:r.length,fragment:i.slice(Math.max(0,r.offset-20),Math.min(i.length,r.offset+r.length+10))})).map(r=>`${r.message} at ${r.offset}:${r.length} (${r.fragment})`),n=o.map(r=>`At ${r.offset}:${r.length} - (${r.content})`);throw new Error(`VS Code configuration file (.vscode/launch.json) is not valid a JSONC after Playground CLI modifications. This is likely a Playground CLI bug. Please report it at https://github.com/WordPress/wordpress-playground/issues and include the contents of your ".vscode/launch.json" file.
21
+
22
+ Applied edits: ${n.join(`
23
+ `)}
24
+
25
+ The errors are: ${s.join(`
26
+ `)}`)}return i}function ae(e){return e.replaceAll(h.sep,h.posix.sep)}const N={Quiet:{name:"quiet",severity:m.LogSeverity.Fatal},Normal:{name:"normal",severity:m.LogSeverity.Info},Debug:{name:"debug",severity:m.LogSeverity.Debug}};async function Ye(){try{const e=ke(process.argv.slice(2)).usage("Usage: wp-playground <command> [options]").positional("command",{describe:"Command to run",choices:["server","run-blueprint","build-snapshot"],demandOption:!0}).option("outfile",{describe:"When building, write to this output file.",type:"string",default:"wordpress.zip"}).option("port",{describe:"Port to listen on when serving.",type:"number",default:9400}).option("site-url",{describe:"Site URL to use for WordPress. Defaults to http://127.0.0.1:{port}",type:"string"}).option("php",{describe:"PHP version to use.",type:"string",default:z.RecommendedPHPVersion,choices:k.SupportedPHPVersions}).option("wp",{describe:"WordPress version to use.",type:"string",default:"latest"}).option("mount",{describe:"Mount a directory to the PHP runtime (can be used multiple times). Format: /host/path:/vfs/path",type:"array",string:!0,coerce:D.parseMountWithDelimiterArguments}).option("mount-before-install",{describe:"Mount a directory to the PHP runtime before WordPress installation (can be used multiple times). Format: /host/path:/vfs/path",type:"array",string:!0,coerce:D.parseMountWithDelimiterArguments}).option("mount-dir",{describe:'Mount a directory to the PHP runtime (can be used multiple times). Format: "/host/path" "/vfs/path"',type:"array",nargs:2,array:!0,coerce:D.parseMountDirArguments}).option("mount-dir-before-install",{describe:'Mount a directory before WordPress installation (can be used multiple times). Format: "/host/path" "/vfs/path"',type:"string",nargs:2,array:!0,coerce:D.parseMountDirArguments}).option("login",{describe:"Should log the user in",type:"boolean",default:!1}).option("blueprint",{describe:"Blueprint to execute.",type:"string"}).option("blueprint-may-read-adjacent-files",{describe:'Consent flag: Allow "bundled" resources in a local blueprint to read files in the same directory as the blueprint file.',type:"boolean",default:!1}).option("wordpress-install-mode",{describe:"Control how Playground prepares WordPress before booting.",type:"string",default:"download-and-install",choices:["download-and-install","install-from-existing-files","install-from-existing-files-if-needed","do-not-attempt-installing"]}).option("skip-wordpress-install",{describe:"[Deprecated] Use --wordpress-install-mode instead.",type:"boolean",hidden:!0}).option("skip-sqlite-setup",{describe:"Skip the SQLite integration plugin setup to allow the WordPress site to use MySQL.",type:"boolean",default:!1}).option("quiet",{describe:"Do not output logs and progress messages.",type:"boolean",default:!1,hidden:!0}).option("verbosity",{describe:"Output logs and progress messages.",type:"string",choices:Object.values(N).map(r=>r.name),default:"normal"}).option("debug",{describe:"Print PHP error log content if an error occurs during Playground boot.",type:"boolean",default:!1}).option("auto-mount",{describe:"Automatically mount the specified directory. If no path is provided, mount the current working directory. You can mount a WordPress directory, a plugin directory, a theme directory, a wp-content directory, or any directory containing PHP and HTML files.",type:"string"}).option("follow-symlinks",{describe:`Allow Playground to follow symlinks by automatically mounting symlinked directories and files encountered in mounted directories.
27
+ Warning: Following symlinks will expose files outside mounted directories to Playground and could be a security risk.`,type:"boolean",default:!1}).option("experimental-trace",{describe:"Print detailed messages about system behavior to the console. Useful for troubleshooting.",type:"boolean",default:!1,hidden:!0}).option("internal-cookie-store",{describe:"Enable internal cookie handling. When enabled, Playground will manage cookies internally using an HttpCookieStore that persists cookies across requests. When disabled, cookies are handled externally (e.g., by a browser in Node.js environments).",type:"boolean",default:!1}).option("xdebug",{describe:"Enable Xdebug.",type:"boolean",default:!1}).option("experimental-unsafe-ide-integration",{describe:"Enable experimental IDE development tools. This option edits IDE config files to set Xdebug path mappings and web server details. CAUTION: If there are bugs, this feature may break your IDE config files. Please consider backing up your IDE configs before using this feature.",type:"string",choices:["","vscode","phpstorm"],coerce:r=>r===""?["vscode","phpstorm"]:[r]}).option("experimental-devtools",{describe:"Enable experimental browser development tools.",type:"boolean"}).conflicts("experimental-unsafe-ide-integration","experimental-devtools").option("experimental-multi-worker",{describe:"Enable experimental multi-worker support which requires a /wordpress directory backed by a real filesystem. Pass a positive number to specify the number of workers to use. Otherwise, default to the number of CPUs minus 1.",type:"number",coerce:r=>r??Y.cpus().length-1}).option("experimental-blueprints-v2-runner",{describe:"Use the experimental Blueprint V2 runner.",type:"boolean",default:!1,hidden:!0}).option("mode",{describe:"Blueprints v2 runner mode to use. This option is required when using the --experimental-blueprints-v2-runner flag with a blueprint.",type:"string",choices:["create-new-site","apply-to-existing-site"],hidden:!0}).showHelpOnFail(!1).strictOptions().check(async r=>{if(r["skip-wordpress-install"]===!0&&(r["wordpress-install-mode"]="do-not-attempt-installing",r.wordpressInstallMode="do-not-attempt-installing"),r.wp!==void 0&&!Me(r.wp))try{new URL(r.wp)}catch{throw new Error('Unrecognized WordPress version. Please use "latest", a URL, or a numeric version such as "6.2", "6.0.1", "6.2-beta1", or "6.2-RC1"')}if(r["site-url"]!==void 0&&r["site-url"]!=="")try{new URL(r["site-url"])}catch{throw new Error(`Invalid site-url "${r["site-url"]}". Please provide a valid URL (e.g., http://localhost:8080 or https://example.com)`)}if(r["auto-mount"]){let a=!1;try{a=u.statSync(r["auto-mount"]).isDirectory()}catch{a=!1}if(!a)throw new Error(`The specified --auto-mount path is not a directory: '${r["auto-mount"]}'.`)}if(r["experimental-multi-worker"]!==void 0&&r["experimental-multi-worker"]<=1)throw new Error("The --experimental-multi-worker flag must be a positive integer greater than 1.");if(r["experimental-blueprints-v2-runner"]===!0){if(r.mode!==void 0){if(r["wordpress-install-mode"]!==void 0)throw new Error("The --wordpress-install-mode option cannot be used with the --mode option. Use one or the other.");if("skip-sqlite-setup"in r)throw new Error("The --skipSqliteSetup option is not supported in Blueprint V2 mode.");if(r["auto-mount"]!==void 0)throw new Error("The --mode option cannot be used with --auto-mount because --auto-mount automatically sets the mode.")}else r["wordpress-install-mode"]==="do-not-attempt-installing"?r.mode="apply-to-existing-site":r.mode="create-new-site";const a=r.allow||[];r.followSymlinks===!0&&a.push("follow-symlinks"),r["blueprint-may-read-adjacent-files"]===!0&&a.push("read-local-fs"),r.allow=a}else if(r.mode!==void 0)throw new Error("The --mode option requires the --experimentalBlueprintsV2Runner flag.");return!0});e.wrap(e.terminalWidth());const o=await e.argv,t=o._[0];["run-blueprint","server","build-snapshot"].includes(t)||(e.showHelp(),process.exit(1));const i={...o,command:t,mount:[...o.mount||[],...o["mount-dir"]||[]],"mount-before-install":[...o["mount-before-install"]||[],...o["mount-dir-before-install"]||[]]},s=await le(i);s===void 0&&process.exit(0);const n=(()=>{let r;return async()=>{r!==void 0&&(r=s[Symbol.asyncDispose]()),await r,process.exit(0)}})();process.on("SIGINT",n),process.on("SIGTERM",n)}catch(e){if(!(e instanceof Error))throw e;if(process.argv.includes("--debug"))k.printDebugDetails(e);else{const t=[];let i=e;do t.push(i.message),i=i.cause;while(i instanceof Error);console.error("\x1B[1m"+t.join(" caused by: ")+"\x1B[0m")}process.exit(1)}}const W=e=>process.stdout.isTTY?"\x1B[1m"+e+"\x1B[0m":e,Ge=e=>process.stdout.isTTY?`\x1B[2m${e}\x1B[0m`:e,X=e=>process.stdout.isTTY?`\x1B[3m${e}\x1B[0m`:e,te=e=>process.stdout.isTTY?`\x1B[33m${e}\x1B[0m`:e;async function le(e){let o,t;const i=[];if(e.autoMount!==void 0&&(e.autoMount===""&&(e={...e,autoMount:process.cwd()}),e=D.expandAutoMounts(e)),e.wordpressInstallMode===void 0&&(e.wordpressInstallMode="download-and-install"),e.quiet&&(e.verbosity="quiet",delete e.quiet),e.debug?e.verbosity="debug":e.verbosity==="debug"&&(e.debug=!0),e.verbosity){const l=Object.values(N).find(d=>d.name===e.verbosity).severity;m.logger.setSeverityFilterLevel(l)}const s=Y.platform()==="win32"?void 0:await import("fs-ext").then(l=>l.flockSync).catch(()=>{m.logger.warn("The fs-ext package is not installed. Internal file locking will not be integrated with host OS file locking.")}),n=new Se.FileLockManagerForNode(s);let r=!1,a=!0;return m.logger.log("Starting a PHP server..."),Le({port:e.port,onBind:async(l,d)=>{const c="127.0.0.1",p=`http://${c}:${d}`,g=e["site-url"]||p,b=e.experimentalMultiWorker??1,S=b+1,I=Math.floor(Number.MAX_SAFE_INTEGER/S),B="-playground-cli-site-",x=await Ae(B);m.logger.debug(`Native temp dir for VFS root: ${x.path}`);const f="WP Playground CLI - Listen for Xdebug",F=".playground-xdebug-root",G=h.join(process.cwd(),F);if(await Oe(G),e.xdebug&&e.experimentalUnsafeIdeIntegration){await _e(x.path,G,process.platform);const w={hostPath:h.join(".",h.sep,F),vfsPath:"/"};try{await Ze(f,process.cwd());const y=typeof e.xdebug=="object"?e.xdebug:void 0,T=await Je({name:f,host:c,port:d,ides:e.experimentalUnsafeIdeIntegration,cwd:process.cwd(),mounts:[w,...e["mount-before-install"]||[],...e.mount||[]],ideKey:y?.ideKey}),P=e.experimentalUnsafeIdeIntegration,E=P.includes("vscode"),L=P.includes("phpstorm");console.log(""),console.log(W("Xdebug configured successfully")),console.log(te("Updated IDE config: ")+T.join(" ")),console.log(te("Playground source root: ")+".playground-xdebug-root"+X(Ge(" – you can set breakpoints and preview Playground's VFS structure in there."))),console.log(""),E&&(console.log(W("VS Code / Cursor instructions:")),console.log(" 1. Ensure you have installed an IDE extension for PHP Debugging"),console.log(` (The ${W("PHP Debug")} extension by ${W("Xdebug")} has been a solid option)`),console.log(" 2. Open the Run and Debug panel on the left sidebar"),console.log(` 3. Select "${X(f)}" from the dropdown`),console.log(' 3. Click "start debugging"'),console.log(" 5. Set a breakpoint. For example, in .playground-xdebug-root/wordpress/index.php"),console.log(" 6. Visit Playground in your browser to hit the breakpoint"),L&&console.log("")),L&&(console.log(W("PhpStorm instructions:")),console.log(` 1. Choose "${X(f)}" debug configuration in the toolbar`),console.log(" 2. Click the debug button (bug icon)`"),console.log(" 3. Set a breakpoint. For example, in .playground-xdebug-root/wordpress/index.php"),console.log(" 4. Visit Playground in your browser to hit the breakpoint")),console.log("")}catch(y){throw new Error("Could not configure Xdebug",{cause:y})}}const ce=h.dirname(x.path),de=2*24*60*60*1e3;Ue(B,de,ce);const V=h.join(x.path,"internal");u.mkdirSync(V);const ue=["wordpress","tmp","home"];for(const w of ue){const y=P=>P.vfsPath===`/${w}`;if(!(e["mount-before-install"]?.some(y)||e.mount?.some(y))){const P=h.join(x.path,w);u.mkdirSync(P),e["mount-before-install"]===void 0&&(e["mount-before-install"]=[]),e["mount-before-install"].unshift({vfsPath:`/${w}`,hostPath:P})}}if(e["mount-before-install"])for(const w of e["mount-before-install"])m.logger.debug(`Mount before WP install: ${w.vfsPath} -> ${w.hostPath}`);if(e.mount)for(const w of e.mount)m.logger.debug(`Mount after WP install: ${w.vfsPath} -> ${w.hostPath}`);let R;e["experimental-blueprints-v2-runner"]?R=new Be(e,{siteUrl:g,processIdSpaceLength:I}):(R=new De(e,{siteUrl:g,processIdSpaceLength:I}),typeof e.blueprint=="string"&&(e.blueprint=await je({sourceString:e.blueprint,blueprintMayReadAdjacentFiles:e["blueprint-may-read-adjacent-files"]===!0})));let _=!1;const O=async function(){_||(_=!0,await Promise.all(i.map(async({playground:y,worker:T})=>{await y.dispose(),await T.terminate()})),l&&await new Promise(y=>l.close(y)),await x.cleanup())},pe=Ke(S,R.getWorkerType(),({exitCode:w,workerIndex:y})=>{_||w===0&&m.logger.error(`Worker ${y} exited with code ${w}
28
+ `)});m.logger.log("Starting up workers");try{const w=await pe,y=await oe(n);{const P=w.shift(),E=await R.bootAndSetUpInitialPlayground(P.phpPort,y,V);if(await E.isReady(),r=!0,m.logger.log("Booted!"),o=new $e(E),!e["experimental-blueprints-v2-runner"]){const L=await R.compileInputBlueprint(e["additional-blueprint-steps"]||[]);L&&(m.logger.log("Running the Blueprint..."),await M.runBlueprintV1Steps(L,E),m.logger.log("Finished running the blueprint"))}if(e.command==="build-snapshot"){await et(t,e.outfile),m.logger.log(`WordPress exported to ${e.outfile}`),await O();return}else if(e.command==="run-blueprint"){m.logger.log("Blueprint executed"),await O();return}await o.removeWorker(E),await E.dispose(),await P.worker.terminate()}m.logger.log("Preparing workers...");const T=I;return[t]=await Promise.all(w.map(async(P,E)=>{const L=T+E*I,fe=await oe(n),H=await R.bootPlayground({worker:P,fileLockManagerPort:fe,firstProcessId:L,nativeInternalDirPath:V});return i.push({playground:H,worker:P.worker}),o.addWorker(H),H})),m.logger.log(`WordPress is running on ${p} with ${b} worker(s)`),e.xdebug&&e.experimentalDevtools&&(await Ee.startBridge({phpInstance:t,phpRoot:"/wordpress"})).start(),{playground:t,server:l,serverUrl:p,[Symbol.asyncDispose]:O,workerThreadCount:b}}catch(w){if(!e.debug)throw w;let y="";throw await t?.fileExists(m.errorLogPath)&&(y=await t.readFileAsText(m.errorLogPath)),new Error(y,{cause:w})}},async handleRequest(l){if(!r)return k.PHPResponse.forHttpCode(502,"WordPress is not ready yet");if(a){a=!1;const d={"Content-Type":["text/plain"],"Content-Length":["0"],Location:[l.url]};return l.headers?.cookie?.includes("playground_auto_login_already_happened")&&(d["Set-Cookie"]=["playground_auto_login_already_happened=1; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=/"]),new k.PHPResponse(302,d,new Uint8Array)}return await o.handleRequest(l)}})}async function Ke(e,o,t){const i=[];for(let s=0;s<e;s++){const n=await Qe(o),r=a=>{t({exitCode:a,workerIndex:s})};i.push(new Promise((a,l)=>{n.once("message",function(d){d.command==="worker-script-initialized"&&a({worker:n,phpPort:d.phpPort})}),n.once("error",function(d){console.error(d);const c=new Error(`Worker failed to load worker. ${d.message?`Original error: ${d.message}`:""}`);l(c)}),n.once("exit",r)}))}return Promise.all(i)}async function Qe(e){return e==="v1"?new J.Worker(new URL("./worker-thread-v1.cjs",typeof document>"u"?require("url").pathToFileURL(__filename).href:$&&$.tagName.toUpperCase()==="SCRIPT"&&$.src||new URL("run-cli-DJ9bUpjg.cjs",document.baseURI).href)):new J.Worker(new URL("./worker-thread-v2.cjs",typeof document>"u"?require("url").pathToFileURL(__filename).href:$&&$.tagName.toUpperCase()==="SCRIPT"&&$.src||new URL("run-cli-DJ9bUpjg.cjs",document.baseURI).href))}async function oe(e){const{port1:o,port2:t}=new J.MessageChannel;return await xe.jspi()?k.exposeAPI(e,null,o):await k.exposeSyncAPI(e,o),t}async function et(e,o){await e.run({code:`<?php
29
+ $zip = new ZipArchive();
30
+ if(false === $zip->open('/tmp/build.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE)) {
31
+ throw new Exception('Failed to create ZIP');
32
+ }
33
+ $files = new RecursiveIteratorIterator(
34
+ new RecursiveDirectoryIterator('/wordpress')
35
+ );
36
+ foreach ($files as $file) {
37
+ echo $file . PHP_EOL;
38
+ if (!$file->isFile()) {
39
+ continue;
40
+ }
41
+ $zip->addFile($file->getPathname(), $file->getPathname());
42
+ }
43
+ $zip->close();
44
+
45
+ `});const t=await e.readFileAsBuffer("/tmp/build.zip");u.writeFileSync(o,t)}exports.LogVerbosity=N;exports.parseOptionsAndRunCLI=Ye;exports.runCLI=le;
46
+ //# sourceMappingURL=run-cli-DJ9bUpjg.cjs.map