@php-wasm/universal 3.1.1 → 3.1.3

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,8 +1,8 @@
1
- var q = (r) => {
1
+ var G = (r) => {
2
2
  throw TypeError(r);
3
3
  };
4
- var B = (r, e, t) => e.has(r) || q("Cannot " + t);
5
- var u = (r, e, t) => (B(r, e, "read from private field"), t ? t.call(r) : e.get(r)), y = (r, e, t) => e.has(r) ? q("Cannot add the same private member more than once") : e instanceof WeakSet ? e.add(r) : e.set(r, t), g = (r, e, t, s) => (B(r, e, "write to private field"), s ? s.call(r, t) : e.set(r, t), t), m = (r, e, t) => (B(r, e, "access private method"), t);
4
+ var W = (r, e, t) => e.has(r) || G("Cannot " + t);
5
+ var u = (r, e, t) => (W(r, e, "read from private field"), t ? t.call(r) : e.get(r)), y = (r, e, t) => e.has(r) ? G("Cannot add the same private member more than once") : e instanceof WeakSet ? e.add(r) : e.set(r, t), g = (r, e, t, s) => (W(r, e, "write to private field"), s ? s.call(r, t) : e.set(r, t), t), m = (r, e, t) => (W(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, basename, normalizePath, AcquireTimeoutError, splitShellCommand } from "@php-wasm/util";
@@ -311,19 +311,31 @@ class FSHelpers {
311
311
  e.mkdirTree(t);
312
312
  }
313
313
  static copyRecursive(e, t, s) {
314
- const n = e.lookupPath(t).node;
315
- if (e.isDir(n.mode)) {
316
- e.mkdirTree(s);
317
- const i = e.readdir(t).filter(
318
- (o) => o !== "." && o !== ".."
319
- );
320
- for (const o of i)
321
- FSHelpers.copyRecursive(
322
- e,
323
- joinPaths(t, o),
324
- joinPaths(s, o)
314
+ try {
315
+ const n = e.lookupPath(t).node;
316
+ if (e.isDir(n.mode)) {
317
+ if (t === s || s.startsWith(`${t}/`))
318
+ throw new ErrnoError(28);
319
+ e.mkdirTree(s);
320
+ const i = e.readdir(t).filter(
321
+ (o) => o !== "." && o !== ".."
325
322
  );
326
- } else e.isLink(n.mode) ? e.symlink(e.readlink(t), s) : e.writeFile(s, e.readFile(t));
323
+ for (const o of i)
324
+ FSHelpers.copyRecursive(
325
+ e,
326
+ joinPaths(t, o),
327
+ joinPaths(s, o)
328
+ );
329
+ } else e.isLink(n.mode) ? e.symlink(e.readlink(t), s) : e.writeFile(s, e.readFile(t));
330
+ } catch (n) {
331
+ const i = getEmscriptenFsError(n);
332
+ throw i ? new Error(
333
+ `Could not copy ${t} to ${s}: ${i}`,
334
+ {
335
+ cause: n
336
+ }
337
+ ) : n;
338
+ }
327
339
  }
328
340
  }
329
341
  FSHelpers.readFileAsText = rethrowFileSystemError('Could not read "{path}"')(
@@ -359,9 +371,6 @@ FSHelpers.fileExists = rethrowFileSystemError('Could not stat "{path}"')(
359
371
  FSHelpers.mkdir = rethrowFileSystemError('Could not create directory "{path}"')(
360
372
  FSHelpers.mkdir
361
373
  );
362
- FSHelpers.copyRecursive = rethrowFileSystemError(
363
- 'Could not copy files from "{path}"'
364
- )(FSHelpers.copyRecursive);
365
374
  const _private = /* @__PURE__ */ new WeakMap();
366
375
  var x;
367
376
  class PHPWorker {
@@ -431,6 +440,19 @@ class PHPWorker {
431
440
  async request(e) {
432
441
  return await _private.get(this).requestHandler.request(e);
433
442
  }
443
+ /**
444
+ * Handles a request with streaming support for large responses.
445
+ * Returns a StreamedPHPResponse that allows processing the response
446
+ * body incrementally without buffering the entire response in memory.
447
+ *
448
+ * This is useful for large file downloads (>2GB) that would otherwise
449
+ * exceed JavaScript's Uint8Array size limits.
450
+ *
451
+ * @param request - PHP Request data.
452
+ */
453
+ async requestStreamed(e) {
454
+ return await _private.get(this).requestHandler.requestStreamed(e);
455
+ }
434
456
  /** @inheritDoc @php-wasm/universal!/PHP.run */
435
457
  async run(e) {
436
458
  const { php: t, reap: s } = await this.acquirePHPInstance();
@@ -623,9 +645,67 @@ const currentJsRuntime = function() {
623
645
  201: "Created",
624
646
  200: "OK"
625
647
  };
626
- class StreamedPHPResponse {
648
+ var C;
649
+ const D = class D {
627
650
  constructor(e, t, s, n) {
628
- this.parsedHeaders = null, this.cachedStdoutBytes = null, this.cachedStderrText = null, this.headersStream = e, this.stdout = t, this.stderr = s, this.exitCode = n;
651
+ /**
652
+ * Response headers stream (internal).
653
+ */
654
+ y(this, C);
655
+ this.parsedHeaders = null, this.cachedStdoutBytes = null, this.cachedStderrText = null, g(this, C, e), this.stdout = t, this.stderr = s, this.exitCode = n;
656
+ }
657
+ /**
658
+ * Creates a StreamedPHPResponse from a buffered PHPResponse.
659
+ * Useful for unifying response handling when both types may be returned.
660
+ */
661
+ static fromPHPResponse(e) {
662
+ const t = new ReadableStream({
663
+ start(c) {
664
+ c.enqueue(e.bytes), c.close();
665
+ }
666
+ }), s = [];
667
+ for (const [c, l] of Object.entries(e.headers))
668
+ for (const d of l)
669
+ s.push(`${c}: ${d}`);
670
+ const n = JSON.stringify({
671
+ status: e.httpStatusCode,
672
+ headers: s
673
+ }), i = new ReadableStream({
674
+ start(c) {
675
+ c.enqueue(new TextEncoder().encode(n)), c.close();
676
+ }
677
+ }), o = new ReadableStream({
678
+ start(c) {
679
+ e.errors.length > 0 && c.enqueue(
680
+ new TextEncoder().encode(e.errors)
681
+ ), c.close();
682
+ }
683
+ }), a = new D(
684
+ i,
685
+ t,
686
+ o,
687
+ Promise.resolve(e.exitCode)
688
+ );
689
+ return a.parsedHeaders = Promise.resolve({
690
+ headers: e.headers,
691
+ httpStatusCode: e.httpStatusCode
692
+ }), a;
693
+ }
694
+ /**
695
+ * Creates a StreamedPHPResponse for a given HTTP status code.
696
+ * Shorthand for `StreamedPHPResponse.fromPHPResponse(PHPResponse.forHttpCode(...))`.
697
+ */
698
+ static forHttpCode(e, t = "") {
699
+ return D.fromPHPResponse(
700
+ PHPResponse.forHttpCode(e, t)
701
+ );
702
+ }
703
+ /**
704
+ * Returns the raw headers stream for serialization purposes.
705
+ * For parsed headers, use the `headers` property instead.
706
+ */
707
+ getHeadersStream() {
708
+ return u(this, C);
629
709
  }
630
710
  /**
631
711
  * True if the response is successful (HTTP status code 200-399),
@@ -685,9 +765,11 @@ class StreamedPHPResponse {
685
765
  return this.cachedStderrText || (this.cachedStderrText = streamToText(this.stderr)), this.cachedStderrText;
686
766
  }
687
767
  async getParsedHeaders() {
688
- return this.parsedHeaders || (this.parsedHeaders = parseHeadersStream(this.headersStream)), await this.parsedHeaders;
768
+ return this.parsedHeaders || (this.parsedHeaders = parseHeadersStream(u(this, C))), await this.parsedHeaders;
689
769
  }
690
- }
770
+ };
771
+ C = new WeakMap();
772
+ let StreamedPHPResponse = D;
691
773
  async function parseHeadersStream(r) {
692
774
  const e = await streamToText(r);
693
775
  let t;
@@ -961,7 +1043,7 @@ class PHPExecutionFailureError extends Error {
961
1043
  }
962
1044
  }
963
1045
  const PHP_INI_PATH = "/internal/shared/php.ini", AUTO_PREPEND_SCRIPT = "/internal/shared/auto_prepend_file.php", OPCACHE_FILE_FOLDER = "/internal/shared/opcache";
964
- var M, R, b, S, T, H, w, h, V, G, J, Y, X, Q, K, Z, D, ee, W, j;
1046
+ var M, R, b, S, H, T, w, p, J, Y, X, Q, K, Z, ee, te, j, re, q, $;
965
1047
  class PHP {
966
1048
  /**
967
1049
  * Initializes a PHP runtime.
@@ -971,7 +1053,7 @@ class PHP {
971
1053
  * @param requestHandlerOptions - Optional. Options for the PHPRequestHandler. If undefined, no request handler will be initialized.
972
1054
  */
973
1055
  constructor(r) {
974
- y(this, h);
1056
+ y(this, p);
975
1057
  y(this, M);
976
1058
  y(this, R, !1);
977
1059
  y(this, b, null);
@@ -979,8 +1061,8 @@ class PHP {
979
1061
  // Listen to all events
980
1062
  ["*", /* @__PURE__ */ new Set()]
981
1063
  ]));
982
- y(this, T, []);
983
- y(this, H, {});
1064
+ y(this, H, []);
1065
+ y(this, T, {});
984
1066
  y(this, w, {
985
1067
  enabled: !1,
986
1068
  recreateRuntime: () => 0,
@@ -1058,8 +1140,8 @@ class PHP {
1058
1140
  * @param listener Callback function to handle the message.
1059
1141
  */
1060
1142
  onMessage(r) {
1061
- return u(this, T).push(r), async () => {
1062
- g(this, T, u(this, T).filter(
1143
+ return u(this, H).push(r), async () => {
1144
+ g(this, H, u(this, H).filter(
1063
1145
  (e) => e !== r
1064
1146
  ));
1065
1147
  };
@@ -1153,7 +1235,7 @@ class PHP {
1153
1235
  }
1154
1236
  `
1155
1237
  ), e.onMessage = async (t) => {
1156
- for (const s of u(this, T)) {
1238
+ for (const s of u(this, H)) {
1157
1239
  const n = await s(t);
1158
1240
  if (n)
1159
1241
  return n;
@@ -1396,7 +1478,7 @@ class PHP {
1396
1478
  async runStream(r) {
1397
1479
  const e = await this.semaphore.acquire();
1398
1480
  let t;
1399
- const s = m(this, h, j).call(this, async () => {
1481
+ const s = m(this, p, $).call(this, async () => {
1400
1482
  if (u(this, R) || (await this[__private__dont__use].ccall(
1401
1483
  "php_wasm_init",
1402
1484
  null,
@@ -1409,22 +1491,22 @@ class PHP {
1409
1491
  throw new Error(
1410
1492
  `The script path "${r.scriptPath}" does not exist.`
1411
1493
  );
1412
- m(this, h, G).call(this, r.relativeUri || ""), m(this, h, Q).call(this, r.method || "GET");
1413
- const i = normalizeHeaders(r.headers || {}), o = i.host || "example.com:443", a = m(this, h, X).call(this, o, r.protocol || "http");
1414
- if (m(this, h, J).call(this, o), m(this, h, Y).call(this, a), m(this, h, K).call(this, i), r.body && (t = m(this, h, Z).call(this, r.body)), typeof r.code == "string")
1415
- this.writeFile("/internal/eval.php", r.code), m(this, h, D).call(this, "/internal/eval.php");
1494
+ m(this, p, Y).call(this, r.relativeUri || ""), m(this, p, Z).call(this, r.method || "GET");
1495
+ const i = normalizeHeaders(r.headers || {}), o = i.host || "example.com:443", a = m(this, p, K).call(this, o, r.protocol || "http");
1496
+ if (m(this, p, X).call(this, o), m(this, p, Q).call(this, a), m(this, p, ee).call(this, i), r.body && (t = m(this, p, te).call(this, r.body)), typeof r.code == "string")
1497
+ this.writeFile("/internal/eval.php", r.code), m(this, p, j).call(this, "/internal/eval.php");
1416
1498
  else if (typeof r.scriptPath == "string")
1417
- m(this, h, D).call(this, r.scriptPath || "");
1499
+ m(this, p, j).call(this, r.scriptPath || "");
1418
1500
  else
1419
1501
  throw new TypeError(
1420
1502
  "The request object must have either a `code` or a `scriptPath` property."
1421
1503
  );
1422
- const c = m(this, h, V).call(this, r.$_SERVER, i, a);
1504
+ const c = m(this, p, J).call(this, r.$_SERVER, i, a);
1423
1505
  for (const d in c)
1424
- m(this, h, ee).call(this, d, c[d]);
1506
+ m(this, p, re).call(this, d, c[d]);
1425
1507
  const l = r.env || {};
1426
1508
  for (const d in l)
1427
- m(this, h, W).call(this, d, l[d]);
1509
+ m(this, p, q).call(this, d, l[d]);
1428
1510
  return await this[__private__dont__use].ccall(
1429
1511
  "wasm_sapi_handle_request",
1430
1512
  NUMBER,
@@ -1542,8 +1624,8 @@ class PHP {
1542
1624
  * Moves a file or directory in the PHP filesystem to a
1543
1625
  * new location.
1544
1626
  *
1545
- * @param oldPath The path to rename.
1546
- * @param newPath The new path.
1627
+ * @param fromPath The path to rename.
1628
+ * @param toPath The new path.
1547
1629
  */
1548
1630
  mv(r, e) {
1549
1631
  const t = FSHelpers.mv(
@@ -1553,6 +1635,21 @@ class PHP {
1553
1635
  );
1554
1636
  return this.dispatchEvent({ type: "filesystem.write" }), t;
1555
1637
  }
1638
+ /**
1639
+ * Copies a file or directory in the PHP filesystem to a
1640
+ * new location.
1641
+ *
1642
+ * @param fromPath The source path.
1643
+ * @param toPath The target path.
1644
+ */
1645
+ cp(r, e) {
1646
+ const t = FSHelpers.copyRecursive(
1647
+ this[__private__dont__use].FS,
1648
+ r,
1649
+ e
1650
+ );
1651
+ return this.dispatchEvent({ type: "filesystem.write" }), t;
1652
+ }
1556
1653
  /**
1557
1654
  * Removes a directory from the PHP filesystem.
1558
1655
  *
@@ -1672,13 +1769,13 @@ class PHP {
1672
1769
  async hotSwapPHPRuntime(r) {
1673
1770
  const e = this[__private__dont__use].FS, t = this.listFiles("/").map((c) => `/${c}`), s = this[__private__dont__use].spawnProcess, n = e.cwd();
1674
1771
  e.chdir("/");
1675
- const i = Object.entries(u(this, H)).map(
1772
+ const i = Object.entries(u(this, T)).map(
1676
1773
  ([c, l]) => ({
1677
1774
  mountHandler: l.mountHandler,
1678
1775
  vfsPath: c
1679
1776
  })
1680
1777
  ), o = Object.values(
1681
- u(this, H)
1778
+ u(this, T)
1682
1779
  ).reverse();
1683
1780
  for (const c of o)
1684
1781
  await c.unmount();
@@ -1718,10 +1815,10 @@ class PHP {
1718
1815
  ), s = {
1719
1816
  mountHandler: e,
1720
1817
  unmount: async () => {
1721
- await t(), delete u(this, H)[r];
1818
+ await t(), delete u(this, T)[r];
1722
1819
  }
1723
1820
  };
1724
- return u(this, H)[r] = s, () => {
1821
+ return u(this, T)[r] = s, () => {
1725
1822
  s.unmount();
1726
1823
  };
1727
1824
  }
@@ -1743,10 +1840,10 @@ class PHP {
1743
1840
  return this.subProcess(r, e);
1744
1841
  u(this, R) && (u(this, w).needsRotating = !0);
1745
1842
  const t = await this.semaphore.acquire();
1746
- return await m(this, h, j).call(this, () => {
1843
+ return await m(this, p, $).call(this, () => {
1747
1844
  const s = e.env || {};
1748
1845
  for (const [n, i] of Object.entries(s))
1749
- m(this, h, W).call(this, n, i);
1846
+ m(this, p, q).call(this, n, i);
1750
1847
  r = [r[0], "-c", PHP_INI_PATH, ...r.slice(1)];
1751
1848
  for (const n of r)
1752
1849
  this[__private__dont__use].ccall(
@@ -1837,7 +1934,7 @@ class PHP {
1837
1934
  this.exit(0);
1838
1935
  }
1839
1936
  }
1840
- M = new WeakMap(), R = new WeakMap(), b = new WeakMap(), S = new WeakMap(), T = new WeakMap(), H = new WeakMap(), w = new WeakMap(), h = new WeakSet(), /**
1937
+ M = new WeakMap(), R = new WeakMap(), b = new WeakMap(), S = new WeakMap(), H = new WeakMap(), T = new WeakMap(), w = new WeakMap(), p = new WeakSet(), /**
1841
1938
  * Prepares the $_SERVER entries for the PHP runtime.
1842
1939
  *
1843
1940
  * @param defaults Default entries to include in $_SERVER.
@@ -1846,7 +1943,7 @@ M = new WeakMap(), R = new WeakMap(), b = new WeakMap(), S = new WeakMap(), T =
1846
1943
  * was provided.
1847
1944
  * @returns Computed $_SERVER entries.
1848
1945
  */
1849
- V = function(r, e, t) {
1946
+ J = function(r, e, t) {
1850
1947
  const s = {
1851
1948
  ...r || {}
1852
1949
  };
@@ -1856,7 +1953,7 @@ V = function(r, e, t) {
1856
1953
  ["content-type", "content-length"].includes(n.toLowerCase()) && (i = ""), s[`${i}${n.toUpperCase().replace(/-/g, "_")}`] = e[n];
1857
1954
  }
1858
1955
  return s;
1859
- }, G = function(r) {
1956
+ }, Y = function(r) {
1860
1957
  this[__private__dont__use].ccall(
1861
1958
  "wasm_set_request_uri",
1862
1959
  null,
@@ -1870,35 +1967,35 @@ V = function(r, e, t) {
1870
1967
  [STRING],
1871
1968
  [e]
1872
1969
  );
1873
- }, J = function(r) {
1970
+ }, X = function(r) {
1874
1971
  this[__private__dont__use].ccall(
1875
1972
  "wasm_set_request_host",
1876
1973
  null,
1877
1974
  [STRING],
1878
1975
  [r]
1879
1976
  );
1880
- }, Y = function(r) {
1977
+ }, Q = function(r) {
1881
1978
  this[__private__dont__use].ccall(
1882
1979
  "wasm_set_request_port",
1883
1980
  null,
1884
1981
  [NUMBER],
1885
1982
  [r]
1886
1983
  );
1887
- }, X = function(r, e) {
1984
+ }, K = function(r, e) {
1888
1985
  let t;
1889
1986
  try {
1890
1987
  t = parseInt(new URL(r).port, 10);
1891
1988
  } catch {
1892
1989
  }
1893
1990
  return (!t || isNaN(t) || t === 80) && (t = e === "https" ? 443 : 80), t;
1894
- }, Q = function(r) {
1991
+ }, Z = function(r) {
1895
1992
  this[__private__dont__use].ccall(
1896
1993
  "wasm_set_request_method",
1897
1994
  null,
1898
1995
  [STRING],
1899
1996
  [r]
1900
1997
  );
1901
- }, K = function(r) {
1998
+ }, ee = function(r) {
1902
1999
  r.cookie && this[__private__dont__use].ccall(
1903
2000
  "wasm_set_cookies",
1904
2001
  null,
@@ -1915,7 +2012,7 @@ V = function(r, e, t) {
1915
2012
  [NUMBER],
1916
2013
  [parseInt(r["content-length"], 10)]
1917
2014
  );
1918
- }, Z = function(r) {
2015
+ }, te = function(r) {
1919
2016
  let e, t;
1920
2017
  typeof r == "string" ? (logger.warn(
1921
2018
  "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"
@@ -1938,54 +2035,54 @@ V = function(r, e, t) {
1938
2035
  [NUMBER],
1939
2036
  [t]
1940
2037
  ), s;
1941
- }, D = function(r) {
2038
+ }, j = function(r) {
1942
2039
  this[__private__dont__use].ccall(
1943
2040
  "wasm_set_path_translated",
1944
2041
  null,
1945
2042
  [STRING],
1946
2043
  [r]
1947
2044
  );
1948
- }, ee = function(r, e) {
2045
+ }, re = function(r, e) {
1949
2046
  this[__private__dont__use].ccall(
1950
2047
  "wasm_add_SERVER_entry",
1951
2048
  null,
1952
2049
  [STRING, STRING],
1953
2050
  [r, e]
1954
2051
  );
1955
- }, W = function(r, e) {
2052
+ }, q = function(r, e) {
1956
2053
  this[__private__dont__use].ccall(
1957
2054
  "wasm_add_ENV_entry",
1958
2055
  null,
1959
2056
  [STRING, STRING],
1960
2057
  [r, e]
1961
2058
  );
1962
- }, j = async function(r) {
2059
+ }, $ = async function(r) {
1963
2060
  u(this, w).enabled && u(this, w).needsRotating && await this.rotateRuntime(), ++u(this, w).requestsMade, u(this, w).requestsMade >= u(this, w).maxRequests && (u(this, w).needsRotating = !0);
1964
2061
  const e = this[__private__dont__use], t = await createInvertedReadableStream();
1965
- e.onHeaders = (p) => {
1966
- a || s || t.controller.enqueue(p.slice());
2062
+ e.onHeaders = (h) => {
2063
+ a || s || t.controller.enqueue(h.slice());
1967
2064
  };
1968
2065
  let s = !1;
1969
2066
  const n = () => {
1970
2067
  s || (s = !0, t.controller.close());
1971
2068
  }, i = await createInvertedReadableStream();
1972
- e.onStdout = (p) => {
1973
- n(), !a && i.controller.enqueue(p.slice());
2069
+ e.onStdout = (h) => {
2070
+ n(), !a && i.controller.enqueue(h.slice());
1974
2071
  };
1975
2072
  const o = await createInvertedReadableStream();
1976
- e.onStderr = (p) => {
1977
- a || o.controller.enqueue(p.slice());
2073
+ e.onStderr = (h) => {
2074
+ a || o.controller.enqueue(h.slice());
1978
2075
  };
1979
2076
  let a = !1, c;
1980
2077
  const d = (async () => {
1981
- var p;
2078
+ var h;
1982
2079
  try {
1983
2080
  return await Promise.race([
1984
2081
  r(),
1985
2082
  new Promise((_, F) => {
1986
2083
  var z;
1987
- c = ($) => {
1988
- isExitCode($.error) || F($.error);
2084
+ c = (V) => {
2085
+ isExitCode(V.error) || F(V.error);
1989
2086
  }, (z = u(this, b)) == null || z.addEventListener(
1990
2087
  "error",
1991
2088
  c,
@@ -2005,27 +2102,27 @@ V = function(r, e, t) {
2005
2102
  });
2006
2103
  throw this.functionsMaybeMissingFromAsyncify = getFunctionsMaybeMissingFromAsyncify(), f;
2007
2104
  } finally {
2008
- a || (i.controller.close(), o.controller.close(), n(), a = !0), (p = u(this, b)) == null || p.removeEventListener(
2105
+ a || (i.controller.close(), o.controller.close(), n(), a = !0), (h = u(this, b)) == null || h.removeEventListener(
2009
2106
  "error",
2010
2107
  c
2011
2108
  );
2012
2109
  }
2013
2110
  })().then(
2014
- (p) => (p !== 0 && this.dispatchEvent({
2111
+ (h) => (h !== 0 && this.dispatchEvent({
2015
2112
  type: "request.error",
2016
2113
  error: new Error(
2017
- `PHP.run() failed with exit code ${p}.`
2114
+ `PHP.run() failed with exit code ${h}.`
2018
2115
  ),
2019
2116
  // Distinguish between PHP request and PHP-wasm errors
2020
2117
  source: "php-wasm"
2021
- }), p),
2022
- (p) => {
2023
- const f = p.source ?? "php-wasm";
2118
+ }), h),
2119
+ (h) => {
2120
+ const f = h.source ?? "php-wasm";
2024
2121
  throw this.dispatchEvent({
2025
2122
  type: "request.error",
2026
- error: p,
2123
+ error: h,
2027
2124
  source: f
2028
- }), p;
2125
+ }), h;
2029
2126
  }
2030
2127
  );
2031
2128
  return new StreamedPHPResponse(
@@ -2468,7 +2565,7 @@ const _default = "application/octet-stream", asx = "video/x-ms-asf", atom = "app
2468
2565
  xspf,
2469
2566
  zip
2470
2567
  };
2471
- var v, C, N, L, I, E, A, k, O, P, te, U, re, se, ne;
2568
+ var v, I, O, L, A, E, N, k, U, P, se, B, ne, ie, oe;
2472
2569
  class PHPRequestHandler {
2473
2570
  /**
2474
2571
  * The request handler needs to decide whether to serve a static asset or
@@ -2484,14 +2581,14 @@ class PHPRequestHandler {
2484
2581
  constructor(e) {
2485
2582
  y(this, P);
2486
2583
  y(this, v);
2487
- y(this, C);
2488
- y(this, N);
2489
- y(this, L);
2490
2584
  y(this, I);
2491
- y(this, E);
2585
+ y(this, O);
2586
+ y(this, L);
2492
2587
  y(this, A);
2588
+ y(this, E);
2589
+ y(this, N);
2493
2590
  y(this, k);
2494
- y(this, O);
2591
+ y(this, U);
2495
2592
  const {
2496
2593
  documentRoot: t = "/www/",
2497
2594
  absoluteUrl: s = typeof location == "object" ? location.href : DEFAULT_BASE_URL,
@@ -2508,11 +2605,11 @@ class PHPRequestHandler {
2508
2605
  else if (e.phpFactory)
2509
2606
  this.instanceManager = new PHPProcessManager({
2510
2607
  phpFactory: async (d) => {
2511
- const p = await e.phpFactory({
2608
+ const h = await e.phpFactory({
2512
2609
  ...d,
2513
2610
  requestHandler: this
2514
2611
  });
2515
- return a(p), p;
2612
+ return a(h), h;
2516
2613
  },
2517
2614
  maxPhpInstances: e.maxPhpInstances
2518
2615
  });
@@ -2522,16 +2619,16 @@ class PHPRequestHandler {
2522
2619
  );
2523
2620
  g(this, k, e.cookieStore === void 0 ? new HttpCookieStore() : e.cookieStore), g(this, v, t);
2524
2621
  const c = new URL(s);
2525
- g(this, N, c.hostname), g(this, L, c.port ? Number(c.port) : c.protocol === "https:" ? 443 : 80), g(this, C, (c.protocol || "").replace(":", ""));
2622
+ g(this, O, c.hostname), g(this, L, c.port ? Number(c.port) : c.protocol === "https:" ? 443 : 80), g(this, I, (c.protocol || "").replace(":", ""));
2526
2623
  const l = u(this, L) !== 443 && u(this, L) !== 80;
2527
- g(this, I, [
2528
- u(this, N),
2624
+ g(this, A, [
2625
+ u(this, O),
2529
2626
  l ? `:${u(this, L)}` : ""
2530
- ].join("")), g(this, E, c.pathname.replace(/\/+$/, "")), g(this, A, [
2531
- `${u(this, C)}://`,
2532
- u(this, I),
2627
+ ].join("")), g(this, E, c.pathname.replace(/\/+$/, "")), g(this, N, [
2628
+ `${u(this, I)}://`,
2629
+ u(this, A),
2533
2630
  u(this, E)
2534
- ].join("")), this.rewriteRules = n, g(this, O, i), this.getFileNotFoundAction = o;
2631
+ ].join("")), this.rewriteRules = n, g(this, U, i), this.getFileNotFoundAction = o;
2535
2632
  }
2536
2633
  async getPrimaryPhp() {
2537
2634
  return await this.instanceManager.getPrimaryPhp();
@@ -2561,7 +2658,7 @@ class PHPRequestHandler {
2561
2658
  * The absolute URL of this PHPRequestHandler instance.
2562
2659
  */
2563
2660
  get absoluteUrl() {
2564
- return u(this, A);
2661
+ return u(this, N);
2565
2662
  }
2566
2663
  /**
2567
2664
  * The directory in the PHP filesystem where the server will look
@@ -2619,11 +2716,32 @@ class PHPRequestHandler {
2619
2716
  * @param request - PHP Request data.
2620
2717
  */
2621
2718
  async request(e) {
2719
+ const t = await this.requestStreamed(e), s = await PHPResponse.fromStreamedResponse(t);
2720
+ return s.ok() && s.exitCode !== 0 ? new PHPResponse(
2721
+ 500,
2722
+ s.headers,
2723
+ s.bytes,
2724
+ s.errors,
2725
+ s.exitCode
2726
+ ) : s;
2727
+ }
2728
+ /**
2729
+ * Serves the request with streaming support – returns a StreamedPHPResponse
2730
+ * that allows processing the response body incrementally without buffering
2731
+ * the entire response in memory.
2732
+ *
2733
+ * This is useful for large file downloads (>2GB) that would otherwise
2734
+ * exceed JavaScript's Uint8Array size limits.
2735
+ *
2736
+ * @param request - PHP Request data.
2737
+ * @returns A StreamedPHPResponse.
2738
+ */
2739
+ async requestStreamed(e) {
2622
2740
  const t = looksLikeAbsoluteUrl(e.url), s = new URL(
2623
2741
  // Remove the hash part of the URL as it's not meant for the server.
2624
2742
  e.url.split("#")[0],
2625
2743
  t ? void 0 : DEFAULT_BASE_URL
2626
- ), n = m(this, P, te).call(this, s), i = await this.getPrimaryPhp(), o = removePathPrefix(
2744
+ ), n = m(this, P, se).call(this, s), i = await this.getPrimaryPhp(), o = removePathPrefix(
2627
2745
  /**
2628
2746
  * URL.pathname returns a URL-encoded path. We need to decode it
2629
2747
  * before using it as a filesystem path.
@@ -2631,13 +2749,15 @@ class PHPRequestHandler {
2631
2749
  decodeURIComponent(n.pathname),
2632
2750
  u(this, E)
2633
2751
  );
2634
- let a = m(this, P, U).call(this, o);
2752
+ let a = m(this, P, B).call(this, o);
2635
2753
  if (i.isDir(a)) {
2636
2754
  if (!o.endsWith("/"))
2637
- return new PHPResponse(
2638
- 301,
2639
- { Location: [`${n.pathname}/`] },
2640
- new Uint8Array(0)
2755
+ return StreamedPHPResponse.fromPHPResponse(
2756
+ new PHPResponse(
2757
+ 301,
2758
+ { Location: [`${n.pathname}/`] },
2759
+ new Uint8Array(0)
2760
+ )
2641
2761
  );
2642
2762
  for (const c of ["index.php", "index.html"]) {
2643
2763
  const l = joinPaths(a, c);
@@ -2654,10 +2774,10 @@ class PHPRequestHandler {
2654
2774
  let c = o;
2655
2775
  for (; c.startsWith("/") && c !== dirname(c); ) {
2656
2776
  c = dirname(c);
2657
- const l = m(this, P, U).call(this, c);
2777
+ const l = m(this, P, B).call(this, c);
2658
2778
  if (i.isFile(l) && // Only run partial path resolution for PHP files.
2659
2779
  l.endsWith(".php")) {
2660
- a = m(this, P, U).call(this, c);
2780
+ a = m(this, P, B).call(this, c);
2661
2781
  break;
2662
2782
  }
2663
2783
  }
@@ -2668,32 +2788,23 @@ class PHPRequestHandler {
2668
2788
  );
2669
2789
  switch (c.type) {
2670
2790
  case "response":
2671
- return c.response;
2791
+ return StreamedPHPResponse.fromPHPResponse(
2792
+ c.response
2793
+ );
2672
2794
  case "internal-redirect":
2673
2795
  a = joinPaths(u(this, v), c.uri);
2674
2796
  break;
2675
2797
  case "404":
2676
- return PHPResponse.forHttpCode(404);
2798
+ return StreamedPHPResponse.forHttpCode(404);
2677
2799
  default:
2678
2800
  throw new Error(
2679
2801
  `Unsupported file-not-found action type: '${c.type}'`
2680
2802
  );
2681
2803
  }
2682
2804
  }
2683
- if (i.isFile(a))
2684
- if (a.endsWith(".php")) {
2685
- const c = await m(this, P, se).call(this, e, s, n, a);
2686
- return c.ok() && c.exitCode !== 0 ? new PHPResponse(
2687
- 500,
2688
- c.headers,
2689
- c.bytes,
2690
- c.errors,
2691
- c.exitCode
2692
- ) : c;
2693
- } else
2694
- return m(this, P, re).call(this, i, a);
2695
- else
2696
- return PHPResponse.forHttpCode(404);
2805
+ return i.isFile(a) ? a.endsWith(".php") ? await m(this, P, ie).call(this, e, s, n, a) : StreamedPHPResponse.fromPHPResponse(
2806
+ m(this, P, ne).call(this, i, a)
2807
+ ) : StreamedPHPResponse.forHttpCode(404);
2697
2808
  }
2698
2809
  /**
2699
2810
  * Computes the essential $_SERVER entries for a request.
@@ -2787,7 +2898,7 @@ class PHPRequestHandler {
2787
2898
  const n = {
2788
2899
  REMOTE_ADDR: "127.0.0.1",
2789
2900
  DOCUMENT_ROOT: u(this, v),
2790
- HTTPS: u(this, A).startsWith("https://") ? "on" : ""
2901
+ HTTPS: u(this, N).startsWith("https://") ? "on" : ""
2791
2902
  };
2792
2903
  return n.REQUEST_URI = e.pathname + e.search, s.startsWith(u(this, v)) && (n.SCRIPT_NAME = s.substring(
2793
2904
  u(this, v).length
@@ -2802,13 +2913,13 @@ class PHPRequestHandler {
2802
2913
  await this.instanceManager[Symbol.asyncDispose]();
2803
2914
  }
2804
2915
  }
2805
- v = new WeakMap(), C = new WeakMap(), N = new WeakMap(), L = new WeakMap(), I = new WeakMap(), E = new WeakMap(), A = new WeakMap(), k = new WeakMap(), O = new WeakMap(), P = new WeakSet(), /**
2916
+ v = new WeakMap(), I = new WeakMap(), O = new WeakMap(), L = new WeakMap(), A = new WeakMap(), E = new WeakMap(), N = new WeakMap(), k = new WeakMap(), U = new WeakMap(), P = new WeakSet(), /**
2806
2917
  * Apply the rewrite rules to the original request URL.
2807
2918
  *
2808
2919
  * @param originalRequestUrl - The original request URL.
2809
2920
  * @returns The rewritten request URL.
2810
2921
  */
2811
- te = function(e) {
2922
+ se = function(e) {
2812
2923
  const t = removePathPrefix(
2813
2924
  decodeURIComponent(e.pathname),
2814
2925
  u(this, E)
@@ -2831,8 +2942,8 @@ te = function(e) {
2831
2942
  * @param urlPath - The URL path to resolve (e.g., '/phpmyadmin/index.php')
2832
2943
  * @returns The resolved filesystem path
2833
2944
  */
2834
- U = function(e) {
2835
- for (const t of u(this, O))
2945
+ B = function(e) {
2946
+ for (const t of u(this, U))
2836
2947
  if (e === t.urlPrefix || e.startsWith(t.urlPrefix + "/")) {
2837
2948
  const s = e.slice(t.urlPrefix.length);
2838
2949
  return joinPaths(t.fsPath, s);
@@ -2844,7 +2955,7 @@ U = function(e) {
2844
2955
  * @param fsPath - Absolute path of the static file to serve.
2845
2956
  * @returns The response.
2846
2957
  */
2847
- re = function(e, t) {
2958
+ ne = function(e, t) {
2848
2959
  const s = e.readFileAsBuffer(t);
2849
2960
  return new PHPResponse(
2850
2961
  200,
@@ -2859,57 +2970,58 @@ re = function(e, t) {
2859
2970
  },
2860
2971
  s
2861
2972
  );
2862
- }, se = async function(e, t, s, n) {
2973
+ }, ie = async function(e, t, s, n) {
2863
2974
  let i;
2864
2975
  try {
2865
2976
  i = await this.instanceManager.acquirePHPInstance();
2866
- } catch (o) {
2867
- return o instanceof MaxPhpInstancesError ? PHPResponse.forHttpCode(502) : PHPResponse.forHttpCode(500);
2977
+ } catch (a) {
2978
+ return a instanceof MaxPhpInstancesError ? StreamedPHPResponse.forHttpCode(502) : StreamedPHPResponse.forHttpCode(500);
2868
2979
  }
2980
+ let o;
2869
2981
  try {
2870
- return await m(this, P, ne).call(this, i.php, e, t, s, n);
2871
- } finally {
2872
- i.reap();
2873
- }
2874
- }, ne = async function(e, t, s, n, i) {
2982
+ o = await m(this, P, oe).call(this, i.php, e, t, s, n);
2983
+ } catch (a) {
2984
+ throw i.reap(), a;
2985
+ }
2986
+ return o.finished.finally(() => {
2987
+ i == null || i.reap();
2988
+ }), o;
2989
+ }, oe = async function(e, t, s, n, i) {
2875
2990
  let o = "GET";
2876
2991
  const a = {
2877
- host: u(this, I),
2992
+ host: u(this, A),
2878
2993
  ...normalizeHeaders(t.headers || {})
2879
2994
  };
2880
2995
  u(this, k) && (a.cookie = u(this, k).getCookieRequestHeader());
2881
2996
  let c = t.body;
2882
2997
  if (typeof c == "object" && !(c instanceof Uint8Array)) {
2883
2998
  o = "POST";
2884
- const { bytes: l, contentType: d } = await encodeAsMultipart(c);
2885
- c = l, a["content-type"] = d;
2999
+ const { bytes: d, contentType: h } = await encodeAsMultipart(c);
3000
+ c = d, a["content-type"] = h;
2886
3001
  }
2887
- try {
2888
- const l = await e.run({
2889
- relativeUri: ensurePathPrefix(
2890
- toRelativeUrl(new URL(n.toString())),
2891
- u(this, E)
2892
- ),
2893
- protocol: u(this, C),
2894
- method: t.method || o,
2895
- $_SERVER: this.prepare_$_SERVER_superglobal(
2896
- s,
2897
- n,
2898
- i
2899
- ),
2900
- body: c,
2901
- scriptPath: i,
2902
- headers: a
3002
+ const l = await e.runStream({
3003
+ relativeUri: ensurePathPrefix(
3004
+ toRelativeUrl(new URL(n.toString())),
3005
+ u(this, E)
3006
+ ),
3007
+ protocol: u(this, I),
3008
+ method: t.method || o,
3009
+ $_SERVER: this.prepare_$_SERVER_superglobal(
3010
+ s,
3011
+ n,
3012
+ i
3013
+ ),
3014
+ body: c,
3015
+ scriptPath: i,
3016
+ headers: a
3017
+ });
3018
+ if (u(this, k)) {
3019
+ const d = u(this, k);
3020
+ l.headers.then((h) => {
3021
+ d.rememberCookiesFromResponseHeaders(h);
2903
3022
  });
2904
- return u(this, k) && u(this, k).rememberCookiesFromResponseHeaders(
2905
- l.headers
2906
- ), l;
2907
- } catch (l) {
2908
- const d = l;
2909
- if (d != null && d.response)
2910
- return d.response;
2911
- throw l;
2912
3023
  }
3024
+ return l;
2913
3025
  };
2914
3026
  function inferMimeType(r) {
2915
3027
  const e = r.split(".").pop();
@@ -2957,12 +3069,12 @@ function ensureProxyFSHasMmapSupport(r) {
2957
3069
  const d = t.malloc(o);
2958
3070
  if (!d)
2959
3071
  throw new n.ErrnoError(48);
2960
- const p = t.HEAPU8.subarray(d, d + o);
3072
+ const h = t.HEAPU8.subarray(d, d + o);
2961
3073
  let f = 0;
2962
3074
  for (; f < o; ) {
2963
3075
  const _ = i.stream_ops.read(
2964
3076
  i,
2965
- p,
3077
+ h,
2966
3078
  f,
2967
3079
  o - f,
2968
3080
  f
@@ -3253,18 +3365,18 @@ function expose(r, e = globalThis, t = ["*"], s) {
3253
3365
  }, l = (i.data.argumentList || []).map(fromWireValue);
3254
3366
  let d;
3255
3367
  try {
3256
- const p = c.slice(0, -1).reduce((_, F) => _[F], r), f = c.reduce((_, F) => _[F], r);
3368
+ const h = c.slice(0, -1).reduce((_, F) => _[F], r), f = c.reduce((_, F) => _[F], r);
3257
3369
  switch (a) {
3258
3370
  case MessageType.GET:
3259
3371
  d = f;
3260
3372
  break;
3261
3373
  case MessageType.SET:
3262
- p[c.slice(-1)[0]] = fromWireValue(
3374
+ h[c.slice(-1)[0]] = fromWireValue(
3263
3375
  i.data.value
3264
3376
  ), d = !0;
3265
3377
  break;
3266
3378
  case MessageType.APPLY:
3267
- d = f.apply(p, l);
3379
+ d = f.apply(h, l);
3268
3380
  break;
3269
3381
  case MessageType.CONSTRUCT:
3270
3382
  {
@@ -3284,18 +3396,18 @@ function expose(r, e = globalThis, t = ["*"], s) {
3284
3396
  default:
3285
3397
  return;
3286
3398
  }
3287
- } catch (p) {
3288
- d = { value: p, [throwMarker]: 0 };
3399
+ } catch (h) {
3400
+ d = { value: h, [throwMarker]: 0 };
3289
3401
  }
3290
- Promise.resolve(d).catch((p) => ({ value: p, [throwMarker]: 0 })).then((p) => {
3291
- const [f, _] = toWireValue(p);
3402
+ Promise.resolve(d).catch((h) => ({ value: h, [throwMarker]: 0 })).then((h) => {
3403
+ const [f, _] = toWireValue(h);
3292
3404
  e.postMessage({ ...f, id: o }, _), a === MessageType.RELEASE && (e.removeEventListener("message", n), closeEndPoint(e), finalizer in r && typeof r[finalizer] == "function" && r[finalizer]());
3293
3405
  }).catch(() => {
3294
- const [p, f] = toWireValue({
3406
+ const [h, f] = toWireValue({
3295
3407
  value: new TypeError("Unserializable return value"),
3296
3408
  [throwMarker]: 0
3297
3409
  });
3298
- e.postMessage({ ...p, id: o }, f);
3410
+ e.postMessage({ ...h, id: o }, f);
3299
3411
  }).finally(() => {
3300
3412
  s == null || s(i);
3301
3413
  });
@@ -3372,7 +3484,7 @@ function createProxy(r, e, t = [], s = function() {
3372
3484
  e,
3373
3485
  {
3374
3486
  type: MessageType.SET,
3375
- path: [...t, a].map((p) => p.toString()),
3487
+ path: [...t, a].map((h) => h.toString()),
3376
3488
  value: l
3377
3489
  },
3378
3490
  d
@@ -3387,7 +3499,7 @@ function createProxy(r, e, t = [], s = function() {
3387
3499
  }).then(fromWireValue);
3388
3500
  if (l === "bind")
3389
3501
  return createProxy(r, e, t.slice(0, -1));
3390
- const [d, p] = processArguments(c);
3502
+ const [d, h] = processArguments(c);
3391
3503
  return requestResponseMessage(
3392
3504
  r,
3393
3505
  e,
@@ -3396,7 +3508,7 @@ function createProxy(r, e, t = [], s = function() {
3396
3508
  path: t.map((f) => f.toString()),
3397
3509
  argumentList: d
3398
3510
  },
3399
- p
3511
+ h
3400
3512
  ).then(fromWireValue);
3401
3513
  },
3402
3514
  construct(o, a) {
@@ -3792,25 +3904,33 @@ function setupTransferHandlers() {
3792
3904
  }, transferHandlers.set("StreamedPHPResponse", {
3793
3905
  canHandle: (t) => t instanceof StreamedPHPResponse,
3794
3906
  serialize(t) {
3795
- const s = supportsTransferableStreams(), n = promiseToPort(t.exitCode);
3907
+ const s = supportsTransferableStreams(), n = promiseToPort(t.exitCode), i = t.getHeadersStream();
3796
3908
  if (s)
3797
- return [{
3798
- __type: "StreamedPHPResponse",
3799
- headers: t.headersStream,
3800
- stdout: t.stdout,
3801
- stderr: t.stderr,
3802
- exitCodePort: n
3803
- }, [n]];
3804
- const i = streamToPort(t.headersStream), o = streamToPort(t.stdout), a = streamToPort(t.stderr);
3909
+ return [
3910
+ {
3911
+ __type: "StreamedPHPResponse",
3912
+ headers: i,
3913
+ stdout: t.stdout,
3914
+ stderr: t.stderr,
3915
+ exitCodePort: n
3916
+ },
3917
+ [
3918
+ i,
3919
+ t.stdout,
3920
+ t.stderr,
3921
+ n
3922
+ ]
3923
+ ];
3924
+ const o = streamToPort(i), a = streamToPort(t.stdout), c = streamToPort(t.stderr);
3805
3925
  return [
3806
3926
  {
3807
3927
  __type: "StreamedPHPResponse",
3808
- headersPort: i,
3809
- stdoutPort: o,
3810
- stderrPort: a,
3928
+ headersPort: o,
3929
+ stdoutPort: a,
3930
+ stderrPort: c,
3811
3931
  exitCodePort: n
3812
3932
  },
3813
- [i, o, a, n]
3933
+ [o, a, c, n]
3814
3934
  ];
3815
3935
  },
3816
3936
  deserialize(t) {
@@ -4573,19 +4693,39 @@ function createObjectPoolProxy(r) {
4573
4693
  return new Proxy(function() {
4574
4694
  }, {
4575
4695
  apply(c, l, d) {
4576
- return i((p) => p[a](...d));
4696
+ return i((h) => h[a](...d));
4577
4697
  },
4578
4698
  get(c, l) {
4579
4699
  if (l === "then")
4580
- return (d, p) => i((f) => f[a]).then(
4700
+ return (d, h) => i((f) => f[a]).then(
4581
4701
  d,
4582
- p
4702
+ h
4583
4703
  );
4584
4704
  }
4585
4705
  });
4586
4706
  }
4587
4707
  });
4588
4708
  }
4709
+ const maxValueForSigned32BitInteger = 2 ** 31 - 1;
4710
+ class ProcessIdAllocator {
4711
+ constructor(e = 1, t = maxValueForSigned32BitInteger) {
4712
+ this.claimed = /* @__PURE__ */ new Set(), this.initialId = e, this.maxId = t, this.nextId = e;
4713
+ }
4714
+ claim() {
4715
+ const e = this.maxId - this.initialId + 1;
4716
+ for (let t = 0; t < e; t++)
4717
+ if (this.claimed.has(this.nextId))
4718
+ this.nextId++, this.nextId > this.maxId && (this.nextId = this.initialId);
4719
+ else
4720
+ return this.claimed.add(this.nextId), this.nextId;
4721
+ throw new Error(
4722
+ `Unable to find free process ID after ${e} tries.`
4723
+ );
4724
+ }
4725
+ release(e) {
4726
+ return this.claimed.has(e) ? (this.claimed.delete(e), !0) : !1;
4727
+ }
4728
+ }
4589
4729
  export {
4590
4730
  DEFAULT_BASE_URL,
4591
4731
  FSHelpers,
@@ -4602,6 +4742,7 @@ export {
4602
4742
  PHPRequestHandler,
4603
4743
  PHPResponse,
4604
4744
  PHPWorker,
4745
+ ProcessIdAllocator,
4605
4746
  SinglePHPInstanceManager,
4606
4747
  StreamedPHPResponse,
4607
4748
  SupportedPHPVersions,