@php-wasm/universal 3.0.22 → 3.0.29

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.
@@ -1,3 +1,4 @@
1
+ /// <reference types="node" />
1
2
  import type { Emscripten } from './emscripten-types';
2
3
  export interface RmDirOptions {
3
4
  /**
@@ -40,7 +41,7 @@ export declare class FSHelpers {
40
41
  * @param path - The file path to write to.
41
42
  * @param data - The data to write to the file.
42
43
  */
43
- static writeFile(FS: Emscripten.RootFS, path: string, data: string | Uint8Array): void;
44
+ static writeFile(FS: Emscripten.RootFS, path: string, data: string | Uint8Array | Buffer): void;
44
45
  /**
45
46
  * Removes a file from the PHP filesystem.
46
47
  *
package/lib/index.d.ts CHANGED
@@ -9,8 +9,15 @@ export { HttpCookieStore } from './http-cookie-store';
9
9
  export type { IteratePhpFilesOptions as IterateFilesOptions } from './iterate-files';
10
10
  export { iteratePhpFiles as iterateFiles } from './iterate-files';
11
11
  export { writeFilesStreamToPhp } from './write-files-stream-to-php';
12
+ export type { PHPInstanceManager, AcquiredPHP,
13
+ /**
14
+ * Backwards compatibility alias.
15
+ */
16
+ AcquiredPHP as SpawnedPHP, } from './php-instance-manager';
17
+ export { SinglePHPInstanceManager } from './single-php-instance-manager';
18
+ export type { SinglePHPInstanceManagerOptions } from './single-php-instance-manager';
12
19
  export { PHPProcessManager } from './php-process-manager';
13
- export type { MaxPhpInstancesError, PHPFactory, PHPFactoryOptions, ProcessManagerOptions, SpawnedPHP, } from './php-process-manager';
20
+ export type { MaxPhpInstancesError, PHPFactory, PHPFactoryOptions, ProcessManagerOptions, } from './php-process-manager';
14
21
  export { PHPResponse, StreamedPHPResponse } from './php-response';
15
22
  export type { PHPResponseData } from './php-response';
16
23
  export type { ErrnoError } from './rethrow-file-system-error';
@@ -18,7 +25,7 @@ export { LatestSupportedPHPVersion, SupportedPHPVersions, SupportedPHPVersionsLi
18
25
  export type { SupportedPHPVersion } from './supported-php-versions';
19
26
  export { PHP, __private__dont__use, PHPExecutionFailureError } from './php';
20
27
  export type { MountHandler, UnmountFunction } from './php';
21
- export { loadPHPRuntime, getLoadedRuntime } from './load-php-runtime';
28
+ export { loadPHPRuntime, popLoadedRuntime } from './load-php-runtime';
22
29
  export type { Emscripten } from './emscripten-types';
23
30
  export type { DataModule, EmscriptenOptions, PHPLoaderModule, PHPRuntime, PHPRuntimeId, RuntimeType, } from './load-php-runtime';
24
31
  export type { PHPRequestHandlerConfiguration, RewriteRule, } from './php-request-handler';
@@ -33,3 +40,4 @@ export { proxyFileSystem, isPathToSharedFS } from './proxy-file-system';
33
40
  export { sandboxedSpawnHandlerFactory } from './sandboxed-spawn-handler-factory';
34
41
  export * from './api';
35
42
  export type { WithAPIState as WithIsReady } from './api';
43
+ export type { Remote } from './comlink-sync';
@@ -122,7 +122,40 @@ import type { IncomingMessage, Server, ServerResponse } from 'http';
122
122
  export declare function loadPHPRuntime(phpLoaderModule: PHPLoaderModule, ...options: EmscriptenOptions[]): Promise<number>;
123
123
  export type RuntimeType = 'NODE' | 'WEB' | 'WORKER';
124
124
  export type PHPRuntimeId = number;
125
- export declare function getLoadedRuntime(id: PHPRuntimeId): PHPRuntime;
125
+ /**
126
+ * Retrieves a PHP runtime by its ID and removes it from the internal registry.
127
+ *
128
+ * When you call `loadPHPRuntime()`, it creates an Emscripten-based PHP instance and
129
+ * stores it in a module-level Map keyed by a numeric ID. This function is the only
130
+ * way to retrieve that runtime object so you can actually use it.
131
+ *
132
+ * The "pop" semantic is intentional: retrieving a runtime also removes it from the
133
+ * registry. This prevents memory leaks since the registry would otherwise hold
134
+ * references to every runtime ever created. Once you pop a runtime, you own it and
135
+ * are responsible for its lifecycle.
136
+ *
137
+ * Typical usage flow:
138
+ * ```ts
139
+ * // 1. Load a PHP runtime (returns just the ID)
140
+ * const runtimeId = await loadPHPRuntime(phpLoaderModule);
141
+ *
142
+ * // 2. Pop the runtime to get the actual Emscripten module
143
+ * const phpRuntime = popLoadedRuntime(runtimeId);
144
+ *
145
+ * // 3. Now you can use phpRuntime to run PHP code, access the filesystem, etc.
146
+ * ```
147
+ *
148
+ * @param id - The numeric ID returned by `loadPHPRuntime()`.
149
+ * @param options.dangerouslyKeepTheRuntimeInTheMap - Test-only escape hatch. When true,
150
+ * retrieves the runtime without removing it from the registry. This violates
151
+ * the function's contract and only works when `process.env.TEST` is set.
152
+ * Never use this in production code.
153
+ * @returns The PHP runtime object (an Emscripten module instance).
154
+ * @throws If no runtime exists with the given ID.
155
+ */
156
+ export declare function popLoadedRuntime(id: PHPRuntimeId, { dangerouslyKeepTheRuntimeInTheMap, }?: {
157
+ dangerouslyKeepTheRuntimeInTheMap?: boolean;
158
+ }): PHPRuntime;
126
159
  export declare const currentJsRuntime: string;
127
160
  export type PHPRuntime = any;
128
161
  export type PHPLoaderModule = {
@@ -0,0 +1,38 @@
1
+ import type { PHP } from './php';
2
+ /**
3
+ * Result of acquiring a PHP instance.
4
+ * The `reap` function should be called when done with the instance.
5
+ */
6
+ export interface AcquiredPHP {
7
+ php: PHP;
8
+ /**
9
+ * Release the PHP instance back to the pool (for multi-instance managers)
10
+ * or mark it as idle (for single-instance managers).
11
+ */
12
+ reap: () => void;
13
+ }
14
+ /**
15
+ * Minimal interface for managing PHP instances.
16
+ *
17
+ * This interface allows PHPRequestHandler to work with different
18
+ * instance management strategies:
19
+ * - PHPProcessManager: Multiple PHP instances with concurrency control
20
+ * - SinglePHPInstanceManager: Single PHP instance for CLI contexts
21
+ */
22
+ export interface PHPInstanceManager extends AsyncDisposable {
23
+ /**
24
+ * Get the primary PHP instance.
25
+ * This instance is persistent and never killed.
26
+ */
27
+ getPrimaryPhp(): Promise<PHP>;
28
+ /**
29
+ * Acquire a PHP instance for processing a request.
30
+ *
31
+ * @param options.considerPrimary - Whether the primary instance can be used.
32
+ * Set to false for operations that would corrupt the primary (e.g., CLI commands).
33
+ * @returns An acquired PHP instance with a reap function.
34
+ */
35
+ acquirePHPInstance(options?: {
36
+ considerPrimary?: boolean;
37
+ }): Promise<AcquiredPHP>;
38
+ }
@@ -1,4 +1,5 @@
1
1
  import type { PHP } from './php';
2
+ import type { PHPInstanceManager, AcquiredPHP } from './php-instance-manager';
2
3
  export type PHPFactoryOptions = {
3
4
  isPrimary: boolean;
4
5
  };
@@ -28,10 +29,6 @@ export interface ProcessManagerOptions {
28
29
  */
29
30
  phpFactory?: PHPFactory;
30
31
  }
31
- export interface SpawnedPHP {
32
- php: PHP;
33
- reap: () => void;
34
- }
35
32
  export declare class MaxPhpInstancesError extends Error {
36
33
  constructor(limit: number);
37
34
  }
@@ -59,7 +56,7 @@ export declare class MaxPhpInstancesError extends Error {
59
56
  * requests requires extra time to spin up a few PHP instances. This is a more
60
57
  * resource-friendly tradeoff than keeping 5 idle instances at all times.
61
58
  */
62
- export declare class PHPProcessManager implements AsyncDisposable {
59
+ export declare class PHPProcessManager implements PHPInstanceManager {
63
60
  private primaryPhp?;
64
61
  private primaryPhpPromise?;
65
62
  private primaryIdle;
@@ -105,7 +102,7 @@ export declare class PHPProcessManager implements AsyncDisposable {
105
102
  */
106
103
  acquirePHPInstance({ considerPrimary, }?: {
107
104
  considerPrimary?: boolean;
108
- }): Promise<SpawnedPHP>;
105
+ }): Promise<AcquiredPHP>;
109
106
  /**
110
107
  * Initiated spawning of a new PHP instance.
111
108
  * This function is synchronous on purpose – it needs to synchronously
@@ -2,7 +2,7 @@ import type { PHP } from './php';
2
2
  import { PHPResponse } from './php-response';
3
3
  import type { PHPRequest } from './universal-php';
4
4
  import type { PHPFactoryOptions } from './php-process-manager';
5
- import { PHPProcessManager } from './php-process-manager';
5
+ import type { PHPInstanceManager } from './php-instance-manager';
6
6
  export type RewriteRule = {
7
7
  match: RegExp;
8
8
  replacement: string;
@@ -59,28 +59,24 @@ interface BaseConfiguration {
59
59
  export type PHPRequestHandlerFactoryArgs = PHPFactoryOptions & {
60
60
  requestHandler: PHPRequestHandler;
61
61
  };
62
- export type PHPRequestHandlerConfiguration = BaseConfiguration & ({
62
+ export type PHPRequestHandlerConfiguration = BaseConfiguration & {
63
+ cookieStore?: CookieStore | false;
63
64
  /**
64
- * PHPProcessManager is required because the request handler needs
65
- * to make a decision for each request.
66
- *
67
- * Static assets are served using the primary PHP's filesystem, even
68
- * when serving 100 static files concurrently. No new PHP interpreter
69
- * is ever created as there's no need for it.
70
- *
71
- * Dynamic PHP requests, however, require grabbing an available PHP
72
- * interpreter, and that's where the PHPProcessManager comes in.
65
+ * Provide a single PHP instance directly.
66
+ * PHPRequestHandler will create a SinglePHPInstanceManager internally.
67
+ * This is the simplest option for CLI contexts with a single PHP instance.
68
+ */
69
+ php?: PHP;
70
+ /**
71
+ * Provide a factory function to create PHP instances.
72
+ * PHPRequestHandler will create a PHPProcessManager internally.
73
73
  */
74
- processManager: PHPProcessManager;
75
- } | {
76
- phpFactory: (requestHandler: PHPRequestHandlerFactoryArgs) => Promise<PHP>;
74
+ phpFactory?: (requestHandler: PHPRequestHandlerFactoryArgs) => Promise<PHP>;
77
75
  /**
78
76
  * The maximum number of PHP instances that can exist at
79
- * the same time.
77
+ * the same time. Only used when phpFactory is provided.
80
78
  */
81
79
  maxPhpInstances?: number;
82
- }) & {
83
- cookieStore?: CookieStore | false;
84
80
  };
85
81
  /**
86
82
  * Handles HTTP requests using PHP runtime as a backend.
@@ -139,7 +135,12 @@ export type PHPRequestHandlerConfiguration = BaseConfiguration & ({
139
135
  export declare class PHPRequestHandler implements AsyncDisposable {
140
136
  #private;
141
137
  rewriteRules: RewriteRule[];
142
- processManager: PHPProcessManager;
138
+ /**
139
+ * The instance manager used for PHP instance lifecycle.
140
+ * This is either a provided instanceManager or a PHPProcessManager
141
+ * created from the phpFactory.
142
+ */
143
+ instanceManager: PHPInstanceManager;
143
144
  getFileNotFoundAction: FileNotFoundGetActionCallback;
144
145
  /**
145
146
  * The request handler needs to decide whether to serve a static asset or
package/lib/php.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ /// <reference types="node" />
1
2
  import { Semaphore } from '@php-wasm/util';
2
3
  import type { Emscripten } from './emscripten-types';
3
4
  import type { ListFilesOptions, RmDirOptions } from './fs-helpers';
@@ -338,7 +339,7 @@ export declare class PHP implements Disposable {
338
339
  * @param path - The file path to write to.
339
340
  * @param data - The data to write to the file.
340
341
  */
341
- writeFile(path: string, data: string | Uint8Array): void;
342
+ writeFile(path: string, data: string | Uint8Array | Buffer): void;
342
343
  /**
343
344
  * Removes a file from the PHP filesystem.
344
345
  *
@@ -1,4 +1,6 @@
1
- import type { PHPProcessManager } from './php-process-manager';
1
+ import type { PHP } from './php';
2
+ import type { PHPWorker } from './php-worker';
3
+ import type { Remote } from './comlink-sync';
2
4
  /**
3
5
  * An isomorphic proc_open() handler that implements typical shell in TypeScript
4
6
  * without relying on a server runtime. It can be used in the browser and Node.js
@@ -9,4 +11,7 @@ import type { PHPProcessManager } from './php-process-manager';
9
11
  * explore bringing in an actual shell implementation or at least a proper command
10
12
  * parser.
11
13
  */
12
- export declare function sandboxedSpawnHandlerFactory(processManager: PHPProcessManager): any;
14
+ export declare function sandboxedSpawnHandlerFactory(getPHPInstance?: () => Promise<{
15
+ php: PHP | Remote<PHPWorker>;
16
+ reap: () => void;
17
+ }>): any;
@@ -0,0 +1,34 @@
1
+ import type { PHP } from './php';
2
+ import type { PHPInstanceManager, AcquiredPHP } from './php-instance-manager';
3
+ export interface SinglePHPInstanceManagerOptions {
4
+ /**
5
+ * Either provide an existing PHP instance...
6
+ */
7
+ php?: PHP;
8
+ /**
9
+ * ...or a factory to create one on demand.
10
+ */
11
+ phpFactory?: () => Promise<PHP>;
12
+ }
13
+ /**
14
+ * A minimal PHP instance manager that manages a single PHP instance.
15
+ *
16
+ * Unlike PHPProcessManager, this does not maintain a pool of instances
17
+ * or implement concurrency control. It simply returns the same PHP
18
+ * instance for every request.
19
+ *
20
+ * This is suitable for CLI contexts where:
21
+ * - Only one PHP instance is needed
22
+ * - Runtime rotation is handled separately via php.enableRuntimeRotation()
23
+ * - Concurrency is not a concern (each worker has its own instance)
24
+ */
25
+ export declare class SinglePHPInstanceManager implements PHPInstanceManager {
26
+ private php;
27
+ private phpPromise;
28
+ private phpFactory?;
29
+ private isAcquired;
30
+ constructor(options: SinglePHPInstanceManagerOptions);
31
+ getPrimaryPhp(): Promise<PHP>;
32
+ acquirePHPInstance(): Promise<AcquiredPHP>;
33
+ [Symbol.asyncDispose](): Promise<void>;
34
+ }
@@ -1,4 +1,4 @@
1
- export declare const SupportedPHPVersions: readonly ["8.4", "8.3", "8.2", "8.1", "8.0", "7.4", "7.3", "7.2"];
2
- export declare const LatestSupportedPHPVersion: "8.4";
1
+ export declare const SupportedPHPVersions: readonly ["8.5", "8.4", "8.3", "8.2", "8.1", "8.0", "7.4", "7.3", "7.2"];
2
+ export declare const LatestSupportedPHPVersion: "8.5";
3
3
  export declare const SupportedPHPVersionsList: string[];
4
4
  export type SupportedPHPVersion = (typeof SupportedPHPVersions)[number];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@php-wasm/universal",
3
- "version": "3.0.22",
3
+ "version": "3.0.29",
4
4
  "description": "PHP.wasm – emscripten bindings for PHP",
5
5
  "repository": {
6
6
  "type": "git",
@@ -37,18 +37,18 @@
37
37
  "module": "./index.js",
38
38
  "types": "index.d.ts",
39
39
  "license": "GPL-2.0-or-later",
40
- "gitHead": "a624d1a97dc639e152d335e6a801b2fad7f6b594",
40
+ "gitHead": "ce450285157be874d4a164b30c0a828946c2d3ad",
41
41
  "engines": {
42
42
  "node": ">=20.18.3",
43
43
  "npm": ">=10.1.0"
44
44
  },
45
45
  "dependencies": {
46
46
  "ini": "4.1.2",
47
- "@php-wasm/node-polyfills": "3.0.22",
48
- "@php-wasm/logger": "3.0.22",
49
- "@php-wasm/util": "3.0.22",
50
- "@php-wasm/stream-compression": "3.0.22",
51
- "@php-wasm/progress": "3.0.22"
47
+ "@php-wasm/node-polyfills": "3.0.29",
48
+ "@php-wasm/logger": "3.0.29",
49
+ "@php-wasm/util": "3.0.29",
50
+ "@php-wasm/stream-compression": "3.0.29",
51
+ "@php-wasm/progress": "3.0.29"
52
52
  },
53
53
  "packageManager": "npm@10.9.2",
54
54
  "overrides": {
@@ -56,8 +56,8 @@
56
56
  "react": "18.3.1",
57
57
  "react-dom": "18.3.1",
58
58
  "typescript": "5.4.5",
59
- "@playwright/test": "1.47.1",
60
- "ws": "^8.18.0",
59
+ "@playwright/test": "1.55.1",
60
+ "ws": "8.18.3",
61
61
  "tmp": "0.2.5",
62
62
  "form-data": "^4.0.4"
63
63
  },