@php-wasm/universal 0.7.19 → 0.9.2

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/index.js CHANGED
@@ -1,29 +1,29 @@
1
- var Q = (e, t, r) => {
2
- if (!t.has(e))
1
+ var Y = (t, e, r) => {
2
+ if (!e.has(t))
3
3
  throw TypeError("Cannot " + r);
4
4
  };
5
- var u = (e, t, r) => (Q(e, t, "read from private field"), r ? r.call(e) : t.get(e)), h = (e, t, r) => {
6
- if (t.has(e))
5
+ var u = (t, e, r) => (Y(t, e, "read from private field"), r ? r.call(t) : e.get(t)), p = (t, e, r) => {
6
+ if (e.has(t))
7
7
  throw TypeError("Cannot add the same private member more than once");
8
- t instanceof WeakSet ? t.add(e) : t.set(e, r);
9
- }, d = (e, t, r, s) => (Q(e, t, "write to private field"), s ? s.call(e, r) : t.set(e, r), r);
10
- var p = (e, t, r) => (Q(e, t, "access private method"), r);
8
+ e instanceof WeakSet ? e.add(t) : e.set(t, r);
9
+ }, f = (t, e, r, s) => (Y(t, e, "write to private field"), s ? s.call(t, r) : e.set(t, r), r);
10
+ var h = (t, e, r) => (Y(t, e, "access private method"), r);
11
11
  const currentJsRuntime$1 = function() {
12
- var e;
13
- return typeof process < "u" && ((e = process.release) == null ? void 0 : e.name) === "node" ? "NODE" : typeof window < "u" ? "WEB" : (
12
+ var t;
13
+ return typeof process < "u" && ((t = process.release) == null ? void 0 : t.name) === "node" ? "NODE" : typeof window < "u" ? "WEB" : (
14
14
  // @ts-ignore
15
15
  typeof WorkerGlobalScope < "u" && // @ts-ignore
16
16
  self instanceof WorkerGlobalScope ? "WORKER" : "NODE"
17
17
  );
18
18
  }();
19
19
  if (currentJsRuntime$1 === "NODE") {
20
- let e = function(r) {
20
+ let t = function(r) {
21
21
  return new Promise(function(s, n) {
22
22
  r.onload = r.onerror = function(i) {
23
23
  r.onload = r.onerror = null, i.type === "load" ? s(r.result) : n(new Error("Failed to read the blob/file"));
24
24
  };
25
25
  });
26
- }, t = function() {
26
+ }, e = function() {
27
27
  const r = new Uint8Array([1, 2, 3, 4]), n = new File([r], "test").stream();
28
28
  try {
29
29
  return n.getReader({ mode: "byob" }), !0;
@@ -35,19 +35,19 @@ if (currentJsRuntime$1 === "NODE") {
35
35
  class r extends Blob {
36
36
  constructor(n, i, o) {
37
37
  super(n);
38
- let a;
39
- o != null && o.lastModified && (a = /* @__PURE__ */ new Date()), (!a || isNaN(a.getFullYear())) && (a = /* @__PURE__ */ new Date()), this.lastModifiedDate = a, this.lastModified = a.getMilliseconds(), this.name = i || "";
38
+ let l;
39
+ o != null && o.lastModified && (l = /* @__PURE__ */ new Date()), (!l || isNaN(l.getFullYear())) && (l = /* @__PURE__ */ new Date()), this.lastModifiedDate = l, this.lastModified = l.getMilliseconds(), this.name = i || "";
40
40
  }
41
41
  }
42
42
  global.File = r;
43
43
  }
44
44
  typeof Blob.prototype.arrayBuffer > "u" && (Blob.prototype.arrayBuffer = function() {
45
45
  const s = new FileReader();
46
- return s.readAsArrayBuffer(this), e(s);
46
+ return s.readAsArrayBuffer(this), t(s);
47
47
  }), typeof Blob.prototype.text > "u" && (Blob.prototype.text = function() {
48
48
  const s = new FileReader();
49
- return s.readAsText(this), e(s);
50
- }), (typeof Blob.prototype.stream > "u" || !t()) && (Blob.prototype.stream = function() {
49
+ return s.readAsText(this), t(s);
50
+ }), (typeof Blob.prototype.stream > "u" || !e()) && (Blob.prototype.stream = function() {
51
51
  let r = 0;
52
52
  const s = this;
53
53
  return new ReadableStream({
@@ -56,93 +56,178 @@ if (currentJsRuntime$1 === "NODE") {
56
56
  // this if needed.
57
57
  autoAllocateChunkSize: 512 * 1024,
58
58
  async pull(n) {
59
- const i = n.byobRequest.view, a = await s.slice(
59
+ const i = n.byobRequest.view, l = await s.slice(
60
60
  r,
61
61
  r + i.byteLength
62
- ).arrayBuffer(), l = new Uint8Array(a);
63
- new Uint8Array(i.buffer).set(l);
64
- const c = l.byteLength;
65
- n.byobRequest.respond(c), r += c, r >= s.size && n.close();
62
+ ).arrayBuffer(), c = new Uint8Array(l);
63
+ new Uint8Array(i.buffer).set(c);
64
+ const a = c.byteLength;
65
+ n.byobRequest.respond(a), r += a, r >= s.size && n.close();
66
66
  }
67
67
  });
68
68
  });
69
69
  }
70
70
  if (currentJsRuntime$1 === "NODE" && typeof CustomEvent > "u") {
71
- class e extends Event {
71
+ class t extends Event {
72
72
  constructor(r, s = {}) {
73
73
  super(r, s), this.detail = s.detail;
74
74
  }
75
75
  initCustomEvent() {
76
76
  }
77
77
  }
78
- globalThis.CustomEvent = e;
78
+ globalThis.CustomEvent = t;
79
79
  }
80
- const kError = Symbol("error"), kMessage = Symbol("message");
81
- class ErrorEvent2 extends Event {
82
- /**
83
- * Create a new `ErrorEvent`.
84
- *
85
- * @param type The name of the event
86
- * @param options A dictionary object that allows for setting
87
- * attributes via object members of the same name.
88
- */
89
- constructor(t, r = {}) {
90
- super(t), this[kError] = r.error === void 0 ? null : r.error, this[kMessage] = r.message === void 0 ? "" : r.message;
91
- }
92
- get error() {
93
- return this[kError];
94
- }
95
- get message() {
96
- return this[kMessage];
97
- }
80
+ const FileErrorCodes = {
81
+ 0: "No error occurred. System call completed successfully.",
82
+ 1: "Argument list too long.",
83
+ 2: "Permission denied.",
84
+ 3: "Address in use.",
85
+ 4: "Address not available.",
86
+ 5: "Address family not supported.",
87
+ 6: "Resource unavailable, or operation would block.",
88
+ 7: "Connection already in progress.",
89
+ 8: "Bad file descriptor.",
90
+ 9: "Bad message.",
91
+ 10: "Device or resource busy.",
92
+ 11: "Operation canceled.",
93
+ 12: "No child processes.",
94
+ 13: "Connection aborted.",
95
+ 14: "Connection refused.",
96
+ 15: "Connection reset.",
97
+ 16: "Resource deadlock would occur.",
98
+ 17: "Destination address required.",
99
+ 18: "Mathematics argument out of domain of function.",
100
+ 19: "Reserved.",
101
+ 20: "File exists.",
102
+ 21: "Bad address.",
103
+ 22: "File too large.",
104
+ 23: "Host is unreachable.",
105
+ 24: "Identifier removed.",
106
+ 25: "Illegal byte sequence.",
107
+ 26: "Operation in progress.",
108
+ 27: "Interrupted function.",
109
+ 28: "Invalid argument.",
110
+ 29: "I/O error.",
111
+ 30: "Socket is connected.",
112
+ 31: "There is a directory under that path.",
113
+ 32: "Too many levels of symbolic links.",
114
+ 33: "File descriptor value too large.",
115
+ 34: "Too many links.",
116
+ 35: "Message too large.",
117
+ 36: "Reserved.",
118
+ 37: "Filename too long.",
119
+ 38: "Network is down.",
120
+ 39: "Connection aborted by network.",
121
+ 40: "Network unreachable.",
122
+ 41: "Too many files open in system.",
123
+ 42: "No buffer space available.",
124
+ 43: "No such device.",
125
+ 44: "There is no such file or directory OR the parent directory does not exist.",
126
+ 45: "Executable file format error.",
127
+ 46: "No locks available.",
128
+ 47: "Reserved.",
129
+ 48: "Not enough space.",
130
+ 49: "No message of the desired type.",
131
+ 50: "Protocol not available.",
132
+ 51: "No space left on device.",
133
+ 52: "Function not supported.",
134
+ 53: "The socket is not connected.",
135
+ 54: "Not a directory or a symbolic link to a directory.",
136
+ 55: "Directory not empty.",
137
+ 56: "State not recoverable.",
138
+ 57: "Not a socket.",
139
+ 58: "Not supported, or operation not supported on socket.",
140
+ 59: "Inappropriate I/O control operation.",
141
+ 60: "No such device or address.",
142
+ 61: "Value too large to be stored in data type.",
143
+ 62: "Previous owner died.",
144
+ 63: "Operation not permitted.",
145
+ 64: "Broken pipe.",
146
+ 65: "Protocol error.",
147
+ 66: "Protocol not supported.",
148
+ 67: "Protocol wrong type for socket.",
149
+ 68: "Result too large.",
150
+ 69: "Read-only file system.",
151
+ 70: "Invalid seek.",
152
+ 71: "No such process.",
153
+ 72: "Reserved.",
154
+ 73: "Connection timed out.",
155
+ 74: "Text file busy.",
156
+ 75: "Cross-device link.",
157
+ 76: "Extension: Capabilities insufficient."
158
+ };
159
+ function getEmscriptenFsError(t) {
160
+ const e = typeof t == "object" ? t == null ? void 0 : t.errno : null;
161
+ if (e in FileErrorCodes)
162
+ return FileErrorCodes[e];
98
163
  }
99
- Object.defineProperty(ErrorEvent2.prototype, "error", { enumerable: !0 });
100
- Object.defineProperty(ErrorEvent2.prototype, "message", { enumerable: !0 });
101
- const ErrorEvent = typeof globalThis.ErrorEvent == "function" ? globalThis.ErrorEvent : ErrorEvent2;
102
- function isExitCodeZero(e) {
103
- return e instanceof Error ? "exitCode" in e && (e == null ? void 0 : e.exitCode) === 0 || (e == null ? void 0 : e.name) === "ExitStatus" && "status" in e && e.status === 0 : !1;
164
+ function rethrowFileSystemError(t = "") {
165
+ return function(r, s, n) {
166
+ const i = n.value;
167
+ n.value = function(...o) {
168
+ try {
169
+ return i.apply(this, o);
170
+ } catch (l) {
171
+ const c = typeof l == "object" ? l == null ? void 0 : l.errno : null;
172
+ if (c in FileErrorCodes) {
173
+ const a = FileErrorCodes[c], d = typeof o[1] == "string" ? o[1] : null, m = d !== null ? t.replaceAll("{path}", d) : t;
174
+ throw new Error(`${m}: ${a}`, {
175
+ cause: l
176
+ });
177
+ }
178
+ throw l;
179
+ }
180
+ };
181
+ };
104
182
  }
105
- const logToConsole = (e, ...t) => {
106
- switch (e.severity) {
183
+ const logEventType = "playground-log", logEvent = (t, ...e) => {
184
+ logger.dispatchEvent(
185
+ new CustomEvent(logEventType, {
186
+ detail: {
187
+ log: t,
188
+ args: e
189
+ }
190
+ })
191
+ );
192
+ }, logToConsole = (t, ...e) => {
193
+ switch (typeof t.message == "string" ? t.message = prepareLogMessage(t.message) : t.message.message && typeof t.message.message == "string" && (t.message.message = prepareLogMessage(t.message.message)), t.severity) {
107
194
  case "Debug":
108
- console.debug(e.message, ...t);
195
+ console.debug(t.message, ...e);
109
196
  break;
110
197
  case "Info":
111
- console.info(e.message, ...t);
198
+ console.info(t.message, ...e);
112
199
  break;
113
200
  case "Warn":
114
- console.warn(e.message, ...t);
201
+ console.warn(t.message, ...e);
115
202
  break;
116
203
  case "Error":
117
- console.error(e.message, ...t);
204
+ console.error(t.message, ...e);
118
205
  break;
119
206
  case "Fatal":
120
- console.error(e.message, ...t);
207
+ console.error(t.message, ...e);
121
208
  break;
122
209
  default:
123
- console.log(e.message, ...t);
124
- }
125
- }, prepareLogMessage = (e, ...t) => [
126
- typeof e == "object" ? JSON.stringify(e) : e,
127
- ...t.map((r) => JSON.stringify(r))
128
- ].join(" "), logs = [], addToLogArray = (e) => {
129
- logs.push(e);
130
- }, logToMemory = (e) => {
131
- if (e.raw === !0)
132
- addToLogArray(e.message);
210
+ console.log(t.message, ...e);
211
+ }
212
+ }, prepareLogMessage$1 = (t) => t instanceof Error ? [t.message, t.stack].join(`
213
+ `) : JSON.stringify(t, null, 2), logs = [], addToLogArray = (t) => {
214
+ logs.push(t);
215
+ }, logToMemory = (t) => {
216
+ if (t.raw === !0)
217
+ addToLogArray(t.message);
133
218
  else {
134
- const t = formatLogEntry(
135
- typeof e.message == "object" ? prepareLogMessage(e.message) : e.message,
136
- e.severity ?? "Info",
137
- e.prefix ?? "JavaScript"
219
+ const e = formatLogEntry(
220
+ typeof t.message == "object" ? prepareLogMessage$1(t.message) : t.message,
221
+ t.severity ?? "Info",
222
+ t.prefix ?? "JavaScript"
138
223
  );
139
- addToLogArray(t);
224
+ addToLogArray(e);
140
225
  }
141
226
  };
142
227
  class Logger extends EventTarget {
143
228
  // constructor
144
- constructor(t = []) {
145
- super(), this.handlers = t, this.fatalErrorEvent = "playground-fatal-error";
229
+ constructor(e = []) {
230
+ super(), this.handlers = e, this.fatalErrorEvent = "playground-fatal-error";
146
231
  }
147
232
  /**
148
233
  * Get all logs.
@@ -161,9 +246,9 @@ class Logger extends EventTarget {
161
246
  * @param raw boolean
162
247
  * @param args any
163
248
  */
164
- logMessage(t, ...r) {
249
+ logMessage(e, ...r) {
165
250
  for (const s of this.handlers)
166
- s(t, ...r);
251
+ s(e, ...r);
167
252
  }
168
253
  /**
169
254
  * Log message
@@ -171,10 +256,10 @@ class Logger extends EventTarget {
171
256
  * @param message any
172
257
  * @param args any
173
258
  */
174
- log(t, ...r) {
259
+ log(e, ...r) {
175
260
  this.logMessage(
176
261
  {
177
- message: t,
262
+ message: e,
178
263
  severity: void 0,
179
264
  prefix: "JavaScript",
180
265
  raw: !1
@@ -188,10 +273,10 @@ class Logger extends EventTarget {
188
273
  * @param message any
189
274
  * @param args any
190
275
  */
191
- debug(t, ...r) {
276
+ debug(e, ...r) {
192
277
  this.logMessage(
193
278
  {
194
- message: t,
279
+ message: e,
195
280
  severity: "Debug",
196
281
  prefix: "JavaScript",
197
282
  raw: !1
@@ -205,10 +290,10 @@ class Logger extends EventTarget {
205
290
  * @param message any
206
291
  * @param args any
207
292
  */
208
- info(t, ...r) {
293
+ info(e, ...r) {
209
294
  this.logMessage(
210
295
  {
211
- message: t,
296
+ message: e,
212
297
  severity: "Info",
213
298
  prefix: "JavaScript",
214
299
  raw: !1
@@ -222,10 +307,10 @@ class Logger extends EventTarget {
222
307
  * @param message any
223
308
  * @param args any
224
309
  */
225
- warn(t, ...r) {
310
+ warn(e, ...r) {
226
311
  this.logMessage(
227
312
  {
228
- message: t,
313
+ message: e,
229
314
  severity: "Warn",
230
315
  prefix: "JavaScript",
231
316
  raw: !1
@@ -239,10 +324,10 @@ class Logger extends EventTarget {
239
324
  * @param message any
240
325
  * @param args any
241
326
  */
242
- error(t, ...r) {
327
+ error(e, ...r) {
243
328
  this.logMessage(
244
329
  {
245
- message: t,
330
+ message: e,
246
331
  severity: "Error",
247
332
  prefix: "JavaScript",
248
333
  raw: !1
@@ -251,7 +336,14 @@ class Logger extends EventTarget {
251
336
  );
252
337
  }
253
338
  }
254
- const logger = new Logger([logToMemory, logToConsole]), formatLogEntry = (e, t, r) => {
339
+ const getDefaultHandlers = () => {
340
+ try {
341
+ if (process.env.NODE_ENV === "test")
342
+ return [logToMemory, logEvent];
343
+ } catch {
344
+ }
345
+ return [logToMemory, logToConsole, logEvent];
346
+ }, logger = new Logger(getDefaultHandlers()), prepareLogMessage = (t) => t.replace(/\t/g, ""), formatLogEntry = (t, e, r) => {
255
347
  const s = /* @__PURE__ */ new Date(), n = new Intl.DateTimeFormat("en-GB", {
256
348
  year: "numeric",
257
349
  month: "short",
@@ -264,160 +356,12 @@ const logger = new Logger([logToMemory, logToConsole]), formatLogEntry = (e, t,
264
356
  hour12: !1,
265
357
  timeZone: "UTC",
266
358
  timeZoneName: "short"
267
- }).format(s);
268
- return `[${n + " " + i}] ${r} ${t}: ${e}`;
269
- };
270
- class UnhandledRejectionsTarget extends EventTarget {
271
- constructor() {
272
- super(...arguments), this.listenersCount = 0;
273
- }
274
- addEventListener(t, r) {
275
- ++this.listenersCount, super.addEventListener(t, r);
276
- }
277
- removeEventListener(t, r) {
278
- --this.listenersCount, super.removeEventListener(t, r);
279
- }
280
- hasListeners() {
281
- return this.listenersCount > 0;
282
- }
283
- }
284
- function improveWASMErrorReporting(e) {
285
- e.asm = {
286
- ...e.asm
287
- };
288
- const t = new UnhandledRejectionsTarget();
289
- for (const r in e.asm)
290
- if (typeof e.asm[r] == "function") {
291
- const s = e.asm[r];
292
- e.asm[r] = function(...n) {
293
- var i;
294
- try {
295
- return s(...n);
296
- } catch (o) {
297
- if (!(o instanceof Error))
298
- throw o;
299
- const a = clarifyErrorMessage(
300
- o,
301
- (i = e.lastAsyncifyStackSource) == null ? void 0 : i.stack
302
- );
303
- if (e.lastAsyncifyStackSource && (o.cause = e.lastAsyncifyStackSource), t.hasListeners()) {
304
- t.dispatchEvent(
305
- new ErrorEvent("error", {
306
- error: o,
307
- message: a
308
- })
309
- );
310
- return;
311
- }
312
- throw isExitCodeZero(o) || showCriticalErrorBox(a), o;
313
- }
314
- };
315
- }
316
- return t;
317
- }
318
- let functionsMaybeMissingFromAsyncify = [];
319
- function getFunctionsMaybeMissingFromAsyncify() {
320
- return functionsMaybeMissingFromAsyncify;
321
- }
322
- function clarifyErrorMessage(e, t) {
323
- if (e.message === "unreachable") {
324
- let r = UNREACHABLE_ERROR;
325
- t || (r += `
326
-
327
- This stack trace is lacking. For a better one initialize
328
- the PHP runtime with { debug: true }, e.g. PHPNode.load('8.1', { debug: true }).
329
-
330
- `), functionsMaybeMissingFromAsyncify = extractPHPFunctionsFromStack(
331
- t || e.stack || ""
332
- );
333
- for (const s of functionsMaybeMissingFromAsyncify)
334
- r += ` * ${s}
335
- `;
336
- return r;
337
- }
338
- return e.message;
339
- }
340
- const UNREACHABLE_ERROR = `
341
- "unreachable" WASM instruction executed.
342
-
343
- The typical reason is a PHP function missing from the ASYNCIFY_ONLY
344
- list when building PHP.wasm.
345
-
346
- You will need to file a new issue in the WordPress Playground repository
347
- and paste this error message there:
348
-
349
- https://github.com/WordPress/wordpress-playground/issues/new
350
-
351
- If you're a core developer, the typical fix is to:
352
-
353
- * Isolate a minimal reproduction of the error
354
- * Add a reproduction of the error to php-asyncify.spec.ts in the WordPress Playground repository
355
- * Run 'npm run fix-asyncify'
356
- * Commit the changes, push to the repo, release updated NPM packages
357
-
358
- Below is a list of all the PHP functions found in the stack trace to
359
- help with the minimal reproduction. If they're all already listed in
360
- the Dockerfile, you'll need to trigger this error again with long stack
361
- traces enabled. In node.js, you can do it using the --stack-trace-limit=100
362
- CLI option:
363
-
364
- `, redBg = "\x1B[41m", bold = "\x1B[1m", reset = "\x1B[0m", eol = "\x1B[K";
365
- let logged = !1;
366
- function showCriticalErrorBox(e) {
367
- if (!logged && (logged = !0, !(e != null && e.trim().startsWith("Program terminated with exit")))) {
368
- logger.log(`${redBg}
369
- ${eol}
370
- ${bold} WASM ERROR${reset}${redBg}`);
371
- for (const t of e.split(`
372
- `))
373
- logger.log(`${eol} ${t} `);
374
- logger.log(`${reset}`);
375
- }
376
- }
377
- function extractPHPFunctionsFromStack(e) {
378
- try {
379
- const t = e.split(`
380
- `).slice(1).map((r) => {
381
- const s = r.trim().substring(3).split(" ");
382
- return {
383
- fn: s.length >= 2 ? s[0] : "<unknown>",
384
- isWasm: r.includes("wasm://")
385
- };
386
- }).filter(
387
- ({ fn: r, isWasm: s }) => s && !r.startsWith("dynCall_") && !r.startsWith("invoke_")
388
- ).map(({ fn: r }) => r);
389
- return Array.from(new Set(t));
390
- } catch {
391
- return [];
392
- }
393
- }
394
- class HttpCookieStore {
395
- constructor() {
396
- this.cookies = {};
397
- }
398
- rememberCookiesFromResponseHeaders(t) {
399
- if (t != null && t["set-cookie"])
400
- for (const r of t["set-cookie"])
401
- try {
402
- if (!r.includes("="))
403
- continue;
404
- const s = r.indexOf("="), n = r.substring(0, s), i = r.substring(s + 1).split(";")[0];
405
- this.cookies[n] = i;
406
- } catch (s) {
407
- logger.error(s);
408
- }
409
- }
410
- getCookieRequestHeader() {
411
- const t = [];
412
- for (const r in this.cookies)
413
- t.push(`${r}=${this.cookies[r]}`);
414
- return t.join("; ");
415
- }
416
- }
417
- const SleepFinished = Symbol("SleepFinished");
418
- function sleep(e) {
419
- return new Promise((t) => {
420
- setTimeout(() => t(SleepFinished), e);
359
+ }).format(s), o = n + " " + i;
360
+ return t = prepareLogMessage(t), `[${o}] ${r} ${e}: ${t}`;
361
+ }, SleepFinished = Symbol("SleepFinished");
362
+ function sleep(t) {
363
+ return new Promise((e) => {
364
+ setTimeout(() => e(SleepFinished), t);
421
365
  });
422
366
  }
423
367
  class AcquireTimeoutError extends Error {
@@ -426,8 +370,8 @@ class AcquireTimeoutError extends Error {
426
370
  }
427
371
  }
428
372
  class Semaphore {
429
- constructor({ concurrency: t, timeout: r }) {
430
- this._running = 0, this.concurrency = t, this.timeout = r, this.queue = [];
373
+ constructor({ concurrency: e, timeout: r }) {
374
+ this._running = 0, this.concurrency = e, this.timeout = r, this.queue = [];
431
375
  }
432
376
  get remaining() {
433
377
  return this.concurrency - this.running;
@@ -438,89 +382,89 @@ class Semaphore {
438
382
  async acquire() {
439
383
  for (; ; )
440
384
  if (this._running >= this.concurrency) {
441
- const t = new Promise((r) => {
385
+ const e = new Promise((r) => {
442
386
  this.queue.push(r);
443
387
  });
444
- this.timeout !== void 0 ? await Promise.race([t, sleep(this.timeout)]).then(
388
+ this.timeout !== void 0 ? await Promise.race([e, sleep(this.timeout)]).then(
445
389
  (r) => {
446
390
  if (r === SleepFinished)
447
391
  throw new AcquireTimeoutError();
448
392
  }
449
- ) : await t;
393
+ ) : await e;
450
394
  } else {
451
395
  this._running++;
452
- let t = !1;
396
+ let e = !1;
453
397
  return () => {
454
- t || (t = !0, this._running--, this.queue.length > 0 && this.queue.shift()());
398
+ e || (e = !0, this._running--, this.queue.length > 0 && this.queue.shift()());
455
399
  };
456
400
  }
457
401
  }
458
- async run(t) {
402
+ async run(e) {
459
403
  const r = await this.acquire();
460
404
  try {
461
- return await t();
405
+ return await e();
462
406
  } finally {
463
407
  r();
464
408
  }
465
409
  }
466
410
  }
467
- function joinPaths(...e) {
468
- let t = e.join("/");
469
- const r = t[0] === "/", s = t.substring(t.length - 1) === "/";
470
- return t = normalizePath(t), !t && !r && (t = "."), t && s && (t += "/"), t;
411
+ function joinPaths(...t) {
412
+ let e = t.join("/");
413
+ const r = e[0] === "/", s = e.substring(e.length - 1) === "/";
414
+ return e = normalizePath(e), !e && !r && (e = "."), e && s && (e += "/"), e;
471
415
  }
472
- function dirname(e) {
473
- if (e === "/")
416
+ function dirname(t) {
417
+ if (t === "/")
474
418
  return "/";
475
- e = normalizePath(e);
476
- const t = e.lastIndexOf("/");
477
- return t === -1 ? "" : t === 0 ? "/" : e.substr(0, t);
419
+ t = normalizePath(t);
420
+ const e = t.lastIndexOf("/");
421
+ return e === -1 ? "" : e === 0 ? "/" : t.substr(0, e);
478
422
  }
479
- function normalizePath(e) {
480
- const t = e[0] === "/";
481
- return e = normalizePathsArray(
482
- e.split("/").filter((r) => !!r),
483
- !t
484
- ).join("/"), (t ? "/" : "") + e.replace(/\/$/, "");
423
+ function normalizePath(t) {
424
+ const e = t[0] === "/";
425
+ return t = normalizePathsArray(
426
+ t.split("/").filter((r) => !!r),
427
+ !e
428
+ ).join("/"), (e ? "/" : "") + t.replace(/\/$/, "");
485
429
  }
486
- function normalizePathsArray(e, t) {
430
+ function normalizePathsArray(t, e) {
487
431
  let r = 0;
488
- for (let s = e.length - 1; s >= 0; s--) {
489
- const n = e[s];
490
- n === "." ? e.splice(s, 1) : n === ".." ? (e.splice(s, 1), r++) : r && (e.splice(s, 1), r--);
432
+ for (let s = t.length - 1; s >= 0; s--) {
433
+ const n = t[s];
434
+ n === "." ? t.splice(s, 1) : n === ".." ? (t.splice(s, 1), r++) : r && (t.splice(s, 1), r--);
491
435
  }
492
- if (t)
436
+ if (e)
493
437
  for (; r; r--)
494
- e.unshift("..");
495
- return e;
438
+ t.unshift("..");
439
+ return t;
496
440
  }
497
- function splitShellCommand(e) {
441
+ function splitShellCommand(t) {
498
442
  let s = 0, n = "";
499
443
  const i = [];
500
444
  let o = "";
501
- for (let a = 0; a < e.length; a++) {
502
- const l = e[a];
503
- l === "\\" ? ((e[a + 1] === '"' || e[a + 1] === "'") && a++, o += e[a]) : s === 0 ? l === '"' || l === "'" ? (s = 1, n = l) : l.match(/\s/) ? (o.trim().length && i.push(o.trim()), o = l) : i.length && !o ? o = i.pop() + l : o += l : s === 1 && (l === n ? (s = 0, n = "") : o += l);
445
+ for (let l = 0; l < t.length; l++) {
446
+ const c = t[l];
447
+ c === "\\" ? ((t[l + 1] === '"' || t[l + 1] === "'") && l++, o += t[l]) : s === 0 ? c === '"' || c === "'" ? (s = 1, n = c) : c.match(/\s/) ? (o.trim().length && i.push(o.trim()), o = c) : i.length && !o ? o = i.pop() + c : o += c : s === 1 && (c === n ? (s = 0, n = "") : o += c);
504
448
  }
505
449
  return o && i.push(o.trim()), i;
506
450
  }
507
- function createSpawnHandler(e) {
508
- return function(t, r = [], s = {}) {
451
+ function createSpawnHandler(t) {
452
+ return function(e, r = [], s = {}) {
509
453
  const n = new ChildProcess(), i = new ProcessApi(n);
510
454
  return setTimeout(async () => {
511
455
  let o = [];
512
456
  if (r.length)
513
- o = [t, ...r];
514
- else if (typeof t == "string")
515
- o = splitShellCommand(t);
516
- else if (Array.isArray(t))
517
- o = t;
457
+ o = [e, ...r];
458
+ else if (typeof e == "string")
459
+ o = splitShellCommand(e);
460
+ else if (Array.isArray(e))
461
+ o = e;
518
462
  else
519
- throw new Error("Invalid command ", t);
463
+ throw new Error("Invalid command ", e);
520
464
  try {
521
- await e(o, i, s);
522
- } catch (a) {
523
- n.emit("error", a), typeof a == "object" && a !== null && "message" in a && typeof a.message == "string" && i.stderr(a.message), i.exit(1);
465
+ await t(o, i, s);
466
+ } catch (l) {
467
+ n.emit("error", l), typeof l == "object" && l !== null && "message" in l && typeof l.message == "string" && i.stderr(l.message), i.exit(1);
524
468
  }
525
469
  n.emit("spawn", !0);
526
470
  }), n;
@@ -530,47 +474,47 @@ class EventEmitter {
530
474
  constructor() {
531
475
  this.listeners = {};
532
476
  }
533
- emit(t, r) {
534
- this.listeners[t] && this.listeners[t].forEach(function(s) {
477
+ emit(e, r) {
478
+ this.listeners[e] && this.listeners[e].forEach(function(s) {
535
479
  s(r);
536
480
  });
537
481
  }
538
- on(t, r) {
539
- this.listeners[t] || (this.listeners[t] = []), this.listeners[t].push(r);
482
+ on(e, r) {
483
+ this.listeners[e] || (this.listeners[e] = []), this.listeners[e].push(r);
540
484
  }
541
485
  }
542
486
  class ProcessApi extends EventEmitter {
543
- constructor(t) {
544
- super(), this.childProcess = t, this.exited = !1, this.stdinData = [], t.on("stdin", (r) => {
487
+ constructor(e) {
488
+ super(), this.childProcess = e, this.exited = !1, this.stdinData = [], e.on("stdin", (r) => {
545
489
  this.stdinData ? this.stdinData.push(r.slice()) : this.emit("stdin", r);
546
490
  });
547
491
  }
548
- stdout(t) {
549
- typeof t == "string" && (t = new TextEncoder().encode(t)), this.childProcess.stdout.emit("data", t);
492
+ stdout(e) {
493
+ typeof e == "string" && (e = new TextEncoder().encode(e)), this.childProcess.stdout.emit("data", e);
550
494
  }
551
495
  stdoutEnd() {
552
496
  this.childProcess.stdout.emit("end", {});
553
497
  }
554
- stderr(t) {
555
- typeof t == "string" && (t = new TextEncoder().encode(t)), this.childProcess.stderr.emit("data", t);
498
+ stderr(e) {
499
+ typeof e == "string" && (e = new TextEncoder().encode(e)), this.childProcess.stderr.emit("data", e);
556
500
  }
557
501
  stderrEnd() {
558
502
  this.childProcess.stderr.emit("end", {});
559
503
  }
560
- exit(t) {
561
- this.exited || (this.exited = !0, this.childProcess.emit("exit", t));
504
+ exit(e) {
505
+ this.exited || (this.exited = !0, this.childProcess.emit("exit", e));
562
506
  }
563
507
  flushStdin() {
564
508
  if (this.stdinData)
565
- for (let t = 0; t < this.stdinData.length; t++)
566
- this.emit("stdin", this.stdinData[t]);
509
+ for (let e = 0; e < this.stdinData.length; e++)
510
+ this.emit("stdin", this.stdinData[e]);
567
511
  this.stdinData = null;
568
512
  }
569
513
  }
570
514
  let lastPid = 9743;
571
515
  class ChildProcess extends EventEmitter {
572
- constructor(t = lastPid++) {
573
- super(), this.pid = t, this.stdout = new EventEmitter(), this.stderr = new EventEmitter();
516
+ constructor(e = lastPid++) {
517
+ super(), this.pid = e, this.stdout = new EventEmitter(), this.stderr = new EventEmitter();
574
518
  const r = this;
575
519
  this.stdin = {
576
520
  write: (s) => {
@@ -579,280 +523,253 @@ class ChildProcess extends EventEmitter {
579
523
  };
580
524
  }
581
525
  }
582
- function concatUint8Array(...e) {
583
- const t = new Uint8Array(
584
- e.reduce((s, n) => s + n.length, 0)
585
- );
586
- let r = 0;
587
- for (const s of e)
588
- t.set(s, r), r += s.length;
589
- return t;
590
- }
591
- function concatBytes(e) {
592
- if (e === void 0) {
593
- let t = new Uint8Array();
594
- return new TransformStream({
595
- transform(r) {
596
- t = concatUint8Array(t, r);
597
- },
598
- flush(r) {
599
- r.enqueue(t);
600
- }
601
- });
602
- } else {
603
- const t = new ArrayBuffer(e || 0);
604
- let r = 0;
605
- return new TransformStream({
606
- transform(s) {
607
- new Uint8Array(t).set(s, r), r += s.byteLength;
608
- },
609
- flush(s) {
610
- s.enqueue(new Uint8Array(t));
611
- }
612
- });
526
+ var __defProp = Object.defineProperty, __getOwnPropDesc = Object.getOwnPropertyDescriptor, __decorateClass = (t, e, r, s) => {
527
+ for (var n = s > 1 ? void 0 : s ? __getOwnPropDesc(e, r) : e, i = t.length - 1, o; i >= 0; i--)
528
+ (o = t[i]) && (n = (s ? o(e, r, n) : o(n)) || n);
529
+ return s && n && __defProp(e, r, n), n;
530
+ };
531
+ const _FSHelpers = class g {
532
+ static readFileAsText(e, r) {
533
+ return new TextDecoder().decode(g.readFileAsBuffer(e, r));
613
534
  }
614
- }
615
- function limitBytes(e, t) {
616
- if (t === 0)
617
- return new ReadableStream({
618
- start(n) {
619
- n.close();
620
- }
621
- });
622
- const r = e.getReader({ mode: "byob" });
623
- let s = 0;
624
- return new ReadableStream({
625
- async pull(n) {
626
- const { value: i, done: o } = await r.read(
627
- new Uint8Array(t - s)
628
- );
629
- if (o) {
630
- r.releaseLock(), n.close();
631
- return;
632
- }
633
- s += i.length, n.enqueue(i), s >= t && (r.releaseLock(), n.close());
634
- },
635
- cancel() {
636
- r.cancel();
637
- }
638
- });
639
- }
640
- async function collectBytes(e, t) {
641
- return t !== void 0 && (e = limitBytes(e, t)), await e.pipeThrough(concatBytes(t)).getReader().read().then(({ value: r }) => r);
642
- }
643
- class StreamedFile extends File {
644
- /**
645
- * Creates a new StreamedFile instance.
646
- *
647
- * @param readableStream The readable stream containing the file data.
648
- * @param name The name of the file.
649
- * @param type The MIME type of the file.
650
- */
651
- constructor(t, r, s) {
652
- super([], r, { type: s }), this.readableStream = t;
653
- }
654
- /**
655
- * Overrides the slice() method of the File class.
656
- *
657
- * @returns A Blob representing a portion of the file.
658
- */
659
- slice() {
660
- throw new Error("slice() is not possible on a StreamedFile");
535
+ static readFileAsBuffer(e, r) {
536
+ return e.readFile(r);
661
537
  }
662
- /**
663
- * Returns the readable stream associated with the file.
664
- *
665
- * @returns The readable stream.
666
- */
667
- stream() {
668
- return this.readableStream;
538
+ static writeFile(e, r, s) {
539
+ e.writeFile(r, s);
669
540
  }
670
- /**
671
- * Loads the file data into memory and then returns it as a string.
672
- *
673
- * @returns File data as text.
674
- */
675
- async text() {
676
- return new TextDecoder().decode(await this.arrayBuffer());
541
+ static unlink(e, r) {
542
+ e.unlink(r);
677
543
  }
678
544
  /**
679
- * Loads the file data into memory and then returns it as an ArrayBuffer.
545
+ * Moves a file or directory in the PHP filesystem to a
546
+ * new location.
680
547
  *
681
- * @returns File data as an ArrayBuffer.
548
+ * @param oldPath The path to rename.
549
+ * @param newPath The new path.
682
550
  */
683
- async arrayBuffer() {
684
- return await collectBytes(this.stream());
685
- }
686
- }
687
- ReadableStream.prototype[Symbol.asyncIterator] || (ReadableStream.prototype[Symbol.asyncIterator] = async function* () {
688
- const e = this.getReader();
689
- try {
690
- for (; ; ) {
691
- const { done: t, value: r } = await e.read();
692
- if (t)
693
- return;
694
- yield r;
551
+ static mv(e, r, s) {
552
+ try {
553
+ const n = e.lookupPath(r).node.mount, i = g.fileExists(e, s) ? e.lookupPath(s).node.mount : e.lookupPath(dirname(s)).node.mount;
554
+ n.mountpoint !== i.mountpoint ? (g.copyRecursive(e, r, s), g.rmdir(e, r, { recursive: !0 })) : e.rename(r, s);
555
+ } catch (n) {
556
+ const i = getEmscriptenFsError(n);
557
+ throw i ? new Error(
558
+ `Could not move ${r} to ${s}: ${i}`,
559
+ {
560
+ cause: n
561
+ }
562
+ ) : n;
695
563
  }
696
- } finally {
697
- e.releaseLock();
698
564
  }
699
- }, ReadableStream.prototype.iterate = // @ts-ignore
700
- ReadableStream.prototype[Symbol.asyncIterator]);
701
- function streamReadFileFromPHP(e, t) {
702
- return new ReadableStream({
703
- async pull(r) {
704
- const s = await e.readFileAsBuffer(t);
705
- r.enqueue(s), r.close();
706
- }
707
- });
708
- }
709
- async function* iteratePhpFiles(e, t, {
710
- relativePaths: r = !0,
711
- pathPrefix: s,
712
- exceptPaths: n = []
713
- } = {}) {
714
- t = normalizePath(t);
715
- const i = [t];
716
- for (; i.length; ) {
717
- const o = i.pop();
718
- if (!o)
719
- return;
720
- const a = await e.listFiles(o);
721
- for (const l of a) {
722
- const c = `${o}/${l}`;
723
- if (n.includes(c.substring(t.length + 1)))
724
- continue;
725
- await e.isDir(c) ? i.push(c) : yield new StreamedFile(
726
- streamReadFileFromPHP(e, c),
727
- r ? joinPaths(
728
- s || "",
729
- c.substring(t.length + 1)
730
- ) : c
565
+ static rmdir(e, r, s = { recursive: !0 }) {
566
+ s != null && s.recursive && g.listFiles(e, r).forEach((n) => {
567
+ const i = `${r}/${n}`;
568
+ g.isDir(e, i) ? g.rmdir(e, i, s) : g.unlink(e, i);
569
+ }), e.rmdir(r);
570
+ }
571
+ static listFiles(e, r, s = { prependPath: !1 }) {
572
+ if (!g.fileExists(e, r))
573
+ return [];
574
+ try {
575
+ const n = e.readdir(r).filter(
576
+ (i) => i !== "." && i !== ".."
731
577
  );
578
+ if (s.prependPath) {
579
+ const i = r.replace(/\/$/, "");
580
+ return n.map((o) => `${i}/${o}`);
581
+ }
582
+ return n;
583
+ } catch (n) {
584
+ return logger.error(n, { path: r }), [];
732
585
  }
733
586
  }
734
- }
735
- function writeFilesStreamToPhp(e, t) {
736
- return new WritableStream({
737
- async write(r) {
738
- const s = joinPaths(t, r.name);
739
- r.type === "directory" ? await e.mkdir(s) : (await e.mkdir(dirname(s)), await e.writeFile(
740
- s,
741
- new Uint8Array(await r.arrayBuffer())
742
- ));
587
+ static isDir(e, r) {
588
+ return g.fileExists(e, r) ? e.isDir(e.lookupPath(r).node.mode) : !1;
589
+ }
590
+ static fileExists(e, r) {
591
+ try {
592
+ return e.lookupPath(r), !0;
593
+ } catch {
594
+ return !1;
743
595
  }
744
- });
745
- }
746
- class MaxPhpInstancesError extends Error {
747
- constructor(t) {
748
- super(
749
- `Requested more concurrent PHP instances than the limit (${t}).`
750
- ), this.name = this.constructor.name;
751
596
  }
752
- }
753
- class PHPProcessManager {
754
- constructor(t) {
755
- this.primaryIdle = !0, this.nextInstance = null, this.allInstances = [], this.maxPhpInstances = (t == null ? void 0 : t.maxPhpInstances) ?? 5, this.phpFactory = t == null ? void 0 : t.phpFactory, this.primaryPhp = t == null ? void 0 : t.primaryPhp, this.semaphore = new Semaphore({
756
- concurrency: this.maxPhpInstances,
757
- /**
758
- * Wait up to 5 seconds for resources to become available
759
- * before assuming that all the PHP instances are deadlocked.
760
- */
761
- timeout: (t == null ? void 0 : t.timeout) || 5e3
762
- });
597
+ static mkdir(e, r) {
598
+ e.mkdirTree(r);
763
599
  }
764
- /**
765
- * Get the primary PHP instance.
766
- *
767
- * If the primary PHP instance is not set, it will be spawned
768
- * using the provided phpFactory.
769
- *
770
- * @throws {Error} when called twice before the first call is resolved.
771
- */
772
- async getPrimaryPhp() {
773
- if (!this.phpFactory && !this.primaryPhp)
774
- throw new Error(
775
- "phpFactory or primaryPhp must be set before calling getPrimaryPhp()."
600
+ static copyRecursive(e, r, s) {
601
+ const n = e.lookupPath(r).node;
602
+ if (e.isDir(n.mode)) {
603
+ e.mkdirTree(s);
604
+ const i = e.readdir(r).filter(
605
+ (o) => o !== "." && o !== ".."
776
606
  );
777
- if (!this.primaryPhp) {
778
- const t = await this.spawn({ isPrimary: !0 });
779
- this.primaryPhp = t.php;
780
- }
781
- return this.primaryPhp;
607
+ for (const o of i)
608
+ g.copyRecursive(
609
+ e,
610
+ joinPaths(r, o),
611
+ joinPaths(s, o)
612
+ );
613
+ } else
614
+ e.writeFile(s, e.readFile(r));
782
615
  }
783
- /**
784
- * Get a PHP instance.
785
- *
786
- * It could be either the primary PHP instance, an idle disposable PHP instance,
787
- * or a newly spawned PHP instance – depending on the resource availability.
788
- *
789
- * @throws {MaxPhpInstancesError} when the maximum number of PHP instances is reached
790
- * and the waiting timeout is exceeded.
791
- */
792
- async acquirePHPInstance() {
793
- if (this.primaryIdle)
794
- return this.primaryIdle = !1, {
795
- php: await this.getPrimaryPhp(),
796
- reap: () => this.primaryIdle = !0
797
- };
798
- const t = this.nextInstance || this.spawn({ isPrimary: !1 });
799
- return this.semaphore.remaining > 0 ? this.nextInstance = this.spawn({ isPrimary: !1 }) : this.nextInstance = null, await t;
616
+ };
617
+ __decorateClass([
618
+ rethrowFileSystemError('Could not read "{path}"')
619
+ ], _FSHelpers, "readFileAsText", 1);
620
+ __decorateClass([
621
+ rethrowFileSystemError('Could not read "{path}"')
622
+ ], _FSHelpers, "readFileAsBuffer", 1);
623
+ __decorateClass([
624
+ rethrowFileSystemError('Could not write to "{path}"')
625
+ ], _FSHelpers, "writeFile", 1);
626
+ __decorateClass([
627
+ rethrowFileSystemError('Could not unlink "{path}"')
628
+ ], _FSHelpers, "unlink", 1);
629
+ __decorateClass([
630
+ rethrowFileSystemError('Could not remove directory "{path}"')
631
+ ], _FSHelpers, "rmdir", 1);
632
+ __decorateClass([
633
+ rethrowFileSystemError('Could not list files in "{path}"')
634
+ ], _FSHelpers, "listFiles", 1);
635
+ __decorateClass([
636
+ rethrowFileSystemError('Could not stat "{path}"')
637
+ ], _FSHelpers, "isDir", 1);
638
+ __decorateClass([
639
+ rethrowFileSystemError('Could not stat "{path}"')
640
+ ], _FSHelpers, "fileExists", 1);
641
+ __decorateClass([
642
+ rethrowFileSystemError('Could not create directory "{path}"')
643
+ ], _FSHelpers, "mkdir", 1);
644
+ __decorateClass([
645
+ rethrowFileSystemError('Could not copy files from "{path}"')
646
+ ], _FSHelpers, "copyRecursive", 1);
647
+ let FSHelpers = _FSHelpers;
648
+ const _private = /* @__PURE__ */ new WeakMap();
649
+ class PHPWorker {
650
+ /** @inheritDoc */
651
+ constructor(e, r) {
652
+ this.absoluteUrl = "", this.documentRoot = "", _private.set(this, {
653
+ monitor: r
654
+ }), e && this.__internal_setRequestHandler(e);
655
+ }
656
+ __internal_setRequestHandler(e) {
657
+ this.absoluteUrl = e.absoluteUrl, this.documentRoot = e.documentRoot, _private.set(this, {
658
+ ..._private.get(this),
659
+ requestHandler: e
660
+ });
800
661
  }
801
662
  /**
802
- * Initiated spawning of a new PHP instance.
803
- * This function is synchronous on purpose – it needs to synchronously
804
- * add the spawn promise to the allInstances array without waiting
805
- * for PHP to spawn.
663
+ * @internal
664
+ * @deprecated
665
+ * Do not use this method directly in the code consuming
666
+ * the web API. It will change or even be removed without
667
+ * a warning.
806
668
  */
807
- spawn(t) {
808
- if (t.isPrimary && this.allInstances.length > 0)
809
- throw new Error(
810
- "Requested spawning a primary PHP instance when another primary instance already started spawning."
811
- );
812
- const r = this.doSpawn(t);
813
- this.allInstances.push(r);
814
- const s = () => {
815
- this.allInstances = this.allInstances.filter(
816
- (n) => n !== r
817
- );
818
- };
819
- return r.catch((n) => {
820
- throw s(), n;
821
- }).then((n) => ({
822
- ...n,
823
- reap: () => {
824
- s(), n.reap();
825
- }
826
- }));
669
+ __internal_getPHP() {
670
+ return _private.get(this).php;
671
+ }
672
+ async setPrimaryPHP(e) {
673
+ _private.set(this, {
674
+ ..._private.get(this),
675
+ php: e
676
+ });
677
+ }
678
+ /** @inheritDoc @php-wasm/universal!PHPRequestHandler.pathToInternalUrl */
679
+ pathToInternalUrl(e) {
680
+ return _private.get(this).requestHandler.pathToInternalUrl(e);
681
+ }
682
+ /** @inheritDoc @php-wasm/universal!PHPRequestHandler.internalUrlToPath */
683
+ internalUrlToPath(e) {
684
+ return _private.get(this).requestHandler.internalUrlToPath(e);
827
685
  }
828
686
  /**
829
- * Actually acquires the lock and spawns a new PHP instance.
687
+ * The onDownloadProgress event listener.
830
688
  */
831
- async doSpawn(t) {
832
- let r;
833
- try {
834
- r = await this.semaphore.acquire();
835
- } catch (s) {
836
- throw s instanceof AcquireTimeoutError ? new MaxPhpInstancesError(this.maxPhpInstances) : s;
837
- }
689
+ async onDownloadProgress(e) {
690
+ var r;
691
+ return (r = _private.get(this).monitor) == null ? void 0 : r.addEventListener("progress", e);
692
+ }
693
+ /** @inheritDoc @php-wasm/universal!PHP.mv */
694
+ async mv(e, r) {
695
+ return _private.get(this).php.mv(e, r);
696
+ }
697
+ /** @inheritDoc @php-wasm/universal!PHP.rmdir */
698
+ async rmdir(e, r) {
699
+ return _private.get(this).php.rmdir(e, r);
700
+ }
701
+ /** @inheritDoc @php-wasm/universal!PHPRequestHandler.request */
702
+ async request(e) {
703
+ return await _private.get(this).requestHandler.request(e);
704
+ }
705
+ /** @inheritDoc @php-wasm/universal!/PHP.run */
706
+ async run(e) {
707
+ const { php: r, reap: s } = await _private.get(this).requestHandler.processManager.acquirePHPInstance();
838
708
  try {
839
- const s = await this.phpFactory(t);
840
- return {
841
- php: s,
842
- reap() {
843
- s.exit(), r();
844
- }
845
- };
846
- } catch (s) {
847
- throw r(), s;
709
+ return await r.run(e);
710
+ } finally {
711
+ s();
848
712
  }
849
713
  }
850
- async [Symbol.asyncDispose]() {
851
- this.primaryPhp && this.primaryPhp.exit(), await Promise.all(
852
- this.allInstances.map(
853
- (t) => t.then(({ reap: r }) => r())
854
- )
855
- );
714
+ /** @inheritDoc @php-wasm/universal!/PHP.chdir */
715
+ chdir(e) {
716
+ return _private.get(this).php.chdir(e);
717
+ }
718
+ /** @inheritDoc @php-wasm/universal!/PHP.setSapiName */
719
+ setSapiName(e) {
720
+ _private.get(this).php.setSapiName(e);
721
+ }
722
+ /** @inheritDoc @php-wasm/universal!/PHP.mkdir */
723
+ mkdir(e) {
724
+ return _private.get(this).php.mkdir(e);
725
+ }
726
+ /** @inheritDoc @php-wasm/universal!/PHP.mkdirTree */
727
+ mkdirTree(e) {
728
+ return _private.get(this).php.mkdirTree(e);
729
+ }
730
+ /** @inheritDoc @php-wasm/universal!/PHP.readFileAsText */
731
+ readFileAsText(e) {
732
+ return _private.get(this).php.readFileAsText(e);
733
+ }
734
+ /** @inheritDoc @php-wasm/universal!/PHP.readFileAsBuffer */
735
+ readFileAsBuffer(e) {
736
+ return _private.get(this).php.readFileAsBuffer(e);
737
+ }
738
+ /** @inheritDoc @php-wasm/universal!/PHP.writeFile */
739
+ writeFile(e, r) {
740
+ return _private.get(this).php.writeFile(e, r);
741
+ }
742
+ /** @inheritDoc @php-wasm/universal!/PHP.unlink */
743
+ unlink(e) {
744
+ return _private.get(this).php.unlink(e);
745
+ }
746
+ /** @inheritDoc @php-wasm/universal!/PHP.listFiles */
747
+ listFiles(e, r) {
748
+ return _private.get(this).php.listFiles(e, r);
749
+ }
750
+ /** @inheritDoc @php-wasm/universal!/PHP.isDir */
751
+ isDir(e) {
752
+ return _private.get(this).php.isDir(e);
753
+ }
754
+ /** @inheritDoc @php-wasm/universal!/PHP.fileExists */
755
+ fileExists(e) {
756
+ return _private.get(this).php.fileExists(e);
757
+ }
758
+ /** @inheritDoc @php-wasm/universal!/PHP.onMessage */
759
+ onMessage(e) {
760
+ _private.get(this).php.onMessage(e);
761
+ }
762
+ /** @inheritDoc @php-wasm/universal!/PHP.defineConstant */
763
+ defineConstant(e, r) {
764
+ _private.get(this).php.defineConstant(e, r);
765
+ }
766
+ /** @inheritDoc @php-wasm/universal!/PHP.addEventListener */
767
+ addEventListener(e, r) {
768
+ _private.get(this).php.addEventListener(e, r);
769
+ }
770
+ /** @inheritDoc @php-wasm/universal!/PHP.removeEventListener */
771
+ removeEventListener(e, r) {
772
+ _private.get(this).php.removeEventListener(e, r);
856
773
  }
857
774
  }
858
775
  const responseTexts = {
@@ -871,25 +788,25 @@ const responseTexts = {
871
788
  200: "OK"
872
789
  };
873
790
  class PHPResponse {
874
- constructor(t, r, s, n = "", i = 0) {
875
- this.httpStatusCode = t, this.headers = r, this.bytes = s, this.exitCode = i, this.errors = n;
791
+ constructor(e, r, s, n = "", i = 0) {
792
+ this.httpStatusCode = e, this.headers = r, this.bytes = s, this.exitCode = i, this.errors = n;
876
793
  }
877
- static forHttpCode(t, r = "") {
794
+ static forHttpCode(e, r = "") {
878
795
  return new PHPResponse(
879
- t,
796
+ e,
880
797
  {},
881
798
  new TextEncoder().encode(
882
- r || responseTexts[t] || ""
799
+ r || responseTexts[e] || ""
883
800
  )
884
801
  );
885
802
  }
886
- static fromRawData(t) {
803
+ static fromRawData(e) {
887
804
  return new PHPResponse(
888
- t.httpStatusCode,
889
- t.headers,
890
- t.bytes,
891
- t.errors,
892
- t.exitCode
805
+ e.httpStatusCode,
806
+ e.headers,
807
+ e.bytes,
808
+ e.errors,
809
+ e.exitCode
893
810
  );
894
811
  }
895
812
  toRawData() {
@@ -914,176 +831,196 @@ class PHPResponse {
914
831
  return new TextDecoder().decode(this.bytes);
915
832
  }
916
833
  }
917
- const SupportedPHPVersions = [
918
- "8.3",
919
- "8.2",
920
- "8.1",
921
- "8.0",
922
- "7.4",
923
- "7.3",
924
- "7.2",
925
- "7.1",
926
- "7.0"
927
- ], LatestSupportedPHPVersion = SupportedPHPVersions[0], SupportedPHPVersionsList = SupportedPHPVersions, SupportedPHPExtensionsList = [
928
- "iconv",
929
- "mbstring",
930
- "xml-bundle",
931
- "gd"
932
- ], SupportedPHPExtensionBundles = {
933
- "kitchen-sink": SupportedPHPExtensionsList,
934
- light: []
935
- }, FileErrorCodes = {
936
- 0: "No error occurred. System call completed successfully.",
937
- 1: "Argument list too long.",
938
- 2: "Permission denied.",
939
- 3: "Address in use.",
940
- 4: "Address not available.",
941
- 5: "Address family not supported.",
942
- 6: "Resource unavailable, or operation would block.",
943
- 7: "Connection already in progress.",
944
- 8: "Bad file descriptor.",
945
- 9: "Bad message.",
946
- 10: "Device or resource busy.",
947
- 11: "Operation canceled.",
948
- 12: "No child processes.",
949
- 13: "Connection aborted.",
950
- 14: "Connection refused.",
951
- 15: "Connection reset.",
952
- 16: "Resource deadlock would occur.",
953
- 17: "Destination address required.",
954
- 18: "Mathematics argument out of domain of function.",
955
- 19: "Reserved.",
956
- 20: "File exists.",
957
- 21: "Bad address.",
958
- 22: "File too large.",
959
- 23: "Host is unreachable.",
960
- 24: "Identifier removed.",
961
- 25: "Illegal byte sequence.",
962
- 26: "Operation in progress.",
963
- 27: "Interrupted function.",
964
- 28: "Invalid argument.",
965
- 29: "I/O error.",
966
- 30: "Socket is connected.",
967
- 31: "There is a directory under that path.",
968
- 32: "Too many levels of symbolic links.",
969
- 33: "File descriptor value too large.",
970
- 34: "Too many links.",
971
- 35: "Message too large.",
972
- 36: "Reserved.",
973
- 37: "Filename too long.",
974
- 38: "Network is down.",
975
- 39: "Connection aborted by network.",
976
- 40: "Network unreachable.",
977
- 41: "Too many files open in system.",
978
- 42: "No buffer space available.",
979
- 43: "No such device.",
980
- 44: "There is no such file or directory OR the parent directory does not exist.",
981
- 45: "Executable file format error.",
982
- 46: "No locks available.",
983
- 47: "Reserved.",
984
- 48: "Not enough space.",
985
- 49: "No message of the desired type.",
986
- 50: "Protocol not available.",
987
- 51: "No space left on device.",
988
- 52: "Function not supported.",
989
- 53: "The socket is not connected.",
990
- 54: "Not a directory or a symbolic link to a directory.",
991
- 55: "Directory not empty.",
992
- 56: "State not recoverable.",
993
- 57: "Not a socket.",
994
- 58: "Not supported, or operation not supported on socket.",
995
- 59: "Inappropriate I/O control operation.",
996
- 60: "No such device or address.",
997
- 61: "Value too large to be stored in data type.",
998
- 62: "Previous owner died.",
999
- 63: "Operation not permitted.",
1000
- 64: "Broken pipe.",
1001
- 65: "Protocol error.",
1002
- 66: "Protocol not supported.",
1003
- 67: "Protocol wrong type for socket.",
1004
- 68: "Result too large.",
1005
- 69: "Read-only file system.",
1006
- 70: "Invalid seek.",
1007
- 71: "No such process.",
1008
- 72: "Reserved.",
1009
- 73: "Connection timed out.",
1010
- 74: "Text file busy.",
1011
- 75: "Cross-device link.",
1012
- 76: "Extension: Capabilities insufficient."
1013
- };
1014
- function getEmscriptenFsError(e) {
1015
- const t = typeof e == "object" ? e == null ? void 0 : e.errno : null;
1016
- if (t in FileErrorCodes)
1017
- return FileErrorCodes[t];
1018
- }
1019
- function rethrowFileSystemError(e = "") {
1020
- return function(r, s, n) {
1021
- const i = n.value;
1022
- n.value = function(...o) {
1023
- try {
1024
- return i.apply(this, o);
1025
- } catch (a) {
1026
- const l = typeof a == "object" ? a == null ? void 0 : a.errno : null;
1027
- if (l in FileErrorCodes) {
1028
- const c = FileErrorCodes[l], g = typeof o[0] == "string" ? o[0] : null, me = g !== null ? e.replaceAll("{path}", g) : e;
1029
- throw new Error(`${me}: ${c}`, {
1030
- cause: a
1031
- });
1032
- }
1033
- throw a;
1034
- }
1035
- };
1036
- };
1037
- }
1038
834
  const RuntimeId = Symbol("RuntimeId"), loadedRuntimes = /* @__PURE__ */ new Map();
1039
835
  let lastRuntimeId = 0;
1040
- async function loadPHPRuntime(e, t = {}) {
1041
- const [r, s, n] = makePromise(), i = e.init(currentJsRuntime, {
1042
- onAbort(a) {
1043
- n(a), logger.error(a);
836
+ async function loadPHPRuntime(t, e = {}) {
837
+ const [r, s, n] = makePromise(), i = t.init(currentJsRuntime, {
838
+ onAbort(l) {
839
+ n(l), logger.error(l);
1044
840
  },
1045
841
  ENV: {},
1046
842
  // Emscripten sometimes prepends a '/' to the path, which
1047
843
  // breaks vite dev mode. An identity `locateFile` function
1048
844
  // fixes it.
1049
- locateFile: (a) => a,
1050
- ...t,
845
+ locateFile: (l) => l,
846
+ ...e,
1051
847
  noInitialRun: !0,
1052
848
  onRuntimeInitialized() {
1053
- t.onRuntimeInitialized && t.onRuntimeInitialized(), s();
849
+ e.onRuntimeInitialized && e.onRuntimeInitialized(), s();
1054
850
  }
1055
851
  });
1056
852
  await r;
1057
853
  const o = ++lastRuntimeId;
1058
- return i.id = o, i.originalExit = i._exit, i._exit = function(a) {
1059
- return loadedRuntimes.delete(o), i.originalExit(a);
854
+ return i.id = o, i.originalExit = i._exit, i._exit = function(l) {
855
+ return loadedRuntimes.delete(o), i.originalExit(l);
1060
856
  }, i[RuntimeId] = o, loadedRuntimes.set(o, i), o;
1061
857
  }
1062
- function getLoadedRuntime(e) {
1063
- return loadedRuntimes.get(e);
858
+ function getLoadedRuntime(t) {
859
+ return loadedRuntimes.get(t);
1064
860
  }
1065
861
  const currentJsRuntime = function() {
1066
- var e;
1067
- return typeof process < "u" && ((e = process.release) == null ? void 0 : e.name) === "node" ? "NODE" : typeof window < "u" ? "WEB" : typeof WorkerGlobalScope < "u" && self instanceof WorkerGlobalScope ? "WORKER" : "NODE";
862
+ var t;
863
+ return typeof process < "u" && ((t = process.release) == null ? void 0 : t.name) === "node" ? "NODE" : typeof window < "u" ? "WEB" : typeof WorkerGlobalScope < "u" && self instanceof WorkerGlobalScope ? "WORKER" : "NODE";
1068
864
  }(), makePromise = () => {
1069
- const e = [], t = new Promise((r, s) => {
1070
- e.push(r, s);
865
+ const t = [], e = new Promise((r, s) => {
866
+ t.push(r, s);
1071
867
  });
1072
- return e.unshift(t), e;
1073
- };
1074
- var __defProp = Object.defineProperty, __getOwnPropDesc = Object.getOwnPropertyDescriptor, __decorateClass = (e, t, r, s) => {
1075
- for (var n = s > 1 ? void 0 : s ? __getOwnPropDesc(t, r) : t, i = e.length - 1, o; i >= 0; i--)
1076
- (o = e[i]) && (n = (s ? o(t, r, n) : o(n)) || n);
1077
- return s && n && __defProp(t, r, n), n;
1078
- };
868
+ return t.unshift(e), t;
869
+ }, kError = Symbol("error"), kMessage = Symbol("message");
870
+ class ErrorEvent2 extends Event {
871
+ /**
872
+ * Create a new `ErrorEvent`.
873
+ *
874
+ * @param type The name of the event
875
+ * @param options A dictionary object that allows for setting
876
+ * attributes via object members of the same name.
877
+ */
878
+ constructor(e, r = {}) {
879
+ super(e), this[kError] = r.error === void 0 ? null : r.error, this[kMessage] = r.message === void 0 ? "" : r.message;
880
+ }
881
+ get error() {
882
+ return this[kError];
883
+ }
884
+ get message() {
885
+ return this[kMessage];
886
+ }
887
+ }
888
+ Object.defineProperty(ErrorEvent2.prototype, "error", { enumerable: !0 });
889
+ Object.defineProperty(ErrorEvent2.prototype, "message", { enumerable: !0 });
890
+ const ErrorEvent = typeof globalThis.ErrorEvent == "function" ? globalThis.ErrorEvent : ErrorEvent2;
891
+ function isExitCodeZero(t) {
892
+ return t instanceof Error ? "exitCode" in t && (t == null ? void 0 : t.exitCode) === 0 || (t == null ? void 0 : t.name) === "ExitStatus" && "status" in t && t.status === 0 : !1;
893
+ }
894
+ class UnhandledRejectionsTarget extends EventTarget {
895
+ constructor() {
896
+ super(...arguments), this.listenersCount = 0;
897
+ }
898
+ addEventListener(e, r) {
899
+ ++this.listenersCount, super.addEventListener(e, r);
900
+ }
901
+ removeEventListener(e, r) {
902
+ --this.listenersCount, super.removeEventListener(e, r);
903
+ }
904
+ hasListeners() {
905
+ return this.listenersCount > 0;
906
+ }
907
+ }
908
+ function improveWASMErrorReporting(t) {
909
+ const e = new UnhandledRejectionsTarget();
910
+ for (const r in t.wasmExports)
911
+ if (typeof t.wasmExports[r] == "function") {
912
+ const s = t.wasmExports[r];
913
+ t.wasmExports[r] = function(...n) {
914
+ var i;
915
+ try {
916
+ return s(...n);
917
+ } catch (o) {
918
+ if (!(o instanceof Error))
919
+ throw o;
920
+ const l = clarifyErrorMessage(
921
+ o,
922
+ (i = t.lastAsyncifyStackSource) == null ? void 0 : i.stack
923
+ );
924
+ if (t.lastAsyncifyStackSource && (o.cause = t.lastAsyncifyStackSource), e.hasListeners()) {
925
+ e.dispatchEvent(
926
+ new ErrorEvent("error", {
927
+ error: o,
928
+ message: l
929
+ })
930
+ );
931
+ return;
932
+ }
933
+ throw isExitCodeZero(o) || showCriticalErrorBox(l), o;
934
+ }
935
+ };
936
+ }
937
+ return e;
938
+ }
939
+ let functionsMaybeMissingFromAsyncify = [];
940
+ function getFunctionsMaybeMissingFromAsyncify() {
941
+ return functionsMaybeMissingFromAsyncify;
942
+ }
943
+ function clarifyErrorMessage(t, e) {
944
+ if (t.message === "unreachable") {
945
+ let r = UNREACHABLE_ERROR;
946
+ e || (r += `
947
+
948
+ This stack trace is lacking. For a better one initialize
949
+ the PHP runtime with { debug: true }, e.g. PHPNode.load('8.1', { debug: true }).
950
+
951
+ `), functionsMaybeMissingFromAsyncify = extractPHPFunctionsFromStack(
952
+ e || t.stack || ""
953
+ );
954
+ for (const s of functionsMaybeMissingFromAsyncify)
955
+ r += ` * ${s}
956
+ `;
957
+ return r;
958
+ }
959
+ return t.message;
960
+ }
961
+ const UNREACHABLE_ERROR = `
962
+ "unreachable" WASM instruction executed.
963
+
964
+ The typical reason is a PHP function missing from the ASYNCIFY_ONLY
965
+ list when building PHP.wasm.
966
+
967
+ You will need to file a new issue in the WordPress Playground repository
968
+ and paste this error message there:
969
+
970
+ https://github.com/WordPress/wordpress-playground/issues/new
971
+
972
+ If you're a core developer, the typical fix is to:
973
+
974
+ * Isolate a minimal reproduction of the error
975
+ * Add a reproduction of the error to php-asyncify.spec.ts in the WordPress Playground repository
976
+ * Run 'npm run fix-asyncify'
977
+ * Commit the changes, push to the repo, release updated NPM packages
978
+
979
+ Below is a list of all the PHP functions found in the stack trace to
980
+ help with the minimal reproduction. If they're all already listed in
981
+ the Dockerfile, you'll need to trigger this error again with long stack
982
+ traces enabled. In node.js, you can do it using the --stack-trace-limit=100
983
+ CLI option:
984
+
985
+ `, redBg = "\x1B[41m", bold = "\x1B[1m", reset = "\x1B[0m", eol = "\x1B[K";
986
+ let logged = !1;
987
+ function showCriticalErrorBox(t) {
988
+ if (!logged && (logged = !0, !(t != null && t.trim().startsWith("Program terminated with exit")))) {
989
+ logger.log(`${redBg}
990
+ ${eol}
991
+ ${bold} WASM ERROR${reset}${redBg}`);
992
+ for (const e of t.split(`
993
+ `))
994
+ logger.log(`${eol} ${e} `);
995
+ logger.log(`${reset}`);
996
+ }
997
+ }
998
+ function extractPHPFunctionsFromStack(t) {
999
+ try {
1000
+ const e = t.split(`
1001
+ `).slice(1).map((r) => {
1002
+ const s = r.trim().substring(3).split(" ");
1003
+ return {
1004
+ fn: s.length >= 2 ? s[0] : "<unknown>",
1005
+ isWasm: r.includes("wasm://")
1006
+ };
1007
+ }).filter(
1008
+ ({ fn: r, isWasm: s }) => s && !r.startsWith("dynCall_") && !r.startsWith("invoke_")
1009
+ ).map(({ fn: r }) => r);
1010
+ return Array.from(new Set(e));
1011
+ } catch {
1012
+ return [];
1013
+ }
1014
+ }
1079
1015
  const STRING = "string", NUMBER = "number", __private__dont__use = Symbol("__private__dont__use");
1080
1016
  class PHPExecutionFailureError extends Error {
1081
- constructor(t, r, s) {
1082
- super(t), this.response = r, this.source = s;
1017
+ constructor(e, r, s) {
1018
+ super(e), this.response = r, this.source = s;
1083
1019
  }
1084
1020
  }
1085
- var w, v, R, f, P, _, S, C, Z, I, Y, A, K, k, X, M, ee, B, te, L, re, N, se, U, ne, O, ie, D, oe, $, ae, q, le, j, ce, z, ue;
1086
- class BasePHP {
1021
+ const PHP_INI_PATH = "/internal/shared/php.ini", AUTO_PREPEND_SCRIPT = "/internal/shared/auto_prepend_file.php";
1022
+ var S, E, x, v, R, M, ee, N, te, U, re, O, se, L, ne, D, ie, j, oe, $, ae, B, le, q, ce, I, K, z, ue, W, pe, G, de;
1023
+ class PHP {
1087
1024
  /**
1088
1025
  * Initializes a PHP runtime.
1089
1026
  *
@@ -1091,7 +1028,7 @@ class BasePHP {
1091
1028
  * @param PHPRuntime - Optional. PHP Runtime ID as initialized by loadPHPRuntime.
1092
1029
  * @param requestHandlerOptions - Optional. Options for the PHPRequestHandler. If undefined, no request handler will be initialized.
1093
1030
  */
1094
- constructor(e) {
1031
+ constructor(t) {
1095
1032
  /**
1096
1033
  * Prepares the $_SERVER entries for the PHP runtime.
1097
1034
  *
@@ -1101,158 +1038,306 @@ class BasePHP {
1101
1038
  * was provided.
1102
1039
  * @returns Computed $_SERVER entries.
1103
1040
  */
1104
- h(this, C);
1105
- h(this, I);
1106
- h(this, A);
1107
- h(this, k);
1108
- h(this, M);
1109
- h(this, B);
1110
- h(this, L);
1111
- h(this, N);
1112
- h(this, U);
1113
- h(this, O);
1114
- h(this, D);
1115
- h(this, $);
1116
- h(this, q);
1117
- h(this, j);
1118
- h(this, z);
1119
- h(this, w, void 0);
1120
- h(this, v, void 0);
1121
- h(this, R, void 0);
1122
- h(this, f, void 0);
1123
- h(this, P, void 0);
1124
- h(this, _, void 0);
1125
- h(this, S, void 0);
1126
- d(this, w, []), d(this, f, !1), d(this, P, null), d(this, _, /* @__PURE__ */ new Map()), d(this, S, []), this.semaphore = new Semaphore({ concurrency: 1 }), e !== void 0 && this.initializeRuntime(e);
1127
- }
1128
- addEventListener(e, t) {
1129
- u(this, _).has(e) || u(this, _).set(e, /* @__PURE__ */ new Set()), u(this, _).get(e).add(t);
1130
- }
1131
- removeEventListener(e, t) {
1041
+ p(this, M);
1042
+ p(this, N);
1043
+ p(this, U);
1044
+ p(this, O);
1045
+ p(this, L);
1046
+ p(this, D);
1047
+ p(this, j);
1048
+ p(this, $);
1049
+ p(this, B);
1050
+ p(this, q);
1051
+ p(this, I);
1052
+ p(this, z);
1053
+ p(this, W);
1054
+ p(this, G);
1055
+ p(this, S, void 0);
1056
+ p(this, E, void 0);
1057
+ p(this, x, void 0);
1058
+ p(this, v, void 0);
1059
+ p(this, R, void 0);
1060
+ f(this, E, !1), f(this, x, null), f(this, v, /* @__PURE__ */ new Map()), f(this, R, []), this.semaphore = new Semaphore({ concurrency: 1 }), t !== void 0 && this.initializeRuntime(t);
1061
+ }
1062
+ /**
1063
+ * Adds an event listener for a PHP event.
1064
+ * @param eventType - The type of event to listen for.
1065
+ * @param listener - The listener function to be called when the event is triggered.
1066
+ */
1067
+ addEventListener(t, e) {
1068
+ u(this, v).has(t) || u(this, v).set(t, /* @__PURE__ */ new Set()), u(this, v).get(t).add(e);
1069
+ }
1070
+ /**
1071
+ * Removes an event listener for a PHP event.
1072
+ * @param eventType - The type of event to remove the listener from.
1073
+ * @param listener - The listener function to be removed.
1074
+ */
1075
+ removeEventListener(t, e) {
1132
1076
  var r;
1133
- (r = u(this, _).get(e)) == null || r.delete(t);
1077
+ (r = u(this, v).get(t)) == null || r.delete(e);
1134
1078
  }
1135
- dispatchEvent(e) {
1136
- const t = u(this, _).get(e.type);
1137
- if (t)
1138
- for (const r of t)
1139
- r(e);
1079
+ dispatchEvent(t) {
1080
+ const e = u(this, v).get(t.type);
1081
+ if (e)
1082
+ for (const r of e)
1083
+ r(t);
1140
1084
  }
1141
- /** @inheritDoc */
1142
- async onMessage(e) {
1143
- u(this, S).push(e);
1085
+ /**
1086
+ * Listens to message sent by the PHP code.
1087
+ *
1088
+ * To dispatch messages, call:
1089
+ *
1090
+ * post_message_to_js(string $data)
1091
+ *
1092
+ * Arguments:
1093
+ * $data (string) – Data to pass to JavaScript.
1094
+ *
1095
+ * @example
1096
+ *
1097
+ * ```ts
1098
+ * const php = await PHP.load('8.0');
1099
+ *
1100
+ * php.onMessage(
1101
+ * // The data is always passed as a string
1102
+ * function (data: string) {
1103
+ * // Let's decode and log the data:
1104
+ * console.log(JSON.parse(data));
1105
+ * }
1106
+ * );
1107
+ *
1108
+ * // Now that we have a listener in place, let's
1109
+ * // dispatch a message:
1110
+ * await php.run({
1111
+ * code: `<?php
1112
+ * post_message_to_js(
1113
+ * json_encode([
1114
+ * 'post_id' => '15',
1115
+ * 'post_title' => 'This is a blog post!'
1116
+ * ])
1117
+ * ));
1118
+ * `,
1119
+ * });
1120
+ * ```
1121
+ *
1122
+ * @param listener Callback function to handle the message.
1123
+ */
1124
+ onMessage(t) {
1125
+ u(this, R).push(t);
1144
1126
  }
1145
- /** @inheritDoc */
1146
1127
  async setSpawnHandler(handler) {
1147
1128
  typeof handler == "string" && (handler = createSpawnHandler(eval(handler))), this[__private__dont__use].spawnProcess = handler;
1148
1129
  }
1149
- /** @inheritDoc */
1130
+ /** @deprecated Use PHPRequestHandler instead. */
1150
1131
  get absoluteUrl() {
1151
1132
  return this.requestHandler.absoluteUrl;
1152
1133
  }
1153
- /** @inheritDoc */
1134
+ /** @deprecated Use PHPRequestHandler instead. */
1154
1135
  get documentRoot() {
1155
1136
  return this.requestHandler.documentRoot;
1156
1137
  }
1157
- /** @inheritDoc */
1158
- pathToInternalUrl(e) {
1159
- return this.requestHandler.pathToInternalUrl(e);
1138
+ /** @deprecated Use PHPRequestHandler instead. */
1139
+ pathToInternalUrl(t) {
1140
+ return this.requestHandler.pathToInternalUrl(t);
1160
1141
  }
1161
- /** @inheritDoc */
1162
- internalUrlToPath(e) {
1163
- return this.requestHandler.internalUrlToPath(e);
1142
+ /** @deprecated Use PHPRequestHandler instead. */
1143
+ internalUrlToPath(t) {
1144
+ return this.requestHandler.internalUrlToPath(t);
1164
1145
  }
1165
- initializeRuntime(e) {
1146
+ initializeRuntime(t) {
1166
1147
  if (this[__private__dont__use])
1167
1148
  throw new Error("PHP runtime already initialized.");
1168
- const t = getLoadedRuntime(e);
1169
- if (!t)
1149
+ const e = getLoadedRuntime(t);
1150
+ if (!e)
1170
1151
  throw new Error("Invalid PHP runtime id.");
1171
- this[__private__dont__use] = t, t.onMessage = async (r) => {
1172
- for (const s of u(this, S)) {
1152
+ this[__private__dont__use] = e, this[__private__dont__use].ccall(
1153
+ "wasm_set_phpini_path",
1154
+ null,
1155
+ ["string"],
1156
+ [PHP_INI_PATH]
1157
+ ), this.fileExists(PHP_INI_PATH) || this.writeFile(
1158
+ PHP_INI_PATH,
1159
+ [
1160
+ "auto_prepend_file=" + AUTO_PREPEND_SCRIPT,
1161
+ "memory_limit=256M",
1162
+ "ignore_repeated_errors = 1",
1163
+ "error_reporting = E_ALL",
1164
+ "display_errors = 1",
1165
+ "html_errors = 1",
1166
+ "display_startup_errors = On",
1167
+ "log_errors = 1",
1168
+ "always_populate_raw_post_data = -1",
1169
+ "upload_max_filesize = 2000M",
1170
+ "post_max_size = 2000M",
1171
+ "disable_functions = curl_exec,curl_multi_exec",
1172
+ "allow_url_fopen = Off",
1173
+ "allow_url_include = Off",
1174
+ "session.save_path = /home/web_user",
1175
+ "implicit_flush = 1",
1176
+ "output_buffering = 0",
1177
+ "max_execution_time = 0",
1178
+ "max_input_time = -1"
1179
+ ].join(`
1180
+ `)
1181
+ ), this.fileExists(AUTO_PREPEND_SCRIPT) || this.writeFile(
1182
+ AUTO_PREPEND_SCRIPT,
1183
+ `<?php
1184
+ // Define constants set via defineConstant() calls
1185
+ if(file_exists('/internal/shared/consts.json')) {
1186
+ $consts = json_decode(file_get_contents('/internal/shared/consts.json'), true);
1187
+ foreach ($consts as $const => $value) {
1188
+ if (!defined($const) && is_scalar($value)) {
1189
+ define($const, $value);
1190
+ }
1191
+ }
1192
+ }
1193
+ // Preload all the files from /internal/shared/preload
1194
+ foreach (glob('/internal/shared/preload/*.php') as $file) {
1195
+ require_once $file;
1196
+ }
1197
+ `
1198
+ ), e.onMessage = async (r) => {
1199
+ for (const s of u(this, R)) {
1173
1200
  const n = await s(r);
1174
1201
  if (n)
1175
1202
  return n;
1176
1203
  }
1177
1204
  return "";
1178
- }, d(this, P, improveWASMErrorReporting(t)), this.dispatchEvent({
1205
+ }, f(this, x, improveWASMErrorReporting(e)), this.dispatchEvent({
1179
1206
  type: "runtime.initialized"
1180
1207
  });
1181
1208
  }
1182
1209
  /** @inheritDoc */
1183
- async setSapiName(e) {
1210
+ async setSapiName(t) {
1184
1211
  if (this[__private__dont__use].ccall(
1185
1212
  "wasm_set_sapi_name",
1186
1213
  NUMBER,
1187
1214
  [STRING],
1188
- [e]
1215
+ [t]
1189
1216
  ) !== 0)
1190
1217
  throw new Error(
1191
1218
  "Could not set SAPI name. This can only be done before the PHP WASM module is initialized.Did you already dispatch any requests?"
1192
1219
  );
1193
- d(this, R, e);
1220
+ f(this, S, t);
1194
1221
  }
1195
- /** @inheritDoc */
1196
- setPhpIniPath(e) {
1197
- if (u(this, f))
1198
- throw new Error("Cannot set PHP ini path after calling run().");
1199
- d(this, v, e), this[__private__dont__use].ccall(
1200
- "wasm_set_phpini_path",
1201
- null,
1202
- ["string"],
1203
- [e]
1204
- );
1205
- }
1206
- /** @inheritDoc */
1207
- setPhpIniEntry(e, t) {
1208
- if (u(this, f))
1209
- throw new Error("Cannot set PHP ini entries after calling run().");
1210
- u(this, w).push([e, t]);
1211
- }
1212
- /** @inheritDoc */
1213
- chdir(e) {
1214
- this[__private__dont__use].FS.chdir(e);
1222
+ /**
1223
+ * Changes the current working directory in the PHP filesystem.
1224
+ * This is the directory that will be used as the base for relative paths.
1225
+ * For example, if the current working directory is `/root/php`, and the
1226
+ * path is `data`, the absolute path will be `/root/php/data`.
1227
+ *
1228
+ * @param path - The new working directory.
1229
+ */
1230
+ chdir(t) {
1231
+ this[__private__dont__use].FS.chdir(t);
1215
1232
  }
1216
1233
  /**
1217
1234
  * Do not use. Use new PHPRequestHandler() instead.
1218
1235
  * @deprecated
1219
1236
  */
1220
- async request(e) {
1237
+ async request(t) {
1221
1238
  if (logger.warn(
1222
1239
  "PHP.request() is deprecated. Please use new PHPRequestHandler() instead."
1223
1240
  ), !this.requestHandler)
1224
1241
  throw new Error("No request handler available.");
1225
- return this.requestHandler.request(e);
1242
+ return this.requestHandler.request(t);
1226
1243
  }
1227
- /** @inheritDoc */
1228
- async run(e) {
1229
- const t = await this.semaphore.acquire();
1244
+ /**
1245
+ * Runs PHP code.
1246
+ *
1247
+ * This low-level method directly interacts with the WebAssembly
1248
+ * PHP interpreter.
1249
+ *
1250
+ * Every time you call run(), it prepares the PHP
1251
+ * environment and:
1252
+ *
1253
+ * * Resets the internal PHP state
1254
+ * * Populates superglobals ($_SERVER, $_GET, etc.)
1255
+ * * Handles file uploads
1256
+ * * Populates input streams (stdin, argv, etc.)
1257
+ * * Sets the current working directory
1258
+ *
1259
+ * You can use run() in two primary modes:
1260
+ *
1261
+ * ### Code snippet mode
1262
+ *
1263
+ * In this mode, you pass a string containing PHP code to run.
1264
+ *
1265
+ * ```ts
1266
+ * const result = await php.run({
1267
+ * code: `<?php echo "Hello world!";`
1268
+ * });
1269
+ * // result.text === "Hello world!"
1270
+ * ```
1271
+ *
1272
+ * In this mode, information like __DIR__ or __FILE__ isn't very
1273
+ * useful because the code is not associated with any file.
1274
+ *
1275
+ * Under the hood, the PHP snippet is passed to the `zend_eval_string`
1276
+ * C function.
1277
+ *
1278
+ * ### File mode
1279
+ *
1280
+ * In the file mode, you pass a scriptPath and PHP executes a file
1281
+ * found at a that path:
1282
+ *
1283
+ * ```ts
1284
+ * php.writeFile(
1285
+ * "/www/index.php",
1286
+ * `<?php echo "Hello world!";"`
1287
+ * );
1288
+ * const result = await php.run({
1289
+ * scriptPath: "/www/index.php"
1290
+ * });
1291
+ * // result.text === "Hello world!"
1292
+ * ```
1293
+ *
1294
+ * In this mode, you can rely on path-related information like __DIR__
1295
+ * or __FILE__.
1296
+ *
1297
+ * Under the hood, the PHP file is executed with the `php_execute_script`
1298
+ * C function.
1299
+ *
1300
+ * The `run()` method cannot be used in conjunction with `cli()`.
1301
+ *
1302
+ * @example
1303
+ * ```js
1304
+ * const result = await php.run(`<?php
1305
+ * $fp = fopen('php://stderr', 'w');
1306
+ * fwrite($fp, "Hello, world!");
1307
+ * `);
1308
+ * // result.errors === "Hello, world!"
1309
+ * ```
1310
+ *
1311
+ * @param options - PHP runtime options.
1312
+ */
1313
+ async run(t) {
1314
+ const e = await this.semaphore.acquire();
1230
1315
  let r;
1231
1316
  try {
1232
- if (u(this, f) || (p(this, I, Y).call(this), d(this, f, !0)), e.scriptPath && !this.fileExists(e.scriptPath))
1317
+ if (u(this, E) || (h(this, N, te).call(this), f(this, E, !0)), t.scriptPath && !this.fileExists(t.scriptPath))
1233
1318
  throw new Error(
1234
- `The script path "${e.scriptPath}" does not exist.`
1319
+ `The script path "${t.scriptPath}" does not exist.`
1235
1320
  );
1236
- p(this, D, oe).call(this, e.scriptPath || ""), p(this, k, X).call(this, e.relativeUri || ""), p(this, N, se).call(this, e.method || "GET");
1237
- const s = normalizeHeaders(e.headers || {}), n = s.host || "example.com:443", i = p(this, L, re).call(this, n, e.protocol || "http");
1238
- p(this, M, ee).call(this, n), p(this, B, te).call(this, i), p(this, U, ne).call(this, s), e.body && (r = p(this, O, ie).call(this, e.body)), typeof e.code == "string" && p(this, j, ce).call(this, " ?>" + e.code);
1239
- const o = p(this, C, Z).call(this, e.$_SERVER, s, i);
1240
- for (const c in o)
1241
- p(this, $, ae).call(this, c, o[c]);
1242
- const a = e.env || {};
1243
- for (const c in a)
1244
- p(this, q, le).call(this, c, a[c]);
1245
- const l = await p(this, z, ue).call(this);
1246
- if (l.exitCode !== 0) {
1247
- logger.warn("PHP.run() output was:", l.text);
1248
- const c = new PHPExecutionFailureError(
1249
- `PHP.run() failed with exit code ${l.exitCode} and the following output: ` + l.errors,
1250
- l,
1321
+ h(this, O, se).call(this, t.relativeUri || ""), h(this, $, ae).call(this, t.method || "GET");
1322
+ const s = normalizeHeaders(t.headers || {}), n = s.host || "example.com:443", i = h(this, j, oe).call(this, n, t.protocol || "http");
1323
+ h(this, L, ne).call(this, n), h(this, D, ie).call(this, i), h(this, B, le).call(this, s), t.body && (r = h(this, q, ce).call(this, t.body)), typeof t.code == "string" ? (this.writeFile("/internal/eval.php", t.code), h(this, I, K).call(this, "/internal/eval.php")) : h(this, I, K).call(this, t.scriptPath || "");
1324
+ const o = h(this, M, ee).call(this, t.$_SERVER, s, i);
1325
+ for (const a in o)
1326
+ h(this, z, ue).call(this, a, o[a]);
1327
+ const l = t.env || {};
1328
+ for (const a in l)
1329
+ h(this, W, pe).call(this, a, l[a]);
1330
+ const c = await h(this, G, de).call(this);
1331
+ if (c.exitCode !== 0) {
1332
+ logger.warn("PHP.run() output was:", c.text);
1333
+ const a = new PHPExecutionFailureError(
1334
+ `PHP.run() failed with exit code ${c.exitCode} and the following output: ` + c.errors,
1335
+ c,
1251
1336
  "request"
1252
1337
  );
1253
- throw logger.error(c), c;
1338
+ throw logger.error(a), a;
1254
1339
  }
1255
- return l;
1340
+ return c;
1256
1341
  } catch (s) {
1257
1342
  throw this.dispatchEvent({
1258
1343
  type: "request.error",
@@ -1264,433 +1349,1020 @@ class BasePHP {
1264
1349
  try {
1265
1350
  r && this[__private__dont__use].free(r);
1266
1351
  } finally {
1267
- t(), this.dispatchEvent({
1352
+ e(), this.dispatchEvent({
1268
1353
  type: "request.end"
1269
1354
  });
1270
1355
  }
1271
1356
  }
1272
1357
  }
1273
- defineConstant(e, t) {
1358
+ /**
1359
+ * Defines a constant in the PHP runtime.
1360
+ * @param key - The name of the constant.
1361
+ * @param value - The value of the constant.
1362
+ */
1363
+ defineConstant(t, e) {
1274
1364
  let r = {};
1275
1365
  try {
1276
1366
  r = JSON.parse(
1277
- this.fileExists("/internal/consts.json") && this.readFileAsText("/internal/consts.json") || "{}"
1367
+ this.fileExists("/internal/shared/consts.json") && this.readFileAsText("/internal/shared/consts.json") || "{}"
1278
1368
  );
1279
1369
  } catch {
1280
1370
  }
1281
1371
  this.writeFile(
1282
- "/internal/consts.json",
1372
+ "/internal/shared/consts.json",
1283
1373
  JSON.stringify({
1284
1374
  ...r,
1285
- [e]: t
1375
+ [t]: e
1286
1376
  })
1287
1377
  );
1288
1378
  }
1289
- mkdir(e) {
1290
- this[__private__dont__use].FS.mkdirTree(e);
1379
+ /**
1380
+ * Recursively creates a directory with the given path in the PHP filesystem.
1381
+ * For example, if the path is `/root/php/data`, and `/root` already exists,
1382
+ * it will create the directories `/root/php` and `/root/php/data`.
1383
+ *
1384
+ * @param path - The directory path to create.
1385
+ */
1386
+ mkdir(t) {
1387
+ return FSHelpers.mkdir(this[__private__dont__use].FS, t);
1291
1388
  }
1292
- mkdirTree(e) {
1293
- this.mkdir(e);
1389
+ /**
1390
+ * @deprecated Use mkdir instead.
1391
+ */
1392
+ mkdirTree(t) {
1393
+ return FSHelpers.mkdir(this[__private__dont__use].FS, t);
1294
1394
  }
1295
- readFileAsText(e) {
1296
- return new TextDecoder().decode(this.readFileAsBuffer(e));
1395
+ /**
1396
+ * Reads a file from the PHP filesystem and returns it as a string.
1397
+ *
1398
+ * @throws {@link @php-wasm/universal:ErrnoError} – If the file doesn't exist.
1399
+ * @param path - The file path to read.
1400
+ * @returns The file contents.
1401
+ */
1402
+ readFileAsText(t) {
1403
+ return FSHelpers.readFileAsText(this[__private__dont__use].FS, t);
1297
1404
  }
1298
- readFileAsBuffer(e) {
1299
- return this[__private__dont__use].FS.readFile(e);
1405
+ /**
1406
+ * Reads a file from the PHP filesystem and returns it as an array buffer.
1407
+ *
1408
+ * @throws {@link @php-wasm/universal:ErrnoError} – If the file doesn't exist.
1409
+ * @param path - The file path to read.
1410
+ * @returns The file contents.
1411
+ */
1412
+ readFileAsBuffer(t) {
1413
+ return FSHelpers.readFileAsBuffer(this[__private__dont__use].FS, t);
1300
1414
  }
1301
- writeFile(e, t) {
1302
- this[__private__dont__use].FS.writeFile(e, t);
1415
+ /**
1416
+ * Overwrites data in a file in the PHP filesystem.
1417
+ * Creates a new file if one doesn't exist yet.
1418
+ *
1419
+ * @param path - The file path to write to.
1420
+ * @param data - The data to write to the file.
1421
+ */
1422
+ writeFile(t, e) {
1423
+ return FSHelpers.writeFile(this[__private__dont__use].FS, t, e);
1303
1424
  }
1304
- unlink(e) {
1305
- this[__private__dont__use].FS.unlink(e);
1425
+ /**
1426
+ * Removes a file from the PHP filesystem.
1427
+ *
1428
+ * @throws {@link @php-wasm/universal:ErrnoError} – If the file doesn't exist.
1429
+ * @param path - The file path to remove.
1430
+ */
1431
+ unlink(t) {
1432
+ return FSHelpers.unlink(this[__private__dont__use].FS, t);
1306
1433
  }
1307
- /** @inheritDoc */
1308
- mv(e, t) {
1434
+ /**
1435
+ * Moves a file or directory in the PHP filesystem to a
1436
+ * new location.
1437
+ *
1438
+ * @param oldPath The path to rename.
1439
+ * @param newPath The new path.
1440
+ */
1441
+ mv(t, e) {
1442
+ return FSHelpers.mv(this[__private__dont__use].FS, t, e);
1443
+ }
1444
+ /**
1445
+ * Removes a directory from the PHP filesystem.
1446
+ *
1447
+ * @param path The directory path to remove.
1448
+ * @param options Options for the removal.
1449
+ */
1450
+ rmdir(t, e = { recursive: !0 }) {
1451
+ return FSHelpers.rmdir(this[__private__dont__use].FS, t, e);
1452
+ }
1453
+ /**
1454
+ * Lists the files and directories in the given directory.
1455
+ *
1456
+ * @param path - The directory path to list.
1457
+ * @param options - Options for the listing.
1458
+ * @returns The list of files and directories in the given directory.
1459
+ */
1460
+ listFiles(t, e = { prependPath: !1 }) {
1461
+ return FSHelpers.listFiles(
1462
+ this[__private__dont__use].FS,
1463
+ t,
1464
+ e
1465
+ );
1466
+ }
1467
+ /**
1468
+ * Checks if a directory exists in the PHP filesystem.
1469
+ *
1470
+ * @param path – The path to check.
1471
+ * @returns True if the path is a directory, false otherwise.
1472
+ */
1473
+ isDir(t) {
1474
+ return FSHelpers.isDir(this[__private__dont__use].FS, t);
1475
+ }
1476
+ /**
1477
+ * Checks if a file (or a directory) exists in the PHP filesystem.
1478
+ *
1479
+ * @param path - The file path to check.
1480
+ * @returns True if the file exists, false otherwise.
1481
+ */
1482
+ fileExists(t) {
1483
+ return FSHelpers.fileExists(this[__private__dont__use].FS, t);
1484
+ }
1485
+ /**
1486
+ * Hot-swaps the PHP runtime for a new one without
1487
+ * interrupting the operations of this PHP instance.
1488
+ *
1489
+ * @param runtime
1490
+ * @param cwd. Internal, the VFS path to recreate in the new runtime.
1491
+ * This arg is temporary and will be removed once BasePHP
1492
+ * is fully decoupled from the request handler and
1493
+ * accepts a constructor-level cwd argument.
1494
+ */
1495
+ hotSwapPHPRuntime(t, e) {
1496
+ const r = this[__private__dont__use].FS;
1497
+ try {
1498
+ this.exit();
1499
+ } catch {
1500
+ }
1501
+ this.initializeRuntime(t), u(this, S) && this.setSapiName(u(this, S)), e && copyFS(r, this[__private__dont__use].FS, e);
1502
+ }
1503
+ /**
1504
+ * Mounts a filesystem to a given path in the PHP filesystem.
1505
+ *
1506
+ * @param virtualFSPath - Where to mount it in the PHP virtual filesystem.
1507
+ * @param mountHandler - The mount handler to use.
1508
+ * @return Unmount function to unmount the filesystem.
1509
+ */
1510
+ async mount(t, e) {
1511
+ return await e(
1512
+ this,
1513
+ this[__private__dont__use].FS,
1514
+ t
1515
+ );
1516
+ }
1517
+ /**
1518
+ * Starts a PHP CLI session with given arguments.
1519
+ *
1520
+ * This method can only be used when PHP was compiled with the CLI SAPI
1521
+ * and it cannot be used in conjunction with `run()`.
1522
+ *
1523
+ * Once this method finishes running, the PHP instance is no
1524
+ * longer usable and should be discarded. This is because PHP
1525
+ * internally cleans up all the resources and calls exit().
1526
+ *
1527
+ * @param argv - The arguments to pass to the CLI.
1528
+ * @returns The exit code of the CLI session.
1529
+ */
1530
+ async cli(t) {
1531
+ for (const e of t)
1532
+ this[__private__dont__use].ccall(
1533
+ "wasm_add_cli_arg",
1534
+ null,
1535
+ [STRING],
1536
+ [e]
1537
+ );
1309
1538
  try {
1310
- this[__private__dont__use].FS.rename(e, t);
1311
- } catch (r) {
1312
- const s = getEmscriptenFsError(r);
1313
- throw s ? new Error(
1314
- `Could not move ${e} to ${t}: ${s}`,
1539
+ return await this[__private__dont__use].ccall(
1540
+ "run_cli",
1541
+ null,
1542
+ [],
1543
+ [],
1315
1544
  {
1316
- cause: r
1545
+ async: !0
1317
1546
  }
1318
- ) : r;
1547
+ );
1548
+ } catch (e) {
1549
+ if (isExitCodeZero(e))
1550
+ return 0;
1551
+ throw e;
1319
1552
  }
1320
1553
  }
1321
- rmdir(e, t = { recursive: !0 }) {
1322
- t != null && t.recursive && this.listFiles(e).forEach((r) => {
1323
- const s = `${e}/${r}`;
1324
- this.isDir(s) ? this.rmdir(s, t) : this.unlink(s);
1325
- }), this[__private__dont__use].FS.rmdir(e);
1554
+ setSkipShebang(t) {
1555
+ this[__private__dont__use].ccall(
1556
+ "wasm_set_skip_shebang",
1557
+ null,
1558
+ [NUMBER],
1559
+ [t ? 1 : 0]
1560
+ );
1326
1561
  }
1327
- listFiles(e, t = { prependPath: !1 }) {
1328
- if (!this.fileExists(e))
1329
- return [];
1562
+ exit(t = 0) {
1563
+ this.dispatchEvent({
1564
+ type: "runtime.beforedestroy"
1565
+ });
1330
1566
  try {
1331
- const r = this[__private__dont__use].FS.readdir(e).filter(
1332
- (s) => s !== "." && s !== ".."
1567
+ this[__private__dont__use]._exit(t);
1568
+ } catch {
1569
+ }
1570
+ f(this, E, !1), f(this, x, null), delete this[__private__dont__use].onMessage, delete this[__private__dont__use];
1571
+ }
1572
+ [Symbol.dispose]() {
1573
+ u(this, E) && this.exit(0);
1574
+ }
1575
+ }
1576
+ S = new WeakMap(), E = new WeakMap(), x = new WeakMap(), v = new WeakMap(), R = new WeakMap(), M = new WeakSet(), ee = function(t, e, r) {
1577
+ const s = {
1578
+ ...t || {}
1579
+ };
1580
+ s.HTTPS = s.HTTPS || r === 443 ? "on" : "off";
1581
+ for (const n in e) {
1582
+ let i = "HTTP_";
1583
+ ["content-type", "content-length"].includes(n.toLowerCase()) && (i = ""), s[`${i}${n.toUpperCase().replace(/-/g, "_")}`] = e[n];
1584
+ }
1585
+ return s;
1586
+ }, N = new WeakSet(), te = function() {
1587
+ this[__private__dont__use].ccall("php_wasm_init", null, [], []);
1588
+ }, U = new WeakSet(), re = function() {
1589
+ const t = "/internal/headers.json";
1590
+ if (!this.fileExists(t))
1591
+ throw new Error(
1592
+ "SAPI Error: Could not find response headers file."
1593
+ );
1594
+ const e = JSON.parse(this.readFileAsText(t)), r = {};
1595
+ for (const s of e.headers) {
1596
+ if (!s.includes(": "))
1597
+ continue;
1598
+ const n = s.indexOf(": "), i = s.substring(0, n).toLowerCase(), o = s.substring(n + 2);
1599
+ i in r || (r[i] = []), r[i].push(o);
1600
+ }
1601
+ return {
1602
+ headers: r,
1603
+ httpStatusCode: e.status
1604
+ };
1605
+ }, O = new WeakSet(), se = function(t) {
1606
+ if (this[__private__dont__use].ccall(
1607
+ "wasm_set_request_uri",
1608
+ null,
1609
+ [STRING],
1610
+ [t]
1611
+ ), t.includes("?")) {
1612
+ const e = t.substring(t.indexOf("?") + 1);
1613
+ this[__private__dont__use].ccall(
1614
+ "wasm_set_query_string",
1615
+ null,
1616
+ [STRING],
1617
+ [e]
1618
+ );
1619
+ }
1620
+ }, L = new WeakSet(), ne = function(t) {
1621
+ this[__private__dont__use].ccall(
1622
+ "wasm_set_request_host",
1623
+ null,
1624
+ [STRING],
1625
+ [t]
1626
+ );
1627
+ }, D = new WeakSet(), ie = function(t) {
1628
+ this[__private__dont__use].ccall(
1629
+ "wasm_set_request_port",
1630
+ null,
1631
+ [NUMBER],
1632
+ [t]
1633
+ );
1634
+ }, j = new WeakSet(), oe = function(t, e) {
1635
+ let r;
1636
+ try {
1637
+ r = parseInt(new URL(t).port, 10);
1638
+ } catch {
1639
+ }
1640
+ return (!r || isNaN(r) || r === 80) && (r = e === "https" ? 443 : 80), r;
1641
+ }, $ = new WeakSet(), ae = function(t) {
1642
+ this[__private__dont__use].ccall(
1643
+ "wasm_set_request_method",
1644
+ null,
1645
+ [STRING],
1646
+ [t]
1647
+ );
1648
+ }, B = new WeakSet(), le = function(t) {
1649
+ t.cookie && this[__private__dont__use].ccall(
1650
+ "wasm_set_cookies",
1651
+ null,
1652
+ [STRING],
1653
+ [t.cookie]
1654
+ ), t["content-type"] && this[__private__dont__use].ccall(
1655
+ "wasm_set_content_type",
1656
+ null,
1657
+ [STRING],
1658
+ [t["content-type"]]
1659
+ ), t["content-length"] && this[__private__dont__use].ccall(
1660
+ "wasm_set_content_length",
1661
+ null,
1662
+ [NUMBER],
1663
+ [parseInt(t["content-length"], 10)]
1664
+ );
1665
+ }, q = new WeakSet(), ce = function(t) {
1666
+ let e, r;
1667
+ typeof t == "string" ? (logger.warn(
1668
+ "Passing a string as the request body is deprecated. Please use a Uint8Array instead. See https://github.com/WordPress/wordpress-playground/issues/997 for more details"
1669
+ ), r = this[__private__dont__use].lengthBytesUTF8(t), e = r + 1) : (r = t.byteLength, e = t.byteLength);
1670
+ const s = this[__private__dont__use].malloc(e);
1671
+ if (!s)
1672
+ throw new Error("Could not allocate memory for the request body.");
1673
+ return typeof t == "string" ? this[__private__dont__use].stringToUTF8(
1674
+ t,
1675
+ s,
1676
+ e + 1
1677
+ ) : this[__private__dont__use].HEAPU8.set(t, s), this[__private__dont__use].ccall(
1678
+ "wasm_set_request_body",
1679
+ null,
1680
+ [NUMBER],
1681
+ [s]
1682
+ ), this[__private__dont__use].ccall(
1683
+ "wasm_set_content_length",
1684
+ null,
1685
+ [NUMBER],
1686
+ [r]
1687
+ ), s;
1688
+ }, I = new WeakSet(), K = function(t) {
1689
+ this[__private__dont__use].ccall(
1690
+ "wasm_set_path_translated",
1691
+ null,
1692
+ [STRING],
1693
+ [t]
1694
+ );
1695
+ }, z = new WeakSet(), ue = function(t, e) {
1696
+ this[__private__dont__use].ccall(
1697
+ "wasm_add_SERVER_entry",
1698
+ null,
1699
+ [STRING, STRING],
1700
+ [t, e]
1701
+ );
1702
+ }, W = new WeakSet(), pe = function(t, e) {
1703
+ this[__private__dont__use].ccall(
1704
+ "wasm_add_ENV_entry",
1705
+ null,
1706
+ [STRING, STRING],
1707
+ [t, e]
1708
+ );
1709
+ }, G = new WeakSet(), de = async function() {
1710
+ var n;
1711
+ let t, e;
1712
+ try {
1713
+ t = await new Promise((i, o) => {
1714
+ var c;
1715
+ e = (a) => {
1716
+ logger.error(a), logger.error(a.error);
1717
+ const d = new Error("Rethrown");
1718
+ d.cause = a.error, d.betterMessage = a.message, o(d);
1719
+ }, (c = u(this, x)) == null || c.addEventListener(
1720
+ "error",
1721
+ e
1722
+ );
1723
+ const l = this[__private__dont__use].ccall(
1724
+ "wasm_sapi_handle_request",
1725
+ NUMBER,
1726
+ [],
1727
+ [],
1728
+ { async: !0 }
1729
+ );
1730
+ return l instanceof Promise ? l.then(i, o) : i(l);
1731
+ });
1732
+ } catch (i) {
1733
+ for (const a in this)
1734
+ typeof this[a] == "function" && (this[a] = () => {
1735
+ throw new Error(
1736
+ "PHP runtime has crashed – see the earlier error for details."
1737
+ );
1738
+ });
1739
+ this.functionsMaybeMissingFromAsyncify = getFunctionsMaybeMissingFromAsyncify();
1740
+ const o = i, l = "betterMessage" in o ? o.betterMessage : o.message, c = new Error(l);
1741
+ throw c.cause = o, logger.error(c), c;
1742
+ } finally {
1743
+ (n = u(this, x)) == null || n.removeEventListener("error", e);
1744
+ }
1745
+ const { headers: r, httpStatusCode: s } = h(this, U, re).call(this);
1746
+ return new PHPResponse(
1747
+ t === 0 ? s : 500,
1748
+ r,
1749
+ this.readFileAsBuffer("/internal/stdout"),
1750
+ this.readFileAsText("/internal/stderr"),
1751
+ t
1752
+ );
1753
+ };
1754
+ function normalizeHeaders(t) {
1755
+ const e = {};
1756
+ for (const r in t)
1757
+ e[r.toLowerCase()] = t[r];
1758
+ return e;
1759
+ }
1760
+ function copyFS(t, e, r) {
1761
+ let s;
1762
+ try {
1763
+ s = t.lookupPath(r);
1764
+ } catch {
1765
+ return;
1766
+ }
1767
+ if (!("contents" in s.node))
1768
+ return;
1769
+ if (!t.isDir(s.node.mode)) {
1770
+ e.writeFile(r, t.readFile(r));
1771
+ return;
1772
+ }
1773
+ e.mkdirTree(r);
1774
+ const n = t.readdir(r).filter((i) => i !== "." && i !== "..");
1775
+ for (const i of n)
1776
+ copyFS(t, e, joinPaths(r, i));
1777
+ }
1778
+ const { hasOwnProperty } = Object.prototype, encode = (t, e = {}) => {
1779
+ typeof e == "string" && (e = { section: e }), e.align = e.align === !0, e.newline = e.newline === !0, e.sort = e.sort === !0, e.whitespace = e.whitespace === !0 || e.align === !0, e.platform = e.platform || typeof process < "u" && process.platform, e.bracketedArray = e.bracketedArray !== !1;
1780
+ const r = e.platform === "win32" ? `\r
1781
+ ` : `
1782
+ `, s = e.whitespace ? " = " : "=", n = [], i = e.sort ? Object.keys(t).sort() : Object.keys(t);
1783
+ let o = 0;
1784
+ e.align && (o = safe(
1785
+ i.filter((a) => t[a] === null || Array.isArray(t[a]) || typeof t[a] != "object").map((a) => Array.isArray(t[a]) ? `${a}[]` : a).concat([""]).reduce((a, d) => safe(a).length >= safe(d).length ? a : d)
1786
+ ).length);
1787
+ let l = "";
1788
+ const c = e.bracketedArray ? "[]" : "";
1789
+ for (const a of i) {
1790
+ const d = t[a];
1791
+ if (d && Array.isArray(d))
1792
+ for (const m of d)
1793
+ l += safe(`${a}${c}`).padEnd(o, " ") + s + safe(m) + r;
1794
+ else
1795
+ d && typeof d == "object" ? n.push(a) : l += safe(a).padEnd(o, " ") + s + safe(d) + r;
1796
+ }
1797
+ e.section && l.length && (l = "[" + safe(e.section) + "]" + (e.newline ? r + r : r) + l);
1798
+ for (const a of n) {
1799
+ const d = splitSections(a, ".").join("\\."), m = (e.section ? e.section + "." : "") + d, y = encode(t[a], {
1800
+ ...e,
1801
+ section: m
1802
+ });
1803
+ l.length && y.length && (l += r), l += y;
1804
+ }
1805
+ return l;
1806
+ };
1807
+ function splitSections(t, e) {
1808
+ var r = 0, s = 0, n = 0, i = [];
1809
+ do
1810
+ if (n = t.indexOf(e, r), n !== -1) {
1811
+ if (r = n + e.length, n > 0 && t[n - 1] === "\\")
1812
+ continue;
1813
+ i.push(t.slice(s, n)), s = n + e.length;
1814
+ }
1815
+ while (n !== -1);
1816
+ return i.push(t.slice(s)), i;
1817
+ }
1818
+ const decode = (t, e = {}) => {
1819
+ e.bracketedArray = e.bracketedArray !== !1;
1820
+ const r = /* @__PURE__ */ Object.create(null);
1821
+ let s = r, n = null;
1822
+ const i = /^\[([^\]]*)\]\s*$|^([^=]+)(=(.*))?$/i, o = t.split(/[\r\n]+/g), l = {};
1823
+ for (const a of o) {
1824
+ if (!a || a.match(/^\s*[;#]/) || a.match(/^\s*$/))
1825
+ continue;
1826
+ const d = a.match(i);
1827
+ if (!d)
1828
+ continue;
1829
+ if (d[1] !== void 0) {
1830
+ if (n = unsafe(d[1]), n === "__proto__") {
1831
+ s = /* @__PURE__ */ Object.create(null);
1832
+ continue;
1833
+ }
1834
+ s = r[n] = r[n] || /* @__PURE__ */ Object.create(null);
1835
+ continue;
1836
+ }
1837
+ const m = unsafe(d[2]);
1838
+ let y;
1839
+ e.bracketedArray ? y = m.length > 2 && m.slice(-2) === "[]" : (l[m] = ((l == null ? void 0 : l[m]) || 0) + 1, y = l[m] > 1);
1840
+ const _ = y ? m.slice(0, -2) : m;
1841
+ if (_ === "__proto__")
1842
+ continue;
1843
+ const A = d[3] ? unsafe(d[4]) : !0, X = A === "true" || A === "false" || A === "null" ? JSON.parse(A) : A;
1844
+ y && (hasOwnProperty.call(s, _) ? Array.isArray(s[_]) || (s[_] = [s[_]]) : s[_] = []), Array.isArray(s[_]) ? s[_].push(X) : s[_] = X;
1845
+ }
1846
+ const c = [];
1847
+ for (const a of Object.keys(r)) {
1848
+ if (!hasOwnProperty.call(r, a) || typeof r[a] != "object" || Array.isArray(r[a]))
1849
+ continue;
1850
+ const d = splitSections(a, ".");
1851
+ s = r;
1852
+ const m = d.pop(), y = m.replace(/\\\./g, ".");
1853
+ for (const _ of d)
1854
+ _ !== "__proto__" && ((!hasOwnProperty.call(s, _) || typeof s[_] != "object") && (s[_] = /* @__PURE__ */ Object.create(null)), s = s[_]);
1855
+ s === r && y === m || (s[y] = r[a], c.push(a));
1856
+ }
1857
+ for (const a of c)
1858
+ delete r[a];
1859
+ return r;
1860
+ }, isQuoted = (t) => t.startsWith('"') && t.endsWith('"') || t.startsWith("'") && t.endsWith("'"), safe = (t) => typeof t != "string" || t.match(/[=\r\n]/) || t.match(/^\[/) || t.length > 1 && isQuoted(t) || t !== t.trim() ? JSON.stringify(t) : t.split(";").join("\\;").split("#").join("\\#"), unsafe = (t) => {
1861
+ if (t = (t || "").trim(), isQuoted(t)) {
1862
+ t.charAt(0) === "'" && (t = t.slice(1, -1));
1863
+ try {
1864
+ t = JSON.parse(t);
1865
+ } catch {
1866
+ }
1867
+ } else {
1868
+ let e = !1, r = "";
1869
+ for (let s = 0, n = t.length; s < n; s++) {
1870
+ const i = t.charAt(s);
1871
+ if (e)
1872
+ "\\;#".indexOf(i) !== -1 ? r += i : r += "\\" + i, e = !1;
1873
+ else {
1874
+ if (";#".indexOf(i) !== -1)
1875
+ break;
1876
+ i === "\\" ? e = !0 : r += i;
1877
+ }
1878
+ }
1879
+ return e && (r += "\\"), r.trim();
1880
+ }
1881
+ return t;
1882
+ };
1883
+ var ini = {
1884
+ parse: decode,
1885
+ decode,
1886
+ stringify: encode,
1887
+ encode,
1888
+ safe,
1889
+ unsafe
1890
+ };
1891
+ async function getPhpIniEntries(t, e) {
1892
+ const r = ini.parse(await t.readFileAsText(PHP_INI_PATH));
1893
+ if (e === void 0)
1894
+ return r;
1895
+ const s = {};
1896
+ for (const n of e)
1897
+ s[n] = r[n];
1898
+ return s;
1899
+ }
1900
+ async function setPhpIniEntries(t, e) {
1901
+ const r = ini.parse(await t.readFileAsText(PHP_INI_PATH));
1902
+ for (const [s, n] of Object.entries(e))
1903
+ n == null ? delete r[s] : r[s] = n;
1904
+ await t.writeFile(PHP_INI_PATH, ini.stringify(r));
1905
+ }
1906
+ async function withPHPIniValues(t, e, r) {
1907
+ const s = await t.readFileAsText(PHP_INI_PATH);
1908
+ try {
1909
+ return await setPhpIniEntries(t, e), await r();
1910
+ } finally {
1911
+ await t.writeFile(PHP_INI_PATH, s);
1912
+ }
1913
+ }
1914
+ class HttpCookieStore {
1915
+ constructor() {
1916
+ this.cookies = {};
1917
+ }
1918
+ rememberCookiesFromResponseHeaders(e) {
1919
+ if (e != null && e["set-cookie"])
1920
+ for (const r of e["set-cookie"])
1921
+ try {
1922
+ if (!r.includes("="))
1923
+ continue;
1924
+ const s = r.indexOf("="), n = r.substring(0, s), i = r.substring(s + 1).split(";")[0];
1925
+ this.cookies[n] = i;
1926
+ } catch (s) {
1927
+ logger.error(s);
1928
+ }
1929
+ }
1930
+ getCookieRequestHeader() {
1931
+ const e = [];
1932
+ for (const r in this.cookies)
1933
+ e.push(`${r}=${this.cookies[r]}`);
1934
+ return e.join("; ");
1935
+ }
1936
+ }
1937
+ function concatUint8Array(...t) {
1938
+ const e = new Uint8Array(
1939
+ t.reduce((s, n) => s + n.length, 0)
1940
+ );
1941
+ let r = 0;
1942
+ for (const s of t)
1943
+ e.set(s, r), r += s.length;
1944
+ return e;
1945
+ }
1946
+ function concatBytes(t) {
1947
+ if (t === void 0) {
1948
+ let e = new Uint8Array();
1949
+ return new TransformStream({
1950
+ transform(r) {
1951
+ e = concatUint8Array(e, r);
1952
+ },
1953
+ flush(r) {
1954
+ r.enqueue(e);
1955
+ }
1956
+ });
1957
+ } else {
1958
+ const e = new ArrayBuffer(t || 0);
1959
+ let r = 0;
1960
+ return new TransformStream({
1961
+ transform(s) {
1962
+ new Uint8Array(e).set(s, r), r += s.byteLength;
1963
+ },
1964
+ flush(s) {
1965
+ s.enqueue(new Uint8Array(e));
1966
+ }
1967
+ });
1968
+ }
1969
+ }
1970
+ function limitBytes(t, e) {
1971
+ if (e === 0)
1972
+ return new ReadableStream({
1973
+ start(n) {
1974
+ n.close();
1975
+ }
1976
+ });
1977
+ const r = t.getReader({ mode: "byob" });
1978
+ let s = 0;
1979
+ return new ReadableStream({
1980
+ async pull(n) {
1981
+ const { value: i, done: o } = await r.read(
1982
+ new Uint8Array(e - s)
1983
+ );
1984
+ if (o) {
1985
+ r.releaseLock(), n.close();
1986
+ return;
1987
+ }
1988
+ s += i.length, n.enqueue(i), s >= e && (r.releaseLock(), n.close());
1989
+ },
1990
+ cancel() {
1991
+ r.cancel();
1992
+ }
1993
+ });
1994
+ }
1995
+ async function collectBytes(t, e) {
1996
+ return e !== void 0 && (t = limitBytes(t, e)), await t.pipeThrough(concatBytes(e)).getReader().read().then(({ value: r }) => r);
1997
+ }
1998
+ class StreamedFile extends File {
1999
+ /**
2000
+ * Creates a new StreamedFile instance.
2001
+ *
2002
+ * @param readableStream The readable stream containing the file data.
2003
+ * @param name The name of the file.
2004
+ * @param type The MIME type of the file.
2005
+ */
2006
+ constructor(e, r, s) {
2007
+ super([], r, { type: s }), this.readableStream = e;
2008
+ }
2009
+ /**
2010
+ * Overrides the slice() method of the File class.
2011
+ *
2012
+ * @returns A Blob representing a portion of the file.
2013
+ */
2014
+ slice() {
2015
+ throw new Error("slice() is not possible on a StreamedFile");
2016
+ }
2017
+ /**
2018
+ * Returns the readable stream associated with the file.
2019
+ *
2020
+ * @returns The readable stream.
2021
+ */
2022
+ stream() {
2023
+ return this.readableStream;
2024
+ }
2025
+ /**
2026
+ * Loads the file data into memory and then returns it as a string.
2027
+ *
2028
+ * @returns File data as text.
2029
+ */
2030
+ async text() {
2031
+ return new TextDecoder().decode(await this.arrayBuffer());
2032
+ }
2033
+ /**
2034
+ * Loads the file data into memory and then returns it as an ArrayBuffer.
2035
+ *
2036
+ * @returns File data as an ArrayBuffer.
2037
+ */
2038
+ async arrayBuffer() {
2039
+ return await collectBytes(this.stream());
2040
+ }
2041
+ }
2042
+ ReadableStream.prototype[Symbol.asyncIterator] || (ReadableStream.prototype[Symbol.asyncIterator] = async function* () {
2043
+ const t = this.getReader();
2044
+ try {
2045
+ for (; ; ) {
2046
+ const { done: e, value: r } = await t.read();
2047
+ if (e)
2048
+ return;
2049
+ yield r;
2050
+ }
2051
+ } finally {
2052
+ t.releaseLock();
2053
+ }
2054
+ }, ReadableStream.prototype.iterate = // @ts-ignore
2055
+ ReadableStream.prototype[Symbol.asyncIterator]);
2056
+ function streamReadFileFromPHP(t, e) {
2057
+ return new ReadableStream({
2058
+ async pull(r) {
2059
+ const s = await t.readFileAsBuffer(e);
2060
+ r.enqueue(s), r.close();
2061
+ }
2062
+ });
2063
+ }
2064
+ async function* iteratePhpFiles(t, e, {
2065
+ relativePaths: r = !0,
2066
+ pathPrefix: s,
2067
+ exceptPaths: n = []
2068
+ } = {}) {
2069
+ e = normalizePath(e);
2070
+ const i = [e];
2071
+ for (; i.length; ) {
2072
+ const o = i.pop();
2073
+ if (!o)
2074
+ return;
2075
+ const l = await t.listFiles(o);
2076
+ for (const c of l) {
2077
+ const a = `${o}/${c}`;
2078
+ if (n.includes(a.substring(e.length + 1)))
2079
+ continue;
2080
+ await t.isDir(a) ? i.push(a) : yield new StreamedFile(
2081
+ streamReadFileFromPHP(t, a),
2082
+ r ? joinPaths(
2083
+ s || "",
2084
+ a.substring(e.length + 1)
2085
+ ) : a
2086
+ );
2087
+ }
2088
+ }
2089
+ }
2090
+ function writeFilesStreamToPhp(t, e) {
2091
+ return new WritableStream({
2092
+ async write(r) {
2093
+ const s = joinPaths(e, r.name);
2094
+ r.type === "directory" ? await t.mkdir(s) : (await t.mkdir(dirname(s)), await t.writeFile(
2095
+ s,
2096
+ new Uint8Array(await r.arrayBuffer())
2097
+ ));
2098
+ }
2099
+ });
2100
+ }
2101
+ class MaxPhpInstancesError extends Error {
2102
+ constructor(e) {
2103
+ super(
2104
+ `Requested more concurrent PHP instances than the limit (${e}).`
2105
+ ), this.name = this.constructor.name;
2106
+ }
2107
+ }
2108
+ class PHPProcessManager {
2109
+ constructor(e) {
2110
+ this.primaryIdle = !0, this.nextInstance = null, this.allInstances = [], this.maxPhpInstances = (e == null ? void 0 : e.maxPhpInstances) ?? 5, this.phpFactory = e == null ? void 0 : e.phpFactory, this.primaryPhp = e == null ? void 0 : e.primaryPhp, this.semaphore = new Semaphore({
2111
+ concurrency: this.maxPhpInstances,
2112
+ /**
2113
+ * Wait up to 5 seconds for resources to become available
2114
+ * before assuming that all the PHP instances are deadlocked.
2115
+ */
2116
+ timeout: (e == null ? void 0 : e.timeout) || 5e3
2117
+ });
2118
+ }
2119
+ /**
2120
+ * Get the primary PHP instance.
2121
+ *
2122
+ * If the primary PHP instance is not set, it will be spawned
2123
+ * using the provided phpFactory.
2124
+ *
2125
+ * @throws {Error} when called twice before the first call is resolved.
2126
+ */
2127
+ async getPrimaryPhp() {
2128
+ if (!this.phpFactory && !this.primaryPhp)
2129
+ throw new Error(
2130
+ "phpFactory or primaryPhp must be set before calling getPrimaryPhp()."
2131
+ );
2132
+ if (!this.primaryPhp) {
2133
+ const e = await this.spawn({ isPrimary: !0 });
2134
+ this.primaryPhp = e.php;
2135
+ }
2136
+ return this.primaryPhp;
2137
+ }
2138
+ /**
2139
+ * Get a PHP instance.
2140
+ *
2141
+ * It could be either the primary PHP instance, an idle disposable PHP instance,
2142
+ * or a newly spawned PHP instance – depending on the resource availability.
2143
+ *
2144
+ * @throws {MaxPhpInstancesError} when the maximum number of PHP instances is reached
2145
+ * and the waiting timeout is exceeded.
2146
+ */
2147
+ async acquirePHPInstance() {
2148
+ if (this.primaryIdle)
2149
+ return this.primaryIdle = !1, {
2150
+ php: await this.getPrimaryPhp(),
2151
+ reap: () => this.primaryIdle = !0
2152
+ };
2153
+ const e = this.nextInstance || this.spawn({ isPrimary: !1 });
2154
+ return this.semaphore.remaining > 0 ? this.nextInstance = this.spawn({ isPrimary: !1 }) : this.nextInstance = null, await e;
2155
+ }
2156
+ /**
2157
+ * Initiated spawning of a new PHP instance.
2158
+ * This function is synchronous on purpose – it needs to synchronously
2159
+ * add the spawn promise to the allInstances array without waiting
2160
+ * for PHP to spawn.
2161
+ */
2162
+ spawn(e) {
2163
+ if (e.isPrimary && this.allInstances.length > 0)
2164
+ throw new Error(
2165
+ "Requested spawning a primary PHP instance when another primary instance already started spawning."
2166
+ );
2167
+ const r = this.doSpawn(e);
2168
+ this.allInstances.push(r);
2169
+ const s = () => {
2170
+ this.allInstances = this.allInstances.filter(
2171
+ (n) => n !== r
1333
2172
  );
1334
- if (t.prependPath) {
1335
- const s = e.replace(/\/$/, "");
1336
- return r.map((n) => `${s}/${n}`);
2173
+ };
2174
+ return r.catch((n) => {
2175
+ throw s(), n;
2176
+ }).then((n) => ({
2177
+ ...n,
2178
+ reap: () => {
2179
+ s(), n.reap();
1337
2180
  }
1338
- return r;
1339
- } catch (r) {
1340
- return logger.error(r, { path: e }), [];
1341
- }
1342
- }
1343
- isDir(e) {
1344
- return this.fileExists(e) ? this[__private__dont__use].FS.isDir(
1345
- this[__private__dont__use].FS.lookupPath(e).node.mode
1346
- ) : !1;
1347
- }
1348
- fileExists(e) {
1349
- try {
1350
- return this[__private__dont__use].FS.lookupPath(e), !0;
1351
- } catch {
1352
- return !1;
1353
- }
2181
+ }));
1354
2182
  }
1355
2183
  /**
1356
- * Hot-swaps the PHP runtime for a new one without
1357
- * interrupting the operations of this PHP instance.
1358
- *
1359
- * @param runtime
1360
- * @param cwd. Internal, the VFS path to recreate in the new runtime.
1361
- * This arg is temporary and will be removed once BasePHP
1362
- * is fully decoupled from the request handler and
1363
- * accepts a constructor-level cwd argument.
2184
+ * Actually acquires the lock and spawns a new PHP instance.
1364
2185
  */
1365
- hotSwapPHPRuntime(e, t) {
1366
- const r = this[__private__dont__use].FS;
2186
+ async doSpawn(e) {
2187
+ let r;
1367
2188
  try {
1368
- this.exit();
1369
- } catch {
2189
+ r = await this.semaphore.acquire();
2190
+ } catch (s) {
2191
+ throw s instanceof AcquireTimeoutError ? new MaxPhpInstancesError(this.maxPhpInstances) : s;
1370
2192
  }
1371
- this.initializeRuntime(e), u(this, v) && this.setPhpIniPath(u(this, v)), u(this, R) && this.setSapiName(u(this, R)), t && copyFS(r, this[__private__dont__use].FS, t);
1372
- }
1373
- exit(e = 0) {
1374
- this.dispatchEvent({
1375
- type: "runtime.beforedestroy"
1376
- });
1377
2193
  try {
1378
- this[__private__dont__use]._exit(e);
1379
- } catch {
2194
+ const s = await this.phpFactory(e);
2195
+ return {
2196
+ php: s,
2197
+ reap() {
2198
+ s.exit(), r();
2199
+ }
2200
+ };
2201
+ } catch (s) {
2202
+ throw r(), s;
1380
2203
  }
1381
- d(this, f, !1), d(this, P, null), delete this[__private__dont__use].onMessage, delete this[__private__dont__use];
1382
- }
1383
- [Symbol.dispose]() {
1384
- u(this, f) && this.exit(0);
1385
- }
1386
- }
1387
- w = new WeakMap(), v = new WeakMap(), R = new WeakMap(), f = new WeakMap(), P = new WeakMap(), _ = new WeakMap(), S = new WeakMap(), C = new WeakSet(), Z = function(e, t, r) {
1388
- const s = {
1389
- ...e || {}
1390
- };
1391
- s.HTTPS = s.HTTPS || r === 443 ? "on" : "off";
1392
- for (const n in t) {
1393
- let i = "HTTP_";
1394
- ["content-type", "content-length"].includes(n.toLowerCase()) && (i = ""), s[`${i}${n.toUpperCase().replace(/-/g, "_")}`] = t[n];
1395
- }
1396
- return s;
1397
- }, I = new WeakSet(), Y = function() {
1398
- if (this.setPhpIniEntry("auto_prepend_file", "/internal/consts.php"), this.fileExists("/internal/consts.php") || this.writeFile(
1399
- "/internal/consts.php",
1400
- `<?php
1401
- if(file_exists('/internal/consts.json')) {
1402
- $consts = json_decode(file_get_contents('/internal/consts.json'), true);
1403
- foreach ($consts as $const => $value) {
1404
- if (!defined($const) && is_scalar($value)) {
1405
- define($const, $value);
1406
- }
1407
- }
1408
- }`
1409
- ), u(this, w).length > 0) {
1410
- const e = u(this, w).map(([t, r]) => `${t}=${r}`).join(`
1411
- `) + `
1412
-
1413
- `;
1414
- this[__private__dont__use].ccall(
1415
- "wasm_set_phpini_entries",
1416
- null,
1417
- [STRING],
1418
- [e]
1419
- );
1420
- }
1421
- this[__private__dont__use].ccall("php_wasm_init", null, [], []);
1422
- }, A = new WeakSet(), K = function() {
1423
- const e = "/internal/headers.json";
1424
- if (!this.fileExists(e))
1425
- throw new Error(
1426
- "SAPI Error: Could not find response headers file."
1427
- );
1428
- const t = JSON.parse(this.readFileAsText(e)), r = {};
1429
- for (const s of t.headers) {
1430
- if (!s.includes(": "))
1431
- continue;
1432
- const n = s.indexOf(": "), i = s.substring(0, n).toLowerCase(), o = s.substring(n + 2);
1433
- i in r || (r[i] = []), r[i].push(o);
1434
2204
  }
1435
- return {
1436
- headers: r,
1437
- httpStatusCode: t.status
1438
- };
1439
- }, k = new WeakSet(), X = function(e) {
1440
- if (this[__private__dont__use].ccall(
1441
- "wasm_set_request_uri",
1442
- null,
1443
- [STRING],
1444
- [e]
1445
- ), e.includes("?")) {
1446
- const t = e.substring(e.indexOf("?") + 1);
1447
- this[__private__dont__use].ccall(
1448
- "wasm_set_query_string",
1449
- null,
1450
- [STRING],
1451
- [t]
2205
+ async [Symbol.asyncDispose]() {
2206
+ this.primaryPhp && this.primaryPhp.exit(), await Promise.all(
2207
+ this.allInstances.map(
2208
+ (e) => e.then(({ reap: r }) => r())
2209
+ )
1452
2210
  );
1453
2211
  }
1454
- }, M = new WeakSet(), ee = function(e) {
1455
- this[__private__dont__use].ccall(
1456
- "wasm_set_request_host",
1457
- null,
1458
- [STRING],
1459
- [e]
1460
- );
1461
- }, B = new WeakSet(), te = function(e) {
1462
- this[__private__dont__use].ccall(
1463
- "wasm_set_request_port",
1464
- null,
1465
- [NUMBER],
1466
- [e]
1467
- );
1468
- }, L = new WeakSet(), re = function(e, t) {
1469
- let r;
1470
- try {
1471
- r = parseInt(new URL(e).port, 10);
1472
- } catch {
1473
- }
1474
- return (!r || isNaN(r) || r === 80) && (r = t === "https" ? 443 : 80), r;
1475
- }, N = new WeakSet(), se = function(e) {
1476
- this[__private__dont__use].ccall(
1477
- "wasm_set_request_method",
1478
- null,
1479
- [STRING],
1480
- [e]
1481
- );
1482
- }, U = new WeakSet(), ne = function(e) {
1483
- e.cookie && this[__private__dont__use].ccall(
1484
- "wasm_set_cookies",
1485
- null,
1486
- [STRING],
1487
- [e.cookie]
1488
- ), e["content-type"] && this[__private__dont__use].ccall(
1489
- "wasm_set_content_type",
1490
- null,
1491
- [STRING],
1492
- [e["content-type"]]
1493
- ), e["content-length"] && this[__private__dont__use].ccall(
1494
- "wasm_set_content_length",
1495
- null,
1496
- [NUMBER],
1497
- [parseInt(e["content-length"], 10)]
1498
- );
1499
- }, O = new WeakSet(), ie = function(e) {
1500
- let t, r;
1501
- typeof e == "string" ? (logger.warn(
1502
- "Passing a string as the request body is deprecated. Please use a Uint8Array instead. See https://github.com/WordPress/wordpress-playground/issues/997 for more details"
1503
- ), r = this[__private__dont__use].lengthBytesUTF8(e), t = r + 1) : (r = e.byteLength, t = e.byteLength);
1504
- const s = this[__private__dont__use].malloc(t);
1505
- if (!s)
1506
- throw new Error("Could not allocate memory for the request body.");
1507
- return typeof e == "string" ? this[__private__dont__use].stringToUTF8(
1508
- e,
1509
- s,
1510
- t + 1
1511
- ) : this[__private__dont__use].HEAPU8.set(e, s), this[__private__dont__use].ccall(
1512
- "wasm_set_request_body",
1513
- null,
1514
- [NUMBER],
1515
- [s]
1516
- ), this[__private__dont__use].ccall(
1517
- "wasm_set_content_length",
1518
- null,
1519
- [NUMBER],
1520
- [r]
1521
- ), s;
1522
- }, D = new WeakSet(), oe = function(e) {
1523
- this[__private__dont__use].ccall(
1524
- "wasm_set_path_translated",
1525
- null,
1526
- [STRING],
1527
- [e]
1528
- );
1529
- }, $ = new WeakSet(), ae = function(e, t) {
1530
- this[__private__dont__use].ccall(
1531
- "wasm_add_SERVER_entry",
1532
- null,
1533
- [STRING, STRING],
1534
- [e, t]
1535
- );
1536
- }, q = new WeakSet(), le = function(e, t) {
1537
- this[__private__dont__use].ccall(
1538
- "wasm_add_ENV_entry",
1539
- null,
1540
- [STRING, STRING],
1541
- [e, t]
1542
- );
1543
- }, j = new WeakSet(), ce = function(e) {
1544
- this[__private__dont__use].ccall(
1545
- "wasm_set_php_code",
1546
- null,
1547
- [STRING],
1548
- [e]
1549
- );
1550
- }, z = new WeakSet(), ue = async function() {
1551
- var n;
1552
- let e, t;
1553
- try {
1554
- e = await new Promise((i, o) => {
1555
- var l;
1556
- t = (c) => {
1557
- logger.error(c), logger.error(c.error);
1558
- const g = new Error("Rethrown");
1559
- g.cause = c.error, g.betterMessage = c.message, o(g);
1560
- }, (l = u(this, P)) == null || l.addEventListener(
1561
- "error",
1562
- t
1563
- );
1564
- const a = this[__private__dont__use].ccall(
1565
- "wasm_sapi_handle_request",
1566
- NUMBER,
1567
- [],
1568
- [],
1569
- { async: !0 }
1570
- );
1571
- return a instanceof Promise ? a.then(i, o) : i(a);
1572
- });
1573
- } catch (i) {
1574
- for (const c in this)
1575
- typeof this[c] == "function" && (this[c] = () => {
1576
- throw new Error(
1577
- "PHP runtime has crashed – see the earlier error for details."
1578
- );
1579
- });
1580
- this.functionsMaybeMissingFromAsyncify = getFunctionsMaybeMissingFromAsyncify();
1581
- const o = i, a = "betterMessage" in o ? o.betterMessage : o.message, l = new Error(a);
1582
- throw l.cause = o, logger.error(l), l;
1583
- } finally {
1584
- (n = u(this, P)) == null || n.removeEventListener("error", t);
1585
- }
1586
- const { headers: r, httpStatusCode: s } = p(this, A, K).call(this);
1587
- return new PHPResponse(
1588
- e === 0 ? s : 500,
1589
- r,
1590
- this.readFileAsBuffer("/internal/stdout"),
1591
- this.readFileAsText("/internal/stderr"),
1592
- e
1593
- );
1594
- };
1595
- __decorateClass([
1596
- rethrowFileSystemError('Could not create directory "{path}"')
1597
- ], BasePHP.prototype, "mkdir", 1);
1598
- __decorateClass([
1599
- rethrowFileSystemError('Could not create directory "{path}"')
1600
- ], BasePHP.prototype, "mkdirTree", 1);
1601
- __decorateClass([
1602
- rethrowFileSystemError('Could not read "{path}"')
1603
- ], BasePHP.prototype, "readFileAsText", 1);
1604
- __decorateClass([
1605
- rethrowFileSystemError('Could not read "{path}"')
1606
- ], BasePHP.prototype, "readFileAsBuffer", 1);
1607
- __decorateClass([
1608
- rethrowFileSystemError('Could not write to "{path}"')
1609
- ], BasePHP.prototype, "writeFile", 1);
1610
- __decorateClass([
1611
- rethrowFileSystemError('Could not unlink "{path}"')
1612
- ], BasePHP.prototype, "unlink", 1);
1613
- __decorateClass([
1614
- rethrowFileSystemError('Could not remove directory "{path}"')
1615
- ], BasePHP.prototype, "rmdir", 1);
1616
- __decorateClass([
1617
- rethrowFileSystemError('Could not list files in "{path}"')
1618
- ], BasePHP.prototype, "listFiles", 1);
1619
- __decorateClass([
1620
- rethrowFileSystemError('Could not stat "{path}"')
1621
- ], BasePHP.prototype, "isDir", 1);
1622
- __decorateClass([
1623
- rethrowFileSystemError('Could not stat "{path}"')
1624
- ], BasePHP.prototype, "fileExists", 1);
1625
- function normalizeHeaders(e) {
1626
- const t = {};
1627
- for (const r in e)
1628
- t[r.toLowerCase()] = e[r];
1629
- return t;
1630
- }
1631
- function copyFS(e, t, r) {
1632
- let s;
1633
- try {
1634
- s = e.lookupPath(r);
1635
- } catch {
1636
- return;
1637
- }
1638
- if (!("contents" in s.node))
1639
- return;
1640
- if (!e.isDir(s.node.mode)) {
1641
- t.writeFile(r, e.readFile(r));
1642
- return;
1643
- }
1644
- t.mkdirTree(r);
1645
- const n = e.readdir(r).filter((i) => i !== "." && i !== "..");
1646
- for (const i of n)
1647
- copyFS(e, t, joinPaths(r, i));
1648
- }
1649
- function isLocalPHP(e) {
1650
- return !(e instanceof BasePHP);
1651
2212
  }
1652
- function isRemotePHP(e) {
1653
- return !isLocalPHP(e);
1654
- }
1655
- const DEFAULT_BASE_URL = "http://example.com";
1656
- function toRelativeUrl(e) {
1657
- return e.toString().substring(e.origin.length);
2213
+ const SupportedPHPVersions = [
2214
+ "8.3",
2215
+ "8.2",
2216
+ "8.1",
2217
+ "8.0",
2218
+ "7.4",
2219
+ "7.3",
2220
+ "7.2",
2221
+ "7.1",
2222
+ "7.0"
2223
+ ], LatestSupportedPHPVersion = SupportedPHPVersions[0], SupportedPHPVersionsList = SupportedPHPVersions, SupportedPHPExtensionsList = [
2224
+ "iconv",
2225
+ "mbstring",
2226
+ "xml-bundle",
2227
+ "gd"
2228
+ ], SupportedPHPExtensionBundles = {
2229
+ "kitchen-sink": SupportedPHPExtensionsList,
2230
+ light: []
2231
+ }, DEFAULT_BASE_URL = "http://example.com";
2232
+ function toRelativeUrl(t) {
2233
+ return t.toString().substring(t.origin.length);
1658
2234
  }
1659
- function removePathPrefix(e, t) {
1660
- return !t || !e.startsWith(t) ? e : e.substring(t.length);
2235
+ function removePathPrefix(t, e) {
2236
+ return !e || !t.startsWith(e) ? t : t.substring(e.length);
1661
2237
  }
1662
- function ensurePathPrefix(e, t) {
1663
- return !t || e.startsWith(t) ? e : t + e;
2238
+ function ensurePathPrefix(t, e) {
2239
+ return !e || t.startsWith(e) ? t : e + t;
1664
2240
  }
1665
- async function encodeAsMultipart(e) {
1666
- const t = `----${Math.random().toString(36).slice(2)}`, r = `multipart/form-data; boundary=${t}`, s = new TextEncoder(), n = [];
1667
- for (const [l, c] of Object.entries(e))
1668
- n.push(`--${t}\r
1669
- `), n.push(`Content-Disposition: form-data; name="${l}"`), c instanceof File && n.push(`; filename="${c.name}"`), n.push(`\r
1670
- `), c instanceof File && (n.push("Content-Type: application/octet-stream"), n.push(`\r
2241
+ async function encodeAsMultipart(t) {
2242
+ const e = `----${Math.random().toString(36).slice(2)}`, r = `multipart/form-data; boundary=${e}`, s = new TextEncoder(), n = [];
2243
+ for (const [c, a] of Object.entries(t))
2244
+ n.push(`--${e}\r
2245
+ `), n.push(`Content-Disposition: form-data; name="${c}"`), a instanceof File && n.push(`; filename="${a.name}"`), n.push(`\r
2246
+ `), a instanceof File && (n.push("Content-Type: application/octet-stream"), n.push(`\r
1671
2247
  `)), n.push(`\r
1672
- `), c instanceof File ? n.push(await fileToUint8Array(c)) : n.push(c), n.push(`\r
2248
+ `), a instanceof File ? n.push(await fileToUint8Array(a)) : n.push(a), n.push(`\r
1673
2249
  `);
1674
- n.push(`--${t}--\r
2250
+ n.push(`--${e}--\r
1675
2251
  `);
1676
- const i = n.reduce((l, c) => l + c.length, 0), o = new Uint8Array(i);
1677
- let a = 0;
1678
- for (const l of n)
2252
+ const i = n.reduce((c, a) => c + a.length, 0), o = new Uint8Array(i);
2253
+ let l = 0;
2254
+ for (const c of n)
1679
2255
  o.set(
1680
- typeof l == "string" ? s.encode(l) : l,
1681
- a
1682
- ), a += l.length;
2256
+ typeof c == "string" ? s.encode(c) : c,
2257
+ l
2258
+ ), l += c.length;
1683
2259
  return { bytes: o, contentType: r };
1684
2260
  }
1685
- function fileToUint8Array(e) {
1686
- return new Promise((t) => {
2261
+ function fileToUint8Array(t) {
2262
+ return new Promise((e) => {
1687
2263
  const r = new FileReader();
1688
2264
  r.onload = () => {
1689
- t(new Uint8Array(r.result));
1690
- }, r.readAsArrayBuffer(e);
2265
+ e(new Uint8Array(r.result));
2266
+ }, r.readAsArrayBuffer(t);
1691
2267
  });
1692
2268
  }
1693
- var y, b, T, E, x, m, F, H, W, he, G, de, J, pe, V, fe;
2269
+ const _default = "application/octet-stream", asx = "video/x-ms-asf", atom = "application/atom+xml", avi = "video/x-msvideo", avif = "image/avif", bin = "application/octet-stream", bmp = "image/x-ms-bmp", cco = "application/x-cocoa", css = "text/css", data = "application/octet-stream", deb = "application/octet-stream", der = "application/x-x509-ca-cert", dmg = "application/octet-stream", doc = "application/msword", docx = "application/vnd.openxmlformats-officedocument.wordprocessingml.document", eot = "application/vnd.ms-fontobject", flv = "video/x-flv", gif = "image/gif", gz = "application/gzip", hqx = "application/mac-binhex40", htc = "text/x-component", html = "text/html", ico = "image/x-icon", iso = "application/octet-stream", jad = "text/vnd.sun.j2me.app-descriptor", jar = "application/java-archive", jardiff = "application/x-java-archive-diff", jng = "image/x-jng", jnlp = "application/x-java-jnlp-file", jpg = "image/jpeg", jpeg = "image/jpeg", js = "application/javascript", json = "application/json", kml = "application/vnd.google-earth.kml+xml", kmz = "application/vnd.google-earth.kmz", m3u8 = "application/vnd.apple.mpegurl", m4a = "audio/x-m4a", m4v = "video/x-m4v", md = "text/plain", mid = "audio/midi", mml = "text/mathml", mng = "video/x-mng", mov = "video/quicktime", mp3 = "audio/mpeg", mp4 = "video/mp4", mpeg = "video/mpeg", msi = "application/octet-stream", odg = "application/vnd.oasis.opendocument.graphics", odp = "application/vnd.oasis.opendocument.presentation", ods = "application/vnd.oasis.opendocument.spreadsheet", odt = "application/vnd.oasis.opendocument.text", ogg = "audio/ogg", otf = "font/otf", pdf = "application/pdf", pl = "application/x-perl", png = "image/png", ppt = "application/vnd.ms-powerpoint", pptx = "application/vnd.openxmlformats-officedocument.presentationml.presentation", prc = "application/x-pilot", ps = "application/postscript", ra = "audio/x-realaudio", rar = "application/x-rar-compressed", rpm = "application/x-redhat-package-manager", rss = "application/rss+xml", rtf = "application/rtf", run = "application/x-makeself", sea = "application/x-sea", sit = "application/x-stuffit", svg = "image/svg+xml", swf = "application/x-shockwave-flash", tcl = "application/x-tcl", tar = "application/x-tar", tif = "image/tiff", ts = "video/mp2t", ttf = "font/ttf", txt = "text/plain", wasm = "application/wasm", wbmp = "image/vnd.wap.wbmp", webm = "video/webm", webp = "image/webp", wml = "text/vnd.wap.wml", wmlc = "application/vnd.wap.wmlc", wmv = "video/x-ms-wmv", woff = "font/woff", woff2 = "font/woff2", xhtml = "application/xhtml+xml", xls = "application/vnd.ms-excel", xlsx = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", xml = "text/xml", xpi = "application/x-xpinstall", xspf = "application/xspf+xml", zip = "application/zip", mimeTypes = {
2270
+ _default,
2271
+ "3gpp": "video/3gpp",
2272
+ "7z": "application/x-7z-compressed",
2273
+ asx,
2274
+ atom,
2275
+ avi,
2276
+ avif,
2277
+ bin,
2278
+ bmp,
2279
+ cco,
2280
+ css,
2281
+ data,
2282
+ deb,
2283
+ der,
2284
+ dmg,
2285
+ doc,
2286
+ docx,
2287
+ eot,
2288
+ flv,
2289
+ gif,
2290
+ gz,
2291
+ hqx,
2292
+ htc,
2293
+ html,
2294
+ ico,
2295
+ iso,
2296
+ jad,
2297
+ jar,
2298
+ jardiff,
2299
+ jng,
2300
+ jnlp,
2301
+ jpg,
2302
+ jpeg,
2303
+ js,
2304
+ json,
2305
+ kml,
2306
+ kmz,
2307
+ m3u8,
2308
+ m4a,
2309
+ m4v,
2310
+ md,
2311
+ mid,
2312
+ mml,
2313
+ mng,
2314
+ mov,
2315
+ mp3,
2316
+ mp4,
2317
+ mpeg,
2318
+ msi,
2319
+ odg,
2320
+ odp,
2321
+ ods,
2322
+ odt,
2323
+ ogg,
2324
+ otf,
2325
+ pdf,
2326
+ pl,
2327
+ png,
2328
+ ppt,
2329
+ pptx,
2330
+ prc,
2331
+ ps,
2332
+ ra,
2333
+ rar,
2334
+ rpm,
2335
+ rss,
2336
+ rtf,
2337
+ run,
2338
+ sea,
2339
+ sit,
2340
+ svg,
2341
+ swf,
2342
+ tcl,
2343
+ tar,
2344
+ tif,
2345
+ ts,
2346
+ ttf,
2347
+ txt,
2348
+ wasm,
2349
+ wbmp,
2350
+ webm,
2351
+ webp,
2352
+ wml,
2353
+ wmlc,
2354
+ wmv,
2355
+ woff,
2356
+ woff2,
2357
+ xhtml,
2358
+ xls,
2359
+ xlsx,
2360
+ xml,
2361
+ xpi,
2362
+ xspf,
2363
+ zip
2364
+ };
2365
+ var w, F, C, b, H, P, T, k, V, he, J, fe, Q, me, Z, _e;
1694
2366
  class PHPRequestHandler {
1695
2367
  /**
1696
2368
  * The request handler needs to decide whether to serve a static asset or
@@ -1703,18 +2375,18 @@ class PHPRequestHandler {
1703
2375
  * @param php - The PHP instance.
1704
2376
  * @param config - Request Handler configuration.
1705
2377
  */
1706
- constructor(t) {
2378
+ constructor(e) {
1707
2379
  /**
1708
2380
  * Serves a static file from the PHP filesystem.
1709
2381
  *
1710
2382
  * @param fsPath - Absolute path of the static file to serve.
1711
2383
  * @returns The response.
1712
2384
  */
1713
- h(this, W);
2385
+ p(this, V);
1714
2386
  /**
1715
2387
  * Spawns a new PHP instance and dispatches a request to it.
1716
2388
  */
1717
- h(this, G);
2389
+ p(this, J);
1718
2390
  /**
1719
2391
  * Runs the requested PHP file with all the request and $_SERVER
1720
2392
  * superglobals populated.
@@ -1722,7 +2394,7 @@ class PHPRequestHandler {
1722
2394
  * @param request - The request.
1723
2395
  * @returns The response.
1724
2396
  */
1725
- h(this, J);
2397
+ p(this, Q);
1726
2398
  /**
1727
2399
  * Resolve the requested path to the filesystem path of the requested PHP file.
1728
2400
  *
@@ -1732,40 +2404,40 @@ class PHPRequestHandler {
1732
2404
  * @throws {Error} If the requested path doesn't exist.
1733
2405
  * @returns The resolved filesystem path.
1734
2406
  */
1735
- h(this, V);
1736
- h(this, y, void 0);
1737
- h(this, b, void 0);
1738
- h(this, T, void 0);
1739
- h(this, E, void 0);
1740
- h(this, x, void 0);
1741
- h(this, m, void 0);
1742
- h(this, F, void 0);
1743
- h(this, H, void 0);
2407
+ p(this, Z);
2408
+ p(this, w, void 0);
2409
+ p(this, F, void 0);
2410
+ p(this, C, void 0);
2411
+ p(this, b, void 0);
2412
+ p(this, H, void 0);
2413
+ p(this, P, void 0);
2414
+ p(this, T, void 0);
2415
+ p(this, k, void 0);
1744
2416
  const {
1745
2417
  documentRoot: r = "/www/",
1746
2418
  absoluteUrl: s = typeof location == "object" ? location == null ? void 0 : location.href : "",
1747
2419
  rewriteRules: n = []
1748
- } = t;
1749
- "processManager" in t ? this.processManager = t.processManager : this.processManager = new PHPProcessManager({
1750
- phpFactory: async (a) => {
1751
- const l = await t.phpFactory({
1752
- ...a,
2420
+ } = e;
2421
+ "processManager" in e ? this.processManager = e.processManager : this.processManager = new PHPProcessManager({
2422
+ phpFactory: async (l) => {
2423
+ const c = await e.phpFactory({
2424
+ ...l,
1753
2425
  requestHandler: this
1754
2426
  });
1755
- return l.requestHandler = this, l;
2427
+ return c.requestHandler = this, c;
1756
2428
  },
1757
- maxPhpInstances: t.maxPhpInstances
1758
- }), d(this, H, new HttpCookieStore()), d(this, y, r);
2429
+ maxPhpInstances: e.maxPhpInstances
2430
+ }), f(this, k, new HttpCookieStore()), f(this, w, r);
1759
2431
  const i = new URL(s);
1760
- d(this, T, i.hostname), d(this, E, i.port ? Number(i.port) : i.protocol === "https:" ? 443 : 80), d(this, b, (i.protocol || "").replace(":", ""));
1761
- const o = u(this, E) !== 443 && u(this, E) !== 80;
1762
- d(this, x, [
1763
- u(this, T),
1764
- o ? `:${u(this, E)}` : ""
1765
- ].join("")), d(this, m, i.pathname.replace(/\/+$/, "")), d(this, F, [
1766
- `${u(this, b)}://`,
1767
- u(this, x),
1768
- u(this, m)
2432
+ f(this, C, i.hostname), f(this, b, i.port ? Number(i.port) : i.protocol === "https:" ? 443 : 80), f(this, F, (i.protocol || "").replace(":", ""));
2433
+ const o = u(this, b) !== 443 && u(this, b) !== 80;
2434
+ f(this, H, [
2435
+ u(this, C),
2436
+ o ? `:${u(this, b)}` : ""
2437
+ ].join("")), f(this, P, i.pathname.replace(/\/+$/, "")), f(this, T, [
2438
+ `${u(this, F)}://`,
2439
+ u(this, H),
2440
+ u(this, P)
1769
2441
  ].join("")), this.rewriteRules = n;
1770
2442
  }
1771
2443
  async getPrimaryPhp() {
@@ -1778,8 +2450,8 @@ class PHPRequestHandler {
1778
2450
  * @param path The server path to convert to an absolute URL.
1779
2451
  * @returns The absolute URL.
1780
2452
  */
1781
- pathToInternalUrl(t) {
1782
- return `${this.absoluteUrl}${t}`;
2453
+ pathToInternalUrl(e) {
2454
+ return `${this.absoluteUrl}${e}`;
1783
2455
  }
1784
2456
  /**
1785
2457
  * Converts an absolute URL based at the PHPRequestHandler to a relative path
@@ -1788,22 +2460,22 @@ class PHPRequestHandler {
1788
2460
  * @param internalUrl An absolute URL based at the PHPRequestHandler root.
1789
2461
  * @returns The relative path.
1790
2462
  */
1791
- internalUrlToPath(t) {
1792
- const r = new URL(t);
1793
- return r.pathname.startsWith(u(this, m)) && (r.pathname = r.pathname.slice(u(this, m).length)), toRelativeUrl(r);
2463
+ internalUrlToPath(e) {
2464
+ const r = new URL(e);
2465
+ return r.pathname.startsWith(u(this, P)) && (r.pathname = r.pathname.slice(u(this, P).length)), toRelativeUrl(r);
1794
2466
  }
1795
2467
  /**
1796
2468
  * The absolute URL of this PHPRequestHandler instance.
1797
2469
  */
1798
2470
  get absoluteUrl() {
1799
- return u(this, F);
2471
+ return u(this, T);
1800
2472
  }
1801
2473
  /**
1802
2474
  * The directory in the PHP filesystem where the server will look
1803
2475
  * for the files to serve. Default: `/var/www`.
1804
2476
  */
1805
2477
  get documentRoot() {
1806
- return u(this, y);
2478
+ return u(this, w);
1807
2479
  }
1808
2480
  /**
1809
2481
  * Serves the request – either by serving a static file, or by
@@ -1853,23 +2525,23 @@ class PHPRequestHandler {
1853
2525
  *
1854
2526
  * @param request - PHP Request data.
1855
2527
  */
1856
- async request(t) {
1857
- const r = t.url.startsWith("http://") || t.url.startsWith("https://"), s = new URL(
2528
+ async request(e) {
2529
+ const r = e.url.startsWith("http://") || e.url.startsWith("https://"), s = new URL(
1858
2530
  // Remove the hash part of the URL as it's not meant for the server.
1859
- t.url.split("#")[0],
2531
+ e.url.split("#")[0],
1860
2532
  r ? void 0 : DEFAULT_BASE_URL
1861
2533
  ), n = applyRewriteRules(
1862
2534
  removePathPrefix(
1863
2535
  decodeURIComponent(s.pathname),
1864
- u(this, m)
2536
+ u(this, P)
1865
2537
  ),
1866
2538
  this.rewriteRules
1867
- ), i = joinPaths(u(this, y), n);
1868
- return seemsLikeAPHPRequestHandlerPath(i) ? p(this, G, de).call(this, t, s) : p(this, W, he).call(this, await this.processManager.getPrimaryPhp(), i);
2539
+ ), i = joinPaths(u(this, w), n);
2540
+ return seemsLikeAPHPRequestHandlerPath(i) ? h(this, J, fe).call(this, e, s) : h(this, V, he).call(this, await this.processManager.getPrimaryPhp(), i);
1869
2541
  }
1870
2542
  }
1871
- y = new WeakMap(), b = new WeakMap(), T = new WeakMap(), E = new WeakMap(), x = new WeakMap(), m = new WeakMap(), F = new WeakMap(), H = new WeakMap(), W = new WeakSet(), he = function(t, r) {
1872
- if (!t.fileExists(r))
2543
+ w = new WeakMap(), F = new WeakMap(), C = new WeakMap(), b = new WeakMap(), H = new WeakMap(), P = new WeakMap(), T = new WeakMap(), k = new WeakMap(), V = new WeakSet(), he = function(e, r) {
2544
+ if (!e.fileExists(r))
1873
2545
  return new PHPResponse(
1874
2546
  404,
1875
2547
  // Let the service worker know that no static file was found
@@ -1879,7 +2551,7 @@ y = new WeakMap(), b = new WeakMap(), T = new WeakMap(), E = new WeakMap(), x =
1879
2551
  },
1880
2552
  new TextEncoder().encode("404 File not found")
1881
2553
  );
1882
- const s = t.readFileAsBuffer(r);
2554
+ const s = e.readFileAsBuffer(r);
1883
2555
  return new PHPResponse(
1884
2556
  200,
1885
2557
  {
@@ -1893,7 +2565,7 @@ y = new WeakMap(), b = new WeakMap(), T = new WeakMap(), E = new WeakMap(), x =
1893
2565
  },
1894
2566
  s
1895
2567
  );
1896
- }, G = new WeakSet(), de = async function(t, r) {
2568
+ }, J = new WeakSet(), fe = async function(e, r) {
1897
2569
  let s;
1898
2570
  try {
1899
2571
  s = await this.processManager.acquirePHPInstance();
@@ -1901,153 +2573,85 @@ y = new WeakMap(), b = new WeakMap(), T = new WeakMap(), E = new WeakMap(), x =
1901
2573
  return n instanceof MaxPhpInstancesError ? PHPResponse.forHttpCode(502) : PHPResponse.forHttpCode(500);
1902
2574
  }
1903
2575
  try {
1904
- return await p(this, J, pe).call(this, s.php, t, r);
2576
+ return await h(this, Q, me).call(this, s.php, e, r);
1905
2577
  } finally {
1906
2578
  s.reap();
1907
2579
  }
1908
- }, J = new WeakSet(), pe = async function(t, r, s) {
2580
+ }, Q = new WeakSet(), me = async function(e, r, s) {
1909
2581
  let n = "GET";
1910
2582
  const i = {
1911
- host: u(this, x),
2583
+ host: u(this, H),
1912
2584
  ...normalizeHeaders(r.headers || {}),
1913
- cookie: u(this, H).getCookieRequestHeader()
2585
+ cookie: u(this, k).getCookieRequestHeader()
1914
2586
  };
1915
2587
  let o = r.body;
1916
2588
  if (typeof o == "object" && !(o instanceof Uint8Array)) {
1917
2589
  n = "POST";
1918
- const { bytes: l, contentType: c } = await encodeAsMultipart(o);
1919
- o = l, i["content-type"] = c;
2590
+ const { bytes: c, contentType: a } = await encodeAsMultipart(o);
2591
+ o = c, i["content-type"] = a;
1920
2592
  }
1921
- let a;
2593
+ let l;
1922
2594
  try {
1923
- a = p(this, V, fe).call(this, t, decodeURIComponent(s.pathname));
2595
+ l = h(this, Z, _e).call(this, e, decodeURIComponent(s.pathname));
1924
2596
  } catch {
1925
2597
  return PHPResponse.forHttpCode(404);
1926
2598
  }
1927
2599
  try {
1928
- const l = await t.run({
2600
+ const c = await e.run({
1929
2601
  relativeUri: ensurePathPrefix(
1930
2602
  toRelativeUrl(s),
1931
- u(this, m)
2603
+ u(this, P)
1932
2604
  ),
1933
- protocol: u(this, b),
2605
+ protocol: u(this, F),
1934
2606
  method: r.method || n,
1935
2607
  $_SERVER: {
1936
2608
  REMOTE_ADDR: "127.0.0.1",
1937
- DOCUMENT_ROOT: u(this, y),
1938
- HTTPS: u(this, F).startsWith("https://") ? "on" : ""
2609
+ DOCUMENT_ROOT: u(this, w),
2610
+ HTTPS: u(this, T).startsWith("https://") ? "on" : ""
1939
2611
  },
1940
2612
  body: o,
1941
- scriptPath: a,
2613
+ scriptPath: l,
1942
2614
  headers: i
1943
2615
  });
1944
- return u(this, H).rememberCookiesFromResponseHeaders(
1945
- l.headers
1946
- ), l;
1947
- } catch (l) {
1948
- const c = l;
1949
- if (c != null && c.response)
1950
- return c.response;
1951
- throw l;
1952
- }
1953
- }, V = new WeakSet(), fe = function(t, r) {
1954
- let s = removePathPrefix(r, u(this, m));
1955
- s = applyRewriteRules(s, this.rewriteRules), s.includes(".php") ? s = s.split(".php")[0] + ".php" : t.isDir(`${u(this, y)}${s}`) ? (s.endsWith("/") || (s = `${s}/`), s = `${s}index.php`) : s = "/index.php";
1956
- const n = `${u(this, y)}${s}`;
1957
- if (t.fileExists(n))
2616
+ return u(this, k).rememberCookiesFromResponseHeaders(
2617
+ c.headers
2618
+ ), c;
2619
+ } catch (c) {
2620
+ const a = c;
2621
+ if (a != null && a.response)
2622
+ return a.response;
2623
+ throw c;
2624
+ }
2625
+ }, Z = new WeakSet(), _e = function(e, r) {
2626
+ let s = removePathPrefix(r, u(this, P));
2627
+ s = applyRewriteRules(s, this.rewriteRules), s.includes(".php") ? s = s.split(".php")[0] + ".php" : e.isDir(`${u(this, w)}${s}`) ? (s.endsWith("/") || (s = `${s}/`), s = `${s}index.php`) : s = "/index.php";
2628
+ let n = `${u(this, w)}${s}`;
2629
+ if (e.fileExists(n) || (n = `${u(this, w)}/index.php`), e.fileExists(n))
1958
2630
  return n;
1959
2631
  throw new Error(`File not found: ${n}`);
1960
2632
  };
1961
- function inferMimeType(e) {
1962
- switch (e.split(".").pop()) {
1963
- case "css":
1964
- return "text/css";
1965
- case "js":
1966
- return "application/javascript";
1967
- case "png":
1968
- return "image/png";
1969
- case "jpg":
1970
- case "jpeg":
1971
- return "image/jpeg";
1972
- case "gif":
1973
- return "image/gif";
1974
- case "svg":
1975
- return "image/svg+xml";
1976
- case "woff":
1977
- return "font/woff";
1978
- case "woff2":
1979
- return "font/woff2";
1980
- case "ttf":
1981
- return "font/ttf";
1982
- case "otf":
1983
- return "font/otf";
1984
- case "eot":
1985
- return "font/eot";
1986
- case "ico":
1987
- return "image/x-icon";
1988
- case "html":
1989
- return "text/html";
1990
- case "json":
1991
- return "application/json";
1992
- case "xml":
1993
- return "application/xml";
1994
- case "txt":
1995
- case "md":
1996
- return "text/plain";
1997
- case "pdf":
1998
- return "application/pdf";
1999
- case "webp":
2000
- return "image/webp";
2001
- case "mp3":
2002
- return "audio/mpeg";
2003
- case "mp4":
2004
- return "video/mp4";
2005
- case "csv":
2006
- return "text/csv";
2007
- case "xls":
2008
- return "application/vnd.ms-excel";
2009
- case "xlsx":
2010
- return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
2011
- case "doc":
2012
- return "application/msword";
2013
- case "docx":
2014
- return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
2015
- case "ppt":
2016
- return "application/vnd.ms-powerpoint";
2017
- case "pptx":
2018
- return "application/vnd.openxmlformats-officedocument.presentationml.presentation";
2019
- case "zip":
2020
- return "application/zip";
2021
- case "rar":
2022
- return "application/x-rar-compressed";
2023
- case "tar":
2024
- return "application/x-tar";
2025
- case "gz":
2026
- return "application/gzip";
2027
- case "7z":
2028
- return "application/x-7z-compressed";
2029
- default:
2030
- return "application-octet-stream";
2031
- }
2633
+ function inferMimeType(t) {
2634
+ const e = t.split(".").pop();
2635
+ return mimeTypes[e] || mimeTypes._default;
2032
2636
  }
2033
- function seemsLikeAPHPRequestHandlerPath(e) {
2034
- return seemsLikeAPHPFile(e) || seemsLikeADirectoryRoot(e);
2637
+ function seemsLikeAPHPRequestHandlerPath(t) {
2638
+ return seemsLikeAPHPFile(t) || seemsLikeADirectoryRoot(t);
2035
2639
  }
2036
- function seemsLikeAPHPFile(e) {
2037
- return e.endsWith(".php") || e.includes(".php/");
2640
+ function seemsLikeAPHPFile(t) {
2641
+ return t.endsWith(".php") || t.includes(".php/");
2038
2642
  }
2039
- function seemsLikeADirectoryRoot(e) {
2040
- return !e.split("/").pop().includes(".");
2643
+ function seemsLikeADirectoryRoot(t) {
2644
+ return !t.split("/").pop().includes(".");
2041
2645
  }
2042
- function applyRewriteRules(e, t) {
2043
- for (const r of t)
2044
- if (new RegExp(r.match).test(e))
2045
- return e.replace(r.match, r.replacement);
2046
- return e;
2646
+ function applyRewriteRules(t, e) {
2647
+ for (const r of e)
2648
+ if (new RegExp(r.match).test(t))
2649
+ return t.replace(r.match, r.replacement);
2650
+ return t;
2047
2651
  }
2048
2652
  function rotatePHPRuntime({
2049
- php: e,
2050
- cwd: t,
2653
+ php: t,
2654
+ cwd: e,
2051
2655
  recreateRuntime: r,
2052
2656
  /*
2053
2657
  * 400 is an arbitrary number that should trigger a rotation
@@ -2064,32 +2668,48 @@ function rotatePHPRuntime({
2064
2668
  if (++n < s)
2065
2669
  return;
2066
2670
  n = 0;
2067
- const o = await e.semaphore.acquire();
2671
+ const o = await t.semaphore.acquire();
2068
2672
  try {
2069
- e.hotSwapPHPRuntime(await r(), t);
2673
+ t.hotSwapPHPRuntime(await r(), e);
2070
2674
  } finally {
2071
2675
  o();
2072
2676
  }
2073
2677
  }
2074
- return e.addEventListener("request.end", i), function() {
2075
- e.removeEventListener("request.end", i);
2678
+ return t.addEventListener("request.end", i), function() {
2679
+ t.removeEventListener("request.end", i);
2076
2680
  };
2077
2681
  }
2078
- async function writeFiles(e, t, r, { rmRoot: s = !1 } = {}) {
2079
- s && await e.isDir(t) && await e.rmdir(t, { recursive: !0 });
2682
+ async function writeFiles(t, e, r, { rmRoot: s = !1 } = {}) {
2683
+ s && await t.isDir(e) && await t.rmdir(e, { recursive: !0 });
2080
2684
  for (const [n, i] of Object.entries(r)) {
2081
- const o = joinPaths(t, n);
2082
- await e.fileExists(dirname(o)) || await e.mkdir(dirname(o)), await e.writeFile(o, i);
2685
+ const o = joinPaths(e, n);
2686
+ await t.fileExists(dirname(o)) || await t.mkdir(dirname(o)), i instanceof Uint8Array || typeof i == "string" ? await t.writeFile(o, i) : await writeFiles(t, o, i);
2083
2687
  }
2084
2688
  }
2689
+ function proxyFileSystem(t, e, r) {
2690
+ const s = Object.getOwnPropertySymbols(t)[0];
2691
+ for (const n of r)
2692
+ e.fileExists(n) || e.mkdir(n), t.fileExists(n) || t.mkdir(n), e[s].FS.mount(
2693
+ // @ts-ignore
2694
+ e[s].PROXYFS,
2695
+ {
2696
+ root: n,
2697
+ // @ts-ignore
2698
+ fs: t[s].FS
2699
+ },
2700
+ n
2701
+ );
2702
+ }
2085
2703
  export {
2086
- BasePHP,
2087
2704
  DEFAULT_BASE_URL,
2705
+ FSHelpers,
2088
2706
  HttpCookieStore,
2089
2707
  LatestSupportedPHPVersion,
2708
+ PHP,
2090
2709
  PHPProcessManager,
2091
2710
  PHPRequestHandler,
2092
2711
  PHPResponse,
2712
+ PHPWorker,
2093
2713
  SupportedPHPExtensionBundles,
2094
2714
  SupportedPHPExtensionsList,
2095
2715
  SupportedPHPVersions,
@@ -2098,15 +2718,16 @@ export {
2098
2718
  __private__dont__use,
2099
2719
  applyRewriteRules,
2100
2720
  ensurePathPrefix,
2721
+ getPhpIniEntries,
2101
2722
  isExitCodeZero,
2102
- isLocalPHP,
2103
- isRemotePHP,
2104
2723
  iteratePhpFiles as iterateFiles,
2105
2724
  loadPHPRuntime,
2725
+ proxyFileSystem,
2106
2726
  removePathPrefix,
2107
- rethrowFileSystemError,
2108
2727
  rotatePHPRuntime,
2728
+ setPhpIniEntries,
2109
2729
  toRelativeUrl,
2730
+ withPHPIniValues,
2110
2731
  writeFiles,
2111
2732
  writeFilesStreamToPhp
2112
2733
  };