@php-wasm/universal 0.6.15 → 0.7.0

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,13 @@
1
- var J = (e, t, r) => {
1
+ var Q = (e, t, r) => {
2
2
  if (!t.has(e))
3
3
  throw TypeError("Cannot " + r);
4
4
  };
5
- var l = (e, t, r) => (J(e, t, "read from private field"), r ? r.call(e) : t.get(e)), u = (e, t, r) => {
5
+ var c = (e, t, r) => (Q(e, t, "read from private field"), r ? r.call(e) : t.get(e)), d = (e, t, r) => {
6
6
  if (t.has(e))
7
7
  throw TypeError("Cannot add the same private member more than once");
8
8
  t instanceof WeakSet ? t.add(e) : t.set(e, r);
9
- }, h = (e, t, r, s) => (J(e, t, "write to private field"), s ? s.call(e, r) : t.set(e, r), r);
10
- var f = (e, t, r) => (J(e, t, "access private method"), r);
9
+ }, h = (e, t, r, s) => (Q(e, t, "write to private field"), s ? s.call(e, r) : t.set(e, r), r);
10
+ var p = (e, t, r) => (Q(e, t, "access private method"), r);
11
11
  const currentJsRuntime$1 = function() {
12
12
  var e;
13
13
  return typeof process < "u" && ((e = process.release) == null ? void 0 : e.name) === "node" ? "NODE" : typeof window < "u" ? "WEB" : (
@@ -59,10 +59,10 @@ if (currentJsRuntime$1 === "NODE") {
59
59
  const o = n.byobRequest.view, a = await s.slice(
60
60
  r,
61
61
  r + o.byteLength
62
- ).arrayBuffer(), c = new Uint8Array(a);
63
- new Uint8Array(o.buffer).set(c);
64
- const d = c.byteLength;
65
- n.byobRequest.respond(d), r += d, r >= s.size && n.close();
62
+ ).arrayBuffer(), u = new Uint8Array(a);
63
+ new Uint8Array(o.buffer).set(u);
64
+ const l = u.byteLength;
65
+ n.byobRequest.respond(l), r += l, r >= s.size && n.close();
66
66
  }
67
67
  });
68
68
  });
@@ -226,18 +226,40 @@ function extractPHPFunctionsFromStack(e) {
226
226
  return [];
227
227
  }
228
228
  }
229
+ const SleepFinished = Symbol("SleepFinished");
230
+ function sleep(e) {
231
+ return new Promise((t) => {
232
+ setTimeout(() => t(SleepFinished), e);
233
+ });
234
+ }
235
+ class AcquireTimeoutError extends Error {
236
+ constructor() {
237
+ super("Acquiring lock timed out");
238
+ }
239
+ }
229
240
  class Semaphore {
230
- constructor({ concurrency: t }) {
231
- this._running = 0, this.concurrency = t, this.queue = [];
241
+ constructor({ concurrency: t, timeout: r }) {
242
+ this._running = 0, this.concurrency = t, this.timeout = r, this.queue = [];
243
+ }
244
+ get remaining() {
245
+ return this.concurrency - this.running;
232
246
  }
233
247
  get running() {
234
248
  return this._running;
235
249
  }
236
250
  async acquire() {
237
251
  for (; ; )
238
- if (this._running >= this.concurrency)
239
- await new Promise((t) => this.queue.push(t));
240
- else {
252
+ if (this._running >= this.concurrency) {
253
+ const t = new Promise((r) => {
254
+ this.queue.push(r);
255
+ });
256
+ this.timeout !== void 0 ? await Promise.race([t, sleep(this.timeout)]).then(
257
+ (r) => {
258
+ if (r === SleepFinished)
259
+ throw new AcquireTimeoutError();
260
+ }
261
+ ) : await t;
262
+ } else {
241
263
  this._running++;
242
264
  let t = !1;
243
265
  return () => {
@@ -289,8 +311,8 @@ function splitShellCommand(e) {
289
311
  const o = [];
290
312
  let i = "";
291
313
  for (let a = 0; a < e.length; a++) {
292
- const c = e[a];
293
- c === "\\" ? ((e[a + 1] === '"' || e[a + 1] === "'") && a++, i += e[a]) : s === 0 ? c === '"' || c === "'" ? (s = 1, n = c) : c.match(/\s/) ? (i.trim().length && o.push(i.trim()), i = c) : o.length && !i ? i = o.pop() + c : i += c : s === 1 && (c === n ? (s = 0, n = "") : i += c);
314
+ const u = e[a];
315
+ u === "\\" ? ((e[a + 1] === '"' || e[a + 1] === "'") && a++, i += e[a]) : s === 0 ? u === '"' || u === "'" ? (s = 1, n = u) : u.match(/\s/) ? (i.trim().length && o.push(i.trim()), i = u) : o.length && !i ? i = o.pop() + u : i += u : s === 1 && (u === n ? (s = 0, n = "") : i += u);
294
316
  }
295
317
  return i && o.push(i.trim()), o;
296
318
  }
@@ -503,16 +525,16 @@ async function* iteratePhpFiles(e, t, {
503
525
  if (!i)
504
526
  return;
505
527
  const a = await e.listFiles(i);
506
- for (const c of a) {
507
- const d = `${i}/${c}`;
508
- if (n.includes(d.substring(t.length + 1)))
528
+ for (const u of a) {
529
+ const l = `${i}/${u}`;
530
+ if (n.includes(l.substring(t.length + 1)))
509
531
  continue;
510
- await e.isDir(d) ? o.push(d) : yield new StreamedFile(
511
- streamReadFileFromPHP(e, d),
532
+ await e.isDir(l) ? o.push(l) : yield new StreamedFile(
533
+ streamReadFileFromPHP(e, l),
512
534
  r ? joinPaths(
513
535
  s || "",
514
- d.substring(t.length + 1)
515
- ) : d
536
+ l.substring(t.length + 1)
537
+ ) : l
516
538
  );
517
539
  }
518
540
  }
@@ -581,96 +603,7 @@ const SupportedPHPVersions = [
581
603
  ], SupportedPHPExtensionBundles = {
582
604
  "kitchen-sink": SupportedPHPExtensionsList,
583
605
  light: []
584
- };
585
- var E, b;
586
- class PHPBrowser {
587
- /**
588
- * @param server - The PHP server to browse.
589
- * @param config - The browser configuration.
590
- */
591
- constructor(t, r = {}) {
592
- u(this, E, void 0);
593
- u(this, b, void 0);
594
- this.requestHandler = t, h(this, E, {}), h(this, b, {
595
- handleRedirects: !1,
596
- maxRedirects: 4,
597
- ...r
598
- });
599
- }
600
- /**
601
- * Sends the request to the server.
602
- *
603
- * When cookies are present in the response, this method stores
604
- * them and sends them with any subsequent requests.
605
- *
606
- * When a redirection is present in the response, this method
607
- * follows it by discarding a response and sending a subsequent
608
- * request.
609
- *
610
- * @param request - The request.
611
- * @param redirects - Internal. The number of redirects handled so far.
612
- * @returns PHPRequestHandler response.
613
- */
614
- async request(t, r = 0) {
615
- const s = await this.requestHandler.request({
616
- ...t,
617
- headers: {
618
- ...t.headers,
619
- cookie: this.serializeCookies()
620
- }
621
- });
622
- if (s.headers["set-cookie"] && this.setCookies(s.headers["set-cookie"]), l(this, b).handleRedirects && s.headers.location && r < l(this, b).maxRedirects) {
623
- const n = new URL(
624
- s.headers.location[0],
625
- this.requestHandler.absoluteUrl
626
- );
627
- return this.request(
628
- {
629
- url: n.toString(),
630
- method: "GET",
631
- headers: {}
632
- },
633
- r + 1
634
- );
635
- }
636
- return s;
637
- }
638
- /** @inheritDoc */
639
- pathToInternalUrl(t) {
640
- return this.requestHandler.pathToInternalUrl(t);
641
- }
642
- /** @inheritDoc */
643
- internalUrlToPath(t) {
644
- return this.requestHandler.internalUrlToPath(t);
645
- }
646
- /** @inheritDoc */
647
- get absoluteUrl() {
648
- return this.requestHandler.absoluteUrl;
649
- }
650
- /** @inheritDoc */
651
- get documentRoot() {
652
- return this.requestHandler.documentRoot;
653
- }
654
- setCookies(t) {
655
- for (const r of t)
656
- try {
657
- if (!r.includes("="))
658
- continue;
659
- const s = r.indexOf("="), n = r.substring(0, s), o = r.substring(s + 1).split(";")[0];
660
- l(this, E)[n] = o;
661
- } catch (s) {
662
- console.error(s);
663
- }
664
- }
665
- serializeCookies() {
666
- const t = [];
667
- for (const r in l(this, E))
668
- t.push(`${r}=${l(this, E)[r]}`);
669
- return t.join("; ");
670
- }
671
- }
672
- E = new WeakMap(), b = new WeakMap();
673
- const DEFAULT_BASE_URL = "http://example.com";
606
+ }, DEFAULT_BASE_URL = "http://example.com";
674
607
  function toRelativeUrl(e) {
675
608
  return e.toString().substring(e.origin.length);
676
609
  }
@@ -682,22 +615,22 @@ function ensurePathPrefix(e, t) {
682
615
  }
683
616
  async function encodeAsMultipart(e) {
684
617
  const t = `----${Math.random().toString(36).slice(2)}`, r = `multipart/form-data; boundary=${t}`, s = new TextEncoder(), n = [];
685
- for (const [c, d] of Object.entries(e))
618
+ for (const [u, l] of Object.entries(e))
686
619
  n.push(`--${t}\r
687
- `), n.push(`Content-Disposition: form-data; name="${c}"`), d instanceof File && n.push(`; filename="${d.name}"`), n.push(`\r
688
- `), d instanceof File && (n.push("Content-Type: application/octet-stream"), n.push(`\r
620
+ `), n.push(`Content-Disposition: form-data; name="${u}"`), l instanceof File && n.push(`; filename="${l.name}"`), n.push(`\r
621
+ `), l instanceof File && (n.push("Content-Type: application/octet-stream"), n.push(`\r
689
622
  `)), n.push(`\r
690
- `), d instanceof File ? n.push(await fileToUint8Array(d)) : n.push(d), n.push(`\r
623
+ `), l instanceof File ? n.push(await fileToUint8Array(l)) : n.push(l), n.push(`\r
691
624
  `);
692
625
  n.push(`--${t}--\r
693
626
  `);
694
- const o = n.reduce((c, d) => c + d.length, 0), i = new Uint8Array(o);
627
+ const o = n.reduce((u, l) => u + l.length, 0), i = new Uint8Array(o);
695
628
  let a = 0;
696
- for (const c of n)
629
+ for (const u of n)
697
630
  i.set(
698
- typeof c == "string" ? s.encode(c) : c,
631
+ typeof u == "string" ? s.encode(u) : u,
699
632
  a
700
- ), a += c.length;
633
+ ), a += u.length;
701
634
  return { bytes: i, contentType: r };
702
635
  }
703
636
  function fileToUint8Array(e) {
@@ -708,7 +641,30 @@ function fileToUint8Array(e) {
708
641
  }, r.readAsArrayBuffer(e);
709
642
  });
710
643
  }
711
- var m, H, k, v, F, p, x, R, U, Q, B, Y, I, K;
644
+ class HttpCookieStore {
645
+ constructor() {
646
+ this.cookies = {};
647
+ }
648
+ rememberCookiesFromResponseHeaders(t) {
649
+ if (t != null && t["set-cookie"])
650
+ for (const r of t["set-cookie"])
651
+ try {
652
+ if (!r.includes("="))
653
+ continue;
654
+ const s = r.indexOf("="), n = r.substring(0, s), o = r.substring(s + 1).split(";")[0];
655
+ this.cookies[n] = o;
656
+ } catch (s) {
657
+ console.error(s);
658
+ }
659
+ }
660
+ getCookieRequestHeader() {
661
+ const t = [];
662
+ for (const r in this.cookies)
663
+ t.push(`${r}=${this.cookies[r]}`);
664
+ return t.join("; ");
665
+ }
666
+ }
667
+ var m, v, C, g, S, _, b, E, x, A, Y, k, K, B, Z;
712
668
  class PHPRequestHandler {
713
669
  /**
714
670
  * @param php - The PHP instance.
@@ -721,7 +677,7 @@ class PHPRequestHandler {
721
677
  * @param fsPath - Absolute path of the static file to serve.
722
678
  * @returns The response.
723
679
  */
724
- u(this, U);
680
+ d(this, A);
725
681
  /**
726
682
  * Runs the requested PHP file with all the request and $_SERVER
727
683
  * superglobals populated.
@@ -729,7 +685,7 @@ class PHPRequestHandler {
729
685
  * @param request - The request.
730
686
  * @returns The response.
731
687
  */
732
- u(this, B);
688
+ d(this, k);
733
689
  /**
734
690
  * Resolve the requested path to the filesystem path of the requested PHP file.
735
691
  *
@@ -739,55 +695,120 @@ class PHPRequestHandler {
739
695
  * @throws {Error} If the requested path doesn't exist.
740
696
  * @returns The resolved filesystem path.
741
697
  */
742
- u(this, I);
743
- u(this, m, void 0);
744
- u(this, H, void 0);
745
- u(this, k, void 0);
746
- u(this, v, void 0);
747
- u(this, F, void 0);
748
- u(this, p, void 0);
749
- u(this, x, void 0);
750
- u(this, R, void 0);
751
- h(this, R, new Semaphore({ concurrency: 1 }));
698
+ d(this, B);
699
+ d(this, m, void 0);
700
+ d(this, v, void 0);
701
+ d(this, C, void 0);
702
+ d(this, g, void 0);
703
+ d(this, S, void 0);
704
+ d(this, _, void 0);
705
+ d(this, b, void 0);
706
+ d(this, E, void 0);
707
+ d(this, x, void 0);
708
+ h(this, E, new Semaphore({ concurrency: 1 }));
752
709
  const {
753
710
  documentRoot: s = "/www/",
754
711
  absoluteUrl: n = typeof location == "object" ? location == null ? void 0 : location.href : "",
755
712
  rewriteRules: o = []
756
713
  } = r;
757
- this.php = t, h(this, m, s);
714
+ this.php = t, h(this, x, new HttpCookieStore()), h(this, m, s);
758
715
  const i = new URL(n);
759
- h(this, k, i.hostname), h(this, v, i.port ? Number(i.port) : i.protocol === "https:" ? 443 : 80), h(this, H, (i.protocol || "").replace(":", ""));
760
- const a = l(this, v) !== 443 && l(this, v) !== 80;
761
- h(this, F, [
762
- l(this, k),
763
- a ? `:${l(this, v)}` : ""
764
- ].join("")), h(this, p, i.pathname.replace(/\/+$/, "")), h(this, x, [
765
- `${l(this, H)}://`,
766
- l(this, F),
767
- l(this, p)
716
+ h(this, C, i.hostname), h(this, g, i.port ? Number(i.port) : i.protocol === "https:" ? 443 : 80), h(this, v, (i.protocol || "").replace(":", ""));
717
+ const a = c(this, g) !== 443 && c(this, g) !== 80;
718
+ h(this, S, [
719
+ c(this, C),
720
+ a ? `:${c(this, g)}` : ""
721
+ ].join("")), h(this, _, i.pathname.replace(/\/+$/, "")), h(this, b, [
722
+ `${c(this, v)}://`,
723
+ c(this, S),
724
+ c(this, _)
768
725
  ].join("")), this.rewriteRules = o;
769
726
  }
770
- /** @inheritDoc */
727
+ /**
728
+ * Converts a path to an absolute URL based at the PHPRequestHandler
729
+ * root.
730
+ *
731
+ * @param path The server path to convert to an absolute URL.
732
+ * @returns The absolute URL.
733
+ */
771
734
  pathToInternalUrl(t) {
772
735
  return `${this.absoluteUrl}${t}`;
773
736
  }
774
- /** @inheritDoc */
737
+ /**
738
+ * Converts an absolute URL based at the PHPRequestHandler to a relative path
739
+ * without the server pathname and scope.
740
+ *
741
+ * @param internalUrl An absolute URL based at the PHPRequestHandler root.
742
+ * @returns The relative path.
743
+ */
775
744
  internalUrlToPath(t) {
776
745
  const r = new URL(t);
777
- return r.pathname.startsWith(l(this, p)) && (r.pathname = r.pathname.slice(l(this, p).length)), toRelativeUrl(r);
746
+ return r.pathname.startsWith(c(this, _)) && (r.pathname = r.pathname.slice(c(this, _).length)), toRelativeUrl(r);
778
747
  }
779
748
  get isRequestRunning() {
780
- return l(this, R).running > 0;
749
+ return c(this, E).running > 0;
781
750
  }
782
- /** @inheritDoc */
751
+ /**
752
+ * The absolute URL of this PHPRequestHandler instance.
753
+ */
783
754
  get absoluteUrl() {
784
- return l(this, x);
755
+ return c(this, b);
785
756
  }
786
- /** @inheritDoc */
757
+ /**
758
+ * The directory in the PHP filesystem where the server will look
759
+ * for the files to serve. Default: `/var/www`.
760
+ */
787
761
  get documentRoot() {
788
- return l(this, m);
762
+ return c(this, m);
789
763
  }
790
- /** @inheritDoc */
764
+ /**
765
+ * Serves the request – either by serving a static file, or by
766
+ * dispatching it to the PHP runtime.
767
+ *
768
+ * The request() method mode behaves like a web server and only works if
769
+ * the PHP was initialized with a `requestHandler` option (which the online version
770
+ * of WordPress Playground does by default).
771
+ *
772
+ * In the request mode, you pass an object containing the request information
773
+ * (method, headers, body, etc.) and the path to the PHP file to run:
774
+ *
775
+ * ```ts
776
+ * const php = PHP.load('7.4', {
777
+ * requestHandler: {
778
+ * documentRoot: "/www"
779
+ * }
780
+ * })
781
+ * php.writeFile("/www/index.php", `<?php echo file_get_contents("php://input");`);
782
+ * const result = await php.request({
783
+ * method: "GET",
784
+ * headers: {
785
+ * "Content-Type": "text/plain"
786
+ * },
787
+ * body: "Hello world!",
788
+ * path: "/www/index.php"
789
+ * });
790
+ * // result.text === "Hello world!"
791
+ * ```
792
+ *
793
+ * The `request()` method cannot be used in conjunction with `cli()`.
794
+ *
795
+ * @example
796
+ * ```js
797
+ * const output = await php.request({
798
+ * method: 'GET',
799
+ * url: '/index.php',
800
+ * headers: {
801
+ * 'X-foo': 'bar',
802
+ * },
803
+ * body: {
804
+ * foo: 'bar',
805
+ * },
806
+ * });
807
+ * console.log(output.stdout); // "Hello world!"
808
+ * ```
809
+ *
810
+ * @param request - PHP Request data.
811
+ */
791
812
  async request(t) {
792
813
  const r = t.url.startsWith("http://") || t.url.startsWith("https://"), s = new URL(
793
814
  // Remove the hash part of the URL as it's not meant for the server.
@@ -796,14 +817,14 @@ class PHPRequestHandler {
796
817
  ), n = applyRewriteRules(
797
818
  removePathPrefix(
798
819
  decodeURIComponent(s.pathname),
799
- l(this, p)
820
+ c(this, _)
800
821
  ),
801
822
  this.rewriteRules
802
- ), o = joinPaths(l(this, m), n);
803
- return seemsLikeAPHPRequestHandlerPath(o) ? await f(this, B, Y).call(this, t, s) : f(this, U, Q).call(this, o);
823
+ ), o = joinPaths(c(this, m), n);
824
+ return seemsLikeAPHPRequestHandlerPath(o) ? await p(this, k, K).call(this, t, s) : p(this, A, Y).call(this, o);
804
825
  }
805
826
  }
806
- m = new WeakMap(), H = new WeakMap(), k = new WeakMap(), v = new WeakMap(), F = new WeakMap(), p = new WeakMap(), x = new WeakMap(), R = new WeakMap(), U = new WeakSet(), Q = function(t) {
827
+ m = new WeakMap(), v = new WeakMap(), C = new WeakMap(), g = new WeakMap(), S = new WeakMap(), _ = new WeakMap(), b = new WeakMap(), E = new WeakMap(), x = new WeakMap(), A = new WeakSet(), Y = function(t) {
807
828
  if (!this.php.fileExists(t))
808
829
  return new PHPResponse(
809
830
  404,
@@ -828,9 +849,9 @@ m = new WeakMap(), H = new WeakMap(), k = new WeakMap(), v = new WeakMap(), F =
828
849
  },
829
850
  r
830
851
  );
831
- }, B = new WeakSet(), Y = async function(t, r) {
852
+ }, k = new WeakSet(), K = async function(t, r) {
832
853
  var n;
833
- if (l(this, R).running > 0 && ((n = t.headers) == null ? void 0 : n["x-request-issuer"]) === "php")
854
+ if (c(this, E).running > 0 && ((n = t.headers) == null ? void 0 : n["x-request-issuer"]) === "php")
834
855
  return console.warn(
835
856
  "Possible deadlock: Called request() before the previous request() have finished. PHP likely issued an HTTP call to itself. Normally this would lead to infinite waiting as Request 1 holds the lock that the Request 2 is waiting to acquire. That's not useful, so PHPRequestHandler will return error 502 instead."
836
857
  ), new PHPResponse(
@@ -838,26 +859,23 @@ m = new WeakMap(), H = new WeakMap(), k = new WeakMap(), v = new WeakMap(), F =
838
859
  {},
839
860
  new TextEncoder().encode("502 Bad Gateway")
840
861
  );
841
- const s = await l(this, R).acquire();
862
+ const s = await c(this, E).acquire();
842
863
  try {
843
- this.php.addServerGlobalEntry("REMOTE_ADDR", "127.0.0.1"), this.php.addServerGlobalEntry("DOCUMENT_ROOT", l(this, m)), this.php.addServerGlobalEntry(
844
- "HTTPS",
845
- l(this, x).startsWith("https://") ? "on" : ""
846
- );
847
864
  let o = "GET";
848
865
  const i = {
849
- host: l(this, F),
850
- ...normalizeHeaders(t.headers || {})
866
+ host: c(this, S),
867
+ ...normalizeHeaders(t.headers || {}),
868
+ cookie: c(this, x).getCookieRequestHeader()
851
869
  };
852
870
  let a = t.body;
853
871
  if (typeof a == "object" && !(a instanceof Uint8Array)) {
854
872
  o = "POST";
855
- const { bytes: d, contentType: _ } = await encodeAsMultipart(a);
856
- a = d, i["content-type"] = _;
873
+ const { bytes: l, contentType: f } = await encodeAsMultipart(a);
874
+ a = l, i["content-type"] = f;
857
875
  }
858
- let c;
876
+ let u;
859
877
  try {
860
- c = f(this, I, K).call(this, decodeURIComponent(r.pathname));
878
+ u = p(this, B, Z).call(this, decodeURIComponent(r.pathname));
861
879
  } catch {
862
880
  return new PHPResponse(
863
881
  404,
@@ -865,24 +883,39 @@ m = new WeakMap(), H = new WeakMap(), k = new WeakMap(), v = new WeakMap(), F =
865
883
  new TextEncoder().encode("404 File not found")
866
884
  );
867
885
  }
868
- return await this.php.run({
869
- relativeUri: ensurePathPrefix(
870
- toRelativeUrl(r),
871
- l(this, p)
872
- ),
873
- protocol: l(this, H),
874
- method: t.method || o,
875
- body: a,
876
- scriptPath: c,
877
- headers: i
878
- });
886
+ try {
887
+ const l = await this.php.run({
888
+ relativeUri: ensurePathPrefix(
889
+ toRelativeUrl(r),
890
+ c(this, _)
891
+ ),
892
+ protocol: c(this, v),
893
+ method: t.method || o,
894
+ $_SERVER: {
895
+ REMOTE_ADDR: "127.0.0.1",
896
+ DOCUMENT_ROOT: c(this, m),
897
+ HTTPS: c(this, b).startsWith("https://") ? "on" : ""
898
+ },
899
+ body: a,
900
+ scriptPath: u,
901
+ headers: i
902
+ });
903
+ return c(this, x).rememberCookiesFromResponseHeaders(
904
+ l.headers
905
+ ), l;
906
+ } catch (l) {
907
+ const f = l;
908
+ if (f != null && f.response)
909
+ return f.response;
910
+ throw l;
911
+ }
879
912
  } finally {
880
913
  s();
881
914
  }
882
- }, I = new WeakSet(), K = function(t) {
883
- let r = removePathPrefix(t, l(this, p));
884
- r = applyRewriteRules(r, this.rewriteRules), r.includes(".php") ? r = r.split(".php")[0] + ".php" : this.php.isDir(`${l(this, m)}${r}`) ? (r.endsWith("/") || (r = `${r}/`), r = `${r}index.php`) : r = "/index.php";
885
- const s = `${l(this, m)}${r}`;
915
+ }, B = new WeakSet(), Z = function(t) {
916
+ let r = removePathPrefix(t, c(this, _));
917
+ r = applyRewriteRules(r, this.rewriteRules), r.includes(".php") ? r = r.split(".php")[0] + ".php" : this.php.isDir(`${c(this, m)}${r}`) ? (r.endsWith("/") || (r = `${r}/`), r = `${r}index.php`) : r = "/index.php";
918
+ const s = `${c(this, m)}${r}`;
886
919
  if (this.php.fileExists(s))
887
920
  return s;
888
921
  throw new Error(`File not found: ${s}`);
@@ -923,6 +956,38 @@ function inferMimeType(e) {
923
956
  case "txt":
924
957
  case "md":
925
958
  return "text/plain";
959
+ case "pdf":
960
+ return "application/pdf";
961
+ case "webp":
962
+ return "image/webp";
963
+ case "mp3":
964
+ return "audio/mpeg";
965
+ case "mp4":
966
+ return "video/mp4";
967
+ case "csv":
968
+ return "text/csv";
969
+ case "xls":
970
+ return "application/vnd.ms-excel";
971
+ case "xlsx":
972
+ return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
973
+ case "doc":
974
+ return "application/msword";
975
+ case "docx":
976
+ return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
977
+ case "ppt":
978
+ return "application/vnd.ms-powerpoint";
979
+ case "pptx":
980
+ return "application/vnd.openxmlformats-officedocument.presentationml.presentation";
981
+ case "zip":
982
+ return "application/zip";
983
+ case "rar":
984
+ return "application/x-rar-compressed";
985
+ case "tar":
986
+ return "application/x-tar";
987
+ case "gz":
988
+ return "application/gzip";
989
+ case "7z":
990
+ return "application/x-7z-compressed";
926
991
  default:
927
992
  return "application-octet-stream";
928
993
  }
@@ -1033,10 +1098,10 @@ function rethrowFileSystemError(e = "") {
1033
1098
  try {
1034
1099
  return o.apply(this, i);
1035
1100
  } catch (a) {
1036
- const c = typeof a == "object" ? a == null ? void 0 : a.errno : null;
1037
- if (c in FileErrorCodes) {
1038
- const d = FileErrorCodes[c], _ = typeof i[0] == "string" ? i[0] : null, ue = _ !== null ? e.replaceAll("{path}", _) : e;
1039
- throw new Error(`${ue}: ${d}`, {
1101
+ const u = typeof a == "object" ? a == null ? void 0 : a.errno : null;
1102
+ if (u in FileErrorCodes) {
1103
+ const l = FileErrorCodes[u], f = typeof i[0] == "string" ? i[0] : null, fe = f !== null ? e.replaceAll("{path}", f) : e;
1104
+ throw new Error(`${fe}: ${l}`, {
1040
1105
  cause: a
1041
1106
  });
1042
1107
  }
@@ -1087,7 +1152,12 @@ var __defProp = Object.defineProperty, __getOwnPropDesc = Object.getOwnPropertyD
1087
1152
  return s && n && __defProp(t, r, n), n;
1088
1153
  };
1089
1154
  const STRING = "string", NUMBER = "number", __private__dont__use = Symbol("__private__dont__use");
1090
- var S, T, C, y, w, g, P, A, N, Z, L, X, q, ee, O, te, M, re, D, se, $, ne, j, ie, W, oe, z, ae, G, le, V, ce;
1155
+ class PHPExecutionFailureError extends Error {
1156
+ constructor(t, r, s) {
1157
+ super(t), this.response = r, this.source = s;
1158
+ }
1159
+ }
1160
+ var R, F, H, y, w, P, T, I, X, N, ee, U, te, L, re, O, se, M, ne, $, ie, D, oe, q, ae, j, le, z, ce, W, ue, G, de, V, he, J, pe;
1091
1161
  class BasePHP {
1092
1162
  /**
1093
1163
  * Initializes a PHP runtime.
@@ -1097,46 +1167,55 @@ class BasePHP {
1097
1167
  * @param serverOptions - Optional. Options for the PHPRequestHandler. If undefined, no request handler will be initialized.
1098
1168
  */
1099
1169
  constructor(e, t) {
1100
- u(this, N);
1101
- u(this, L);
1102
- u(this, q);
1103
- u(this, O);
1104
- u(this, M);
1105
- u(this, D);
1106
- u(this, $);
1107
- u(this, j);
1108
- u(this, W);
1109
- u(this, z);
1110
- u(this, G);
1111
- u(this, V);
1112
- u(this, S, void 0);
1113
- u(this, T, void 0);
1114
- u(this, C, void 0);
1115
- u(this, y, void 0);
1116
- u(this, w, void 0);
1117
- u(this, g, void 0);
1118
- u(this, P, void 0);
1119
- u(this, A, void 0);
1120
- h(this, S, []), h(this, y, !1), h(this, w, null), h(this, g, {}), h(this, P, /* @__PURE__ */ new Map()), h(this, A, []), this.semaphore = new Semaphore({ concurrency: 1 }), e !== void 0 && this.initializeRuntime(e), t && (this.requestHandler = new PHPBrowser(
1121
- new PHPRequestHandler(this, t)
1122
- ));
1170
+ /**
1171
+ * Prepares the $_SERVER entries for the PHP runtime.
1172
+ *
1173
+ * @param defaults Default entries to include in $_SERVER.
1174
+ * @param headers HTTP headers to include in $_SERVER (as HTTP_ prefixed entries).
1175
+ * @param port HTTP port, used to determine infer $_SERVER['HTTPS'] value if none
1176
+ * was provided.
1177
+ * @returns Computed $_SERVER entries.
1178
+ */
1179
+ d(this, I);
1180
+ d(this, N);
1181
+ d(this, U);
1182
+ d(this, L);
1183
+ d(this, O);
1184
+ d(this, M);
1185
+ d(this, $);
1186
+ d(this, D);
1187
+ d(this, q);
1188
+ d(this, j);
1189
+ d(this, z);
1190
+ d(this, W);
1191
+ d(this, G);
1192
+ d(this, V);
1193
+ d(this, J);
1194
+ d(this, R, void 0);
1195
+ d(this, F, void 0);
1196
+ d(this, H, void 0);
1197
+ d(this, y, void 0);
1198
+ d(this, w, void 0);
1199
+ d(this, P, void 0);
1200
+ d(this, T, void 0);
1201
+ h(this, R, []), h(this, y, !1), h(this, w, null), h(this, P, /* @__PURE__ */ new Map()), h(this, T, []), this.semaphore = new Semaphore({ concurrency: 1 }), e !== void 0 && this.initializeRuntime(e), t && (this.requestHandler = new PHPRequestHandler(this, t));
1123
1202
  }
1124
1203
  addEventListener(e, t) {
1125
- l(this, P).has(e) || l(this, P).set(e, /* @__PURE__ */ new Set()), l(this, P).get(e).add(t);
1204
+ c(this, P).has(e) || c(this, P).set(e, /* @__PURE__ */ new Set()), c(this, P).get(e).add(t);
1126
1205
  }
1127
1206
  removeEventListener(e, t) {
1128
1207
  var r;
1129
- (r = l(this, P).get(e)) == null || r.delete(t);
1208
+ (r = c(this, P).get(e)) == null || r.delete(t);
1130
1209
  }
1131
1210
  dispatchEvent(e) {
1132
- const t = l(this, P).get(e.type);
1211
+ const t = c(this, P).get(e.type);
1133
1212
  if (t)
1134
1213
  for (const r of t)
1135
1214
  r(e);
1136
1215
  }
1137
1216
  /** @inheritDoc */
1138
1217
  async onMessage(e) {
1139
- l(this, A).push(e);
1218
+ c(this, T).push(e);
1140
1219
  }
1141
1220
  /** @inheritDoc */
1142
1221
  async setSpawnHandler(handler) {
@@ -1144,21 +1223,19 @@ class BasePHP {
1144
1223
  }
1145
1224
  /** @inheritDoc */
1146
1225
  get absoluteUrl() {
1147
- return this.requestHandler.requestHandler.absoluteUrl;
1226
+ return this.requestHandler.absoluteUrl;
1148
1227
  }
1149
1228
  /** @inheritDoc */
1150
1229
  get documentRoot() {
1151
- return this.requestHandler.requestHandler.documentRoot;
1230
+ return this.requestHandler.documentRoot;
1152
1231
  }
1153
1232
  /** @inheritDoc */
1154
1233
  pathToInternalUrl(e) {
1155
- return this.requestHandler.requestHandler.pathToInternalUrl(e);
1234
+ return this.requestHandler.pathToInternalUrl(e);
1156
1235
  }
1157
1236
  /** @inheritDoc */
1158
1237
  internalUrlToPath(e) {
1159
- return this.requestHandler.requestHandler.internalUrlToPath(
1160
- e
1161
- );
1238
+ return this.requestHandler.internalUrlToPath(e);
1162
1239
  }
1163
1240
  initializeRuntime(e) {
1164
1241
  if (this[__private__dont__use])
@@ -1167,7 +1244,7 @@ class BasePHP {
1167
1244
  if (!t)
1168
1245
  throw new Error("Invalid PHP runtime id.");
1169
1246
  this[__private__dont__use] = t, t.onMessage = async (r) => {
1170
- for (const s of l(this, A)) {
1247
+ for (const s of c(this, T)) {
1171
1248
  const n = await s(r);
1172
1249
  if (n)
1173
1250
  return n;
@@ -1188,13 +1265,13 @@ class BasePHP {
1188
1265
  throw new Error(
1189
1266
  "Could not set SAPI name. This can only be done before the PHP WASM module is initialized.Did you already dispatch any requests?"
1190
1267
  );
1191
- h(this, C, e);
1268
+ h(this, H, e);
1192
1269
  }
1193
1270
  /** @inheritDoc */
1194
1271
  setPhpIniPath(e) {
1195
- if (l(this, y))
1272
+ if (c(this, y))
1196
1273
  throw new Error("Cannot set PHP ini path after calling run().");
1197
- h(this, T, e), this[__private__dont__use].ccall(
1274
+ h(this, F, e), this[__private__dont__use].ccall(
1198
1275
  "wasm_set_phpini_path",
1199
1276
  null,
1200
1277
  ["string"],
@@ -1203,44 +1280,49 @@ class BasePHP {
1203
1280
  }
1204
1281
  /** @inheritDoc */
1205
1282
  setPhpIniEntry(e, t) {
1206
- if (l(this, y))
1283
+ if (c(this, y))
1207
1284
  throw new Error("Cannot set PHP ini entries after calling run().");
1208
- l(this, S).push([e, t]);
1285
+ c(this, R).push([e, t]);
1209
1286
  }
1210
1287
  /** @inheritDoc */
1211
1288
  chdir(e) {
1212
1289
  this[__private__dont__use].FS.chdir(e);
1213
1290
  }
1214
1291
  /** @inheritDoc */
1215
- async request(e, t) {
1292
+ async request(e) {
1216
1293
  if (!this.requestHandler)
1217
1294
  throw new Error("No request handler available.");
1218
- return this.requestHandler.request(e, t);
1295
+ return this.requestHandler.request(e);
1219
1296
  }
1220
1297
  /** @inheritDoc */
1221
1298
  async run(e) {
1222
1299
  const t = await this.semaphore.acquire();
1223
1300
  let r;
1224
1301
  try {
1225
- if (l(this, y) || (f(this, N, Z).call(this), h(this, y, !0)), e.scriptPath && !this.fileExists(e.scriptPath))
1302
+ if (c(this, y) || (p(this, N, ee).call(this), h(this, y, !0)), e.scriptPath && !this.fileExists(e.scriptPath))
1226
1303
  throw new Error(
1227
1304
  `The script path "${e.scriptPath}" does not exist.`
1228
1305
  );
1229
- f(this, j, ie).call(this, e.scriptPath || ""), f(this, q, ee).call(this, e.relativeUri || ""), f(this, M, re).call(this, e.method || "GET");
1230
- const s = normalizeHeaders(e.headers || {}), n = s.host || "example.com:443";
1231
- f(this, O, te).call(this, n, e.protocol || "http"), f(this, D, se).call(this, s), e.body && (r = f(this, $, ne).call(this, e.body)), typeof e.code == "string" && f(this, G, le).call(this, " ?>" + e.code), f(this, W, oe).call(this);
1232
- const o = e.env || {};
1233
- for (const a in o)
1234
- f(this, z, ae).call(this, a, o[a]);
1235
- const i = await f(this, V, ce).call(this);
1236
- if (i.exitCode !== 0) {
1237
- console.warn("PHP.run() output was:", i.text);
1238
- const a = new Error(
1239
- `PHP.run() failed with exit code ${i.exitCode} and the following output: ` + i.errors
1306
+ p(this, z, ce).call(this, e.scriptPath || ""), p(this, L, re).call(this, e.relativeUri || ""), p(this, D, oe).call(this, e.method || "GET");
1307
+ const s = normalizeHeaders(e.headers || {}), n = s.host || "example.com:443", o = p(this, $, ie).call(this, n, e.protocol || "http");
1308
+ p(this, O, se).call(this, n), p(this, M, ne).call(this, o), p(this, q, ae).call(this, s), e.body && (r = p(this, j, le).call(this, e.body)), typeof e.code == "string" && p(this, V, he).call(this, " ?>" + e.code);
1309
+ const i = p(this, I, X).call(this, e.$_SERVER, s, o);
1310
+ for (const l in i)
1311
+ p(this, W, ue).call(this, l, i[l]);
1312
+ const a = e.env || {};
1313
+ for (const l in a)
1314
+ p(this, G, de).call(this, l, a[l]);
1315
+ const u = await p(this, J, pe).call(this);
1316
+ if (u.exitCode !== 0) {
1317
+ console.warn("PHP.run() output was:", u.text);
1318
+ const l = new PHPExecutionFailureError(
1319
+ `PHP.run() failed with exit code ${u.exitCode} and the following output: ` + u.errors,
1320
+ u,
1321
+ "request"
1240
1322
  );
1241
- throw a.response = i, a.source = "request", console.error(a), a;
1323
+ throw console.error(l), l;
1242
1324
  }
1243
- return i;
1325
+ return u;
1244
1326
  } catch (s) {
1245
1327
  throw this.dispatchEvent({
1246
1328
  type: "request.error",
@@ -1258,9 +1340,6 @@ class BasePHP {
1258
1340
  }
1259
1341
  }
1260
1342
  }
1261
- addServerGlobalEntry(e, t) {
1262
- l(this, g)[e] = t;
1263
- }
1264
1343
  defineConstant(e, t) {
1265
1344
  let r = {};
1266
1345
  try {
@@ -1348,17 +1427,18 @@ class BasePHP {
1348
1427
  * interrupting the operations of this PHP instance.
1349
1428
  *
1350
1429
  * @param runtime
1430
+ * @param cwd. Internal, the VFS path to recreate in the new runtime.
1431
+ * This arg is temporary and will be removed once BasePHP
1432
+ * is fully decoupled from the request handler and
1433
+ * accepts a constructor-level cwd argument.
1351
1434
  */
1352
- hotSwapPHPRuntime(e) {
1353
- const t = this[__private__dont__use].FS;
1435
+ hotSwapPHPRuntime(e, t) {
1436
+ const r = this[__private__dont__use].FS;
1354
1437
  try {
1355
1438
  this.exit();
1356
1439
  } catch {
1357
1440
  }
1358
- if (this.initializeRuntime(e), l(this, T) && this.setPhpIniPath(l(this, T)), l(this, C) && this.setSapiName(l(this, C)), this.requestHandler) {
1359
- const r = this.documentRoot;
1360
- copyFS(t, this[__private__dont__use].FS, r);
1361
- }
1441
+ this.initializeRuntime(e), c(this, F) && this.setPhpIniPath(c(this, F)), c(this, H) && this.setSapiName(c(this, H)), t && copyFS(r, this[__private__dont__use].FS, t);
1362
1442
  }
1363
1443
  exit(e = 0) {
1364
1444
  this.dispatchEvent({
@@ -1371,7 +1451,17 @@ class BasePHP {
1371
1451
  h(this, y, !1), h(this, w, null), delete this[__private__dont__use].onMessage, delete this[__private__dont__use];
1372
1452
  }
1373
1453
  }
1374
- S = new WeakMap(), T = new WeakMap(), C = new WeakMap(), y = new WeakMap(), w = new WeakMap(), g = new WeakMap(), P = new WeakMap(), A = new WeakMap(), N = new WeakSet(), Z = function() {
1454
+ R = new WeakMap(), F = new WeakMap(), H = new WeakMap(), y = new WeakMap(), w = new WeakMap(), P = new WeakMap(), T = new WeakMap(), I = new WeakSet(), X = function(e, t, r) {
1455
+ const s = {
1456
+ ...e || {}
1457
+ };
1458
+ s.HTTPS = s.HTTPS || r === 443 ? "on" : "off";
1459
+ for (const n in t) {
1460
+ let o = "HTTP_";
1461
+ ["content-type", "content-length"].includes(n.toLowerCase()) && (o = ""), s[`${o}${n.toUpperCase().replace(/-/g, "_")}`] = t[n];
1462
+ }
1463
+ return s;
1464
+ }, N = new WeakSet(), ee = function() {
1375
1465
  if (this.setPhpIniEntry("auto_prepend_file", "/internal/consts.php"), this.fileExists("/internal/consts.php") || this.writeFile(
1376
1466
  "/internal/consts.php",
1377
1467
  `<?php
@@ -1383,8 +1473,8 @@ S = new WeakMap(), T = new WeakMap(), C = new WeakMap(), y = new WeakMap(), w =
1383
1473
  }
1384
1474
  }
1385
1475
  }`
1386
- ), l(this, S).length > 0) {
1387
- const e = l(this, S).map(([t, r]) => `${t}=${r}`).join(`
1476
+ ), c(this, R).length > 0) {
1477
+ const e = c(this, R).map(([t, r]) => `${t}=${r}`).join(`
1388
1478
  `) + `
1389
1479
 
1390
1480
  `;
@@ -1396,7 +1486,7 @@ S = new WeakMap(), T = new WeakMap(), C = new WeakMap(), y = new WeakMap(), w =
1396
1486
  );
1397
1487
  }
1398
1488
  this[__private__dont__use].ccall("php_wasm_init", null, [], []);
1399
- }, L = new WeakSet(), X = function() {
1489
+ }, U = new WeakSet(), te = function() {
1400
1490
  const e = "/internal/headers.json";
1401
1491
  if (!this.fileExists(e))
1402
1492
  throw new Error(
@@ -1413,7 +1503,7 @@ S = new WeakMap(), T = new WeakMap(), C = new WeakMap(), y = new WeakMap(), w =
1413
1503
  headers: r,
1414
1504
  httpStatusCode: t.status
1415
1505
  };
1416
- }, q = new WeakSet(), ee = function(e) {
1506
+ }, L = new WeakSet(), re = function(e) {
1417
1507
  if (this[__private__dont__use].ccall(
1418
1508
  "wasm_set_request_uri",
1419
1509
  null,
@@ -1428,32 +1518,35 @@ S = new WeakMap(), T = new WeakMap(), C = new WeakMap(), y = new WeakMap(), w =
1428
1518
  [t]
1429
1519
  );
1430
1520
  }
1431
- }, O = new WeakSet(), te = function(e, t) {
1521
+ }, O = new WeakSet(), se = function(e) {
1432
1522
  this[__private__dont__use].ccall(
1433
1523
  "wasm_set_request_host",
1434
1524
  null,
1435
1525
  [STRING],
1436
1526
  [e]
1437
1527
  );
1528
+ }, M = new WeakSet(), ne = function(e) {
1529
+ this[__private__dont__use].ccall(
1530
+ "wasm_set_request_port",
1531
+ null,
1532
+ [NUMBER],
1533
+ [e]
1534
+ );
1535
+ }, $ = new WeakSet(), ie = function(e, t) {
1438
1536
  let r;
1439
1537
  try {
1440
1538
  r = parseInt(new URL(e).port, 10);
1441
1539
  } catch {
1442
1540
  }
1443
- (!r || isNaN(r) || r === 80) && (r = t === "https" ? 443 : 80), this[__private__dont__use].ccall(
1444
- "wasm_set_request_port",
1445
- null,
1446
- [NUMBER],
1447
- [r]
1448
- ), (t === "https" || !t && r === 443) && this.addServerGlobalEntry("HTTPS", "on");
1449
- }, M = new WeakSet(), re = function(e) {
1541
+ return (!r || isNaN(r) || r === 80) && (r = t === "https" ? 443 : 80), r;
1542
+ }, D = new WeakSet(), oe = function(e) {
1450
1543
  this[__private__dont__use].ccall(
1451
1544
  "wasm_set_request_method",
1452
1545
  null,
1453
1546
  [STRING],
1454
1547
  [e]
1455
1548
  );
1456
- }, D = new WeakSet(), se = function(e) {
1549
+ }, q = new WeakSet(), ae = function(e) {
1457
1550
  e.cookie && this[__private__dont__use].ccall(
1458
1551
  "wasm_set_cookies",
1459
1552
  null,
@@ -1470,14 +1563,7 @@ S = new WeakMap(), T = new WeakMap(), C = new WeakMap(), y = new WeakMap(), w =
1470
1563
  [NUMBER],
1471
1564
  [parseInt(e["content-length"], 10)]
1472
1565
  );
1473
- for (const t in e) {
1474
- let r = "HTTP_";
1475
- ["content-type", "content-length"].includes(t.toLowerCase()) && (r = ""), this.addServerGlobalEntry(
1476
- `${r}${t.toUpperCase().replace(/-/g, "_")}`,
1477
- e[t]
1478
- );
1479
- }
1480
- }, $ = new WeakSet(), ne = function(e) {
1566
+ }, j = new WeakSet(), le = function(e) {
1481
1567
  let t, r;
1482
1568
  typeof e == "string" ? (console.warn(
1483
1569
  "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"
@@ -1500,46 +1586,45 @@ S = new WeakMap(), T = new WeakMap(), C = new WeakMap(), y = new WeakMap(), w =
1500
1586
  [NUMBER],
1501
1587
  [r]
1502
1588
  ), s;
1503
- }, j = new WeakSet(), ie = function(e) {
1589
+ }, z = new WeakSet(), ce = function(e) {
1504
1590
  this[__private__dont__use].ccall(
1505
1591
  "wasm_set_path_translated",
1506
1592
  null,
1507
1593
  [STRING],
1508
1594
  [e]
1509
1595
  );
1510
- }, W = new WeakSet(), oe = function() {
1511
- for (const e in l(this, g))
1512
- this[__private__dont__use].ccall(
1513
- "wasm_add_SERVER_entry",
1514
- null,
1515
- [STRING, STRING],
1516
- [e, l(this, g)[e]]
1517
- );
1518
- }, z = new WeakSet(), ae = function(e, t) {
1596
+ }, W = new WeakSet(), ue = function(e, t) {
1597
+ this[__private__dont__use].ccall(
1598
+ "wasm_add_SERVER_entry",
1599
+ null,
1600
+ [STRING, STRING],
1601
+ [e, t]
1602
+ );
1603
+ }, G = new WeakSet(), de = function(e, t) {
1519
1604
  this[__private__dont__use].ccall(
1520
1605
  "wasm_add_ENV_entry",
1521
1606
  null,
1522
1607
  [STRING, STRING],
1523
1608
  [e, t]
1524
1609
  );
1525
- }, G = new WeakSet(), le = function(e) {
1610
+ }, V = new WeakSet(), he = function(e) {
1526
1611
  this[__private__dont__use].ccall(
1527
1612
  "wasm_set_php_code",
1528
1613
  null,
1529
1614
  [STRING],
1530
1615
  [e]
1531
1616
  );
1532
- }, V = new WeakSet(), ce = async function() {
1617
+ }, J = new WeakSet(), pe = async function() {
1533
1618
  var n;
1534
1619
  let e, t;
1535
1620
  try {
1536
1621
  e = await new Promise((o, i) => {
1537
- var c;
1538
- t = (d) => {
1539
- console.error(d), console.error(d.error);
1540
- const _ = new Error("Rethrown");
1541
- _.cause = d.error, _.betterMessage = d.message, i(_);
1542
- }, (c = l(this, w)) == null || c.addEventListener(
1622
+ var u;
1623
+ t = (l) => {
1624
+ console.error(l), console.error(l.error);
1625
+ const f = new Error("Rethrown");
1626
+ f.cause = l.error, f.betterMessage = l.message, i(f);
1627
+ }, (u = c(this, w)) == null || u.addEventListener(
1543
1628
  "error",
1544
1629
  t
1545
1630
  );
@@ -1553,21 +1638,21 @@ S = new WeakMap(), T = new WeakMap(), C = new WeakMap(), y = new WeakMap(), w =
1553
1638
  return a instanceof Promise ? a.then(o, i) : o(a);
1554
1639
  });
1555
1640
  } catch (o) {
1556
- for (const d in this)
1557
- typeof this[d] == "function" && (this[d] = () => {
1641
+ for (const l in this)
1642
+ typeof this[l] == "function" && (this[l] = () => {
1558
1643
  throw new Error(
1559
1644
  "PHP runtime has crashed – see the earlier error for details."
1560
1645
  );
1561
1646
  });
1562
1647
  this.functionsMaybeMissingFromAsyncify = getFunctionsMaybeMissingFromAsyncify();
1563
- const i = o, a = "betterMessage" in i ? i.betterMessage : i.message, c = new Error(a);
1564
- throw c.cause = i, console.error(c), c;
1648
+ const i = o, a = "betterMessage" in i ? i.betterMessage : i.message, u = new Error(a);
1649
+ throw u.cause = i, console.error(u), u;
1565
1650
  } finally {
1566
- (n = l(this, w)) == null || n.removeEventListener("error", t), h(this, g, {});
1651
+ (n = c(this, w)) == null || n.removeEventListener("error", t);
1567
1652
  }
1568
- const { headers: r, httpStatusCode: s } = f(this, L, X).call(this);
1653
+ const { headers: r, httpStatusCode: s } = p(this, U, te).call(this);
1569
1654
  return new PHPResponse(
1570
- s,
1655
+ e === 0 ? s : 500,
1571
1656
  r,
1572
1657
  this.readFileAsBuffer("/internal/stdout"),
1573
1658
  this.readFileAsText("/internal/stderr"),
@@ -1636,23 +1721,32 @@ function isRemotePHP(e) {
1636
1721
  }
1637
1722
  function rotatePHPRuntime({
1638
1723
  php: e,
1639
- recreateRuntime: t,
1640
- maxRequests: r
1724
+ cwd: t,
1725
+ recreateRuntime: r,
1726
+ /*
1727
+ * 400 is an arbitrary number that should trigger a rotation
1728
+ * way before the memory gets too fragmented. If it doesn't,
1729
+ * let's explore:
1730
+ * * Rotating based on an actual memory usage and
1731
+ * fragmentation.
1732
+ * * Resetting HEAP to its initial value.
1733
+ */
1734
+ maxRequests: s = 400
1641
1735
  }) {
1642
- let s = 0;
1643
- async function n() {
1644
- if (++s < r)
1736
+ let n = 0;
1737
+ async function o() {
1738
+ if (++n < s)
1645
1739
  return;
1646
- s = 0;
1647
- const o = await e.semaphore.acquire();
1740
+ n = 0;
1741
+ const i = await e.semaphore.acquire();
1648
1742
  try {
1649
- e.hotSwapPHPRuntime(await t());
1743
+ e.hotSwapPHPRuntime(await r(), t);
1650
1744
  } finally {
1651
- o();
1745
+ i();
1652
1746
  }
1653
1747
  }
1654
- return e.addEventListener("request.end", n), function() {
1655
- e.removeEventListener("request.end", n);
1748
+ return e.addEventListener("request.end", o), function() {
1749
+ e.removeEventListener("request.end", o);
1656
1750
  };
1657
1751
  }
1658
1752
  async function writeFiles(e, t, r, { rmRoot: s = !1 } = {}) {
@@ -1666,7 +1760,6 @@ export {
1666
1760
  BasePHP,
1667
1761
  DEFAULT_BASE_URL,
1668
1762
  LatestSupportedPHPVersion,
1669
- PHPBrowser,
1670
1763
  PHPRequestHandler,
1671
1764
  PHPResponse,
1672
1765
  SupportedPHPExtensionBundles,