rabin 11 ماه پیش
کامیت
ef108495d0
100فایلهای تغییر یافته به همراه7127 افزوده شده و 0 حذف شده
  1. 5 0
      composer.json
  2. 454 0
      composer.lock
  3. 5 0
      index.php
  4. 1 0
      node_modules/.bin/browsers
  5. 1 0
      node_modules/.bin/escodegen
  6. 1 0
      node_modules/.bin/esgenerate
  7. 1 0
      node_modules/.bin/esparse
  8. 1 0
      node_modules/.bin/esvalidate
  9. 1 0
      node_modules/.bin/extract-zip
  10. 1 0
      node_modules/.bin/js-yaml
  11. 1188 0
      node_modules/.package-lock.json
  12. 22 0
      node_modules/@babel/code-frame/LICENSE
  13. 19 0
      node_modules/@babel/code-frame/README.md
  14. 156 0
      node_modules/@babel/code-frame/lib/index.js
  15. 0 0
      node_modules/@babel/code-frame/lib/index.js.map
  16. 30 0
      node_modules/@babel/code-frame/package.json
  17. 22 0
      node_modules/@babel/helper-validator-identifier/LICENSE
  18. 19 0
      node_modules/@babel/helper-validator-identifier/README.md
  19. 8 0
      node_modules/@babel/helper-validator-identifier/lib/identifier.js
  20. 0 0
      node_modules/@babel/helper-validator-identifier/lib/identifier.js.map
  21. 57 0
      node_modules/@babel/helper-validator-identifier/lib/index.js
  22. 1 0
      node_modules/@babel/helper-validator-identifier/lib/index.js.map
  23. 35 0
      node_modules/@babel/helper-validator-identifier/lib/keyword.js
  24. 0 0
      node_modules/@babel/helper-validator-identifier/lib/keyword.js.map
  25. 28 0
      node_modules/@babel/helper-validator-identifier/package.json
  26. 73 0
      node_modules/@babel/helper-validator-identifier/scripts/generate-identifier-regex.js
  27. 22 0
      node_modules/@babel/highlight/LICENSE
  28. 19 0
      node_modules/@babel/highlight/README.md
  29. 119 0
      node_modules/@babel/highlight/lib/index.js
  30. 0 0
      node_modules/@babel/highlight/lib/index.js.map
  31. 30 0
      node_modules/@babel/highlight/package.json
  32. 18 0
      node_modules/@nesk/rialto/.travis.yml
  33. 89 0
      node_modules/@nesk/rialto/CHANGELOG.md
  34. 19 0
      node_modules/@nesk/rialto/LICENSE
  35. 32 0
      node_modules/@nesk/rialto/README.md
  36. 51 0
      node_modules/@nesk/rialto/composer.json
  37. 210 0
      node_modules/@nesk/rialto/docs/api.md
  38. 188 0
      node_modules/@nesk/rialto/docs/tutorial.md
  39. 27 0
      node_modules/@nesk/rialto/package.json
  40. 21 0
      node_modules/@nesk/rialto/phpunit.xml
  41. 47 0
      node_modules/@nesk/rialto/src/AbstractEntryPoint.php
  42. 19 0
      node_modules/@nesk/rialto/src/Data/BasicResource.php
  43. 124 0
      node_modules/@nesk/rialto/src/Data/JsFunction.php
  44. 57 0
      node_modules/@nesk/rialto/src/Data/ResourceIdentity.php
  45. 47 0
      node_modules/@nesk/rialto/src/Data/UnserializesData.php
  46. 21 0
      node_modules/@nesk/rialto/src/Exceptions/IdentifiesProcess.php
  47. 35 0
      node_modules/@nesk/rialto/src/Exceptions/IdleTimeoutException.php
  48. 18 0
      node_modules/@nesk/rialto/src/Exceptions/Node/Exception.php
  49. 31 0
      node_modules/@nesk/rialto/src/Exceptions/Node/FatalException.php
  50. 49 0
      node_modules/@nesk/rialto/src/Exceptions/Node/HandlesNodeErrors.php
  51. 20 0
      node_modules/@nesk/rialto/src/Exceptions/ProcessUnexpectedlyTerminatedException.php
  52. 19 0
      node_modules/@nesk/rialto/src/Exceptions/ReadSocketTimeoutException.php
  53. 180 0
      node_modules/@nesk/rialto/src/Instruction.php
  54. 15 0
      node_modules/@nesk/rialto/src/Interfaces/ShouldCommunicateWithProcessSupervisor.php
  55. 16 0
      node_modules/@nesk/rialto/src/Interfaces/ShouldHandleProcessDelegation.php
  56. 20 0
      node_modules/@nesk/rialto/src/Interfaces/ShouldIdentifyResource.php
  57. 125 0
      node_modules/@nesk/rialto/src/Logger.php
  58. 469 0
      node_modules/@nesk/rialto/src/ProcessSupervisor.php
  59. 122 0
      node_modules/@nesk/rialto/src/Traits/CommunicatesWithProcessSupervisor.php
  60. 38 0
      node_modules/@nesk/rialto/src/Traits/IdentifiesResource.php
  61. 14 0
      node_modules/@nesk/rialto/src/Traits/UsesBasicResourceAsDefault.php
  62. 157 0
      node_modules/@nesk/rialto/src/node-process/Connection.js
  63. 41 0
      node_modules/@nesk/rialto/src/node-process/ConnectionDelegate.js
  64. 62 0
      node_modules/@nesk/rialto/src/node-process/Data/ResourceIdentity.js
  65. 113 0
      node_modules/@nesk/rialto/src/node-process/Data/ResourceRepository.js
  66. 52 0
      node_modules/@nesk/rialto/src/node-process/Data/Serializer.js
  67. 98 0
      node_modules/@nesk/rialto/src/node-process/Data/Unserializer.js
  68. 63 0
      node_modules/@nesk/rialto/src/node-process/Data/Value.js
  69. 225 0
      node_modules/@nesk/rialto/src/node-process/Instruction.js
  70. 30 0
      node_modules/@nesk/rialto/src/node-process/Logger.js
  71. 101 0
      node_modules/@nesk/rialto/src/node-process/NodeInterceptors/ConsoleInterceptor.js
  72. 54 0
      node_modules/@nesk/rialto/src/node-process/NodeInterceptors/StandardStreamsInterceptor.js
  73. 74 0
      node_modules/@nesk/rialto/src/node-process/Server.js
  74. 5 0
      node_modules/@nesk/rialto/src/node-process/index.js
  75. 40 0
      node_modules/@nesk/rialto/src/node-process/serve.js
  76. 56 0
      node_modules/@nesk/rialto/tests/Implementation/FsConnectionDelegate.js
  77. 18 0
      node_modules/@nesk/rialto/tests/Implementation/FsProcessDelegate.php
  78. 21 0
      node_modules/@nesk/rialto/tests/Implementation/FsWithProcessDelegation.php
  79. 13 0
      node_modules/@nesk/rialto/tests/Implementation/FsWithoutProcessDelegation.php
  80. 10 0
      node_modules/@nesk/rialto/tests/Implementation/Resources/Stats.php
  81. 533 0
      node_modules/@nesk/rialto/tests/ImplementationTest.php
  82. 105 0
      node_modules/@nesk/rialto/tests/TestCase.php
  83. 1 0
      node_modules/@nesk/rialto/tests/resources/file
  84. 28 0
      node_modules/@puppeteer/browsers/README.md
  85. 31 0
      node_modules/@puppeteer/browsers/lib/cjs/CLI.d.ts
  86. 1 0
      node_modules/@puppeteer/browsers/lib/cjs/CLI.d.ts.map
  87. 230 0
      node_modules/@puppeteer/browsers/lib/cjs/CLI.js
  88. 0 0
      node_modules/@puppeteer/browsers/lib/cjs/CLI.js.map
  89. 53 0
      node_modules/@puppeteer/browsers/lib/cjs/Cache.d.ts
  90. 1 0
      node_modules/@puppeteer/browsers/lib/cjs/Cache.d.ts.map
  91. 108 0
      node_modules/@puppeteer/browsers/lib/cjs/Cache.js
  92. 0 0
      node_modules/@puppeteer/browsers/lib/cjs/Cache.js.map
  93. 53 0
      node_modules/@puppeteer/browsers/lib/cjs/browser-data/browser-data.d.ts
  94. 1 0
      node_modules/@puppeteer/browsers/lib/cjs/browser-data/browser-data.d.ts.map
  95. 150 0
      node_modules/@puppeteer/browsers/lib/cjs/browser-data/browser-data.js
  96. 0 0
      node_modules/@puppeteer/browsers/lib/cjs/browser-data/browser-data.js.map
  97. 26 0
      node_modules/@puppeteer/browsers/lib/cjs/browser-data/chrome.d.ts
  98. 1 0
      node_modules/@puppeteer/browsers/lib/cjs/browser-data/chrome.d.ts.map
  99. 112 0
      node_modules/@puppeteer/browsers/lib/cjs/browser-data/chrome.js
  100. 0 0
      node_modules/@puppeteer/browsers/lib/cjs/browser-data/chrome.js.map

+ 5 - 0
composer.json

@@ -0,0 +1,5 @@
+{
+    "require-dev": {
+        "zoon/puphpeteer": "^1.6"
+    }
+}

+ 454 - 0
composer.lock

@@ -0,0 +1,454 @@
+{
+    "_readme": [
+        "This file locks the dependencies of your project to a known state",
+        "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
+        "This file is @generated automatically"
+    ],
+    "content-hash": "f3e030390ed4e19d06851f02ba32aa0a",
+    "packages": [],
+    "packages-dev": [
+        {
+            "name": "clue/socket-raw",
+            "version": "v1.6.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/clue/socket-raw.git",
+                "reference": "91e9f619f6769f931454a9882c21ffd7623d06cb"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/clue/socket-raw/zipball/91e9f619f6769f931454a9882c21ffd7623d06cb",
+                "reference": "91e9f619f6769f931454a9882c21ffd7623d06cb",
+                "shasum": ""
+            },
+            "require": {
+                "ext-sockets": "*",
+                "php": ">=5.3"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Socket\\Raw\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Christian Lück",
+                    "email": "christian@clue.engineering"
+                }
+            ],
+            "description": "Simple and lightweight OOP wrapper for PHP's low-level sockets extension (ext-sockets).",
+            "homepage": "https://github.com/clue/socket-raw",
+            "keywords": [
+                "Socket",
+                "client",
+                "datagram",
+                "dgram",
+                "icmp",
+                "ipv6",
+                "server",
+                "stream",
+                "tcp",
+                "udg",
+                "udp",
+                "unix"
+            ],
+            "support": {
+                "issues": "https://github.com/clue/socket-raw/issues",
+                "source": "https://github.com/clue/socket-raw/tree/v1.6.0"
+            },
+            "funding": [
+                {
+                    "url": "https://clue.engineering/support",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/clue",
+                    "type": "github"
+                }
+            ],
+            "time": "2022-04-14T14:58:06+00:00"
+        },
+        {
+            "name": "nesk/rialto",
+            "version": "1.4.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/nesk/rialto.git",
+                "reference": "a3db615d845cca42135fa1e271b323ffe904b83c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/nesk/rialto/zipball/a3db615d845cca42135fa1e271b323ffe904b83c",
+                "reference": "a3db615d845cca42135fa1e271b323ffe904b83c",
+                "shasum": ""
+            },
+            "require": {
+                "clue/socket-raw": "^1.2",
+                "php": ">=7.1",
+                "psr/log": "^1.0",
+                "symfony/process": "^3.3|^4.0|^5.0"
+            },
+            "require-dev": {
+                "codedungeon/phpunit-result-printer": ">=0.6 <1.0",
+                "monolog/monolog": "^1.23",
+                "phpunit/phpunit": "^6.5|^7.0"
+            },
+            "suggest": {
+                "ext-weakref": "Required to run all the tests"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Nesk\\Rialto\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Johann Pardanaud",
+                    "email": "pardanaud.j@gmail.com"
+                }
+            ],
+            "description": "Manage Node resources from PHP",
+            "keywords": [
+                "Bridge",
+                "Socket",
+                "communication",
+                "node",
+                "php",
+                "wrapper"
+            ],
+            "support": {
+                "issues": "https://github.com/nesk/rialto/issues",
+                "source": "https://github.com/nesk/rialto/tree/1.4.0"
+            },
+            "abandoned": true,
+            "time": "2020-04-12T13:11:08+00:00"
+        },
+        {
+            "name": "psr/log",
+            "version": "1.1.4",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/log.git",
+                "reference": "d49695b909c3b7628b6289db5479a1c204601f11"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11",
+                "reference": "d49695b909c3b7628b6289db5479a1c204601f11",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.1.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Psr\\Log\\": "Psr/Log/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "https://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interface for logging libraries",
+            "homepage": "https://github.com/php-fig/log",
+            "keywords": [
+                "log",
+                "psr",
+                "psr-3"
+            ],
+            "support": {
+                "source": "https://github.com/php-fig/log/tree/1.1.4"
+            },
+            "time": "2021-05-03T11:20:27+00:00"
+        },
+        {
+            "name": "symfony/polyfill-php80",
+            "version": "v1.29.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-php80.git",
+                "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
+                "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.1"
+            },
+            "type": "library",
+            "extra": {
+                "thanks": {
+                    "name": "symfony/polyfill",
+                    "url": "https://github.com/symfony/polyfill"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "bootstrap.php"
+                ],
+                "psr-4": {
+                    "Symfony\\Polyfill\\Php80\\": ""
+                },
+                "classmap": [
+                    "Resources/stubs"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Ion Bazan",
+                    "email": "ion.bazan@gmail.com"
+                },
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/polyfill-php80/tree/v1.29.0"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2024-01-29T20:11:03+00:00"
+        },
+        {
+            "name": "symfony/process",
+            "version": "v5.4.36",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/process.git",
+                "reference": "4fdf34004f149cc20b2f51d7d119aa500caad975"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/process/zipball/4fdf34004f149cc20b2f51d7d119aa500caad975",
+                "reference": "4fdf34004f149cc20b2f51d7d119aa500caad975",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.2.5",
+                "symfony/polyfill-php80": "^1.16"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Process\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Executes commands in sub-processes",
+            "homepage": "https://symfony.com",
+            "support": {
+                "source": "https://github.com/symfony/process/tree/v5.4.36"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2024-02-12T15:49:53+00:00"
+        },
+        {
+            "name": "vierbergenlars/php-semver",
+            "version": "v3.0.4",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/vierbergenlars/php-semver.git",
+                "reference": "ff2f5b33f33a1e702a09c6f91f3ea34f5cf78bdf"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/vierbergenlars/php-semver/zipball/ff2f5b33f33a1e702a09c6f91f3ea34f5cf78bdf",
+                "reference": "ff2f5b33f33a1e702a09c6f91f3ea34f5cf78bdf",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^9.5.21"
+            },
+            "bin": [
+                "bin/semver",
+                "bin/update-versions"
+            ],
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "vierbergenlars\\LibJs\\": "src/",
+                    "vierbergenlars\\SemVer\\": "src/"
+                },
+                "classmap": [
+                    "src/vierbergenlars/SemVer/internal.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Lars Vierbergen",
+                    "email": "vierbergenlars@gmail.com"
+                }
+            ],
+            "description": "The Semantic Versioner for PHP",
+            "keywords": [
+                "semantic",
+                "semver",
+                "versioning"
+            ],
+            "support": {
+                "issues": "https://github.com/vierbergenlars/php-semver/issues",
+                "source": "https://github.com/vierbergenlars/php-semver/tree/v3.0.4"
+            },
+            "abandoned": "composer/semver",
+            "time": "2023-05-02T06:45:47+00:00"
+        },
+        {
+            "name": "zoon/puphpeteer",
+            "version": "1.6.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/zoonru/puphpeteer.git",
+                "reference": "21adf25d320f32b005cb3e2f9026616566015fcc"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/zoonru/puphpeteer/zipball/21adf25d320f32b005cb3e2f9026616566015fcc",
+                "reference": "21adf25d320f32b005cb3e2f9026616566015fcc",
+                "shasum": ""
+            },
+            "require": {
+                "nesk/rialto": "^1.2.0",
+                "php": ">=7.1",
+                "psr/log": "^1.0",
+                "vierbergenlars/php-semver": "^3.0.2"
+            },
+            "require-dev": {
+                "codedungeon/phpunit-result-printer": ">=0.6 <1.0",
+                "monolog/monolog": "^1.23",
+                "phpunit/phpunit": "^6.5|^7.0",
+                "symfony/process": "^4.0"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "Nesk\\Puphpeteer\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Johann Pardanaud",
+                    "email": "pardanaud.j@gmail.com"
+                }
+            ],
+            "description": "A Puppeteer bridge for PHP, supporting the entire API.",
+            "keywords": [
+                "automation",
+                "developer-tools",
+                "headless-chrome",
+                "php",
+                "puppeteer",
+                "testing",
+                "web"
+            ],
+            "support": {
+                "source": "https://github.com/zoonru/puphpeteer/tree/1.6.0"
+            },
+            "time": "2019-06-24T11:12:21+00:00"
+        }
+    ],
+    "aliases": [],
+    "minimum-stability": "stable",
+    "stability-flags": [],
+    "prefer-stable": false,
+    "prefer-lowest": false,
+    "platform": [],
+    "platform-dev": [],
+    "plugin-api-version": "2.3.0"
+}

+ 5 - 0
index.php

@@ -0,0 +1,5 @@
+<?php
+define('DEVER_APP_NAME', 'puppeteer');
+define('DEVER_APP_LANG', 'puppeteer组件');
+define('DEVER_APP_PATH', dirname(__FILE__) . DIRECTORY_SEPARATOR);
+include(DEVER_APP_PATH . '../../boot.php');

+ 1 - 0
node_modules/.bin/browsers

@@ -0,0 +1 @@
+../@puppeteer/browsers/lib/cjs/main-cli.js

+ 1 - 0
node_modules/.bin/escodegen

@@ -0,0 +1 @@
+../escodegen/bin/escodegen.js

+ 1 - 0
node_modules/.bin/esgenerate

@@ -0,0 +1 @@
+../escodegen/bin/esgenerate.js

+ 1 - 0
node_modules/.bin/esparse

@@ -0,0 +1 @@
+../esprima/bin/esparse.js

+ 1 - 0
node_modules/.bin/esvalidate

@@ -0,0 +1 @@
+../esprima/bin/esvalidate.js

+ 1 - 0
node_modules/.bin/extract-zip

@@ -0,0 +1 @@
+../extract-zip/cli.js

+ 1 - 0
node_modules/.bin/js-yaml

@@ -0,0 +1 @@
+../js-yaml/bin/js-yaml.js

+ 1188 - 0
node_modules/.package-lock.json

@@ -0,0 +1,1188 @@
+{
+  "name": "puppeteer",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "node_modules/@babel/code-frame": {
+      "version": "7.24.2",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz",
+      "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==",
+      "dependencies": {
+        "@babel/highlight": "^7.24.2",
+        "picocolors": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-validator-identifier": {
+      "version": "7.22.20",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
+      "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/highlight": {
+      "version": "7.24.2",
+      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz",
+      "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==",
+      "dependencies": {
+        "@babel/helper-validator-identifier": "^7.22.20",
+        "chalk": "^2.4.2",
+        "js-tokens": "^4.0.0",
+        "picocolors": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@nesk/rialto": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/@nesk/rialto/-/rialto-1.4.0.tgz",
+      "integrity": "sha512-TNbEFnUD9KnbTIPlYBvrAc/oi+SN0W9oEcGmpTvKkmJIYYKPrnxrenAtEI14NWN7gAPX0B9xiNFhBsMn1I/SXg==",
+      "dependencies": {
+        "lodash": "^4.17.10"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/@puppeteer/browsers": {
+      "version": "1.4.6",
+      "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.4.6.tgz",
+      "integrity": "sha512-x4BEjr2SjOPowNeiguzjozQbsc6h437ovD/wu+JpaenxVLm3jkgzHY2xOslMTp50HoTvQreMjiexiGQw1sqZlQ==",
+      "dependencies": {
+        "debug": "4.3.4",
+        "extract-zip": "2.0.1",
+        "progress": "2.0.3",
+        "proxy-agent": "6.3.0",
+        "tar-fs": "3.0.4",
+        "unbzip2-stream": "1.4.3",
+        "yargs": "17.7.1"
+      },
+      "bin": {
+        "browsers": "lib/cjs/main-cli.js"
+      },
+      "engines": {
+        "node": ">=16.3.0"
+      },
+      "peerDependencies": {
+        "typescript": ">= 4.7.4"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@tootallnate/quickjs-emscripten": {
+      "version": "0.23.0",
+      "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz",
+      "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA=="
+    },
+    "node_modules/@types/node": {
+      "version": "20.12.5",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.5.tgz",
+      "integrity": "sha512-BD+BjQ9LS/D8ST9p5uqBxghlN+S42iuNxjsUGjeZobe/ciXzk2qb1B6IXc6AnRLS+yFJRpN2IPEHMzwspfDJNw==",
+      "optional": true,
+      "dependencies": {
+        "undici-types": "~5.26.4"
+      }
+    },
+    "node_modules/@types/yauzl": {
+      "version": "2.10.3",
+      "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz",
+      "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==",
+      "optional": true,
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@zoon/puphpeteer": {
+      "version": "2.1.0",
+      "resolved": "git+ssh://git@github.com/zoonru/puphpeteer.git#78c7b48817edd9920d1b87a386c59ccedc45fc2b",
+      "dependencies": {
+        "@zoon/rialto": "github:zoonru/rialto#semver:^1.5.0",
+        "puppeteer": "^20"
+      },
+      "engines": {
+        "node": ">=9.0.0"
+      }
+    },
+    "node_modules/@zoon/rialto": {
+      "version": "1.5.0",
+      "resolved": "git+ssh://git@github.com/zoonru/rialto.git#f631b78bf5ae36b236050c87cd45a9433c55ab6e",
+      "dependencies": {
+        "lodash": "^4.17.10"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/agent-base": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz",
+      "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==",
+      "dependencies": {
+        "debug": "^4.3.4"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/ansi-styles": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+      "dependencies": {
+        "color-convert": "^1.9.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/argparse": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
+    },
+    "node_modules/ast-types": {
+      "version": "0.13.4",
+      "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz",
+      "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==",
+      "dependencies": {
+        "tslib": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/b4a": {
+      "version": "1.6.6",
+      "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz",
+      "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg=="
+    },
+    "node_modules/bare-events": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.2.2.tgz",
+      "integrity": "sha512-h7z00dWdG0PYOQEvChhOSWvOfkIKsdZGkWr083FgN/HyoQuebSew/cgirYqh9SCuy/hRvxc5Vy6Fw8xAmYHLkQ==",
+      "optional": true
+    },
+    "node_modules/base64-js": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+      "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
+    },
+    "node_modules/basic-ftp": {
+      "version": "5.0.5",
+      "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz",
+      "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==",
+      "engines": {
+        "node": ">=10.0.0"
+      }
+    },
+    "node_modules/buffer": {
+      "version": "5.7.1",
+      "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+      "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "dependencies": {
+        "base64-js": "^1.3.1",
+        "ieee754": "^1.1.13"
+      }
+    },
+    "node_modules/buffer-crc32": {
+      "version": "0.2.13",
+      "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+      "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/callsites": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+      "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/chalk": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+      "dependencies": {
+        "ansi-styles": "^3.2.1",
+        "escape-string-regexp": "^1.0.5",
+        "supports-color": "^5.3.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/chromium-bidi": {
+      "version": "0.4.16",
+      "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.16.tgz",
+      "integrity": "sha512-7ZbXdWERxRxSwo3txsBjjmc/NLxqb1Bk30mRb0BMS4YIaiV6zvKZqL/UAH+DdqcDYayDWk2n/y8klkBDODrPvA==",
+      "dependencies": {
+        "mitt": "3.0.0"
+      },
+      "peerDependencies": {
+        "devtools-protocol": "*"
+      }
+    },
+    "node_modules/cliui": {
+      "version": "8.0.1",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+      "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+      "dependencies": {
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.1",
+        "wrap-ansi": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/color-convert": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+      "dependencies": {
+        "color-name": "1.1.3"
+      }
+    },
+    "node_modules/color-name": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
+    },
+    "node_modules/cosmiconfig": {
+      "version": "8.2.0",
+      "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.2.0.tgz",
+      "integrity": "sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ==",
+      "dependencies": {
+        "import-fresh": "^3.2.1",
+        "js-yaml": "^4.1.0",
+        "parse-json": "^5.0.0",
+        "path-type": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/d-fischer"
+      }
+    },
+    "node_modules/cross-fetch": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz",
+      "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==",
+      "dependencies": {
+        "node-fetch": "^2.6.12"
+      }
+    },
+    "node_modules/data-uri-to-buffer": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz",
+      "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==",
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/debug": {
+      "version": "4.3.4",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+      "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+      "dependencies": {
+        "ms": "2.1.2"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/degenerator": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz",
+      "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==",
+      "dependencies": {
+        "ast-types": "^0.13.4",
+        "escodegen": "^2.1.0",
+        "esprima": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/devtools-protocol": {
+      "version": "0.0.1147663",
+      "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1147663.tgz",
+      "integrity": "sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ=="
+    },
+    "node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
+    },
+    "node_modules/end-of-stream": {
+      "version": "1.4.4",
+      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+      "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+      "dependencies": {
+        "once": "^1.4.0"
+      }
+    },
+    "node_modules/error-ex": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+      "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+      "dependencies": {
+        "is-arrayish": "^0.2.1"
+      }
+    },
+    "node_modules/escalade": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
+      "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/escodegen": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz",
+      "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==",
+      "dependencies": {
+        "esprima": "^4.0.1",
+        "estraverse": "^5.2.0",
+        "esutils": "^2.0.2"
+      },
+      "bin": {
+        "escodegen": "bin/escodegen.js",
+        "esgenerate": "bin/esgenerate.js"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "optionalDependencies": {
+        "source-map": "~0.6.1"
+      }
+    },
+    "node_modules/esprima": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+      "bin": {
+        "esparse": "bin/esparse.js",
+        "esvalidate": "bin/esvalidate.js"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/estraverse": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+      "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/esutils": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+      "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/extract-zip": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz",
+      "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==",
+      "dependencies": {
+        "debug": "^4.1.1",
+        "get-stream": "^5.1.0",
+        "yauzl": "^2.10.0"
+      },
+      "bin": {
+        "extract-zip": "cli.js"
+      },
+      "engines": {
+        "node": ">= 10.17.0"
+      },
+      "optionalDependencies": {
+        "@types/yauzl": "^2.9.1"
+      }
+    },
+    "node_modules/fast-fifo": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz",
+      "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ=="
+    },
+    "node_modules/fd-slicer": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
+      "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==",
+      "dependencies": {
+        "pend": "~1.2.0"
+      }
+    },
+    "node_modules/fs-extra": {
+      "version": "11.2.0",
+      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz",
+      "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==",
+      "dependencies": {
+        "graceful-fs": "^4.2.0",
+        "jsonfile": "^6.0.1",
+        "universalify": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=14.14"
+      }
+    },
+    "node_modules/get-caller-file": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+      "engines": {
+        "node": "6.* || 8.* || >= 10.*"
+      }
+    },
+    "node_modules/get-stream": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
+      "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
+      "dependencies": {
+        "pump": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/get-uri": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.3.tgz",
+      "integrity": "sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==",
+      "dependencies": {
+        "basic-ftp": "^5.0.2",
+        "data-uri-to-buffer": "^6.0.2",
+        "debug": "^4.3.4",
+        "fs-extra": "^11.2.0"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/graceful-fs": {
+      "version": "4.2.11",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+      "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
+    },
+    "node_modules/has-flag": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+      "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/http-proxy-agent": {
+      "version": "7.0.2",
+      "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
+      "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
+      "dependencies": {
+        "agent-base": "^7.1.0",
+        "debug": "^4.3.4"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/https-proxy-agent": {
+      "version": "7.0.4",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz",
+      "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==",
+      "dependencies": {
+        "agent-base": "^7.0.2",
+        "debug": "4"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/ieee754": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+      "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
+    },
+    "node_modules/import-fresh": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+      "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+      "dependencies": {
+        "parent-module": "^1.0.0",
+        "resolve-from": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/ip-address": {
+      "version": "9.0.5",
+      "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz",
+      "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==",
+      "dependencies": {
+        "jsbn": "1.1.0",
+        "sprintf-js": "^1.1.3"
+      },
+      "engines": {
+        "node": ">= 12"
+      }
+    },
+    "node_modules/is-arrayish": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+      "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="
+    },
+    "node_modules/is-fullwidth-code-point": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/js-tokens": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
+    },
+    "node_modules/js-yaml": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+      "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
+      "dependencies": {
+        "argparse": "^2.0.1"
+      },
+      "bin": {
+        "js-yaml": "bin/js-yaml.js"
+      }
+    },
+    "node_modules/jsbn": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz",
+      "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A=="
+    },
+    "node_modules/json-parse-even-better-errors": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+      "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
+    },
+    "node_modules/jsonfile": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+      "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+      "dependencies": {
+        "universalify": "^2.0.0"
+      },
+      "optionalDependencies": {
+        "graceful-fs": "^4.1.6"
+      }
+    },
+    "node_modules/lines-and-columns": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+      "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
+    },
+    "node_modules/lodash": {
+      "version": "4.17.21",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+    },
+    "node_modules/lru-cache": {
+      "version": "7.18.3",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
+      "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==",
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/mitt": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.0.tgz",
+      "integrity": "sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ=="
+    },
+    "node_modules/mkdirp-classic": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
+      "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="
+    },
+    "node_modules/ms": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+      "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+    },
+    "node_modules/netmask": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz",
+      "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==",
+      "engines": {
+        "node": ">= 0.4.0"
+      }
+    },
+    "node_modules/node-fetch": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
+      "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
+      "dependencies": {
+        "whatwg-url": "^5.0.0"
+      },
+      "engines": {
+        "node": "4.x || >=6.0.0"
+      },
+      "peerDependencies": {
+        "encoding": "^0.1.0"
+      },
+      "peerDependenciesMeta": {
+        "encoding": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+      "dependencies": {
+        "wrappy": "1"
+      }
+    },
+    "node_modules/pac-proxy-agent": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.1.tgz",
+      "integrity": "sha512-ASV8yU4LLKBAjqIPMbrgtaKIvxQri/yh2OpI+S6hVa9JRkUI3Y3NPFbfngDtY7oFtSMD3w31Xns89mDa3Feo5A==",
+      "dependencies": {
+        "@tootallnate/quickjs-emscripten": "^0.23.0",
+        "agent-base": "^7.0.2",
+        "debug": "^4.3.4",
+        "get-uri": "^6.0.1",
+        "http-proxy-agent": "^7.0.0",
+        "https-proxy-agent": "^7.0.2",
+        "pac-resolver": "^7.0.0",
+        "socks-proxy-agent": "^8.0.2"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/pac-resolver": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz",
+      "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==",
+      "dependencies": {
+        "degenerator": "^5.0.0",
+        "netmask": "^2.0.2"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/parent-module": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+      "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+      "dependencies": {
+        "callsites": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/parse-json": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+      "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
+      "dependencies": {
+        "@babel/code-frame": "^7.0.0",
+        "error-ex": "^1.3.1",
+        "json-parse-even-better-errors": "^2.3.0",
+        "lines-and-columns": "^1.1.6"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/path-type": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+      "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/pend": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
+      "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg=="
+    },
+    "node_modules/picocolors": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
+      "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
+    },
+    "node_modules/progress": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
+      "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/proxy-agent": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.0.tgz",
+      "integrity": "sha512-0LdR757eTj/JfuU7TL2YCuAZnxWXu3tkJbg4Oq3geW/qFNT/32T0sp2HnZ9O0lMR4q3vwAt0+xCA8SR0WAD0og==",
+      "dependencies": {
+        "agent-base": "^7.0.2",
+        "debug": "^4.3.4",
+        "http-proxy-agent": "^7.0.0",
+        "https-proxy-agent": "^7.0.0",
+        "lru-cache": "^7.14.1",
+        "pac-proxy-agent": "^7.0.0",
+        "proxy-from-env": "^1.1.0",
+        "socks-proxy-agent": "^8.0.1"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/proxy-from-env": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+      "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
+    },
+    "node_modules/pump": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+      "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+      "dependencies": {
+        "end-of-stream": "^1.1.0",
+        "once": "^1.3.1"
+      }
+    },
+    "node_modules/puppeteer": {
+      "version": "20.9.0",
+      "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-20.9.0.tgz",
+      "integrity": "sha512-kAglT4VZ9fWEGg3oLc4/de+JcONuEJhlh3J6f5R1TLkrY/EHHIHxWXDOzXvaxQCtedmyVXBwg8M+P8YCO/wZjw==",
+      "deprecated": "< 21.8.0 is no longer supported",
+      "hasInstallScript": true,
+      "dependencies": {
+        "@puppeteer/browsers": "1.4.6",
+        "cosmiconfig": "8.2.0",
+        "puppeteer-core": "20.9.0"
+      },
+      "engines": {
+        "node": ">=16.3.0"
+      }
+    },
+    "node_modules/puppeteer-core": {
+      "version": "20.9.0",
+      "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.9.0.tgz",
+      "integrity": "sha512-H9fYZQzMTRrkboEfPmf7m3CLDN6JvbxXA3qTtS+dFt27tR+CsFHzPsT6pzp6lYL6bJbAPaR0HaPO6uSi+F94Pg==",
+      "dependencies": {
+        "@puppeteer/browsers": "1.4.6",
+        "chromium-bidi": "0.4.16",
+        "cross-fetch": "4.0.0",
+        "debug": "4.3.4",
+        "devtools-protocol": "0.0.1147663",
+        "ws": "8.13.0"
+      },
+      "engines": {
+        "node": ">=16.3.0"
+      },
+      "peerDependencies": {
+        "typescript": ">= 4.7.4"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/queue-tick": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz",
+      "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag=="
+    },
+    "node_modules/require-directory": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+      "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/resolve-from": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+      "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/smart-buffer": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
+      "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
+      "engines": {
+        "node": ">= 6.0.0",
+        "npm": ">= 3.0.0"
+      }
+    },
+    "node_modules/socks": {
+      "version": "2.8.1",
+      "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.1.tgz",
+      "integrity": "sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ==",
+      "dependencies": {
+        "ip-address": "^9.0.5",
+        "smart-buffer": "^4.2.0"
+      },
+      "engines": {
+        "node": ">= 10.0.0",
+        "npm": ">= 3.0.0"
+      }
+    },
+    "node_modules/socks-proxy-agent": {
+      "version": "8.0.3",
+      "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.3.tgz",
+      "integrity": "sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A==",
+      "dependencies": {
+        "agent-base": "^7.1.1",
+        "debug": "^4.3.4",
+        "socks": "^2.7.1"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "optional": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/sprintf-js": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
+      "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA=="
+    },
+    "node_modules/streamx": {
+      "version": "2.16.1",
+      "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.16.1.tgz",
+      "integrity": "sha512-m9QYj6WygWyWa3H1YY69amr4nVgy61xfjys7xO7kviL5rfIEc2naf+ewFiOA+aEJD7y0JO3h2GoiUv4TDwEGzQ==",
+      "dependencies": {
+        "fast-fifo": "^1.1.0",
+        "queue-tick": "^1.0.1"
+      },
+      "optionalDependencies": {
+        "bare-events": "^2.2.0"
+      }
+    },
+    "node_modules/string-width": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/supports-color": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+      "dependencies": {
+        "has-flag": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/tar-fs": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz",
+      "integrity": "sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==",
+      "dependencies": {
+        "mkdirp-classic": "^0.5.2",
+        "pump": "^3.0.0",
+        "tar-stream": "^3.1.5"
+      }
+    },
+    "node_modules/tar-stream": {
+      "version": "3.1.7",
+      "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz",
+      "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==",
+      "dependencies": {
+        "b4a": "^1.6.4",
+        "fast-fifo": "^1.2.0",
+        "streamx": "^2.15.0"
+      }
+    },
+    "node_modules/through": {
+      "version": "2.3.8",
+      "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+      "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg=="
+    },
+    "node_modules/tr46": {
+      "version": "0.0.3",
+      "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+      "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
+    },
+    "node_modules/tslib": {
+      "version": "2.6.2",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
+      "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
+    },
+    "node_modules/unbzip2-stream": {
+      "version": "1.4.3",
+      "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz",
+      "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==",
+      "dependencies": {
+        "buffer": "^5.2.1",
+        "through": "^2.3.8"
+      }
+    },
+    "node_modules/undici-types": {
+      "version": "5.26.5",
+      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
+      "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
+      "optional": true
+    },
+    "node_modules/universalify": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
+      "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
+      "engines": {
+        "node": ">= 10.0.0"
+      }
+    },
+    "node_modules/webidl-conversions": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+      "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
+    },
+    "node_modules/whatwg-url": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+      "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+      "dependencies": {
+        "tr46": "~0.0.3",
+        "webidl-conversions": "^3.0.0"
+      }
+    },
+    "node_modules/wrap-ansi": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+      "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+      }
+    },
+    "node_modules/wrap-ansi/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/wrap-ansi/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/wrap-ansi/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+    },
+    "node_modules/wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
+    },
+    "node_modules/ws": {
+      "version": "8.13.0",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
+      "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
+      "engines": {
+        "node": ">=10.0.0"
+      },
+      "peerDependencies": {
+        "bufferutil": "^4.0.1",
+        "utf-8-validate": ">=5.0.2"
+      },
+      "peerDependenciesMeta": {
+        "bufferutil": {
+          "optional": true
+        },
+        "utf-8-validate": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/y18n": {
+      "version": "5.0.8",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+      "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/yargs": {
+      "version": "17.7.1",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz",
+      "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==",
+      "dependencies": {
+        "cliui": "^8.0.1",
+        "escalade": "^3.1.1",
+        "get-caller-file": "^2.0.5",
+        "require-directory": "^2.1.1",
+        "string-width": "^4.2.3",
+        "y18n": "^5.0.5",
+        "yargs-parser": "^21.1.1"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/yargs-parser": {
+      "version": "21.1.1",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+      "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/yauzl": {
+      "version": "2.10.0",
+      "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
+      "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==",
+      "dependencies": {
+        "buffer-crc32": "~0.2.3",
+        "fd-slicer": "~1.1.0"
+      }
+    }
+  }
+}

+ 22 - 0
node_modules/@babel/code-frame/LICENSE

@@ -0,0 +1,22 @@
+MIT License
+
+Copyright (c) 2014-present Sebastian McKenzie and other contributors
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 19 - 0
node_modules/@babel/code-frame/README.md

@@ -0,0 +1,19 @@
+# @babel/code-frame
+
+> Generate errors that contain a code frame that point to source locations.
+
+See our website [@babel/code-frame](https://babeljs.io/docs/babel-code-frame) for more information.
+
+## Install
+
+Using npm:
+
+```sh
+npm install --save-dev @babel/code-frame
+```
+
+or using yarn:
+
+```sh
+yarn add @babel/code-frame --dev
+```

+ 156 - 0
node_modules/@babel/code-frame/lib/index.js

@@ -0,0 +1,156 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.codeFrameColumns = codeFrameColumns;
+exports.default = _default;
+var _highlight = require("@babel/highlight");
+var _picocolors = _interopRequireWildcard(require("picocolors"), true);
+function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
+function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
+const colors = typeof process === "object" && (process.env.FORCE_COLOR === "0" || process.env.FORCE_COLOR === "false") ? (0, _picocolors.createColors)(false) : _picocolors.default;
+const compose = (f, g) => v => f(g(v));
+let pcWithForcedColor = undefined;
+function getColors(forceColor) {
+  if (forceColor) {
+    var _pcWithForcedColor;
+    (_pcWithForcedColor = pcWithForcedColor) != null ? _pcWithForcedColor : pcWithForcedColor = (0, _picocolors.createColors)(true);
+    return pcWithForcedColor;
+  }
+  return colors;
+}
+let deprecationWarningShown = false;
+function getDefs(colors) {
+  return {
+    gutter: colors.gray,
+    marker: compose(colors.red, colors.bold),
+    message: compose(colors.red, colors.bold)
+  };
+}
+const NEWLINE = /\r\n|[\n\r\u2028\u2029]/;
+function getMarkerLines(loc, source, opts) {
+  const startLoc = Object.assign({
+    column: 0,
+    line: -1
+  }, loc.start);
+  const endLoc = Object.assign({}, startLoc, loc.end);
+  const {
+    linesAbove = 2,
+    linesBelow = 3
+  } = opts || {};
+  const startLine = startLoc.line;
+  const startColumn = startLoc.column;
+  const endLine = endLoc.line;
+  const endColumn = endLoc.column;
+  let start = Math.max(startLine - (linesAbove + 1), 0);
+  let end = Math.min(source.length, endLine + linesBelow);
+  if (startLine === -1) {
+    start = 0;
+  }
+  if (endLine === -1) {
+    end = source.length;
+  }
+  const lineDiff = endLine - startLine;
+  const markerLines = {};
+  if (lineDiff) {
+    for (let i = 0; i <= lineDiff; i++) {
+      const lineNumber = i + startLine;
+      if (!startColumn) {
+        markerLines[lineNumber] = true;
+      } else if (i === 0) {
+        const sourceLength = source[lineNumber - 1].length;
+        markerLines[lineNumber] = [startColumn, sourceLength - startColumn + 1];
+      } else if (i === lineDiff) {
+        markerLines[lineNumber] = [0, endColumn];
+      } else {
+        const sourceLength = source[lineNumber - i].length;
+        markerLines[lineNumber] = [0, sourceLength];
+      }
+    }
+  } else {
+    if (startColumn === endColumn) {
+      if (startColumn) {
+        markerLines[startLine] = [startColumn, 0];
+      } else {
+        markerLines[startLine] = true;
+      }
+    } else {
+      markerLines[startLine] = [startColumn, endColumn - startColumn];
+    }
+  }
+  return {
+    start,
+    end,
+    markerLines
+  };
+}
+function codeFrameColumns(rawLines, loc, opts = {}) {
+  const highlighted = (opts.highlightCode || opts.forceColor) && (0, _highlight.shouldHighlight)(opts);
+  const colors = getColors(opts.forceColor);
+  const defs = getDefs(colors);
+  const maybeHighlight = (fmt, string) => {
+    return highlighted ? fmt(string) : string;
+  };
+  const lines = rawLines.split(NEWLINE);
+  const {
+    start,
+    end,
+    markerLines
+  } = getMarkerLines(loc, lines, opts);
+  const hasColumns = loc.start && typeof loc.start.column === "number";
+  const numberMaxWidth = String(end).length;
+  const highlightedLines = highlighted ? (0, _highlight.default)(rawLines, opts) : rawLines;
+  let frame = highlightedLines.split(NEWLINE, end).slice(start, end).map((line, index) => {
+    const number = start + 1 + index;
+    const paddedNumber = ` ${number}`.slice(-numberMaxWidth);
+    const gutter = ` ${paddedNumber} |`;
+    const hasMarker = markerLines[number];
+    const lastMarkerLine = !markerLines[number + 1];
+    if (hasMarker) {
+      let markerLine = "";
+      if (Array.isArray(hasMarker)) {
+        const markerSpacing = line.slice(0, Math.max(hasMarker[0] - 1, 0)).replace(/[^\t]/g, " ");
+        const numberOfMarkers = hasMarker[1] || 1;
+        markerLine = ["\n ", maybeHighlight(defs.gutter, gutter.replace(/\d/g, " ")), " ", markerSpacing, maybeHighlight(defs.marker, "^").repeat(numberOfMarkers)].join("");
+        if (lastMarkerLine && opts.message) {
+          markerLine += " " + maybeHighlight(defs.message, opts.message);
+        }
+      }
+      return [maybeHighlight(defs.marker, ">"), maybeHighlight(defs.gutter, gutter), line.length > 0 ? ` ${line}` : "", markerLine].join("");
+    } else {
+      return ` ${maybeHighlight(defs.gutter, gutter)}${line.length > 0 ? ` ${line}` : ""}`;
+    }
+  }).join("\n");
+  if (opts.message && !hasColumns) {
+    frame = `${" ".repeat(numberMaxWidth + 1)}${opts.message}\n${frame}`;
+  }
+  if (highlighted) {
+    return colors.reset(frame);
+  } else {
+    return frame;
+  }
+}
+function _default(rawLines, lineNumber, colNumber, opts = {}) {
+  if (!deprecationWarningShown) {
+    deprecationWarningShown = true;
+    const message = "Passing lineNumber and colNumber is deprecated to @babel/code-frame. Please use `codeFrameColumns`.";
+    if (process.emitWarning) {
+      process.emitWarning(message, "DeprecationWarning");
+    } else {
+      const deprecationError = new Error(message);
+      deprecationError.name = "DeprecationWarning";
+      console.warn(new Error(message));
+    }
+  }
+  colNumber = Math.max(colNumber, 0);
+  const location = {
+    start: {
+      column: colNumber,
+      line: lineNumber
+    }
+  };
+  return codeFrameColumns(rawLines, location, opts);
+}
+
+//# sourceMappingURL=index.js.map

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
node_modules/@babel/code-frame/lib/index.js.map


+ 30 - 0
node_modules/@babel/code-frame/package.json

@@ -0,0 +1,30 @@
+{
+  "name": "@babel/code-frame",
+  "version": "7.24.2",
+  "description": "Generate errors that contain a code frame that point to source locations.",
+  "author": "The Babel Team (https://babel.dev/team)",
+  "homepage": "https://babel.dev/docs/en/next/babel-code-frame",
+  "bugs": "https://github.com/babel/babel/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen",
+  "license": "MIT",
+  "publishConfig": {
+    "access": "public"
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/babel/babel.git",
+    "directory": "packages/babel-code-frame"
+  },
+  "main": "./lib/index.js",
+  "dependencies": {
+    "@babel/highlight": "^7.24.2",
+    "picocolors": "^1.0.0"
+  },
+  "devDependencies": {
+    "import-meta-resolve": "^4.0.0",
+    "strip-ansi": "^4.0.0"
+  },
+  "engines": {
+    "node": ">=6.9.0"
+  },
+  "type": "commonjs"
+}

+ 22 - 0
node_modules/@babel/helper-validator-identifier/LICENSE

@@ -0,0 +1,22 @@
+MIT License
+
+Copyright (c) 2014-present Sebastian McKenzie and other contributors
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 19 - 0
node_modules/@babel/helper-validator-identifier/README.md

@@ -0,0 +1,19 @@
+# @babel/helper-validator-identifier
+
+> Validate identifier/keywords name
+
+See our website [@babel/helper-validator-identifier](https://babeljs.io/docs/babel-helper-validator-identifier) for more information.
+
+## Install
+
+Using npm:
+
+```sh
+npm install --save @babel/helper-validator-identifier
+```
+
+or using yarn:
+
+```sh
+yarn add @babel/helper-validator-identifier
+```

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 8 - 0
node_modules/@babel/helper-validator-identifier/lib/identifier.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
node_modules/@babel/helper-validator-identifier/lib/identifier.js.map


+ 57 - 0
node_modules/@babel/helper-validator-identifier/lib/index.js

@@ -0,0 +1,57 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+Object.defineProperty(exports, "isIdentifierChar", {
+  enumerable: true,
+  get: function () {
+    return _identifier.isIdentifierChar;
+  }
+});
+Object.defineProperty(exports, "isIdentifierName", {
+  enumerable: true,
+  get: function () {
+    return _identifier.isIdentifierName;
+  }
+});
+Object.defineProperty(exports, "isIdentifierStart", {
+  enumerable: true,
+  get: function () {
+    return _identifier.isIdentifierStart;
+  }
+});
+Object.defineProperty(exports, "isKeyword", {
+  enumerable: true,
+  get: function () {
+    return _keyword.isKeyword;
+  }
+});
+Object.defineProperty(exports, "isReservedWord", {
+  enumerable: true,
+  get: function () {
+    return _keyword.isReservedWord;
+  }
+});
+Object.defineProperty(exports, "isStrictBindOnlyReservedWord", {
+  enumerable: true,
+  get: function () {
+    return _keyword.isStrictBindOnlyReservedWord;
+  }
+});
+Object.defineProperty(exports, "isStrictBindReservedWord", {
+  enumerable: true,
+  get: function () {
+    return _keyword.isStrictBindReservedWord;
+  }
+});
+Object.defineProperty(exports, "isStrictReservedWord", {
+  enumerable: true,
+  get: function () {
+    return _keyword.isStrictReservedWord;
+  }
+});
+var _identifier = require("./identifier.js");
+var _keyword = require("./keyword.js");
+
+//# sourceMappingURL=index.js.map

+ 1 - 0
node_modules/@babel/helper-validator-identifier/lib/index.js.map

@@ -0,0 +1 @@
+{"version":3,"names":["_identifier","require","_keyword"],"sources":["../src/index.ts"],"sourcesContent":["export {\n  isIdentifierName,\n  isIdentifierChar,\n  isIdentifierStart,\n} from \"./identifier.ts\";\nexport {\n  isReservedWord,\n  isStrictBindOnlyReservedWord,\n  isStrictBindReservedWord,\n  isStrictReservedWord,\n  isKeyword,\n} from \"./keyword.ts\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,IAAAA,WAAA,GAAAC,OAAA;AAKA,IAAAC,QAAA,GAAAD,OAAA"}

+ 35 - 0
node_modules/@babel/helper-validator-identifier/lib/keyword.js

@@ -0,0 +1,35 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.isKeyword = isKeyword;
+exports.isReservedWord = isReservedWord;
+exports.isStrictBindOnlyReservedWord = isStrictBindOnlyReservedWord;
+exports.isStrictBindReservedWord = isStrictBindReservedWord;
+exports.isStrictReservedWord = isStrictReservedWord;
+const reservedWords = {
+  keyword: ["break", "case", "catch", "continue", "debugger", "default", "do", "else", "finally", "for", "function", "if", "return", "switch", "throw", "try", "var", "const", "while", "with", "new", "this", "super", "class", "extends", "export", "import", "null", "true", "false", "in", "instanceof", "typeof", "void", "delete"],
+  strict: ["implements", "interface", "let", "package", "private", "protected", "public", "static", "yield"],
+  strictBind: ["eval", "arguments"]
+};
+const keywords = new Set(reservedWords.keyword);
+const reservedWordsStrictSet = new Set(reservedWords.strict);
+const reservedWordsStrictBindSet = new Set(reservedWords.strictBind);
+function isReservedWord(word, inModule) {
+  return inModule && word === "await" || word === "enum";
+}
+function isStrictReservedWord(word, inModule) {
+  return isReservedWord(word, inModule) || reservedWordsStrictSet.has(word);
+}
+function isStrictBindOnlyReservedWord(word) {
+  return reservedWordsStrictBindSet.has(word);
+}
+function isStrictBindReservedWord(word, inModule) {
+  return isStrictReservedWord(word, inModule) || isStrictBindOnlyReservedWord(word);
+}
+function isKeyword(word) {
+  return keywords.has(word);
+}
+
+//# sourceMappingURL=keyword.js.map

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
node_modules/@babel/helper-validator-identifier/lib/keyword.js.map


+ 28 - 0
node_modules/@babel/helper-validator-identifier/package.json

@@ -0,0 +1,28 @@
+{
+  "name": "@babel/helper-validator-identifier",
+  "version": "7.22.20",
+  "description": "Validate identifier/keywords name",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/babel/babel.git",
+    "directory": "packages/babel-helper-validator-identifier"
+  },
+  "license": "MIT",
+  "publishConfig": {
+    "access": "public"
+  },
+  "main": "./lib/index.js",
+  "exports": {
+    ".": "./lib/index.js",
+    "./package.json": "./package.json"
+  },
+  "devDependencies": {
+    "@unicode/unicode-15.1.0": "^1.5.2",
+    "charcodes": "^0.2.0"
+  },
+  "engines": {
+    "node": ">=6.9.0"
+  },
+  "author": "The Babel Team (https://babel.dev/team)",
+  "type": "commonjs"
+}

+ 73 - 0
node_modules/@babel/helper-validator-identifier/scripts/generate-identifier-regex.js

@@ -0,0 +1,73 @@
+"use strict";
+
+// Always use the latest available version of Unicode!
+// https://tc39.github.io/ecma262/#sec-conformance
+const version = "15.1.0";
+
+const start = require(
+  "@unicode/unicode-" + version + "/Binary_Property/ID_Start/code-points.js"
+).filter(function (ch) {
+  return ch > 0x7f;
+});
+let last = -1;
+const cont = require(
+  "@unicode/unicode-" + version + "/Binary_Property/ID_Continue/code-points.js"
+).filter(function (ch) {
+  return ch > 0x7f && search(start, ch, last + 1) == -1;
+});
+
+function search(arr, ch, starting) {
+  for (let i = starting; arr[i] <= ch && i < arr.length; last = i++) {
+    if (arr[i] === ch) return i;
+  }
+  return -1;
+}
+
+function pad(str, width) {
+  while (str.length < width) str = "0" + str;
+  return str;
+}
+
+function esc(code) {
+  const hex = code.toString(16);
+  if (hex.length <= 2) return "\\x" + pad(hex, 2);
+  else return "\\u" + pad(hex, 4);
+}
+
+function generate(chars) {
+  const astral = [];
+  let re = "";
+  for (let i = 0, at = 0x10000; i < chars.length; i++) {
+    const from = chars[i];
+    let to = from;
+    while (i < chars.length - 1 && chars[i + 1] == to + 1) {
+      i++;
+      to++;
+    }
+    if (to <= 0xffff) {
+      if (from == to) re += esc(from);
+      else if (from + 1 == to) re += esc(from) + esc(to);
+      else re += esc(from) + "-" + esc(to);
+    } else {
+      astral.push(from - at, to - from);
+      at = to;
+    }
+  }
+  return { nonASCII: re, astral: astral };
+}
+
+const startData = generate(start);
+const contData = generate(cont);
+
+console.log("/* prettier-ignore */");
+console.log('let nonASCIIidentifierStartChars = "' + startData.nonASCII + '";');
+console.log("/* prettier-ignore */");
+console.log('let nonASCIIidentifierChars = "' + contData.nonASCII + '";');
+console.log("/* prettier-ignore */");
+console.log(
+  "const astralIdentifierStartCodes = " + JSON.stringify(startData.astral) + ";"
+);
+console.log("/* prettier-ignore */");
+console.log(
+  "const astralIdentifierCodes = " + JSON.stringify(contData.astral) + ";"
+);

+ 22 - 0
node_modules/@babel/highlight/LICENSE

@@ -0,0 +1,22 @@
+MIT License
+
+Copyright (c) 2014-present Sebastian McKenzie and other contributors
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 19 - 0
node_modules/@babel/highlight/README.md

@@ -0,0 +1,19 @@
+# @babel/highlight
+
+> Syntax highlight JavaScript strings for output in terminals.
+
+See our website [@babel/highlight](https://babeljs.io/docs/babel-highlight) for more information.
+
+## Install
+
+Using npm:
+
+```sh
+npm install --save-dev @babel/highlight
+```
+
+or using yarn:
+
+```sh
+yarn add @babel/highlight --dev
+```

+ 119 - 0
node_modules/@babel/highlight/lib/index.js

@@ -0,0 +1,119 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.default = highlight;
+exports.shouldHighlight = shouldHighlight;
+var _jsTokens = require("js-tokens");
+var _helperValidatorIdentifier = require("@babel/helper-validator-identifier");
+var _picocolors = _interopRequireWildcard(require("picocolors"), true);
+function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
+function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
+const colors = typeof process === "object" && (process.env.FORCE_COLOR === "0" || process.env.FORCE_COLOR === "false") ? (0, _picocolors.createColors)(false) : _picocolors.default;
+const compose = (f, g) => v => f(g(v));
+const sometimesKeywords = new Set(["as", "async", "from", "get", "of", "set"]);
+function getDefs(colors) {
+  return {
+    keyword: colors.cyan,
+    capitalized: colors.yellow,
+    jsxIdentifier: colors.yellow,
+    punctuator: colors.yellow,
+    number: colors.magenta,
+    string: colors.green,
+    regex: colors.magenta,
+    comment: colors.gray,
+    invalid: compose(compose(colors.white, colors.bgRed), colors.bold)
+  };
+}
+const NEWLINE = /\r\n|[\n\r\u2028\u2029]/;
+const BRACKET = /^[()[\]{}]$/;
+let tokenize;
+{
+  const JSX_TAG = /^[a-z][\w-]*$/i;
+  const getTokenType = function (token, offset, text) {
+    if (token.type === "name") {
+      if ((0, _helperValidatorIdentifier.isKeyword)(token.value) || (0, _helperValidatorIdentifier.isStrictReservedWord)(token.value, true) || sometimesKeywords.has(token.value)) {
+        return "keyword";
+      }
+      if (JSX_TAG.test(token.value) && (text[offset - 1] === "<" || text.slice(offset - 2, offset) == "</")) {
+        return "jsxIdentifier";
+      }
+      if (token.value[0] !== token.value[0].toLowerCase()) {
+        return "capitalized";
+      }
+    }
+    if (token.type === "punctuator" && BRACKET.test(token.value)) {
+      return "bracket";
+    }
+    if (token.type === "invalid" && (token.value === "@" || token.value === "#")) {
+      return "punctuator";
+    }
+    return token.type;
+  };
+  tokenize = function* (text) {
+    let match;
+    while (match = _jsTokens.default.exec(text)) {
+      const token = _jsTokens.matchToToken(match);
+      yield {
+        type: getTokenType(token, match.index, text),
+        value: token.value
+      };
+    }
+  };
+}
+function highlightTokens(defs, text) {
+  let highlighted = "";
+  for (const {
+    type,
+    value
+  } of tokenize(text)) {
+    const colorize = defs[type];
+    if (colorize) {
+      highlighted += value.split(NEWLINE).map(str => colorize(str)).join("\n");
+    } else {
+      highlighted += value;
+    }
+  }
+  return highlighted;
+}
+function shouldHighlight(options) {
+  return colors.isColorSupported || options.forceColor;
+}
+let pcWithForcedColor = undefined;
+function getColors(forceColor) {
+  if (forceColor) {
+    var _pcWithForcedColor;
+    (_pcWithForcedColor = pcWithForcedColor) != null ? _pcWithForcedColor : pcWithForcedColor = (0, _picocolors.createColors)(true);
+    return pcWithForcedColor;
+  }
+  return colors;
+}
+function highlight(code, options = {}) {
+  if (code !== "" && shouldHighlight(options)) {
+    const defs = getDefs(getColors(options.forceColor));
+    return highlightTokens(defs, code);
+  } else {
+    return code;
+  }
+}
+{
+  let chalk, chalkWithForcedColor;
+  exports.getChalk = ({
+    forceColor
+  }) => {
+    var _chalk;
+    (_chalk = chalk) != null ? _chalk : chalk = require("chalk");
+    if (forceColor) {
+      var _chalkWithForcedColor;
+      (_chalkWithForcedColor = chalkWithForcedColor) != null ? _chalkWithForcedColor : chalkWithForcedColor = new chalk.constructor({
+        enabled: true,
+        level: 1
+      });
+      return chalkWithForcedColor;
+    }
+    return chalk;
+  };
+}
+
+//# sourceMappingURL=index.js.map

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
node_modules/@babel/highlight/lib/index.js.map


+ 30 - 0
node_modules/@babel/highlight/package.json

@@ -0,0 +1,30 @@
+{
+  "name": "@babel/highlight",
+  "version": "7.24.2",
+  "description": "Syntax highlight JavaScript strings for output in terminals.",
+  "author": "The Babel Team (https://babel.dev/team)",
+  "homepage": "https://babel.dev/docs/en/next/babel-highlight",
+  "license": "MIT",
+  "publishConfig": {
+    "access": "public"
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/babel/babel.git",
+    "directory": "packages/babel-highlight"
+  },
+  "main": "./lib/index.js",
+  "dependencies": {
+    "@babel/helper-validator-identifier": "^7.22.20",
+    "chalk": "^2.4.2",
+    "js-tokens": "^4.0.0",
+    "picocolors": "^1.0.0"
+  },
+  "devDependencies": {
+    "strip-ansi": "^4.0.0"
+  },
+  "engines": {
+    "node": ">=6.9.0"
+  },
+  "type": "commonjs"
+}

+ 18 - 0
node_modules/@nesk/rialto/.travis.yml

@@ -0,0 +1,18 @@
+language: php
+
+php:
+  - 7.1
+  - 7.2
+  - 7.3
+
+env:
+  - COMPOSER_FLAGS="--prefer-lowest"
+  - COMPOSER_FLAGS=""
+
+install:
+  - php -v | grep '^PHP 7.[^3]' && pecl install weakref-beta || true
+  - travis_retry composer self-update
+  - travis_retry composer update ${COMPOSER_FLAGS} --no-interaction --prefer-source
+  - nvm install stable
+  - nvm use stable
+  - npm install

+ 89 - 0
node_modules/@nesk/rialto/CHANGELOG.md

@@ -0,0 +1,89 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
+and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
+
+## [Unreleased]
+_In progress…_
+
+## [1.4.0] - 2020-04-12
+### Added
+- Support symfony/process v5
+
+## [1.3.0] - 2019-03-14
+### Added
+- Support string casting for resources
+
+## [1.2.1] - 2018-08-28
+### Fixed
+- Heavy socket payloads are no longer unreadable in slow environments
+- Fix an issue where the console object can't be set in some environments
+
+## [1.2.0] - 2018-08-20
+### Added
+- Add a `log_node_console` option to log the output of console methods (`console.log`, `console.debug`, `console.table`, etc…) to the PHP logger
+
+### Changed
+- Drastically improve the log contents
+
+### Fixed
+- Fix a bug where some standard streams logs were missing
+- Fix double declarations of some JS classes due to a require with two different paths
+- Fix a bug where sending `null` values was crashing the Node process
+
+## [1.1.0] - 2018-07-20
+### Added
+- Support passing Node resources in JS functions
+- Add chaining methods to the `JsFunction` class
+- Add an `async()` method to the `JsFunction` class to allow developers to write `await` instructions in their JS code
+- The `idle_timeout` and `read_timeout` options can be disabled by setting them to `null`
+
+### Deprecated
+- Deprecate the `JsFunction::create` method in favor of the new chaining methods
+
+## [1.0.2] - 2018-06-18
+### Fixed
+- Fix an issue where the socket port couldn't be retrieved
+
+## [1.0.1] - 2018-06-12
+### Fixed
+- Fix `false` values being parsed as `null` by the unserializer
+- Fix Travis tests
+
+## [1.0.0] - 2018-06-05
+### Changed
+- Change PHP's vendor name from `extractr-io` to `nesk`
+- Change NPM's scope name from `@extractr-io` to `@nesk`
+
+## [0.1.2] - 2018-04-09
+### Added
+- Support PHPUnit v7
+- Add Travis integration
+
+### Changed
+- Improve the conditions to throw `ReadSocketTimeoutException`
+
+### Fixed
+- Support heavy socket payloads containing non-ASCII characters
+
+## [0.1.1] - 2018-01-29
+### Fixed
+- Fix an issue on an internal type check
+
+## 0.1.0 - 2018-01-29
+First release
+
+
+[Unreleased]: https://github.com/nesk/rialto/compare/1.4.0...HEAD
+[1.4.0]: https://github.com/nesk/rialto/compare/1.3.0...1.4.0
+[1.3.0]: https://github.com/nesk/rialto/compare/1.2.1...1.3.0
+[1.2.1]: https://github.com/nesk/rialto/compare/1.2.0...1.2.1
+[1.2.0]: https://github.com/nesk/rialto/compare/1.1.0...1.2.0
+[1.1.0]: https://github.com/nesk/rialto/compare/1.0.2...1.1.0
+[1.0.2]: https://github.com/nesk/rialto/compare/1.0.1...1.0.2
+[1.0.1]: https://github.com/nesk/rialto/compare/1.0.0...1.0.1
+[1.0.0]: https://github.com/nesk/rialto/compare/0.1.2...1.0.0
+[0.1.2]: https://github.com/nesk/rialto/compare/0.1.1...0.1.2
+[0.1.1]: https://github.com/nesk/rialto/compare/0.1.0...0.1.1

+ 19 - 0
node_modules/@nesk/rialto/LICENSE

@@ -0,0 +1,19 @@
+Copyright (c) Johann Pardanaud
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.

+ 32 - 0
node_modules/@nesk/rialto/README.md

@@ -0,0 +1,32 @@
+# Rialto
+
+[![PHP Version](https://img.shields.io/packagist/php-v/nesk/rialto.svg?style=flat-square)](http://php.net/)
+[![Composer Version](https://img.shields.io/packagist/v/nesk/rialto.svg?style=flat-square&label=Composer)](https://packagist.org/packages/nesk/rialto)
+[![Node Version](https://img.shields.io/node/v/@nesk/rialto.svg?style=flat-square&label=Node)](https://nodejs.org/)
+[![NPM Version](https://img.shields.io/npm/v/@nesk/rialto.svg?style=flat-square&label=NPM)](https://www.npmjs.com/package/@nesk/rialto)
+[![Build Status](https://img.shields.io/travis/nesk/rialto.svg?style=flat-square&label=Build%20Status)](https://travis-ci.org/nesk/rialto)
+
+A package to manage Node resources from PHP. It can be used to create bridges to interact with Node libraries in PHP, like [PuPHPeteer](https://github.com/nesk/puphpeteer/).
+
+It works by creating a Node process and communicates with it through sockets.
+
+## Requirements and installation
+
+Rialto requires PHP >= 7.1 and Node >= 8.
+
+Install it in your project:
+
+```shell
+composer require nesk/rialto
+npm install @nesk/rialto
+```
+
+## Usage
+
+See our tutorial to [create your first bridge with Rialto](docs/tutorial.md).
+
+An [API documentation](docs/api.md) is also available.
+
+## License
+
+The MIT License (MIT). Please see [License File](LICENSE) for more information.

+ 51 - 0
node_modules/@nesk/rialto/composer.json

@@ -0,0 +1,51 @@
+{
+    "name": "nesk/rialto",
+    "description": "Manage Node resources from PHP",
+    "keywords": [
+        "php",
+        "node",
+        "wrapper",
+        "communication",
+        "bridge",
+        "socket"
+    ],
+    "type": "library",
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "Johann Pardanaud",
+            "email": "pardanaud.j@gmail.com"
+        }
+    ],
+    "require": {
+        "php": ">=7.1",
+        "clue/socket-raw": "^1.2",
+        "psr/log": "^1.0",
+        "symfony/process": "^3.3|^4.0|^5.0"
+    },
+    "require-dev": {
+        "codedungeon/phpunit-result-printer": ">=0.6 <1.0",
+        "monolog/monolog": "^1.23",
+        "phpunit/phpunit": "^6.5|^7.0"
+    },
+    "suggest": {
+        "ext-weakref": "Required to run all the tests"
+    },
+    "autoload": {
+        "psr-4": {
+            "Nesk\\Rialto\\": "src/"
+        }
+    },
+    "autoload-dev": {
+        "psr-4": {
+            "Nesk\\Rialto\\Tests\\": "tests/"
+        }
+    },
+    "scripts": {
+        "post-install-cmd": "npm install",
+        "test": "./vendor/bin/phpunit"
+    },
+    "config": {
+        "sort-packages": true
+    }
+}

+ 210 - 0
node_modules/@nesk/rialto/docs/api.md

@@ -0,0 +1,210 @@
+# API usage
+
+## Options
+
+The entry point of Rialto accepts [multiple options](https://github.com/nesk/rialto/blob/75b5a9464235a597e3ab71ac90246779a40fe145/src/ProcessSupervisor.php#L42-L70), here are some descriptions with the default values:
+
+```php
+[
+    // Node's executable path
+    'executable_path' => 'node',
+
+    // How much time (in seconds) the process can stay inactive before being killed (set to null to disable)
+    'idle_timeout' => 60,
+
+    // How much time (in seconds) an instruction can take to return a value (set to null to disable)
+    'read_timeout' => 30,
+
+    // How much time (in seconds) the process can take to shutdown properly before being killed
+    'stop_timeout' => 3,
+
+    // A logger instance for debugging (must implement \Psr\Log\LoggerInterface)
+    'logger' => null,
+
+    // Logs the output of console methods (console.log, console.debug, console.table, etc...) to the PHP logger
+    'log_node_console' => false,
+
+    // Enables debugging mode:
+    //   - adds the --inspect flag to Node's command
+    //   - appends stack traces to Node exception messages
+    'debug' => false,
+]
+```
+
+You can define an option in your entry point using the third parameter of the parent constructor:
+
+```php
+class MyEntryPoint extends AbstractEntryPoint
+{
+    public function __construct()
+    {
+        // ...
+
+        $myOptions = [
+            'idle_timeout' => 300, // 5 minutes
+        ];
+
+        parent::__construct($connectionDelegate, $processDelegate, $myOptions);
+    }
+}
+```
+
+### Accepting user options
+
+If you want your users to define some of Rialto's options, you can use the fourth parameter:
+
+```php
+class MyEntryPoint extends AbstractEntryPoint
+{
+    public function __construct(array $userOptions = [])
+    {
+        // ...
+
+        parent::__construct($connectionDelegate, $processDelegate, $myOptions, $userOptions);
+    }
+}
+```
+
+User options will override your own defaults. To prevent a user to define some specific options, use the `$forbiddenOptions` property:
+
+```php
+class MyEntryPoint extends AbstractEntryPoint
+{
+    protected $forbiddenOptions = ['idle_timeout', 'stop_timeout'];
+
+    public function __construct(array $userOptions = [])
+    {
+        // ...
+
+        parent::__construct($connectionDelegate, $processDelegate, $myOptions, $userOptions);
+    }
+}
+```
+
+By default, users are forbidden to define the `stop_timeout` option.
+
+**Note:** You should authorize your users to define, at least, the `executable_path`, `logger` and `debug` options.
+
+## Node errors
+
+If an error (or an unhandled rejection) occurs in Node, a `Node\FatalException` will be thrown and the process closed, you will have to create a new instance of your entry point.
+
+To avoid that, you can ask Node to catch these errors by prepending your instruction with `->tryCatch`:
+
+```php
+use Nesk\Rialto\Exceptions\Node;
+
+try {
+    $someResource->tryCatch->inexistantMethod();
+} catch (Node\Exception $exception) {
+    // Handle the exception...
+}
+```
+
+Instead, a `Node\Exception` will be thrown, the Node process will stay alive and usable.
+
+## JavaScript functions
+
+With Rialto you can create JavaScript functions and pass them to the Node process, this can be useful to map some values or any other actions based on callbacks.
+
+To create them, you need to use the `Nesk\Rialto\Data\JsFunction` class and call one or multiple methods in this list:
+
+- `parameters(array)`: Sets parameters for your function, each string in the array is a parameter. You can define a default value for a parameter by using the parameter name as a key and its default value as the item value (e.g. `->parameters(['firstParam', 'secondParam' => 'Default string value'])`).
+
+- `body(string)`: Sets the body of your function, just write your JS code in a PHP string (e.g. `->body("return 'Hello world!'")`).
+
+- `scope(array)`: Defines scope variables for your function. Say you have `$hello = 'Hello world!'` in your PHP and you want to use it in your JS code, you can write `->scope(['myVar' => $hello])` and you will be able to use it in your body `->body("console.log(myVar)")`.
+<br> **Note:** Scope variables must be JSON serializable values or resources created by Rialto.
+
+- `async(?bool)`: Makes your JS function async. Optionally, you can provide a boolean: `true` will make the function async, `false` will remove the `async` state.
+<br> **Note:** Like in the ECMAScript specification, JS functions _aren't_ async by default.
+
+To create a new JS function, use `JsFunction::createWith__METHOD_NAME__` with the method name you want (in the list just above):
+
+```php
+JsFunction::createWithParameters(['a', 'b'])
+    ->body('return a + b;');
+```
+
+Here we used `createWithParameters` to start the creation, but we could have used `createWithBody`, `createWithScope`, etc…
+
+<details>
+<summary><strong>⚙️ Some examples showing how to use these methods</strong></summary> <br>
+
+- A function with a body:
+
+```php
+$jsFunction = JsFunction::createWithBody("return process.uptime()");
+
+$someResource->someMethodWithCallback($jsFunction);
+```
+
+- A function with parameters and a body:
+
+```php
+$jsFunction = JsFunction::createWithParameters(['str', 'str2' => 'Default value!'])
+    ->body("return 'This is my string: ' + str");
+
+$someResource->someMethodWithCallback($jsFunction);
+```
+
+- A function with parameters, a body, scoped values, and async flag:
+
+```php
+$functionScope = ['stringtoPrepend' => 'This is another string: '];
+
+$jsFunction = JsFunction::createWithAsync()
+    ->parameters(['str'])
+    ->body("return stringToPrepend + str")
+    ->scope($functionScope);
+
+$someResource->someMethodWithCallback($jsFunction);
+```
+
+</details>
+
+<br>
+
+<details>
+<summary><strong>⚠️ Deprecated examples of the <code>JsFunction::create()</code> method</strong></summary> <br>
+
+- A function with a body:
+
+```php
+$jsFunction = JsFunction::create("
+    return process.uptime();
+");
+
+$someResource->someMethodWithCallback($jsFunction);
+```
+
+- A function with parameters:
+
+```php
+$jsFunction = JsFunction::create(['str', 'str2' => 'Default value!'], "
+    return 'This is my string: ' + str;
+");
+
+$someResource->someMethodWithCallback($jsFunction);
+```
+
+- A function with parameters, a body, and scoped values:
+
+```php
+$functionScope = ['stringtoPrepend' => 'This is another string: '];
+
+$jsFunction = JsFunction::create(['str'], "
+    return stringToPrepend + str;
+", $functionScope);
+
+$someResource->someMethodWithCallback($jsFunction);
+```
+
+</details>
+
+## Destruction
+
+If you're worried about the destruction of the Node process, here's two things you need to know:
+
+- Once the entry point and all the resources (like the `BasicResource` class) are unset, the Node process is automatically terminated.
+- If, for any reason, the Node process doesn't terminate, it will kill itself once the `idle_timeout` is exceeded.

+ 188 - 0
node_modules/@nesk/rialto/docs/tutorial.md

@@ -0,0 +1,188 @@
+# Creating your first bridge with Rialto
+
+We will create a bridge to use [Node's File System module](https://nodejs.org/api/fs.html) in PHP. This is not especially useful but it will show you how Rialto works and handles pretty much everything for you.
+
+## Importing Rialto
+
+Import Rialto in your project:
+
+```
+composer require nesk/rialto
+npm install @nesk/rialto
+```
+
+## The essential files
+
+You will need to create at least two files for your package:
+
+- **An entry point** (`FileSystem.php`): this PHP class inherits [`AbstractEntryPoint`](../src/AbstractEntryPoint.php) and its instanciation creates the Node process. Every instruction (calling a method, setting a property, etc…) made on this class will be intercepted and sent to Node.
+
+```php
+use Nesk\Rialto\AbstractEntryPoint;
+
+class FileSystem extends AbstractEntryPoint
+{
+    public function __construct()
+    {
+        parent::__construct(__DIR__.'/FileSystemConnectionDelegate.js');
+    }
+}
+```
+
+- **A connection delegate** (`FileSystemConnectionDelegate.js`): this JavaScript class inherits [`ConnectionDelegate`](../src/node-process/ConnectionDelegate.js) and will execute the instructions made with PHP (calling a method, setting a property, etc…).
+
+```js
+const fs = require('fs'),
+    {ConnectionDelegate} = require('@nesk/rialto');
+
+module.exports = class FileSystemConnectionDelegate extends ConnectionDelegate
+{
+    handleInstruction(instruction, responseHandler, errorHandler)
+    {
+        // Define on which resource the instruction should be applied by default,
+        // here we want to apply them on the "fs" module.
+        instruction.setDefaultResource(fs);
+
+        let value = null;
+
+        try {
+            // Try to execute the instruction
+            value = instruction.execute();
+        } catch (error) {
+            // If the instruction fails and the user asked to catch errors (see the `tryCatch` property in the API),
+            // send it with the error handler.
+            if (instruction.shouldCatchErrors()) {
+                return errorHandler(error);
+            }
+
+            throw error;
+        }
+
+        // Send back the value returned by the instruction
+        responseHandler(value);
+    }
+}
+```
+
+With these two files, you should already be able to use your bridge:
+
+```php
+use Nesk\Puphpeteer\Fs\FileSystem;
+
+$fs = new FileSystem;
+
+$stats = $fs->statSync('/valid/file/path'); // Returns a basic resource representing a Stats instance
+
+$stats->isFile(); // Returns true if the path points to a file
+```
+
+**Note:** You should use the synchronous methods of Node's FileSystem module. There is no way to handle asynchronous callbacks with Rialto for the moment.
+
+## Creating specific resources
+
+The example above returns a [`BasicResource`](../src/Data/BasicResource.php) class when the JavaScript API returns a resource (typically, a class instance). See this example:
+
+```php
+$buffer = $fs->readFileSync('/valid/file/path'); // Returns a basic resource representing a Buffer instance
+
+$stats = $fs->statSync('/valid/file/path'); // Returns a basic resource representing a Stats instance
+```
+
+Its possible to know the name of the resource class:
+
+```php
+$buffer->getResourceIdentity()->className(); // Returns "Buffer"
+
+$stats->getResourceIdentity()->className(); // Returns "Stats"
+```
+
+However, this is not convenient. That's why you can create specific resources to improve that. We will create 3 files:
+
+- **A process delegate** (`FileSystemProcessDelegate.php`): this PHP class implements [`ShouldHandleProcessDelegation`](../src/Interfaces/ShouldHandleProcessDelegation.php) and is responsible to return the class names of the specific and default resources.
+
+```php
+use Nesk\Rialto\Traits\UsesBasicResourceAsDefault;
+use Nesk\Rialto\Interfaces\ShouldHandleProcessDelegation;
+
+class FileSystemProcessDelegate implements ShouldHandleProcessDelegation
+{
+    // Define that we want to use the BasicResource class as a default if resourceFromOriginalClassName() returns null
+    use UsesBasicResourceAsDefault;
+
+    public function resourceFromOriginalClassName(string $jsClassName): ?string
+    {
+        // Generate the appropriate class name for PHP
+        $class = "{$jsClassName}Resource";
+
+        // If the PHP class doesn't exist, return null, it will automatically create a basic resource.
+        return class_exists($class) ? $class : null;
+    }
+}
+```
+
+- **A resource to represent Buffer instances** (`BufferResource.php`): this class inherits `BasicResource` by convenience but the only requirement is to implement the [`ShouldIdentifyResource`](../src/Interfaces/ShouldIdentifyResource.php) interface.
+
+```php
+use Nesk\Rialto\Data\BasicResource;
+
+class BufferResource extends BasicResource
+{
+}
+```
+
+- **A resource to represent Stats instances** (`StatsResource.php`):
+
+```php
+use Nesk\Rialto\Data\BasicResource;
+
+class StatsResource extends BasicResource
+{
+}
+```
+
+Once those 3 files are created, you will have to register the process delegate in your entry point (`FileSystem.php`):
+
+```php
+use Nesk\Rialto\AbstractEntryPoint;
+
+class FileSystem extends AbstractEntryPoint
+{
+    public function __construct()
+    {
+        // Add the process delegate in addition to the connection delegate
+        parent::__construct(__DIR__.'/FileSystemConnectionDelegate.js', new FileSystemProcessDelegate);
+    }
+}
+```
+
+Now you will get specific resources instead of the default one:
+
+```php
+$fs->readFileSync('/valid/file/path'); // Returns BufferResource
+
+$fs->statSync('/valid/file/path'); // Returns StatsResource
+
+$fs->statSync('/valid/file/path')->birthtime; // Returns a basic resource representing a Date instance
+```
+
+Specific resources can also help you to improve your API by adding methods to them:
+
+```php
+use Nesk\Rialto\Data\BasicResource;
+
+class StatsResource extends BasicResource
+{
+    public function birthtime(): \DateTime
+    {
+        return (new \DateTime)->setTimestamp($this->birthtimeMs / 1000);
+    }
+}
+```
+
+```php
+$fs->statSync('/valid/file/path')->birthtime(); // Returns a PHP's DateTime instance
+```
+
+## Learn more
+
+Your first bridge with Rialto is ready, you can learn more by reading the [API documentation](api.md).

+ 27 - 0
node_modules/@nesk/rialto/package.json

@@ -0,0 +1,27 @@
+{
+  "name": "@nesk/rialto",
+  "version": "1.4.0",
+  "description": "Manage Node resources from PHP",
+  "keywords": [
+    "php",
+    "node",
+    "wrapper",
+    "communication",
+    "bridge",
+    "socket"
+  ],
+  "author": {
+    "name": "Johann Pardanaud",
+    "email": "pardanaud.j@gmail.com",
+    "url": "https://johann.pardanaud.com/"
+  },
+  "license": "MIT",
+  "repository": "github:nesk/rialto",
+  "main": "src/node-process",
+  "engines": {
+    "node": ">=8.0.0"
+  },
+  "dependencies": {
+    "lodash": "^4.17.10"
+  }
+}

+ 21 - 0
node_modules/@nesk/rialto/phpunit.xml

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/6.5/phpunit.xsd"
+         bootstrap="vendor/autoload.php"
+         printerClass="Codedungeon\PHPUnitPrettyResultPrinter\Printer"
+         forceCoversAnnotation="true"
+         beStrictAboutCoversAnnotation="true"
+         beStrictAboutOutputDuringTests="true"
+         beStrictAboutTodoAnnotatedTests="true"
+         colors="true"
+         verbose="true">
+    <testsuite name="default">
+        <directory suffix="Test.php">tests</directory>
+    </testsuite>
+
+    <filter>
+        <whitelist processUncoveredFilesFromWhitelist="true">
+            <directory suffix=".php">src</directory>
+        </whitelist>
+    </filter>
+</phpunit>

+ 47 - 0
node_modules/@nesk/rialto/src/AbstractEntryPoint.php

@@ -0,0 +1,47 @@
+<?php
+
+namespace Nesk\Rialto;
+
+use Nesk\Rialto\Interfaces\ShouldHandleProcessDelegation;
+
+abstract class AbstractEntryPoint
+{
+    use Traits\CommunicatesWithProcessSupervisor;
+
+    /**
+     * Forbidden options for the user.
+     *
+     * @var string[]
+     */
+    protected $forbiddenOptions = ['stop_timeout'];
+
+    /**
+     * Instanciate the entry point of the implementation.
+     */
+    public function __construct(
+        string $connectionDelegatePath,
+        ?ShouldHandleProcessDelegation $processDelegate = null,
+        array $implementationOptions = [],
+        array $userOptions = []
+    ) {
+        $process = new ProcessSupervisor(
+            $connectionDelegatePath,
+            $processDelegate,
+            $this->consolidateOptions($implementationOptions, $userOptions)
+        );
+
+        $this->setProcessSupervisor($process);
+    }
+
+    /**
+     * Clean the user options.
+     */
+    protected function consolidateOptions(array $implementationOptions, array $userOptions): array
+    {
+        // Filter out the forbidden option
+        $userOptions = array_diff_key($userOptions, array_flip($this->forbiddenOptions));
+
+        // Merge the user options with the implementation ones
+        return array_merge($implementationOptions, $userOptions);
+    }
+}

+ 19 - 0
node_modules/@nesk/rialto/src/Data/BasicResource.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace Nesk\Rialto\Data;
+
+use Nesk\Rialto\Traits\{IdentifiesResource, CommunicatesWithProcessSupervisor};
+use Nesk\Rialto\Interfaces\{ShouldIdentifyResource, ShouldCommunicateWithProcessSupervisor};
+
+class BasicResource implements ShouldIdentifyResource, ShouldCommunicateWithProcessSupervisor, \JsonSerializable
+{
+    use IdentifiesResource, CommunicatesWithProcessSupervisor;
+
+    /**
+     * Serialize the object to a value that can be serialized natively by {@see json_encode}.
+     */
+    public function jsonSerialize(): ResourceIdentity
+    {
+        return $this->getResourceIdentity();
+    }
+}

+ 124 - 0
node_modules/@nesk/rialto/src/Data/JsFunction.php

@@ -0,0 +1,124 @@
+<?php
+
+namespace Nesk\Rialto\Data;
+
+class JsFunction implements \JsonSerializable
+{
+    /**
+    * The parameters of the function.
+    *
+    * @var array
+    */
+    protected $parameters;
+
+    /**
+     * The body of the function.
+     *
+     * @var string
+     */
+    protected $body;
+
+    /**
+     * The scope of the function.
+     *
+     * @var array
+     */
+    protected $scope;
+
+    /**
+     * The async state of the function.
+     *
+     * @var bool
+     */
+    protected $async = false;
+
+    /**
+     * Create a new JS function.
+     *
+     * @deprecated 2.0.0 Chaining methods should be used instead.
+     */
+    public static function create(...$arguments)
+    {
+        trigger_error(__METHOD__.'() has been deprecated and will be removed from v2.', E_USER_DEPRECATED);
+
+        if (isset($arguments[0]) && is_string($arguments[0])) {
+            return new static([], $arguments[0], $arguments[1] ?? []);
+        }
+
+        return new static(...$arguments);
+    }
+
+    /**
+     * Constructor.
+     */
+    public function __construct(array $parameters = [], string $body = '', array $scope = [])
+    {
+        $this->parameters = $parameters;
+        $this->body = $body;
+        $this->scope = $scope;
+    }
+
+    /**
+     * Return a new instance with the specified parameters.
+     */
+    public function parameters(array $parameters): self {
+        $clone = clone $this;
+        $clone->parameters = $parameters;
+        return $clone;
+    }
+
+    /**
+     * Return a new instance with the specified body.
+     */
+    public function body(string $body): self {
+        $clone = clone $this;
+        $clone->body = $body;
+        return $clone;
+    }
+
+    /**
+     * Return a new instance with the specified scope.
+     */
+    public function scope(array $scope): self {
+        $clone = clone $this;
+        $clone->scope = $scope;
+        return $clone;
+    }
+
+    /**
+     * Return a new instance with the specified async state.
+     */
+    public function async(bool $isAsync = true): self {
+        $clone = clone $this;
+        $clone->async = $isAsync;
+        return $clone;
+    }
+
+    /**
+     * Serialize the object to a value that can be serialized natively by {@see json_encode}.
+     */
+    public function jsonSerialize(): array
+    {
+        return [
+            '__rialto_function__' => true,
+            'parameters' => (object) $this->parameters,
+            'body' => $this->body,
+            'scope' => (object) $this->scope,
+            'async' => $this->async,
+        ];
+    }
+
+    /**
+     * Proxy the "createWith*" static method calls to the "*" non-static method calls of a new instance.
+     */
+    public static function __callStatic(string $name, array $arguments)
+    {
+        $name = lcfirst(substr($name, strlen('createWith')));
+
+        if ($name === 'jsonSerialize') {
+            throw new BadMethodCallException;
+        }
+
+        return call_user_func([new self, $name], ...$arguments);
+    }
+}

+ 57 - 0
node_modules/@nesk/rialto/src/Data/ResourceIdentity.php

@@ -0,0 +1,57 @@
+<?php
+
+namespace Nesk\Rialto\Data;
+
+class ResourceIdentity implements \JsonSerializable
+{
+    /**
+     * The class name of the resource.
+     *
+     * @var string
+     */
+    protected $className;
+
+    /**
+     * The unique identifier of the resource.
+     *
+     * @var string
+     */
+    protected $uniqueIdentifier;
+
+    /**
+     * Constructor.
+     */
+    public function __construct(string $className, string $uniqueIdentifier)
+    {
+        $this->className = $className;
+        $this->uniqueIdentifier = $uniqueIdentifier;
+    }
+
+    /**
+     * Return the class name of the resource.
+     */
+    public function className(): string
+    {
+        return $this->className;
+    }
+
+    /**
+     * Return the unique identifier of the resource.
+     */
+    public function uniqueIdentifier(): string
+    {
+        return $this->uniqueIdentifier;
+    }
+
+    /**
+     * Serialize the object to a value that can be serialized natively by {@see json_encode}.
+     */
+    public function jsonSerialize(): array
+    {
+        return [
+            '__rialto_resource__' => true,
+            'class_name' => $this->className(),
+            'id' => $this->uniqueIdentifier(),
+        ];
+    }
+}

+ 47 - 0
node_modules/@nesk/rialto/src/Data/UnserializesData.php

@@ -0,0 +1,47 @@
+<?php
+
+namespace Nesk\Rialto\Data;
+
+use Nesk\Rialto\Exceptions\Node\Exception;
+use Nesk\Rialto\Interfaces\ShouldHandleProcessDelegation;
+use Nesk\Rialto\Interfaces\{ShouldIdentifyResource, ShouldCommunicateWithProcessSupervisor};
+
+trait UnserializesData
+{
+    /**
+     * Unserialize a value.
+     */
+    protected function unserialize($value)
+    {
+        if (!is_array($value)) {
+            return $value;
+        } else {
+            if (($value['__rialto_error__'] ?? false) === true) {
+                return new Exception($value, $this->options['debug']);
+            } else if (($value['__rialto_resource__'] ?? false) === true) {
+                if ($this->delegate instanceof ShouldHandleProcessDelegation) {
+                    $classPath = $this->delegate->resourceFromOriginalClassName($value['class_name'])
+                        ?: $this->delegate->defaultResource();
+                } else {
+                    $classPath = $this->defaultResource();
+                }
+
+                $resource = new $classPath;
+
+                if ($resource instanceof ShouldIdentifyResource) {
+                    $resource->setResourceIdentity(new ResourceIdentity($value['class_name'], $value['id']));
+                }
+
+                if ($resource instanceof ShouldCommunicateWithProcessSupervisor) {
+                    $resource->setProcessSupervisor($this);
+                }
+
+                return $resource;
+            } else {
+                return array_map(function ($value) {
+                    return $this->unserialize($value);
+                }, $value);
+            }
+        }
+    }
+}

+ 21 - 0
node_modules/@nesk/rialto/src/Exceptions/IdentifiesProcess.php

@@ -0,0 +1,21 @@
+<?php
+
+namespace Nesk\Rialto\Exceptions;
+
+trait IdentifiesProcess
+{
+    /**
+     * The associated process.
+     *
+     * @var \Symfony\Component\Process\Process
+     */
+    private $process;
+
+    /**
+     * Return the associated process.
+     */
+    public function getProcess(): Process
+    {
+        return $this->process;
+    }
+}

+ 35 - 0
node_modules/@nesk/rialto/src/Exceptions/IdleTimeoutException.php

@@ -0,0 +1,35 @@
+<?php
+
+namespace Nesk\Rialto\Exceptions;
+
+use Symfony\Component\Process\Process;
+
+class IdleTimeoutException extends \RuntimeException
+{
+    /**
+     * Check if the exception can be applied to the process.
+     */
+    public static function exceptionApplies(Process $process): bool
+    {
+        if (Node\FatalException::exceptionApplies($process)) {
+            $error = json_decode($process->getErrorOutput(), true);
+
+            return $error['message'] === 'The idle timeout has been reached.';
+        }
+
+        return false;
+    }
+
+    /**
+     * Constructor.
+     */
+    public function __construct(float $timeout, \Throwable $previous = null)
+    {
+        $timeout = number_format($timeout, 3);
+
+        parent::__construct(implode(' ', [
+            "The idle timeout ($timeout seconds) has been exceeded.",
+            'Maybe you should increase the "idle_timeout" option.',
+        ]), 0, $previous);
+    }
+}

+ 18 - 0
node_modules/@nesk/rialto/src/Exceptions/Node/Exception.php

@@ -0,0 +1,18 @@
+<?php
+
+namespace Nesk\Rialto\Exceptions\Node;
+
+class Exception extends \RuntimeException
+{
+    use HandlesNodeErrors;
+
+    /**
+     * Constructor.
+     */
+    public function __construct($error, bool $appendStackTraceToMessage = false)
+    {
+        $message = $this->setTraceAndGetMessage($error, $appendStackTraceToMessage);
+
+        parent::__construct($message);
+    }
+}

+ 31 - 0
node_modules/@nesk/rialto/src/Exceptions/Node/FatalException.php

@@ -0,0 +1,31 @@
+<?php
+
+namespace Nesk\Rialto\Exceptions\Node;
+
+use Symfony\Component\Process\Process;
+use Nesk\Rialto\Exceptions\IdentifiesProcess;
+
+class FatalException extends \RuntimeException
+{
+    use HandlesNodeErrors, IdentifiesProcess;
+
+    /**
+     * Check if the exception can be applied to the process.
+     */
+    public static function exceptionApplies(Process $process): bool
+    {
+        return static::isNodeError($process->getErrorOutput());
+    }
+
+    /**
+     * Constructor.
+     */
+    public function __construct(Process $process, bool $appendStackTraceToMessage = false)
+    {
+        $this->process = $process;
+
+        $message = $this->setTraceAndGetMessage($process->getErrorOutput(), $appendStackTraceToMessage);
+
+        parent::__construct($message);
+    }
+}

+ 49 - 0
node_modules/@nesk/rialto/src/Exceptions/Node/HandlesNodeErrors.php

@@ -0,0 +1,49 @@
+<?php
+
+namespace Nesk\Rialto\Exceptions\Node;
+
+trait HandlesNodeErrors
+{
+    /**
+     * The original stack trace.
+     *
+     * @var string|null
+     */
+    protected $originalTrace = null;
+
+    /**
+     * Determines if the string contains a Node error.
+     */
+    protected static function isNodeError(string $error): bool
+    {
+        $error = json_decode($error, true);
+
+        return ($error['__rialto_error__'] ?? false) === true;
+    }
+
+    /**
+     * Set the original trace and return the message.
+     */
+    protected function setTraceAndGetMessage($error, bool $appendStackTraceToMessage = false): string
+    {
+        $error = is_string($error) ? json_decode($error, true) : $error;
+
+        $this->originalTrace = $error['stack'] ?? null;
+
+        $message = $error['message'];
+
+        if ($appendStackTraceToMessage) {
+            $message .= "\n\n".$error['stack'];
+        }
+
+        return $message;
+    }
+
+    /**
+     * Return the original stack trace.
+     */
+    public function getOriginalTrace(): ?string
+    {
+        return $this->originalTrace;
+    }
+}

+ 20 - 0
node_modules/@nesk/rialto/src/Exceptions/ProcessUnexpectedlyTerminatedException.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace Nesk\Rialto\Exceptions;
+
+use Symfony\Component\Process\Process;
+
+class ProcessUnexpectedlyTerminatedException extends \RuntimeException
+{
+    use IdentifiesProcess;
+
+    /**
+     * Constructor.
+     */
+    public function __construct(Process $process)
+    {
+        parent::__construct('The process has been unexpectedly terminated.');
+
+        $this->process = $process;
+    }
+}

+ 19 - 0
node_modules/@nesk/rialto/src/Exceptions/ReadSocketTimeoutException.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace Nesk\Rialto\Exceptions;
+
+class ReadSocketTimeoutException extends \RuntimeException
+{
+    /**
+     * Constructor.
+     */
+    public function __construct(float $timeout, \Throwable $previous = null)
+    {
+        $timeout = number_format($timeout, 3);
+
+        parent::__construct(implode(' ', [
+            "The timeout ($timeout seconds) has been exceeded while reading the socket of the process.",
+            'Maybe you should increase the "read_timeout" option.',
+        ]), 0, $previous);
+    }
+}

+ 180 - 0
node_modules/@nesk/rialto/src/Instruction.php

@@ -0,0 +1,180 @@
+<?php
+
+namespace Nesk\Rialto;
+
+use BadMethodCallException;
+use InvalidArgumentException;
+use Nesk\Rialto\Interfaces\ShouldIdentifyResource;
+use Nesk\Rialto\Exceptions\Node\Exception as NodeException;
+
+class Instruction implements \JsonSerializable
+{
+    public const TYPE_CALL = 'call';
+    public const TYPE_GET = 'get';
+    public const TYPE_SET = 'set';
+    public const TYPE_NOOP = 'noop';
+
+    /**
+     * The instruction type.
+     *
+     * @var string
+     */
+    protected $type = self::TYPE_NOOP;
+
+    /**
+     * The name the instruction refers to.
+     *
+     * @var string|null
+     */
+    protected $name;
+
+    /**
+     * The value(s) the instruction should use.
+     *
+     * @var array[]|array|null
+     */
+    protected $value;
+
+    /**
+     * The resource associated to the instruction.
+     *
+     * @var \Nesk\Rialto\Traits\IdentifiesResource|null
+     */
+    protected $resource;
+
+    /**
+     * Define whether instruction errors should be catched.
+     *
+     * @var boolean
+     */
+    protected $shouldCatchErrors = false;
+
+    /**
+     * Create a no-op instruction.
+     */
+    public static function noop(): self
+    {
+        return new self;
+    }
+
+    /**
+     * Define a method call.
+     */
+    public function call(string $name, ...$arguments): self
+    {
+        $this->type = self::TYPE_CALL;
+        $this->name = $name;
+        $this->setValue($arguments, $this->type);
+
+        return $this;
+    }
+
+    /**
+     * Define a getter.
+     */
+    public function get(string $name): self
+    {
+        $this->type = self::TYPE_GET;
+        $this->name = $name;
+        $this->setValue(null, $this->type);
+
+        return $this;
+    }
+
+    /**
+     * Define a setter.
+     */
+    public function set(string $name, $value): self
+    {
+        $this->type = self::TYPE_SET;
+        $this->name = $name;
+        $this->setValue($value, $this->type);
+
+        return $this;
+    }
+
+    /**
+     * Link the instruction to the provided resource.
+     */
+    public function linkToResource(?ShouldIdentifyResource $resource): self
+    {
+        $this->resource = $resource;
+
+        return $this;
+    }
+
+    /**
+     * Define if instruction errors should be catched.
+     */
+    public function shouldCatchErrors(bool $catch): self
+    {
+        $this->shouldCatchErrors = $catch;
+
+        return $this;
+    }
+
+    /**
+     * Set the instruction value.
+     */
+    protected function setValue($value, string $type)
+    {
+        $this->value = $type !== self::TYPE_CALL
+            ? $this->validateValue($value)
+            : array_map(function ($value) {
+                return $this->validateValue($value);
+            }, $value);
+    }
+
+    /**
+     * Validate a value.
+     *
+     * @throws \InvalidArgumentException if the value contains PHP closures.
+     */
+    protected function validateValue($value)
+    {
+        if (is_object($value) && ($value instanceof Closure)) {
+            throw new InvalidArgumentException('You must use JS function wrappers instead of PHP closures.');
+        }
+
+        return $value;
+    }
+
+    /**
+     * Serialize the object to a value that can be serialized natively by {@see json_encode}.
+     */
+    public function jsonSerialize(): array
+    {
+        $instruction = ['type' => $this->type];
+
+        if ($this->type !== self::TYPE_NOOP) {
+            $instruction = array_merge($instruction, [
+                'name' => $this->name,
+                'catched' => $this->shouldCatchErrors,
+            ]);
+
+            if ($this->type !== self::TYPE_GET) {
+                $instruction['value'] = $this->value;
+            }
+
+            if ($this->resource !== null) {
+                $instruction['resource'] = $this->resource;
+            }
+        }
+
+        return $instruction;
+    }
+
+    /**
+     * Proxy the "with*" static method calls to the "*" non-static method calls of a new instance.
+     */
+    public static function __callStatic(string $name, array $arguments)
+    {
+        $name = lcfirst(substr($name, strlen('with')));
+
+        if ($name === 'jsonSerialize') {
+            throw new BadMethodCallException;
+        }
+
+        return call_user_func([new self, $name], ...$arguments);
+    }
+}

+ 15 - 0
node_modules/@nesk/rialto/src/Interfaces/ShouldCommunicateWithProcessSupervisor.php

@@ -0,0 +1,15 @@
+<?php
+
+namespace Nesk\Rialto\Interfaces;
+
+use Nesk\Rialto\ProcessSupervisor;
+
+interface ShouldCommunicateWithProcessSupervisor
+{
+    /**
+     * Set the process supervisor.
+     *
+     * @throws \RuntimeException if the process has already been set.
+     */
+    public function setProcessSupervisor(ProcessSupervisor $process): void;
+}

+ 16 - 0
node_modules/@nesk/rialto/src/Interfaces/ShouldHandleProcessDelegation.php

@@ -0,0 +1,16 @@
+<?php
+
+namespace Nesk\Rialto\Interfaces;
+
+interface ShouldHandleProcessDelegation
+{
+    /**
+     * Return the fully qualified name of the default resource.
+     */
+    public function defaultResource(): string;
+
+    /**
+     * Return the fully qualified name of a resource based on the original class name.
+     */
+    public function resourceFromOriginalClassName(string $className): ?string;
+}

+ 20 - 0
node_modules/@nesk/rialto/src/Interfaces/ShouldIdentifyResource.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace Nesk\Rialto\Interfaces;
+
+use Nesk\Rialto\Data\ResourceIdentity;
+
+interface ShouldIdentifyResource
+{
+    /**
+     * Return the identity of the resource.
+     */
+    public function getResourceIdentity(): ?ResourceIdentity;
+
+    /**
+     * Set the identity of the resource.
+     *
+     * @throws \RuntimeException if the resource identity has already been set.
+     */
+    public function setResourceIdentity(ResourceIdentity $identity): void;
+}

+ 125 - 0
node_modules/@nesk/rialto/src/Logger.php

@@ -0,0 +1,125 @@
+<?php
+
+namespace Nesk\Rialto;
+
+use Symfony\Component\Process\Process;
+use Psr\Log\{LoggerInterface, LogLevel};
+
+class Logger implements LoggerInterface
+{
+    /**
+     * The original logger.
+     *
+     * @var \Psr\Log\LoggerInterface
+     */
+    protected $logger;
+
+    /**
+     * Constructor.
+     */
+    public function __construct(?LoggerInterface $logger) {
+        $this->logger = $logger;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @param string $message
+     */
+    public function emergency($message, array $context = []): void {
+        $this->log(LogLevel::EMERGENCY, $message, $context);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @param string $message
+     */
+    public function alert($message, array $context = []): void {
+        $this->log(LogLevel::ALERT, $message, $context);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @param string $message
+     */
+    public function critical($message, array $context = []): void {
+        $this->log(LogLevel::CRITICAL, $message, $context);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @param string $message
+     */
+    public function error($message, array $context = []): void {
+        $this->log(LogLevel::ERROR, $message, $context);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @param string $message
+     */
+    public function warning($message, array $context = []): void {
+        $this->log(LogLevel::WARNING, $message, $context);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @param string $message
+     */
+    public function notice($message, array $context = []): void {
+        $this->log(LogLevel::NOTICE, $message, $context);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @param string $message
+     */
+    public function info($message, array $context = []): void {
+        $this->log(LogLevel::INFO, $message, $context);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @param string $message
+     */
+    public function debug($message, array $context = []): void {
+        $this->log(LogLevel::DEBUG, $message, $context);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @param mixed $level
+     * @param string $message
+     */
+    public function log($level, $message, array $context = []): void {
+        if ($this->logger instanceof LoggerInterface) {
+            $message = $this->interpolate($message, $context);
+            $this->logger->log($level, $message, $context);
+        }
+    }
+
+    /**
+     * Interpolate context values into the message placeholders.
+     *
+     * @see https://www.php-fig.org/psr/psr-3/#12-message
+     */
+    protected function interpolate(string $message, array $context = []): string {
+        $replace = array();
+
+        foreach ($context as $key => $val) {
+            if (!is_array($val) && (!is_object($val) || method_exists($val, '__toString'))) {
+                $replace['{' . $key . '}'] = $val;
+            }
+        }
+
+        return strtr($message, $replace);
+    }
+}

+ 469 - 0
node_modules/@nesk/rialto/src/ProcessSupervisor.php

@@ -0,0 +1,469 @@
+<?php
+
+namespace Nesk\Rialto;
+
+use Psr\Log\LogLevel;
+use RuntimeException;
+use Socket\Raw\Socket;
+use Socket\Raw\Factory as SocketFactory;
+use Socket\Raw\Exception as SocketException;
+use Nesk\Rialto\Exceptions\IdleTimeoutException;
+use Symfony\Component\Process\Process as SymfonyProcess;
+use Symfony\Component\Process\Exception\ProcessFailedException;
+use Nesk\Rialto\Interfaces\ShouldHandleProcessDelegation;
+use Nesk\Rialto\Exceptions\Node\Exception as NodeException;
+use Nesk\Rialto\Exceptions\Node\FatalException as NodeFatalException;
+
+class ProcessSupervisor
+{
+    use Data\UnserializesData, Traits\UsesBasicResourceAsDefault;
+
+    /**
+     * A reasonable delay to let the process terminate itself (in milliseconds).
+     *
+     * @var int
+     */
+    protected const PROCESS_TERMINATION_DELAY = 100;
+
+    /**
+     * The size of a packet sent through the sockets (in bytes).
+     *
+     * @var int
+     */
+    protected const SOCKET_PACKET_SIZE = 1024;
+
+    /**
+     * The size of the header in each packet sent through the sockets (in bytes).
+     *
+     * @var int
+     */
+    protected const SOCKET_HEADER_SIZE = 5;
+
+    /**
+     * A short period to wait before reading the next chunk (in milliseconds), this avoids the next chunk to be read as
+     * an empty string when PuPHPeteer is running on a slow environment.
+     *
+     * @var int
+     */
+    protected const SOCKET_NEXT_CHUNK_DELAY = 1;
+
+    /**
+     * Options to remove before sending them for the process.
+     *
+     * @var string[]
+     */
+    protected const USELESS_OPTIONS_FOR_PROCESS = [
+        'executable_path', 'read_timeout', 'stop_timeout', 'logger', 'debug',
+    ];
+
+    /**
+     * The associative array containing the options.
+     *
+     * @var array
+     */
+    protected $options = [
+        // Node's executable path
+        'executable_path' => 'node',
+
+        // How much time (in seconds) the process can stay inactive before being killed (set to null to disable)
+        'idle_timeout' => 60,
+
+        // How much time (in seconds) an instruction can take to return a value (set to null to disable)
+        'read_timeout' => 30,
+
+        // How much time (in seconds) the process can take to shutdown properly before being killed
+        'stop_timeout' => 3,
+
+        // A logger instance for debugging (must implement \Psr\Log\LoggerInterface)
+        'logger' => null,
+
+        // Logs the output of console methods (console.log, console.debug, console.table, etc...) to the PHP logger
+        'log_node_console' => false,
+
+        // Enables debugging mode:
+        //   - adds the --inspect flag to Node's command
+        //   - appends stack traces to Node exception messages
+        'debug' => false,
+    ];
+
+    /**
+     * The running process.
+     *
+     * @var \Symfony\Component\Process\Process
+     */
+    protected $process;
+
+    /**
+     * The PID of the running process.
+     *
+     * @var int
+     */
+    protected $processPid;
+
+    /**
+     * The process delegate.
+     *
+     * @var \Nesk\Rialto\ShouldHandleProcessDelegation;
+     */
+    protected $delegate;
+
+    /**
+     * The client to communicate with the process.
+     *
+     * @var \Socket\Raw\Socket
+     */
+    protected $client;
+
+    /**
+     * The server port.
+     *
+     * @var int
+     */
+    protected $serverPort;
+
+    /**
+     * The logger instance.
+     *
+     * @var \Psr\Log\LoggerInterface
+     */
+    protected $logger;
+
+    /**
+     * Constructor.
+     */
+    public function __construct(
+        string $connectionDelegatePath,
+        ?ShouldHandleProcessDelegation $processDelegate = null,
+        array $options = []
+    ) {
+        $this->logger = new Logger($options['logger'] ?? null);
+
+        $this->applyOptions($options);
+
+        $this->process = $this->createNewProcess($connectionDelegatePath);
+
+        $this->processPid = $this->startProcess($this->process);
+
+        $this->delegate = $processDelegate;
+
+        $this->client = $this->createNewClient($this->serverPort());
+
+        if ($this->options['debug']) {
+            // Clear error output made by the "--inspect" flag
+            $this->process->clearErrorOutput();
+        }
+    }
+
+    /**
+     * Destructor.
+     */
+    public function __destruct()
+    {
+        $logContext = ['pid' => $this->processPid];
+
+        $this->waitForProcessTermination();
+
+        if ($this->process->isRunning()) {
+            $this->executeInstruction(Instruction::noop(), false); // Fetch the missing remote logs
+
+            $this->logger->info('Stopping process with PID {pid}...', $logContext);
+            $this->process->stop($this->options['stop_timeout']);
+            $this->logger->info('Stopped process with PID {pid}', $logContext);
+        } else {
+            $this->logger->warning("The process cannot because be stopped because it's no longer running", $logContext);
+        }
+    }
+
+    /**
+     * Log data from the process standard streams.
+     */
+    protected function logProcessStandardStreams(): void
+    {
+        if (!empty($output = $this->process->getIncrementalOutput())) {
+            $this->logger->notice('Received data on stdout: {output}', [
+                'pid' => $this->processPid,
+                'stream' => 'stdout',
+                'output' => $output,
+            ]);
+        }
+
+        if (!empty($errorOutput = $this->process->getIncrementalErrorOutput())) {
+            $this->logger->error('Received data on stderr: {output}', [
+                'pid' => $this->processPid,
+                'stream' => 'stderr',
+                'output' => $errorOutput,
+            ]);
+        }
+    }
+
+    /**
+     * Apply the options.
+     */
+    protected function applyOptions(array $options): void
+    {
+        $this->logger->info('Applying options...', ['options' => $options]);
+
+        $this->options = array_merge($this->options, $options);
+
+        $this->logger->debug('Options applied and merged with defaults', ['options' => $this->options]);
+    }
+
+    /**
+     * Return the script path of the Node process.
+     *
+     * In production, the script path must target the NPM package. In local development, the script path targets the
+     * Composer package (since the NPM package is not installed).
+     *
+     * This avoids double declarations of some JS classes in production, due to a require with two different paths (one
+     * with the NPM path, the other one with the Composer path).
+     */
+    protected function getProcessScriptPath(): string {
+        static $scriptPath = null;
+
+        if ($scriptPath !== null) {
+            return $scriptPath;
+        }
+
+        // The script path in local development
+        $scriptPath = __DIR__.'/node-process/serve.js';
+
+        $process = new SymfonyProcess([
+            $this->options['executable_path'],
+            '-e',
+            "process.stdout.write(require.resolve('@nesk/rialto/src/node-process/serve.js'))",
+        ]);
+
+        $exitCode = $process->run();
+
+        if ($exitCode === 0) {
+            // The script path in production
+            $scriptPath = $process->getOutput();
+        }
+
+        return $scriptPath;
+    }
+
+    /**
+     * Create a new Node process.
+     *
+     * @throws RuntimeException if the path to the connection delegate cannot be found.
+     */
+    protected function createNewProcess(string $connectionDelegatePath): SymfonyProcess
+    {
+        $realConnectionDelegatePath = realpath($connectionDelegatePath);
+
+        if ($realConnectionDelegatePath === false) {
+            throw new RuntimeException("Cannot find file or directory '$connectionDelegatePath'.");
+        }
+
+        // Remove useless options for the process
+        $processOptions = array_diff_key($this->options, array_flip(self::USELESS_OPTIONS_FOR_PROCESS));
+
+        return new SymfonyProcess(array_merge(
+            [$this->options['executable_path']],
+            $this->options['debug'] ? ['--inspect'] : [],
+            [$this->getProcessScriptPath()],
+            [$realConnectionDelegatePath],
+            [json_encode((object) $processOptions)]
+        ));
+    }
+
+    /**
+     * Start the Node process.
+     */
+    protected function startProcess(SymfonyProcess $process): int
+    {
+        $this->logger->info('Starting process with command line: {commandline}', [
+            'commandline' => $process->getCommandLine(),
+        ]);
+
+        $process->start();
+
+        $pid = $process->getPid();
+
+        $this->logger->info('Process started with PID {pid}', ['pid' => $pid]);
+
+        return $pid;
+    }
+
+    /**
+     * Check if the process is still running without errors.
+     *
+     * @throws \Symfony\Component\Process\Exception\ProcessFailedException
+     */
+    protected function checkProcessStatus(): void
+    {
+        $this->logProcessStandardStreams();
+
+        $process = $this->process;
+
+        if (!empty($process->getErrorOutput())) {
+            if (IdleTimeoutException::exceptionApplies($process)) {
+                throw new IdleTimeoutException(
+                    $this->options['idle_timeout'],
+                    new NodeFatalException($process, $this->options['debug'])
+                );
+            } else if (NodeFatalException::exceptionApplies($process)) {
+                throw new NodeFatalException($process, $this->options['debug']);
+            } elseif ($process->isTerminated() && !$process->isSuccessful()) {
+                throw new ProcessFailedException($process);
+            }
+        }
+
+        if ($process->isTerminated()) {
+            throw new Exceptions\ProcessUnexpectedlyTerminatedException($process);
+        }
+    }
+
+    /**
+     * Wait for process termination.
+     *
+     * The process might take a while to stop itself. So, before trying to check its status or reading its standard
+     * streams, this method should be executed.
+     */
+    protected function waitForProcessTermination(): void {
+        usleep(self::PROCESS_TERMINATION_DELAY * 1000);
+    }
+
+    /**
+     * Return the port of the server.
+     */
+    protected function serverPort(): int
+    {
+        if ($this->serverPort !== null) {
+            return $this->serverPort;
+        }
+
+        $iterator = $this->process->getIterator(SymfonyProcess::ITER_SKIP_ERR | SymfonyProcess::ITER_KEEP_OUTPUT);
+
+        foreach ($iterator as $data) {
+            return $this->serverPort = (int) $data;
+        }
+
+        // If the iterator didn't execute properly, then the process must have failed, we must check to be sure.
+        $this->checkProcessStatus();
+    }
+
+    /**
+     * Create a new client to communicate with the process.
+     */
+    protected function createNewClient(int $port): Socket
+    {
+        // Set the client as non-blocking to handle the exceptions thrown by the process
+        return (new SocketFactory)
+            ->createClient("tcp://127.0.0.1:$port")
+            ->setBlocking(false);
+    }
+
+    /**
+     * Send an instruction to the process for execution.
+     */
+    public function executeInstruction(Instruction $instruction, bool $instructionShouldBeLogged = true)
+    {
+        // Check the process status because it could have crash in idle status.
+        $this->checkProcessStatus();
+
+        $serializedInstruction = json_encode($instruction);
+
+        if ($instructionShouldBeLogged) {
+            $this->logger->debug('Sending an instruction to the port {port}...', [
+                'pid' => $this->processPid,
+                'port' => $this->serverPort(),
+
+                // The instruction must be fully encoded and decoded to appear properly in the logs (this way,
+                // JS functions and resources are serialized too).
+                'instruction' => json_decode($serializedInstruction, true),
+            ]);
+        }
+
+        $this->client->selectWrite(1);
+        $this->client->write($serializedInstruction);
+
+        $value = $this->readNextProcessValue($instructionShouldBeLogged);
+
+        // Check the process status if the value is null because, if the process crash while executing the instruction,
+        // the socket closes and returns an empty value (which is converted to `null`).
+        if ($value === null) {
+            $this->checkProcessStatus();
+        }
+
+        return $value;
+    }
+
+    /**
+     * Read the next value written by the process.
+     *
+     * @throws \Nesk\Rialto\Exceptions\ReadSocketTimeoutException if reading the socket exceeded the timeout.
+     * @throws \Nesk\Rialto\Exceptions\Node\Exception if the process returned an error.
+     */
+    protected function readNextProcessValue(bool $valueShouldBeLogged = true)
+    {
+        $readTimeout = $this->options['read_timeout'];
+        $payload = '';
+
+        try {
+            $startTimestamp = microtime(true);
+
+            do {
+                $this->client->selectRead($readTimeout);
+                $packet = $this->client->read(static::SOCKET_PACKET_SIZE);
+
+                $chunksLeft = (int) substr($packet, 0, static::SOCKET_HEADER_SIZE);
+                $chunk = substr($packet, static::SOCKET_HEADER_SIZE);
+
+                $payload .= $chunk;
+
+                if ($chunksLeft > 0) {
+                    // The next chunk might be an empty string if don't wait a short period on slow environments.
+                    usleep(self::SOCKET_NEXT_CHUNK_DELAY * 1000);
+                }
+            } while ($chunksLeft > 0);
+        } catch (SocketException $exception) {
+            $this->waitForProcessTermination();
+            $this->checkProcessStatus();
+
+            // Extract the socket error code to throw more specific exceptions
+            preg_match('/\(([A-Z_]+?)\)$/', $exception->getMessage(), $socketErrorMatches);
+            $socketErrorCode = constant($socketErrorMatches[1]);
+
+            $elapsedTime = microtime(true) - $startTimestamp;
+            if ($socketErrorCode === SOCKET_EAGAIN && $readTimeout !== null && $elapsedTime >= $readTimeout) {
+                throw new Exceptions\ReadSocketTimeoutException($readTimeout, $exception);
+            }
+
+            throw $exception;
+        }
+
+        $this->logProcessStandardStreams();
+
+        ['logs' => $logs, 'value' => $value] = json_decode(base64_decode($payload), true);
+
+        foreach ($logs ?: [] as $log) {
+            $level = (new \ReflectionClass(LogLevel::class))->getConstant($log['level']);
+            $messageContainsLineBreaks = strstr($log['message'], PHP_EOL) !== false;
+            $formattedMessage = $messageContainsLineBreaks ? "\n{log}\n" : '{log}';
+
+            $this->logger->log($level, "Received a $log[origin] log: $formattedMessage", [
+                'pid' => $this->processPid,
+                'port' => $this->serverPort(),
+                'log' => $log['message'],
+            ]);
+        }
+
+        $value = $this->unserialize($value);
+
+        if ($valueShouldBeLogged) {
+            $this->logger->debug('Received data from the port {port}...', [
+                'pid' => $this->processPid,
+                'port' => $this->serverPort(),
+                'data' => $value,
+            ]);
+        }
+
+        if ($value instanceof NodeException) {
+            throw $value;
+        }
+
+        return $value;
+    }
+}

+ 122 - 0
node_modules/@nesk/rialto/src/Traits/CommunicatesWithProcessSupervisor.php

@@ -0,0 +1,122 @@
+<?php
+
+namespace Nesk\Rialto\Traits;
+
+use Nesk\Rialto\{Instruction, ProcessSupervisor};
+use Nesk\Rialto\Interfaces\ShouldIdentifyResource;
+
+trait CommunicatesWithProcessSupervisor
+{
+    /**
+     * The process supervisor to communicate with.
+     *
+     * @var \Nesk\Rialto\ProcessSupervisor
+     */
+    protected $processSupervisor;
+
+    /**
+     * Whether the current resource should catch instruction errors.
+     *
+     * @var boolean
+     */
+    protected $catchInstructionErrors = false;
+
+    /**
+    * Get the process supervisor.
+    */
+    protected function getProcessSupervisor(): ProcessSupervisor
+    {
+        return $this->processSupervisor;
+    }
+
+    /**
+     * Set the process supervisor.
+     *
+     * @throws \RuntimeException if the process supervisor has already been set.
+     */
+    public function setProcessSupervisor(ProcessSupervisor $processSupervisor): void
+    {
+        if ($this->processSupervisor !== null) {
+            throw new RuntimeException('The process supervisor has already been set.');
+        }
+
+        $this->processSupervisor = $processSupervisor;
+    }
+
+    /**
+     * Clone the resource and catch its instruction errors.
+     */
+    protected function createCatchingResource()
+    {
+        $resource = clone $this;
+
+        $resource->catchInstructionErrors = true;
+
+        return $resource;
+    }
+
+    /**
+     * Proxy an action.
+     */
+    protected function proxyAction(string $actionType, string $name, $value = null)
+    {
+        switch ($actionType) {
+            case Instruction::TYPE_CALL:
+                $value = $value ?? [];
+                $instruction = Instruction::withCall($name, ...$value);
+                break;
+            case Instruction::TYPE_GET:
+                $instruction = Instruction::withGet($name);
+                break;
+            case Instruction::TYPE_SET:
+                $instruction = Instruction::withSet($name, $value);
+                break;
+        }
+
+        $identifiesResource = $this instanceof ShouldIdentifyResource;
+
+        $instruction->linkToResource($identifiesResource ? $this : null);
+
+        if ($this->catchInstructionErrors) {
+            $instruction->shouldCatchErrors(true);
+        }
+
+        return $this->getProcessSupervisor()->executeInstruction($instruction);
+    }
+
+    /**
+     * Proxy the string casting to the process supervisor.
+     */
+    public function __toString(): string
+    {
+        return $this->proxyAction(Instruction::TYPE_CALL, 'toString');
+    }
+
+    /**
+     * Proxy the method call to the process supervisor.
+     */
+    public function __call(string $name, array $arguments)
+    {
+        return $this->proxyAction(Instruction::TYPE_CALL, $name, $arguments);
+    }
+
+    /**
+     * Proxy the property reading to the process supervisor.
+     */
+    public function __get(string $name)
+    {
+        if ($name === 'tryCatch' && !$this->catchInstructionErrors) {
+            return $this->createCatchingResource();
+        }
+
+        return $this->proxyAction(Instruction::TYPE_GET, $name);
+    }
+
+    /**
+     * Proxy the property writing to the process supervisor.
+     */
+    public function __set(string $name, $value)
+    {
+        return $this->proxyAction(Instruction::TYPE_SET, $name, $value);
+    }
+}

+ 38 - 0
node_modules/@nesk/rialto/src/Traits/IdentifiesResource.php

@@ -0,0 +1,38 @@
+<?php
+
+namespace Nesk\Rialto\Traits;
+
+use RuntimeException;
+use Nesk\Rialto\Data\ResourceIdentity;
+
+trait IdentifiesResource
+{
+    /**
+     * The identity of the resource.
+     *
+     * @var \Nesk\Rialto\ResourceIdentity
+     */
+    protected $resourceIdentity;
+
+    /**
+     * Return the identity of the resource.
+     */
+    public function getResourceIdentity(): ?ResourceIdentity
+    {
+        return $this->resourceIdentity;
+    }
+
+    /**
+     * Set the identity of the resource.
+     *
+     * @throws \RuntimeException if the resource identity has already been set.
+     */
+    public function setResourceIdentity(ResourceIdentity $identity): void
+    {
+        if ($this->resourceIdentity !== null) {
+            throw new RuntimeException('The resource identity has already been set.');
+        }
+
+        $this->resourceIdentity = $identity;
+    }
+}

+ 14 - 0
node_modules/@nesk/rialto/src/Traits/UsesBasicResourceAsDefault.php

@@ -0,0 +1,14 @@
+<?php
+
+namespace Nesk\Rialto\Traits;
+
+trait UsesBasicResourceAsDefault
+{
+    /**
+     * Return the fully qualified name of the default resource.
+     */
+    public function defaultResource(): string
+    {
+        return \Nesk\Rialto\Data\BasicResource::class;
+    }
+}

+ 157 - 0
node_modules/@nesk/rialto/src/node-process/Connection.js

@@ -0,0 +1,157 @@
+'use strict';
+
+const EventEmitter = require('events'),
+    ConnectionDelegate = require('./ConnectionDelegate'),
+    ResourceRepository = require('./Data/ResourceRepository'),
+    Instruction = require('./Instruction'),
+    DataSerializer = require('./Data/Serializer'),
+    DataUnserializer = require('./Data/Unserializer'),
+    Logger = require('./Logger');
+
+/**
+ * Handle a connection interacting with this process.
+ */
+class Connection extends EventEmitter
+{
+    /**
+     * Constructor.
+     *
+     * @param  {net.Socket} socket
+     * @param  {ConnectionDelegate} delegate
+     */
+    constructor(socket, delegate)
+    {
+        super();
+
+        this.socket = this.configureSocket(socket);
+
+        this.delegate = delegate;
+
+        this.resources = new ResourceRepository;
+
+        this.dataSerializer = new DataSerializer(this.resources);
+        this.dataUnserializer = new DataUnserializer(this.resources);
+    }
+
+    /**
+     * Configure the socket for communication.
+     *
+     * @param  {net.Socket} socket
+     * @return {net.Socket}
+     */
+    configureSocket(socket)
+    {
+        socket.setEncoding('utf8');
+
+        socket.on('data', data => {
+            this.emit('activity');
+
+            this.handleSocketData(data);
+        });
+
+        return socket;
+    }
+
+    /**
+     * Handle data received on the socket.
+     *
+     * @param  {string} data
+     */
+    handleSocketData(data)
+    {
+        const instruction = new Instruction(JSON.parse(data), this.resources, this.dataUnserializer),
+            {responseHandler, errorHandler} = this.createInstructionHandlers();
+
+        this.delegate.handleInstruction(instruction, responseHandler, errorHandler);
+    }
+
+    /**
+     * Generate response and errors handlers.
+     *
+     * @return {Object}
+     */
+    createInstructionHandlers()
+    {
+        let handlerHasBeenCalled = false;
+
+        const handler = (serializingMethod, value) => {
+            if (handlerHasBeenCalled) {
+                throw new Error('You can call only once the response/error handler.');
+            }
+
+            handlerHasBeenCalled = true;
+
+            this.writeToSocket(JSON.stringify({
+                logs: Logger.logs(),
+                value: this[serializingMethod](value),
+            }));
+        };
+
+        return {
+            responseHandler: handler.bind(this, 'serializeValue'),
+            errorHandler: handler.bind(this, 'serializeError'),
+        };
+    }
+
+    /**
+     * Write a string to the socket by slitting it in packets of fixed length.
+     *
+     * @param  {string} str
+     */
+    writeToSocket(str)
+    {
+        const payload = Buffer.from(str).toString('base64');
+
+        const bodySize = Connection.SOCKET_PACKET_SIZE - Connection.SOCKET_HEADER_SIZE,
+            chunkCount = Math.ceil(payload.length / bodySize);
+
+        for (let i = 0 ; i < chunkCount ; i++) {
+            const chunk = payload.substr(i * bodySize, bodySize);
+
+            let chunksLeft = String(chunkCount - 1 - i);
+            chunksLeft = chunksLeft.padStart(Connection.SOCKET_HEADER_SIZE - 1, '0');
+
+            this.socket.write(`${chunksLeft}:${chunk}`);
+        }
+    }
+
+    /**
+     * Serialize a value to return to the client.
+     *
+     * @param  {*} value
+     * @return {Object}
+     */
+    serializeValue(value)
+    {
+        return this.dataSerializer.serialize(value);
+    }
+
+    /**
+     * Serialize an error to return to the client.
+     *
+     * @param  {Error} error
+     * @return {Object}
+     */
+    serializeError(error)
+    {
+        return DataSerializer.serializeError(error);
+    }
+}
+
+/**
+ * The size of a packet sent through the sockets.
+ *
+ * @constant
+ * @type {number}
+*/
+Connection.SOCKET_PACKET_SIZE = 1024;
+
+/**
+ * The size of the header in each packet sent through the sockets.
+ *
+ * @constant
+ * @type {number}
+ */
+Connection.SOCKET_HEADER_SIZE = 5;
+
+module.exports = Connection;

+ 41 - 0
node_modules/@nesk/rialto/src/node-process/ConnectionDelegate.js

@@ -0,0 +1,41 @@
+'use strict';
+
+/**
+ * @callback responseHandler
+ * @param  {*} value
+ */
+
+/**
+ * @callback errorHandler
+ * @param  {Error} error
+ */
+
+/**
+ * Handle the requests of a connection.
+ */
+class ConnectionDelegate
+{
+    /**
+     * Constructor.
+     *
+     * @param  {Object} options
+     */
+    constructor(options)
+    {
+        this.options = options;
+    }
+
+    /**
+     * Handle the provided instruction and respond to it.
+     *
+     * @param  {Instruction} instruction
+     * @param  {responseHandler} responseHandler
+     * @param  {errorHandler} errorHandler
+     */
+    handleInstruction(instruction, responseHandler, errorHandler)
+    {
+        responseHandler(null);
+    }
+}
+
+module.exports = ConnectionDelegate;

+ 62 - 0
node_modules/@nesk/rialto/src/node-process/Data/ResourceIdentity.js

@@ -0,0 +1,62 @@
+'use strict';
+
+class ResourceIdentity
+{
+    /**
+     * Constructor.
+     *
+     * @param  {string} uniqueIdentifier
+     * @param  {string|null} className
+     */
+    constructor(uniqueIdentifier, className = null)
+    {
+        this.resource = {uniqueIdentifier, className};
+    }
+
+    /**
+     * Return the unique identifier of the resource.
+     *
+     * @return {string}
+     */
+    uniqueIdentifier()
+    {
+        return this.resource.uniqueIdentifier;
+    }
+
+    /**
+     * Return the class name of the resource.
+     *
+     * @return {string|null}
+     */
+    className()
+    {
+        return this.resource.className;
+    }
+
+    /**
+     * Unserialize a resource identity.
+     *
+     * @param  {Object} identity
+     * @return {ResourceIdentity}
+     */
+    static unserialize(identity)
+    {
+        return new ResourceIdentity(identity.id, identity.class_name);
+    }
+
+    /**
+     * Serialize the resource identity.
+     *
+     * @return {Object}
+     */
+    serialize()
+    {
+        return {
+            __rialto_resource__: true,
+            id: this.uniqueIdentifier(),
+            class_name: this.className(),
+        };
+    }
+}
+
+module.exports = ResourceIdentity;

+ 113 - 0
node_modules/@nesk/rialto/src/node-process/Data/ResourceRepository.js

@@ -0,0 +1,113 @@
+'use strict';
+
+const ResourceIdentity = require('./ResourceIdentity');
+
+class ResourceRepository
+{
+    /**
+     * Constructor.
+     */
+    constructor()
+    {
+        this.resources = new Map;
+    }
+
+    /**
+     * Retrieve a resource with its identity from a specific storage.
+     *
+     * @param  {Map} storage
+     * @param  {ResourceIdentity} identity
+     * @return {*}
+     */
+    static retrieveFrom(storage, identity)
+    {
+        for (let [resource, id] of storage) {
+            if (identity.uniqueIdentifier() === id) {
+                return resource;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Retrieve a resource with its identity from the local storage.
+     *
+     * @param  {ResourceIdentity} identity
+     * @return {*}
+     */
+    retrieve(identity)
+    {
+        return ResourceRepository.retrieveFrom(this.resources, identity);
+    }
+
+    /**
+     * Retrieve a resource with its unique identifier from the global storage.
+     *
+     * @param  {string} uniqueIdentifier
+     * @return {*}
+     */
+    static retrieveGlobal(uniqueIdentifier)
+    {
+        const identity = new ResourceIdentity(uniqueIdentifier);
+        return ResourceRepository.retrieveFrom(ResourceRepository.globalResources, identity);
+    }
+
+    /**
+     * Store a resource in a specific storage and return its identity.
+     *
+     * @param  {Map} storage
+     * @param  {*} resource
+     * @return {ResourceIdentity}
+     */
+    static storeIn(storage, resource)
+    {
+        if (storage.has(resource)) {
+            return ResourceRepository.generateResourceIdentity(resource, storage.get(resource));
+        }
+
+        const id = String(Date.now() + Math.random());
+
+        storage.set(resource, id);
+
+        return ResourceRepository.generateResourceIdentity(resource, id);
+    }
+
+    /**
+     * Store a resource in the local storage and return its identity.
+     *
+     * @param  {*} resource
+     * @return {ResourceIdentity}
+     */
+    store(resource)
+    {
+        return ResourceRepository.storeIn(this.resources, resource);
+    }
+
+    /**
+     * Store a resource in the global storage and return its unique identifier.
+     *
+     * @param  {*} resource
+     * @return {string}
+     */
+    static storeGlobal(resource)
+    {
+        return ResourceRepository.storeIn(ResourceRepository.globalResources, resource).uniqueIdentifier();
+    }
+
+    /**
+     * Generate a resource identity.
+     *
+     * @param  {*} resource
+     * @param  {string} uniqueIdentifier
+     * @return {ResourceIdentity}
+     */
+    static generateResourceIdentity(resource, uniqueIdentifier)
+    {
+        return new ResourceIdentity(uniqueIdentifier, resource.constructor.name);
+    }
+}
+
+ResourceRepository.globalResources = new Map;
+
+module.exports = ResourceRepository;

+ 52 - 0
node_modules/@nesk/rialto/src/node-process/Data/Serializer.js

@@ -0,0 +1,52 @@
+'use strict';
+
+const Value = require('./Value');
+
+class Serializer
+{
+    /**
+     * Serialize an error to JSON.
+     *
+     * @param  {Error} error
+     * @return {Object}
+     */
+    static serializeError(error)
+    {
+        return {
+            __rialto_error__: true,
+            message: error.message,
+            stack: error.stack,
+        };
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param  {ResourceRepository} resources
+     */
+    constructor(resources)
+    {
+        this.resources = resources;
+    }
+
+    /**
+     * Serialize a value.
+     *
+     * @param  {*} value
+     * @return {*}
+     */
+    serialize(value)
+    {
+        value = value === undefined ? null : value;
+
+        if (Value.isContainer(value)) {
+            return Value.mapContainer(value, this.serialize.bind(this));
+        } else if (Value.isScalar(value)) {
+            return value;
+        } else {
+            return this.resources.store(value).serialize();
+        }
+    }
+}
+
+module.exports = Serializer;

+ 98 - 0
node_modules/@nesk/rialto/src/node-process/Data/Unserializer.js

@@ -0,0 +1,98 @@
+'use strict';
+
+const _ = require('lodash'),
+    Value = require('./Value'),
+    ResourceIdentity = require('./ResourceIdentity'),
+    ResourceRepository = require('./ResourceRepository');
+
+// Some unserialized functions require an access to the ResourceRepository class, so we must put it in the global scope.
+global.__rialto_ResourceRepository__ = ResourceRepository;
+
+class Unserializer
+{
+    /**
+     * Constructor.
+     *
+     * @param  {ResourceRepository} resources
+     */
+    constructor(resources)
+    {
+        this.resources = resources;
+    }
+
+    /**
+     * Unserialize a value.
+     *
+     * @param  {*} value
+     * @return {*}
+     */
+    unserialize(value)
+    {
+        if (_.get(value, '__rialto_resource__') === true) {
+            return this.resources.retrieve(ResourceIdentity.unserialize(value));
+        } else if (_.get(value, '__rialto_function__') === true) {
+            return this.unserializeFunction(value);
+        } else if (Value.isContainer(value)) {
+            return Value.mapContainer(value, this.unserialize.bind(this));
+        } else {
+            return value;
+        }
+    }
+
+    /**
+     * Return a string used to embed a value in a function.
+     *
+     * @param  {*} value
+     * @return {string}
+     */
+    embedFunctionValue(value)
+    {
+        value = this.unserialize(value);
+        const valueUniqueIdentifier = ResourceRepository.storeGlobal(value);
+
+        const a = Value.isResource(value)
+            ? `
+                __rialto_ResourceRepository__
+                    .retrieveGlobal(${JSON.stringify(valueUniqueIdentifier)})
+            `
+            : JSON.stringify(value);
+
+        return a;
+    }
+
+    /**
+     * Unserialize a function.
+     *
+     * @param  {Object} value
+     * @return {Function}
+     */
+    unserializeFunction(value)
+    {
+        const scopedVariables = [];
+
+        for (let [varName, varValue] of Object.entries(value.scope)) {
+            scopedVariables.push(`var ${varName} = ${this.embedFunctionValue(varValue)};`);
+        }
+
+        const parameters = [];
+
+        for (let [paramKey, paramValue] of Object.entries(value.parameters)) {
+            if (!isNaN(parseInt(paramKey, 10))) {
+                parameters.push(paramValue);
+            } else {
+                parameters.push(`${paramKey} = ${this.embedFunctionValue(paramValue)}`);
+            }
+        }
+
+        const asyncFlag = value.async ? 'async' : '';
+
+        return new Function(`
+            return ${asyncFlag} function (${parameters.join(', ')}) {
+                ${scopedVariables.join('\n')}
+                ${value.body}
+            };
+        `)();
+    }
+}
+
+module.exports = Unserializer;

+ 63 - 0
node_modules/@nesk/rialto/src/node-process/Data/Value.js

@@ -0,0 +1,63 @@
+'use strict';
+
+const _ = require('lodash');
+
+class Value
+{
+    /**
+     * Determine if the value is a string, a number, a boolean, or null.
+     *
+     * @param  {*} value
+     * @return {boolean}
+     */
+    static isScalar(value)
+    {
+        return _.isString(value) || _.isNumber(value) || _.isBoolean(value) || _.isNull(value);
+    }
+
+    /**
+     * Determine if the value is an array or a plain object.
+     *
+     * @param  {*} value
+     * @return {boolean}
+     */
+    static isContainer(value)
+    {
+        return _.isArray(value) || _.isPlainObject(value);
+    }
+
+    /**
+     * Map the values of a container.
+     *
+     * @param  {*} container
+     * @param  {callback} mapper
+     * @return {array}
+     */
+    static mapContainer(container, mapper)
+    {
+        if (_.isArray(container)) {
+            return container.map(mapper);
+        } else if (_.isPlainObject(container)) {
+            return Object.entries(container).reduce((finalObject, [key, value]) => {
+                finalObject[key] = mapper(value);
+
+                return finalObject;
+            }, {});
+        } else {
+            return container;
+        }
+    }
+
+    /**
+     * Determine if the value is a resource.
+     *
+     * @param  {*} value
+     * @return {boolean}
+     */
+    static isResource(value)
+    {
+        return !Value.isContainer(value) && !Value.isScalar(value);
+    }
+}
+
+module.exports = Value;

+ 225 - 0
node_modules/@nesk/rialto/src/node-process/Instruction.js

@@ -0,0 +1,225 @@
+'use strict';
+
+const ResourceIdentity = require('./Data/ResourceIdentity');
+
+class Instruction
+{
+    /**
+     * Constructor.
+     *
+     * @param  {Object} serializedInstruction
+     * @param  {ResourceRepository} resources
+     * @param  {DataUnserializer} dataUnserializer
+     */
+    constructor(serializedInstruction, resources, dataUnserializer)
+    {
+        this.instruction = serializedInstruction;
+        this.resources = resources;
+        this.dataUnserializer = dataUnserializer;
+        this.defaultResource = process;
+    }
+
+    /**
+     * Return the type of the instruction.
+     *
+     * @return {instructionTypeEnum}
+     */
+    type()
+    {
+        return this.instruction.type;
+    }
+
+    /**
+     * Override the type of the instruction.
+     *
+     * @param  {instructionTypeEnum} type
+     * @return {this}
+     */
+    overrideType(type)
+    {
+        this.instruction.type = type;
+
+        return this;
+    }
+
+    /**
+     * Return the name of the instruction.
+     *
+     * @return {string}
+     */
+    name()
+    {
+        return this.instruction.name;
+    }
+
+    /**
+     * Override the name of the instruction.
+     *
+     * @param  {string} name
+     * @return {this}
+     */
+    overrideName(name)
+    {
+        this.instruction.name = name;
+
+        return this;
+    }
+
+    /**
+     * Return the value of the instruction.
+     *
+     * @return {*}
+     */
+    value()
+    {
+        const {value} = this.instruction;
+
+        return value !== undefined ? value : null;
+    }
+
+    /**
+     * Override the value of the instruction.
+     *
+     * @param  {*} value
+     * @return {this}
+     */
+    overrideValue(value)
+    {
+        this.instruction.value = value;
+
+        return this;
+    }
+
+    /**
+     * Return the resource of the instruction.
+     *
+     * @return {Object|null}
+     */
+    resource()
+    {
+        const {resource} = this.instruction;
+
+        return resource
+            ? this.resources.retrieve(ResourceIdentity.unserialize(resource))
+            : null;
+    }
+
+    /**
+     * Override the resource of the instruction.
+     *
+     * @param  {Object|null} resource
+     * @return {this}
+     */
+    overrideResource(resource)
+    {
+        if (resource !== null) {
+            this.instruction.resource = this.resources.store(resource);
+        }
+
+        return this;
+    }
+
+    /**
+     * Set the default resource to use.
+     *
+     * @param  {Object} resource
+     * @return {this}
+     */
+    setDefaultResource(resource)
+    {
+        this.defaultResource = resource;
+
+        return this;
+    }
+
+    /**
+     * Whether errors thrown by the instruction should be catched.
+     *
+     * @return {boolean}
+     */
+    shouldCatchErrors()
+    {
+        return this.instruction.catched;
+    }
+
+    /**
+     * Execute the instruction.
+     *
+     * @return {*}
+     */
+    execute()
+    {
+        const type = this.type(),
+            name = this.name(),
+            value = this.value(),
+            resource = this.resource() || this.defaultResource;
+
+        let output = null;
+
+        switch (type) {
+            case Instruction.TYPE_CALL:
+                output = this.callResourceMethod(resource, name, value || []);
+                break;
+            case Instruction.TYPE_GET:
+                output = resource[name];
+                break;
+            case Instruction.TYPE_SET:
+                output = resource[name] = this.unserializeValue(value);
+                break;
+        }
+
+        return output;
+    }
+
+    /**
+     * Call a method on a resource.
+     *
+     * @protected
+     * @param  {Object} resource
+     * @param  {string} methodName
+     * @param  {array} args
+     * @return {*}
+     */
+    callResourceMethod(resource, methodName, args)
+    {
+        try {
+            return resource[methodName](...args.map(this.unserializeValue.bind(this)));
+        } catch (error) {
+            if (error.message === 'resource[methodName] is not a function') {
+                const resourceName = resource.constructor.name === 'Function'
+                    ? resource.name
+                    : resource.constructor.name;
+
+                throw new Error(`"${resourceName}.${methodName} is not a function"`);
+            }
+
+            throw error;
+        }
+    }
+
+    /**
+     * Unserialize a value.
+     *
+     * @protected
+     * @param  {Object} value
+     * @return {*}
+     */
+    unserializeValue(value)
+    {
+        return this.dataUnserializer.unserialize(value);
+    }
+}
+
+/**
+ * Instruction types.
+ *
+ * @enum {instructionTypeEnum}
+ * @readonly
+ */
+Object.assign(Instruction, {
+    TYPE_CALL: 'call',
+    TYPE_GET: 'get',
+    TYPE_SET: 'set',
+});
+
+module.exports = Instruction;

+ 30 - 0
node_modules/@nesk/rialto/src/node-process/Logger.js

@@ -0,0 +1,30 @@
+'use strict';
+
+class Logger
+{
+    /**
+     * Add a new log to the queue.
+     *
+     * @param  {string} origin
+     * @param  {string} level
+     * @param  {string} message
+     */
+    static log(origin, level, message) {
+        this.logsQueue.push({origin, level, message});
+    }
+
+    /**
+     * Flush and return the logs in the queue.
+     *
+     * @return {array}
+     */
+    static logs() {
+        const logs = this.logsQueue;
+        this.logsQueue = [];
+        return logs;
+    }
+}
+
+Logger.logsQueue = [];
+
+module.exports = Logger;

+ 101 - 0
node_modules/@nesk/rialto/src/node-process/NodeInterceptors/ConsoleInterceptor.js

@@ -0,0 +1,101 @@
+'use strict';
+
+const StandardStreamsInterceptor = require('./StandardStreamsInterceptor');
+
+const SUPPORTED_CONSOLE_METHODS = {
+    'debug': 'DEBUG',
+    'dir': 'DEBUG',
+    'dirxml': 'INFO',
+    'error': 'ERROR',
+    'info': 'INFO',
+    'log': 'INFO',
+    'table': 'DEBUG',
+    'warn': 'WARNING',
+};
+
+class ConsoleInterceptor
+{
+    /**
+     * Log interceptor.
+     *
+     * @callback logInterceptor
+     * @param  {string} type
+     * @param  {string} message
+     */
+
+    /**
+     * Replace the global "console" object by a proxy to intercept the logs.
+     *
+     * @param  {logInterceptor} interceptor
+     */
+    static startInterceptingLogs(interceptor) {
+        const consoleProxy = new Proxy(console, {
+            get: (_, type) => this.getLoggingMethod(type, interceptor),
+        });
+
+        // Define the property instead of directly setting the property, the latter is forbidden in some environments.
+        Object.defineProperty(global, 'console', {value: consoleProxy});
+    }
+
+    /**
+     * Return an appropriate logging method for the console proxy.
+     *
+     * @param  {string} type
+     * @param  {logInterceptor} interceptor
+     * @return {callback}
+     */
+    static getLoggingMethod(type, interceptor) {
+        const originalMethod = this.originalConsole[type].bind(this.originalConsole);
+
+        if (!this.typeIsSupported(type)) {
+            return originalMethod;
+        }
+
+        return (...args) => {
+            StandardStreamsInterceptor.startInterceptingStrings(message => interceptor(type, message));
+            originalMethod(...args);
+            StandardStreamsInterceptor.stopInterceptingStrings();
+        };
+    }
+
+    /**
+     * Check if the type of the log is supported.
+     *
+     * @param  {*} type
+     * @return {boolean}
+     */
+    static typeIsSupported(type) {
+        return Object.keys(SUPPORTED_CONSOLE_METHODS).includes(type);
+    }
+
+    /**
+     * Return a log level based on the provided type.
+     *
+     * @param  {*} type
+     * @return {string|null}
+     */
+    static getLevelFromType(type) {
+        return SUPPORTED_CONSOLE_METHODS[type] || null;
+    }
+
+    /**
+     * Format a message from a console method.
+     *
+     * @param  {string} message
+     * @return {string}
+     */
+    static formatMessage(message) {
+        // Remove terminal colors written as escape sequences
+        // See: https://stackoverflow.com/a/41407246/1513045
+        message = message.replace(/\x1b\[\d+m/g, '');
+
+        // Remove the final new line
+        message = message.endsWith('\n') ? message.slice(0, -1) : message;
+
+        return message;
+    }
+}
+
+ConsoleInterceptor.originalConsole = console;
+
+module.exports = ConsoleInterceptor;

+ 54 - 0
node_modules/@nesk/rialto/src/node-process/NodeInterceptors/StandardStreamsInterceptor.js

@@ -0,0 +1,54 @@
+'use strict';
+
+const _ = require('lodash');
+
+const STANDARD_STREAMS = [process.stdout, process.stderr];
+
+class StandardStreamsInterceptor
+{
+    /**
+     * Standard stream interceptor.
+     *
+     * @callback standardStreamInterceptor
+     * @param  {string} message
+     */
+
+    /**
+     * Start intercepting data written on the standard streams.
+     *
+     * @param  {standardStreamInterceptor} interceptor
+     */
+    static startInterceptingStrings(interceptor) {
+        STANDARD_STREAMS.forEach(stream => {
+            this.standardStreamWriters.set(stream, stream.write);
+
+            stream.write = (chunk, encoding, callback) => {
+                if (_.isString(chunk)) {
+                    interceptor(chunk);
+
+                    if (_.isFunction(callback)) {
+                        callback();
+                    }
+
+                    return true;
+                }
+
+                return stream.write(chunk, encoding, callback);
+            };
+        });
+    }
+
+    /**
+     * Stop intercepting data written on the standard streams.
+     */
+    static stopInterceptingStrings() {
+        STANDARD_STREAMS.forEach(stream => {
+            stream.write = this.standardStreamWriters.get(stream);
+            this.standardStreamWriters.delete(stream);
+        });
+    }
+}
+
+StandardStreamsInterceptor.standardStreamWriters = new Map;
+
+module.exports = StandardStreamsInterceptor;

+ 74 - 0
node_modules/@nesk/rialto/src/node-process/Server.js

@@ -0,0 +1,74 @@
+'use strict';
+
+const net = require('net'),
+    Connection = require('./Connection');
+
+/**
+ * Listen for new socket connections.
+ */
+class Server
+{
+    /**
+     * Constructor.
+     *
+     * @param  {ConnectionDelegate} connectionDelegate
+     * @param  {Object} options
+     */
+    constructor(connectionDelegate, options = {})
+    {
+        this.options = options;
+
+        this.started = this.start(connectionDelegate);
+
+        this.resetIdleTimeout();
+    }
+
+    /**
+     * Start the server and listen for new connections.
+     *
+     * @param  {ConnectionDelegate} connectionDelegate
+     * @return {Promise}
+     */
+    start(connectionDelegate)
+    {
+        this.server = net.createServer(socket => {
+            const connection = new Connection(socket, connectionDelegate);
+
+            connection.on('activity', () => this.resetIdleTimeout());
+
+            this.resetIdleTimeout();
+        });
+
+        return new Promise(resolve => {
+            this.server.listen(() => resolve());
+        });
+    }
+
+    /**
+     * Write the listening port on the process output.
+     */
+    writePortToOutput()
+    {
+        process.stdout.write(`${this.server.address().port}\n`);
+    }
+
+    /**
+     * Reset the idle timeout.
+     *
+     * @protected
+     */
+    resetIdleTimeout()
+    {
+        clearTimeout(this.idleTimer);
+
+        const {idle_timeout: idleTimeout} = this.options;
+
+        if (idleTimeout !== null) {
+            this.idleTimer = setTimeout(() => {
+                throw new Error('The idle timeout has been reached.');
+            }, idleTimeout * 1000);
+        }
+    }
+}
+
+module.exports = Server;

+ 5 - 0
node_modules/@nesk/rialto/src/node-process/index.js

@@ -0,0 +1,5 @@
+'use strict';
+
+module.exports = {
+    ConnectionDelegate: require('./ConnectionDelegate'),
+};

+ 40 - 0
node_modules/@nesk/rialto/src/node-process/serve.js

@@ -0,0 +1,40 @@
+'use strict';
+
+const ConsoleInterceptor = require('./NodeInterceptors/ConsoleInterceptor'),
+    Logger = require('./Logger'),
+    Server = require('./Server'),
+    DataSerializer = require('./Data/Serializer');
+
+// Throw unhandled rejections
+process.on('unhandledRejection', error => {
+    throw error;
+});
+
+// Output the exceptions in JSON format
+process.on('uncaughtException', error => {
+    process.stderr.write(JSON.stringify(DataSerializer.serializeError(error)));
+    process.exit(1);
+});
+
+// Retrieve the options
+let options = process.argv.slice(2)[1];
+options = options !== undefined ? JSON.parse(options) : {};
+
+// Intercept Node logs
+if (options.log_node_console === true) {
+    ConsoleInterceptor.startInterceptingLogs((type, originalMessage) => {
+        const level = ConsoleInterceptor.getLevelFromType(type);
+        const message = ConsoleInterceptor.formatMessage(originalMessage);
+
+        Logger.log('Node', level, message);
+    });
+}
+
+// Instanciate the custom connection delegate
+const connectionDelegate = new (require(process.argv.slice(2)[0]))(options);
+
+// Start the server with the custom connection delegate
+const server = new Server(connectionDelegate, options);
+
+// Write the server port to the process output
+server.started.then(() => server.writePortToOutput());

+ 56 - 0
node_modules/@nesk/rialto/tests/Implementation/FsConnectionDelegate.js

@@ -0,0 +1,56 @@
+'use strict';
+
+const fs = require('fs'),
+    {ConnectionDelegate} = require('../../src/node-process');
+
+/**
+ * Handle the requests of a connection to control the "fs" module.
+ */
+class FsConnectionDelegate extends ConnectionDelegate
+{
+    async handleInstruction(instruction, responseHandler, errorHandler)
+    {
+        instruction.setDefaultResource(this.extendFsModule(fs));
+
+        let value = null;
+
+        try {
+            value = await instruction.execute();
+        } catch (error) {
+            if (instruction.shouldCatchErrors()) {
+                return errorHandler(error);
+            }
+
+            throw error;
+        }
+
+        responseHandler(value);
+    }
+
+    extendFsModule(fs)
+    {
+        fs.multipleStatSync = (...paths) => paths.map(fs.statSync);
+
+        fs.multipleResourcesIsFile = resources => resources.map(resource => resource.isFile());
+
+        fs.getHeavyPayloadWithNonAsciiChars = () => {
+            let payload = '';
+
+            for (let i = 0 ; i < 1024 ; i++) {
+                payload += 'a';
+            }
+
+            return `😘${payload}😘`;
+        };
+
+        fs.wait = ms => new Promise(resolve => setTimeout(resolve, ms));
+
+        fs.runCallback = cb => cb(fs);
+
+        fs.getOption = name => this.options[name];
+
+        return fs;
+    }
+}
+
+module.exports = FsConnectionDelegate;

+ 18 - 0
node_modules/@nesk/rialto/tests/Implementation/FsProcessDelegate.php

@@ -0,0 +1,18 @@
+<?php
+
+namespace Nesk\Rialto\Tests\Implementation;
+
+use Nesk\Rialto\Traits\UsesBasicResourceAsDefault;
+use Nesk\Rialto\Interfaces\ShouldHandleProcessDelegation;
+
+class FsProcessDelegate implements ShouldHandleProcessDelegation
+{
+    use UsesBasicResourceAsDefault;
+
+    public function resourceFromOriginalClassName(string $className): ?string
+    {
+        $class = __NAMESPACE__."\\Resources\\$className";
+
+        return class_exists($class) ? $class : null;
+    }
+}

+ 21 - 0
node_modules/@nesk/rialto/tests/Implementation/FsWithProcessDelegation.php

@@ -0,0 +1,21 @@
+<?php
+
+namespace Nesk\Rialto\Tests\Implementation;
+
+use Nesk\Rialto\ProcessSupervisor;
+use Nesk\Rialto\AbstractEntryPoint;
+
+class FsWithProcessDelegation extends AbstractEntryPoint
+{
+    protected $forbiddenOptions = ['stop_timeout', 'foo'];
+
+    public function __construct(array $userOptions = [])
+    {
+        parent::__construct(__DIR__.'/FsConnectionDelegate.js', new FsProcessDelegate, [], $userOptions);
+    }
+
+    public function getProcessSupervisor(): ProcessSupervisor
+    {
+        return parent::getProcessSupervisor();
+    }
+}

+ 13 - 0
node_modules/@nesk/rialto/tests/Implementation/FsWithoutProcessDelegation.php

@@ -0,0 +1,13 @@
+<?php
+
+namespace Nesk\Rialto\Tests\Implementation;
+
+use Nesk\Rialto\AbstractEntryPoint;
+
+class FsWithoutProcessDelegation extends AbstractEntryPoint
+{
+    public function __construct()
+    {
+        parent::__construct(__DIR__.'/FsConnectionDelegate.js');
+    }
+}

+ 10 - 0
node_modules/@nesk/rialto/tests/Implementation/Resources/Stats.php

@@ -0,0 +1,10 @@
+<?php
+
+namespace Nesk\Rialto\Tests\Implementation\Resources;
+
+use Nesk\Rialto\Data\BasicResource;
+
+class Stats extends BasicResource
+{
+    //
+}

+ 533 - 0
node_modules/@nesk/rialto/tests/ImplementationTest.php

@@ -0,0 +1,533 @@
+<?php
+
+namespace Nesk\Rialto\Tests;
+
+use Monolog\Logger;
+use Nesk\Rialto\Data\JsFunction;
+use Nesk\Rialto\Exceptions\Node;
+use Nesk\Rialto\Data\BasicResource;
+use Symfony\Component\Process\Process;
+use Nesk\Rialto\Tests\Implementation\Resources\Stats;
+use Nesk\Rialto\Tests\Implementation\{FsWithProcessDelegation, FsWithoutProcessDelegation};
+
+class ImplementationTest extends TestCase
+{
+    const JS_FUNCTION_CREATE_DEPRECATION_PATTERN = '/^Nesk\\\\Rialto\\\\Data\\\\JsFunction::create\(\)/';
+
+    public function setUp(): void
+    {
+        parent::setUp();
+
+        $this->dirPath = realpath(__DIR__.'/resources');
+        $this->filePath = "{$this->dirPath}/file";
+
+        $this->fs = $this->canPopulateProperty('fs') ? new FsWithProcessDelegation : null;
+    }
+
+    public function tearDown(): void
+    {
+        $this->fs = null;
+    }
+
+    /** @test */
+    public function can_call_method_and_get_its_return_value()
+    {
+        $content = $this->fs->readFileSync($this->filePath, 'utf8');
+
+        $this->assertEquals('Hello world!', $content);
+    }
+
+    /** @test */
+    public function can_get_property()
+    {
+        $constants = $this->fs->constants;
+
+        $this->assertInternalType('array', $constants);
+    }
+
+    /** @test */
+    public function can_set_property()
+    {
+        $this->fs->foo = 'bar';
+        $this->assertEquals('bar', $this->fs->foo);
+
+        $this->fs->foo = null;
+        $this->assertNull($this->fs->foo);
+    }
+
+    /** @test */
+    public function can_return_basic_resources()
+    {
+        $resource = $this->fs->readFileSync($this->filePath);
+
+        $this->assertInstanceOf(BasicResource::class, $resource);
+    }
+
+    /** @test */
+    public function can_return_specific_resources()
+    {
+        $resource = $this->fs->statSync($this->filePath);
+
+        $this->assertInstanceOf(Stats::class, $resource);
+    }
+
+    /** @test */
+    public function can_cast_resources_to_string()
+    {
+        $resource = $this->fs->statSync($this->filePath);
+
+        $this->assertEquals('[object Object]', (string) $resource);
+    }
+
+    /**
+     * @test
+     * @dontPopulateProperties fs
+     */
+    public function can_omit_process_delegation()
+    {
+        $this->fs = new FsWithoutProcessDelegation;
+
+        $resource = $this->fs->statSync($this->filePath);
+
+        $this->assertInstanceOf(BasicResource::class, $resource);
+        $this->assertNotInstanceOf(Stats::class, $resource);
+    }
+
+    /** @test */
+    public function can_use_nested_resources()
+    {
+        $resources = $this->fs->multipleStatSync($this->dirPath, $this->filePath);
+
+        $this->assertCount(2, $resources);
+        $this->assertContainsOnlyInstancesOf(Stats::class, $resources);
+
+        $isFile = $this->fs->multipleResourcesIsFile($resources);
+
+        $this->assertFalse($isFile[0]);
+        $this->assertTrue($isFile[1]);
+    }
+
+    /** @test */
+    public function can_use_multiple_resources_without_confusion()
+    {
+        $dirStats = $this->fs->statSync($this->dirPath);
+        $fileStats = $this->fs->statSync($this->filePath);
+
+        $this->assertInstanceOf(Stats::class, $dirStats);
+        $this->assertInstanceOf(Stats::class, $fileStats);
+
+        $this->assertTrue($dirStats->isDirectory());
+        $this->assertTrue($fileStats->isFile());
+    }
+
+    /** @test */
+    public function can_return_multiple_times_the_same_resource()
+    {
+        $stats1 = $this->fs->Stats;
+        $stats2 = $this->fs->Stats;
+
+        $this->assertEquals($stats1, $stats2);
+    }
+
+    /**
+     * @test
+     * @group js-functions
+     */
+    public function can_use_js_functions_with_a_body()
+    {
+        $functions = [
+            $this->ignoreUserDeprecation(self::JS_FUNCTION_CREATE_DEPRECATION_PATTERN, function () {
+                return JsFunction::create("return 'Simple callback';");
+            }),
+            JsFunction::createWithBody("return 'Simple callback';"),
+        ];
+
+        foreach ($functions as $function) {
+            $value = $this->fs->runCallback($function);
+            $this->assertEquals('Simple callback', $value);
+        }
+    }
+
+    /**
+     * @test
+     * @group js-functions
+     */
+    public function can_use_js_functions_with_parameters()
+    {
+        $functions = [
+            $this->ignoreUserDeprecation(self::JS_FUNCTION_CREATE_DEPRECATION_PATTERN, function () {
+                return JsFunction::create(['fs'], "
+                    return 'Callback using arguments: ' + fs.constructor.name;
+                ");
+            }),
+            JsFunction::createWithParameters(['fs'])
+                ->body("return 'Callback using arguments: ' + fs.constructor.name;"),
+        ];
+
+        foreach ($functions as $function) {
+            $value = $this->fs->runCallback($function);
+            $this->assertEquals('Callback using arguments: Object', $value);
+        }
+    }
+
+    /**
+     * @test
+     * @group js-functions
+     */
+    public function can_use_js_functions_with_scope()
+    {
+        $functions = [
+            $this->ignoreUserDeprecation(self::JS_FUNCTION_CREATE_DEPRECATION_PATTERN, function () {
+                return JsFunction::create("
+                    return 'Callback using scope: ' + foo;
+                ", ['foo' => 'bar']);
+            }),
+            JsFunction::createWithScope(['foo' => 'bar'])
+                ->body("return 'Callback using scope: ' + foo;"),
+        ];
+
+        foreach ($functions as $function) {
+            $value = $this->fs->runCallback($function);
+            $this->assertEquals('Callback using scope: bar', $value);
+        }
+    }
+
+    /**
+     * @test
+     * @group js-functions
+     */
+    public function can_use_resources_in_js_functions()
+    {
+        $fileStats = $this->fs->statSync($this->filePath);
+
+        $functions = [
+            JsFunction::createWithParameters(['fs', 'fileStats' => $fileStats])
+                ->body("return fileStats.isFile();"),
+            JsFunction::createWithScope(['fileStats' => $fileStats])
+                ->body("return fileStats.isFile();"),
+        ];
+
+        foreach ($functions as $function) {
+            $isFile = $this->fs->runCallback($function);
+            $this->assertTrue($isFile);
+        }
+    }
+
+    /**
+     * @test
+     * @group js-functions
+     */
+    public function can_use_async_with_js_functions()
+    {
+        $function = JsFunction::createWithAsync()
+            ->body("
+                await Promise.resolve();
+                return true;
+            ");
+
+        $this->assertTrue($this->fs->runCallback($function));
+
+        $function = $function->async(false);
+
+        $this->expectException(Node\FatalException::class);
+        $this->expectExceptionMessage('await is only valid in async function');
+
+        $this->fs->runCallback($function);
+    }
+
+    /**
+     * @test
+     * @group js-functions
+     */
+    public function js_functions_are_sync_by_default()
+    {
+        $function = JsFunction::createWithBody('await null');
+
+        $this->expectException(Node\FatalException::class);
+        $this->expectExceptionMessage('await is only valid in async function');
+
+        $this->fs->runCallback($function);
+    }
+
+    /** @test */
+    public function can_receive_heavy_payloads_with_non_ascii_chars()
+    {
+        $payload = $this->fs->getHeavyPayloadWithNonAsciiChars();
+
+        $this->assertStringStartsWith('😘', $payload);
+        $this->assertStringEndsWith('😘', $payload);
+    }
+
+    /**
+     * @test
+     * @expectedException \Nesk\Rialto\Exceptions\Node\FatalException
+     * @expectedExceptionMessage Object.__inexistantMethod__ is not a function
+     */
+    public function node_crash_throws_a_fatal_exception()
+    {
+        $this->fs->__inexistantMethod__();
+    }
+
+    /**
+     * @test
+     * @expectedException \Nesk\Rialto\Exceptions\Node\Exception
+     * @expectedExceptionMessage Object.__inexistantMethod__ is not a function
+     */
+    public function can_catch_errors()
+    {
+        $this->fs->tryCatch->__inexistantMethod__();
+    }
+
+    /**
+     * @test
+     * @expectedException \Nesk\Rialto\Exceptions\Node\FatalException
+     * @expectedExceptionMessage Object.__inexistantMethod__ is not a function
+     */
+    public function catching_a_node_exception_doesnt_catch_fatal_exceptions()
+    {
+        try {
+            $this->fs->__inexistantMethod__();
+        } catch (Node\Exception $exception) {
+            //
+        }
+    }
+
+    /**
+     * @test
+     * @dontPopulateProperties fs
+     */
+    public function in_debug_mode_node_exceptions_contain_stack_trace_in_message()
+    {
+        $this->fs = new FsWithProcessDelegation(['debug' => true]);
+
+        $regex = '/\n\nError: "Object\.__inexistantMethod__ is not a function"\n\s+at /';
+
+        try {
+            $this->fs->tryCatch->__inexistantMethod__();
+        } catch (Node\Exception $exception) {
+            $this->assertRegExp($regex, $exception->getMessage());
+        }
+
+        try {
+            $this->fs->__inexistantMethod__();
+        } catch (Node\FatalException $exception) {
+            $this->assertRegExp($regex, $exception->getMessage());
+        }
+    }
+
+    /** @test */
+    public function node_current_working_directory_is_the_same_as_php()
+    {
+        $result = $this->fs->accessSync('tests/resources/file');
+
+        $this->assertNull($result);
+    }
+
+    /**
+     * @test
+     * @expectedException \Symfony\Component\Process\Exception\ProcessFailedException
+     * @expectedExceptionMessageRegExp /Error Output:\n=+\n.*__inexistant_process__.*not found/
+     */
+    public function executable_path_option_changes_the_process_prefix()
+    {
+        new FsWithProcessDelegation(['executable_path' => '__inexistant_process__']);
+    }
+
+    /**
+     * @test
+     * @dontPopulateProperties fs
+     */
+    public function idle_timeout_option_closes_node_once_timer_is_reached()
+    {
+        $this->fs = new FsWithProcessDelegation(['idle_timeout' => 0.5]);
+
+        $this->fs->constants;
+
+        sleep(1);
+
+        $this->expectException(\Nesk\Rialto\Exceptions\IdleTimeoutException::class);
+        $this->expectExceptionMessageRegExp('/^The idle timeout \(0\.500 seconds\) has been exceeded/');
+
+        $this->fs->constants;
+    }
+
+    /**
+     * @test
+     * @dontPopulateProperties fs
+     * @expectedException \Nesk\Rialto\Exceptions\ReadSocketTimeoutException
+     * @expectedExceptionMessageRegExp /^The timeout \(0\.010 seconds\) has been exceeded/
+     */
+    public function read_timeout_option_throws_an_exception_on_long_actions()
+    {
+        $this->fs = new FsWithProcessDelegation(['read_timeout' => 0.01]);
+
+        $this->fs->wait(20);
+    }
+
+    /**
+     * @test
+     * @group logs
+     * @dontPopulateProperties fs
+     */
+    public function forbidden_options_are_removed()
+    {
+        $this->fs = new FsWithProcessDelegation([
+            'logger' => $this->loggerMock(
+                $this->at(0),
+                $this->isLogLevel(),
+                'Applying options...',
+                $this->callback(function ($context) {
+                    $this->assertArrayHasKey('read_timeout', $context['options']);
+                    $this->assertArrayNotHasKey('stop_timeout', $context['options']);
+                    $this->assertArrayNotHasKey('foo', $context['options']);
+
+                    return true;
+                })
+            ),
+
+            'read_timeout' => 5,
+            'stop_timeout' => 0,
+            'foo' => 'bar',
+        ]);
+    }
+
+    /**
+     * @test
+     * @dontPopulateProperties fs
+     */
+    public function connection_delegate_receives_options()
+    {
+        $this->fs = new FsWithProcessDelegation([
+            'log_node_console' => true,
+            'new_option' => false,
+        ]);
+
+        $this->assertNull($this->fs->getOption('read_timeout')); // Assert this option is stripped by the supervisor
+        $this->assertTrue($this->fs->getOption('log_node_console'));
+        $this->assertFalse($this->fs->getOption('new_option'));
+    }
+
+    /**
+     * @test
+     * @dontPopulateProperties fs
+     */
+    public function process_status_is_tracked()
+    {
+        if (PHP_OS === 'WINNT') {
+            $this->markTestSkipped('This test is not supported on Windows.');
+        }
+
+        if ((new Process(['which', 'pgrep']))->run() !== 0) {
+            $this->markTestSkipped('The "pgrep" command is not available.');
+        }
+
+        $oldPids = $this->getPidsForProcessName('node');
+        $this->fs = new FsWithProcessDelegation;
+        $newPids = $this->getPidsForProcessName('node');
+
+        $newNodeProcesses = array_values(array_diff($newPids, $oldPids));
+        $newNodeProcessesCount = count($newNodeProcesses);
+        $this->assertCount(
+            1,
+            $newNodeProcesses,
+            "One Node process should have been created instead of $newNodeProcessesCount. Try running again."
+        );
+
+        $processKilled = posix_kill($newNodeProcesses[0], SIGKILL);
+        $this->assertTrue($processKilled);
+
+        $this->expectException(\Nesk\Rialto\Exceptions\ProcessUnexpectedlyTerminatedException::class);
+        $this->expectExceptionMessage('The process has been unexpectedly terminated.');
+
+        $this->fs->foo;
+    }
+
+    /** @test */
+    public function process_is_properly_shutdown_when_there_are_no_more_references()
+    {
+        if (!class_exists('WeakRef')) {
+            $this->markTestSkipped(
+                'This test requires weak references (unavailable for PHP 7.3): http://php.net/weakref/'
+            );
+        }
+
+        $ref = new \WeakRef($this->fs->getProcessSupervisor());
+
+        $resource = $this->fs->readFileSync($this->filePath);
+
+        $this->assertInstanceOf(BasicResource::class, $resource);
+
+        $this->fs = null;
+        unset($resource);
+
+        $this->assertFalse($ref->valid());
+    }
+
+    /**
+     * @test
+     * @group logs
+     * @dontPopulateProperties fs
+     */
+    public function logger_is_used_when_provided()
+    {
+        $this->fs = new FsWithProcessDelegation([
+            'logger' => $this->loggerMock(
+                $this->atLeastOnce(),
+                $this->isLogLevel(),
+                $this->isType('string')
+            ),
+        ]);
+    }
+
+    /**
+     * @test
+     * @group logs
+     * @dontPopulateProperties fs
+     */
+    public function node_console_calls_are_logged()
+    {
+        $setups = [
+            [false, 'Received data on stdout:'],
+            [true, 'Received a Node log:'],
+        ];
+
+        foreach ($setups as [$logNodeConsole, $startsWith]) {
+            $this->fs = new FsWithProcessDelegation([
+                'log_node_console' => $logNodeConsole,
+                'logger' => $this->loggerMock(
+                    $this->at(5),
+                    $this->isLogLevel(),
+                    $this->stringStartsWith($startsWith)
+                ),
+            ]);
+
+            $this->fs->runCallback(JsFunction::createWithBody("console.log('Hello World!')"));
+        }
+    }
+
+    /**
+     * @test
+     * @group logs
+     * @dontPopulateProperties fs
+     */
+    public function delayed_node_console_calls_and_data_on_standard_streams_are_logged()
+    {
+        $this->fs = new FsWithProcessDelegation([
+            'log_node_console' => true,
+            'logger' => $this->loggerMock([
+                [$this->at(6), $this->isLogLevel(), $this->stringStartsWith('Received data on stdout:')],
+                [$this->at(7), $this->isLogLevel(), $this->stringStartsWith('Received a Node log:')],
+            ]),
+        ]);
+
+        $this->fs->runCallback(JsFunction::createWithBody("
+            setTimeout(() => {
+                process.stdout.write('Hello Stdout!');
+                console.log('Hello Console!');
+            });
+        "));
+
+        usleep(10000); // 10ms, to be sure the delayed instructions just above are executed.
+        $this->fs = null;
+    }
+}

+ 105 - 0
node_modules/@nesk/rialto/tests/TestCase.php

@@ -0,0 +1,105 @@
+<?php
+
+namespace Nesk\Rialto\Tests;
+
+use Monolog\Logger;
+use ReflectionClass;
+use Psr\Log\LogLevel;
+use PHPUnit\Util\ErrorHandler;
+use Symfony\Component\Process\Process;
+use PHPUnit\Framework\Constraint\Callback;
+use PHPUnit\Framework\TestCase as BaseTestCase;
+use PHPUnit\Framework\MockObject\Matcher\Invocation;
+
+class TestCase extends BaseTestCase
+{
+    private $dontPopulateProperties = [];
+
+    public function setUp(): void
+    {
+        parent::setUp();
+
+        $testMethod = new \ReflectionMethod($this, $this->getName());
+        $docComment = $testMethod->getDocComment();
+
+        if (preg_match('/@dontPopulateProperties (.*)/', $docComment, $matches)) {
+            $this->dontPopulateProperties = array_values(array_filter(explode(' ', $matches[1])));
+        }
+    }
+
+    public function canPopulateProperty(string $propertyName): bool
+    {
+        return !in_array($propertyName, $this->dontPopulateProperties);
+    }
+
+    public function ignoreUserDeprecation(string $messagePattern, callable $callback) {
+        set_error_handler(
+            function (int $errorNumber, string $errorString, string $errorFile, int $errorLine) use ($messagePattern) {
+                if ($errorNumber !== E_USER_DEPRECATED || preg_match($messagePattern, $errorString) !== 1) {
+                    ErrorHandler::handleError($errorNumber, $errorString, $errorFile, $errorLine);
+                }
+            }
+        );
+
+        $value = $callback();
+
+        restore_error_handler();
+
+        return $value;
+    }
+
+    public function getPidsForProcessName(string $processName) {
+        $pgrep = new Process(['pgrep', $processName]);
+        $pgrep->run();
+
+        $pids = explode("\n", $pgrep->getOutput());
+
+        $pids = array_filter($pids, function ($pid) {
+            return !empty($pid);
+        });
+
+        $pids = array_map(function ($pid) {
+            return (int) $pid;
+        }, $pids);
+
+        return $pids;
+    }
+
+    public function loggerMock($expectations) {
+        $loggerMock = $this->getMockBuilder(Logger::class)
+            ->setConstructorArgs(['rialto'])
+            ->setMethods(['log'])
+            ->getMock();
+
+        if ($expectations instanceof Invocation) {
+            $expectations = [func_get_args()];
+        }
+
+        foreach ($expectations as $expectation) {
+            [$matcher] = $expectation;
+            $with = array_slice($expectation, 1);
+
+            $loggerMock->expects($matcher)
+                ->method('log')
+                ->with(...$with);
+        }
+
+        return $loggerMock;
+    }
+
+    public function isLogLevel(): Callback {
+        $psrLogLevels = (new ReflectionClass(LogLevel::class))->getConstants();
+        $monologLevels = (new ReflectionClass(Logger::class))->getConstants();
+        $monologLevels = array_intersect_key($monologLevels, $psrLogLevels);
+
+        return $this->callback(function ($level) use ($psrLogLevels, $monologLevels) {
+            if (is_string($level)) {
+                return in_array($level, $psrLogLevels, true);
+            } else if (is_int($level)) {
+                return in_array($level, $monologLevels, true);
+            }
+
+            return false;
+        });
+    }
+}

+ 1 - 0
node_modules/@nesk/rialto/tests/resources/file

@@ -0,0 +1 @@
+Hello world!

+ 28 - 0
node_modules/@puppeteer/browsers/README.md

@@ -0,0 +1,28 @@
+# @puppeteer/browsers
+
+Manage and launch browsers/drivers from a CLI or programmatically.
+
+## CLI
+
+Use `npx` to run the CLI:
+
+```bash
+npx @puppeteer/browsers --help
+```
+
+CLI help will provide all documentation you need to use the CLI.
+
+```bash
+npx @puppeteer/browsers --help # help for all commands
+npx @puppeteer/browsers install --help # help for the install command
+npx @puppeteer/browsers launch --help # help for the launch command
+```
+
+## Known limitations
+
+1. We support installing and running Firefox, Chrome and Chromium. The `latest`, `beta`, `dev`, `canary`, `stable` keywords are only supported for the install command. For the `launch` command you need to specify an exact build ID. The build ID is provided by the `install` command (see `npx @puppeteer/browsers install --help` for the format).
+2. Launching the system browsers is only possible for Chrome/Chromium.
+
+## API
+
+The programmatic API allows installing and launching browsers from your code. See the `test` folder for examples on how to use the `install`, `canInstall`, `launch`, `computeExecutablePath`, `computeSystemExecutablePath` and other methods.

+ 31 - 0
node_modules/@puppeteer/browsers/lib/cjs/CLI.d.ts

@@ -0,0 +1,31 @@
+/**
+ * Copyright 2023 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/// <reference types="node" />
+import * as readline from 'readline';
+import { Browser } from './browser-data/browser-data.js';
+/**
+ * @public
+ */
+export declare class CLI {
+    #private;
+    constructor(cachePath?: string, rl?: readline.Interface);
+    run(argv: string[]): Promise<void>;
+}
+/**
+ * @public
+ */
+export declare function makeProgressCallback(browser: Browser, buildId: string): (downloadedBytes: number, totalBytes: number) => void;
+//# sourceMappingURL=CLI.d.ts.map

+ 1 - 0
node_modules/@puppeteer/browsers/lib/cjs/CLI.d.ts.map

@@ -0,0 +1 @@
+{"version":3,"file":"CLI.d.ts","sourceRoot":"","sources":["../../src/CLI.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;;AAGH,OAAO,KAAK,QAAQ,MAAM,UAAU,CAAC;AAOrC,OAAO,EAEL,OAAO,EAGR,MAAM,gCAAgC,CAAC;AAmCxC;;GAEG;AACH,qBAAa,GAAG;;gBAIF,SAAS,SAAgB,EAAE,EAAE,CAAC,EAAE,QAAQ,CAAC,SAAS;IAwCxD,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAwKzC;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,MAAM,GACd,CAAC,eAAe,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,IAAI,CAqBvD"}

+ 230 - 0
node_modules/@puppeteer/browsers/lib/cjs/CLI.js

@@ -0,0 +1,230 @@
+"use strict";
+/**
+ * Copyright 2023 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+    if (k2 === undefined) k2 = k;
+    var desc = Object.getOwnPropertyDescriptor(m, k);
+    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+      desc = { enumerable: true, get: function() { return m[k]; } };
+    }
+    Object.defineProperty(o, k2, desc);
+}) : (function(o, m, k, k2) {
+    if (k2 === undefined) k2 = k;
+    o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+    Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+    o["default"] = v;
+});
+var __importStar = (this && this.__importStar) || function (mod) {
+    if (mod && mod.__esModule) return mod;
+    var result = {};
+    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
+    __setModuleDefault(result, mod);
+    return result;
+};
+var __importDefault = (this && this.__importDefault) || function (mod) {
+    return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.makeProgressCallback = exports.CLI = void 0;
+const process_1 = require("process");
+const readline = __importStar(require("readline"));
+const progress_1 = __importDefault(require("progress"));
+const helpers_1 = require("yargs/helpers");
+const yargs_1 = __importDefault(require("yargs/yargs"));
+const browser_data_js_1 = require("./browser-data/browser-data.js");
+const Cache_js_1 = require("./Cache.js");
+const detectPlatform_js_1 = require("./detectPlatform.js");
+const install_js_1 = require("./install.js");
+const launch_js_1 = require("./launch.js");
+/**
+ * @public
+ */
+class CLI {
+    #cachePath;
+    #rl;
+    constructor(cachePath = process.cwd(), rl) {
+        this.#cachePath = cachePath;
+        this.#rl = rl;
+    }
+    #defineBrowserParameter(yargs) {
+        yargs.positional('browser', {
+            description: 'Which browser to install <browser>[@<buildId|latest>]. `latest` will try to find the latest available build. `buildId` is a browser-specific identifier such as a version or a revision.',
+            type: 'string',
+            coerce: (opt) => {
+                return {
+                    name: this.#parseBrowser(opt),
+                    buildId: this.#parseBuildId(opt),
+                };
+            },
+        });
+    }
+    #definePlatformParameter(yargs) {
+        yargs.option('platform', {
+            type: 'string',
+            desc: 'Platform that the binary needs to be compatible with.',
+            choices: Object.values(browser_data_js_1.BrowserPlatform),
+            defaultDescription: 'Auto-detected',
+        });
+    }
+    #definePathParameter(yargs, required = false) {
+        yargs.option('path', {
+            type: 'string',
+            desc: 'Path to the root folder for the browser downloads and installation. The installation folder structure is compatible with the cache structure used by Puppeteer.',
+            defaultDescription: 'Current working directory',
+            ...(required ? {} : { default: process.cwd() }),
+        });
+        if (required) {
+            yargs.demandOption('path');
+        }
+    }
+    async run(argv) {
+        const yargsInstance = (0, yargs_1.default)((0, helpers_1.hideBin)(argv));
+        await yargsInstance
+            .scriptName('@puppeteer/browsers')
+            .command('install <browser>', 'Download and install the specified browser. If successful, the command outputs the actual browser buildId that was installed and the absolute path to the browser executable (format: <browser>@<buildID> <path>).', yargs => {
+            this.#defineBrowserParameter(yargs);
+            this.#definePlatformParameter(yargs);
+            this.#definePathParameter(yargs);
+            yargs.option('base-url', {
+                type: 'string',
+                desc: 'Base URL to download from',
+            });
+            yargs.example('$0 install chrome', 'Install the latest available build of the Chrome browser.');
+            yargs.example('$0 install chrome@latest', 'Install the latest available build for the Chrome browser.');
+            yargs.example('$0 install chromium@1083080', 'Install the revision 1083080 of the Chromium browser.');
+            yargs.example('$0 install firefox', 'Install the latest available build of the Firefox browser.');
+            yargs.example('$0 install firefox --platform mac', 'Install the latest Mac (Intel) build of the Firefox browser.');
+            yargs.example('$0 install firefox --path /tmp/my-browser-cache', 'Install to the specified cache directory.');
+        }, async (argv) => {
+            const args = argv;
+            args.platform ??= (0, detectPlatform_js_1.detectBrowserPlatform)();
+            if (!args.platform) {
+                throw new Error(`Could not resolve the current platform`);
+            }
+            args.browser.buildId = await (0, browser_data_js_1.resolveBuildId)(args.browser.name, args.platform, args.browser.buildId);
+            await (0, install_js_1.install)({
+                browser: args.browser.name,
+                buildId: args.browser.buildId,
+                platform: args.platform,
+                cacheDir: args.path ?? this.#cachePath,
+                downloadProgressCallback: makeProgressCallback(args.browser.name, args.browser.buildId),
+                baseUrl: args.baseUrl,
+            });
+            console.log(`${args.browser.name}@${args.browser.buildId} ${(0, launch_js_1.computeExecutablePath)({
+                browser: args.browser.name,
+                buildId: args.browser.buildId,
+                cacheDir: args.path ?? this.#cachePath,
+                platform: args.platform,
+            })}`);
+        })
+            .command('launch <browser>', 'Launch the specified browser', yargs => {
+            this.#defineBrowserParameter(yargs);
+            this.#definePlatformParameter(yargs);
+            this.#definePathParameter(yargs);
+            yargs.option('detached', {
+                type: 'boolean',
+                desc: 'Detach the child process.',
+                default: false,
+            });
+            yargs.option('system', {
+                type: 'boolean',
+                desc: 'Search for a browser installed on the system instead of the cache folder.',
+                default: false,
+            });
+            yargs.example('$0 launch chrome@1083080', 'Launch the Chrome browser identified by the revision 1083080.');
+            yargs.example('$0 launch firefox@112.0a1', 'Launch the Firefox browser identified by the milestone 112.0a1.');
+            yargs.example('$0 launch chrome@1083080 --detached', 'Launch the browser but detach the sub-processes.');
+            yargs.example('$0 launch chrome@canary --system', 'Try to locate the Canary build of Chrome installed on the system and launch it.');
+        }, async (argv) => {
+            const args = argv;
+            const executablePath = args.system
+                ? (0, launch_js_1.computeSystemExecutablePath)({
+                    browser: args.browser.name,
+                    // TODO: throw an error if not a ChromeReleaseChannel is provided.
+                    channel: args.browser.buildId,
+                    platform: args.platform,
+                })
+                : (0, launch_js_1.computeExecutablePath)({
+                    browser: args.browser.name,
+                    buildId: args.browser.buildId,
+                    cacheDir: args.path ?? this.#cachePath,
+                    platform: args.platform,
+                });
+            (0, launch_js_1.launch)({
+                executablePath,
+                detached: args.detached,
+            });
+        })
+            .command('clear', 'Removes all installed browsers from the specified cache directory', yargs => {
+            this.#definePathParameter(yargs, true);
+        }, async (argv) => {
+            const args = argv;
+            const cacheDir = args.path ?? this.#cachePath;
+            const rl = this.#rl ?? readline.createInterface({ input: process_1.stdin, output: process_1.stdout });
+            rl.question(`Do you want to permanently and recursively delete the content of ${cacheDir} (yes/No)? `, answer => {
+                rl.close();
+                if (!['y', 'yes'].includes(answer.toLowerCase().trim())) {
+                    console.log('Cancelled.');
+                    return;
+                }
+                const cache = new Cache_js_1.Cache(cacheDir);
+                cache.clear();
+                console.log(`${cacheDir} cleared.`);
+            });
+        })
+            .demandCommand(1)
+            .help()
+            .wrap(Math.min(120, yargsInstance.terminalWidth()))
+            .parse();
+    }
+    #parseBrowser(version) {
+        return version.split('@').shift();
+    }
+    #parseBuildId(version) {
+        const parts = version.split('@');
+        return parts.length === 2 ? parts[1] : 'latest';
+    }
+}
+exports.CLI = CLI;
+/**
+ * @public
+ */
+function makeProgressCallback(browser, buildId) {
+    let progressBar;
+    let lastDownloadedBytes = 0;
+    return (downloadedBytes, totalBytes) => {
+        if (!progressBar) {
+            progressBar = new progress_1.default(`Downloading ${browser} r${buildId} - ${toMegabytes(totalBytes)} [:bar] :percent :etas `, {
+                complete: '=',
+                incomplete: ' ',
+                width: 20,
+                total: totalBytes,
+            });
+        }
+        const delta = downloadedBytes - lastDownloadedBytes;
+        lastDownloadedBytes = downloadedBytes;
+        progressBar.tick(delta);
+    };
+}
+exports.makeProgressCallback = makeProgressCallback;
+function toMegabytes(bytes) {
+    const mb = bytes / 1000 / 1000;
+    return `${Math.round(mb * 10) / 10} MB`;
+}
+//# sourceMappingURL=CLI.js.map

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
node_modules/@puppeteer/browsers/lib/cjs/CLI.js.map


+ 53 - 0
node_modules/@puppeteer/browsers/lib/cjs/Cache.d.ts

@@ -0,0 +1,53 @@
+/**
+ * Copyright 2023 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { Browser, BrowserPlatform } from './browser-data/browser-data.js';
+/**
+ * @public
+ */
+export interface InstalledBrowser {
+    /**
+     * Path to the root of the installation folder. Use
+     * {@link computeExecutablePath} to get the path to the executable binary.
+     */
+    path: string;
+    browser: Browser;
+    buildId: string;
+    platform: BrowserPlatform;
+}
+/**
+ * The cache used by Puppeteer relies on the following structure:
+ *
+ * - rootDir
+ *   -- <browser1> | browserRoot(browser1)
+ *   ---- <platform>-<buildId> | installationDir()
+ *   ------ the browser-platform-buildId
+ *   ------ specific structure.
+ *   -- <browser2> | browserRoot(browser2)
+ *   ---- <platform>-<buildId> | installationDir()
+ *   ------ the browser-platform-buildId
+ *   ------ specific structure.
+ *   @internal
+ */
+export declare class Cache {
+    #private;
+    constructor(rootDir: string);
+    browserRoot(browser: Browser): string;
+    installationDir(browser: Browser, platform: BrowserPlatform, buildId: string): string;
+    clear(): void;
+    uninstall(browser: Browser, platform: BrowserPlatform, buildId: string): void;
+    getInstalledBrowsers(): InstalledBrowser[];
+}
+//# sourceMappingURL=Cache.d.ts.map

+ 1 - 0
node_modules/@puppeteer/browsers/lib/cjs/Cache.d.ts.map

@@ -0,0 +1 @@
+{"version":3,"file":"Cache.d.ts","sourceRoot":"","sources":["../../src/Cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,OAAO,EAAC,OAAO,EAAE,eAAe,EAAC,MAAM,gCAAgC,CAAC;AAExE;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,eAAe,CAAC;CAC3B;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,KAAK;;gBAGJ,OAAO,EAAE,MAAM;IAI3B,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM;IAIrC,eAAe,CACb,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,eAAe,EACzB,OAAO,EAAE,MAAM,GACd,MAAM;IAIT,KAAK,IAAI,IAAI;IASb,SAAS,CACP,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,eAAe,EACzB,OAAO,EAAE,MAAM,GACd,IAAI;IASP,oBAAoB,IAAI,gBAAgB,EAAE;CA8B3C"}

+ 108 - 0
node_modules/@puppeteer/browsers/lib/cjs/Cache.js

@@ -0,0 +1,108 @@
+"use strict";
+/**
+ * Copyright 2023 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+var __importDefault = (this && this.__importDefault) || function (mod) {
+    return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.Cache = void 0;
+const fs_1 = __importDefault(require("fs"));
+const path_1 = __importDefault(require("path"));
+const browser_data_js_1 = require("./browser-data/browser-data.js");
+/**
+ * The cache used by Puppeteer relies on the following structure:
+ *
+ * - rootDir
+ *   -- <browser1> | browserRoot(browser1)
+ *   ---- <platform>-<buildId> | installationDir()
+ *   ------ the browser-platform-buildId
+ *   ------ specific structure.
+ *   -- <browser2> | browserRoot(browser2)
+ *   ---- <platform>-<buildId> | installationDir()
+ *   ------ the browser-platform-buildId
+ *   ------ specific structure.
+ *   @internal
+ */
+class Cache {
+    #rootDir;
+    constructor(rootDir) {
+        this.#rootDir = rootDir;
+    }
+    browserRoot(browser) {
+        return path_1.default.join(this.#rootDir, browser);
+    }
+    installationDir(browser, platform, buildId) {
+        return path_1.default.join(this.browserRoot(browser), `${platform}-${buildId}`);
+    }
+    clear() {
+        fs_1.default.rmSync(this.#rootDir, {
+            force: true,
+            recursive: true,
+            maxRetries: 10,
+            retryDelay: 500,
+        });
+    }
+    uninstall(browser, platform, buildId) {
+        fs_1.default.rmSync(this.installationDir(browser, platform, buildId), {
+            force: true,
+            recursive: true,
+            maxRetries: 10,
+            retryDelay: 500,
+        });
+    }
+    getInstalledBrowsers() {
+        if (!fs_1.default.existsSync(this.#rootDir)) {
+            return [];
+        }
+        const types = fs_1.default.readdirSync(this.#rootDir);
+        const browsers = types.filter((t) => {
+            return Object.values(browser_data_js_1.Browser).includes(t);
+        });
+        return browsers.flatMap(browser => {
+            const files = fs_1.default.readdirSync(this.browserRoot(browser));
+            return files
+                .map(file => {
+                const result = parseFolderPath(path_1.default.join(this.browserRoot(browser), file));
+                if (!result) {
+                    return null;
+                }
+                return {
+                    path: path_1.default.join(this.browserRoot(browser), file),
+                    browser,
+                    platform: result.platform,
+                    buildId: result.buildId,
+                };
+            })
+                .filter((item) => {
+                return item !== null;
+            });
+        });
+    }
+}
+exports.Cache = Cache;
+function parseFolderPath(folderPath) {
+    const name = path_1.default.basename(folderPath);
+    const splits = name.split('-');
+    if (splits.length !== 2) {
+        return;
+    }
+    const [platform, buildId] = splits;
+    if (!buildId || !platform) {
+        return;
+    }
+    return { platform, buildId };
+}
+//# sourceMappingURL=Cache.js.map

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
node_modules/@puppeteer/browsers/lib/cjs/Cache.js.map


+ 53 - 0
node_modules/@puppeteer/browsers/lib/cjs/browser-data/browser-data.d.ts

@@ -0,0 +1,53 @@
+/**
+ * Copyright 2023 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import * as chrome from './chrome.js';
+import * as chromedriver from './chromedriver.js';
+import * as chromium from './chromium.js';
+import * as firefox from './firefox.js';
+import { Browser, BrowserPlatform, ChromeReleaseChannel, ProfileOptions } from './types.js';
+export { ProfileOptions };
+export declare const downloadUrls: {
+    chromedriver: typeof chromedriver.resolveDownloadUrl;
+    chrome: typeof chrome.resolveDownloadUrl;
+    chromium: typeof chromium.resolveDownloadUrl;
+    firefox: typeof firefox.resolveDownloadUrl;
+};
+export declare const downloadPaths: {
+    chromedriver: typeof chromedriver.resolveDownloadPath;
+    chrome: typeof chrome.resolveDownloadPath;
+    chromium: typeof chromium.resolveDownloadPath;
+    firefox: typeof firefox.resolveDownloadPath;
+};
+export declare const executablePathByBrowser: {
+    chromedriver: typeof chromedriver.relativeExecutablePath;
+    chrome: typeof chrome.relativeExecutablePath;
+    chromium: typeof chromium.relativeExecutablePath;
+    firefox: typeof firefox.relativeExecutablePath;
+};
+export { Browser, BrowserPlatform, ChromeReleaseChannel };
+/**
+ * @public
+ */
+export declare function resolveBuildId(browser: Browser, platform: BrowserPlatform, tag: string): Promise<string>;
+/**
+ * @public
+ */
+export declare function createProfile(browser: Browser, opts: ProfileOptions): Promise<void>;
+/**
+ * @public
+ */
+export declare function resolveSystemExecutablePath(browser: Browser, platform: BrowserPlatform, channel: ChromeReleaseChannel): string;
+//# sourceMappingURL=browser-data.d.ts.map

+ 1 - 0
node_modules/@puppeteer/browsers/lib/cjs/browser-data/browser-data.d.ts.map

@@ -0,0 +1 @@
+{"version":3,"file":"browser-data.d.ts","sourceRoot":"","sources":["../../../src/browser-data/browser-data.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAC1C,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AACxC,OAAO,EACL,OAAO,EACP,eAAe,EAEf,oBAAoB,EACpB,cAAc,EACf,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAC,cAAc,EAAC,CAAC;AAExB,eAAO,MAAM,YAAY;;;;;CAKxB,CAAC;AAEF,eAAO,MAAM,aAAa;;;;;CAKzB,CAAC;AAEF,eAAO,MAAM,uBAAuB;;;;;CAKnC,CAAC;AAEF,OAAO,EAAC,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAC,CAAC;AAExD;;GAEG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,eAAe,EACzB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,MAAM,CAAC,CAqEjB;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,cAAc,GACnB,OAAO,CAAC,IAAI,CAAC,CAQf;AAED;;GAEG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,eAAe,EACzB,OAAO,EAAE,oBAAoB,GAC5B,MAAM,CAWR"}

+ 150 - 0
node_modules/@puppeteer/browsers/lib/cjs/browser-data/browser-data.js

@@ -0,0 +1,150 @@
+"use strict";
+/**
+ * Copyright 2023 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+    if (k2 === undefined) k2 = k;
+    var desc = Object.getOwnPropertyDescriptor(m, k);
+    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+      desc = { enumerable: true, get: function() { return m[k]; } };
+    }
+    Object.defineProperty(o, k2, desc);
+}) : (function(o, m, k, k2) {
+    if (k2 === undefined) k2 = k;
+    o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+    Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+    o["default"] = v;
+});
+var __importStar = (this && this.__importStar) || function (mod) {
+    if (mod && mod.__esModule) return mod;
+    var result = {};
+    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
+    __setModuleDefault(result, mod);
+    return result;
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.resolveSystemExecutablePath = exports.createProfile = exports.resolveBuildId = exports.ChromeReleaseChannel = exports.BrowserPlatform = exports.Browser = exports.executablePathByBrowser = exports.downloadPaths = exports.downloadUrls = void 0;
+const chrome = __importStar(require("./chrome.js"));
+const chromedriver = __importStar(require("./chromedriver.js"));
+const chromium = __importStar(require("./chromium.js"));
+const firefox = __importStar(require("./firefox.js"));
+const types_js_1 = require("./types.js");
+Object.defineProperty(exports, "Browser", { enumerable: true, get: function () { return types_js_1.Browser; } });
+Object.defineProperty(exports, "BrowserPlatform", { enumerable: true, get: function () { return types_js_1.BrowserPlatform; } });
+Object.defineProperty(exports, "ChromeReleaseChannel", { enumerable: true, get: function () { return types_js_1.ChromeReleaseChannel; } });
+exports.downloadUrls = {
+    [types_js_1.Browser.CHROMEDRIVER]: chromedriver.resolveDownloadUrl,
+    [types_js_1.Browser.CHROME]: chrome.resolveDownloadUrl,
+    [types_js_1.Browser.CHROMIUM]: chromium.resolveDownloadUrl,
+    [types_js_1.Browser.FIREFOX]: firefox.resolveDownloadUrl,
+};
+exports.downloadPaths = {
+    [types_js_1.Browser.CHROMEDRIVER]: chromedriver.resolveDownloadPath,
+    [types_js_1.Browser.CHROME]: chrome.resolveDownloadPath,
+    [types_js_1.Browser.CHROMIUM]: chromium.resolveDownloadPath,
+    [types_js_1.Browser.FIREFOX]: firefox.resolveDownloadPath,
+};
+exports.executablePathByBrowser = {
+    [types_js_1.Browser.CHROMEDRIVER]: chromedriver.relativeExecutablePath,
+    [types_js_1.Browser.CHROME]: chrome.relativeExecutablePath,
+    [types_js_1.Browser.CHROMIUM]: chromium.relativeExecutablePath,
+    [types_js_1.Browser.FIREFOX]: firefox.relativeExecutablePath,
+};
+/**
+ * @public
+ */
+async function resolveBuildId(browser, platform, tag) {
+    switch (browser) {
+        case types_js_1.Browser.FIREFOX:
+            switch (tag) {
+                case types_js_1.BrowserTag.LATEST:
+                    return await firefox.resolveBuildId('FIREFOX_NIGHTLY');
+                case types_js_1.BrowserTag.BETA:
+                case types_js_1.BrowserTag.CANARY:
+                case types_js_1.BrowserTag.DEV:
+                case types_js_1.BrowserTag.STABLE:
+                    throw new Error(`${tag} is not supported for ${browser}. Use 'latest' instead.`);
+            }
+        case types_js_1.Browser.CHROME:
+            switch (tag) {
+                case types_js_1.BrowserTag.LATEST:
+                    return await chrome.resolveBuildId(platform, types_js_1.ChromeReleaseChannel.CANARY);
+                case types_js_1.BrowserTag.BETA:
+                    return await chrome.resolveBuildId(platform, types_js_1.ChromeReleaseChannel.BETA);
+                case types_js_1.BrowserTag.CANARY:
+                    return await chrome.resolveBuildId(platform, types_js_1.ChromeReleaseChannel.CANARY);
+                case types_js_1.BrowserTag.DEV:
+                    return await chrome.resolveBuildId(platform, types_js_1.ChromeReleaseChannel.DEV);
+                case types_js_1.BrowserTag.STABLE:
+                    return await chrome.resolveBuildId(platform, types_js_1.ChromeReleaseChannel.STABLE);
+            }
+        case types_js_1.Browser.CHROMEDRIVER:
+            switch (tag) {
+                case types_js_1.BrowserTag.LATEST:
+                case types_js_1.BrowserTag.CANARY:
+                    return await chromedriver.resolveBuildId(types_js_1.ChromeReleaseChannel.CANARY);
+                case types_js_1.BrowserTag.BETA:
+                    return await chromedriver.resolveBuildId(types_js_1.ChromeReleaseChannel.BETA);
+                case types_js_1.BrowserTag.DEV:
+                    return await chromedriver.resolveBuildId(types_js_1.ChromeReleaseChannel.DEV);
+                case types_js_1.BrowserTag.STABLE:
+                    return await chromedriver.resolveBuildId(types_js_1.ChromeReleaseChannel.STABLE);
+            }
+        case types_js_1.Browser.CHROMIUM:
+            switch (tag) {
+                case types_js_1.BrowserTag.LATEST:
+                    return await chromium.resolveBuildId(platform);
+                case types_js_1.BrowserTag.BETA:
+                case types_js_1.BrowserTag.CANARY:
+                case types_js_1.BrowserTag.DEV:
+                case types_js_1.BrowserTag.STABLE:
+                    throw new Error(`${tag} is not supported for ${browser}. Use 'latest' instead.`);
+            }
+    }
+    // We assume the tag is the buildId if it didn't match any keywords.
+    return tag;
+}
+exports.resolveBuildId = resolveBuildId;
+/**
+ * @public
+ */
+async function createProfile(browser, opts) {
+    switch (browser) {
+        case types_js_1.Browser.FIREFOX:
+            return await firefox.createProfile(opts);
+        case types_js_1.Browser.CHROME:
+        case types_js_1.Browser.CHROMIUM:
+            throw new Error(`Profile creation is not support for ${browser} yet`);
+    }
+}
+exports.createProfile = createProfile;
+/**
+ * @public
+ */
+function resolveSystemExecutablePath(browser, platform, channel) {
+    switch (browser) {
+        case types_js_1.Browser.CHROMEDRIVER:
+        case types_js_1.Browser.FIREFOX:
+        case types_js_1.Browser.CHROMIUM:
+            throw new Error(`System browser detection is not supported for ${browser} yet.`);
+        case types_js_1.Browser.CHROME:
+            return chrome.resolveSystemExecutablePath(platform, channel);
+    }
+}
+exports.resolveSystemExecutablePath = resolveSystemExecutablePath;
+//# sourceMappingURL=browser-data.js.map

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
node_modules/@puppeteer/browsers/lib/cjs/browser-data/browser-data.js.map


+ 26 - 0
node_modules/@puppeteer/browsers/lib/cjs/browser-data/chrome.d.ts

@@ -0,0 +1,26 @@
+/**
+ * Copyright 2023 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { BrowserPlatform, ChromeReleaseChannel } from './types.js';
+export declare function resolveDownloadUrl(platform: BrowserPlatform, buildId: string, baseUrl?: string): string;
+export declare function resolveDownloadPath(platform: BrowserPlatform, buildId: string): string[];
+export declare function relativeExecutablePath(platform: BrowserPlatform, _buildId: string): string;
+export declare function getLastKnownGoodReleaseForChannel(channel: ChromeReleaseChannel): Promise<{
+    version: string;
+    revision: string;
+}>;
+export declare function resolveBuildId(_platform: BrowserPlatform, channel: ChromeReleaseChannel): Promise<string>;
+export declare function resolveSystemExecutablePath(platform: BrowserPlatform, channel: ChromeReleaseChannel): string;
+//# sourceMappingURL=chrome.d.ts.map

+ 1 - 0
node_modules/@puppeteer/browsers/lib/cjs/browser-data/chrome.d.ts.map

@@ -0,0 +1 @@
+{"version":3,"file":"chrome.d.ts","sourceRoot":"","sources":["../../../src/browser-data/chrome.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAMH,OAAO,EAAC,eAAe,EAAE,oBAAoB,EAAC,MAAM,YAAY,CAAC;AAiBjE,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,eAAe,EACzB,OAAO,EAAE,MAAM,EACf,OAAO,SAAgE,GACtE,MAAM,CAER;AAED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,eAAe,EACzB,OAAO,EAAE,MAAM,GACd,MAAM,EAAE,CAEV;AAED,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,eAAe,EACzB,QAAQ,EAAE,MAAM,GACf,MAAM,CAiBR;AAED,wBAAsB,iCAAiC,CACrD,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAC,CAAC,CAqB9C;AAED,wBAAsB,cAAc,CAClC,SAAS,EAAE,eAAe,EAC1B,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,MAAM,CAAC,CAEjB;AAED,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,eAAe,EACzB,OAAO,EAAE,oBAAoB,GAC5B,MAAM,CAwCR"}

+ 112 - 0
node_modules/@puppeteer/browsers/lib/cjs/browser-data/chrome.js

@@ -0,0 +1,112 @@
+"use strict";
+/**
+ * Copyright 2023 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+var __importDefault = (this && this.__importDefault) || function (mod) {
+    return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.resolveSystemExecutablePath = exports.resolveBuildId = exports.getLastKnownGoodReleaseForChannel = exports.relativeExecutablePath = exports.resolveDownloadPath = exports.resolveDownloadUrl = void 0;
+const path_1 = __importDefault(require("path"));
+const httpUtil_js_1 = require("../httpUtil.js");
+const types_js_1 = require("./types.js");
+function folder(platform) {
+    switch (platform) {
+        case types_js_1.BrowserPlatform.LINUX:
+            return 'linux64';
+        case types_js_1.BrowserPlatform.MAC_ARM:
+            return 'mac-arm64';
+        case types_js_1.BrowserPlatform.MAC:
+            return 'mac-x64';
+        case types_js_1.BrowserPlatform.WIN32:
+            return 'win32';
+        case types_js_1.BrowserPlatform.WIN64:
+            return 'win64';
+    }
+}
+function resolveDownloadUrl(platform, buildId, baseUrl = 'https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing') {
+    return `${baseUrl}/${resolveDownloadPath(platform, buildId).join('/')}`;
+}
+exports.resolveDownloadUrl = resolveDownloadUrl;
+function resolveDownloadPath(platform, buildId) {
+    return [buildId, folder(platform), `chrome-${folder(platform)}.zip`];
+}
+exports.resolveDownloadPath = resolveDownloadPath;
+function relativeExecutablePath(platform, _buildId) {
+    switch (platform) {
+        case types_js_1.BrowserPlatform.MAC:
+        case types_js_1.BrowserPlatform.MAC_ARM:
+            return path_1.default.join('chrome-' + folder(platform), 'Google Chrome for Testing.app', 'Contents', 'MacOS', 'Google Chrome for Testing');
+        case types_js_1.BrowserPlatform.LINUX:
+            return path_1.default.join('chrome-linux64', 'chrome');
+        case types_js_1.BrowserPlatform.WIN32:
+        case types_js_1.BrowserPlatform.WIN64:
+            return path_1.default.join('chrome-' + folder(platform), 'chrome.exe');
+    }
+}
+exports.relativeExecutablePath = relativeExecutablePath;
+async function getLastKnownGoodReleaseForChannel(channel) {
+    const data = (await (0, httpUtil_js_1.getJSON)(new URL('https://googlechromelabs.github.io/chrome-for-testing/last-known-good-versions.json')));
+    for (const channel of Object.keys(data.channels)) {
+        data.channels[channel.toLowerCase()] = data.channels[channel];
+        delete data.channels[channel];
+    }
+    return data.channels[channel];
+}
+exports.getLastKnownGoodReleaseForChannel = getLastKnownGoodReleaseForChannel;
+async function resolveBuildId(_platform, channel) {
+    return (await getLastKnownGoodReleaseForChannel(channel)).version;
+}
+exports.resolveBuildId = resolveBuildId;
+function resolveSystemExecutablePath(platform, channel) {
+    switch (platform) {
+        case types_js_1.BrowserPlatform.WIN64:
+        case types_js_1.BrowserPlatform.WIN32:
+            switch (channel) {
+                case types_js_1.ChromeReleaseChannel.STABLE:
+                    return `${process.env['PROGRAMFILES']}\\Google\\Chrome\\Application\\chrome.exe`;
+                case types_js_1.ChromeReleaseChannel.BETA:
+                    return `${process.env['PROGRAMFILES']}\\Google\\Chrome Beta\\Application\\chrome.exe`;
+                case types_js_1.ChromeReleaseChannel.CANARY:
+                    return `${process.env['PROGRAMFILES']}\\Google\\Chrome SxS\\Application\\chrome.exe`;
+                case types_js_1.ChromeReleaseChannel.DEV:
+                    return `${process.env['PROGRAMFILES']}\\Google\\Chrome Dev\\Application\\chrome.exe`;
+            }
+        case types_js_1.BrowserPlatform.MAC_ARM:
+        case types_js_1.BrowserPlatform.MAC:
+            switch (channel) {
+                case types_js_1.ChromeReleaseChannel.STABLE:
+                    return '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
+                case types_js_1.ChromeReleaseChannel.BETA:
+                    return '/Applications/Google Chrome Beta.app/Contents/MacOS/Google Chrome Beta';
+                case types_js_1.ChromeReleaseChannel.CANARY:
+                    return '/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary';
+                case types_js_1.ChromeReleaseChannel.DEV:
+                    return '/Applications/Google Chrome Dev.app/Contents/MacOS/Google Chrome Dev';
+            }
+        case types_js_1.BrowserPlatform.LINUX:
+            switch (channel) {
+                case types_js_1.ChromeReleaseChannel.STABLE:
+                    return '/opt/google/chrome/chrome';
+                case types_js_1.ChromeReleaseChannel.BETA:
+                    return '/opt/google/chrome-beta/chrome';
+                case types_js_1.ChromeReleaseChannel.DEV:
+                    return '/opt/google/chrome-unstable/chrome';
+            }
+    }
+    throw new Error(`Unable to detect browser executable path for '${channel}' on ${platform}.`);
+}
+exports.resolveSystemExecutablePath = resolveSystemExecutablePath;
+//# sourceMappingURL=chrome.js.map

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
node_modules/@puppeteer/browsers/lib/cjs/browser-data/chrome.js.map


برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است