@php-wasm/universal 0.6.16 → 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)), d = (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 u = c.byteLength;
65
- n.byobRequest.respond(u), r += u, 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 u = `${i}/${c}`;
508
- if (n.includes(u.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(u) ? o.push(u) : yield new StreamedFile(
511
- streamReadFileFromPHP(e, u),
532
+ await e.isDir(l) ? o.push(l) : yield new StreamedFile(
533
+ streamReadFileFromPHP(e, l),
512
534
  r ? joinPaths(
513
535
  s || "",
514
- u.substring(t.length + 1)
515
- ) : u
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
- d(this, E, void 0);
593
- d(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, u] 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}"`), u instanceof File && n.push(`; filename="${u.name}"`), n.push(`\r
688
- `), u 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
- `), u instanceof File ? n.push(await fileToUint8Array(u)) : n.push(u), 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, u) => c + u.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, _, 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
- d(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
- d(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
- d(this, I);
698
+ d(this, B);
743
699
  d(this, m, void 0);
744
- d(this, H, void 0);
745
- d(this, k, void 0);
746
700
  d(this, v, void 0);
747
- d(this, F, void 0);
701
+ d(this, C, void 0);
702
+ d(this, g, void 0);
703
+ d(this, S, void 0);
748
704
  d(this, _, void 0);
705
+ d(this, b, void 0);
706
+ d(this, E, void 0);
749
707
  d(this, x, void 0);
750
- d(this, R, void 0);
751
- h(this, R, new Semaphore({ concurrency: 1 }));
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, _, i.pathname.replace(/\/+$/, "")), h(this, x, [
765
- `${l(this, H)}://`,
766
- l(this, F),
767
- l(this, _)
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, _)) && (r.pathname = r.pathname.slice(l(this, _).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, _)
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(), _ = 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: u, contentType: p } = await encodeAsMultipart(a);
856
- a = u, i["content-type"] = p;
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,
@@ -866,30 +884,38 @@ m = new WeakMap(), H = new WeakMap(), k = new WeakMap(), v = new WeakMap(), F =
866
884
  );
867
885
  }
868
886
  try {
869
- return await this.php.run({
887
+ const l = await this.php.run({
870
888
  relativeUri: ensurePathPrefix(
871
889
  toRelativeUrl(r),
872
- l(this, _)
890
+ c(this, _)
873
891
  ),
874
- protocol: l(this, H),
892
+ protocol: c(this, v),
875
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
+ },
876
899
  body: a,
877
- scriptPath: c,
900
+ scriptPath: u,
878
901
  headers: i
879
902
  });
880
- } catch (u) {
881
- const p = u;
882
- if (p != null && p.response)
883
- return p.response;
884
- throw u;
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;
885
911
  }
886
912
  } finally {
887
913
  s();
888
914
  }
889
- }, I = new WeakSet(), K = function(t) {
890
- let r = removePathPrefix(t, l(this, _));
891
- 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";
892
- 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}`;
893
919
  if (this.php.fileExists(s))
894
920
  return s;
895
921
  throw new Error(`File not found: ${s}`);
@@ -930,6 +956,38 @@ function inferMimeType(e) {
930
956
  case "txt":
931
957
  case "md":
932
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";
933
991
  default:
934
992
  return "application-octet-stream";
935
993
  }
@@ -1040,10 +1098,10 @@ function rethrowFileSystemError(e = "") {
1040
1098
  try {
1041
1099
  return o.apply(this, i);
1042
1100
  } catch (a) {
1043
- const c = typeof a == "object" ? a == null ? void 0 : a.errno : null;
1044
- if (c in FileErrorCodes) {
1045
- const u = FileErrorCodes[c], p = typeof i[0] == "string" ? i[0] : null, ue = p !== null ? e.replaceAll("{path}", p) : e;
1046
- throw new Error(`${ue}: ${u}`, {
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}`, {
1047
1105
  cause: a
1048
1106
  });
1049
1107
  }
@@ -1099,7 +1157,7 @@ class PHPExecutionFailureError extends Error {
1099
1157
  super(t), this.response = r, this.source = s;
1100
1158
  }
1101
1159
  }
1102
- 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;
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;
1103
1161
  class BasePHP {
1104
1162
  /**
1105
1163
  * Initializes a PHP runtime.
@@ -1109,46 +1167,55 @@ class BasePHP {
1109
1167
  * @param serverOptions - Optional. Options for the PHPRequestHandler. If undefined, no request handler will be initialized.
1110
1168
  */
1111
1169
  constructor(e, t) {
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);
1112
1180
  d(this, N);
1181
+ d(this, U);
1113
1182
  d(this, L);
1114
- d(this, q);
1115
1183
  d(this, O);
1116
1184
  d(this, M);
1117
- d(this, D);
1118
1185
  d(this, $);
1186
+ d(this, D);
1187
+ d(this, q);
1119
1188
  d(this, j);
1120
- d(this, W);
1121
1189
  d(this, z);
1190
+ d(this, W);
1122
1191
  d(this, G);
1123
1192
  d(this, V);
1124
- d(this, S, void 0);
1125
- d(this, T, void 0);
1126
- d(this, C, void 0);
1193
+ d(this, J);
1194
+ d(this, R, void 0);
1195
+ d(this, F, void 0);
1196
+ d(this, H, void 0);
1127
1197
  d(this, y, void 0);
1128
1198
  d(this, w, void 0);
1129
- d(this, g, void 0);
1130
1199
  d(this, P, void 0);
1131
- d(this, A, void 0);
1132
- 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(
1133
- new PHPRequestHandler(this, t)
1134
- ));
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));
1135
1202
  }
1136
1203
  addEventListener(e, t) {
1137
- 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);
1138
1205
  }
1139
1206
  removeEventListener(e, t) {
1140
1207
  var r;
1141
- (r = l(this, P).get(e)) == null || r.delete(t);
1208
+ (r = c(this, P).get(e)) == null || r.delete(t);
1142
1209
  }
1143
1210
  dispatchEvent(e) {
1144
- const t = l(this, P).get(e.type);
1211
+ const t = c(this, P).get(e.type);
1145
1212
  if (t)
1146
1213
  for (const r of t)
1147
1214
  r(e);
1148
1215
  }
1149
1216
  /** @inheritDoc */
1150
1217
  async onMessage(e) {
1151
- l(this, A).push(e);
1218
+ c(this, T).push(e);
1152
1219
  }
1153
1220
  /** @inheritDoc */
1154
1221
  async setSpawnHandler(handler) {
@@ -1156,21 +1223,19 @@ class BasePHP {
1156
1223
  }
1157
1224
  /** @inheritDoc */
1158
1225
  get absoluteUrl() {
1159
- return this.requestHandler.requestHandler.absoluteUrl;
1226
+ return this.requestHandler.absoluteUrl;
1160
1227
  }
1161
1228
  /** @inheritDoc */
1162
1229
  get documentRoot() {
1163
- return this.requestHandler.requestHandler.documentRoot;
1230
+ return this.requestHandler.documentRoot;
1164
1231
  }
1165
1232
  /** @inheritDoc */
1166
1233
  pathToInternalUrl(e) {
1167
- return this.requestHandler.requestHandler.pathToInternalUrl(e);
1234
+ return this.requestHandler.pathToInternalUrl(e);
1168
1235
  }
1169
1236
  /** @inheritDoc */
1170
1237
  internalUrlToPath(e) {
1171
- return this.requestHandler.requestHandler.internalUrlToPath(
1172
- e
1173
- );
1238
+ return this.requestHandler.internalUrlToPath(e);
1174
1239
  }
1175
1240
  initializeRuntime(e) {
1176
1241
  if (this[__private__dont__use])
@@ -1179,7 +1244,7 @@ class BasePHP {
1179
1244
  if (!t)
1180
1245
  throw new Error("Invalid PHP runtime id.");
1181
1246
  this[__private__dont__use] = t, t.onMessage = async (r) => {
1182
- for (const s of l(this, A)) {
1247
+ for (const s of c(this, T)) {
1183
1248
  const n = await s(r);
1184
1249
  if (n)
1185
1250
  return n;
@@ -1200,13 +1265,13 @@ class BasePHP {
1200
1265
  throw new Error(
1201
1266
  "Could not set SAPI name. This can only be done before the PHP WASM module is initialized.Did you already dispatch any requests?"
1202
1267
  );
1203
- h(this, C, e);
1268
+ h(this, H, e);
1204
1269
  }
1205
1270
  /** @inheritDoc */
1206
1271
  setPhpIniPath(e) {
1207
- if (l(this, y))
1272
+ if (c(this, y))
1208
1273
  throw new Error("Cannot set PHP ini path after calling run().");
1209
- h(this, T, e), this[__private__dont__use].ccall(
1274
+ h(this, F, e), this[__private__dont__use].ccall(
1210
1275
  "wasm_set_phpini_path",
1211
1276
  null,
1212
1277
  ["string"],
@@ -1215,46 +1280,49 @@ class BasePHP {
1215
1280
  }
1216
1281
  /** @inheritDoc */
1217
1282
  setPhpIniEntry(e, t) {
1218
- if (l(this, y))
1283
+ if (c(this, y))
1219
1284
  throw new Error("Cannot set PHP ini entries after calling run().");
1220
- l(this, S).push([e, t]);
1285
+ c(this, R).push([e, t]);
1221
1286
  }
1222
1287
  /** @inheritDoc */
1223
1288
  chdir(e) {
1224
1289
  this[__private__dont__use].FS.chdir(e);
1225
1290
  }
1226
1291
  /** @inheritDoc */
1227
- async request(e, t) {
1292
+ async request(e) {
1228
1293
  if (!this.requestHandler)
1229
1294
  throw new Error("No request handler available.");
1230
- return this.requestHandler.request(e, t);
1295
+ return this.requestHandler.request(e);
1231
1296
  }
1232
1297
  /** @inheritDoc */
1233
1298
  async run(e) {
1234
1299
  const t = await this.semaphore.acquire();
1235
1300
  let r;
1236
1301
  try {
1237
- 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))
1238
1303
  throw new Error(
1239
1304
  `The script path "${e.scriptPath}" does not exist.`
1240
1305
  );
1241
- 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");
1242
- const s = normalizeHeaders(e.headers || {}), n = s.host || "example.com:443";
1243
- 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);
1244
- const o = e.env || {};
1245
- for (const a in o)
1246
- f(this, z, ae).call(this, a, o[a]);
1247
- const i = await f(this, V, ce).call(this);
1248
- if (i.exitCode !== 0) {
1249
- console.warn("PHP.run() output was:", i.text);
1250
- const a = new PHPExecutionFailureError(
1251
- `PHP.run() failed with exit code ${i.exitCode} and the following output: ` + i.errors,
1252
- i,
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,
1253
1321
  "request"
1254
1322
  );
1255
- throw console.error(a), a;
1323
+ throw console.error(l), l;
1256
1324
  }
1257
- return i;
1325
+ return u;
1258
1326
  } catch (s) {
1259
1327
  throw this.dispatchEvent({
1260
1328
  type: "request.error",
@@ -1272,9 +1340,6 @@ class BasePHP {
1272
1340
  }
1273
1341
  }
1274
1342
  }
1275
- addServerGlobalEntry(e, t) {
1276
- l(this, g)[e] = t;
1277
- }
1278
1343
  defineConstant(e, t) {
1279
1344
  let r = {};
1280
1345
  try {
@@ -1362,17 +1427,18 @@ class BasePHP {
1362
1427
  * interrupting the operations of this PHP instance.
1363
1428
  *
1364
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.
1365
1434
  */
1366
- hotSwapPHPRuntime(e) {
1367
- const t = this[__private__dont__use].FS;
1435
+ hotSwapPHPRuntime(e, t) {
1436
+ const r = this[__private__dont__use].FS;
1368
1437
  try {
1369
1438
  this.exit();
1370
1439
  } catch {
1371
1440
  }
1372
- if (this.initializeRuntime(e), l(this, T) && this.setPhpIniPath(l(this, T)), l(this, C) && this.setSapiName(l(this, C)), this.requestHandler) {
1373
- const r = this.documentRoot;
1374
- copyFS(t, this[__private__dont__use].FS, r);
1375
- }
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);
1376
1442
  }
1377
1443
  exit(e = 0) {
1378
1444
  this.dispatchEvent({
@@ -1385,7 +1451,17 @@ class BasePHP {
1385
1451
  h(this, y, !1), h(this, w, null), delete this[__private__dont__use].onMessage, delete this[__private__dont__use];
1386
1452
  }
1387
1453
  }
1388
- 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() {
1389
1465
  if (this.setPhpIniEntry("auto_prepend_file", "/internal/consts.php"), this.fileExists("/internal/consts.php") || this.writeFile(
1390
1466
  "/internal/consts.php",
1391
1467
  `<?php
@@ -1397,8 +1473,8 @@ S = new WeakMap(), T = new WeakMap(), C = new WeakMap(), y = new WeakMap(), w =
1397
1473
  }
1398
1474
  }
1399
1475
  }`
1400
- ), l(this, S).length > 0) {
1401
- 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(`
1402
1478
  `) + `
1403
1479
 
1404
1480
  `;
@@ -1410,7 +1486,7 @@ S = new WeakMap(), T = new WeakMap(), C = new WeakMap(), y = new WeakMap(), w =
1410
1486
  );
1411
1487
  }
1412
1488
  this[__private__dont__use].ccall("php_wasm_init", null, [], []);
1413
- }, L = new WeakSet(), X = function() {
1489
+ }, U = new WeakSet(), te = function() {
1414
1490
  const e = "/internal/headers.json";
1415
1491
  if (!this.fileExists(e))
1416
1492
  throw new Error(
@@ -1427,7 +1503,7 @@ S = new WeakMap(), T = new WeakMap(), C = new WeakMap(), y = new WeakMap(), w =
1427
1503
  headers: r,
1428
1504
  httpStatusCode: t.status
1429
1505
  };
1430
- }, q = new WeakSet(), ee = function(e) {
1506
+ }, L = new WeakSet(), re = function(e) {
1431
1507
  if (this[__private__dont__use].ccall(
1432
1508
  "wasm_set_request_uri",
1433
1509
  null,
@@ -1442,32 +1518,35 @@ S = new WeakMap(), T = new WeakMap(), C = new WeakMap(), y = new WeakMap(), w =
1442
1518
  [t]
1443
1519
  );
1444
1520
  }
1445
- }, O = new WeakSet(), te = function(e, t) {
1521
+ }, O = new WeakSet(), se = function(e) {
1446
1522
  this[__private__dont__use].ccall(
1447
1523
  "wasm_set_request_host",
1448
1524
  null,
1449
1525
  [STRING],
1450
1526
  [e]
1451
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) {
1452
1536
  let r;
1453
1537
  try {
1454
1538
  r = parseInt(new URL(e).port, 10);
1455
1539
  } catch {
1456
1540
  }
1457
- (!r || isNaN(r) || r === 80) && (r = t === "https" ? 443 : 80), this[__private__dont__use].ccall(
1458
- "wasm_set_request_port",
1459
- null,
1460
- [NUMBER],
1461
- [r]
1462
- ), (t === "https" || !t && r === 443) && this.addServerGlobalEntry("HTTPS", "on");
1463
- }, 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) {
1464
1543
  this[__private__dont__use].ccall(
1465
1544
  "wasm_set_request_method",
1466
1545
  null,
1467
1546
  [STRING],
1468
1547
  [e]
1469
1548
  );
1470
- }, D = new WeakSet(), se = function(e) {
1549
+ }, q = new WeakSet(), ae = function(e) {
1471
1550
  e.cookie && this[__private__dont__use].ccall(
1472
1551
  "wasm_set_cookies",
1473
1552
  null,
@@ -1484,14 +1563,7 @@ S = new WeakMap(), T = new WeakMap(), C = new WeakMap(), y = new WeakMap(), w =
1484
1563
  [NUMBER],
1485
1564
  [parseInt(e["content-length"], 10)]
1486
1565
  );
1487
- for (const t in e) {
1488
- let r = "HTTP_";
1489
- ["content-type", "content-length"].includes(t.toLowerCase()) && (r = ""), this.addServerGlobalEntry(
1490
- `${r}${t.toUpperCase().replace(/-/g, "_")}`,
1491
- e[t]
1492
- );
1493
- }
1494
- }, $ = new WeakSet(), ne = function(e) {
1566
+ }, j = new WeakSet(), le = function(e) {
1495
1567
  let t, r;
1496
1568
  typeof e == "string" ? (console.warn(
1497
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"
@@ -1514,46 +1586,45 @@ S = new WeakMap(), T = new WeakMap(), C = new WeakMap(), y = new WeakMap(), w =
1514
1586
  [NUMBER],
1515
1587
  [r]
1516
1588
  ), s;
1517
- }, j = new WeakSet(), ie = function(e) {
1589
+ }, z = new WeakSet(), ce = function(e) {
1518
1590
  this[__private__dont__use].ccall(
1519
1591
  "wasm_set_path_translated",
1520
1592
  null,
1521
1593
  [STRING],
1522
1594
  [e]
1523
1595
  );
1524
- }, W = new WeakSet(), oe = function() {
1525
- for (const e in l(this, g))
1526
- this[__private__dont__use].ccall(
1527
- "wasm_add_SERVER_entry",
1528
- null,
1529
- [STRING, STRING],
1530
- [e, l(this, g)[e]]
1531
- );
1532
- }, 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) {
1533
1604
  this[__private__dont__use].ccall(
1534
1605
  "wasm_add_ENV_entry",
1535
1606
  null,
1536
1607
  [STRING, STRING],
1537
1608
  [e, t]
1538
1609
  );
1539
- }, G = new WeakSet(), le = function(e) {
1610
+ }, V = new WeakSet(), he = function(e) {
1540
1611
  this[__private__dont__use].ccall(
1541
1612
  "wasm_set_php_code",
1542
1613
  null,
1543
1614
  [STRING],
1544
1615
  [e]
1545
1616
  );
1546
- }, V = new WeakSet(), ce = async function() {
1617
+ }, J = new WeakSet(), pe = async function() {
1547
1618
  var n;
1548
1619
  let e, t;
1549
1620
  try {
1550
1621
  e = await new Promise((o, i) => {
1551
- var c;
1552
- t = (u) => {
1553
- console.error(u), console.error(u.error);
1554
- const p = new Error("Rethrown");
1555
- p.cause = u.error, p.betterMessage = u.message, i(p);
1556
- }, (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(
1557
1628
  "error",
1558
1629
  t
1559
1630
  );
@@ -1567,19 +1638,19 @@ S = new WeakMap(), T = new WeakMap(), C = new WeakMap(), y = new WeakMap(), w =
1567
1638
  return a instanceof Promise ? a.then(o, i) : o(a);
1568
1639
  });
1569
1640
  } catch (o) {
1570
- for (const u in this)
1571
- typeof this[u] == "function" && (this[u] = () => {
1641
+ for (const l in this)
1642
+ typeof this[l] == "function" && (this[l] = () => {
1572
1643
  throw new Error(
1573
1644
  "PHP runtime has crashed – see the earlier error for details."
1574
1645
  );
1575
1646
  });
1576
1647
  this.functionsMaybeMissingFromAsyncify = getFunctionsMaybeMissingFromAsyncify();
1577
- const i = o, a = "betterMessage" in i ? i.betterMessage : i.message, c = new Error(a);
1578
- 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;
1579
1650
  } finally {
1580
- (n = l(this, w)) == null || n.removeEventListener("error", t), h(this, g, {});
1651
+ (n = c(this, w)) == null || n.removeEventListener("error", t);
1581
1652
  }
1582
- const { headers: r, httpStatusCode: s } = f(this, L, X).call(this);
1653
+ const { headers: r, httpStatusCode: s } = p(this, U, te).call(this);
1583
1654
  return new PHPResponse(
1584
1655
  e === 0 ? s : 500,
1585
1656
  r,
@@ -1650,23 +1721,32 @@ function isRemotePHP(e) {
1650
1721
  }
1651
1722
  function rotatePHPRuntime({
1652
1723
  php: e,
1653
- recreateRuntime: t,
1654
- 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
1655
1735
  }) {
1656
- let s = 0;
1657
- async function n() {
1658
- if (++s < r)
1736
+ let n = 0;
1737
+ async function o() {
1738
+ if (++n < s)
1659
1739
  return;
1660
- s = 0;
1661
- const o = await e.semaphore.acquire();
1740
+ n = 0;
1741
+ const i = await e.semaphore.acquire();
1662
1742
  try {
1663
- e.hotSwapPHPRuntime(await t());
1743
+ e.hotSwapPHPRuntime(await r(), t);
1664
1744
  } finally {
1665
- o();
1745
+ i();
1666
1746
  }
1667
1747
  }
1668
- return e.addEventListener("request.end", n), function() {
1669
- e.removeEventListener("request.end", n);
1748
+ return e.addEventListener("request.end", o), function() {
1749
+ e.removeEventListener("request.end", o);
1670
1750
  };
1671
1751
  }
1672
1752
  async function writeFiles(e, t, r, { rmRoot: s = !1 } = {}) {
@@ -1680,7 +1760,6 @@ export {
1680
1760
  BasePHP,
1681
1761
  DEFAULT_BASE_URL,
1682
1762
  LatestSupportedPHPVersion,
1683
- PHPBrowser,
1684
1763
  PHPRequestHandler,
1685
1764
  PHPResponse,
1686
1765
  SupportedPHPExtensionBundles,