@php-wasm/universal 1.1.2 → 1.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/lib/index.d.ts CHANGED
@@ -10,12 +10,12 @@ export { iteratePhpFiles as iterateFiles } from './iterate-files';
10
10
  export { writeFilesStreamToPhp } from './write-files-stream-to-php';
11
11
  export { PHPProcessManager } from './php-process-manager';
12
12
  export type { MaxPhpInstancesError, PHPFactory, PHPFactoryOptions, ProcessManagerOptions, SpawnedPHP, } from './php-process-manager';
13
- export { PHPResponse } from './php-response';
13
+ export { PHPResponse, StreamedPHPResponse } from './php-response';
14
14
  export type { PHPResponseData } from './php-response';
15
15
  export type { ErrnoError } from './rethrow-file-system-error';
16
16
  export { LatestSupportedPHPVersion, SupportedPHPVersions, SupportedPHPVersionsList, } from './supported-php-versions';
17
17
  export type { SupportedPHPVersion } from './supported-php-versions';
18
- export { PHP, __private__dont__use } from './php';
18
+ export { PHP, __private__dont__use, PHPExecutionFailureError } from './php';
19
19
  export type { MountHandler, UnmountFunction } from './php';
20
20
  export { loadPHPRuntime, getLoadedRuntime } from './load-php-runtime';
21
21
  export type { Emscripten } from './emscripten-types';
@@ -27,5 +27,5 @@ export { rotatePHPRuntime } from './rotate-php-runtime';
27
27
  export { writeFiles } from './write-files';
28
28
  export type { FileTree } from './write-files';
29
29
  export { DEFAULT_BASE_URL, ensurePathPrefix, removePathPrefix, toRelativeUrl, } from './urls';
30
- export { isExitCodeZero } from './is-exit-code-zero';
30
+ export { isExitCode } from './is-exit-code';
31
31
  export { proxyFileSystem } from './proxy-file-system';
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Check if the Emscripten-thrown error is an exit code 0 error.
3
+ *
4
+ * @param e The error to check
5
+ * @returns True if the error appears to represent an exit code or status
6
+ */
7
+ export declare function isExitCode(e: any): e is {
8
+ exitCode: number;
9
+ };
@@ -61,6 +61,7 @@ export declare class MaxPhpInstancesError extends Error {
61
61
  */
62
62
  export declare class PHPProcessManager implements AsyncDisposable {
63
63
  private primaryPhp?;
64
+ private primaryPhpPromise?;
64
65
  private primaryIdle;
65
66
  private nextInstance;
66
67
  /**
@@ -88,10 +89,23 @@ export declare class PHPProcessManager implements AsyncDisposable {
88
89
  * instance, or a newly spawned PHP instance – depending on the resource
89
90
  * availability.
90
91
  *
92
+ * @param considerPrimary - Whether to consider the primary PHP instance.
93
+ * It matters because PHP.cli() sets the SAPI to CLI and
94
+ * kills the entire process after it finishes running,
95
+ * making the primary PHP instance non-reusable for
96
+ * subsequent .run() calls. This is fine for one-off
97
+ * child PHP instances, but not for the primary PHP
98
+ * that's meant to continue working for the entire duration
99
+ * of the ProcessManager lifetime. Therefore, we don't
100
+ * consider the primary PHP instance by default unless
101
+ * the caller explicitly requests it.
102
+ *
91
103
  * @throws {MaxPhpInstancesError} when the maximum number of PHP instances is reached
92
104
  * and the waiting timeout is exceeded.
93
105
  */
94
- acquirePHPInstance(): Promise<SpawnedPHP>;
106
+ acquirePHPInstance({ considerPrimary, }?: {
107
+ considerPrimary?: boolean;
108
+ }): Promise<SpawnedPHP>;
95
109
  /**
96
110
  * Initiated spawning of a new PHP instance.
97
111
  * This function is synchronous on purpose – it needs to synchronously
@@ -7,7 +7,7 @@ export interface PHPResponseData {
7
7
  * Response body. Contains the output from `echo`,
8
8
  * `print`, inline HTML etc.
9
9
  */
10
- readonly bytes: ArrayBuffer;
10
+ readonly bytes: Uint8Array;
11
11
  /**
12
12
  * Stderr contents, if any.
13
13
  */
@@ -22,6 +22,56 @@ export interface PHPResponseData {
22
22
  */
23
23
  readonly httpStatusCode: number;
24
24
  }
25
+ export declare class StreamedPHPResponse {
26
+ /**
27
+ * Response headers.
28
+ */
29
+ private readonly headersStream;
30
+ /**
31
+ * Response body. Contains the output from `echo`,
32
+ * `print`, inline HTML etc.
33
+ */
34
+ readonly stdout: ReadableStream<Uint8Array>;
35
+ /**
36
+ * Stderr contents, if any.
37
+ */
38
+ readonly stderr: ReadableStream<Uint8Array>;
39
+ /**
40
+ * The exit code of the script. `0` is a success, anything
41
+ * else is an error.
42
+ */
43
+ readonly exitCode: Promise<number>;
44
+ private parsedHeaders;
45
+ private cachedStdoutText;
46
+ private cachedStderrText;
47
+ constructor(headers: ReadableStream<Uint8Array>, stdout: ReadableStream<Uint8Array>, stderr: ReadableStream<Uint8Array>, exitCode: Promise<number>);
48
+ /**
49
+ * True if the response is successful (HTTP status code 200-399),
50
+ * false otherwise.
51
+ */
52
+ ok(): Promise<boolean>;
53
+ /**
54
+ * Resolves when the response has finished processing – either successfully or not.
55
+ */
56
+ get finished(): Promise<void>;
57
+ /**
58
+ * Resolves once HTTP headers are available.
59
+ */
60
+ get headers(): Promise<Record<string, string[]>>;
61
+ /**
62
+ * Resolves once HTTP status code is available.
63
+ */
64
+ get httpStatusCode(): Promise<number>;
65
+ /**
66
+ * Exposes the stdout bytes as they're produced by the PHP instance
67
+ */
68
+ get stdoutText(): Promise<string>;
69
+ /**
70
+ * Exposes the stderr bytes as they're produced by the PHP instance
71
+ */
72
+ get stderrText(): Promise<string>;
73
+ private getParsedHeaders;
74
+ }
25
75
  /**
26
76
  * PHP response. Body is an `ArrayBuffer` because it can
27
77
  * contain binary data.
@@ -33,16 +83,17 @@ export declare class PHPResponse implements PHPResponseData {
33
83
  /** @inheritDoc */
34
84
  readonly headers: Record<string, string[]>;
35
85
  /** @inheritDoc */
36
- readonly bytes: ArrayBuffer;
86
+ readonly bytes: Uint8Array;
37
87
  /** @inheritDoc */
38
88
  readonly errors: string;
39
89
  /** @inheritDoc */
40
90
  readonly exitCode: number;
41
91
  /** @inheritDoc */
42
92
  readonly httpStatusCode: number;
43
- constructor(httpStatusCode: number, headers: Record<string, string[]>, body: ArrayBuffer, errors?: string, exitCode?: number);
93
+ constructor(httpStatusCode: number, headers: Record<string, string[]>, body: Uint8Array, errors?: string, exitCode?: number);
44
94
  static forHttpCode(httpStatusCode: number, text?: string): PHPResponse;
45
95
  static fromRawData(data: PHPResponseData): PHPResponse;
96
+ static fromStreamedResponse(streamedResponse: StreamedPHPResponse): Promise<PHPResponse>;
46
97
  toRawData(): PHPResponseData;
47
98
  /**
48
99
  * Response body as JSON.
package/lib/php.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { PHPResponse } from './php-response';
1
+ import { PHPResponse, StreamedPHPResponse } from './php-response';
2
2
  import type { PHPRuntimeId } from './load-php-runtime';
3
3
  import type { MessageListener, PHPRequest, PHPRequestHeaders, PHPRunOptions, SpawnHandler, PHPEventListener, PHPEvent } from './universal-php';
4
4
  import type { RmDirOptions, ListFilesOptions } from './fs-helpers';
@@ -179,16 +179,111 @@ export declare class PHP implements Disposable {
179
179
  *
180
180
  * @example
181
181
  * ```js
182
- * const result = await php.run(`<?php
183
- * $fp = fopen('php://stderr', 'w');
184
- * fwrite($fp, "Hello, world!");
185
- * `);
182
+ * const result = await php.run({
183
+ * code: `<?php
184
+ * $fp = fopen('php://stderr', 'w');
185
+ * fwrite($fp, "Hello, world!");
186
+ * `
187
+ * });
186
188
  * // result.errors === "Hello, world!"
187
189
  * ```
188
190
  *
189
- * @param options - PHP runtime options.
191
+ * @deprecated Use stream() instead.
192
+ * @param request - PHP runtime options.
190
193
  */
191
194
  run(request: PHPRunOptions): Promise<PHPResponse>;
195
+ /**
196
+ * Runs PHP code and returns a StreamedPHPResponse object that can be used to
197
+ * process the output incrementally.
198
+ *
199
+ * This low-level method directly interacts with the WebAssembly
200
+ * PHP interpreter and provides streaming capabilities for processing
201
+ * PHP output as it becomes available.
202
+ *
203
+ * Every time you call stream(), it prepares the PHP
204
+ * environment and:
205
+ *
206
+ * * Resets the internal PHP state
207
+ * * Populates superglobals ($_SERVER, $_GET, etc.)
208
+ * * Handles file uploads
209
+ * * Populates input streams (stdin, argv, etc.)
210
+ * * Sets the current working directory
211
+ *
212
+ * You can use stream() in two primary modes:
213
+ *
214
+ * ### Code snippet mode
215
+ *
216
+ * In this mode, you pass a string containing PHP code to run.
217
+ *
218
+ * ```ts
219
+ * const streamedResponse = await php.stream({
220
+ * code: `<?php echo "Hello world!";`
221
+ * });
222
+ * // Process output incrementally
223
+ * for await (const chunk of streamedResponse.text) {
224
+ * console.log(chunk);
225
+ * }
226
+ * ```
227
+ *
228
+ * In this mode, information like __DIR__ or __FILE__ isn't very
229
+ * useful because the code is not associated with any file.
230
+ *
231
+ * Under the hood, the PHP snippet is passed to the `zend_eval_string`
232
+ * C function.
233
+ *
234
+ * ### File mode
235
+ *
236
+ * In the file mode, you pass a scriptPath and PHP executes a file
237
+ * found at that path:
238
+ *
239
+ * ```ts
240
+ * php.writeFile(
241
+ * "/www/index.php",
242
+ * `<?php echo "Hello world!";"`
243
+ * );
244
+ * const streamedResponse = await php.stream({
245
+ * scriptPath: "/www/index.php"
246
+ * });
247
+ * // Process output incrementally
248
+ * for await (const chunk of streamedResponse.text) {
249
+ * console.log(chunk);
250
+ * }
251
+ * ```
252
+ *
253
+ * In this mode, you can rely on path-related information like __DIR__
254
+ * or __FILE__.
255
+ *
256
+ * Under the hood, the PHP file is executed with the `php_execute_script`
257
+ * C function.
258
+ *
259
+ * The `stream()` method cannot be used in conjunction with `cli()`.
260
+ *
261
+ * @example
262
+ * ```js
263
+ * const streamedResponse = await php.stream({
264
+ * code: `<?php
265
+ * for ($i = 0; $i < 5; $i++) {
266
+ * echo "Line $i\n";
267
+ * flush();
268
+ * }
269
+ * `
270
+ * });
271
+ *
272
+ * // Process output as it becomes available
273
+ * for await (const chunk of streamedResponse.text) {
274
+ * console.log('Received:', chunk);
275
+ * }
276
+ *
277
+ * // Get the final exit code
278
+ * const exitCode = await streamedResponse.exitCode;
279
+ * console.log('Exit code:', exitCode);
280
+ * ```
281
+ *
282
+ * @see run() – a synchronous version of this method.
283
+ * @param request - PHP runtime options.
284
+ * @returns A StreamedPHPResponse object.
285
+ */
286
+ runStream(request: PHPRunOptions): Promise<StreamedPHPResponse>;
192
287
  /**
193
288
  * Defines a constant in the PHP runtime.
194
289
  * @param key - The name of the constant.
@@ -340,7 +435,9 @@ export declare class PHP implements Disposable {
340
435
  * @param argv - The arguments to pass to the CLI.
341
436
  * @returns The exit code of the CLI session.
342
437
  */
343
- cli(argv: string[]): Promise<number>;
438
+ cli(argv: string[], options?: {
439
+ env?: Record<string, string>;
440
+ }): Promise<StreamedPHPResponse>;
344
441
  setSkipShebang(shouldSkip: boolean): void;
345
442
  exit(code?: number): void;
346
443
  [Symbol.dispose](): void;
@@ -4,8 +4,8 @@ type Runtime = {
4
4
  };
5
5
  export declare class UnhandledRejectionsTarget extends EventTarget {
6
6
  listenersCount: number;
7
- addEventListener(type: unknown, callback: unknown): void;
8
- removeEventListener(type: unknown, callback: unknown): void;
7
+ addEventListener(type: unknown, callback: unknown, options?: boolean | AddEventListenerOptions): void;
8
+ removeEventListener(type: unknown, callback: unknown, options?: boolean | EventListenerOptions): void;
9
9
  hasListeners(): boolean;
10
10
  }
11
11
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@php-wasm/universal",
3
- "version": "1.1.2",
3
+ "version": "1.1.3",
4
4
  "description": "PHP.wasm – emscripten bindings for PHP",
5
5
  "repository": {
6
6
  "type": "git",
@@ -37,7 +37,7 @@
37
37
  "module": "./index.js",
38
38
  "types": "index.d.ts",
39
39
  "license": "GPL-2.0-or-later",
40
- "gitHead": "59c2db1ec41efa10ffa01e6e1ea7ac6e78bc693e",
40
+ "gitHead": "977f8e90eabb2c8d4eed75677ddd9fb6c13274ae",
41
41
  "engines": {
42
42
  "node": ">=20.18.3",
43
43
  "npm": ">=10.1.0"
@@ -45,11 +45,11 @@
45
45
  "dependencies": {
46
46
  "comlink": "^4.4.1",
47
47
  "ini": "4.1.2",
48
- "@php-wasm/node-polyfills": "1.1.2",
49
- "@php-wasm/logger": "1.1.2",
50
- "@php-wasm/util": "1.1.2",
51
- "@php-wasm/stream-compression": "1.1.2",
52
- "@php-wasm/progress": "1.1.2"
48
+ "@php-wasm/node-polyfills": "1.1.3",
49
+ "@php-wasm/logger": "1.1.3",
50
+ "@php-wasm/util": "1.1.3",
51
+ "@php-wasm/stream-compression": "1.1.3",
52
+ "@php-wasm/progress": "1.1.3"
53
53
  },
54
54
  "overrides": {
55
55
  "rollup": "^4.34.6",
@@ -1,7 +0,0 @@
1
- /**
2
- * Check if the Emscripten-thrown error is an exit code 0 error.
3
- *
4
- * @param e The error to check
5
- * @returns True if the error is an exit code 0 error
6
- */
7
- export declare function isExitCodeZero(e: any): boolean;