@php-wasm/node 0.7.1 → 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.d.ts CHANGED
@@ -36,6 +36,7 @@ declare class PHPResponse implements PHPResponseData {
36
36
  /** @inheritDoc */
37
37
  readonly httpStatusCode: number;
38
38
  constructor(httpStatusCode: number, headers: Record<string, string[]>, body: ArrayBuffer, errors?: string, exitCode?: number);
39
+ static forHttpCode(httpStatusCode: number, text?: string): PHPResponse;
39
40
  static fromRawData(data: PHPResponseData): PHPResponse;
40
41
  toRawData(): PHPResponseData;
41
42
  /**
@@ -414,23 +415,57 @@ export interface ListFilesOptions {
414
415
  */
415
416
  prependPath: boolean;
416
417
  }
417
- declare const SupportedPHPVersions: readonly [
418
- "8.3",
419
- "8.2",
420
- "8.1",
421
- "8.0",
422
- "7.4",
423
- "7.3",
424
- "7.2",
425
- "7.1",
426
- "7.0"
427
- ];
428
- export type SupportedPHPVersion = (typeof SupportedPHPVersions)[number];
418
+ export type PHPRuntimeId = number;
419
+ export type PHPRuntime = any;
420
+ export type PHPLoaderModule = {
421
+ dependencyFilename: string;
422
+ dependenciesTotalSize: number;
423
+ init: (jsRuntime: string, options: EmscriptenOptions) => PHPRuntime;
424
+ };
425
+ export type EmscriptenOptions = {
426
+ onAbort?: (message: string) => void;
427
+ /**
428
+ * Set to true for debugging tricky WebAssembly errors.
429
+ */
430
+ debug?: boolean;
431
+ ENV?: Record<string, string>;
432
+ locateFile?: (path: string) => string;
433
+ noInitialRun?: boolean;
434
+ print?: (message: string) => void;
435
+ printErr?: (message: string) => void;
436
+ quit?: (status: number, toThrow: any) => void;
437
+ onRuntimeInitialized?: () => void;
438
+ monitorRunDependencies?: (left: number) => void;
439
+ onMessage?: (listener: EmscriptenMessageListener) => void;
440
+ instantiateWasm?: (info: WebAssembly.Imports, receiveInstance: (instance: WebAssembly.Instance, module: WebAssembly.Module) => void) => void;
441
+ } & Record<string, any>;
442
+ export type EmscriptenMessageListener = (type: string, data: string) => void;
443
+ export interface SemaphoreOptions {
444
+ /**
445
+ * The maximum number of concurrent locks.
446
+ */
447
+ concurrency: number;
448
+ /**
449
+ * The maximum time to wait for a lock to become available.
450
+ */
451
+ timeout?: number;
452
+ }
453
+ declare class Semaphore {
454
+ private _running;
455
+ private concurrency;
456
+ private timeout?;
457
+ private queue;
458
+ constructor({ concurrency, timeout }: SemaphoreOptions);
459
+ get remaining(): number;
460
+ get running(): number;
461
+ acquire(): Promise<() => void>;
462
+ run<T>(fn: () => T | Promise<T>): Promise<T>;
463
+ }
429
464
  export type RewriteRule = {
430
465
  match: RegExp;
431
466
  replacement: string;
432
467
  };
433
- export interface PHPRequestHandlerConfiguration {
468
+ export interface BaseConfiguration {
434
469
  /**
435
470
  * The directory in the PHP filesystem where the server will look
436
471
  * for the files to serve. Default: `/var/www`.
@@ -445,18 +480,47 @@ export interface PHPRequestHandlerConfiguration {
445
480
  */
446
481
  rewriteRules?: RewriteRule[];
447
482
  }
448
- declare class PHPRequestHandler {
449
- #private;
450
- rewriteRules: RewriteRule[];
483
+ export type PHPRequestHandlerFactoryArgs<PHP extends BasePHP> = PHPFactoryOptions & {
484
+ requestHandler: PHPRequestHandler<PHP>;
485
+ };
486
+ export type PHPRequestHandlerConfiguration<PHP extends BasePHP> = BaseConfiguration & ({
487
+ /**
488
+ * PHPProcessManager is required because the request handler needs
489
+ * to make a decision for each request.
490
+ *
491
+ * Static assets are served using the primary PHP's filesystem, even
492
+ * when serving 100 static files concurrently. No new PHP interpreter
493
+ * is ever created as there's no need for it.
494
+ *
495
+ * Dynamic PHP requests, however, require grabbing an available PHP
496
+ * interpreter, and that's where the PHPProcessManager comes in.
497
+ */
498
+ processManager: PHPProcessManager<PHP>;
499
+ } | {
500
+ phpFactory: (requestHandler: PHPRequestHandlerFactoryArgs<PHP>) => Promise<PHP>;
451
501
  /**
452
- * The PHP instance
502
+ * The maximum number of PHP instances that can exist at
503
+ * the same time.
453
504
  */
454
- php: BasePHP;
505
+ maxPhpInstances?: number;
506
+ });
507
+ declare class PHPRequestHandler<PHP extends BasePHP> {
508
+ #private;
509
+ rewriteRules: RewriteRule[];
510
+ processManager: PHPProcessManager<PHP>;
455
511
  /**
512
+ * The request handler needs to decide whether to serve a static asset or
513
+ * run the PHP interpreter. For static assets it should just reuse the primary
514
+ * PHP even if there's 50 concurrent requests to serve. However, for
515
+ * dynamic PHP requests, it needs to grab an available interpreter.
516
+ * Therefore, it cannot just accept PHP as an argument as serving requests
517
+ * requires access to ProcessManager.
518
+ *
456
519
  * @param php - The PHP instance.
457
520
  * @param config - Request Handler configuration.
458
521
  */
459
- constructor(php: BasePHP, config?: PHPRequestHandlerConfiguration);
522
+ constructor(config: PHPRequestHandlerConfiguration<PHP>);
523
+ getPrimaryPhp(): Promise<PHP>;
460
524
  /**
461
525
  * Converts a path to an absolute URL based at the PHPRequestHandler
462
526
  * root.
@@ -473,7 +537,6 @@ declare class PHPRequestHandler {
473
537
  * @returns The relative path.
474
538
  */
475
539
  internalUrlToPath(internalUrl: string): string;
476
- get isRequestRunning(): boolean;
477
540
  /**
478
541
  * The absolute URL of this PHPRequestHandler instance.
479
542
  */
@@ -533,57 +596,11 @@ declare class PHPRequestHandler {
533
596
  */
534
597
  request(request: PHPRequest): Promise<PHPResponse>;
535
598
  }
536
- export type PHPRuntimeId = number;
537
- export type PHPRuntime = any;
538
- export type PHPLoaderModule = {
539
- dependencyFilename: string;
540
- dependenciesTotalSize: number;
541
- init: (jsRuntime: string, options: EmscriptenOptions) => PHPRuntime;
542
- };
543
- export type EmscriptenOptions = {
544
- onAbort?: (message: string) => void;
545
- /**
546
- * Set to true for debugging tricky WebAssembly errors.
547
- */
548
- debug?: boolean;
549
- ENV?: Record<string, string>;
550
- locateFile?: (path: string) => string;
551
- noInitialRun?: boolean;
552
- print?: (message: string) => void;
553
- printErr?: (message: string) => void;
554
- quit?: (status: number, toThrow: any) => void;
555
- onRuntimeInitialized?: () => void;
556
- monitorRunDependencies?: (left: number) => void;
557
- onMessage?: (listener: EmscriptenMessageListener) => void;
558
- instantiateWasm?: (info: WebAssembly.Imports, receiveInstance: (instance: WebAssembly.Instance, module: WebAssembly.Module) => void) => void;
559
- } & Record<string, any>;
560
- export type EmscriptenMessageListener = (type: string, data: string) => void;
561
- export interface SemaphoreOptions {
562
- /**
563
- * The maximum number of concurrent locks.
564
- */
565
- concurrency: number;
566
- /**
567
- * The maximum time to wait for a lock to become available.
568
- */
569
- timeout?: number;
570
- }
571
- declare class Semaphore {
572
- private _running;
573
- private concurrency;
574
- private timeout?;
575
- private queue;
576
- constructor({ concurrency, timeout }: SemaphoreOptions);
577
- get remaining(): number;
578
- get running(): number;
579
- acquire(): Promise<() => void>;
580
- run<T>(fn: () => T | Promise<T>): Promise<T>;
581
- }
582
599
  declare const __private__dont__use: unique symbol;
583
- declare abstract class BasePHP implements IsomorphicLocalPHP {
600
+ declare abstract class BasePHP implements IsomorphicLocalPHP, Disposable {
584
601
  #private;
585
602
  protected [__private__dont__use]: any;
586
- requestHandler?: PHPRequestHandler;
603
+ requestHandler?: PHPRequestHandler<any>;
587
604
  /**
588
605
  * An exclusive lock that prevent multiple requests from running at
589
606
  * the same time.
@@ -594,9 +611,9 @@ declare abstract class BasePHP implements IsomorphicLocalPHP {
594
611
  *
595
612
  * @internal
596
613
  * @param PHPRuntime - Optional. PHP Runtime ID as initialized by loadPHPRuntime.
597
- * @param serverOptions - Optional. Options for the PHPRequestHandler. If undefined, no request handler will be initialized.
614
+ * @param requestHandlerOptions - Optional. Options for the PHPRequestHandler. If undefined, no request handler will be initialized.
598
615
  */
599
- constructor(PHPRuntimeId?: PHPRuntimeId, serverOptions?: PHPRequestHandlerConfiguration);
616
+ constructor(PHPRuntimeId?: PHPRuntimeId);
600
617
  addEventListener(eventType: PHPEvent["type"], listener: PHPEventListener): void;
601
618
  removeEventListener(eventType: PHPEvent["type"], listener: PHPEventListener): void;
602
619
  dispatchEvent<Event extends PHPEvent>(event: Event): void;
@@ -621,7 +638,10 @@ declare abstract class BasePHP implements IsomorphicLocalPHP {
621
638
  setPhpIniEntry(key: string, value: string): void;
622
639
  /** @inheritDoc */
623
640
  chdir(path: string): void;
624
- /** @inheritDoc */
641
+ /**
642
+ * Do not use. Use new PHPRequestHandler() instead.
643
+ * @deprecated
644
+ */
625
645
  request(request: PHPRequest): Promise<PHPResponse>;
626
646
  /** @inheritDoc */
627
647
  run(request: PHPRunOptions): Promise<PHPResponse>;
@@ -660,12 +680,102 @@ declare abstract class BasePHP implements IsomorphicLocalPHP {
660
680
  */
661
681
  hotSwapPHPRuntime(runtime: number, cwd?: string): void;
662
682
  exit(code?: number): void;
683
+ [Symbol.dispose](): void;
663
684
  }
685
+ export type PHPFactoryOptions = {
686
+ isPrimary: boolean;
687
+ };
688
+ export type PHPFactory<PHP extends BasePHP> = (options: PHPFactoryOptions) => Promise<PHP>;
689
+ export interface ProcessManagerOptions<PHP extends BasePHP> {
690
+ /**
691
+ * The maximum number of PHP instances that can exist at
692
+ * the same time.
693
+ */
694
+ maxPhpInstances?: number;
695
+ /**
696
+ * The number of milliseconds to wait for a PHP instance when
697
+ * we have reached the maximum number of PHP instances and
698
+ * cannot spawn a new one. If the timeout is reached, we assume
699
+ * all the PHP instances are deadlocked and a throw MaxPhpInstancesError.
700
+ *
701
+ * Default: 5000
702
+ */
703
+ timeout?: number;
704
+ /**
705
+ * The primary PHP instance that's never killed. This instance
706
+ * contains the reference filesystem used by all other PHP instances.
707
+ */
708
+ primaryPhp?: PHP;
709
+ /**
710
+ * A factory function used for spawning new PHP instances.
711
+ */
712
+ phpFactory?: PHPFactory<PHP>;
713
+ }
714
+ export interface SpawnedPHP<PHP extends BasePHP> {
715
+ php: PHP;
716
+ reap: () => void;
717
+ }
718
+ declare class PHPProcessManager<PHP extends BasePHP> implements AsyncDisposable {
719
+ private primaryPhp?;
720
+ private primaryIdle;
721
+ private nextInstance;
722
+ /**
723
+ * All spawned PHP instances, including the primary PHP instance.
724
+ * Used for bookkeeping and reaping all instances on dispose.
725
+ */
726
+ private allInstances;
727
+ private phpFactory?;
728
+ private maxPhpInstances;
729
+ private semaphore;
730
+ constructor(options?: ProcessManagerOptions<PHP>);
731
+ /**
732
+ * Get the primary PHP instance.
733
+ *
734
+ * If the primary PHP instance is not set, it will be spawned
735
+ * using the provided phpFactory.
736
+ *
737
+ * @throws {Error} when called twice before the first call is resolved.
738
+ */
739
+ getPrimaryPhp(): Promise<PHP>;
740
+ /**
741
+ * Get a PHP instance.
742
+ *
743
+ * It could be either the primary PHP instance, an idle disposable PHP instance,
744
+ * or a newly spawned PHP instance – depending on the resource availability.
745
+ *
746
+ * @throws {MaxPhpInstancesError} when the maximum number of PHP instances is reached
747
+ * and the waiting timeout is exceeded.
748
+ */
749
+ acquirePHPInstance(): Promise<SpawnedPHP<PHP>>;
750
+ /**
751
+ * Initiated spawning of a new PHP instance.
752
+ * This function is synchronous on purpose – it needs to synchronously
753
+ * add the spawn promise to the allInstances array without waiting
754
+ * for PHP to spawn.
755
+ */
756
+ private spawn;
757
+ /**
758
+ * Actually acquires the lock and spawns a new PHP instance.
759
+ */
760
+ private doSpawn;
761
+ [Symbol.asyncDispose](): Promise<void>;
762
+ }
763
+ declare const SupportedPHPVersions: readonly [
764
+ "8.3",
765
+ "8.2",
766
+ "8.1",
767
+ "8.0",
768
+ "7.4",
769
+ "7.3",
770
+ "7.2",
771
+ "7.1",
772
+ "7.0"
773
+ ];
774
+ export type SupportedPHPVersion = (typeof SupportedPHPVersions)[number];
664
775
  export declare function getPHPLoaderModule(version?: SupportedPHPVersion): Promise<PHPLoaderModule>;
665
776
  export declare function withNetworking(phpModuleArgs?: EmscriptenOptions): Promise<EmscriptenOptions>;
666
777
  export interface PHPLoaderOptions {
667
778
  emscriptenOptions?: EmscriptenOptions;
668
- requestHandler?: PHPRequestHandlerConfiguration;
669
779
  }
670
780
  export type MountSettings = {
671
781
  root: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@php-wasm/node",
3
- "version": "0.7.1",
3
+ "version": "0.7.3",
4
4
  "description": "PHP.wasm for Node.js",
5
5
  "repository": {
6
6
  "type": "git",
@@ -28,7 +28,7 @@
28
28
  "license": "GPL-2.0-or-later",
29
29
  "main": "index.cjs",
30
30
  "types": "index.d.ts",
31
- "gitHead": "ed0ec39040ab4cd69dc48a8eac157436b30f9d55",
31
+ "gitHead": "e8fedf92bbead5cec963c8d6976e7143d8e68721",
32
32
  "engines": {
33
33
  "node": ">=18.18.0",
34
34
  "npm": ">=8.11.0"
@@ -37,8 +37,9 @@
37
37
  "comlink": "^4.4.1",
38
38
  "ws": "8.13.0",
39
39
  "yargs": "17.7.2",
40
- "@php-wasm/node-polyfills": "0.7.1",
41
- "@php-wasm/universal": "0.7.1",
42
- "@php-wasm/util": "0.7.1"
40
+ "@php-wasm/node-polyfills": "0.7.3",
41
+ "@php-wasm/universal": "0.7.3",
42
+ "@php-wasm/logger": "0.7.3",
43
+ "@php-wasm/util": "0.7.3"
43
44
  }
44
45
  }