@php-wasm/universal 0.7.0 → 0.7.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.cjs +14 -12
- package/index.js +1360 -1032
- package/lib/base-php.d.ts +10 -6
- package/lib/index.d.ts +3 -0
- package/lib/php-process-manager.d.ts +104 -0
- package/lib/php-request-handler.d.ts +38 -8
- package/lib/php-response.d.ts +1 -0
- package/lib/universal-php.d.ts +7 -1
- package/package.json +2 -2
package/lib/base-php.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { PHPRequestHandler, PHPRequestHandlerConfiguration } from './php-request-handler';
|
|
2
1
|
import { PHPResponse } from './php-response';
|
|
3
2
|
import type { PHPRuntimeId } from './load-php-runtime';
|
|
4
3
|
import { IsomorphicLocalPHP, MessageListener, PHPRequest, PHPRequestHeaders, PHPRunOptions, RmDirOptions, ListFilesOptions, SpawnHandler, PHPEventListener, PHPEvent } from './universal-php';
|
|
5
4
|
import { Semaphore } from '../../../util/src/index.ts';
|
|
5
|
+
import { PHPRequestHandler } from './php-request-handler';
|
|
6
6
|
export declare const __private__dont__use: unique symbol;
|
|
7
7
|
export declare class PHPExecutionFailureError extends Error {
|
|
8
8
|
response: PHPResponse;
|
|
@@ -17,10 +17,10 @@ export declare class PHPExecutionFailureError extends Error {
|
|
|
17
17
|
* It exposes a minimal set of methods to run PHP scripts and to
|
|
18
18
|
* interact with the PHP filesystem.
|
|
19
19
|
*/
|
|
20
|
-
export declare abstract class BasePHP implements IsomorphicLocalPHP {
|
|
20
|
+
export declare abstract class BasePHP implements IsomorphicLocalPHP, Disposable {
|
|
21
21
|
#private;
|
|
22
22
|
protected [__private__dont__use]: any;
|
|
23
|
-
requestHandler?: PHPRequestHandler
|
|
23
|
+
requestHandler?: PHPRequestHandler<any>;
|
|
24
24
|
/**
|
|
25
25
|
* An exclusive lock that prevent multiple requests from running at
|
|
26
26
|
* the same time.
|
|
@@ -31,9 +31,9 @@ export declare abstract class BasePHP implements IsomorphicLocalPHP {
|
|
|
31
31
|
*
|
|
32
32
|
* @internal
|
|
33
33
|
* @param PHPRuntime - Optional. PHP Runtime ID as initialized by loadPHPRuntime.
|
|
34
|
-
* @param
|
|
34
|
+
* @param requestHandlerOptions - Optional. Options for the PHPRequestHandler. If undefined, no request handler will be initialized.
|
|
35
35
|
*/
|
|
36
|
-
constructor(PHPRuntimeId?: PHPRuntimeId
|
|
36
|
+
constructor(PHPRuntimeId?: PHPRuntimeId);
|
|
37
37
|
addEventListener(eventType: PHPEvent['type'], listener: PHPEventListener): void;
|
|
38
38
|
removeEventListener(eventType: PHPEvent['type'], listener: PHPEventListener): void;
|
|
39
39
|
dispatchEvent<Event extends PHPEvent>(event: Event): void;
|
|
@@ -58,7 +58,10 @@ export declare abstract class BasePHP implements IsomorphicLocalPHP {
|
|
|
58
58
|
setPhpIniEntry(key: string, value: string): void;
|
|
59
59
|
/** @inheritDoc */
|
|
60
60
|
chdir(path: string): void;
|
|
61
|
-
/**
|
|
61
|
+
/**
|
|
62
|
+
* Do not use. Use new PHPRequestHandler() instead.
|
|
63
|
+
* @deprecated
|
|
64
|
+
*/
|
|
62
65
|
request(request: PHPRequest): Promise<PHPResponse>;
|
|
63
66
|
/** @inheritDoc */
|
|
64
67
|
run(request: PHPRunOptions): Promise<PHPResponse>;
|
|
@@ -97,6 +100,7 @@ export declare abstract class BasePHP implements IsomorphicLocalPHP {
|
|
|
97
100
|
*/
|
|
98
101
|
hotSwapPHPRuntime(runtime: number, cwd?: string): void;
|
|
99
102
|
exit(code?: number): void;
|
|
103
|
+
[Symbol.dispose](): void;
|
|
100
104
|
}
|
|
101
105
|
export declare function normalizeHeaders(headers: PHPRequestHeaders): PHPRequestHeaders;
|
|
102
106
|
type EmscriptenFS = any;
|
package/lib/index.d.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
export type { IsomorphicLocalPHP, IsomorphicRemotePHP, MessageListener, PHPOutput, PHPRunOptions, UniversalPHP, ListFilesOptions, RmDirOptions, PHPEvent, PHPEventListener, HTTPMethod, PHPRequest, PHPRequestHeaders, SpawnHandler, } from './universal-php';
|
|
2
2
|
export { UnhandledRejectionsTarget } from './wasm-error-reporting';
|
|
3
|
+
export { HttpCookieStore } from './http-cookie-store';
|
|
3
4
|
export type { IteratePhpFilesOptions as IterateFilesOptions } from './iterate-files';
|
|
4
5
|
export { iteratePhpFiles as iterateFiles } from './iterate-files';
|
|
5
6
|
export { writeFilesStreamToPhp } from './write-files-stream-to-php';
|
|
7
|
+
export { PHPProcessManager } from './php-process-manager';
|
|
8
|
+
export type { MaxPhpInstancesError, PHPFactory, PHPFactoryOptions, ProcessManagerOptions, SpawnedPHP, } from './php-process-manager';
|
|
6
9
|
export { PHPResponse } from './php-response';
|
|
7
10
|
export type { PHPResponseData } from './php-response';
|
|
8
11
|
export type { ErrnoError } from './rethrow-file-system-error';
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { BasePHP } from './base-php';
|
|
2
|
+
export type PHPFactoryOptions = {
|
|
3
|
+
isPrimary: boolean;
|
|
4
|
+
};
|
|
5
|
+
export type PHPFactory<PHP extends BasePHP> = (options: PHPFactoryOptions) => Promise<PHP>;
|
|
6
|
+
export interface ProcessManagerOptions<PHP extends BasePHP> {
|
|
7
|
+
/**
|
|
8
|
+
* The maximum number of PHP instances that can exist at
|
|
9
|
+
* the same time.
|
|
10
|
+
*/
|
|
11
|
+
maxPhpInstances?: number;
|
|
12
|
+
/**
|
|
13
|
+
* The number of milliseconds to wait for a PHP instance when
|
|
14
|
+
* we have reached the maximum number of PHP instances and
|
|
15
|
+
* cannot spawn a new one. If the timeout is reached, we assume
|
|
16
|
+
* all the PHP instances are deadlocked and a throw MaxPhpInstancesError.
|
|
17
|
+
*
|
|
18
|
+
* Default: 5000
|
|
19
|
+
*/
|
|
20
|
+
timeout?: number;
|
|
21
|
+
/**
|
|
22
|
+
* The primary PHP instance that's never killed. This instance
|
|
23
|
+
* contains the reference filesystem used by all other PHP instances.
|
|
24
|
+
*/
|
|
25
|
+
primaryPhp?: PHP;
|
|
26
|
+
/**
|
|
27
|
+
* A factory function used for spawning new PHP instances.
|
|
28
|
+
*/
|
|
29
|
+
phpFactory?: PHPFactory<PHP>;
|
|
30
|
+
}
|
|
31
|
+
export interface SpawnedPHP<PHP extends BasePHP> {
|
|
32
|
+
php: PHP;
|
|
33
|
+
reap: () => void;
|
|
34
|
+
}
|
|
35
|
+
export declare class MaxPhpInstancesError extends Error {
|
|
36
|
+
constructor(limit: number);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* A PHP Process manager.
|
|
40
|
+
*
|
|
41
|
+
* Maintains:
|
|
42
|
+
* * A single "primary" PHP instance that's never killed – it contains the
|
|
43
|
+
* reference filesystem used by all other PHP instances.
|
|
44
|
+
* * A pool of disposable PHP instances that are spawned to handle a single
|
|
45
|
+
* request and reaped immediately after.
|
|
46
|
+
*
|
|
47
|
+
* When a new request comes in, PHPProcessManager yields the idle instance to handle it,
|
|
48
|
+
* and immediately starts initializing a new idle instance. In other words, for n concurrent
|
|
49
|
+
* requests, there are at most n+1 PHP instances running at the same time.
|
|
50
|
+
*
|
|
51
|
+
* A slight nuance is that the first idle instance is not initialized until the first
|
|
52
|
+
* concurrent request comes in. This is because many use-cases won't involve parallel
|
|
53
|
+
* requests and, for those, we can avoid eagerly spinning up a second PHP instance.
|
|
54
|
+
*
|
|
55
|
+
* This strategy is inspired by Cowboy, an Erlang HTTP server. Handling a single extra
|
|
56
|
+
* request can happen immediately, while handling multiple extra requests requires
|
|
57
|
+
* extra time to spin up a few PHP instances. This is a more resource-friendly tradeoff
|
|
58
|
+
* than keeping 5 idle instances at all times.
|
|
59
|
+
*/
|
|
60
|
+
export declare class PHPProcessManager<PHP extends BasePHP> implements AsyncDisposable {
|
|
61
|
+
private primaryPhp?;
|
|
62
|
+
private primaryIdle;
|
|
63
|
+
private nextInstance;
|
|
64
|
+
/**
|
|
65
|
+
* All spawned PHP instances, including the primary PHP instance.
|
|
66
|
+
* Used for bookkeeping and reaping all instances on dispose.
|
|
67
|
+
*/
|
|
68
|
+
private allInstances;
|
|
69
|
+
private phpFactory?;
|
|
70
|
+
private maxPhpInstances;
|
|
71
|
+
private semaphore;
|
|
72
|
+
constructor(options?: ProcessManagerOptions<PHP>);
|
|
73
|
+
/**
|
|
74
|
+
* Get the primary PHP instance.
|
|
75
|
+
*
|
|
76
|
+
* If the primary PHP instance is not set, it will be spawned
|
|
77
|
+
* using the provided phpFactory.
|
|
78
|
+
*
|
|
79
|
+
* @throws {Error} when called twice before the first call is resolved.
|
|
80
|
+
*/
|
|
81
|
+
getPrimaryPhp(): Promise<PHP>;
|
|
82
|
+
/**
|
|
83
|
+
* Get a PHP instance.
|
|
84
|
+
*
|
|
85
|
+
* It could be either the primary PHP instance, an idle disposable PHP instance,
|
|
86
|
+
* or a newly spawned PHP instance – depending on the resource availability.
|
|
87
|
+
*
|
|
88
|
+
* @throws {MaxPhpInstancesError} when the maximum number of PHP instances is reached
|
|
89
|
+
* and the waiting timeout is exceeded.
|
|
90
|
+
*/
|
|
91
|
+
acquirePHPInstance(): Promise<SpawnedPHP<PHP>>;
|
|
92
|
+
/**
|
|
93
|
+
* Initiated spawning of a new PHP instance.
|
|
94
|
+
* This function is synchronous on purpose – it needs to synchronously
|
|
95
|
+
* add the spawn promise to the allInstances array without waiting
|
|
96
|
+
* for PHP to spawn.
|
|
97
|
+
*/
|
|
98
|
+
private spawn;
|
|
99
|
+
/**
|
|
100
|
+
* Actually acquires the lock and spawns a new PHP instance.
|
|
101
|
+
*/
|
|
102
|
+
private doSpawn;
|
|
103
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
104
|
+
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { BasePHP } from './base-php';
|
|
2
2
|
import { PHPResponse } from './php-response';
|
|
3
3
|
import { PHPRequest } from './universal-php';
|
|
4
|
+
import { PHPFactoryOptions, PHPProcessManager } from './php-process-manager';
|
|
4
5
|
export type RewriteRule = {
|
|
5
6
|
match: RegExp;
|
|
6
7
|
replacement: string;
|
|
7
8
|
};
|
|
8
|
-
|
|
9
|
+
interface BaseConfiguration {
|
|
9
10
|
/**
|
|
10
11
|
* The directory in the PHP filesystem where the server will look
|
|
11
12
|
* for the files to serve. Default: `/var/www`.
|
|
@@ -20,6 +21,30 @@ export interface PHPRequestHandlerConfiguration {
|
|
|
20
21
|
*/
|
|
21
22
|
rewriteRules?: RewriteRule[];
|
|
22
23
|
}
|
|
24
|
+
export type PHPRequestHandlerFactoryArgs<PHP extends BasePHP> = PHPFactoryOptions & {
|
|
25
|
+
requestHandler: PHPRequestHandler<PHP>;
|
|
26
|
+
};
|
|
27
|
+
export type PHPRequestHandlerConfiguration<PHP extends BasePHP> = BaseConfiguration & ({
|
|
28
|
+
/**
|
|
29
|
+
* PHPProcessManager is required because the request handler needs
|
|
30
|
+
* to make a decision for each request.
|
|
31
|
+
*
|
|
32
|
+
* Static assets are served using the primary PHP's filesystem, even
|
|
33
|
+
* when serving 100 static files concurrently. No new PHP interpreter
|
|
34
|
+
* is ever created as there's no need for it.
|
|
35
|
+
*
|
|
36
|
+
* Dynamic PHP requests, however, require grabbing an available PHP
|
|
37
|
+
* interpreter, and that's where the PHPProcessManager comes in.
|
|
38
|
+
*/
|
|
39
|
+
processManager: PHPProcessManager<PHP>;
|
|
40
|
+
} | {
|
|
41
|
+
phpFactory: (requestHandler: PHPRequestHandlerFactoryArgs<PHP>) => Promise<PHP>;
|
|
42
|
+
/**
|
|
43
|
+
* The maximum number of PHP instances that can exist at
|
|
44
|
+
* the same time.
|
|
45
|
+
*/
|
|
46
|
+
maxPhpInstances?: number;
|
|
47
|
+
});
|
|
23
48
|
/**
|
|
24
49
|
* Handles HTTP requests using PHP runtime as a backend.
|
|
25
50
|
*
|
|
@@ -74,18 +99,23 @@ export interface PHPRequestHandlerConfiguration {
|
|
|
74
99
|
* // "Hi from PHP!"
|
|
75
100
|
* ```
|
|
76
101
|
*/
|
|
77
|
-
export declare class PHPRequestHandler {
|
|
102
|
+
export declare class PHPRequestHandler<PHP extends BasePHP> {
|
|
78
103
|
#private;
|
|
79
104
|
rewriteRules: RewriteRule[];
|
|
105
|
+
processManager: PHPProcessManager<PHP>;
|
|
80
106
|
/**
|
|
81
|
-
* The
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
107
|
+
* The request handler needs to decide whether to serve a static asset or
|
|
108
|
+
* run the PHP interpreter. For static assets it should just reuse the primary
|
|
109
|
+
* PHP even if there's 50 concurrent requests to serve. However, for
|
|
110
|
+
* dynamic PHP requests, it needs to grab an available interpreter.
|
|
111
|
+
* Therefore, it cannot just accept PHP as an argument as serving requests
|
|
112
|
+
* requires access to ProcessManager.
|
|
113
|
+
*
|
|
85
114
|
* @param php - The PHP instance.
|
|
86
115
|
* @param config - Request Handler configuration.
|
|
87
116
|
*/
|
|
88
|
-
constructor(
|
|
117
|
+
constructor(config: PHPRequestHandlerConfiguration<PHP>);
|
|
118
|
+
getPrimaryPhp(): Promise<PHP>;
|
|
89
119
|
/**
|
|
90
120
|
* Converts a path to an absolute URL based at the PHPRequestHandler
|
|
91
121
|
* root.
|
|
@@ -102,7 +132,6 @@ export declare class PHPRequestHandler {
|
|
|
102
132
|
* @returns The relative path.
|
|
103
133
|
*/
|
|
104
134
|
internalUrlToPath(internalUrl: string): string;
|
|
105
|
-
get isRequestRunning(): boolean;
|
|
106
135
|
/**
|
|
107
136
|
* The absolute URL of this PHPRequestHandler instance.
|
|
108
137
|
*/
|
|
@@ -187,3 +216,4 @@ export declare function seemsLikeAPHPRequestHandlerPath(path: string): boolean;
|
|
|
187
216
|
* @returns The path with the rules applied.
|
|
188
217
|
*/
|
|
189
218
|
export declare function applyRewriteRules(path: string, rules: RewriteRule[]): string;
|
|
219
|
+
export {};
|
package/lib/php-response.d.ts
CHANGED
|
@@ -41,6 +41,7 @@ export declare class PHPResponse implements PHPResponseData {
|
|
|
41
41
|
/** @inheritDoc */
|
|
42
42
|
readonly httpStatusCode: number;
|
|
43
43
|
constructor(httpStatusCode: number, headers: Record<string, string[]>, body: ArrayBuffer, errors?: string, exitCode?: number);
|
|
44
|
+
static forHttpCode(httpStatusCode: number, text?: string): PHPResponse;
|
|
44
45
|
static fromRawData(data: PHPResponseData): PHPResponse;
|
|
45
46
|
toRawData(): PHPResponseData;
|
|
46
47
|
/**
|
package/lib/universal-php.d.ts
CHANGED
|
@@ -293,7 +293,13 @@ type ChildProcess = EventEmitter & {
|
|
|
293
293
|
stderr: EventEmitter;
|
|
294
294
|
};
|
|
295
295
|
export type SpawnHandler = (command: string, args: string[]) => ChildProcess;
|
|
296
|
-
|
|
296
|
+
/**
|
|
297
|
+
* The omited methods must either be called synchronously before
|
|
298
|
+
* the PHP internal state is initialized, or with a complex argument
|
|
299
|
+
* that can't be serialized over a remote connection. Therefeore,
|
|
300
|
+
* they don't make sense in a remote PHP instance.
|
|
301
|
+
*/
|
|
302
|
+
export type IsomorphicRemotePHP = Remote<Omit<IsomorphicLocalPHP, 'setSapiName' | 'setPhpIniEntry' | 'setPhpIniPath'>>;
|
|
297
303
|
export type UniversalPHP = IsomorphicLocalPHP | IsomorphicRemotePHP;
|
|
298
304
|
export type HTTPMethod = 'GET' | 'POST' | 'HEAD' | 'OPTIONS' | 'PATCH' | 'PUT' | 'DELETE';
|
|
299
305
|
export type PHPRequestHeaders = Record<string, string>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@php-wasm/universal",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.3",
|
|
4
4
|
"description": "PHP.wasm – emscripten bindings for PHP",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"main": "./index.cjs",
|
|
37
37
|
"module": "./index.js",
|
|
38
38
|
"license": "GPL-2.0-or-later",
|
|
39
|
-
"gitHead": "
|
|
39
|
+
"gitHead": "e8fedf92bbead5cec963c8d6976e7143d8e68721",
|
|
40
40
|
"engines": {
|
|
41
41
|
"node": ">=18.18.0",
|
|
42
42
|
"npm": ">=8.11.0"
|