@wp-playground/cli 3.0.43 → 3.0.45

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.
@@ -1,26 +1,26 @@
1
- import { logger as g, LogSeverity as j, errorLogPath as ee } from "@php-wasm/logger";
2
- import { PHPResponse as Y, consumeAPI as F, SupportedPHPVersions as te, printDebugDetails as ye, exposeAPI as be, exposeSyncAPI as ve } from "@php-wasm/universal";
3
- import { resolveRemoteBlueprint as Pe, resolveRuntimeConfiguration as re, compileBlueprintV1 as Se, isBlueprintBundle as xe, runBlueprintV1Steps as ke } from "@wp-playground/blueprints";
4
- import { zipDirectory as Ie, RecommendedPHPVersion as U } from "@wp-playground/common";
5
- import p, { existsSync as X, rmdirSync as $e, mkdirSync as z, readdirSync as Te } from "fs";
6
- import { MessageChannel as Be, Worker as oe } from "worker_threads";
7
- import { createNodeFsMountHandler as Ee, FileLockManagerForNode as Le } from "@php-wasm/node";
8
- import h, { basename as A, join as ue } from "path";
1
+ import { logger as y, LogSeverity as j, errorLogPath as re } from "@php-wasm/logger";
2
+ import { PHPResponse as z, consumeAPI as U, SupportedPHPVersions as oe, printDebugDetails as ve, exposeAPI as Pe, exposeSyncAPI as Se } from "@php-wasm/universal";
3
+ import { resolveRemoteBlueprint as xe, resolveRuntimeConfiguration as se, compileBlueprintV1 as ke, isBlueprintBundle as Ie, runBlueprintV1Steps as $e } from "@wp-playground/blueprints";
4
+ import { zipDirectory as Ee, RecommendedPHPVersion as F } from "@wp-playground/common";
5
+ import c, { existsSync as Z, rmdirSync as Te, mkdirSync as G, readdirSync as Be } from "fs";
6
+ import { MessageChannel as Me, Worker as ie } from "worker_threads";
7
+ import { createNodeFsMountHandler as Ce, FileLockManagerForNode as Le } from "@php-wasm/node";
8
+ import p, { basename as A, join as ce } from "path";
9
9
  import We from "express";
10
- import O, { cpus as Ce } from "os";
11
- import { jspi as Me } from "wasm-feature-detect";
10
+ import N, { cpus as De } from "os";
11
+ import { jspi as Q } from "wasm-feature-detect";
12
12
  import Re from "yargs";
13
- import { NodeJsFilesystem as De, OverlayFilesystem as Ae, InMemoryFilesystem as Fe, ZipFilesystem as Ue } from "@wp-playground/storage";
14
- import { EmscriptenDownloadMonitor as Oe, ProgressTracker as He } from "@php-wasm/progress";
15
- import { resolveWordPressRelease as Ve } from "@wp-playground/wordpress";
13
+ import { NodeJsFilesystem as Ae, OverlayFilesystem as Ue, InMemoryFilesystem as Fe, ZipFilesystem as Oe } from "@wp-playground/storage";
14
+ import { EmscriptenDownloadMonitor as Ne, ProgressTracker as _e } from "@php-wasm/progress";
15
+ import { resolveWordPressRelease as He } from "@wp-playground/wordpress";
16
16
  import B from "fs-extra";
17
- import { startBridge as Ne } from "@php-wasm/xdebug-bridge";
17
+ import { startBridge as Ve } from "@php-wasm/xdebug-bridge";
18
18
  import { exec as je } from "child_process";
19
- import { dir as _e, setGracefulCleanup as qe } from "tmp-promise";
20
- import Ye from "ps-man";
21
- import { removeTempDirSymlink as ze, createTempDirSymlink as Qe, clearXdebugIDEConfig as Xe, addXdebugIDEConfig as Ze } from "@php-wasm/cli-util";
22
- import { createHash as Ge } from "crypto";
23
- function _(e) {
19
+ import { dir as qe, setGracefulCleanup as Ye } from "tmp-promise";
20
+ import ze from "ps-man";
21
+ import { removeTempDirSymlink as Ge, createTempDirSymlink as Qe, clearXdebugIDEConfig as Xe, addXdebugIDEConfig as Ze } from "@php-wasm/cli-util";
22
+ import { createHash as Je } from "crypto";
23
+ function q(e) {
24
24
  const t = [];
25
25
  for (const r of e) {
26
26
  const s = r.split(":");
@@ -30,35 +30,35 @@ function _(e) {
30
30
  If your path contains a colon, e.g. C:\\myplugin, use the --mount-dir option instead.
31
31
  Example: --mount-dir C:\\my-plugin /wordpress/wp-content/plugins/my-plugin`);
32
32
  const [o, i] = s;
33
- if (!X(o))
33
+ if (!Z(o))
34
34
  throw new Error(`Host path does not exist: ${o}`);
35
35
  t.push({ hostPath: o, vfsPath: i });
36
36
  }
37
37
  return t;
38
38
  }
39
- function se(e) {
39
+ function ne(e) {
40
40
  if (e.length % 2 !== 0)
41
41
  throw new Error("Invalid mount format. Expected: /host/path /vfs/path");
42
42
  const t = [];
43
43
  for (let r = 0; r < e.length; r += 2) {
44
44
  const s = e[r], o = e[r + 1];
45
- if (!X(s))
45
+ if (!Z(s))
46
46
  throw new Error(`Host path does not exist: ${s}`);
47
47
  t.push({
48
- hostPath: h.resolve(process.cwd(), s),
48
+ hostPath: p.resolve(process.cwd(), s),
49
49
  vfsPath: o
50
50
  });
51
51
  }
52
52
  return t;
53
53
  }
54
- async function Gt(e, t) {
54
+ async function rr(e, t) {
55
55
  for (const r of t)
56
56
  await e.mount(
57
57
  r.vfsPath,
58
- Ee(r.hostPath)
58
+ Ce(r.hostPath)
59
59
  );
60
60
  }
61
- const ie = {
61
+ const ae = {
62
62
  step: "runPHP",
63
63
  code: {
64
64
  filename: "activate-theme.php",
@@ -77,7 +77,7 @@ const ie = {
77
77
  `
78
78
  }
79
79
  };
80
- function de(e) {
80
+ function pe(e) {
81
81
  const t = e.autoMount, r = [...e.mount || []], s = [...e["mount-before-install"] || []], o = {
82
82
  ...e,
83
83
  mount: r,
@@ -86,7 +86,7 @@ function de(e) {
86
86
  ...e["additional-blueprint-steps"] || []
87
87
  ]
88
88
  };
89
- if (tt(t)) {
89
+ if (rt(t)) {
90
90
  const n = `/wordpress/wp-content/plugins/${A(t)}`;
91
91
  r.push({
92
92
  hostPath: t,
@@ -96,7 +96,7 @@ function de(e) {
96
96
  step: "activatePlugin",
97
97
  pluginPath: `/wordpress/wp-content/plugins/${A(t)}`
98
98
  });
99
- } else if (et(t)) {
99
+ } else if (tt(t)) {
100
100
  const i = A(t), n = `/wordpress/wp-content/themes/${i}`;
101
101
  r.push({
102
102
  hostPath: t,
@@ -111,44 +111,117 @@ function de(e) {
111
111
  themeFolderName: i
112
112
  }
113
113
  );
114
- } else if (Ke(t)) {
115
- const i = p.readdirSync(t);
114
+ } else if (et(t)) {
115
+ const i = c.readdirSync(t);
116
116
  for (const n of i)
117
117
  n !== "index.php" && r.push({
118
118
  hostPath: `${t}/${n}`,
119
119
  vfsPath: `/wordpress/wp-content/${n}`,
120
120
  autoMounted: !0
121
121
  });
122
- o["additional-blueprint-steps"].push(ie);
123
- } else Je(t) && (s.push({
122
+ o["additional-blueprint-steps"].push(ae);
123
+ } else Ke(t) && (s.push({
124
124
  hostPath: t,
125
125
  vfsPath: "/wordpress",
126
126
  autoMounted: !0
127
- }), o.mode = "apply-to-existing-site", o["additional-blueprint-steps"].push(ie), o.wordpressInstallMode || (o.wordpressInstallMode = "install-from-existing-files-if-needed"));
127
+ }), o.mode = "apply-to-existing-site", o["additional-blueprint-steps"].push(ae), o.wordpressInstallMode || (o.wordpressInstallMode = "install-from-existing-files-if-needed"));
128
128
  return o;
129
129
  }
130
- function Je(e) {
131
- const t = p.readdirSync(e);
130
+ function Ke(e) {
131
+ const t = c.readdirSync(e);
132
132
  return t.includes("wp-admin") && t.includes("wp-includes") && t.includes("wp-content");
133
133
  }
134
- function Ke(e) {
135
- const t = p.readdirSync(e);
134
+ function et(e) {
135
+ const t = c.readdirSync(e);
136
136
  return t.includes("themes") || t.includes("plugins") || t.includes("mu-plugins") || t.includes("uploads");
137
137
  }
138
- function et(e) {
139
- if (!p.readdirSync(e).includes("style.css"))
138
+ function tt(e) {
139
+ if (!c.readdirSync(e).includes("style.css"))
140
140
  return !1;
141
- const r = p.readFileSync(ue(e, "style.css"), "utf8");
141
+ const r = c.readFileSync(ce(e, "style.css"), "utf8");
142
142
  return !!/^(?:[ \t]*<\?php)?[ \t/*#@]*Theme Name:(.*)$/im.exec(r);
143
143
  }
144
- function tt(e) {
145
- const t = p.readdirSync(e), r = /^(?:[ \t]*<\?php)?[ \t/*#@]*Plugin Name:(.*)$/im;
144
+ function rt(e) {
145
+ const t = c.readdirSync(e), r = /^(?:[ \t]*<\?php)?[ \t/*#@]*Plugin Name:(.*)$/im;
146
146
  return !!t.filter((o) => o.endsWith(".php")).find((o) => {
147
- const i = p.readFileSync(ue(e, o), "utf8");
147
+ const i = c.readFileSync(ce(e, o), "utf8");
148
148
  return !!r.exec(i);
149
149
  });
150
150
  }
151
- async function rt(e) {
151
+ function ot(e) {
152
+ if (e.length % 2 !== 0)
153
+ throw new Error(
154
+ "Invalid constant definition format. Expected pairs of NAME value"
155
+ );
156
+ const t = {};
157
+ for (let r = 0; r < e.length; r += 2) {
158
+ const s = e[r], o = e[r + 1];
159
+ if (!s || !s.trim())
160
+ throw new Error("Constant name cannot be empty");
161
+ t[s.trim()] = o;
162
+ }
163
+ return t;
164
+ }
165
+ function st(e) {
166
+ if (e.length % 2 !== 0)
167
+ throw new Error(
168
+ "Invalid boolean constant definition format. Expected pairs of NAME value"
169
+ );
170
+ const t = {};
171
+ for (let r = 0; r < e.length; r += 2) {
172
+ const s = e[r], o = e[r + 1].trim().toLowerCase();
173
+ if (!s || !s.trim())
174
+ throw new Error("Constant name cannot be empty");
175
+ if (o === "true" || o === "1")
176
+ t[s.trim()] = !0;
177
+ else if (o === "false" || o === "0")
178
+ t[s.trim()] = !1;
179
+ else
180
+ throw new Error(
181
+ `Invalid boolean value for constant "${s}": "${o}". Must be "true", "false", "1", or "0".`
182
+ );
183
+ }
184
+ return t;
185
+ }
186
+ function it(e) {
187
+ if (e.length % 2 !== 0)
188
+ throw new Error(
189
+ "Invalid number constant definition format. Expected pairs of NAME value"
190
+ );
191
+ const t = {};
192
+ for (let r = 0; r < e.length; r += 2) {
193
+ const s = e[r], o = e[r + 1].trim();
194
+ if (!s || !s.trim())
195
+ throw new Error("Constant name cannot be empty");
196
+ const i = Number(o);
197
+ if (isNaN(i))
198
+ throw new Error(
199
+ `Invalid number value for constant "${s}": "${o}". Must be a valid number.`
200
+ );
201
+ t[s.trim()] = i;
202
+ }
203
+ return t;
204
+ }
205
+ function nt(e = {}, t = {}, r = {}) {
206
+ const s = {}, o = /* @__PURE__ */ new Set(), i = (n, l) => {
207
+ for (const u in n) {
208
+ if (o.has(u))
209
+ throw new Error(
210
+ `Constant "${u}" is defined multiple times across different --define-${l} flags`
211
+ );
212
+ o.add(u), s[u] = n[u];
213
+ }
214
+ };
215
+ return i(e, "string"), i(t, "bool"), i(r, "number"), s;
216
+ }
217
+ function O(e) {
218
+ return nt(
219
+ e.define,
220
+ e["define-bool"],
221
+ e["define-number"]
222
+ );
223
+ }
224
+ async function at(e) {
152
225
  const t = We(), r = await new Promise((i, n) => {
153
226
  const l = t.listen(e.port, () => {
154
227
  const u = l.address();
@@ -160,12 +233,12 @@ async function rt(e) {
160
233
  try {
161
234
  l = await e.handleRequest({
162
235
  url: i.url,
163
- headers: st(i),
236
+ headers: ut(i),
164
237
  method: i.method,
165
- body: await ot(i)
238
+ body: await lt(i)
166
239
  });
167
240
  } catch (u) {
168
- g.error(u), l = Y.forHttpCode(500);
241
+ y.error(u), l = z.forHttpCode(500);
169
242
  }
170
243
  n.statusCode = l.httpStatusCode;
171
244
  for (const u in l.headers)
@@ -175,21 +248,21 @@ async function rt(e) {
175
248
  const o = r.address().port;
176
249
  return await e.onBind(r, o);
177
250
  }
178
- const ot = async (e) => await new Promise((t) => {
251
+ const lt = async (e) => await new Promise((t) => {
179
252
  const r = [];
180
253
  e.on("data", (s) => {
181
254
  r.push(s);
182
255
  }), e.on("end", () => {
183
256
  t(new Uint8Array(Buffer.concat(r)));
184
257
  });
185
- }), st = (e) => {
258
+ }), ut = (e) => {
186
259
  const t = {};
187
260
  if (e.rawHeaders && e.rawHeaders.length)
188
261
  for (let r = 0; r < e.rawHeaders.length; r += 2)
189
262
  t[e.rawHeaders[r].toLowerCase()] = e.rawHeaders[r + 1];
190
263
  return t;
191
264
  };
192
- class it {
265
+ class dt {
193
266
  constructor(t) {
194
267
  this.workerLoads = [], this.addWorker(t);
195
268
  }
@@ -220,33 +293,33 @@ class it {
220
293
  });
221
294
  }
222
295
  }
223
- function nt(e) {
296
+ function ct(e) {
224
297
  return /^latest$|^trunk$|^nightly$|^(?:(\d+)\.(\d+)(?:\.(\d+))?)((?:-beta(?:\d+)?)|(?:-RC(?:\d+)?))?$/.test(e);
225
298
  }
226
- async function at({
299
+ async function pt({
227
300
  sourceString: e,
228
301
  blueprintMayReadAdjacentFiles: t
229
302
  }) {
230
303
  if (!e)
231
304
  return;
232
305
  if (e.startsWith("http://") || e.startsWith("https://"))
233
- return await Pe(e);
234
- let r = h.resolve(process.cwd(), e);
235
- if (!p.existsSync(r))
306
+ return await xe(e);
307
+ let r = p.resolve(process.cwd(), e);
308
+ if (!c.existsSync(r))
236
309
  throw new Error(`Blueprint file does not exist: ${r}`);
237
- const s = p.statSync(r);
238
- if (s.isDirectory() && (r = h.join(r, "blueprint.json")), !s.isFile() && s.isSymbolicLink())
310
+ const s = c.statSync(r);
311
+ if (s.isDirectory() && (r = p.join(r, "blueprint.json")), !s.isFile() && s.isSymbolicLink())
239
312
  throw new Error(
240
313
  `Blueprint path is neither a file nor a directory: ${r}`
241
314
  );
242
- const o = h.extname(r);
315
+ const o = p.extname(r);
243
316
  switch (o) {
244
317
  case ".zip":
245
- return Ue.fromArrayBuffer(
246
- p.readFileSync(r).buffer
318
+ return Oe.fromArrayBuffer(
319
+ c.readFileSync(r).buffer
247
320
  );
248
321
  case ".json": {
249
- const i = p.readFileSync(r, "utf-8");
322
+ const i = c.readFileSync(r, "utf-8");
250
323
  try {
251
324
  JSON.parse(i);
252
325
  } catch {
@@ -254,8 +327,8 @@ async function at({
254
327
  `Blueprint file at ${r} is not a valid JSON file`
255
328
  );
256
329
  }
257
- const n = h.dirname(r), l = new De(n);
258
- return new Ae([
330
+ const n = p.dirname(r), l = new Ae(n);
331
+ return new Ue([
259
332
  new Fe({
260
333
  "blueprint.json": i
261
334
  }),
@@ -282,7 +355,7 @@ You can allow this Blueprint to read files from the same parent directory by exp
282
355
  );
283
356
  }
284
357
  }
285
- class lt {
358
+ class mt {
286
359
  constructor(t, r) {
287
360
  this.args = t, this.siteUrl = r.siteUrl, this.processIdSpaceLength = r.processIdSpaceLength, this.phpVersion = t.php, this.cliOutput = r.cliOutput;
288
361
  }
@@ -290,7 +363,7 @@ class lt {
290
363
  return "v2";
291
364
  }
292
365
  async bootAndSetUpInitialPlayground(t, r, s) {
293
- const o = F(t);
366
+ const o = U(t);
294
367
  await o.useFileLockManager(r);
295
368
  const i = {
296
369
  ...this.args,
@@ -301,6 +374,8 @@ class lt {
301
374
  trace: this.args.verbosity === "debug",
302
375
  blueprint: this.args.blueprint,
303
376
  withIntl: this.args.intl,
377
+ withRedis: this.args.redis,
378
+ withMemcached: this.args.memcached,
304
379
  // We do not enable Xdebug by default for the initial worker
305
380
  // because we do not imagine users expect to hit breakpoints
306
381
  // until Playground has fully booted.
@@ -309,7 +384,8 @@ class lt {
309
384
  xdebug: void 0,
310
385
  nativeInternalDirPath: s,
311
386
  mountsBeforeWpInstall: this.args["mount-before-install"] || [],
312
- mountsAfterWpInstall: this.args.mount || []
387
+ mountsAfterWpInstall: this.args.mount || [],
388
+ constants: O(this.args)
313
389
  };
314
390
  return await o.bootAndSetUpInitialWorker(i), o;
315
391
  }
@@ -319,7 +395,7 @@ class lt {
319
395
  firstProcessId: s,
320
396
  nativeInternalDirPath: o
321
397
  }) {
322
- const i = F(t.phpPort);
398
+ const i = U(t.phpPort);
323
399
  await i.useFileLockManager(r);
324
400
  const n = {
325
401
  ...this.args,
@@ -329,27 +405,30 @@ class lt {
329
405
  processIdSpaceLength: this.processIdSpaceLength,
330
406
  trace: this.args.verbosity === "debug",
331
407
  withIntl: this.args.intl,
408
+ withRedis: this.args.redis,
409
+ withMemcached: this.args.memcached,
332
410
  withXdebug: !!this.args.xdebug,
333
411
  nativeInternalDirPath: o,
334
412
  mountsBeforeWpInstall: this.args["mount-before-install"] || [],
335
- mountsAfterWpInstall: this.args.mount || []
413
+ mountsAfterWpInstall: this.args.mount || [],
414
+ constants: O(this.args)
336
415
  };
337
416
  return await i.bootWorker(n), i;
338
417
  }
339
418
  }
340
- const Q = h.join(O.homedir(), ".wordpress-playground");
341
- async function ut(e) {
342
- return await pe(
419
+ const X = p.join(N.homedir(), ".wordpress-playground");
420
+ async function ht(e) {
421
+ return await me(
343
422
  "https://github.com/WordPress/sqlite-database-integration/archive/refs/heads/develop.zip",
344
423
  "sqlite.zip",
345
424
  e
346
425
  );
347
426
  }
348
- async function pe(e, t, r) {
349
- const s = h.join(Q, t);
350
- return B.existsSync(s) || (B.ensureDirSync(Q), await dt(e, s, r)), ce(s);
427
+ async function me(e, t, r) {
428
+ const s = p.join(X, t);
429
+ return B.existsSync(s) || (B.ensureDirSync(X), await ft(e, s, r)), he(s);
351
430
  }
352
- async function dt(e, t, r) {
431
+ async function ft(e, t, r) {
353
432
  const o = (await r.monitorFetch(fetch(e))).body.getReader(), i = `${t}.partial`, n = B.createWriteStream(i);
354
433
  for (; ; ) {
355
434
  const { done: l, value: u } = await o.read();
@@ -359,15 +438,15 @@ async function dt(e, t, r) {
359
438
  n.close(), n.closed || await new Promise((l, u) => {
360
439
  n.on("finish", () => {
361
440
  B.renameSync(i, t), l(null);
362
- }), n.on("error", (b) => {
363
- B.removeSync(i), u(b);
441
+ }), n.on("error", (v) => {
442
+ B.removeSync(i), u(v);
364
443
  });
365
444
  });
366
445
  }
367
- function ce(e, t) {
446
+ function he(e, t) {
368
447
  return new File([B.readFileSync(e)], A(e));
369
448
  }
370
- class pt {
449
+ class wt {
371
450
  constructor(t, r) {
372
451
  this.args = t, this.siteUrl = r.siteUrl, this.processIdSpaceLength = r.processIdSpaceLength, this.cliOutput = r.cliOutput;
373
452
  }
@@ -376,62 +455,65 @@ class pt {
376
455
  }
377
456
  async bootAndSetUpInitialPlayground(t, r, s) {
378
457
  let o, i, n;
379
- const l = new Oe();
458
+ const l = new Ne();
380
459
  if (this.args.wordpressInstallMode === "download-and-install") {
381
- let E = !1;
382
- l.addEventListener("progress", (k) => {
383
- if (E)
460
+ let k = !1;
461
+ l.addEventListener("progress", (I) => {
462
+ if (k)
384
463
  return;
385
- const { loaded: W, total: Z } = k.detail, C = Math.floor(
386
- Math.min(100, 100 * W / Z)
464
+ const { loaded: C, total: J } = I.detail, L = Math.floor(
465
+ Math.min(100, 100 * C / J)
387
466
  );
388
- E = C === 100, this.cliOutput.updateProgress(
467
+ k = L === 100, this.cliOutput.updateProgress(
389
468
  "Downloading WordPress",
390
- C
469
+ L
391
470
  );
392
- }), o = await Ve(this.args.wp), n = h.join(
393
- Q,
471
+ }), o = await He(this.args.wp), n = p.join(
472
+ X,
394
473
  `prebuilt-wp-content-for-wp-${o.version}.zip`
395
- ), i = p.existsSync(n) ? ce(n) : await pe(
474
+ ), i = c.existsSync(n) ? he(n) : await me(
396
475
  o.releaseUrl,
397
476
  `${o.version}.zip`,
398
477
  l
399
- ), g.debug(
478
+ ), y.debug(
400
479
  `Resolved WordPress release URL: ${o?.releaseUrl}`
401
480
  );
402
481
  }
403
482
  let u;
404
- this.args.skipSqliteSetup ? (g.debug("Skipping SQLite integration plugin setup..."), u = void 0) : (this.cliOutput.updateProgress("Preparing SQLite database"), u = await ut(l));
405
- const b = this.args.followSymlinks === !0, v = this.args.experimentalTrace === !0, a = this.args["mount-before-install"] || [], f = this.args.mount || [], c = F(t);
406
- await c.isConnected(), this.cliOutput.updateProgress("Booting WordPress");
407
- const S = await re(
483
+ this.args.skipSqliteSetup ? (y.debug("Skipping SQLite integration plugin setup..."), u = void 0) : (this.cliOutput.updateProgress("Preparing SQLite database"), u = await ht(l));
484
+ const v = this.args.followSymlinks === !0, P = this.args.experimentalTrace === !0, w = this.args["mount-before-install"] || [], a = this.args.mount || [], g = U(t);
485
+ await g.isConnected(), this.cliOutput.updateProgress("Booting WordPress");
486
+ const h = await se(
408
487
  this.getEffectiveBlueprint()
409
488
  );
410
- return await c.useFileLockManager(r), await c.bootAndSetUpInitialWorker({
411
- phpVersion: S.phpVersion,
412
- wpVersion: S.wpVersion,
489
+ return await g.useFileLockManager(r), await g.bootAndSetUpInitialWorker({
490
+ phpVersion: h.phpVersion,
491
+ wpVersion: h.wpVersion,
413
492
  siteUrl: this.siteUrl,
414
- mountsBeforeWpInstall: a,
415
- mountsAfterWpInstall: f,
493
+ mountsBeforeWpInstall: w,
494
+ mountsAfterWpInstall: a,
416
495
  wordpressInstallMode: this.args.wordpressInstallMode || "download-and-install",
417
496
  wordPressZip: i && await i.arrayBuffer(),
418
497
  sqliteIntegrationPluginZip: await u?.arrayBuffer(),
419
498
  firstProcessId: 0,
420
499
  processIdSpaceLength: this.processIdSpaceLength,
421
- followSymlinks: b,
422
- trace: v,
500
+ followSymlinks: v,
501
+ trace: P,
423
502
  internalCookieStore: this.args.internalCookieStore,
424
503
  withIntl: this.args.intl,
504
+ withRedis: this.args.redis,
505
+ withMemcached: this.args.memcached,
425
506
  // We do not enable Xdebug by default for the initial worker
426
507
  // because we do not imagine users expect to hit breakpoints
427
508
  // until Playground has fully booted.
428
509
  // TODO: Consider supporting Xdebug for the initial worker via a dedicated flag.
429
510
  withXdebug: !1,
430
- nativeInternalDirPath: s
431
- }), n && !this.args["mount-before-install"] && !p.existsSync(n) && (this.cliOutput.updateProgress("Caching WordPress for next boot"), p.writeFileSync(
511
+ nativeInternalDirPath: s,
512
+ constants: O(this.args)
513
+ }), n && !this.args["mount-before-install"] && !c.existsSync(n) && (this.cliOutput.updateProgress("Caching WordPress for next boot"), c.writeFileSync(
432
514
  n,
433
- await Ie(c, "/wordpress")
434
- )), c;
515
+ await Ee(g, "/wordpress")
516
+ )), g;
435
517
  }
436
518
  async bootPlayground({
437
519
  worker: t,
@@ -439,11 +521,11 @@ class pt {
439
521
  firstProcessId: s,
440
522
  nativeInternalDirPath: o
441
523
  }) {
442
- const i = F(
524
+ const i = U(
443
525
  t.phpPort
444
526
  );
445
527
  await i.isConnected();
446
- const n = await re(
528
+ const n = await se(
447
529
  this.getEffectiveBlueprint()
448
530
  );
449
531
  return await i.useFileLockManager(r), await i.bootWorker({
@@ -459,12 +541,15 @@ class pt {
459
541
  // will have a separate cookie store.
460
542
  internalCookieStore: this.args.internalCookieStore,
461
543
  withIntl: this.args.intl,
544
+ withRedis: this.args.redis,
545
+ withMemcached: this.args.memcached,
462
546
  withXdebug: !!this.args.xdebug,
463
- nativeInternalDirPath: o
547
+ nativeInternalDirPath: o,
548
+ constants: O(this.args)
464
549
  }), await i.isReady(), i;
465
550
  }
466
551
  async compileInputBlueprint(t) {
467
- const r = this.getEffectiveBlueprint(), s = new He();
552
+ const r = this.getEffectiveBlueprint(), s = new _e();
468
553
  let o = "", i = !1;
469
554
  return s.addEventListener("progress", (n) => {
470
555
  if (i)
@@ -472,26 +557,26 @@ class pt {
472
557
  i = n.detail.progress === 100;
473
558
  const l = Math.floor(n.detail.progress);
474
559
  o = n.detail.caption || o || "Running Blueprint", this.cliOutput.updateProgress(o.trim(), l);
475
- }), await Se(r, {
560
+ }), await ke(r, {
476
561
  progress: s,
477
562
  additionalSteps: t
478
563
  });
479
564
  }
480
565
  getEffectiveBlueprint() {
481
566
  const t = this.args.blueprint;
482
- return xe(t) ? t : {
567
+ return Ie(t) ? t : {
483
568
  login: this.args.login,
484
569
  ...t || {},
485
570
  preferredVersions: {
486
- php: this.args.php ?? t?.preferredVersions?.php ?? U,
571
+ php: this.args.php ?? t?.preferredVersions?.php ?? F,
487
572
  wp: this.args.wp ?? t?.preferredVersions?.wp ?? "latest",
488
573
  ...t?.preferredVersions || {}
489
574
  }
490
575
  };
491
576
  }
492
577
  }
493
- async function ct(e, t = !0) {
494
- const s = `${h.basename(process.argv0)}${e}${process.pid}-`, o = await _e({
578
+ async function gt(e, t = !0) {
579
+ const s = `${p.basename(process.argv0)}${e}${process.pid}-`, o = await qe({
495
580
  prefix: s,
496
581
  /*
497
582
  * Allow recursive cleanup on process exit.
@@ -503,20 +588,20 @@ async function ct(e, t = !0) {
503
588
  */
504
589
  unsafeCleanup: !0
505
590
  });
506
- return t && qe(), o;
591
+ return t && Ye(), o;
507
592
  }
508
- async function ht(e, t, r) {
509
- const o = (await mt(
593
+ async function yt(e, t, r) {
594
+ const o = (await bt(
510
595
  e,
511
596
  t,
512
597
  r
513
598
  )).map(
514
599
  (i) => new Promise((n) => {
515
- p.rm(i, { recursive: !0 }, (l) => {
516
- l ? g.warn(
600
+ c.rm(i, { recursive: !0 }, (l) => {
601
+ l ? y.warn(
517
602
  `Failed to delete stale Playground temp dir: ${i}`,
518
603
  l
519
- ) : g.info(
604
+ ) : y.info(
520
605
  `Deleted stale Playground temp dir: ${i}`
521
606
  ), n();
522
607
  });
@@ -524,24 +609,24 @@ async function ht(e, t, r) {
524
609
  );
525
610
  await Promise.all(o);
526
611
  }
527
- async function mt(e, t, r) {
612
+ async function bt(e, t, r) {
528
613
  try {
529
- const s = p.readdirSync(r).map((i) => h.join(r, i)), o = [];
614
+ const s = c.readdirSync(r).map((i) => p.join(r, i)), o = [];
530
615
  for (const i of s)
531
- await ft(
616
+ await vt(
532
617
  e,
533
618
  t,
534
619
  i
535
620
  ) && o.push(i);
536
621
  return o;
537
622
  } catch (s) {
538
- return g.warn(`Failed to find stale Playground temp dirs: ${s}`), [];
623
+ return y.warn(`Failed to find stale Playground temp dirs: ${s}`), [];
539
624
  }
540
625
  }
541
- async function ft(e, t, r) {
542
- if (!p.lstatSync(r).isDirectory())
626
+ async function vt(e, t, r) {
627
+ if (!c.lstatSync(r).isDirectory())
543
628
  return !1;
544
- const o = h.basename(r);
629
+ const o = p.basename(r);
545
630
  if (!o.includes(e))
546
631
  return !1;
547
632
  const i = o.match(
@@ -553,15 +638,15 @@ async function ft(e, t, r) {
553
638
  executableName: i[1],
554
639
  pid: i[2]
555
640
  };
556
- if (await wt(n.pid, n.executableName))
641
+ if (await Pt(n.pid, n.executableName))
557
642
  return !1;
558
643
  const l = Date.now() - t;
559
- return p.statSync(r).mtime.getTime() < l;
644
+ return c.statSync(r).mtime.getTime() < l;
560
645
  }
561
- async function wt(e, t) {
646
+ async function Pt(e, t) {
562
647
  const [r] = await new Promise(
563
648
  (s, o) => {
564
- Ye.list(
649
+ ze.list(
565
650
  {
566
651
  pid: e,
567
652
  name: t,
@@ -576,10 +661,10 @@ async function wt(e, t) {
576
661
  );
577
662
  return !!r && r.pid === e && r.command === t;
578
663
  }
579
- function gt(e) {
664
+ function St(e) {
580
665
  return process.env.CI === "true" || process.env.CI === "1" || process.env.GITHUB_ACTIONS === "true" || process.env.GITHUB_ACTIONS === "1" || (process.env.TERM || "").toLowerCase() === "dumb" ? !1 : e ? !!e.isTTY : process.stdout.isTTY;
581
666
  }
582
- class yt {
667
+ class xt {
583
668
  constructor(t) {
584
669
  this.lastProgressLine = "", this.progressActive = !1, this.verbosity = t.verbosity, this.writeStream = t.writeStream || process.stdout;
585
670
  }
@@ -593,7 +678,7 @@ class yt {
593
678
  * This prevents progress spam in logs - users only see the final outcome.
594
679
  */
595
680
  get shouldRender() {
596
- return gt(this.writeStream);
681
+ return St(this.writeStream);
597
682
  }
598
683
  get isQuiet() {
599
684
  return this.verbosity === "quiet";
@@ -645,7 +730,7 @@ ${t}
645
730
  `${this.dim("PHP")} ${this.cyan(t.phpVersion)} ${this.dim("WordPress")} ${this.cyan(t.wpVersion)}`
646
731
  );
647
732
  const s = [];
648
- if (t.intl && s.push("intl"), t.xdebug && s.push(this.yellow("xdebug")), s.length > 0 && r.push(`${this.dim("Extensions")} ${s.join(", ")}`), t.mounts.length > 0)
733
+ if (t.intl && s.push("intl"), t.redis && s.push("redis"), t.memcached && s.push("memcached"), t.xdebug && s.push(this.yellow("xdebug")), s.length > 0 && r.push(`${this.dim("Extensions")} ${s.join(", ")}`), t.mounts.length > 0)
649
734
  for (const o of t.mounts) {
650
735
  const i = o.autoMounted ? ` ${this.dim("(auto-mount)")}` : "";
651
736
  r.push(
@@ -732,12 +817,12 @@ ${this.green("Ready!")} WordPress is running on ${this.bold(t)} ${this.dim(`(${r
732
817
  `);
733
818
  }
734
819
  }
735
- const he = {
820
+ const fe = {
736
821
  Quiet: { name: "quiet", severity: j.Fatal },
737
822
  Normal: { name: "normal", severity: j.Info },
738
823
  Debug: { name: "debug", severity: j.Debug }
739
824
  };
740
- async function Jt(e) {
825
+ async function or(e) {
741
826
  try {
742
827
  const t = {
743
828
  "site-url": {
@@ -747,41 +832,62 @@ async function Jt(e) {
747
832
  php: {
748
833
  describe: "PHP version to use.",
749
834
  type: "string",
750
- default: U,
751
- choices: te
835
+ default: F,
836
+ choices: oe
752
837
  },
753
838
  wp: {
754
839
  describe: "WordPress version to use.",
755
840
  type: "string",
756
841
  default: "latest"
757
842
  },
843
+ define: {
844
+ describe: 'Define PHP string constants (can be used multiple times). Format: NAME value. These constants are set via php.defineConstant() and only exist for the current request. Examples: --define API_KEY secret --define CON=ST "va=lu=e"',
845
+ type: "string",
846
+ nargs: 2,
847
+ array: !0,
848
+ coerce: ot
849
+ },
850
+ "define-bool": {
851
+ describe: 'Define PHP boolean constants (can be used multiple times). Format: NAME value. Value must be "true", "false", "1", or "0". Examples: --define-bool WP_DEBUG true --define-bool MY_FEATURE false',
852
+ type: "string",
853
+ nargs: 2,
854
+ array: !0,
855
+ coerce: st
856
+ },
857
+ "define-number": {
858
+ describe: "Define PHP number constants (can be used multiple times). Format: NAME value. Examples: --define-number LIMIT 100 --define-number RATE 45.67",
859
+ type: "string",
860
+ nargs: 2,
861
+ array: !0,
862
+ coerce: it
863
+ },
758
864
  // @TODO: Support read-only mounts, e.g. via WORKERFS, a custom
759
865
  // ReadOnlyNODEFS, or by copying the files into MEMFS
760
866
  mount: {
761
867
  describe: "Mount a directory to the PHP runtime (can be used multiple times). Format: /host/path:/vfs/path",
762
868
  type: "array",
763
869
  string: !0,
764
- coerce: _
870
+ coerce: q
765
871
  },
766
872
  "mount-before-install": {
767
873
  describe: "Mount a directory to the PHP runtime before WordPress installation (can be used multiple times). Format: /host/path:/vfs/path",
768
874
  type: "array",
769
875
  string: !0,
770
- coerce: _
876
+ coerce: q
771
877
  },
772
878
  "mount-dir": {
773
879
  describe: 'Mount a directory to the PHP runtime (can be used multiple times). Format: "/host/path" "/vfs/path"',
774
880
  type: "array",
775
881
  nargs: 2,
776
882
  array: !0,
777
- coerce: se
883
+ coerce: ne
778
884
  },
779
885
  "mount-dir-before-install": {
780
886
  describe: 'Mount a directory before WordPress installation (can be used multiple times). Format: "/host/path" "/vfs/path"',
781
887
  type: "string",
782
888
  nargs: 2,
783
889
  array: !0,
784
- coerce: se
890
+ coerce: ne
785
891
  },
786
892
  login: {
787
893
  describe: "Should log the user in",
@@ -828,7 +934,7 @@ async function Jt(e) {
828
934
  verbosity: {
829
935
  describe: "Output logs and progress messages.",
830
936
  type: "string",
831
- choices: Object.values(he).map(
937
+ choices: Object.values(fe).map(
832
938
  (a) => a.name
833
939
  ),
834
940
  default: "normal"
@@ -867,6 +973,16 @@ Warning: Following symlinks will expose files outside mounted directories to Pla
867
973
  type: "boolean",
868
974
  default: !0
869
975
  },
976
+ redis: {
977
+ describe: "Enable Redis (requires JSPI support).",
978
+ type: "boolean"
979
+ // No default - will be determined at runtime based on JSPI availability
980
+ },
981
+ memcached: {
982
+ describe: "Enable Memcached.",
983
+ type: "boolean"
984
+ // No default - will be determined at runtime based on JSPI availability
985
+ },
870
986
  xdebug: {
871
987
  describe: "Enable Xdebug.",
872
988
  type: "boolean",
@@ -904,7 +1020,7 @@ Warning: Following symlinks will expose files outside mounted directories to Pla
904
1020
  "experimental-multi-worker": {
905
1021
  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.",
906
1022
  type: "number",
907
- coerce: (a) => a ?? Ce().length - 1
1023
+ coerce: (a) => a ?? De().length - 1
908
1024
  },
909
1025
  "experimental-devtools": {
910
1026
  describe: "Enable experimental browser development tools.",
@@ -919,8 +1035,8 @@ Warning: Following symlinks will expose files outside mounted directories to Pla
919
1035
  php: {
920
1036
  describe: "PHP version to use.",
921
1037
  type: "string",
922
- default: U,
923
- choices: te
1038
+ default: F,
1039
+ choices: oe
924
1040
  },
925
1041
  wp: {
926
1042
  describe: "WordPress version to use.",
@@ -966,7 +1082,7 @@ Warning: Following symlinks will expose files outside mounted directories to Pla
966
1082
  describe: "Mount a directory to the PHP runtime (can be used multiple times). Format: /host/path:/vfs/path. Use this for additional mounts beyond auto-detection.",
967
1083
  type: "array",
968
1084
  string: !0,
969
- coerce: _
1085
+ coerce: q
970
1086
  },
971
1087
  reset: {
972
1088
  describe: "Deletes the stored site directory and starts a new site from scratch.",
@@ -977,7 +1093,11 @@ Warning: Following symlinks will expose files outside mounted directories to Pla
977
1093
  describe: "Disable automatic project type detection. Use --mount to manually specify mounts instead.",
978
1094
  type: "boolean",
979
1095
  default: !1
980
- }
1096
+ },
1097
+ // Define constants
1098
+ define: t.define,
1099
+ "define-bool": t["define-bool"],
1100
+ "define-number": t["define-number"]
981
1101
  }, o = {
982
1102
  outfile: {
983
1103
  describe: "When building, write to this output file.",
@@ -1022,13 +1142,13 @@ Examples:
1022
1142
  ).demandCommand(1, "Please specify a command").strictCommands().conflicts(
1023
1143
  "experimental-unsafe-ide-integration",
1024
1144
  "experimental-devtools"
1025
- ).showHelpOnFail(!1).fail((a, f, c) => {
1026
- if (f)
1027
- throw f;
1028
- a && a.includes("Please specify a command") && (c.showHelp(), console.error(`
1145
+ ).showHelpOnFail(!1).fail((a, g, h) => {
1146
+ if (g)
1147
+ throw g;
1148
+ a && a.includes("Please specify a command") && (h.showHelp(), console.error(`
1029
1149
  ` + a), process.exit(1)), console.error(a), process.exit(1);
1030
1150
  }).strictOptions().check(async (a) => {
1031
- if (a["skip-wordpress-install"] === !0 && (a["wordpress-install-mode"] = "do-not-attempt-installing", a.wordpressInstallMode = "do-not-attempt-installing"), a.wp !== void 0 && typeof a.wp == "string" && !nt(a.wp))
1151
+ if (a["skip-wordpress-install"] === !0 && (a["wordpress-install-mode"] = "do-not-attempt-installing", a.wordpressInstallMode = "do-not-attempt-installing"), a.wp !== void 0 && typeof a.wp == "string" && !ct(a.wp))
1032
1152
  try {
1033
1153
  new URL(a.wp);
1034
1154
  } catch {
@@ -1036,25 +1156,25 @@ Examples:
1036
1156
  '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"'
1037
1157
  );
1038
1158
  }
1039
- const f = a["site-url"];
1040
- if (typeof f == "string" && f.trim() !== "")
1159
+ const g = a["site-url"];
1160
+ if (typeof g == "string" && g.trim() !== "")
1041
1161
  try {
1042
- new URL(f);
1162
+ new URL(g);
1043
1163
  } catch {
1044
1164
  throw new Error(
1045
- `Invalid site-url "${f}". Please provide a valid URL (e.g., http://localhost:8080 or https://example.com)`
1165
+ `Invalid site-url "${g}". Please provide a valid URL (e.g., http://localhost:8080 or https://example.com)`
1046
1166
  );
1047
1167
  }
1048
1168
  if (a["auto-mount"]) {
1049
- let c = !1;
1169
+ let h = !1;
1050
1170
  try {
1051
- c = p.statSync(
1171
+ h = c.statSync(
1052
1172
  a["auto-mount"]
1053
1173
  ).isDirectory();
1054
1174
  } catch {
1055
- c = !1;
1175
+ h = !1;
1056
1176
  }
1057
- if (!c)
1177
+ if (!h)
1058
1178
  throw new Error(
1059
1179
  `The specified --auto-mount path is not a directory: '${a["auto-mount"]}'.`
1060
1180
  );
@@ -1085,8 +1205,8 @@ Examples:
1085
1205
  );
1086
1206
  } else
1087
1207
  a["wordpress-install-mode"] === "do-not-attempt-installing" ? a.mode = "apply-to-existing-site" : a.mode = "create-new-site";
1088
- const c = a.allow || [];
1089
- a.followSymlinks === !0 && c.push("follow-symlinks"), a["blueprint-may-read-adjacent-files"] === !0 && c.push("read-local-fs"), a.allow = c;
1208
+ const h = a.allow || [];
1209
+ a.followSymlinks === !0 && h.push("follow-symlinks"), a["blueprint-may-read-adjacent-files"] === !0 && h.push("read-local-fs"), a.allow = h;
1090
1210
  } else if (a.mode !== void 0)
1091
1211
  throw new Error(
1092
1212
  "The --mode option requires the --experimentalBlueprintsV2Runner flag."
@@ -1098,8 +1218,11 @@ Examples:
1098
1218
  ["start", "run-blueprint", "server", "build-snapshot"].includes(
1099
1219
  l
1100
1220
  ) || (i.showHelp(), process.exit(1));
1101
- const u = {
1221
+ const u = n.define || {};
1222
+ !("WP_DEBUG" in u) && !("WP_DEBUG_LOG" in u) && !("WP_DEBUG_DISPLAY" in u) && (u.WP_DEBUG = "true", u.WP_DEBUG_LOG = "true", u.WP_DEBUG_DISPLAY = "true");
1223
+ const v = {
1102
1224
  ...n,
1225
+ define: u,
1103
1226
  command: l,
1104
1227
  mount: [
1105
1228
  ...n.mount || [],
@@ -1109,20 +1232,20 @@ Examples:
1109
1232
  ...n["mount-before-install"] || [],
1110
1233
  ...n["mount-dir-before-install"] || []
1111
1234
  ]
1112
- }, b = await St(u);
1113
- b === void 0 && process.exit(0);
1114
- const v = /* @__PURE__ */ (() => {
1235
+ }, P = await Et(v);
1236
+ P === void 0 && process.exit(0);
1237
+ const w = /* @__PURE__ */ (() => {
1115
1238
  let a;
1116
1239
  return async () => {
1117
- a !== void 0 && (a = b[Symbol.asyncDispose]()), await a, process.exit(0);
1240
+ a !== void 0 && (a = P[Symbol.asyncDispose]()), await a, process.exit(0);
1118
1241
  };
1119
1242
  })();
1120
- process.on("SIGINT", v), process.on("SIGTERM", v);
1243
+ process.on("SIGINT", w), process.on("SIGTERM", w);
1121
1244
  } catch (t) {
1122
1245
  if (console.error(t), !(t instanceof Error))
1123
1246
  throw t;
1124
1247
  if (process.argv.includes("--debug"))
1125
- ye(t);
1248
+ ve(t);
1126
1249
  else {
1127
1250
  const s = [];
1128
1251
  let o = t;
@@ -1136,73 +1259,75 @@ Examples:
1136
1259
  process.exit(1);
1137
1260
  }
1138
1261
  }
1139
- function ne(e, t) {
1262
+ function le(e, t) {
1140
1263
  return e.find(
1141
1264
  (r) => r.vfsPath.replace(/\/$/, "") === t.replace(/\/$/, "")
1142
1265
  );
1143
1266
  }
1144
- const bt = Symbol("playground-cli-testing"), T = (e) => process.stdout.isTTY ? "\x1B[1m" + e + "\x1B[0m" : e, vt = (e) => process.stdout.isTTY ? "\x1B[31m" + e + "\x1B[0m" : e, Pt = (e) => process.stdout.isTTY ? `\x1B[2m${e}\x1B[0m` : e, q = (e) => process.stdout.isTTY ? `\x1B[3m${e}\x1B[0m` : e, ae = (e) => process.stdout.isTTY ? `\x1B[33m${e}\x1B[0m` : e;
1145
- async function St(e) {
1267
+ const kt = Symbol("playground-cli-testing"), T = (e) => process.stdout.isTTY ? "\x1B[1m" + e + "\x1B[0m" : e, It = (e) => process.stdout.isTTY ? "\x1B[31m" + e + "\x1B[0m" : e, $t = (e) => process.stdout.isTTY ? `\x1B[2m${e}\x1B[0m` : e, Y = (e) => process.stdout.isTTY ? `\x1B[3m${e}\x1B[0m` : e, ue = (e) => process.stdout.isTTY ? `\x1B[33m${e}\x1B[0m` : e;
1268
+ async function Et(e) {
1146
1269
  let t, r;
1147
1270
  const s = /* @__PURE__ */ new Map();
1148
- if (e.command === "start" && (e = xt(e)), e.autoMount !== void 0 && (e.autoMount === "" && (e = { ...e, autoMount: process.cwd() }), e = de(e)), e.wordpressInstallMode === void 0 && (e.wordpressInstallMode = "download-and-install"), e.quiet && (e.verbosity = "quiet", delete e.quiet), e.debug && (e.verbosity = "debug", delete e.debug), e.verbosity) {
1149
- const a = Object.values(he).find(
1150
- (f) => f.name === e.verbosity
1271
+ if (e.command === "start" && (e = Tt(e)), e.autoMount !== void 0 && (e.autoMount === "" && (e = { ...e, autoMount: process.cwd() }), e = pe(e)), e.wordpressInstallMode === void 0 && (e.wordpressInstallMode = "download-and-install"), e.quiet && (e.verbosity = "quiet", delete e.quiet), e.debug && (e.verbosity = "debug", delete e.debug), e.verbosity) {
1272
+ const w = Object.values(fe).find(
1273
+ (a) => a.name === e.verbosity
1151
1274
  ).severity;
1152
- g.setSeverityFilterLevel(a);
1275
+ y.setSeverityFilterLevel(w);
1153
1276
  }
1154
- e.intl || (e.intl = !0);
1155
- const o = new yt({
1277
+ e.intl || (e.intl = !0), e.redis === void 0 && (e.redis = await Q()), e.memcached === void 0 && (e.memcached = await Q());
1278
+ const o = new xt({
1156
1279
  verbosity: e.verbosity || "normal"
1157
1280
  });
1158
1281
  e.command === "server" && (o.printBanner(), o.printConfig({
1159
- phpVersion: e.php || U,
1282
+ phpVersion: e.php || F,
1160
1283
  wpVersion: e.wp || "latest",
1161
1284
  port: e.port || 9400,
1162
1285
  xdebug: !!e.xdebug,
1163
1286
  intl: !!e.intl,
1287
+ redis: !!e.redis,
1288
+ memcached: !!e.memcached,
1164
1289
  mounts: [
1165
1290
  ...e.mount || [],
1166
1291
  ...e["mount-before-install"] || []
1167
1292
  ],
1168
1293
  blueprint: typeof e.blueprint == "string" ? e.blueprint : void 0
1169
1294
  }));
1170
- const i = e.command === "server" ? e.port ?? 9400 : 0, n = O.platform() === "win32" ? (
1295
+ const i = e.command === "server" ? e.port ?? 9400 : 0, n = N.platform() === "win32" ? (
1171
1296
  // @TODO: Enable fs-ext here when it works with Windows.
1172
1297
  void 0
1173
- ) : await import("fs-ext").then((a) => a.flockSync).catch(() => {
1174
- g.debug(
1298
+ ) : await import("fs-ext").then((w) => w.flockSync).catch(() => {
1299
+ y.debug(
1175
1300
  "The fs-ext package is not installed. Internal file locking will not be integrated with host OS file locking."
1176
1301
  );
1177
1302
  }), l = new Le(n);
1178
- let u = !1, b = !0;
1179
- const v = await rt({
1303
+ let u = !1, v = !0;
1304
+ const P = await at({
1180
1305
  port: i,
1181
- onBind: async (a, f) => {
1182
- const c = "127.0.0.1", S = `http://${c}:${f}`, E = e["site-url"] || S, k = e.command === "server" ? e.experimentalMultiWorker ?? 1 : 1, W = e.command === "server" ? (
1306
+ onBind: async (w, a) => {
1307
+ const g = "127.0.0.1", h = `http://${g}:${a}`, k = e["site-url"] || h, I = e.command === "server" ? e.experimentalMultiWorker ?? 1 : 1, C = e.command === "server" ? (
1183
1308
  // Account for the initial worker which is discarded by the server after setup.
1184
- k + 1
1185
- ) : k, C = 2 ** 31 - 1, L = Math.floor(
1186
- C / W
1187
- ), G = "-playground-cli-site-", I = await ct(G);
1188
- g.debug(`Native temp dir for VFS root: ${I.path}`);
1189
- const M = "WP Playground CLI - Listen for Xdebug", J = ".playground-xdebug-root", K = h.join(process.cwd(), J);
1190
- if (await ze(K), e.xdebug && e.experimentalUnsafeIdeIntegration) {
1309
+ I + 1
1310
+ ) : I, L = 2 ** 31 - 1, M = Math.floor(
1311
+ L / C
1312
+ ), K = "-playground-cli-site-", $ = await gt(K);
1313
+ y.debug(`Native temp dir for VFS root: ${$.path}`);
1314
+ const W = "WP Playground CLI - Listen for Xdebug", ee = ".playground-xdebug-root", te = p.join(process.cwd(), ee);
1315
+ if (await Ge(te), e.xdebug && e.experimentalUnsafeIdeIntegration) {
1191
1316
  await Qe(
1192
- I.path,
1193
- K,
1317
+ $.path,
1318
+ te,
1194
1319
  process.platform
1195
1320
  );
1196
1321
  const d = {
1197
- hostPath: h.join(".", h.sep, J),
1322
+ hostPath: p.join(".", p.sep, ee),
1198
1323
  vfsPath: "/"
1199
1324
  };
1200
1325
  try {
1201
- await Xe(M, process.cwd());
1202
- const w = typeof e.xdebug == "object" ? e.xdebug : void 0, P = await Ze({
1203
- name: M,
1204
- host: c,
1205
- port: f,
1326
+ await Xe(W, process.cwd());
1327
+ const f = typeof e.xdebug == "object" ? e.xdebug : void 0, S = await Ze({
1328
+ name: W,
1329
+ host: g,
1330
+ port: a,
1206
1331
  ides: e.experimentalUnsafeIdeIntegration,
1207
1332
  cwd: process.cwd(),
1208
1333
  mounts: [
@@ -1210,19 +1335,19 @@ async function St(e) {
1210
1335
  ...e["mount-before-install"] || [],
1211
1336
  ...e.mount || []
1212
1337
  ],
1213
- ideKey: w?.ideKey
1214
- }), m = e.experimentalUnsafeIdeIntegration, y = m.includes("vscode"), x = m.includes("phpstorm"), D = Object.values(P);
1215
- console.log(""), D.length > 0 ? (console.log(T("Xdebug configured successfully")), console.log(
1216
- ae("Updated IDE config: ") + D.join(" ")
1338
+ ideKey: f?.ideKey
1339
+ }), m = e.experimentalUnsafeIdeIntegration, b = m.includes("vscode"), x = m.includes("phpstorm"), R = Object.values(S);
1340
+ console.log(""), R.length > 0 ? (console.log(T("Xdebug configured successfully")), console.log(
1341
+ ue("Updated IDE config: ") + R.join(" ")
1217
1342
  ), console.log(
1218
- ae("Playground source root: ") + ".playground-xdebug-root" + q(
1219
- Pt(
1343
+ ue("Playground source root: ") + ".playground-xdebug-root" + Y(
1344
+ $t(
1220
1345
  " – you can set breakpoints and preview Playground's VFS structure in there."
1221
1346
  )
1222
1347
  )
1223
1348
  )) : (console.log(T("Xdebug configuration failed.")), console.log(
1224
1349
  "No IDE-specific project settings directory was found in the current working directory."
1225
- )), console.log(""), y && P.vscode && (console.log(T("VS Code / Cursor instructions:")), console.log(
1350
+ )), console.log(""), b && S.vscode && (console.log(T("VS Code / Cursor instructions:")), console.log(
1226
1351
  " 1. Ensure you have installed an IDE extension for PHP Debugging"
1227
1352
  ), console.log(
1228
1353
  ` (The ${T("PHP Debug")} extension by ${T(
@@ -1231,37 +1356,37 @@ async function St(e) {
1231
1356
  ), console.log(
1232
1357
  " 2. Open the Run and Debug panel on the left sidebar"
1233
1358
  ), console.log(
1234
- ` 3. Select "${q(
1235
- M
1359
+ ` 3. Select "${Y(
1360
+ W
1236
1361
  )}" from the dropdown`
1237
1362
  ), console.log(' 3. Click "start debugging"'), console.log(
1238
1363
  " 5. Set a breakpoint. For example, in .playground-xdebug-root/wordpress/index.php"
1239
1364
  ), console.log(
1240
1365
  " 6. Visit Playground in your browser to hit the breakpoint"
1241
- ), x && console.log("")), x && P.phpstorm && (console.log(T("PhpStorm instructions:")), console.log(
1242
- ` 1. Choose "${q(
1243
- M
1366
+ ), x && console.log("")), x && S.phpstorm && (console.log(T("PhpStorm instructions:")), console.log(
1367
+ ` 1. Choose "${Y(
1368
+ W
1244
1369
  )}" debug configuration in the toolbar`
1245
1370
  ), console.log(" 2. Click the debug button (bug icon)`"), console.log(
1246
1371
  " 3. Set a breakpoint. For example, in .playground-xdebug-root/wordpress/index.php"
1247
1372
  ), console.log(
1248
1373
  " 4. Visit Playground in your browser to hit the breakpoint"
1249
1374
  )), console.log("");
1250
- } catch (w) {
1375
+ } catch (f) {
1251
1376
  throw new Error("Could not configure Xdebug", {
1252
- cause: w
1377
+ cause: f
1253
1378
  });
1254
1379
  }
1255
1380
  }
1256
- const me = h.dirname(I.path), fe = 2 * 24 * 60 * 60 * 1e3;
1257
- ht(
1258
- G,
1259
- fe,
1260
- me
1381
+ const we = p.dirname($.path), ge = 2 * 24 * 60 * 60 * 1e3;
1382
+ yt(
1383
+ K,
1384
+ ge,
1385
+ we
1261
1386
  );
1262
- const H = h.join(I.path, "internal");
1263
- z(H);
1264
- const we = [
1387
+ const _ = p.join($.path, "internal");
1388
+ G(_);
1389
+ const ye = [
1265
1390
  "wordpress",
1266
1391
  // Note: These dirs are from Emscripten's "default dirs" list:
1267
1392
  // https://github.com/emscripten-core/emscripten/blob/f431ec220e472e1f8d3db6b52fe23fb377facf30/src/lib/libfs.js#L1400-L1402
@@ -1272,14 +1397,14 @@ async function St(e) {
1272
1397
  "tmp",
1273
1398
  "home"
1274
1399
  ];
1275
- for (const d of we) {
1276
- const w = (m) => m.vfsPath === `/${d}`;
1277
- if (!(e["mount-before-install"]?.some(w) || e.mount?.some(w))) {
1278
- const m = h.join(
1279
- I.path,
1400
+ for (const d of ye) {
1401
+ const f = (m) => m.vfsPath === `/${d}`;
1402
+ if (!(e["mount-before-install"]?.some(f) || e.mount?.some(f))) {
1403
+ const m = p.join(
1404
+ $.path,
1280
1405
  d
1281
1406
  );
1282
- z(m), e["mount-before-install"] === void 0 && (e["mount-before-install"] = []), e["mount-before-install"].unshift({
1407
+ G(m), e["mount-before-install"] === void 0 && (e["mount-before-install"] = []), e["mount-before-install"].unshift({
1283
1408
  vfsPath: `/${d}`,
1284
1409
  hostPath: m
1285
1410
  });
@@ -1287,144 +1412,144 @@ async function St(e) {
1287
1412
  }
1288
1413
  if (e["mount-before-install"])
1289
1414
  for (const d of e["mount-before-install"])
1290
- g.debug(
1415
+ y.debug(
1291
1416
  `Mount before WP install: ${d.vfsPath} -> ${d.hostPath}`
1292
1417
  );
1293
1418
  if (e.mount)
1294
1419
  for (const d of e.mount)
1295
- g.debug(
1420
+ y.debug(
1296
1421
  `Mount after WP install: ${d.vfsPath} -> ${d.hostPath}`
1297
1422
  );
1298
- let $;
1299
- e["experimental-blueprints-v2-runner"] ? $ = new lt(e, {
1300
- siteUrl: E,
1301
- processIdSpaceLength: L,
1423
+ let E;
1424
+ e["experimental-blueprints-v2-runner"] ? E = new mt(e, {
1425
+ siteUrl: k,
1426
+ processIdSpaceLength: M,
1302
1427
  cliOutput: o
1303
- }) : ($ = new pt(e, {
1304
- siteUrl: E,
1305
- processIdSpaceLength: L,
1428
+ }) : (E = new wt(e, {
1429
+ siteUrl: k,
1430
+ processIdSpaceLength: M,
1306
1431
  cliOutput: o
1307
- }), typeof e.blueprint == "string" && (e.blueprint = await at({
1432
+ }), typeof e.blueprint == "string" && (e.blueprint = await pt({
1308
1433
  sourceString: e.blueprint,
1309
1434
  blueprintMayReadAdjacentFiles: e["blueprint-may-read-adjacent-files"] === !0
1310
1435
  })));
1311
- let V = !1;
1312
- const R = async function() {
1313
- V || (V = !0, await Promise.all(
1436
+ let H = !1;
1437
+ const D = async function() {
1438
+ H || (H = !0, await Promise.all(
1314
1439
  [...s].map(
1315
- async ([w, P]) => {
1316
- await P.dispose(), await w.terminate();
1440
+ async ([f, S]) => {
1441
+ await S.dispose(), await f.terminate();
1317
1442
  }
1318
1443
  )
1319
- ), a && await new Promise((w) => a.close(w)), await I.cleanup());
1320
- }, ge = kt(
1321
- W,
1322
- $.getWorkerType(),
1323
- ({ exitCode: d, workerIndex: w }) => {
1324
- V || d === 0 && g.error(
1325
- `Worker ${w} exited with code ${d}
1444
+ ), w && await new Promise((f) => w.close(f)), await $.cleanup());
1445
+ }, be = Bt(
1446
+ C,
1447
+ E.getWorkerType(),
1448
+ ({ exitCode: d, workerIndex: f }) => {
1449
+ H || d === 0 && y.error(
1450
+ `Worker ${f} exited with code ${d}
1326
1451
  `
1327
1452
  );
1328
1453
  }
1329
1454
  );
1330
1455
  o.startProgress("Starting...");
1331
1456
  try {
1332
- const d = await ge, w = await le(l);
1457
+ const d = await be, f = await de(l);
1333
1458
  {
1334
- const m = d.shift(), y = await $.bootAndSetUpInitialPlayground(
1459
+ const m = d.shift(), b = await E.bootAndSetUpInitialPlayground(
1335
1460
  m.phpPort,
1336
- w,
1337
- H
1461
+ f,
1462
+ _
1338
1463
  );
1339
1464
  if (s.set(
1340
1465
  m.worker,
1341
- y
1342
- ), await y.isReady(), u = !0, t = new it(y), !e["experimental-blueprints-v2-runner"]) {
1343
- const x = await $.compileInputBlueprint(
1466
+ b
1467
+ ), await b.isReady(), u = !0, t = new dt(b), !e["experimental-blueprints-v2-runner"]) {
1468
+ const x = await E.compileInputBlueprint(
1344
1469
  e["additional-blueprint-steps"] || []
1345
1470
  );
1346
- x && await ke(
1471
+ x && await $e(
1347
1472
  x,
1348
- y
1473
+ b
1349
1474
  );
1350
1475
  }
1351
1476
  if (e.command === "build-snapshot") {
1352
- await Tt(r, e.outfile), o.printStatus(`Exported to ${e.outfile}`), await R();
1477
+ await Lt(r, e.outfile), o.printStatus(`Exported to ${e.outfile}`), await D();
1353
1478
  return;
1354
1479
  } else if (e.command === "run-blueprint") {
1355
- o.finishProgress("Done"), await R();
1480
+ o.finishProgress("Done"), await D();
1356
1481
  return;
1357
1482
  }
1358
- await t.removeWorker(y), await y.dispose(), await m.worker.terminate(), s.delete(m.worker);
1483
+ await t.removeWorker(b), await b.dispose(), await m.worker.terminate(), s.delete(m.worker);
1359
1484
  }
1360
- const P = L;
1485
+ const S = M;
1361
1486
  return [r] = await Promise.all(
1362
- d.map(async (m, y) => {
1363
- const x = P + y * L, D = await le(l), N = await $.bootPlayground({
1487
+ d.map(async (m, b) => {
1488
+ const x = S + b * M, R = await de(l), V = await E.bootPlayground({
1364
1489
  worker: m,
1365
- fileLockManagerPort: D,
1490
+ fileLockManagerPort: R,
1366
1491
  firstProcessId: x,
1367
- nativeInternalDirPath: H
1492
+ nativeInternalDirPath: _
1368
1493
  });
1369
1494
  return s.set(
1370
1495
  m.worker,
1371
- N
1372
- ), t.addWorker(N), N;
1496
+ V
1497
+ ), t.addWorker(V), V;
1373
1498
  })
1374
- ), o.finishProgress(), o.printReady(S, k), e.xdebug && e.experimentalDevtools && (await Ne({
1499
+ ), o.finishProgress(), o.printReady(h, I), e.xdebug && e.experimentalDevtools && (await Ve({
1375
1500
  phpInstance: r,
1376
1501
  phpRoot: "/wordpress"
1377
1502
  })).start(), {
1378
1503
  playground: r,
1379
- server: a,
1380
- serverUrl: S,
1381
- [Symbol.asyncDispose]: R,
1382
- [bt]: {
1383
- workerThreadCount: k,
1384
- getWorkerNumberFromProcessId: (m) => Math.floor(m / L)
1504
+ server: w,
1505
+ serverUrl: h,
1506
+ [Symbol.asyncDispose]: D,
1507
+ [kt]: {
1508
+ workerThreadCount: I,
1509
+ getWorkerNumberFromProcessId: (m) => Math.floor(m / M)
1385
1510
  }
1386
1511
  };
1387
1512
  } catch (d) {
1388
1513
  if (e.verbosity !== "debug")
1389
1514
  throw d;
1390
- let w = "";
1391
- throw await r?.fileExists(ee) && (w = await r.readFileAsText(ee)), await R(), new Error(w, { cause: d });
1515
+ let f = "";
1516
+ throw await r?.fileExists(re) && (f = await r.readFileAsText(re)), await D(), new Error(f, { cause: d });
1392
1517
  }
1393
1518
  },
1394
- async handleRequest(a) {
1519
+ async handleRequest(w) {
1395
1520
  if (!u)
1396
- return Y.forHttpCode(
1521
+ return z.forHttpCode(
1397
1522
  502,
1398
1523
  "WordPress is not ready yet"
1399
1524
  );
1400
- if (b) {
1401
- b = !1;
1402
- const f = {
1525
+ if (v) {
1526
+ v = !1;
1527
+ const a = {
1403
1528
  "Content-Type": ["text/plain"],
1404
1529
  "Content-Length": ["0"],
1405
- Location: [a.url]
1530
+ Location: [w.url]
1406
1531
  };
1407
- return a.headers?.cookie?.includes(
1532
+ return w.headers?.cookie?.includes(
1408
1533
  "playground_auto_login_already_happened"
1409
- ) && (f["Set-Cookie"] = [
1534
+ ) && (a["Set-Cookie"] = [
1410
1535
  "playground_auto_login_already_happened=1; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=/"
1411
- ]), new Y(302, f, new Uint8Array());
1536
+ ]), new z(302, a, new Uint8Array());
1412
1537
  }
1413
- return await t.handleRequest(a);
1538
+ return await t.handleRequest(w);
1414
1539
  }
1415
1540
  });
1416
- return v && e.command === "start" && !e.skipBrowser && $t(v.serverUrl), v;
1541
+ return P && e.command === "start" && !e.skipBrowser && Ct(P.serverUrl), P;
1417
1542
  }
1418
- function xt(e) {
1543
+ function Tt(e) {
1419
1544
  let t = { ...e, command: "server" };
1420
- e.noAutoMount || (t.autoMount = h.resolve(process.cwd(), t.path ?? ""), t = de(t), delete t.autoMount);
1421
- const r = ne(
1545
+ e.noAutoMount || (t.autoMount = p.resolve(process.cwd(), t.path ?? ""), t = pe(t), delete t.autoMount);
1546
+ const r = le(
1422
1547
  t["mount-before-install"] || [],
1423
1548
  "/wordpress"
1424
- ) || ne(t.mount || [], "/wordpress");
1549
+ ) || le(t.mount || [], "/wordpress");
1425
1550
  if (r)
1426
1551
  console.log("Site files stored at:", r?.hostPath), e.reset && (console.log(""), console.log(
1427
- vt(
1552
+ It(
1428
1553
  "This site is not managed by Playground CLI and cannot be reset."
1429
1554
  )
1430
1555
  ), console.log(
@@ -1433,15 +1558,15 @@ function xt(e) {
1433
1558
  "You may still remove the site's directory manually if you wish."
1434
1559
  ), process.exit(1));
1435
1560
  else {
1436
- const s = t.autoMount || process.cwd(), o = Ge("sha256").update(s).digest("hex"), i = O.homedir(), n = h.join(
1561
+ const s = t.autoMount || process.cwd(), o = Je("sha256").update(s).digest("hex"), i = N.homedir(), n = p.join(
1437
1562
  i,
1438
1563
  ".wordpress-playground/sites",
1439
1564
  o
1440
1565
  );
1441
- console.log("Site files stored at:", n), X(n) && e.reset && (console.log("Resetting site..."), $e(n, { recursive: !0 })), z(n, { recursive: !0 }), t["mount-before-install"] = [
1566
+ console.log("Site files stored at:", n), Z(n) && e.reset && (console.log("Resetting site..."), Te(n, { recursive: !0 })), G(n, { recursive: !0 }), t["mount-before-install"] = [
1442
1567
  ...t["mount-before-install"] || [],
1443
1568
  { vfsPath: "/wordpress", hostPath: n }
1444
- ], t.wordpressInstallMode = Te(n).length === 0 ? (
1569
+ ], t.wordpressInstallMode = Be(n).length === 0 ? (
1445
1570
  // Only download WordPress on the first run when the site directory is still
1446
1571
  // empty.
1447
1572
  "download-and-install"
@@ -1452,10 +1577,10 @@ function xt(e) {
1452
1577
  }
1453
1578
  return t;
1454
1579
  }
1455
- async function kt(e, t, r) {
1580
+ async function Bt(e, t, r) {
1456
1581
  const s = [];
1457
1582
  for (let o = 0; o < e; o++) {
1458
- const n = It(t, { onExit: (l) => {
1583
+ const n = Mt(t, { onExit: (l) => {
1459
1584
  r({
1460
1585
  exitCode: l,
1461
1586
  workerIndex: o
@@ -1465,9 +1590,9 @@ async function kt(e, t, r) {
1465
1590
  }
1466
1591
  return Promise.all(s);
1467
1592
  }
1468
- function It(e, { onExit: t } = {}) {
1593
+ function Mt(e, { onExit: t } = {}) {
1469
1594
  let r;
1470
- return e === "v1" ? r = new oe(new URL("./worker-thread-v1.js", import.meta.url)) : r = new oe(new URL("./worker-thread-v2.js", import.meta.url)), new Promise((s, o) => {
1595
+ return e === "v1" ? r = new ie(new URL("./worker-thread-v1.js", import.meta.url)) : r = new ie(new URL("./worker-thread-v2.js", import.meta.url)), new Promise((s, o) => {
1471
1596
  r.once("message", function(n) {
1472
1597
  n.command === "worker-script-initialized" && s({ worker: r, phpPort: n.phpPort });
1473
1598
  }), r.once("error", function(n) {
@@ -1485,12 +1610,12 @@ function It(e, { onExit: t } = {}) {
1485
1610
  });
1486
1611
  });
1487
1612
  }
1488
- async function le(e) {
1489
- const { port1: t, port2: r } = new Be();
1490
- return await Me() ? be(e, null, t) : await ve(e, t), r;
1613
+ async function de(e) {
1614
+ const { port1: t, port2: r } = new Me();
1615
+ return await Q() ? Pe(e, null, t) : await Se(e, t), r;
1491
1616
  }
1492
- function $t(e) {
1493
- const t = O.platform();
1617
+ function Ct(e) {
1618
+ const t = N.platform();
1494
1619
  let r;
1495
1620
  switch (t) {
1496
1621
  case "darwin":
@@ -1504,10 +1629,10 @@ function $t(e) {
1504
1629
  break;
1505
1630
  }
1506
1631
  je(r, (s) => {
1507
- s && g.debug(`Could not open browser: ${s.message}`);
1632
+ s && y.debug(`Could not open browser: ${s.message}`);
1508
1633
  });
1509
1634
  }
1510
- async function Tt(e, t) {
1635
+ async function Lt(e, t) {
1511
1636
  await e.run({
1512
1637
  code: `<?php
1513
1638
  $zip = new ZipArchive();
@@ -1529,15 +1654,16 @@ async function Tt(e, t) {
1529
1654
  `
1530
1655
  });
1531
1656
  const r = await e.readFileAsBuffer("/tmp/build.zip");
1532
- p.writeFileSync(t, r);
1657
+ c.writeFileSync(t, r);
1533
1658
  }
1534
1659
  export {
1535
- he as L,
1536
- gt as a,
1537
- bt as i,
1538
- Gt as m,
1539
- Jt as p,
1540
- St as r,
1541
- It as s
1660
+ fe as L,
1661
+ rr as a,
1662
+ St as b,
1663
+ kt as i,
1664
+ O as m,
1665
+ or as p,
1666
+ Et as r,
1667
+ Mt as s
1542
1668
  };
1543
- //# sourceMappingURL=run-cli-NcKUE5gJ.js.map
1669
+ //# sourceMappingURL=run-cli-BK0MGgcU.js.map