@php-wasm/universal 3.0.22 → 3.0.30

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
@@ -5,7 +5,7 @@ var O = (t, e, r) => e.has(t) || B("Cannot " + r);
5
5
  var u = (t, e, r) => (O(t, e, "read from private field"), r ? r.call(t) : e.get(t)), y = (t, e, r) => e.has(t) ? B("Cannot add the same private member more than once") : e instanceof WeakSet ? e.add(t) : e.set(t, r), w = (t, e, r, s) => (O(t, e, "write to private field"), s ? s.call(t, r) : e.set(t, r), r), f = (t, e, r) => (O(t, e, "access private method"), r);
6
6
  import "@php-wasm/node-polyfills";
7
7
  import { logger } from "@php-wasm/logger";
8
- import { dirname, joinPaths, Semaphore, createSpawnHandler, basename, normalizePath, AcquireTimeoutError } from "@php-wasm/util";
8
+ import { dirname, joinPaths, Semaphore, createSpawnHandler, basename, normalizePath, AcquireTimeoutError, splitShellCommand } from "@php-wasm/util";
9
9
  import { parse, stringify } from "ini";
10
10
  import { StreamedFile } from "@php-wasm/stream-compression";
11
11
  class ErrnoError extends Error {
@@ -363,12 +363,12 @@ FSHelpers.copyRecursive = rethrowFileSystemError(
363
363
  'Could not copy files from "{path}"'
364
364
  )(FSHelpers.copyRecursive);
365
365
  const _private = /* @__PURE__ */ new WeakMap();
366
- var S;
366
+ var x;
367
367
  class PHPWorker {
368
368
  /** @inheritDoc */
369
369
  constructor(e, r) {
370
- y(this, S);
371
- this.absoluteUrl = "", this.documentRoot = "", this.chroot = null, w(this, S, /* @__PURE__ */ new Map()), this.onMessageListeners = [], _private.set(this, {
370
+ y(this, x);
371
+ this.absoluteUrl = "", this.documentRoot = "", this.chroot = null, w(this, x, /* @__PURE__ */ new Map()), this.onMessageListeners = [], _private.set(this, {
372
372
  monitor: r
373
373
  }), e && this.__internal_setRequestHandler(e);
374
374
  }
@@ -463,7 +463,7 @@ class PHPWorker {
463
463
  * @returns A PHP instance with a consistent chroot.
464
464
  */
465
465
  async acquirePHPInstance() {
466
- const { php: e, reap: r } = await _private.get(this).requestHandler.processManager.acquirePHPInstance();
466
+ const { php: e, reap: r } = await _private.get(this).requestHandler.instanceManager.acquirePHPInstance();
467
467
  return this.chroot !== null && e.chdir(this.chroot), this.registerWorkerListeners(e), { php: e, reap: r };
468
468
  }
469
469
  /** @inheritDoc @php-wasm/universal!/PHP.setSapiName */
@@ -524,7 +524,7 @@ class PHPWorker {
524
524
  }
525
525
  /** @inheritDoc @php-wasm/universal!/PHP.addEventListener */
526
526
  addEventListener(e, r) {
527
- u(this, S).has(e) || u(this, S).set(e, /* @__PURE__ */ new Set()), u(this, S).get(e).add(r);
527
+ u(this, x).has(e) || u(this, x).set(e, /* @__PURE__ */ new Set()), u(this, x).get(e).add(r);
528
528
  }
529
529
  /**
530
530
  * Removes an event listener for a PHP event.
@@ -533,10 +533,10 @@ class PHPWorker {
533
533
  */
534
534
  removeEventListener(e, r) {
535
535
  var s;
536
- (s = u(this, S).get(e)) == null || s.delete(r);
536
+ (s = u(this, x).get(e)) == null || s.delete(r);
537
537
  }
538
538
  dispatchEvent(e) {
539
- const r = u(this, S).get(e.type);
539
+ const r = u(this, x).get(e.type);
540
540
  if (r)
541
541
  for (const s of r)
542
542
  s(e);
@@ -558,7 +558,7 @@ class PHPWorker {
558
558
  await ((e = _private.get(this).requestHandler) == null ? void 0 : e[Symbol.asyncDispose]());
559
559
  }
560
560
  }
561
- S = new WeakMap();
561
+ x = new WeakMap();
562
562
  function isExitCode(t) {
563
563
  return t instanceof Error ? (t == null ? void 0 : t.name) === "ExitStatus" && "status" in t : !1;
564
564
  }
@@ -586,8 +586,19 @@ async function loadPHPRuntime(t, ...e) {
586
586
  return o.outboundNetworkProxyServer && (o.outboundNetworkProxyServer.close(), o.outboundNetworkProxyServer.closeAllConnections()), loadedRuntimes.delete(a), o.originalExit(c);
587
587
  }, o[RuntimeId] = a, loadedRuntimes.set(a, o), a;
588
588
  }
589
- function getLoadedRuntime(t) {
590
- return loadedRuntimes.get(t);
589
+ function popLoadedRuntime(t, {
590
+ dangerouslyKeepTheRuntimeInTheMap: e = !1
591
+ } = {}) {
592
+ var s;
593
+ const r = loadedRuntimes.get(t);
594
+ if (!r)
595
+ throw new Error(`Runtime with id ${t} not found`);
596
+ if (e) {
597
+ if (!((s = process == null ? void 0 : process.env) != null && s.TEST))
598
+ throw new Error("Cannot pop runtime in non-test environment");
599
+ return r;
600
+ }
601
+ return loadedRuntimes.delete(t), r;
591
602
  }
592
603
  const currentJsRuntime = function() {
593
604
  var t;
@@ -950,7 +961,7 @@ class PHPExecutionFailureError extends Error {
950
961
  }
951
962
  }
952
963
  const PHP_INI_PATH = "/internal/shared/php.ini", AUTO_PREPEND_SCRIPT = "/internal/shared/auto_prepend_file.php", OPCACHE_FILE_FOLDER = "/internal/shared/opcache";
953
- var M, H, T, v, F, k, _, h, z, $, V, G, J, Y, Q, K, U, X, j, D;
964
+ var M, H, T, v, F, k, _, h, z, $, V, G, J, Y, Q, K, U, X, q, j;
954
965
  class PHP {
955
966
  /**
956
967
  * Initializes a PHP runtime.
@@ -1075,7 +1086,7 @@ class PHP {
1075
1086
  initializeRuntime(t) {
1076
1087
  if (this[__private__dont__use])
1077
1088
  throw new Error("PHP runtime already initialized.");
1078
- const e = getLoadedRuntime(t);
1089
+ const e = popLoadedRuntime(t);
1079
1090
  if (!e)
1080
1091
  throw new Error("Invalid PHP runtime id.");
1081
1092
  if (this[__private__dont__use] = e, this[__private__dont__use].ccall(
@@ -1276,9 +1287,7 @@ class PHP {
1276
1287
  * @param request - PHP runtime options.
1277
1288
  */
1278
1289
  async run(t) {
1279
- const e = await this.runStream(t), r = await PHPResponse.fromStreamedResponse(
1280
- e
1281
- );
1290
+ const e = await this.runStream(t), r = await PHPResponse.fromStreamedResponse(e);
1282
1291
  if (r.exitCode !== 0)
1283
1292
  throw new PHPExecutionFailureError(
1284
1293
  `PHP.run() failed with exit code ${r.exitCode}.
@@ -1387,7 +1396,7 @@ class PHP {
1387
1396
  async runStream(t) {
1388
1397
  const e = await this.semaphore.acquire();
1389
1398
  let r;
1390
- const s = f(this, h, D).call(this, async () => {
1399
+ const s = f(this, h, j).call(this, async () => {
1391
1400
  if (u(this, H) || (await this[__private__dont__use].ccall(
1392
1401
  "php_wasm_init",
1393
1402
  null,
@@ -1411,11 +1420,11 @@ class PHP {
1411
1420
  "The request object must have either a `code` or a `scriptPath` property."
1412
1421
  );
1413
1422
  const c = f(this, h, z).call(this, t.$_SERVER, i, a);
1414
- for (const d in c)
1415
- f(this, h, X).call(this, d, c[d]);
1423
+ for (const p in c)
1424
+ f(this, h, X).call(this, p, c[p]);
1416
1425
  const l = t.env || {};
1417
- for (const d in l)
1418
- f(this, h, j).call(this, d, l[d]);
1426
+ for (const p in l)
1427
+ f(this, h, q).call(this, p, l[p]);
1419
1428
  return await this[__private__dont__use].ccall(
1420
1429
  "wasm_sapi_handle_request",
1421
1430
  NUMBER,
@@ -1734,10 +1743,10 @@ class PHP {
1734
1743
  return this.subProcess(t, e);
1735
1744
  u(this, H) && (u(this, _).needsRotating = !0);
1736
1745
  const r = await this.semaphore.acquire();
1737
- return await f(this, h, D).call(this, () => {
1746
+ return await f(this, h, j).call(this, () => {
1738
1747
  const s = e.env || {};
1739
1748
  for (const [n, i] of Object.entries(s))
1740
- f(this, h, j).call(this, n, i);
1749
+ f(this, h, q).call(this, n, i);
1741
1750
  t = [t[0], "-c", PHP_INI_PATH, ...t.slice(1)];
1742
1751
  for (const n of t)
1743
1752
  this[__private__dont__use].ccall(
@@ -1943,41 +1952,41 @@ z = function(t, e, r) {
1943
1952
  [STRING, STRING],
1944
1953
  [t, e]
1945
1954
  );
1946
- }, j = function(t, e) {
1955
+ }, q = function(t, e) {
1947
1956
  this[__private__dont__use].ccall(
1948
1957
  "wasm_add_ENV_entry",
1949
1958
  null,
1950
1959
  [STRING, STRING],
1951
1960
  [t, e]
1952
1961
  );
1953
- }, D = async function(t) {
1962
+ }, j = async function(t) {
1954
1963
  u(this, _).enabled && u(this, _).needsRotating && await this.rotateRuntime(), ++u(this, _).requestsMade, u(this, _).requestsMade >= u(this, _).maxRequests && (u(this, _).needsRotating = !0);
1955
1964
  const e = this[__private__dont__use], r = await createInvertedReadableStream();
1956
- e.onHeaders = (p) => {
1957
- a || s || r.controller.enqueue(p.slice());
1965
+ e.onHeaders = (d) => {
1966
+ a || s || r.controller.enqueue(d.slice());
1958
1967
  };
1959
1968
  let s = !1;
1960
1969
  const n = () => {
1961
1970
  s || (s = !0, r.controller.close());
1962
1971
  }, i = await createInvertedReadableStream();
1963
- e.onStdout = (p) => {
1964
- n(), !a && i.controller.enqueue(p.slice());
1972
+ e.onStdout = (d) => {
1973
+ n(), !a && i.controller.enqueue(d.slice());
1965
1974
  };
1966
1975
  const o = await createInvertedReadableStream();
1967
- e.onStderr = (p) => {
1968
- a || o.controller.enqueue(p.slice());
1976
+ e.onStderr = (d) => {
1977
+ a || o.controller.enqueue(d.slice());
1969
1978
  };
1970
1979
  let a = !1, c;
1971
- const d = (async () => {
1972
- var p;
1980
+ const p = (async () => {
1981
+ var d;
1973
1982
  try {
1974
1983
  return await Promise.race([
1975
1984
  t(),
1976
- new Promise((g, b) => {
1977
- var q;
1985
+ new Promise((P, b) => {
1986
+ var D;
1978
1987
  c = (W) => {
1979
1988
  isExitCode(W.error) || b(W.error);
1980
- }, (q = u(this, T)) == null || q.addEventListener(
1989
+ }, (D = u(this, T)) == null || D.addEventListener(
1981
1990
  "error",
1982
1991
  c,
1983
1992
  { once: !0 }
@@ -1988,42 +1997,42 @@ z = function(t, e, r) {
1988
1997
  if (isExitCode(m))
1989
1998
  return m.status;
1990
1999
  i.controller.error(m), o.controller.error(m), r.controller.error(m), a = !0;
1991
- for (const g in this)
1992
- typeof this[g] == "function" && (this[g] = () => {
2000
+ for (const P in this)
2001
+ typeof this[P] == "function" && (this[P] = () => {
1993
2002
  throw new Error(
1994
2003
  "PHP runtime has crashed – see the earlier error for details."
1995
2004
  );
1996
2005
  });
1997
2006
  throw this.functionsMaybeMissingFromAsyncify = getFunctionsMaybeMissingFromAsyncify(), m;
1998
2007
  } finally {
1999
- a || (i.controller.close(), o.controller.close(), n(), a = !0), (p = u(this, T)) == null || p.removeEventListener(
2008
+ a || (i.controller.close(), o.controller.close(), n(), a = !0), (d = u(this, T)) == null || d.removeEventListener(
2000
2009
  "error",
2001
2010
  c
2002
2011
  );
2003
2012
  }
2004
2013
  })().then(
2005
- (p) => (p !== 0 && this.dispatchEvent({
2014
+ (d) => (d !== 0 && this.dispatchEvent({
2006
2015
  type: "request.error",
2007
2016
  error: new Error(
2008
- `PHP.run() failed with exit code ${p}.`
2017
+ `PHP.run() failed with exit code ${d}.`
2009
2018
  ),
2010
2019
  // Distinguish between PHP request and PHP-wasm errors
2011
2020
  source: "php-wasm"
2012
- }), p),
2013
- (p) => {
2014
- const m = p.source ?? "php-wasm";
2021
+ }), d),
2022
+ (d) => {
2023
+ const m = d.source ?? "php-wasm";
2015
2024
  throw this.dispatchEvent({
2016
2025
  type: "request.error",
2017
- error: p,
2026
+ error: d,
2018
2027
  source: m
2019
- }), p;
2028
+ }), d;
2020
2029
  }
2021
2030
  );
2022
2031
  return new StreamedPHPResponse(
2023
2032
  r.stream,
2024
2033
  i.stream,
2025
2034
  o.stream,
2026
- d
2035
+ p
2027
2036
  );
2028
2037
  };
2029
2038
  function normalizeHeaders(t) {
@@ -2067,8 +2076,8 @@ const getNodeType = (t, e) => {
2067
2076
  try {
2068
2077
  return "contents" in t.lookupPath(e, { follow: !0 }).node ? "memfs" : (
2069
2078
  /**
2070
- * Could be NODEFS, PROXYFS, etc.
2071
- */
2079
+ * Could be NODEFS, PROXYFS, etc.
2080
+ */
2072
2081
  "not-memfs"
2073
2082
  );
2074
2083
  } catch {
@@ -2218,6 +2227,34 @@ function writeFilesStreamToPhp(t, e) {
2218
2227
  }
2219
2228
  });
2220
2229
  }
2230
+ class SinglePHPInstanceManager {
2231
+ constructor(e) {
2232
+ if (this.isAcquired = !1, !e.php && !e.phpFactory)
2233
+ throw new Error(
2234
+ "SinglePHPInstanceManager requires either php or phpFactory"
2235
+ );
2236
+ this.php = e.php, this.phpFactory = e.phpFactory;
2237
+ }
2238
+ async getPrimaryPhp() {
2239
+ return this.php ? this.php : (this.phpPromise || (this.phpPromise = this.phpFactory().then((e) => (this.php = e, this.phpPromise = void 0, e))), this.phpPromise);
2240
+ }
2241
+ async acquirePHPInstance() {
2242
+ if (this.isAcquired)
2243
+ throw new Error(
2244
+ "The PHP instance already acquired. SinglePHPInstanceManager cannot spawn another PHP instance since, by definition, it only manages a single PHP instance."
2245
+ );
2246
+ const e = await this.getPrimaryPhp();
2247
+ return this.isAcquired = !0, {
2248
+ php: e,
2249
+ reap: () => {
2250
+ this.isAcquired = !1;
2251
+ }
2252
+ };
2253
+ }
2254
+ async [Symbol.asyncDispose]() {
2255
+ this.php && this.php.exit();
2256
+ }
2257
+ }
2221
2258
  class MaxPhpInstancesError extends Error {
2222
2259
  constructor(e) {
2223
2260
  super(
@@ -2343,6 +2380,7 @@ class PHPProcessManager {
2343
2380
  }
2344
2381
  }
2345
2382
  const SupportedPHPVersions = [
2383
+ "8.5",
2346
2384
  "8.4",
2347
2385
  "8.3",
2348
2386
  "8.2",
@@ -2480,7 +2518,7 @@ const _default = "application/octet-stream", asx = "video/x-ms-asf", atom = "app
2480
2518
  xspf,
2481
2519
  zip
2482
2520
  };
2483
- var P, I, L, C, A, E, N, R, x, Z, ee, te, re;
2521
+ var g, I, L, C, A, E, N, R, S, Z, ee, te, re;
2484
2522
  class PHPRequestHandler {
2485
2523
  /**
2486
2524
  * The request handler needs to decide whether to serve a static asset or
@@ -2494,8 +2532,8 @@ class PHPRequestHandler {
2494
2532
  * @param config - Request Handler configuration.
2495
2533
  */
2496
2534
  constructor(e) {
2497
- y(this, x);
2498
- y(this, P);
2535
+ y(this, S);
2536
+ y(this, g);
2499
2537
  y(this, I);
2500
2538
  y(this, L);
2501
2539
  y(this, C);
@@ -2508,31 +2546,43 @@ class PHPRequestHandler {
2508
2546
  absoluteUrl: s = typeof location == "object" ? location.href : DEFAULT_BASE_URL,
2509
2547
  rewriteRules: n = [],
2510
2548
  getFileNotFoundAction: i = () => ({ type: "404" })
2511
- } = e;
2512
- "processManager" in e ? this.processManager = e.processManager : this.processManager = new PHPProcessManager({
2513
- phpFactory: async (c) => {
2514
- const l = await e.phpFactory({
2515
- ...c,
2516
- requestHandler: this
2517
- });
2518
- return l.isDir(r) || l.mkdir(r), l.chdir(r), l.requestHandler = this, l;
2519
- },
2520
- maxPhpInstances: e.maxPhpInstances
2521
- }), w(this, R, e.cookieStore === void 0 ? new HttpCookieStore() : e.cookieStore), w(this, P, r);
2522
- const o = new URL(s);
2523
- w(this, L, o.hostname), w(this, C, o.port ? Number(o.port) : o.protocol === "https:" ? 443 : 80), w(this, I, (o.protocol || "").replace(":", ""));
2524
- const a = u(this, C) !== 443 && u(this, C) !== 80;
2549
+ } = e, o = (l) => {
2550
+ l.isDir(r) || l.mkdir(r), l.chdir(r), l.requestHandler = this;
2551
+ };
2552
+ if (e.php)
2553
+ o(e.php), this.instanceManager = new SinglePHPInstanceManager({
2554
+ php: e.php
2555
+ });
2556
+ else if (e.phpFactory)
2557
+ this.instanceManager = new PHPProcessManager({
2558
+ phpFactory: async (l) => {
2559
+ const p = await e.phpFactory({
2560
+ ...l,
2561
+ requestHandler: this
2562
+ });
2563
+ return o(p), p;
2564
+ },
2565
+ maxPhpInstances: e.maxPhpInstances
2566
+ });
2567
+ else
2568
+ throw new Error(
2569
+ "Either php or phpFactory must be provided in the configuration."
2570
+ );
2571
+ w(this, R, e.cookieStore === void 0 ? new HttpCookieStore() : e.cookieStore), w(this, g, r);
2572
+ const a = new URL(s);
2573
+ w(this, L, a.hostname), w(this, C, a.port ? Number(a.port) : a.protocol === "https:" ? 443 : 80), w(this, I, (a.protocol || "").replace(":", ""));
2574
+ const c = u(this, C) !== 443 && u(this, C) !== 80;
2525
2575
  w(this, A, [
2526
2576
  u(this, L),
2527
- a ? `:${u(this, C)}` : ""
2528
- ].join("")), w(this, E, o.pathname.replace(/\/+$/, "")), w(this, N, [
2577
+ c ? `:${u(this, C)}` : ""
2578
+ ].join("")), w(this, E, a.pathname.replace(/\/+$/, "")), w(this, N, [
2529
2579
  `${u(this, I)}://`,
2530
2580
  u(this, A),
2531
2581
  u(this, E)
2532
2582
  ].join("")), this.rewriteRules = n, this.getFileNotFoundAction = i;
2533
2583
  }
2534
2584
  async getPrimaryPhp() {
2535
- return await this.processManager.getPrimaryPhp();
2585
+ return await this.instanceManager.getPrimaryPhp();
2536
2586
  }
2537
2587
  /**
2538
2588
  * Converts a path to an absolute URL based at the PHPRequestHandler
@@ -2566,7 +2616,7 @@ class PHPRequestHandler {
2566
2616
  * for the files to serve. Default: `/var/www`.
2567
2617
  */
2568
2618
  get documentRoot() {
2569
- return u(this, P);
2619
+ return u(this, g);
2570
2620
  }
2571
2621
  /**
2572
2622
  * Serves the request – either by serving a static file, or by
@@ -2621,9 +2671,9 @@ class PHPRequestHandler {
2621
2671
  // Remove the hash part of the URL as it's not meant for the server.
2622
2672
  e.url.split("#")[0],
2623
2673
  r ? void 0 : DEFAULT_BASE_URL
2624
- ), n = f(this, x, Z).call(this, s), i = await this.getPrimaryPhp();
2674
+ ), n = f(this, S, Z).call(this, s), i = await this.getPrimaryPhp();
2625
2675
  let o = joinPaths(
2626
- u(this, P),
2676
+ u(this, g),
2627
2677
  /**
2628
2678
  * Turn a URL such as `https://playground/scope:my-site/wp-admin/index.php`
2629
2679
  * into a site-relative path, such as `/wp-admin/index.php`.
@@ -2659,10 +2709,10 @@ class PHPRequestHandler {
2659
2709
  let a = n.pathname;
2660
2710
  for (; a.startsWith("/") && a !== dirname(a); ) {
2661
2711
  a = dirname(a);
2662
- const c = joinPaths(u(this, P), a);
2712
+ const c = joinPaths(u(this, g), a);
2663
2713
  if (i.isFile(c) && // Only run partial path resolution for PHP files.
2664
2714
  c.endsWith(".php")) {
2665
- o = joinPaths(u(this, P), a);
2715
+ o = joinPaths(u(this, g), a);
2666
2716
  break;
2667
2717
  }
2668
2718
  }
@@ -2675,7 +2725,7 @@ class PHPRequestHandler {
2675
2725
  case "response":
2676
2726
  return a.response;
2677
2727
  case "internal-redirect":
2678
- o = joinPaths(u(this, P), a.uri);
2728
+ o = joinPaths(u(this, g), a.uri);
2679
2729
  break;
2680
2730
  case "404":
2681
2731
  return PHPResponse.forHttpCode(404);
@@ -2687,7 +2737,7 @@ class PHPRequestHandler {
2687
2737
  }
2688
2738
  if (i.isFile(o))
2689
2739
  if (o.endsWith(".php")) {
2690
- const a = await f(this, x, te).call(this, e, s, n, o);
2740
+ const a = await f(this, S, te).call(this, e, s, n, o);
2691
2741
  return a.ok() && a.exitCode !== 0 ? new PHPResponse(
2692
2742
  500,
2693
2743
  a.headers,
@@ -2696,7 +2746,7 @@ class PHPRequestHandler {
2696
2746
  a.exitCode
2697
2747
  ) : a;
2698
2748
  } else
2699
- return f(this, x, ee).call(this, i, o);
2749
+ return f(this, S, ee).call(this, i, o);
2700
2750
  else
2701
2751
  return PHPResponse.forHttpCode(404);
2702
2752
  }
@@ -2791,11 +2841,11 @@ class PHPRequestHandler {
2791
2841
  prepare_$_SERVER_superglobal(e, r, s) {
2792
2842
  const n = {
2793
2843
  REMOTE_ADDR: "127.0.0.1",
2794
- DOCUMENT_ROOT: u(this, P),
2844
+ DOCUMENT_ROOT: u(this, g),
2795
2845
  HTTPS: u(this, N).startsWith("https://") ? "on" : ""
2796
2846
  };
2797
- return n.REQUEST_URI = e.pathname + e.search, s.startsWith(u(this, P)) && (n.SCRIPT_NAME = s.substring(
2798
- u(this, P).length
2847
+ return n.REQUEST_URI = e.pathname + e.search, s.startsWith(u(this, g)) && (n.SCRIPT_NAME = s.substring(
2848
+ u(this, g).length
2799
2849
  ), n.PHP_SELF = r.pathname, n.REQUEST_URI.startsWith(n.SCRIPT_NAME) && (n.PATH_INFO = n.REQUEST_URI.substring(
2800
2850
  n.SCRIPT_NAME.length
2801
2851
  ), n.PATH_INFO.includes("?") && (n.PATH_INFO = n.PATH_INFO.substring(
@@ -2804,10 +2854,10 @@ class PHPRequestHandler {
2804
2854
  )))), n.QUERY_STRING = r.search.substring(1), n;
2805
2855
  }
2806
2856
  async [Symbol.asyncDispose]() {
2807
- await this.processManager[Symbol.asyncDispose]();
2857
+ await this.instanceManager[Symbol.asyncDispose]();
2808
2858
  }
2809
2859
  }
2810
- P = new WeakMap(), I = new WeakMap(), L = new WeakMap(), C = new WeakMap(), A = new WeakMap(), E = new WeakMap(), N = new WeakMap(), R = new WeakMap(), x = new WeakSet(), /**
2860
+ g = new WeakMap(), I = new WeakMap(), L = new WeakMap(), C = new WeakMap(), A = new WeakMap(), E = new WeakMap(), N = new WeakMap(), R = new WeakMap(), S = new WeakSet(), /**
2811
2861
  * Apply the rewrite rules to the original request URL.
2812
2862
  *
2813
2863
  * @param originalRequestUrl - The original request URL.
@@ -2851,14 +2901,14 @@ ee = function(e, r) {
2851
2901
  }, te = async function(e, r, s, n) {
2852
2902
  let i;
2853
2903
  try {
2854
- i = await this.processManager.acquirePHPInstance({
2904
+ i = await this.instanceManager.acquirePHPInstance({
2855
2905
  considerPrimary: !0
2856
2906
  });
2857
2907
  } catch (o) {
2858
2908
  return o instanceof MaxPhpInstancesError ? PHPResponse.forHttpCode(502) : PHPResponse.forHttpCode(500);
2859
2909
  }
2860
2910
  try {
2861
- return await f(this, x, re).call(this, i.php, e, r, s, n);
2911
+ return await f(this, S, re).call(this, i.php, e, r, s, n);
2862
2912
  } finally {
2863
2913
  i.reap();
2864
2914
  }
@@ -2872,8 +2922,8 @@ ee = function(e, r) {
2872
2922
  let c = r.body;
2873
2923
  if (typeof c == "object" && !(c instanceof Uint8Array)) {
2874
2924
  o = "POST";
2875
- const { bytes: l, contentType: d } = await encodeAsMultipart(c);
2876
- c = l, a["content-type"] = d;
2925
+ const { bytes: l, contentType: p } = await encodeAsMultipart(c);
2926
+ c = l, a["content-type"] = p;
2877
2927
  }
2878
2928
  try {
2879
2929
  const l = await e.run({
@@ -2896,9 +2946,9 @@ ee = function(e, r) {
2896
2946
  l.headers
2897
2947
  ), l;
2898
2948
  } catch (l) {
2899
- const d = l;
2900
- if (d != null && d.response)
2901
- return d.response;
2949
+ const p = l;
2950
+ if (p != null && p.response)
2951
+ return p.response;
2902
2952
  throw l;
2903
2953
  }
2904
2954
  };
@@ -2959,7 +3009,7 @@ function isPathToSharedFS(t, e) {
2959
3009
  }
2960
3010
  function sandboxedSpawnHandlerFactory(t) {
2961
3011
  return createSpawnHandler(async function(e, r, s) {
2962
- r.notifySpawn(), e[0] === "exec" && e.shift(), (e[0].endsWith(".php") || e[0].endsWith(".phar")) && e.unshift("php");
3012
+ r.notifySpawn(), (e == null ? void 0 : e[0]) === "/bin/sh" && (e == null ? void 0 : e[1]) === "-c" && typeof e[2] == "string" && (e = splitShellCommand(e[2])), e[0] === "exec" && e.shift(), (e[0].endsWith(".php") || e[0].endsWith(".phar")) && e.unshift("php");
2963
3013
  const n = e[0].split("/").pop();
2964
3014
  if (e[0] === "/usr/bin/env" && e[1] === "stty" && e[2] === "size")
2965
3015
  r.stdout("18 140"), r.exit(0);
@@ -2979,12 +3029,16 @@ function sandboxedSpawnHandlerFactory(t) {
2979
3029
  r.exit(127);
2980
3030
  return;
2981
3031
  }
2982
- const { php: i, reap: o } = await t.acquirePHPInstance({
2983
- considerPrimary: !1
2984
- });
3032
+ if (!t) {
3033
+ logger.warn(
3034
+ "Tried to spawn a PHP subprocess, but the sandboxed spawn handler was created without a getPHPInstance function."
3035
+ ), r.exit(127);
3036
+ return;
3037
+ }
3038
+ const { php: i, reap: o } = await t();
2985
3039
  try {
2986
- s.cwd && i.chdir(s.cwd);
2987
- const a = i.cwd();
3040
+ s.cwd && await i.chdir(s.cwd);
3041
+ const a = await i.cwd();
2988
3042
  switch (n) {
2989
3043
  case "php": {
2990
3044
  const c = await i.cli(e, {
@@ -3013,7 +3067,7 @@ function sandboxedSpawnHandlerFactory(t) {
3013
3067
  break;
3014
3068
  }
3015
3069
  case "ls": {
3016
- const c = i.listFiles(e[1] ?? a);
3070
+ const c = await i.listFiles(e[1] ?? a);
3017
3071
  for (const l of c)
3018
3072
  r.stdout(l + `
3019
3073
  `);
@@ -3119,10 +3173,10 @@ class NodeSABSyncReceiveMessageTransport {
3119
3173
  ), Atomics.wait(i, 0, 0, 5e3) === "timed-out")
3120
3174
  throw new Error("Timeout waiting for response");
3121
3175
  for (; ; ) {
3122
- const d = NodeSABSyncReceiveMessageTransport.receiveMessageOnPort(e);
3123
- if (((l = d.message) == null ? void 0 : l.id) === o)
3124
- return d.message;
3125
- if (!d)
3176
+ const p = NodeSABSyncReceiveMessageTransport.receiveMessageOnPort(e);
3177
+ if (((l = p.message) == null ? void 0 : l.id) === o)
3178
+ return p.message;
3179
+ if (!p)
3126
3180
  throw new Error("No response received");
3127
3181
  }
3128
3182
  }
@@ -3200,51 +3254,51 @@ function expose(t, e = globalThis, r = ["*"], s) {
3200
3254
  path: [],
3201
3255
  ...i.data
3202
3256
  }, l = (i.data.argumentList || []).map(fromWireValue);
3203
- let d;
3257
+ let p;
3204
3258
  try {
3205
- const p = c.slice(0, -1).reduce((g, b) => g[b], t), m = c.reduce((g, b) => g[b], t);
3259
+ const d = c.slice(0, -1).reduce((P, b) => P[b], t), m = c.reduce((P, b) => P[b], t);
3206
3260
  switch (a) {
3207
3261
  case MessageType.GET:
3208
- d = m;
3262
+ p = m;
3209
3263
  break;
3210
3264
  case MessageType.SET:
3211
- p[c.slice(-1)[0]] = fromWireValue(
3265
+ d[c.slice(-1)[0]] = fromWireValue(
3212
3266
  i.data.value
3213
- ), d = !0;
3267
+ ), p = !0;
3214
3268
  break;
3215
3269
  case MessageType.APPLY:
3216
- d = m.apply(p, l);
3270
+ p = m.apply(d, l);
3217
3271
  break;
3218
3272
  case MessageType.CONSTRUCT:
3219
3273
  {
3220
- const g = new m(...l);
3221
- d = proxy(g);
3274
+ const P = new m(...l);
3275
+ p = proxy(P);
3222
3276
  }
3223
3277
  break;
3224
3278
  case MessageType.ENDPOINT:
3225
3279
  {
3226
- const { port1: g, port2: b } = new MessageChannel();
3227
- expose(t, b), d = transfer(g, [g]);
3280
+ const { port1: P, port2: b } = new MessageChannel();
3281
+ expose(t, b), p = transfer(P, [P]);
3228
3282
  }
3229
3283
  break;
3230
3284
  case MessageType.RELEASE:
3231
- d = void 0;
3285
+ p = void 0;
3232
3286
  break;
3233
3287
  default:
3234
3288
  return;
3235
3289
  }
3236
- } catch (p) {
3237
- d = { value: p, [throwMarker]: 0 };
3290
+ } catch (d) {
3291
+ p = { value: d, [throwMarker]: 0 };
3238
3292
  }
3239
- Promise.resolve(d).catch((p) => ({ value: p, [throwMarker]: 0 })).then((p) => {
3240
- const [m, g] = toWireValue(p);
3241
- e.postMessage({ ...m, id: o }, g), a === MessageType.RELEASE && (e.removeEventListener("message", n), closeEndPoint(e), finalizer in t && typeof t[finalizer] == "function" && t[finalizer]());
3293
+ Promise.resolve(p).catch((d) => ({ value: d, [throwMarker]: 0 })).then((d) => {
3294
+ const [m, P] = toWireValue(d);
3295
+ e.postMessage({ ...m, id: o }, P), a === MessageType.RELEASE && (e.removeEventListener("message", n), closeEndPoint(e), finalizer in t && typeof t[finalizer] == "function" && t[finalizer]());
3242
3296
  }).catch(() => {
3243
- const [p, m] = toWireValue({
3297
+ const [d, m] = toWireValue({
3244
3298
  value: new TypeError("Unserializable return value"),
3245
3299
  [throwMarker]: 0
3246
3300
  });
3247
- e.postMessage({ ...p, id: o }, m);
3301
+ e.postMessage({ ...d, id: o }, m);
3248
3302
  }).finally(() => {
3249
3303
  s == null || s(i);
3250
3304
  });
@@ -3315,16 +3369,16 @@ function createProxy(t, e, r = [], s = function() {
3315
3369
  },
3316
3370
  set(o, a, c) {
3317
3371
  throwIfProxyReleased(n);
3318
- const [l, d] = toWireValue(c);
3372
+ const [l, p] = toWireValue(c);
3319
3373
  return requestResponseMessage(
3320
3374
  t,
3321
3375
  e,
3322
3376
  {
3323
3377
  type: MessageType.SET,
3324
- path: [...r, a].map((p) => p.toString()),
3378
+ path: [...r, a].map((d) => d.toString()),
3325
3379
  value: l
3326
3380
  },
3327
- d
3381
+ p
3328
3382
  ).then(fromWireValue);
3329
3383
  },
3330
3384
  apply(o, a, c) {
@@ -3336,16 +3390,16 @@ function createProxy(t, e, r = [], s = function() {
3336
3390
  }).then(fromWireValue);
3337
3391
  if (l === "bind")
3338
3392
  return createProxy(t, e, r.slice(0, -1));
3339
- const [d, p] = processArguments(c);
3393
+ const [p, d] = processArguments(c);
3340
3394
  return requestResponseMessage(
3341
3395
  t,
3342
3396
  e,
3343
3397
  {
3344
3398
  type: MessageType.APPLY,
3345
3399
  path: r.map((m) => m.toString()),
3346
- argumentList: d
3400
+ argumentList: p
3347
3401
  },
3348
- p
3402
+ d
3349
3403
  ).then(fromWireValue);
3350
3404
  },
3351
3405
  construct(o, a) {
@@ -3356,7 +3410,7 @@ function createProxy(t, e, r = [], s = function() {
3356
3410
  e,
3357
3411
  {
3358
3412
  type: MessageType.CONSTRUCT,
3359
- path: r.map((d) => d.toString()),
3413
+ path: r.map((p) => p.toString()),
3360
3414
  argumentList: c
3361
3415
  },
3362
3416
  l
@@ -3527,19 +3581,19 @@ const errorProperties = [
3527
3581
  useToJSON: o,
3528
3582
  serialize: a
3529
3583
  });
3530
- for (const [l, d] of Object.entries(t)) {
3531
- if (d && d instanceof Uint8Array && d.constructor.name === "Buffer") {
3584
+ for (const [l, p] of Object.entries(t)) {
3585
+ if (p && p instanceof Uint8Array && p.constructor.name === "Buffer") {
3532
3586
  r[l] = "[object Buffer]";
3533
3587
  continue;
3534
3588
  }
3535
- if (d !== null && typeof d == "object" && typeof d.pipe == "function") {
3589
+ if (p !== null && typeof p == "object" && typeof p.pipe == "function") {
3536
3590
  r[l] = "[object Stream]";
3537
3591
  continue;
3538
3592
  }
3539
- if (typeof d != "function") {
3540
- if (!d || typeof d != "object") {
3593
+ if (typeof p != "function") {
3594
+ if (!p || typeof p != "object") {
3541
3595
  try {
3542
- r[l] = d;
3596
+ r[l] = p;
3543
3597
  } catch {
3544
3598
  }
3545
3599
  continue;
@@ -3552,10 +3606,10 @@ const errorProperties = [
3552
3606
  }
3553
3607
  }
3554
3608
  if (a || r instanceof Error)
3555
- for (const { property: l, enumerable: d } of errorProperties)
3609
+ for (const { property: l, enumerable: p } of errorProperties)
3556
3610
  t[l] !== void 0 && t[l] !== null && Object.defineProperty(r, l, {
3557
3611
  value: isErrorLike(t[l]) || Array.isArray(t[l]) ? c(t[l]) : t[l],
3558
- enumerable: s ? !0 : d,
3612
+ enumerable: s ? !0 : p,
3559
3613
  configurable: !0,
3560
3614
  writable: !0
3561
3615
  });
@@ -3674,7 +3728,8 @@ function setupTransferHandlers() {
3674
3728
  }), transferHandlers.set("PHPResponse", {
3675
3729
  canHandle: (r) => typeof r == "object" && r !== null && "headers" in r && "bytes" in r && "errors" in r && "exitCode" in r && "httpStatusCode" in r,
3676
3730
  serialize(r) {
3677
- return [r.toRawData(), []];
3731
+ const s = r.toRawData(), n = [];
3732
+ return s.bytes.buffer.byteLength > 0 && n.push(s.bytes.buffer), [s, n];
3678
3733
  },
3679
3734
  deserialize(r) {
3680
3735
  return PHPResponse.fromRawData(r);
@@ -3929,6 +3984,7 @@ export {
3929
3984
  PHPRequestHandler,
3930
3985
  PHPResponse,
3931
3986
  PHPWorker,
3987
+ SinglePHPInstanceManager,
3932
3988
  StreamedPHPResponse,
3933
3989
  SupportedPHPVersions,
3934
3990
  SupportedPHPVersionsList,
@@ -3940,13 +3996,13 @@ export {
3940
3996
  ensurePathPrefix,
3941
3997
  exposeAPI,
3942
3998
  exposeSyncAPI,
3943
- getLoadedRuntime,
3944
3999
  getPhpIniEntries,
3945
4000
  inferMimeType,
3946
4001
  isExitCode,
3947
4002
  isPathToSharedFS,
3948
4003
  iteratePhpFiles as iterateFiles,
3949
4004
  loadPHPRuntime,
4005
+ popLoadedRuntime,
3950
4006
  prettyPrintFullStackTrace,
3951
4007
  printDebugDetails,
3952
4008
  printResponseDebugDetails,