@php-wasm/universal 1.1.2 → 1.1.4

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,13 +1,14 @@
1
- var C = (t) => {
2
- throw TypeError(t);
1
+ var O = (r) => {
2
+ throw TypeError(r);
3
3
  };
4
- var I = (t, e, r) => e.has(t) || C("Cannot " + r);
5
- var c = (t, e, r) => (I(t, e, "read from private field"), r ? r.call(t) : e.get(t)), h = (t, e, r) => e.has(t) ? C("Cannot add the same private member more than once") : e instanceof WeakSet ? e.add(t) : e.set(t, r), m = (t, e, r, s) => (I(t, e, "write to private field"), s ? s.call(t, r) : e.set(t, r), r), d = (t, e, r) => (I(t, e, "access private method"), r);
4
+ var q = (r, e, t) => e.has(r) || O("Cannot " + t);
5
+ var c = (r, e, t) => (q(r, e, "read from private field"), t ? t.call(r) : e.get(r)), h = (r, e, t) => e.has(r) ? O("Cannot add the same private member more than once") : e instanceof WeakSet ? e.add(r) : e.set(r, t), f = (r, e, t, s) => (q(r, e, "write to private field"), s ? s.call(r, t) : e.set(r, t), t), d = (r, e, t) => (q(r, e, "access private method"), t);
6
6
  import "@php-wasm/node-polyfills";
7
7
  import { logger } from "@php-wasm/logger";
8
8
  import { dirname, joinPaths, Semaphore, createSpawnHandler, normalizePath, AcquireTimeoutError } from "@php-wasm/util";
9
9
  import { parse, stringify } from "ini";
10
10
  import { StreamedFile } from "@php-wasm/stream-compression";
11
+ import * as Comlink from "comlink";
11
12
  const FileErrorCodes = {
12
13
  0: "No error occurred. System call completed successfully.",
13
14
  1: "Argument list too long.",
@@ -87,21 +88,21 @@ const FileErrorCodes = {
87
88
  75: "Cross-device link.",
88
89
  76: "Extension: Capabilities insufficient."
89
90
  };
90
- function getEmscriptenFsError(t) {
91
- const e = typeof t == "object" ? t == null ? void 0 : t.errno : null;
91
+ function getEmscriptenFsError(r) {
92
+ const e = typeof r == "object" ? r == null ? void 0 : r.errno : null;
92
93
  if (e in FileErrorCodes)
93
94
  return FileErrorCodes[e];
94
95
  }
95
- function rethrowFileSystemError(t = "") {
96
- return function(r) {
96
+ function rethrowFileSystemError(r = "") {
97
+ return function(t) {
97
98
  return function(...s) {
98
99
  try {
99
- return r.apply(this, s);
100
+ return t.apply(this, s);
100
101
  } catch (i) {
101
- const o = typeof i == "object" ? i == null ? void 0 : i.errno : null;
102
- if (o in FileErrorCodes) {
103
- const n = FileErrorCodes[o], l = typeof s[1] == "string" ? s[1] : null, a = l !== null ? t.replaceAll("{path}", l) : t;
104
- throw new Error(`${a}: ${n}`, {
102
+ const n = typeof i == "object" ? i == null ? void 0 : i.errno : null;
103
+ if (n in FileErrorCodes) {
104
+ const o = FileErrorCodes[n], a = typeof s[1] == "string" ? s[1] : null, l = a !== null ? r.replaceAll("{path}", a) : r;
105
+ throw new Error(`${l}: ${o}`, {
105
106
  cause: i
106
107
  });
107
108
  }
@@ -119,8 +120,8 @@ class FSHelpers {
119
120
  * @param path - The file path to read.
120
121
  * @returns The file contents.
121
122
  */
122
- static readFileAsText(e, r) {
123
- return new TextDecoder().decode(FSHelpers.readFileAsBuffer(e, r));
123
+ static readFileAsText(e, t) {
124
+ return new TextDecoder().decode(FSHelpers.readFileAsBuffer(e, t));
124
125
  }
125
126
  /**
126
127
  * Reads a file from the PHP filesystem and returns it as an array buffer.
@@ -130,8 +131,8 @@ class FSHelpers {
130
131
  * @param path - The file path to read.
131
132
  * @returns The file contents.
132
133
  */
133
- static readFileAsBuffer(e, r) {
134
- return e.readFile(r);
134
+ static readFileAsBuffer(e, t) {
135
+ return e.readFile(t);
135
136
  }
136
137
  /**
137
138
  * Overwrites data in a file in the PHP filesystem.
@@ -141,8 +142,8 @@ class FSHelpers {
141
142
  * @param path - The file path to write to.
142
143
  * @param data - The data to write to the file.
143
144
  */
144
- static writeFile(e, r, s) {
145
- e.writeFile(r, s);
145
+ static writeFile(e, t, s) {
146
+ e.writeFile(t, s);
146
147
  }
147
148
  /**
148
149
  * Removes a file from the PHP filesystem.
@@ -151,8 +152,8 @@ class FSHelpers {
151
152
  * @param FS
152
153
  * @param path - The file path to remove.
153
154
  */
154
- static unlink(e, r) {
155
- e.unlink(r);
155
+ static unlink(e, t) {
156
+ e.unlink(t);
156
157
  }
157
158
  /**
158
159
  * Moves a file or directory in the PHP filesystem to a
@@ -162,14 +163,14 @@ class FSHelpers {
162
163
  * @param fromPath The path to rename.
163
164
  * @param toPath The new path.
164
165
  */
165
- static mv(e, r, s) {
166
+ static mv(e, t, s) {
166
167
  try {
167
- const i = e.lookupPath(r).node.mount, o = FSHelpers.fileExists(e, s) ? e.lookupPath(s).node.mount : e.lookupPath(dirname(s)).node.mount;
168
- i.mountpoint !== o.mountpoint ? (FSHelpers.copyRecursive(e, r, s), FSHelpers.isDir(e, r) ? FSHelpers.rmdir(e, r, { recursive: !0 }) : e.unlink(r)) : e.rename(r, s);
168
+ const i = e.lookupPath(t).node.mount, n = FSHelpers.fileExists(e, s) ? e.lookupPath(s).node.mount : e.lookupPath(dirname(s)).node.mount;
169
+ i.mountpoint !== n.mountpoint ? (FSHelpers.copyRecursive(e, t, s), FSHelpers.isDir(e, t) ? FSHelpers.rmdir(e, t, { recursive: !0 }) : e.unlink(t)) : e.rename(t, s);
169
170
  } catch (i) {
170
- const o = getEmscriptenFsError(i);
171
- throw o ? new Error(
172
- `Could not move ${r} to ${s}: ${o}`,
171
+ const n = getEmscriptenFsError(i);
172
+ throw n ? new Error(
173
+ `Could not move ${t} to ${s}: ${n}`,
173
174
  {
174
175
  cause: i
175
176
  }
@@ -183,11 +184,11 @@ class FSHelpers {
183
184
  * @param path The directory path to remove.
184
185
  * @param options Options for the removal.
185
186
  */
186
- static rmdir(e, r, s = { recursive: !0 }) {
187
- s != null && s.recursive && FSHelpers.listFiles(e, r).forEach((i) => {
188
- const o = `${r}/${i}`;
189
- FSHelpers.isDir(e, o) ? FSHelpers.rmdir(e, o, s) : FSHelpers.unlink(e, o);
190
- }), e.rmdir(r);
187
+ static rmdir(e, t, s = { recursive: !0 }) {
188
+ s != null && s.recursive && FSHelpers.listFiles(e, t).forEach((i) => {
189
+ const n = `${t}/${i}`;
190
+ FSHelpers.isDir(e, n) ? FSHelpers.rmdir(e, n, s) : FSHelpers.unlink(e, n);
191
+ }), e.getPath(e.lookupPath(t).node) === e.cwd() && e.chdir(joinPaths(e.cwd(), "..")), e.rmdir(t);
191
192
  }
192
193
  /**
193
194
  * Lists the files and directories in the given directory.
@@ -197,20 +198,20 @@ class FSHelpers {
197
198
  * @param options - Options for the listing.
198
199
  * @returns The list of files and directories in the given directory.
199
200
  */
200
- static listFiles(e, r, s = { prependPath: !1 }) {
201
- if (!FSHelpers.fileExists(e, r))
201
+ static listFiles(e, t, s = { prependPath: !1 }) {
202
+ if (!FSHelpers.fileExists(e, t))
202
203
  return [];
203
204
  try {
204
- const i = e.readdir(r).filter(
205
- (o) => o !== "." && o !== ".."
205
+ const i = e.readdir(t).filter(
206
+ (n) => n !== "." && n !== ".."
206
207
  );
207
208
  if (s.prependPath) {
208
- const o = r.replace(/\/$/, "");
209
- return i.map((n) => `${o}/${n}`);
209
+ const n = t.replace(/\/$/, "");
210
+ return i.map((o) => `${n}/${o}`);
210
211
  }
211
212
  return i;
212
213
  } catch (i) {
213
- return logger.error(i, { path: r }), [];
214
+ return logger.error(i, { path: t }), [];
214
215
  }
215
216
  }
216
217
  /**
@@ -220,8 +221,8 @@ class FSHelpers {
220
221
  * @param path – The path to check.
221
222
  * @returns True if the path is a directory, false otherwise.
222
223
  */
223
- static isDir(e, r) {
224
- return FSHelpers.fileExists(e, r) ? e.isDir(e.lookupPath(r, { follow: !0 }).node.mode) : !1;
224
+ static isDir(e, t) {
225
+ return FSHelpers.fileExists(e, t) ? e.isDir(e.lookupPath(t, { follow: !0 }).node.mode) : !1;
225
226
  }
226
227
  /**
227
228
  * Checks if a file exists in the PHP filesystem.
@@ -230,8 +231,8 @@ class FSHelpers {
230
231
  * @param path – The path to check.
231
232
  * @returns True if the path is a file, false otherwise.
232
233
  */
233
- static isFile(e, r) {
234
- return FSHelpers.fileExists(e, r) ? e.isFile(e.lookupPath(r, { follow: !0 }).node.mode) : !1;
234
+ static isFile(e, t) {
235
+ return FSHelpers.fileExists(e, t) ? e.isFile(e.lookupPath(t, { follow: !0 }).node.mode) : !1;
235
236
  }
236
237
  /**
237
238
  * Creates a symlink in the PHP filesystem.
@@ -240,8 +241,8 @@ class FSHelpers {
240
241
  * @param target
241
242
  * @param link
242
243
  */
243
- static symlink(e, r, s) {
244
- return e.symlink(r, s);
244
+ static symlink(e, t, s) {
245
+ return e.symlink(t, s);
245
246
  }
246
247
  /**
247
248
  * Checks if a path is a symlink in the PHP filesystem.
@@ -250,8 +251,8 @@ class FSHelpers {
250
251
  * @param path
251
252
  * @returns True if the path is a symlink, false otherwise.
252
253
  */
253
- static isSymlink(e, r) {
254
- return FSHelpers.fileExists(e, r) ? e.isLink(e.lookupPath(r).node.mode) : !1;
254
+ static isSymlink(e, t) {
255
+ return FSHelpers.fileExists(e, t) ? e.isLink(e.lookupPath(t).node.mode) : !1;
255
256
  }
256
257
  /**
257
258
  * Reads the target of a symlink in the PHP filesystem.
@@ -260,8 +261,8 @@ class FSHelpers {
260
261
  * @returns The target of the symlink.
261
262
  * @throws {@link @php-wasm/universal:ErrnoError} – If the path is not a symlink.
262
263
  */
263
- static readlink(e, r) {
264
- return e.readlink(r);
264
+ static readlink(e, t) {
265
+ return e.readlink(t);
265
266
  }
266
267
  /**
267
268
  * Gets the real path of a file in the PHP filesystem.
@@ -270,8 +271,8 @@ class FSHelpers {
270
271
  *
271
272
  * @returns The real path of the file.
272
273
  */
273
- static realpath(e, r) {
274
- return e.lookupPath(r, { follow: !0 }).path;
274
+ static realpath(e, t) {
275
+ return e.lookupPath(t, { follow: !0 }).path;
275
276
  }
276
277
  /**
277
278
  * Checks if a file (or a directory) exists in the PHP filesystem.
@@ -280,9 +281,9 @@ class FSHelpers {
280
281
  * @param path - The file path to check.
281
282
  * @returns True if the file exists, false otherwise.
282
283
  */
283
- static fileExists(e, r) {
284
+ static fileExists(e, t) {
284
285
  try {
285
- return e.lookupPath(r), !0;
286
+ return e.lookupPath(t), !0;
286
287
  } catch {
287
288
  return !1;
288
289
  }
@@ -295,24 +296,24 @@ class FSHelpers {
295
296
  * @param FS
296
297
  * @param path - The directory path to create.
297
298
  */
298
- static mkdir(e, r) {
299
- e.mkdirTree(r);
299
+ static mkdir(e, t) {
300
+ e.mkdirTree(t);
300
301
  }
301
- static copyRecursive(e, r, s) {
302
- const i = e.lookupPath(r).node;
302
+ static copyRecursive(e, t, s) {
303
+ const i = e.lookupPath(t).node;
303
304
  if (e.isDir(i.mode)) {
304
305
  e.mkdirTree(s);
305
- const o = e.readdir(r).filter(
306
- (n) => n !== "." && n !== ".."
306
+ const n = e.readdir(t).filter(
307
+ (o) => o !== "." && o !== ".."
307
308
  );
308
- for (const n of o)
309
+ for (const o of n)
309
310
  FSHelpers.copyRecursive(
310
311
  e,
311
- joinPaths(r, n),
312
- joinPaths(s, n)
312
+ joinPaths(t, o),
313
+ joinPaths(s, o)
313
314
  );
314
315
  } else
315
- e.writeFile(s, e.readFile(r));
316
+ e.writeFile(s, e.readFile(t));
316
317
  }
317
318
  }
318
319
  FSHelpers.readFileAsText = rethrowFileSystemError('Could not read "{path}"')(
@@ -354,9 +355,9 @@ FSHelpers.copyRecursive = rethrowFileSystemError(
354
355
  const _private = /* @__PURE__ */ new WeakMap();
355
356
  class PHPWorker {
356
357
  /** @inheritDoc */
357
- constructor(e, r) {
358
+ constructor(e, t) {
358
359
  this.absoluteUrl = "", this.documentRoot = "", _private.set(this, {
359
- monitor: r
360
+ monitor: t
360
361
  }), e && this.__internal_setRequestHandler(e);
361
362
  }
362
363
  __internal_setRequestHandler(e) {
@@ -393,16 +394,16 @@ class PHPWorker {
393
394
  * The onDownloadProgress event listener.
394
395
  */
395
396
  async onDownloadProgress(e) {
396
- var r;
397
- return (r = _private.get(this).monitor) == null ? void 0 : r.addEventListener("progress", e);
397
+ var t;
398
+ return (t = _private.get(this).monitor) == null ? void 0 : t.addEventListener("progress", e);
398
399
  }
399
400
  /** @inheritDoc @php-wasm/universal!PHP.mv */
400
- async mv(e, r) {
401
- return _private.get(this).php.mv(e, r);
401
+ async mv(e, t) {
402
+ return _private.get(this).php.mv(e, t);
402
403
  }
403
404
  /** @inheritDoc @php-wasm/universal!PHP.rmdir */
404
- async rmdir(e, r) {
405
- return _private.get(this).php.rmdir(e, r);
405
+ async rmdir(e, t) {
406
+ return _private.get(this).php.rmdir(e, t);
406
407
  }
407
408
  /** @inheritDoc @php-wasm/universal!PHPRequestHandler.request */
408
409
  async request(e) {
@@ -410,9 +411,9 @@ class PHPWorker {
410
411
  }
411
412
  /** @inheritDoc @php-wasm/universal!/PHP.run */
412
413
  async run(e) {
413
- const { php: r, reap: s } = await _private.get(this).requestHandler.processManager.acquirePHPInstance();
414
+ const { php: t, reap: s } = await _private.get(this).requestHandler.processManager.acquirePHPInstance();
414
415
  try {
415
- return await r.run(e);
416
+ return await t.run(e);
416
417
  } finally {
417
418
  s();
418
419
  }
@@ -442,16 +443,16 @@ class PHPWorker {
442
443
  return _private.get(this).php.readFileAsBuffer(e);
443
444
  }
444
445
  /** @inheritDoc @php-wasm/universal!/PHP.writeFile */
445
- writeFile(e, r) {
446
- return _private.get(this).php.writeFile(e, r);
446
+ writeFile(e, t) {
447
+ return _private.get(this).php.writeFile(e, t);
447
448
  }
448
449
  /** @inheritDoc @php-wasm/universal!/PHP.unlink */
449
450
  unlink(e) {
450
451
  return _private.get(this).php.unlink(e);
451
452
  }
452
453
  /** @inheritDoc @php-wasm/universal!/PHP.listFiles */
453
- listFiles(e, r) {
454
- return _private.get(this).php.listFiles(e, r);
454
+ listFiles(e, t) {
455
+ return _private.get(this).php.listFiles(e, t);
455
456
  }
456
457
  /** @inheritDoc @php-wasm/universal!/PHP.isDir */
457
458
  isDir(e) {
@@ -470,16 +471,20 @@ class PHPWorker {
470
471
  return _private.get(this).php.onMessage(e);
471
472
  }
472
473
  /** @inheritDoc @php-wasm/universal!/PHP.defineConstant */
473
- defineConstant(e, r) {
474
- _private.get(this).php.defineConstant(e, r);
474
+ defineConstant(e, t) {
475
+ _private.get(this).php.defineConstant(e, t);
475
476
  }
476
477
  /** @inheritDoc @php-wasm/universal!/PHP.addEventListener */
477
- addEventListener(e, r) {
478
- _private.get(this).php.addEventListener(e, r);
478
+ addEventListener(e, t) {
479
+ _private.get(this).php.addEventListener(e, t);
479
480
  }
480
481
  /** @inheritDoc @php-wasm/universal!/PHP.removeEventListener */
481
- removeEventListener(e, r) {
482
- _private.get(this).php.removeEventListener(e, r);
482
+ removeEventListener(e, t) {
483
+ _private.get(this).php.removeEventListener(e, t);
484
+ }
485
+ async [Symbol.asyncDispose]() {
486
+ var e;
487
+ await ((e = _private.get(this).requestHandler) == null ? void 0 : e[Symbol.asyncDispose]());
483
488
  }
484
489
  }
485
490
  const responseTexts = {
@@ -497,16 +502,107 @@ const responseTexts = {
497
502
  201: "Created",
498
503
  200: "OK"
499
504
  };
505
+ class StreamedPHPResponse {
506
+ constructor(e, t, s, i) {
507
+ this.parsedHeaders = null, this.cachedStdoutText = null, this.cachedStderrText = null, this.headersStream = e, this.stdout = t, this.stderr = s, this.exitCode = i;
508
+ }
509
+ /**
510
+ * True if the response is successful (HTTP status code 200-399),
511
+ * false otherwise.
512
+ */
513
+ async ok() {
514
+ try {
515
+ const e = await this.httpStatusCode;
516
+ return e >= 200 && e < 400;
517
+ } catch {
518
+ return !1;
519
+ }
520
+ }
521
+ /**
522
+ * Resolves when the response has finished processing – either successfully or not.
523
+ */
524
+ get finished() {
525
+ return Promise.allSettled([this.exitCode.finally(() => {
526
+ })]).then(
527
+ () => {
528
+ }
529
+ );
530
+ }
531
+ /**
532
+ * Resolves once HTTP headers are available.
533
+ */
534
+ get headers() {
535
+ return this.getParsedHeaders().then((e) => e.headers);
536
+ }
537
+ /**
538
+ * Resolves once HTTP status code is available.
539
+ */
540
+ get httpStatusCode() {
541
+ return Promise.race([
542
+ this.getParsedHeaders().then((e) => e.httpStatusCode),
543
+ this.exitCode.then(
544
+ (e) => e !== 0 ? 500 : void 0
545
+ )
546
+ ]).then((e) => e !== void 0 ? e : this.getParsedHeaders().then(
547
+ (t) => t.httpStatusCode,
548
+ () => 200
549
+ )).catch(() => 500);
550
+ }
551
+ /**
552
+ * Exposes the stdout bytes as they're produced by the PHP instance
553
+ */
554
+ get stdoutText() {
555
+ return this.cachedStdoutText || (this.cachedStdoutText = streamToText(this.stdout)), this.cachedStdoutText;
556
+ }
557
+ /**
558
+ * Exposes the stderr bytes as they're produced by the PHP instance
559
+ */
560
+ get stderrText() {
561
+ return this.cachedStderrText || (this.cachedStderrText = streamToText(this.stderr)), this.cachedStderrText;
562
+ }
563
+ async getParsedHeaders() {
564
+ return this.parsedHeaders || (this.parsedHeaders = parseHeadersStream(this.headersStream)), await this.parsedHeaders;
565
+ }
566
+ }
567
+ async function parseHeadersStream(r) {
568
+ const e = await streamToText(r);
569
+ let t;
570
+ try {
571
+ t = JSON.parse(e);
572
+ } catch {
573
+ return { headers: {}, httpStatusCode: 200 };
574
+ }
575
+ const s = {};
576
+ for (const i of t.headers) {
577
+ if (!i.includes(": "))
578
+ continue;
579
+ const n = i.indexOf(": "), o = i.substring(0, n).toLowerCase(), a = i.substring(n + 2);
580
+ o in s || (s[o] = []), s[o].push(a);
581
+ }
582
+ return {
583
+ headers: s,
584
+ httpStatusCode: t.status
585
+ };
586
+ }
587
+ async function streamToText(r) {
588
+ const e = r.pipeThrough(new TextDecoderStream()).getReader(), t = [];
589
+ for (; ; ) {
590
+ const { done: s, value: i } = await e.read();
591
+ if (s)
592
+ return t.join("");
593
+ i && t.push(i);
594
+ }
595
+ }
500
596
  class PHPResponse {
501
- constructor(e, r, s, i = "", o = 0) {
502
- this.httpStatusCode = e, this.headers = r, this.bytes = s, this.exitCode = o, this.errors = i;
597
+ constructor(e, t, s, i = "", n = 0) {
598
+ this.httpStatusCode = e, this.headers = t, this.bytes = s, this.exitCode = n, this.errors = i;
503
599
  }
504
- static forHttpCode(e, r = "") {
600
+ static forHttpCode(e, t = "") {
505
601
  return new PHPResponse(
506
602
  e,
507
603
  {},
508
604
  new TextEncoder().encode(
509
- r || responseTexts[e] || ""
605
+ t || responseTexts[e] || ""
510
606
  )
511
607
  );
512
608
  }
@@ -519,6 +615,15 @@ class PHPResponse {
519
615
  e.exitCode
520
616
  );
521
617
  }
618
+ static async fromStreamedResponse(e) {
619
+ return await e.finished, new PHPResponse(
620
+ await e.httpStatusCode,
621
+ await e.headers,
622
+ new TextEncoder().encode(await e.stdoutText),
623
+ await e.stderrText,
624
+ await e.exitCode
625
+ );
626
+ }
522
627
  toRawData() {
523
628
  return {
524
629
  headers: this.headers,
@@ -543,39 +648,39 @@ class PHPResponse {
543
648
  }
544
649
  const RuntimeId = Symbol("RuntimeId"), loadedRuntimes = /* @__PURE__ */ new Map();
545
650
  let lastRuntimeId = 0;
546
- async function loadPHPRuntime(t, ...e) {
547
- const r = Object.assign({}, ...e), [s, i, o] = makePromise(), n = t.init(currentJsRuntime, {
548
- onAbort(a) {
549
- o(a), logger.error(a);
651
+ async function loadPHPRuntime(r, ...e) {
652
+ const t = Object.assign({}, ...e), [s, i, n] = makePromise(), o = r.init(currentJsRuntime, {
653
+ onAbort(l) {
654
+ n(l), logger.error(l);
550
655
  },
551
656
  ENV: {},
552
657
  // Emscripten sometimes prepends a '/' to the path, which
553
658
  // breaks vite dev mode. An identity `locateFile` function
554
659
  // fixes it.
555
- locateFile: (a) => a,
556
- ...r,
660
+ locateFile: (l) => l,
661
+ ...t,
557
662
  noInitialRun: !0,
558
663
  onRuntimeInitialized() {
559
- r.onRuntimeInitialized && r.onRuntimeInitialized(n), i();
664
+ t.onRuntimeInitialized && t.onRuntimeInitialized(o), i();
560
665
  }
561
666
  });
562
667
  await s;
563
- const l = ++lastRuntimeId;
564
- return n.FS, n.id = l, n.originalExit = n._exit, n._exit = function(a) {
565
- return n.outboundNetworkProxyServer && (n.outboundNetworkProxyServer.close(), n.outboundNetworkProxyServer.closeAllConnections()), loadedRuntimes.delete(l), n.originalExit(a);
566
- }, n[RuntimeId] = l, loadedRuntimes.set(l, n), l;
668
+ const a = ++lastRuntimeId;
669
+ return o.FS, o.id = a, o.originalExit = o._exit, o._exit = function(l) {
670
+ return o.outboundNetworkProxyServer && (o.outboundNetworkProxyServer.close(), o.outboundNetworkProxyServer.closeAllConnections()), loadedRuntimes.delete(a), o.originalExit(l);
671
+ }, o[RuntimeId] = a, loadedRuntimes.set(a, o), a;
567
672
  }
568
- function getLoadedRuntime(t) {
569
- return loadedRuntimes.get(t);
673
+ function getLoadedRuntime(r) {
674
+ return loadedRuntimes.get(r);
570
675
  }
571
676
  const currentJsRuntime = function() {
572
- var t;
573
- 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";
677
+ var r;
678
+ return typeof process < "u" && ((r = process.release) == null ? void 0 : r.name) === "node" ? "NODE" : typeof window < "u" ? "WEB" : typeof WorkerGlobalScope < "u" && self instanceof WorkerGlobalScope ? "WORKER" : "NODE";
574
679
  }(), makePromise = () => {
575
- const t = [], e = new Promise((r, s) => {
576
- t.push(r, s);
680
+ const r = [], e = new Promise((t, s) => {
681
+ r.push(t, s);
577
682
  });
578
- return t.unshift(e), t;
683
+ return r.unshift(e), r;
579
684
  };
580
685
  var _a;
581
686
  const kError = Symbol("error"), kMessage = Symbol("message");
@@ -587,8 +692,8 @@ class ErrorEvent2 extends (_a = Event, _a) {
587
692
  * @param options A dictionary object that allows for setting
588
693
  * attributes via object members of the same name.
589
694
  */
590
- constructor(e, r = {}) {
591
- super(e), this[kError] = r.error === void 0 ? null : r.error, this[kMessage] = r.message === void 0 ? "" : r.message;
695
+ constructor(e, t = {}) {
696
+ super(e), this[kError] = t.error === void 0 ? null : t.error, this[kMessage] = t.message === void 0 ? "" : t.message;
592
697
  }
593
698
  get error() {
594
699
  return this[kError];
@@ -600,49 +705,56 @@ class ErrorEvent2 extends (_a = Event, _a) {
600
705
  Object.defineProperty(ErrorEvent2.prototype, "error", { enumerable: !0 });
601
706
  Object.defineProperty(ErrorEvent2.prototype, "message", { enumerable: !0 });
602
707
  const ErrorEvent = typeof globalThis.ErrorEvent == "function" ? globalThis.ErrorEvent : ErrorEvent2;
603
- function isExitCodeZero(t) {
604
- 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;
708
+ function isExitCode(r) {
709
+ return r instanceof Error ? "exitCode" in r || (r == null ? void 0 : r.name) === "ExitStatus" && "status" in r : !1;
605
710
  }
606
711
  class UnhandledRejectionsTarget extends EventTarget {
607
712
  constructor() {
608
713
  super(...arguments), this.listenersCount = 0;
609
714
  }
610
- addEventListener(e, r) {
611
- ++this.listenersCount, super.addEventListener(e, r);
715
+ addEventListener(e, t, s) {
716
+ ++this.listenersCount, super.addEventListener(
717
+ e,
718
+ t,
719
+ s
720
+ );
612
721
  }
613
- removeEventListener(e, r) {
614
- --this.listenersCount, super.removeEventListener(e, r);
722
+ removeEventListener(e, t, s) {
723
+ --this.listenersCount, super.removeEventListener(
724
+ e,
725
+ t,
726
+ s
727
+ );
615
728
  }
616
729
  hasListeners() {
617
730
  return this.listenersCount > 0;
618
731
  }
619
732
  }
620
- function improveWASMErrorReporting(t) {
733
+ function improveWASMErrorReporting(r) {
621
734
  const e = new UnhandledRejectionsTarget();
622
- for (const r in t.wasmExports)
623
- if (typeof t.wasmExports[r] == "function") {
624
- const s = t.wasmExports[r];
625
- t.wasmExports[r] = function(...i) {
626
- var o;
735
+ for (const t in r.wasmExports)
736
+ if (typeof r.wasmExports[t] == "function") {
737
+ const s = r.wasmExports[t];
738
+ r.wasmExports[t] = function(...i) {
739
+ var n;
627
740
  try {
628
741
  return s(...i);
629
- } catch (n) {
630
- if (!(n instanceof Error))
631
- throw n;
632
- const l = clarifyErrorMessage(
633
- n,
634
- (o = t.lastAsyncifyStackSource) == null ? void 0 : o.stack
742
+ } catch (o) {
743
+ if (!(o instanceof Error))
744
+ throw o;
745
+ r.lastAsyncifyStackSource && (o.cause = r.lastAsyncifyStackSource);
746
+ const a = clarifyErrorMessage(
747
+ o,
748
+ (n = r.lastAsyncifyStackSource) == null ? void 0 : n.stack
635
749
  );
636
- if (t.lastAsyncifyStackSource && (n.cause = t.lastAsyncifyStackSource), e.hasListeners()) {
637
- e.dispatchEvent(
638
- new ErrorEvent("error", {
639
- error: n,
640
- message: l
641
- })
642
- );
643
- return;
750
+ if (e.hasListeners()) {
751
+ const l = new ErrorEvent("error", {
752
+ error: o,
753
+ message: a
754
+ });
755
+ throw e.dispatchEvent(l), o;
644
756
  }
645
- throw isExitCodeZero(n) || showCriticalErrorBox(l), n;
757
+ throw (!isExitCode(o) || o.exitCode !== 0) && showCriticalErrorBox(a), o;
646
758
  }
647
759
  };
648
760
  }
@@ -652,23 +764,33 @@ let functionsMaybeMissingFromAsyncify = [];
652
764
  function getFunctionsMaybeMissingFromAsyncify() {
653
765
  return functionsMaybeMissingFromAsyncify;
654
766
  }
655
- function clarifyErrorMessage(t, e) {
656
- if (t.message === "unreachable") {
657
- let r = UNREACHABLE_ERROR;
658
- e || (r += `
767
+ function clarifyErrorMessage(r, e) {
768
+ if (r.message === "unreachable") {
769
+ let t = UNREACHABLE_ERROR;
770
+ e || (t += `
659
771
 
660
772
  This stack trace is lacking. For a better one initialize
661
773
  the PHP runtime with { debug: true }, e.g. PHPNode.load('8.1', { debug: true }).
662
774
 
663
- `), functionsMaybeMissingFromAsyncify = extractPHPFunctionsFromStack(
664
- e || t.stack || ""
775
+ `);
776
+ const s = new Set(
777
+ extractPHPFunctionsFromStack(e || "")
665
778
  );
666
- for (const s of functionsMaybeMissingFromAsyncify)
667
- r += ` * ${s}
779
+ let i = r;
780
+ do {
781
+ for (const n of extractPHPFunctionsFromStack(
782
+ i.stack || ""
783
+ ))
784
+ s.add(n);
785
+ i = i.cause;
786
+ } while (i);
787
+ functionsMaybeMissingFromAsyncify = Array.from(s);
788
+ for (const n of s)
789
+ t += ` * ${n}
668
790
  `;
669
- return r;
791
+ return t;
670
792
  }
671
- return t.message;
793
+ return r.message;
672
794
  }
673
795
  const UNREACHABLE_ERROR = `
674
796
  "unreachable" WASM instruction executed.
@@ -696,29 +818,29 @@ CLI option:
696
818
 
697
819
  `, redBg = "\x1B[41m", bold = "\x1B[1m", reset = "\x1B[0m", eol = "\x1B[K";
698
820
  let logged = !1;
699
- function showCriticalErrorBox(t) {
700
- if (!logged && (logged = !0, !(t != null && t.trim().startsWith("Program terminated with exit")))) {
821
+ function showCriticalErrorBox(r) {
822
+ if (!logged && (logged = !0, !(r != null && r.trim().startsWith("Program terminated with exit")))) {
701
823
  logger.log(`${redBg}
702
824
  ${eol}
703
825
  ${bold} WASM ERROR${reset}${redBg}`);
704
- for (const e of t.split(`
826
+ for (const e of r.split(`
705
827
  `))
706
828
  logger.log(`${eol} ${e} `);
707
829
  logger.log(`${reset}`);
708
830
  }
709
831
  }
710
- function extractPHPFunctionsFromStack(t) {
832
+ function extractPHPFunctionsFromStack(r) {
711
833
  try {
712
- const e = t.split(`
713
- `).slice(1).map((r) => {
714
- const s = r.trim().substring(3).split(" ");
834
+ const e = r.split(`
835
+ `).slice(1).map((t) => {
836
+ const s = t.trim().substring(3).split(" ");
715
837
  return {
716
838
  fn: s.length >= 2 ? s[0] : "<unknown>",
717
- isWasm: r.includes("wasm://")
839
+ isWasm: t.includes("wasm:/")
718
840
  };
719
841
  }).filter(
720
- ({ fn: r, isWasm: s }) => s && !r.startsWith("dynCall_") && !r.startsWith("invoke_")
721
- ).map(({ fn: r }) => r);
842
+ ({ fn: t, isWasm: s }) => s && !t.startsWith("dynCall_") && !t.startsWith("invoke_")
843
+ ).map(({ fn: t }) => t);
722
844
  return Array.from(new Set(e));
723
845
  } catch {
724
846
  return [];
@@ -726,12 +848,12 @@ function extractPHPFunctionsFromStack(t) {
726
848
  }
727
849
  const STRING = "string", NUMBER = "number", __private__dont__use = Symbol("__private__dont__use");
728
850
  class PHPExecutionFailureError extends Error {
729
- constructor(e, r, s) {
730
- super(e), this.response = r, this.source = s;
851
+ constructor(e, t, s) {
852
+ super(e), this.response = t, this.source = s;
731
853
  }
732
854
  }
733
855
  const PHP_INI_PATH = "/internal/shared/php.ini", AUTO_PREPEND_SCRIPT = "/internal/shared/auto_prepend_file.php";
734
- var F, P, v, _, x, R, u, N, M, j, U, L, q, $, B, O, D, A, z, W, G;
856
+ var T, _, H, P, R, k, u, z, L, W, G, V, J, Y, K, X, $, Q, B, D;
735
857
  class PHP {
736
858
  /**
737
859
  * Initializes a PHP runtime.
@@ -740,38 +862,38 @@ class PHP {
740
862
  * @param PHPRuntime - Optional. PHP Runtime ID as initialized by loadPHPRuntime.
741
863
  * @param requestHandlerOptions - Optional. Options for the PHPRequestHandler. If undefined, no request handler will be initialized.
742
864
  */
743
- constructor(t) {
865
+ constructor(r) {
744
866
  h(this, u);
745
- h(this, F);
746
- h(this, P, !1);
747
- h(this, v, null);
748
- h(this, _, /* @__PURE__ */ new Map());
749
- h(this, x, []);
750
- h(this, R, {});
751
- this.semaphore = new Semaphore({ concurrency: 1 }), t !== void 0 && this.initializeRuntime(t);
867
+ h(this, T);
868
+ h(this, _, !1);
869
+ h(this, H, null);
870
+ h(this, P, /* @__PURE__ */ new Map());
871
+ h(this, R, []);
872
+ h(this, k, {});
873
+ this.semaphore = new Semaphore({ concurrency: 1 }), r !== void 0 && this.initializeRuntime(r);
752
874
  }
753
875
  /**
754
876
  * Adds an event listener for a PHP event.
755
877
  * @param eventType - The type of event to listen for.
756
878
  * @param listener - The listener function to be called when the event is triggered.
757
879
  */
758
- addEventListener(t, e) {
759
- c(this, _).has(t) || c(this, _).set(t, /* @__PURE__ */ new Set()), c(this, _).get(t).add(e);
880
+ addEventListener(r, e) {
881
+ c(this, P).has(r) || c(this, P).set(r, /* @__PURE__ */ new Set()), c(this, P).get(r).add(e);
760
882
  }
761
883
  /**
762
884
  * Removes an event listener for a PHP event.
763
885
  * @param eventType - The type of event to remove the listener from.
764
886
  * @param listener - The listener function to be removed.
765
887
  */
766
- removeEventListener(t, e) {
767
- var r;
768
- (r = c(this, _).get(t)) == null || r.delete(e);
888
+ removeEventListener(r, e) {
889
+ var t;
890
+ (t = c(this, P).get(r)) == null || t.delete(e);
769
891
  }
770
- dispatchEvent(t) {
771
- const e = c(this, _).get(t.type);
892
+ dispatchEvent(r) {
893
+ const e = c(this, P).get(r.type);
772
894
  if (e)
773
- for (const r of e)
774
- r(t);
895
+ for (const t of e)
896
+ t(r);
775
897
  }
776
898
  /**
777
899
  * Listens to message sent by the PHP code.
@@ -812,10 +934,10 @@ class PHP {
812
934
  *
813
935
  * @param listener Callback function to handle the message.
814
936
  */
815
- onMessage(t) {
816
- return c(this, x).push(t), async () => {
817
- m(this, x, c(this, x).filter(
818
- (e) => e !== t
937
+ onMessage(r) {
938
+ return c(this, R).push(r), async () => {
939
+ f(this, R, c(this, R).filter(
940
+ (e) => e !== r
819
941
  ));
820
942
  };
821
943
  }
@@ -831,17 +953,17 @@ class PHP {
831
953
  return this.requestHandler.documentRoot;
832
954
  }
833
955
  /** @deprecated Use PHPRequestHandler instead. */
834
- pathToInternalUrl(t) {
835
- return this.requestHandler.pathToInternalUrl(t);
956
+ pathToInternalUrl(r) {
957
+ return this.requestHandler.pathToInternalUrl(r);
836
958
  }
837
959
  /** @deprecated Use PHPRequestHandler instead. */
838
- internalUrlToPath(t) {
839
- return this.requestHandler.internalUrlToPath(t);
960
+ internalUrlToPath(r) {
961
+ return this.requestHandler.internalUrlToPath(r);
840
962
  }
841
- initializeRuntime(t) {
963
+ initializeRuntime(r) {
842
964
  if (this[__private__dont__use])
843
965
  throw new Error("PHP runtime already initialized.");
844
- const e = getLoadedRuntime(t);
966
+ const e = getLoadedRuntime(r);
845
967
  if (!e)
846
968
  throw new Error("Invalid PHP runtime id.");
847
969
  this[__private__dont__use] = e, this[__private__dont__use].ccall(
@@ -889,29 +1011,29 @@ class PHP {
889
1011
  require_once $file;
890
1012
  }
891
1013
  `
892
- ), e.onMessage = async (r) => {
893
- for (const s of c(this, x)) {
894
- const i = await s(r);
1014
+ ), e.onMessage = async (t) => {
1015
+ for (const s of c(this, R)) {
1016
+ const i = await s(t);
895
1017
  if (i)
896
1018
  return i;
897
1019
  }
898
1020
  return "";
899
- }, m(this, v, improveWASMErrorReporting(e)), this.dispatchEvent({
1021
+ }, f(this, H, improveWASMErrorReporting(e)), this.dispatchEvent({
900
1022
  type: "runtime.initialized"
901
1023
  });
902
1024
  }
903
1025
  /** @inheritDoc */
904
- async setSapiName(t) {
1026
+ async setSapiName(r) {
905
1027
  if (this[__private__dont__use].ccall(
906
1028
  "wasm_set_sapi_name",
907
1029
  NUMBER,
908
1030
  [STRING],
909
- [t]
1031
+ [r]
910
1032
  ) !== 0)
911
1033
  throw new Error(
912
1034
  "Could not set SAPI name. This can only be done before the PHP WASM module is initialized.Did you already dispatch any requests?"
913
1035
  );
914
- m(this, F, t);
1036
+ f(this, T, r);
915
1037
  }
916
1038
  /**
917
1039
  * Changes the current working directory in the PHP filesystem.
@@ -921,19 +1043,19 @@ class PHP {
921
1043
  *
922
1044
  * @param path - The new working directory.
923
1045
  */
924
- chdir(t) {
925
- this[__private__dont__use].FS.chdir(t);
1046
+ chdir(r) {
1047
+ this[__private__dont__use].FS.chdir(r);
926
1048
  }
927
1049
  /**
928
1050
  * Do not use. Use new PHPRequestHandler() instead.
929
1051
  * @deprecated
930
1052
  */
931
- async request(t) {
1053
+ async request(r) {
932
1054
  if (logger.warn(
933
1055
  "PHP.request() is deprecated. Please use new PHPRequestHandler() instead."
934
1056
  ), !this.requestHandler)
935
1057
  throw new Error("No request handler available.");
936
- return this.requestHandler.request(t);
1058
+ return this.requestHandler.request(r);
937
1059
  }
938
1060
  /**
939
1061
  * Runs PHP code.
@@ -995,76 +1117,189 @@ class PHP {
995
1117
  *
996
1118
  * @example
997
1119
  * ```js
998
- * const result = await php.run(`<?php
999
- * $fp = fopen('php://stderr', 'w');
1000
- * fwrite($fp, "Hello, world!");
1001
- * `);
1120
+ * const result = await php.run({
1121
+ * code: `<?php
1122
+ * $fp = fopen('php://stderr', 'w');
1123
+ * fwrite($fp, "Hello, world!");
1124
+ * `
1125
+ * });
1002
1126
  * // result.errors === "Hello, world!"
1003
1127
  * ```
1004
1128
  *
1005
- * @param options - PHP runtime options.
1129
+ * @deprecated Use stream() instead.
1130
+ * @param request - PHP runtime options.
1131
+ */
1132
+ async run(r) {
1133
+ const e = await this.runStream(r), t = await PHPResponse.fromStreamedResponse(
1134
+ e
1135
+ );
1136
+ if (t.exitCode !== 0) {
1137
+ logger.warn("PHP.run() output was:", t.text);
1138
+ const s = new PHPExecutionFailureError(
1139
+ `PHP.run() failed with exit code ${t.exitCode} and the following output: ` + t.errors + `
1140
+
1141
+ ` + t.text,
1142
+ t,
1143
+ "request"
1144
+ );
1145
+ throw logger.error(s), this.dispatchEvent({
1146
+ type: "request.error",
1147
+ error: new Error(
1148
+ "PHP.run() failed with exit code " + t.exitCode
1149
+ ),
1150
+ // Distinguish between PHP request and PHP-wasm errors
1151
+ source: "request"
1152
+ }), s;
1153
+ }
1154
+ return t;
1155
+ }
1156
+ /**
1157
+ * Runs PHP code and returns a StreamedPHPResponse object that can be used to
1158
+ * process the output incrementally.
1159
+ *
1160
+ * This low-level method directly interacts with the WebAssembly
1161
+ * PHP interpreter and provides streaming capabilities for processing
1162
+ * PHP output as it becomes available.
1163
+ *
1164
+ * Every time you call stream(), it prepares the PHP
1165
+ * environment and:
1166
+ *
1167
+ * * Resets the internal PHP state
1168
+ * * Populates superglobals ($_SERVER, $_GET, etc.)
1169
+ * * Handles file uploads
1170
+ * * Populates input streams (stdin, argv, etc.)
1171
+ * * Sets the current working directory
1172
+ *
1173
+ * You can use stream() in two primary modes:
1174
+ *
1175
+ * ### Code snippet mode
1176
+ *
1177
+ * In this mode, you pass a string containing PHP code to run.
1178
+ *
1179
+ * ```ts
1180
+ * const streamedResponse = await php.stream({
1181
+ * code: `<?php echo "Hello world!";`
1182
+ * });
1183
+ * // Process output incrementally
1184
+ * for await (const chunk of streamedResponse.text) {
1185
+ * console.log(chunk);
1186
+ * }
1187
+ * ```
1188
+ *
1189
+ * In this mode, information like __DIR__ or __FILE__ isn't very
1190
+ * useful because the code is not associated with any file.
1191
+ *
1192
+ * Under the hood, the PHP snippet is passed to the `zend_eval_string`
1193
+ * C function.
1194
+ *
1195
+ * ### File mode
1196
+ *
1197
+ * In the file mode, you pass a scriptPath and PHP executes a file
1198
+ * found at that path:
1199
+ *
1200
+ * ```ts
1201
+ * php.writeFile(
1202
+ * "/www/index.php",
1203
+ * `<?php echo "Hello world!";"`
1204
+ * );
1205
+ * const streamedResponse = await php.stream({
1206
+ * scriptPath: "/www/index.php"
1207
+ * });
1208
+ * // Process output incrementally
1209
+ * for await (const chunk of streamedResponse.text) {
1210
+ * console.log(chunk);
1211
+ * }
1212
+ * ```
1213
+ *
1214
+ * In this mode, you can rely on path-related information like __DIR__
1215
+ * or __FILE__.
1216
+ *
1217
+ * Under the hood, the PHP file is executed with the `php_execute_script`
1218
+ * C function.
1219
+ *
1220
+ * The `stream()` method cannot be used in conjunction with `cli()`.
1221
+ *
1222
+ * @example
1223
+ * ```js
1224
+ * const streamedResponse = await php.stream({
1225
+ * code: `<?php
1226
+ * for ($i = 0; $i < 5; $i++) {
1227
+ * echo "Line $i\n";
1228
+ * flush();
1229
+ * }
1230
+ * `
1231
+ * });
1232
+ *
1233
+ * // Process output as it becomes available
1234
+ * for await (const chunk of streamedResponse.text) {
1235
+ * console.log('Received:', chunk);
1236
+ * }
1237
+ *
1238
+ * // Get the final exit code
1239
+ * const exitCode = await streamedResponse.exitCode;
1240
+ * console.log('Exit code:', exitCode);
1241
+ * ```
1242
+ *
1243
+ * @see run() – a synchronous version of this method.
1244
+ * @param request - PHP runtime options.
1245
+ * @returns A StreamedPHPResponse object.
1006
1246
  */
1007
- async run(t) {
1247
+ async runStream(r) {
1008
1248
  const e = await this.semaphore.acquire();
1009
- let r;
1010
- try {
1011
- if (c(this, P) || (d(this, u, M).call(this), m(this, P, !0)), t.scriptPath && !this.fileExists(t.scriptPath))
1249
+ let t;
1250
+ const s = d(this, u, D).call(this, () => {
1251
+ if (c(this, _) || (d(this, u, L).call(this), f(this, _, !0)), r.scriptPath && !this.fileExists(r.scriptPath))
1012
1252
  throw new Error(
1013
- `The script path "${t.scriptPath}" does not exist.`
1253
+ `The script path "${r.scriptPath}" does not exist.`
1014
1254
  );
1015
- d(this, u, U).call(this, t.relativeUri || ""), d(this, u, B).call(this, t.method || "GET");
1016
- const s = normalizeHeaders(t.headers || {}), i = s.host || "example.com:443", o = d(this, u, $).call(this, i, t.protocol || "http");
1017
- if (d(this, u, L).call(this, i), d(this, u, q).call(this, o), d(this, u, O).call(this, s), t.body && (r = d(this, u, D).call(this, t.body)), typeof t.code == "string")
1018
- this.writeFile("/internal/eval.php", t.code), d(this, u, A).call(this, "/internal/eval.php");
1019
- else if (typeof t.scriptPath == "string")
1020
- d(this, u, A).call(this, t.scriptPath || "");
1255
+ d(this, u, W).call(this, r.relativeUri || ""), d(this, u, Y).call(this, r.method || "GET");
1256
+ const i = normalizeHeaders(r.headers || {}), n = i.host || "example.com:443", o = d(this, u, J).call(this, n, r.protocol || "http");
1257
+ if (d(this, u, G).call(this, n), d(this, u, V).call(this, o), d(this, u, K).call(this, i), r.body && (t = d(this, u, X).call(this, r.body)), typeof r.code == "string")
1258
+ this.writeFile("/internal/eval.php", r.code), d(this, u, $).call(this, "/internal/eval.php");
1259
+ else if (typeof r.scriptPath == "string")
1260
+ d(this, u, $).call(this, r.scriptPath || "");
1021
1261
  else
1022
1262
  throw new TypeError(
1023
1263
  "The request object must have either a `code` or a `scriptPath` property."
1024
1264
  );
1025
- const n = d(this, u, N).call(this, t.$_SERVER, s, o);
1026
- for (const p in n)
1027
- d(this, u, z).call(this, p, n[p]);
1028
- const l = t.env || {};
1265
+ const a = d(this, u, z).call(this, r.$_SERVER, i, o);
1266
+ for (const p in a)
1267
+ d(this, u, Q).call(this, p, a[p]);
1268
+ const l = r.env || {};
1029
1269
  for (const p in l)
1030
- d(this, u, W).call(this, p, l[p]);
1031
- const a = await d(this, u, G).call(this);
1032
- if (a.exitCode !== 0) {
1033
- logger.warn("PHP.run() output was:", a.text);
1034
- const p = new PHPExecutionFailureError(
1035
- `PHP.run() failed with exit code ${a.exitCode} and the following output: ` + a.errors,
1036
- a,
1037
- "request"
1038
- );
1039
- throw logger.error(p), p;
1040
- }
1041
- return a;
1042
- } catch (s) {
1043
- throw this.dispatchEvent({
1270
+ d(this, u, B).call(this, p, l[p]);
1271
+ return c(this, _) || (d(this, u, L).call(this), f(this, _, !0)), this[__private__dont__use].ccall(
1272
+ "wasm_sapi_handle_request",
1273
+ NUMBER,
1274
+ [],
1275
+ [],
1276
+ { async: !0 }
1277
+ );
1278
+ });
1279
+ return await s.catch((i) => {
1280
+ this.dispatchEvent({
1044
1281
  type: "request.error",
1045
- error: s,
1282
+ error: i,
1046
1283
  // Distinguish between PHP request and PHP-wasm errors
1047
- source: s.source ?? "php-wasm"
1048
- }), s;
1049
- } finally {
1050
- try {
1051
- r && this[__private__dont__use].free(r);
1052
- } finally {
1053
- e(), this.dispatchEvent({
1054
- type: "request.end"
1055
- });
1056
- }
1057
- }
1284
+ source: i.source ?? "php-wasm"
1285
+ });
1286
+ }).finally(() => {
1287
+ t && this[__private__dont__use].free(t);
1288
+ }).finally(() => {
1289
+ e(), this.dispatchEvent({
1290
+ type: "request.end"
1291
+ });
1292
+ }), s;
1058
1293
  }
1059
1294
  /**
1060
1295
  * Defines a constant in the PHP runtime.
1061
1296
  * @param key - The name of the constant.
1062
1297
  * @param value - The value of the constant.
1063
1298
  */
1064
- defineConstant(t, e) {
1065
- let r = {};
1299
+ defineConstant(r, e) {
1300
+ let t = {};
1066
1301
  try {
1067
- r = JSON.parse(
1302
+ t = JSON.parse(
1068
1303
  this.fileExists("/internal/shared/consts.json") && this.readFileAsText("/internal/shared/consts.json") || "{}"
1069
1304
  );
1070
1305
  } catch {
@@ -1072,8 +1307,8 @@ class PHP {
1072
1307
  this.writeFile(
1073
1308
  "/internal/shared/consts.json",
1074
1309
  JSON.stringify({
1075
- ...r,
1076
- [t]: e
1310
+ ...t,
1311
+ [r]: e
1077
1312
  })
1078
1313
  );
1079
1314
  }
@@ -1084,14 +1319,14 @@ class PHP {
1084
1319
  *
1085
1320
  * @param path - The directory path to create.
1086
1321
  */
1087
- mkdir(t) {
1088
- return FSHelpers.mkdir(this[__private__dont__use].FS, t);
1322
+ mkdir(r) {
1323
+ return FSHelpers.mkdir(this[__private__dont__use].FS, r);
1089
1324
  }
1090
1325
  /**
1091
1326
  * @deprecated Use mkdir instead.
1092
1327
  */
1093
- mkdirTree(t) {
1094
- return FSHelpers.mkdir(this[__private__dont__use].FS, t);
1328
+ mkdirTree(r) {
1329
+ return FSHelpers.mkdir(this[__private__dont__use].FS, r);
1095
1330
  }
1096
1331
  /**
1097
1332
  * Reads a file from the PHP filesystem and returns it as a string.
@@ -1100,8 +1335,8 @@ class PHP {
1100
1335
  * @param path - The file path to read.
1101
1336
  * @returns The file contents.
1102
1337
  */
1103
- readFileAsText(t) {
1104
- return FSHelpers.readFileAsText(this[__private__dont__use].FS, t);
1338
+ readFileAsText(r) {
1339
+ return FSHelpers.readFileAsText(this[__private__dont__use].FS, r);
1105
1340
  }
1106
1341
  /**
1107
1342
  * Reads a file from the PHP filesystem and returns it as an array buffer.
@@ -1110,8 +1345,8 @@ class PHP {
1110
1345
  * @param path - The file path to read.
1111
1346
  * @returns The file contents.
1112
1347
  */
1113
- readFileAsBuffer(t) {
1114
- return FSHelpers.readFileAsBuffer(this[__private__dont__use].FS, t);
1348
+ readFileAsBuffer(r) {
1349
+ return FSHelpers.readFileAsBuffer(this[__private__dont__use].FS, r);
1115
1350
  }
1116
1351
  /**
1117
1352
  * Overwrites data in a file in the PHP filesystem.
@@ -1120,8 +1355,8 @@ class PHP {
1120
1355
  * @param path - The file path to write to.
1121
1356
  * @param data - The data to write to the file.
1122
1357
  */
1123
- writeFile(t, e) {
1124
- return FSHelpers.writeFile(this[__private__dont__use].FS, t, e);
1358
+ writeFile(r, e) {
1359
+ return FSHelpers.writeFile(this[__private__dont__use].FS, r, e);
1125
1360
  }
1126
1361
  /**
1127
1362
  * Removes a file from the PHP filesystem.
@@ -1129,8 +1364,8 @@ class PHP {
1129
1364
  * @throws {@link @php-wasm/universal:ErrnoError} – If the file doesn't exist.
1130
1365
  * @param path - The file path to remove.
1131
1366
  */
1132
- unlink(t) {
1133
- return FSHelpers.unlink(this[__private__dont__use].FS, t);
1367
+ unlink(r) {
1368
+ return FSHelpers.unlink(this[__private__dont__use].FS, r);
1134
1369
  }
1135
1370
  /**
1136
1371
  * Moves a file or directory in the PHP filesystem to a
@@ -1139,8 +1374,8 @@ class PHP {
1139
1374
  * @param oldPath The path to rename.
1140
1375
  * @param newPath The new path.
1141
1376
  */
1142
- mv(t, e) {
1143
- return FSHelpers.mv(this[__private__dont__use].FS, t, e);
1377
+ mv(r, e) {
1378
+ return FSHelpers.mv(this[__private__dont__use].FS, r, e);
1144
1379
  }
1145
1380
  /**
1146
1381
  * Removes a directory from the PHP filesystem.
@@ -1148,8 +1383,8 @@ class PHP {
1148
1383
  * @param path The directory path to remove.
1149
1384
  * @param options Options for the removal.
1150
1385
  */
1151
- rmdir(t, e = { recursive: !0 }) {
1152
- return FSHelpers.rmdir(this[__private__dont__use].FS, t, e);
1386
+ rmdir(r, e = { recursive: !0 }) {
1387
+ return FSHelpers.rmdir(this[__private__dont__use].FS, r, e);
1153
1388
  }
1154
1389
  /**
1155
1390
  * Lists the files and directories in the given directory.
@@ -1158,10 +1393,10 @@ class PHP {
1158
1393
  * @param options - Options for the listing.
1159
1394
  * @returns The list of files and directories in the given directory.
1160
1395
  */
1161
- listFiles(t, e = { prependPath: !1 }) {
1396
+ listFiles(r, e = { prependPath: !1 }) {
1162
1397
  return FSHelpers.listFiles(
1163
1398
  this[__private__dont__use].FS,
1164
- t,
1399
+ r,
1165
1400
  e
1166
1401
  );
1167
1402
  }
@@ -1171,8 +1406,8 @@ class PHP {
1171
1406
  * @param path – The path to check.
1172
1407
  * @returns True if the path is a directory, false otherwise.
1173
1408
  */
1174
- isDir(t) {
1175
- return FSHelpers.isDir(this[__private__dont__use].FS, t);
1409
+ isDir(r) {
1410
+ return FSHelpers.isDir(this[__private__dont__use].FS, r);
1176
1411
  }
1177
1412
  /**
1178
1413
  * Checks if a file exists in the PHP filesystem.
@@ -1180,16 +1415,16 @@ class PHP {
1180
1415
  * @param path – The path to check.
1181
1416
  * @returns True if the path is a file, false otherwise.
1182
1417
  */
1183
- isFile(t) {
1184
- return FSHelpers.isFile(this[__private__dont__use].FS, t);
1418
+ isFile(r) {
1419
+ return FSHelpers.isFile(this[__private__dont__use].FS, r);
1185
1420
  }
1186
1421
  /**
1187
1422
  * Creates a symlink in the PHP filesystem.
1188
1423
  * @param target
1189
1424
  * @param path
1190
1425
  */
1191
- symlink(t, e) {
1192
- return FSHelpers.symlink(this[__private__dont__use].FS, t, e);
1426
+ symlink(r, e) {
1427
+ return FSHelpers.symlink(this[__private__dont__use].FS, r, e);
1193
1428
  }
1194
1429
  /**
1195
1430
  * Checks if a path is a symlink in the PHP filesystem.
@@ -1197,8 +1432,8 @@ class PHP {
1197
1432
  * @param path
1198
1433
  * @returns True if the path is a symlink, false otherwise.
1199
1434
  */
1200
- isSymlink(t) {
1201
- return FSHelpers.isSymlink(this[__private__dont__use].FS, t);
1435
+ isSymlink(r) {
1436
+ return FSHelpers.isSymlink(this[__private__dont__use].FS, r);
1202
1437
  }
1203
1438
  /**
1204
1439
  * Reads the target of a symlink in the PHP filesystem.
@@ -1206,16 +1441,16 @@ class PHP {
1206
1441
  * @param path
1207
1442
  * @returns The target of the symlink.
1208
1443
  */
1209
- readlink(t) {
1210
- return FSHelpers.readlink(this[__private__dont__use].FS, t);
1444
+ readlink(r) {
1445
+ return FSHelpers.readlink(this[__private__dont__use].FS, r);
1211
1446
  }
1212
1447
  /**
1213
1448
  * Resolves the real path of a file in the PHP filesystem.
1214
1449
  * @param path
1215
1450
  * @returns The real path of the file.
1216
1451
  */
1217
- realpath(t) {
1218
- return FSHelpers.realpath(this[__private__dont__use].FS, t);
1452
+ realpath(r) {
1453
+ return FSHelpers.realpath(this[__private__dont__use].FS, r);
1219
1454
  }
1220
1455
  /**
1221
1456
  * Checks if a file (or a directory) exists in the PHP filesystem.
@@ -1223,8 +1458,8 @@ class PHP {
1223
1458
  * @param path - The file path to check.
1224
1459
  * @returns True if the file exists, false otherwise.
1225
1460
  */
1226
- fileExists(t) {
1227
- return FSHelpers.fileExists(this[__private__dont__use].FS, t);
1461
+ fileExists(r) {
1462
+ return FSHelpers.fileExists(this[__private__dont__use].FS, r);
1228
1463
  }
1229
1464
  /**
1230
1465
  * Hot-swaps the PHP runtime for a new one without
@@ -1236,17 +1471,17 @@ class PHP {
1236
1471
  * is fully decoupled from the request handler and
1237
1472
  * accepts a constructor-level cwd argument.
1238
1473
  */
1239
- async hotSwapPHPRuntime(t, e) {
1240
- const r = this[__private__dont__use].FS, s = [];
1241
- for (const [i, o] of Object.entries(c(this, R)))
1242
- s.push({ mountHandler: o.mountHandler, vfsPath: i }), await o.unmount();
1474
+ async hotSwapPHPRuntime(r, e) {
1475
+ const t = this[__private__dont__use].FS, s = [];
1476
+ for (const [i, n] of Object.entries(c(this, k)))
1477
+ s.push({ mountHandler: n.mountHandler, vfsPath: i }), await n.unmount();
1243
1478
  try {
1244
1479
  this.exit();
1245
1480
  } catch {
1246
1481
  }
1247
- this.initializeRuntime(t), c(this, F) && this.setSapiName(c(this, F)), copyFS(r, this[__private__dont__use].FS, "/internal"), e && copyFS(r, this[__private__dont__use].FS, e);
1248
- for (const { mountHandler: i, vfsPath: o } of s)
1249
- this.mkdir(o), await this.mount(o, i);
1482
+ this.initializeRuntime(r), c(this, T) && this.setSapiName(c(this, T)), copyFS(t, this[__private__dont__use].FS, "/internal"), e && copyFS(t, this[__private__dont__use].FS, e);
1483
+ for (const { mountHandler: i, vfsPath: n } of s)
1484
+ this.mkdir(n), await this.mount(n, i);
1250
1485
  }
1251
1486
  /**
1252
1487
  * Mounts a filesystem to a given path in the PHP filesystem.
@@ -1255,18 +1490,18 @@ class PHP {
1255
1490
  * @param mountHandler - The mount handler to use.
1256
1491
  * @return Unmount function to unmount the filesystem.
1257
1492
  */
1258
- async mount(t, e) {
1259
- const r = await e(
1493
+ async mount(r, e) {
1494
+ const t = await e(
1260
1495
  this,
1261
1496
  this[__private__dont__use].FS,
1262
- t
1497
+ r
1263
1498
  ), s = {
1264
1499
  mountHandler: e,
1265
1500
  unmount: async () => {
1266
- await r(), delete c(this, R)[t];
1501
+ await t(), delete c(this, k)[r];
1267
1502
  }
1268
1503
  };
1269
- return c(this, R)[t] = s, () => {
1504
+ return c(this, k)[r] = s, () => {
1270
1505
  s.unmount();
1271
1506
  };
1272
1507
  }
@@ -1283,53 +1518,45 @@ class PHP {
1283
1518
  * @param argv - The arguments to pass to the CLI.
1284
1519
  * @returns The exit code of the CLI session.
1285
1520
  */
1286
- async cli(t) {
1287
- for (const e of t)
1521
+ async cli(r, e = {}) {
1522
+ const t = await this.semaphore.acquire(), s = e.env || {};
1523
+ for (const [i, n] of Object.entries(s))
1524
+ d(this, u, B).call(this, i, n);
1525
+ r = [r[0], "-c", PHP_INI_PATH, ...r.slice(1)];
1526
+ for (const i of r)
1288
1527
  this[__private__dont__use].ccall(
1289
1528
  "wasm_add_cli_arg",
1290
1529
  null,
1291
1530
  [STRING],
1292
- [e]
1531
+ [i]
1293
1532
  );
1294
- try {
1295
- return await this[__private__dont__use].ccall(
1296
- "run_cli",
1297
- null,
1298
- [],
1299
- [],
1300
- {
1301
- async: !0
1302
- }
1303
- );
1304
- } catch (e) {
1305
- if (isExitCodeZero(e))
1306
- return 0;
1307
- throw e;
1308
- }
1533
+ return await d(this, u, D).call(this, () => this[__private__dont__use].ccall("run_cli", null, [], [], {
1534
+ async: !0
1535
+ })).then((i) => (i.exitCode.finally(t), i));
1309
1536
  }
1310
- setSkipShebang(t) {
1537
+ setSkipShebang(r) {
1311
1538
  this[__private__dont__use].ccall(
1312
1539
  "wasm_set_skip_shebang",
1313
1540
  null,
1314
1541
  [NUMBER],
1315
- [t ? 1 : 0]
1542
+ [r ? 1 : 0]
1316
1543
  );
1317
1544
  }
1318
- exit(t = 0) {
1545
+ exit(r = 0) {
1319
1546
  this.dispatchEvent({
1320
1547
  type: "runtime.beforedestroy"
1321
1548
  });
1322
1549
  try {
1323
- this[__private__dont__use]._exit(t);
1550
+ this[__private__dont__use]._exit(r);
1324
1551
  } catch {
1325
1552
  }
1326
- m(this, P, !1), m(this, v, null), delete this[__private__dont__use].onMessage, delete this[__private__dont__use];
1553
+ f(this, _, !1), f(this, H, null), this[__private__dont__use] && (delete this[__private__dont__use].onMessage, delete this[__private__dont__use]);
1327
1554
  }
1328
1555
  [Symbol.dispose]() {
1329
- c(this, P) && this.exit(0);
1556
+ c(this, _) && this.exit(0);
1330
1557
  }
1331
1558
  }
1332
- F = new WeakMap(), P = new WeakMap(), v = new WeakMap(), _ = new WeakMap(), x = new WeakMap(), R = new WeakMap(), u = new WeakSet(), /**
1559
+ T = new WeakMap(), _ = new WeakMap(), H = new WeakMap(), P = new WeakMap(), R = new WeakMap(), k = new WeakMap(), u = new WeakSet(), /**
1333
1560
  * Prepares the $_SERVER entries for the PHP runtime.
1334
1561
  *
1335
1562
  * @param defaults Default entries to include in $_SERVER.
@@ -1338,107 +1565,90 @@ F = new WeakMap(), P = new WeakMap(), v = new WeakMap(), _ = new WeakMap(), x =
1338
1565
  * was provided.
1339
1566
  * @returns Computed $_SERVER entries.
1340
1567
  */
1341
- N = function(t, e, r) {
1568
+ z = function(r, e, t) {
1342
1569
  const s = {
1343
- ...t || {}
1570
+ ...r || {}
1344
1571
  };
1345
- s.HTTPS = s.HTTPS || r === 443 ? "on" : "off";
1572
+ s.HTTPS = s.HTTPS || t === 443 ? "on" : "off";
1346
1573
  for (const i in e) {
1347
- let o = "HTTP_";
1348
- ["content-type", "content-length"].includes(i.toLowerCase()) && (o = ""), s[`${o}${i.toUpperCase().replace(/-/g, "_")}`] = e[i];
1574
+ let n = "HTTP_";
1575
+ ["content-type", "content-length"].includes(i.toLowerCase()) && (n = ""), s[`${n}${i.toUpperCase().replace(/-/g, "_")}`] = e[i];
1349
1576
  }
1350
1577
  return s;
1351
- }, M = function() {
1578
+ }, L = function() {
1352
1579
  this[__private__dont__use].ccall("php_wasm_init", null, [], []);
1353
- }, j = function() {
1354
- const t = "/internal/headers.json";
1355
- if (!this.fileExists(t))
1356
- throw new Error(
1357
- "SAPI Error: Could not find response headers file."
1358
- );
1359
- const e = JSON.parse(this.readFileAsText(t)), r = {};
1360
- for (const s of e.headers) {
1361
- if (!s.includes(": "))
1362
- continue;
1363
- const i = s.indexOf(": "), o = s.substring(0, i).toLowerCase(), n = s.substring(i + 2);
1364
- o in r || (r[o] = []), r[o].push(n);
1365
- }
1366
- return {
1367
- headers: r,
1368
- httpStatusCode: e.status
1369
- };
1370
- }, U = function(t) {
1580
+ }, W = function(r) {
1371
1581
  this[__private__dont__use].ccall(
1372
1582
  "wasm_set_request_uri",
1373
1583
  null,
1374
1584
  [STRING],
1375
- [t]
1585
+ [r]
1376
1586
  );
1377
1587
  let e = "";
1378
- t.includes("?") && (e = t.substring(t.indexOf("?") + 1)), this[__private__dont__use].ccall(
1588
+ r.includes("?") && (e = r.substring(r.indexOf("?") + 1)), this[__private__dont__use].ccall(
1379
1589
  "wasm_set_query_string",
1380
1590
  null,
1381
1591
  [STRING],
1382
1592
  [e]
1383
1593
  );
1384
- }, L = function(t) {
1594
+ }, G = function(r) {
1385
1595
  this[__private__dont__use].ccall(
1386
1596
  "wasm_set_request_host",
1387
1597
  null,
1388
1598
  [STRING],
1389
- [t]
1599
+ [r]
1390
1600
  );
1391
- }, q = function(t) {
1601
+ }, V = function(r) {
1392
1602
  this[__private__dont__use].ccall(
1393
1603
  "wasm_set_request_port",
1394
1604
  null,
1395
1605
  [NUMBER],
1396
- [t]
1606
+ [r]
1397
1607
  );
1398
- }, $ = function(t, e) {
1399
- let r;
1608
+ }, J = function(r, e) {
1609
+ let t;
1400
1610
  try {
1401
- r = parseInt(new URL(t).port, 10);
1611
+ t = parseInt(new URL(r).port, 10);
1402
1612
  } catch {
1403
1613
  }
1404
- return (!r || isNaN(r) || r === 80) && (r = e === "https" ? 443 : 80), r;
1405
- }, B = function(t) {
1614
+ return (!t || isNaN(t) || t === 80) && (t = e === "https" ? 443 : 80), t;
1615
+ }, Y = function(r) {
1406
1616
  this[__private__dont__use].ccall(
1407
1617
  "wasm_set_request_method",
1408
1618
  null,
1409
1619
  [STRING],
1410
- [t]
1620
+ [r]
1411
1621
  );
1412
- }, O = function(t) {
1413
- t.cookie && this[__private__dont__use].ccall(
1622
+ }, K = function(r) {
1623
+ r.cookie && this[__private__dont__use].ccall(
1414
1624
  "wasm_set_cookies",
1415
1625
  null,
1416
1626
  [STRING],
1417
- [t.cookie]
1418
- ), t["content-type"] && this[__private__dont__use].ccall(
1627
+ [r.cookie]
1628
+ ), r["content-type"] && this[__private__dont__use].ccall(
1419
1629
  "wasm_set_content_type",
1420
1630
  null,
1421
1631
  [STRING],
1422
- [t["content-type"]]
1423
- ), t["content-length"] && this[__private__dont__use].ccall(
1632
+ [r["content-type"]]
1633
+ ), r["content-length"] && this[__private__dont__use].ccall(
1424
1634
  "wasm_set_content_length",
1425
1635
  null,
1426
1636
  [NUMBER],
1427
- [parseInt(t["content-length"], 10)]
1637
+ [parseInt(r["content-length"], 10)]
1428
1638
  );
1429
- }, D = function(t) {
1430
- let e, r;
1431
- typeof t == "string" ? (logger.warn(
1639
+ }, X = function(r) {
1640
+ let e, t;
1641
+ typeof r == "string" ? (logger.warn(
1432
1642
  "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"
1433
- ), r = this[__private__dont__use].lengthBytesUTF8(t), e = r + 1) : (r = t.byteLength, e = t.byteLength);
1643
+ ), t = this[__private__dont__use].lengthBytesUTF8(r), e = t + 1) : (t = r.byteLength, e = r.byteLength);
1434
1644
  const s = this[__private__dont__use].malloc(e);
1435
1645
  if (!s)
1436
1646
  throw new Error("Could not allocate memory for the request body.");
1437
- return typeof t == "string" ? this[__private__dont__use].stringToUTF8(
1438
- t,
1647
+ return typeof r == "string" ? this[__private__dont__use].stringToUTF8(
1648
+ r,
1439
1649
  s,
1440
1650
  e + 1
1441
- ) : this[__private__dont__use].HEAPU8.set(t, s), this[__private__dont__use].ccall(
1651
+ ) : this[__private__dont__use].HEAPU8.set(r, s), this[__private__dont__use].ccall(
1442
1652
  "wasm_set_request_body",
1443
1653
  null,
1444
1654
  [NUMBER],
@@ -1447,119 +1657,155 @@ N = function(t, e, r) {
1447
1657
  "wasm_set_content_length",
1448
1658
  null,
1449
1659
  [NUMBER],
1450
- [r]
1660
+ [t]
1451
1661
  ), s;
1452
- }, A = function(t) {
1662
+ }, $ = function(r) {
1453
1663
  this[__private__dont__use].ccall(
1454
1664
  "wasm_set_path_translated",
1455
1665
  null,
1456
1666
  [STRING],
1457
- [t]
1667
+ [r]
1458
1668
  );
1459
- }, z = function(t, e) {
1669
+ }, Q = function(r, e) {
1460
1670
  this[__private__dont__use].ccall(
1461
1671
  "wasm_add_SERVER_entry",
1462
1672
  null,
1463
1673
  [STRING, STRING],
1464
- [t, e]
1674
+ [r, e]
1465
1675
  );
1466
- }, W = function(t, e) {
1676
+ }, B = function(r, e) {
1467
1677
  this[__private__dont__use].ccall(
1468
1678
  "wasm_add_ENV_entry",
1469
1679
  null,
1470
1680
  [STRING, STRING],
1471
- [t, e]
1681
+ [r, e]
1472
1682
  );
1473
- }, G = async function() {
1474
- var i;
1475
- let t, e;
1476
- try {
1477
- t = await new Promise((o, n) => {
1478
- var a;
1479
- e = (p) => {
1480
- logger.error(p), logger.error(p.error);
1481
- const T = new Error("Rethrown");
1482
- T.cause = p.error, T.betterMessage = p.message, n(T);
1483
- }, (a = c(this, v)) == null || a.addEventListener(
1683
+ }, D = async function(r) {
1684
+ const e = this[__private__dont__use], t = await createInvertedReadableStream();
1685
+ e.onHeaders = (m) => {
1686
+ a || s || t.controller.enqueue(m.slice());
1687
+ };
1688
+ let s = !1;
1689
+ const i = () => {
1690
+ s || (s = !0, t.controller.close());
1691
+ }, n = await createInvertedReadableStream();
1692
+ e.onStdout = (m) => {
1693
+ i(), !a && n.controller.enqueue(m.slice());
1694
+ };
1695
+ const o = await createInvertedReadableStream();
1696
+ e.onStderr = (m) => {
1697
+ a || o.controller.enqueue(m.slice());
1698
+ };
1699
+ let a = !1, l;
1700
+ const E = (async () => {
1701
+ var m;
1702
+ try {
1703
+ return await Promise.race([
1704
+ r(),
1705
+ new Promise((N, U) => {
1706
+ var b;
1707
+ l = (w) => {
1708
+ if (logger.error(w), logger.error(w.error), !isExitCode(w.error)) {
1709
+ const j = new Error("Rethrown");
1710
+ j.cause = w.error, j.betterMessage = w.message, U(j);
1711
+ }
1712
+ }, (b = c(this, H)) == null || b.addEventListener(
1713
+ "error",
1714
+ l,
1715
+ { once: !0 }
1716
+ );
1717
+ })
1718
+ ]);
1719
+ } catch (S) {
1720
+ if (isExitCode(S))
1721
+ return S.exitCode;
1722
+ n.controller.error(S), o.controller.error(S), t.controller.error(S), a = !0;
1723
+ for (const w in this)
1724
+ typeof this[w] == "function" && (this[w] = () => {
1725
+ throw new Error(
1726
+ "PHP runtime has crashed – see the earlier error for details."
1727
+ );
1728
+ });
1729
+ this.functionsMaybeMissingFromAsyncify = getFunctionsMaybeMissingFromAsyncify();
1730
+ const N = S, U = "betterMessage" in N ? N.betterMessage : N.message, b = new Error(U);
1731
+ throw b.cause = N, logger.error(b), b;
1732
+ } finally {
1733
+ a || (n.controller.close(), o.controller.close(), i(), a = !0), (m = c(this, H)) == null || m.removeEventListener(
1484
1734
  "error",
1485
- e
1735
+ l
1486
1736
  );
1487
- const l = this[__private__dont__use].ccall(
1488
- "wasm_sapi_handle_request",
1489
- NUMBER,
1490
- [],
1491
- [],
1492
- { async: !0 }
1493
- );
1494
- return l instanceof Promise ? l.then(o, n) : o(l);
1495
- });
1496
- } catch (o) {
1497
- for (const p in this)
1498
- typeof this[p] == "function" && (this[p] = () => {
1499
- throw new Error(
1500
- "PHP runtime has crashed – see the earlier error for details."
1501
- );
1502
- });
1503
- this.functionsMaybeMissingFromAsyncify = getFunctionsMaybeMissingFromAsyncify();
1504
- const n = o, l = "betterMessage" in n ? n.betterMessage : n.message, a = new Error(l);
1505
- throw a.cause = n, logger.error(a), a;
1506
- } finally {
1507
- (i = c(this, v)) == null || i.removeEventListener("error", e);
1508
- }
1509
- const { headers: r, httpStatusCode: s } = d(this, u, j).call(this);
1510
- return new PHPResponse(
1511
- t === 0 ? s : 500,
1512
- r,
1513
- this.readFileAsBuffer("/internal/stdout"),
1514
- this.readFileAsText("/internal/stderr"),
1515
- t
1737
+ }
1738
+ })();
1739
+ return new StreamedPHPResponse(
1740
+ t.stream,
1741
+ n.stream,
1742
+ o.stream,
1743
+ E
1516
1744
  );
1517
1745
  };
1518
- function normalizeHeaders(t) {
1746
+ function normalizeHeaders(r) {
1519
1747
  const e = {};
1520
- for (const r in t)
1521
- e[r.toLowerCase()] = t[r];
1748
+ for (const t in r)
1749
+ e[t.toLowerCase()] = r[t];
1522
1750
  return e;
1523
1751
  }
1524
- function copyFS(t, e, r) {
1752
+ function copyFS(r, e, t) {
1525
1753
  let s;
1526
1754
  try {
1527
- s = t.lookupPath(r);
1755
+ s = r.lookupPath(t);
1528
1756
  } catch {
1529
1757
  return;
1530
1758
  }
1531
1759
  if (!("contents" in s.node))
1532
1760
  return;
1533
- if (!t.isDir(s.node.mode)) {
1534
- e.writeFile(r, t.readFile(r));
1761
+ if (!r.isDir(s.node.mode)) {
1762
+ e.writeFile(t, r.readFile(t));
1535
1763
  return;
1536
1764
  }
1537
- e.mkdirTree(r);
1538
- const i = t.readdir(r).filter((o) => o !== "." && o !== "..");
1539
- for (const o of i)
1540
- copyFS(t, e, joinPaths(r, o));
1765
+ e.mkdirTree(t);
1766
+ const i = r.readdir(t).filter((n) => n !== "." && n !== "..");
1767
+ for (const n of i)
1768
+ copyFS(r, e, joinPaths(t, n));
1769
+ }
1770
+ async function createInvertedReadableStream(r = {}) {
1771
+ let e;
1772
+ const t = new Promise(
1773
+ (n) => {
1774
+ e = n;
1775
+ }
1776
+ ), s = new ReadableStream({
1777
+ ...r,
1778
+ start(n) {
1779
+ if (e(n), r.start)
1780
+ return r.start(n);
1781
+ }
1782
+ }), i = await t;
1783
+ return {
1784
+ stream: s,
1785
+ controller: i
1786
+ };
1541
1787
  }
1542
- async function getPhpIniEntries(t, e) {
1543
- const r = parse(await t.readFileAsText(PHP_INI_PATH));
1788
+ async function getPhpIniEntries(r, e) {
1789
+ const t = parse(await r.readFileAsText(PHP_INI_PATH));
1544
1790
  if (e === void 0)
1545
- return r;
1791
+ return t;
1546
1792
  const s = {};
1547
1793
  for (const i of e)
1548
- s[i] = r[i];
1794
+ s[i] = t[i];
1549
1795
  return s;
1550
1796
  }
1551
- async function setPhpIniEntries(t, e) {
1552
- const r = parse(await t.readFileAsText(PHP_INI_PATH));
1797
+ async function setPhpIniEntries(r, e) {
1798
+ const t = parse(await r.readFileAsText(PHP_INI_PATH));
1553
1799
  for (const [s, i] of Object.entries(e))
1554
- i == null ? delete r[s] : r[s] = i;
1555
- await t.writeFile(PHP_INI_PATH, stringify(r));
1800
+ i == null ? delete t[s] : t[s] = i;
1801
+ await r.writeFile(PHP_INI_PATH, stringify(t));
1556
1802
  }
1557
- async function withPHPIniValues(t, e, r) {
1558
- const s = await t.readFileAsText(PHP_INI_PATH);
1803
+ async function withPHPIniValues(r, e, t) {
1804
+ const s = await r.readFileAsText(PHP_INI_PATH);
1559
1805
  try {
1560
- return await setPhpIniEntries(t, e), await r();
1806
+ return await setPhpIniEntries(r, e), await t();
1561
1807
  } finally {
1562
- await t.writeFile(PHP_INI_PATH, s);
1808
+ await r.writeFile(PHP_INI_PATH, s);
1563
1809
  }
1564
1810
  }
1565
1811
  class HttpCookieStore {
@@ -1568,50 +1814,50 @@ class HttpCookieStore {
1568
1814
  }
1569
1815
  rememberCookiesFromResponseHeaders(e) {
1570
1816
  if (e != null && e["set-cookie"])
1571
- for (const r of e["set-cookie"])
1817
+ for (const t of e["set-cookie"])
1572
1818
  try {
1573
- if (!r.includes("="))
1819
+ if (!t.includes("="))
1574
1820
  continue;
1575
- const s = r.indexOf("="), i = r.substring(0, s), o = r.substring(s + 1).split(";")[0];
1576
- this.cookies[i] = o;
1821
+ const s = t.indexOf("="), i = t.substring(0, s), n = t.substring(s + 1).split(";")[0];
1822
+ this.cookies[i] = n;
1577
1823
  } catch (s) {
1578
1824
  logger.error(s);
1579
1825
  }
1580
1826
  }
1581
1827
  getCookieRequestHeader() {
1582
1828
  const e = [];
1583
- for (const r in this.cookies)
1584
- e.push(`${r}=${this.cookies[r]}`);
1829
+ for (const t in this.cookies)
1830
+ e.push(`${t}=${this.cookies[t]}`);
1585
1831
  return e.join("; ");
1586
1832
  }
1587
1833
  }
1588
- function streamReadFileFromPHP(t, e) {
1834
+ function streamReadFileFromPHP(r, e) {
1589
1835
  return new ReadableStream({
1590
- async pull(r) {
1591
- const s = await t.readFileAsBuffer(e);
1592
- r.enqueue(s), r.close();
1836
+ async pull(t) {
1837
+ const s = await r.readFileAsBuffer(e);
1838
+ t.enqueue(s), t.close();
1593
1839
  }
1594
1840
  });
1595
1841
  }
1596
- async function* iteratePhpFiles(t, e, {
1597
- relativePaths: r = !0,
1842
+ async function* iteratePhpFiles(r, e, {
1843
+ relativePaths: t = !0,
1598
1844
  pathPrefix: s,
1599
1845
  exceptPaths: i = []
1600
1846
  } = {}) {
1601
1847
  e = normalizePath(e);
1602
- const o = [e];
1603
- for (; o.length; ) {
1604
- const n = o.pop();
1605
- if (!n)
1848
+ const n = [e];
1849
+ for (; n.length; ) {
1850
+ const o = n.pop();
1851
+ if (!o)
1606
1852
  return;
1607
- const l = await t.listFiles(n);
1608
- for (const a of l) {
1609
- const p = `${n}/${a}`;
1853
+ const a = await r.listFiles(o);
1854
+ for (const l of a) {
1855
+ const p = `${o}/${l}`;
1610
1856
  if (i.includes(p.substring(e.length + 1)))
1611
1857
  continue;
1612
- await t.isDir(p) ? o.push(p) : yield new StreamedFile(
1613
- streamReadFileFromPHP(t, p),
1614
- r ? joinPaths(
1858
+ await r.isDir(p) ? n.push(p) : yield new StreamedFile(
1859
+ streamReadFileFromPHP(r, p),
1860
+ t ? joinPaths(
1615
1861
  s || "",
1616
1862
  p.substring(e.length + 1)
1617
1863
  ) : p
@@ -1619,13 +1865,13 @@ async function* iteratePhpFiles(t, e, {
1619
1865
  }
1620
1866
  }
1621
1867
  }
1622
- function writeFilesStreamToPhp(t, e) {
1868
+ function writeFilesStreamToPhp(r, e) {
1623
1869
  return new WritableStream({
1624
- async write(r) {
1625
- const s = joinPaths(e, r.name);
1626
- r.type === "directory" ? await t.mkdir(s) : (await t.mkdir(dirname(s)), await t.writeFile(
1870
+ async write(t) {
1871
+ const s = joinPaths(e, t.name);
1872
+ t.type === "directory" ? await r.mkdir(s) : (await r.mkdir(dirname(s)), await r.writeFile(
1627
1873
  s,
1628
- new Uint8Array(await r.arrayBuffer())
1874
+ new Uint8Array(await t.arrayBuffer())
1629
1875
  ));
1630
1876
  }
1631
1877
  });
@@ -1661,11 +1907,7 @@ class PHPProcessManager {
1661
1907
  throw new Error(
1662
1908
  "phpFactory or primaryPhp must be set before calling getPrimaryPhp()."
1663
1909
  );
1664
- if (!this.primaryPhp) {
1665
- const e = await this.spawn({ isPrimary: !0 });
1666
- this.primaryPhp = e.php;
1667
- }
1668
- return this.primaryPhp;
1910
+ return this.primaryPhp || (this.primaryPhpPromise || (this.primaryPhpPromise = this.spawn({ isPrimary: !0 })), this.primaryPhp = (await this.primaryPhpPromise).php, this.primaryPhpPromise = void 0), this.primaryPhp;
1669
1911
  }
1670
1912
  /**
1671
1913
  * Get a PHP instance.
@@ -1674,17 +1916,32 @@ class PHPProcessManager {
1674
1916
  * instance, or a newly spawned PHP instance – depending on the resource
1675
1917
  * availability.
1676
1918
  *
1919
+ * @param considerPrimary - Whether to consider the primary PHP instance.
1920
+ * It matters because PHP.cli() sets the SAPI to CLI and
1921
+ * kills the entire process after it finishes running,
1922
+ * making the primary PHP instance non-reusable for
1923
+ * subsequent .run() calls. This is fine for one-off
1924
+ * child PHP instances, but not for the primary PHP
1925
+ * that's meant to continue working for the entire duration
1926
+ * of the ProcessManager lifetime. Therefore, we don't
1927
+ * consider the primary PHP instance by default unless
1928
+ * the caller explicitly requests it.
1929
+ *
1677
1930
  * @throws {MaxPhpInstancesError} when the maximum number of PHP instances is reached
1678
1931
  * and the waiting timeout is exceeded.
1679
1932
  */
1680
- async acquirePHPInstance() {
1681
- if (this.primaryIdle)
1933
+ async acquirePHPInstance({
1934
+ considerPrimary: e = !0
1935
+ } = {}) {
1936
+ if (this.primaryPhp || await this.getPrimaryPhp(), this.primaryIdle && e)
1682
1937
  return this.primaryIdle = !1, {
1683
1938
  php: await this.getPrimaryPhp(),
1684
- reap: () => this.primaryIdle = !0
1939
+ reap: () => {
1940
+ this.primaryIdle = !0;
1941
+ }
1685
1942
  };
1686
- const e = this.nextInstance || this.spawn({ isPrimary: !1 });
1687
- return this.semaphore.remaining > 0 ? this.nextInstance = this.spawn({ isPrimary: !1 }) : this.nextInstance = null, await e;
1943
+ const t = this.nextInstance || this.spawn({ isPrimary: !1 });
1944
+ return this.semaphore.remaining > 0 ? this.nextInstance = this.spawn({ isPrimary: !1 }) : this.nextInstance = null, await t;
1688
1945
  }
1689
1946
  /**
1690
1947
  * Initiated spawning of a new PHP instance.
@@ -1693,18 +1950,18 @@ class PHPProcessManager {
1693
1950
  * for PHP to spawn.
1694
1951
  */
1695
1952
  spawn(e) {
1696
- if (e.isPrimary && this.allInstances.length > 0)
1953
+ if (e.isPrimary && this.primaryPhpPromise && !this.primaryPhp)
1697
1954
  throw new Error(
1698
1955
  "Requested spawning a primary PHP instance when another primary instance already started spawning."
1699
1956
  );
1700
- const r = this.doSpawn(e);
1701
- this.allInstances.push(r);
1957
+ const t = this.doSpawn(e);
1958
+ this.allInstances.push(t);
1702
1959
  const s = () => {
1703
1960
  this.allInstances = this.allInstances.filter(
1704
- (i) => i !== r
1961
+ (i) => i !== t
1705
1962
  );
1706
1963
  };
1707
- return r.catch((i) => {
1964
+ return t.catch((i) => {
1708
1965
  throw s(), i;
1709
1966
  }).then((i) => ({
1710
1967
  ...i,
@@ -1717,9 +1974,9 @@ class PHPProcessManager {
1717
1974
  * Actually acquires the lock and spawns a new PHP instance.
1718
1975
  */
1719
1976
  async doSpawn(e) {
1720
- let r;
1977
+ let t;
1721
1978
  try {
1722
- r = await this.semaphore.acquire();
1979
+ t = await this.semaphore.acquire();
1723
1980
  } catch (s) {
1724
1981
  throw s instanceof AcquireTimeoutError ? new MaxPhpInstancesError(this.maxPhpInstances) : s;
1725
1982
  }
@@ -1728,17 +1985,17 @@ class PHPProcessManager {
1728
1985
  return {
1729
1986
  php: s,
1730
1987
  reap() {
1731
- s.exit(), r();
1988
+ s.exit(), t();
1732
1989
  }
1733
1990
  };
1734
1991
  } catch (s) {
1735
- throw r(), s;
1992
+ throw t(), s;
1736
1993
  }
1737
1994
  }
1738
1995
  async [Symbol.asyncDispose]() {
1739
1996
  this.primaryPhp && this.primaryPhp.exit(), await Promise.all(
1740
1997
  this.allInstances.map(
1741
- (e) => e.then(({ reap: r }) => r())
1998
+ (e) => e.then(({ reap: t }) => t())
1742
1999
  )
1743
2000
  );
1744
2001
  }
@@ -1753,37 +2010,37 @@ const SupportedPHPVersions = [
1753
2010
  "7.3",
1754
2011
  "7.2"
1755
2012
  ], LatestSupportedPHPVersion = SupportedPHPVersions[0], SupportedPHPVersionsList = SupportedPHPVersions, DEFAULT_BASE_URL = "http://example.com";
1756
- function toRelativeUrl(t) {
1757
- return t.toString().substring(t.origin.length);
2013
+ function toRelativeUrl(r) {
2014
+ return r.toString().substring(r.origin.length);
1758
2015
  }
1759
- function removePathPrefix(t, e) {
1760
- return !e || !t.startsWith(e) ? t : t.substring(e.length);
2016
+ function removePathPrefix(r, e) {
2017
+ return !e || !r.startsWith(e) ? r : r.substring(e.length);
1761
2018
  }
1762
- function ensurePathPrefix(t, e) {
1763
- return !e || t.startsWith(e) ? t : e + t;
2019
+ function ensurePathPrefix(r, e) {
2020
+ return !e || r.startsWith(e) ? r : e + r;
1764
2021
  }
1765
- async function encodeAsMultipart(t) {
1766
- const e = `----${Math.random().toString(36).slice(2)}`, r = `multipart/form-data; boundary=${e}`, s = new TextEncoder(), i = [];
1767
- for (const [a, p] of Object.entries(t))
2022
+ async function encodeAsMultipart(r) {
2023
+ const e = `----${Math.random().toString(36).slice(2)}`, t = `multipart/form-data; boundary=${e}`, s = new TextEncoder(), i = [];
2024
+ for (const [l, p] of Object.entries(r))
1768
2025
  i.push(`--${e}\r
1769
- `), i.push(`Content-Disposition: form-data; name="${a}"`), p instanceof File && i.push(`; filename="${p.name}"`), i.push(`\r
2026
+ `), i.push(`Content-Disposition: form-data; name="${l}"`), p instanceof File && i.push(`; filename="${p.name}"`), i.push(`\r
1770
2027
  `), p instanceof File && (i.push("Content-Type: application/octet-stream"), i.push(`\r
1771
2028
  `)), i.push(`\r
1772
2029
  `), p instanceof File ? i.push(await fileToUint8Array(p)) : i.push(p), i.push(`\r
1773
2030
  `);
1774
2031
  i.push(`--${e}--\r
1775
2032
  `);
1776
- const o = i.reduce((a, p) => a + p.length, 0), n = new Uint8Array(o);
1777
- let l = 0;
1778
- for (const a of i)
1779
- n.set(
1780
- typeof a == "string" ? s.encode(a) : a,
1781
- l
1782
- ), l += a.length;
1783
- return { bytes: n, contentType: r };
2033
+ const n = i.reduce((l, p) => l + p.length, 0), o = new Uint8Array(n);
2034
+ let a = 0;
2035
+ for (const l of i)
2036
+ o.set(
2037
+ typeof l == "string" ? s.encode(l) : l,
2038
+ a
2039
+ ), a += l.length;
2040
+ return { bytes: o, contentType: t };
1784
2041
  }
1785
- function fileToUint8Array(t) {
1786
- return t.arrayBuffer().then((e) => new Uint8Array(e));
2042
+ function fileToUint8Array(r) {
2043
+ return r.arrayBuffer().then((e) => new Uint8Array(e));
1787
2044
  }
1788
2045
  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 = {
1789
2046
  _default,
@@ -1881,7 +2138,7 @@ const _default = "application/octet-stream", asx = "video/x-ms-asf", atom = "app
1881
2138
  xspf,
1882
2139
  zip
1883
2140
  };
1884
- var g, S, k, E, H, f, b, y, w, V, J, Y;
2141
+ var g, C, M, F, I, y, A, v, x, Z, ee, te;
1885
2142
  class PHPRequestHandler {
1886
2143
  /**
1887
2144
  * The request handler needs to decide whether to serve a static asset or
@@ -1895,42 +2152,42 @@ class PHPRequestHandler {
1895
2152
  * @param config - Request Handler configuration.
1896
2153
  */
1897
2154
  constructor(e) {
1898
- h(this, w);
2155
+ h(this, x);
1899
2156
  h(this, g);
1900
- h(this, S);
1901
- h(this, k);
1902
- h(this, E);
1903
- h(this, H);
1904
- h(this, f);
1905
- h(this, b);
2157
+ h(this, C);
2158
+ h(this, M);
2159
+ h(this, F);
2160
+ h(this, I);
1906
2161
  h(this, y);
2162
+ h(this, A);
2163
+ h(this, v);
1907
2164
  const {
1908
- documentRoot: r = "/www/",
2165
+ documentRoot: t = "/www/",
1909
2166
  absoluteUrl: s = typeof location == "object" ? location.href : DEFAULT_BASE_URL,
1910
2167
  rewriteRules: i = [],
1911
- getFileNotFoundAction: o = () => ({ type: "404" })
2168
+ getFileNotFoundAction: n = () => ({ type: "404" })
1912
2169
  } = e;
1913
2170
  "processManager" in e ? this.processManager = e.processManager : this.processManager = new PHPProcessManager({
1914
- phpFactory: async (a) => {
2171
+ phpFactory: async (l) => {
1915
2172
  const p = await e.phpFactory({
1916
- ...a,
2173
+ ...l,
1917
2174
  requestHandler: this
1918
2175
  });
1919
- return p.requestHandler = this, p;
2176
+ return p.isDir(t) || p.mkdir(t), p.chdir(t), p.requestHandler = this, p;
1920
2177
  },
1921
2178
  maxPhpInstances: e.maxPhpInstances
1922
- }), m(this, y, e.cookieStore === void 0 ? new HttpCookieStore() : e.cookieStore), m(this, g, r);
1923
- const n = new URL(s);
1924
- m(this, k, n.hostname), m(this, E, n.port ? Number(n.port) : n.protocol === "https:" ? 443 : 80), m(this, S, (n.protocol || "").replace(":", ""));
1925
- const l = c(this, E) !== 443 && c(this, E) !== 80;
1926
- m(this, H, [
1927
- c(this, k),
1928
- l ? `:${c(this, E)}` : ""
1929
- ].join("")), m(this, f, n.pathname.replace(/\/+$/, "")), m(this, b, [
1930
- `${c(this, S)}://`,
1931
- c(this, H),
1932
- c(this, f)
1933
- ].join("")), this.rewriteRules = i, this.getFileNotFoundAction = o;
2179
+ }), f(this, v, e.cookieStore === void 0 ? new HttpCookieStore() : e.cookieStore), f(this, g, t);
2180
+ const o = new URL(s);
2181
+ f(this, M, o.hostname), f(this, F, o.port ? Number(o.port) : o.protocol === "https:" ? 443 : 80), f(this, C, (o.protocol || "").replace(":", ""));
2182
+ const a = c(this, F) !== 443 && c(this, F) !== 80;
2183
+ f(this, I, [
2184
+ c(this, M),
2185
+ a ? `:${c(this, F)}` : ""
2186
+ ].join("")), f(this, y, o.pathname.replace(/\/+$/, "")), f(this, A, [
2187
+ `${c(this, C)}://`,
2188
+ c(this, I),
2189
+ c(this, y)
2190
+ ].join("")), this.rewriteRules = i, this.getFileNotFoundAction = n;
1934
2191
  }
1935
2192
  async getPrimaryPhp() {
1936
2193
  return await this.processManager.getPrimaryPhp();
@@ -1953,14 +2210,14 @@ class PHPRequestHandler {
1953
2210
  * @returns The relative path.
1954
2211
  */
1955
2212
  internalUrlToPath(e) {
1956
- const r = new URL(e);
1957
- return r.pathname.startsWith(c(this, f)) && (r.pathname = r.pathname.slice(c(this, f).length)), toRelativeUrl(r);
2213
+ const t = new URL(e);
2214
+ return t.pathname.startsWith(c(this, y)) && (t.pathname = t.pathname.slice(c(this, y).length)), toRelativeUrl(t);
1958
2215
  }
1959
2216
  /**
1960
2217
  * The absolute URL of this PHPRequestHandler instance.
1961
2218
  */
1962
2219
  get absoluteUrl() {
1963
- return c(this, b);
2220
+ return c(this, A);
1964
2221
  }
1965
2222
  /**
1966
2223
  * The directory in the PHP filesystem where the server will look
@@ -2018,73 +2275,76 @@ class PHPRequestHandler {
2018
2275
  * @param request - PHP Request data.
2019
2276
  */
2020
2277
  async request(e) {
2021
- const r = URL.canParse(e.url), s = new URL(
2278
+ const t = URL.canParse(e.url), s = new URL(
2022
2279
  // Remove the hash part of the URL as it's not meant for the server.
2023
2280
  e.url.split("#")[0],
2024
- r ? void 0 : DEFAULT_BASE_URL
2281
+ t ? void 0 : DEFAULT_BASE_URL
2025
2282
  ), i = applyRewriteRules(
2026
2283
  removePathPrefix(
2027
2284
  decodeURIComponent(s.pathname),
2028
- c(this, f)
2285
+ c(this, y)
2029
2286
  ),
2030
2287
  this.rewriteRules
2031
- ), o = await this.getPrimaryPhp();
2032
- let n = joinPaths(c(this, g), i);
2033
- if (o.isDir(n)) {
2034
- if (!n.endsWith("/"))
2288
+ ), n = await this.getPrimaryPhp();
2289
+ let o = joinPaths(c(this, g), i);
2290
+ if (n.isDir(o)) {
2291
+ if (!o.endsWith("/"))
2035
2292
  return new PHPResponse(
2036
2293
  301,
2037
2294
  { Location: [`${s.pathname}/`] },
2038
2295
  new Uint8Array(0)
2039
2296
  );
2040
- for (const l of ["index.php", "index.html"]) {
2041
- const a = joinPaths(n, l);
2042
- if (o.isFile(a)) {
2043
- n = a;
2297
+ for (const a of ["index.php", "index.html"]) {
2298
+ const l = joinPaths(o, a);
2299
+ if (n.isFile(l)) {
2300
+ o = l;
2044
2301
  break;
2045
2302
  }
2046
2303
  }
2047
2304
  }
2048
- if (!o.isFile(n)) {
2049
- const l = this.getFileNotFoundAction(
2305
+ if (!n.isFile(o)) {
2306
+ const a = this.getFileNotFoundAction(
2050
2307
  i
2051
2308
  );
2052
- switch (l.type) {
2309
+ switch (a.type) {
2053
2310
  case "response":
2054
- return l.response;
2311
+ return a.response;
2055
2312
  case "internal-redirect":
2056
- n = joinPaths(c(this, g), l.uri);
2313
+ o = joinPaths(c(this, g), a.uri);
2057
2314
  break;
2058
2315
  case "404":
2059
2316
  return PHPResponse.forHttpCode(404);
2060
2317
  default:
2061
2318
  throw new Error(
2062
- `Unsupported file-not-found action type: '${l.type}'`
2319
+ `Unsupported file-not-found action type: '${a.type}'`
2063
2320
  );
2064
2321
  }
2065
2322
  }
2066
- if (o.isFile(n))
2067
- if (n.endsWith(".php")) {
2068
- const l = {
2323
+ if (n.isFile(o))
2324
+ if (o.endsWith(".php")) {
2325
+ const a = {
2069
2326
  ...e,
2070
2327
  // Pass along URL with the #fragment filtered out
2071
2328
  url: s.toString()
2072
2329
  };
2073
- return d(this, w, J).call(this, l, n);
2330
+ return d(this, x, ee).call(this, a, o);
2074
2331
  } else
2075
- return d(this, w, V).call(this, o, n);
2332
+ return d(this, x, Z).call(this, n, o);
2076
2333
  else
2077
2334
  return PHPResponse.forHttpCode(404);
2078
2335
  }
2336
+ async [Symbol.asyncDispose]() {
2337
+ await this.processManager[Symbol.asyncDispose]();
2338
+ }
2079
2339
  }
2080
- g = new WeakMap(), S = new WeakMap(), k = new WeakMap(), E = new WeakMap(), H = new WeakMap(), f = new WeakMap(), b = new WeakMap(), y = new WeakMap(), w = new WeakSet(), /**
2340
+ g = new WeakMap(), C = new WeakMap(), M = new WeakMap(), F = new WeakMap(), I = new WeakMap(), y = new WeakMap(), A = new WeakMap(), v = new WeakMap(), x = new WeakSet(), /**
2081
2341
  * Serves a static file from the PHP filesystem.
2082
2342
  *
2083
2343
  * @param fsPath - Absolute path of the static file to serve.
2084
2344
  * @returns The response.
2085
2345
  */
2086
- V = function(e, r) {
2087
- const s = e.readFileAsBuffer(r);
2346
+ Z = function(e, t) {
2347
+ const s = e.readFileAsBuffer(t);
2088
2348
  return new PHPResponse(
2089
2349
  200,
2090
2350
  {
@@ -2092,78 +2352,80 @@ V = function(e, r) {
2092
2352
  // @TODO: Infer the content-type from the arrayBuffer instead of the
2093
2353
  // file path. The code below won't return the correct mime-type if the
2094
2354
  // extension was tampered with.
2095
- "content-type": [inferMimeType(r)],
2355
+ "content-type": [inferMimeType(t)],
2096
2356
  "accept-ranges": ["bytes"],
2097
2357
  "cache-control": ["public, max-age=0"]
2098
2358
  },
2099
2359
  s
2100
2360
  );
2101
- }, J = async function(e, r) {
2361
+ }, ee = async function(e, t) {
2102
2362
  let s;
2103
2363
  try {
2104
- s = await this.processManager.acquirePHPInstance();
2364
+ s = await this.processManager.acquirePHPInstance({
2365
+ considerPrimary: !0
2366
+ });
2105
2367
  } catch (i) {
2106
2368
  return i instanceof MaxPhpInstancesError ? PHPResponse.forHttpCode(502) : PHPResponse.forHttpCode(500);
2107
2369
  }
2108
2370
  try {
2109
- return await d(this, w, Y).call(this, s.php, e, r);
2371
+ return await d(this, x, te).call(this, s.php, e, t);
2110
2372
  } finally {
2111
2373
  s.reap();
2112
2374
  }
2113
- }, Y = async function(e, r, s) {
2375
+ }, te = async function(e, t, s) {
2114
2376
  let i = "GET";
2115
- const o = {
2116
- host: c(this, H),
2117
- ...normalizeHeaders(r.headers || {})
2377
+ const n = {
2378
+ host: c(this, I),
2379
+ ...normalizeHeaders(t.headers || {})
2118
2380
  };
2119
- c(this, y) && (o.cookie = c(this, y).getCookieRequestHeader());
2120
- let n = r.body;
2121
- if (typeof n == "object" && !(n instanceof Uint8Array)) {
2381
+ c(this, v) && (n.cookie = c(this, v).getCookieRequestHeader());
2382
+ let o = t.body;
2383
+ if (typeof o == "object" && !(o instanceof Uint8Array)) {
2122
2384
  i = "POST";
2123
- const { bytes: l, contentType: a } = await encodeAsMultipart(n);
2124
- n = l, o["content-type"] = a;
2385
+ const { bytes: a, contentType: l } = await encodeAsMultipart(o);
2386
+ o = a, n["content-type"] = l;
2125
2387
  }
2126
2388
  try {
2127
- const l = await e.run({
2389
+ const a = await e.run({
2128
2390
  relativeUri: ensurePathPrefix(
2129
- toRelativeUrl(new URL(r.url)),
2130
- c(this, f)
2391
+ toRelativeUrl(new URL(t.url)),
2392
+ c(this, y)
2131
2393
  ),
2132
- protocol: c(this, S),
2133
- method: r.method || i,
2394
+ protocol: c(this, C),
2395
+ method: t.method || i,
2134
2396
  $_SERVER: {
2135
2397
  REMOTE_ADDR: "127.0.0.1",
2136
2398
  DOCUMENT_ROOT: c(this, g),
2137
- HTTPS: c(this, b).startsWith("https://") ? "on" : ""
2399
+ HTTPS: c(this, A).startsWith("https://") ? "on" : ""
2138
2400
  },
2139
- body: n,
2401
+ body: o,
2140
2402
  scriptPath: s,
2141
- headers: o
2403
+ headers: n
2142
2404
  });
2143
- return c(this, y) && c(this, y).rememberCookiesFromResponseHeaders(
2144
- l.headers
2145
- ), l;
2146
- } catch (l) {
2147
- const a = l;
2148
- if (a != null && a.response)
2149
- return a.response;
2150
- throw l;
2405
+ return c(this, v) && c(this, v).rememberCookiesFromResponseHeaders(
2406
+ a.headers
2407
+ ), a;
2408
+ } catch (a) {
2409
+ const l = a;
2410
+ if (l != null && l.response)
2411
+ return l.response;
2412
+ throw a;
2151
2413
  }
2152
2414
  };
2153
- function inferMimeType(t) {
2154
- const e = t.split(".").pop();
2415
+ function inferMimeType(r) {
2416
+ const e = r.split(".").pop();
2155
2417
  return mimeTypes[e] || mimeTypes._default;
2156
2418
  }
2157
- function applyRewriteRules(t, e) {
2158
- for (const r of e)
2159
- if (new RegExp(r.match).test(t))
2160
- return t.replace(r.match, r.replacement);
2161
- return t;
2419
+ function applyRewriteRules(r, e) {
2420
+ for (const t of e)
2421
+ if (new RegExp(t.match).test(r))
2422
+ return r.replace(t.match, t.replacement);
2423
+ return r;
2162
2424
  }
2163
2425
  function rotatePHPRuntime({
2164
- php: t,
2426
+ php: r,
2165
2427
  cwd: e,
2166
- recreateRuntime: r,
2428
+ recreateRuntime: t,
2167
2429
  /*
2168
2430
  * 400 is an arbitrary number that should trigger a rotation
2169
2431
  * way before the memory gets too fragmented. If it doesn't,
@@ -2175,64 +2437,180 @@ function rotatePHPRuntime({
2175
2437
  maxRequests: s = 400
2176
2438
  }) {
2177
2439
  let i = 0;
2178
- async function o() {
2179
- const a = await t.semaphore.acquire();
2440
+ async function n() {
2441
+ const l = await r.semaphore.acquire();
2180
2442
  try {
2181
- await t.hotSwapPHPRuntime(await r(), e), i = 0;
2443
+ await r.hotSwapPHPRuntime(await t(), e), i = 0;
2182
2444
  } finally {
2183
- a();
2445
+ l();
2184
2446
  }
2185
2447
  }
2186
- async function n() {
2187
- ++i < s || await o();
2448
+ async function o() {
2449
+ ++i < s || await n();
2188
2450
  }
2189
- async function l(a) {
2190
- a.type === "request.error" && a.source === "php-wasm" && await o();
2451
+ async function a(l) {
2452
+ l.type === "request.error" && l.source === "php-wasm" && await n();
2191
2453
  }
2192
- return t.addEventListener("request.error", l), t.addEventListener("request.end", n), function() {
2193
- t.removeEventListener("request.error", l), t.removeEventListener("request.end", n);
2454
+ return r.addEventListener("request.error", a), r.addEventListener("request.end", o), function() {
2455
+ r.removeEventListener("request.error", a), r.removeEventListener("request.end", o);
2194
2456
  };
2195
2457
  }
2196
- async function writeFiles(t, e, r, { rmRoot: s = !1 } = {}) {
2197
- s && await t.isDir(e) && await t.rmdir(e, { recursive: !0 });
2198
- for (const [i, o] of Object.entries(r)) {
2199
- const n = joinPaths(e, i);
2200
- await t.fileExists(dirname(n)) || await t.mkdir(dirname(n)), o instanceof Uint8Array || typeof o == "string" ? await t.writeFile(n, o) : await writeFiles(t, n, o);
2458
+ async function writeFiles(r, e, t, { rmRoot: s = !1 } = {}) {
2459
+ s && await r.isDir(e) && await r.rmdir(e, { recursive: !0 });
2460
+ for (const [i, n] of Object.entries(t)) {
2461
+ const o = joinPaths(e, i);
2462
+ await r.fileExists(dirname(o)) || await r.mkdir(dirname(o)), n instanceof Uint8Array || typeof n == "string" ? await r.writeFile(o, n) : await writeFiles(r, o, n);
2201
2463
  }
2202
2464
  }
2203
- function proxyFileSystem(t, e, r) {
2204
- const s = Object.getOwnPropertySymbols(t)[0];
2205
- for (const i of r)
2206
- e.fileExists(i) || e.mkdir(i), t.fileExists(i) || t.mkdir(i), e[s].FS.mount(
2465
+ function proxyFileSystem(r, e, t) {
2466
+ const s = Object.getOwnPropertySymbols(r)[0];
2467
+ for (const i of t)
2468
+ e.fileExists(i) || e.mkdir(i), r.fileExists(i) || r.mkdir(i), e[s].FS.mount(
2207
2469
  // @ts-ignore
2208
2470
  e[s].PROXYFS,
2209
2471
  {
2210
2472
  root: i,
2211
2473
  // @ts-ignore
2212
- fs: t[s].FS
2474
+ fs: r[s].FS
2213
2475
  },
2214
2476
  i
2215
2477
  );
2216
2478
  }
2479
+ /**
2480
+ * @license
2481
+ * Copyright 2019 Google LLC
2482
+ * SPDX-License-Identifier: Apache-2.0
2483
+ */
2484
+ function nodeEndpoint(r) {
2485
+ const e = /* @__PURE__ */ new WeakMap();
2486
+ return {
2487
+ postMessage: r.postMessage.bind(r),
2488
+ addEventListener: (t, s) => {
2489
+ const i = (n) => {
2490
+ "handleEvent" in s ? s.handleEvent({ data: n }) : s({ data: n });
2491
+ };
2492
+ r.on("message", i), e.set(s, i);
2493
+ },
2494
+ removeEventListener: (t, s) => {
2495
+ const i = e.get(s);
2496
+ i && (r.off("message", i), e.delete(s));
2497
+ },
2498
+ start: r.start && r.start.bind(r)
2499
+ };
2500
+ }
2501
+ function consumeAPI(r, e = void 0) {
2502
+ setupTransferHandlers();
2503
+ let t;
2504
+ import.meta.url.startsWith("file://") ? t = nodeEndpoint(r) : t = r instanceof Worker ? r : Comlink.windowEndpoint(r, e);
2505
+ const i = Comlink.wrap(t), n = proxyClone(i);
2506
+ return new Proxy(n, {
2507
+ get: (o, a) => a === "isConnected" ? async () => {
2508
+ for (; ; )
2509
+ try {
2510
+ await runWithTimeout(i.isConnected(), 200);
2511
+ break;
2512
+ } catch {
2513
+ }
2514
+ } : i[a]
2515
+ });
2516
+ }
2517
+ async function runWithTimeout(r, e) {
2518
+ return new Promise((t, s) => {
2519
+ setTimeout(s, e), r.then(t);
2520
+ });
2521
+ }
2522
+ function exposeAPI(r, e, t) {
2523
+ setupTransferHandlers();
2524
+ const s = Promise.resolve();
2525
+ let i, n;
2526
+ const o = new Promise((E, m) => {
2527
+ i = E, n = m;
2528
+ }), a = proxyClone(r), l = new Proxy(a, {
2529
+ get: (E, m) => m === "isConnected" ? () => s : m === "isReady" ? () => o : m in E ? E[m] : e == null ? void 0 : e[m]
2530
+ });
2531
+ let p;
2532
+ return t ? p = nodeEndpoint(t) : p = typeof window < "u" ? Comlink.windowEndpoint(self.parent) : void 0, Comlink.expose(l, p), [i, n, l];
2533
+ }
2534
+ let isTransferHandlersSetup = !1;
2535
+ function setupTransferHandlers() {
2536
+ if (isTransferHandlersSetup)
2537
+ return;
2538
+ isTransferHandlersSetup = !0, Comlink.transferHandlers.set("EVENT", {
2539
+ canHandle: (t) => t instanceof CustomEvent,
2540
+ serialize: (t) => [
2541
+ {
2542
+ detail: t.detail
2543
+ },
2544
+ []
2545
+ ],
2546
+ deserialize: (t) => t
2547
+ }), Comlink.transferHandlers.set("FUNCTION", {
2548
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
2549
+ canHandle: (t) => typeof t == "function",
2550
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
2551
+ serialize(t) {
2552
+ const { port1: s, port2: i } = new MessageChannel();
2553
+ return Comlink.expose(t, s), [i, [i]];
2554
+ },
2555
+ deserialize(t) {
2556
+ return t.start(), Comlink.wrap(t);
2557
+ }
2558
+ }), Comlink.transferHandlers.set("PHPResponse", {
2559
+ canHandle: (t) => typeof t == "object" && t !== null && "headers" in t && "bytes" in t && "errors" in t && "exitCode" in t && "httpStatusCode" in t,
2560
+ serialize(t) {
2561
+ return [t.toRawData(), []];
2562
+ },
2563
+ deserialize(t) {
2564
+ return PHPResponse.fromRawData(t);
2565
+ }
2566
+ });
2567
+ const r = Comlink.transferHandlers.get("throw"), e = r == null ? void 0 : r.serialize;
2568
+ r.serialize = ({ value: t }) => {
2569
+ const s = e({ value: t });
2570
+ return t.response && (s[0].value.response = t.response), t.source && (s[0].value.source = t.source), s;
2571
+ };
2572
+ }
2573
+ function proxyClone(r) {
2574
+ return new Proxy(r, {
2575
+ get(e, t) {
2576
+ switch (typeof e[t]) {
2577
+ case "function":
2578
+ return (...s) => e[t](...s);
2579
+ case "object":
2580
+ return e[t] === null ? e[t] : proxyClone(e[t]);
2581
+ case "undefined":
2582
+ case "number":
2583
+ case "string":
2584
+ return e[t];
2585
+ default:
2586
+ return Comlink.proxy(e[t]);
2587
+ }
2588
+ }
2589
+ });
2590
+ }
2217
2591
  export {
2218
2592
  DEFAULT_BASE_URL,
2219
2593
  FSHelpers,
2220
2594
  HttpCookieStore,
2221
2595
  LatestSupportedPHPVersion,
2222
2596
  PHP,
2597
+ PHPExecutionFailureError,
2223
2598
  PHPProcessManager,
2224
2599
  PHPRequestHandler,
2225
2600
  PHPResponse,
2226
2601
  PHPWorker,
2602
+ StreamedPHPResponse,
2227
2603
  SupportedPHPVersions,
2228
2604
  SupportedPHPVersionsList,
2229
2605
  UnhandledRejectionsTarget,
2230
2606
  __private__dont__use,
2231
2607
  applyRewriteRules,
2608
+ consumeAPI,
2232
2609
  ensurePathPrefix,
2610
+ exposeAPI,
2233
2611
  getLoadedRuntime,
2234
2612
  getPhpIniEntries,
2235
- isExitCodeZero,
2613
+ isExitCode,
2236
2614
  iteratePhpFiles as iterateFiles,
2237
2615
  loadPHPRuntime,
2238
2616
  proxyFileSystem,