diff --git a/api/.env b/api/.env index 9e7c528..2768dc8 100644 --- a/api/.env +++ b/api/.env @@ -6,4 +6,4 @@ LXD_CLIENT_CERT=/etc/ssl/lxdapp/client.crt LXD_CLIENT_KEY=/etc/ssl/lxdapp/client.key LXD_IMAGE_FINGERPRINT=2edfd84b1396 AUTH_KEY=R9kX2HFA7ZjLdVYm8TsQWpCeNuB1v0GrS6MI4axf - +STATEDIR=/tmp \ No newline at end of file diff --git a/api/composer.lock b/api/composer.lock new file mode 100644 index 0000000..01d4bd9 --- /dev/null +++ b/api/composer.lock @@ -0,0 +1,1407 @@ +{ + "_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": "922ee7e3fd54ca2747cf5ce18d09b50c", + "packages": [ + { + "name": "fig/http-message-util", + "version": "1.1.5", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message-util.git", + "reference": "9d94dc0154230ac39e5bf89398b324a86f63f765" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message-util/zipball/9d94dc0154230ac39e5bf89398b324a86f63f765", + "reference": "9d94dc0154230ac39e5bf89398b324a86f63f765", + "shasum": "" + }, + "require": { + "php": "^5.3 || ^7.0 || ^8.0" + }, + "suggest": { + "psr/http-message": "The package containing the PSR-7 interfaces" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Fig\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Utility classes and constants for use with PSR-7 (psr/http-message)", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "issues": "https://github.com/php-fig/http-message-util/issues", + "source": "https://github.com/php-fig/http-message-util/tree/1.1.5" + }, + "time": "2020-11-24T22:02:12+00:00" + }, + { + "name": "graham-campbell/result-type", + "version": "v1.1.3", + "source": { + "type": "git", + "url": "https://github.com/GrahamCampbell/Result-Type.git", + "reference": "3ba905c11371512af9d9bdd27d99b782216b6945" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/3ba905c11371512af9d9bdd27d99b782216b6945", + "reference": "3ba905c11371512af9d9bdd27d99b782216b6945", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.3" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" + }, + "type": "library", + "autoload": { + "psr-4": { + "GrahamCampbell\\ResultType\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "An Implementation Of The Result Type", + "keywords": [ + "Graham Campbell", + "GrahamCampbell", + "Result Type", + "Result-Type", + "result" + ], + "support": { + "issues": "https://github.com/GrahamCampbell/Result-Type/issues", + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type", + "type": "tidelift" + } + ], + "time": "2024-07-20T21:45:45+00:00" + }, + { + "name": "laravel/serializable-closure", + "version": "v2.0.4", + "source": { + "type": "git", + "url": "https://github.com/laravel/serializable-closure.git", + "reference": "b352cf0534aa1ae6b4d825d1e762e35d43f8a841" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/b352cf0534aa1ae6b4d825d1e762e35d43f8a841", + "reference": "b352cf0534aa1ae6b4d825d1e762e35d43f8a841", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "illuminate/support": "^10.0|^11.0|^12.0", + "nesbot/carbon": "^2.67|^3.0", + "pestphp/pest": "^2.36|^3.0", + "phpstan/phpstan": "^2.0", + "symfony/var-dumper": "^6.2.0|^7.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Laravel\\SerializableClosure\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + }, + { + "name": "Nuno Maduro", + "email": "nuno@laravel.com" + } + ], + "description": "Laravel Serializable Closure provides an easy and secure way to serialize closures in PHP.", + "keywords": [ + "closure", + "laravel", + "serializable" + ], + "support": { + "issues": "https://github.com/laravel/serializable-closure/issues", + "source": "https://github.com/laravel/serializable-closure" + }, + "time": "2025-03-19T13:51:03+00:00" + }, + { + "name": "nikic/fast-route", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/FastRoute.git", + "reference": "181d480e08d9476e61381e04a71b34dc0432e812" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/FastRoute/zipball/181d480e08d9476e61381e04a71b34dc0432e812", + "reference": "181d480e08d9476e61381e04a71b34dc0432e812", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35|~5.7" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "FastRoute\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov", + "email": "nikic@php.net" + } + ], + "description": "Fast request router for PHP", + "keywords": [ + "router", + "routing" + ], + "support": { + "issues": "https://github.com/nikic/FastRoute/issues", + "source": "https://github.com/nikic/FastRoute/tree/master" + }, + "time": "2018-02-13T20:26:39+00:00" + }, + { + "name": "php-di/invoker", + "version": "2.3.7", + "source": { + "type": "git", + "url": "https://github.com/PHP-DI/Invoker.git", + "reference": "3c1ddfdef181431fbc4be83378f6d036d59e81e1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-DI/Invoker/zipball/3c1ddfdef181431fbc4be83378f6d036d59e81e1", + "reference": "3c1ddfdef181431fbc4be83378f6d036d59e81e1", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "psr/container": "^1.0|^2.0" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "mnapoli/hard-mode": "~0.3.0", + "phpunit/phpunit": "^9.0 || ^10 || ^11 || ^12" + }, + "type": "library", + "autoload": { + "psr-4": { + "Invoker\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Generic and extensible callable invoker", + "homepage": "https://github.com/PHP-DI/Invoker", + "keywords": [ + "callable", + "dependency", + "dependency-injection", + "injection", + "invoke", + "invoker" + ], + "support": { + "issues": "https://github.com/PHP-DI/Invoker/issues", + "source": "https://github.com/PHP-DI/Invoker/tree/2.3.7" + }, + "funding": [ + { + "url": "https://github.com/mnapoli", + "type": "github" + } + ], + "time": "2025-08-30T10:22:22+00:00" + }, + { + "name": "php-di/php-di", + "version": "7.1.1", + "source": { + "type": "git", + "url": "https://github.com/PHP-DI/PHP-DI.git", + "reference": "f88054cc052e40dbe7b383c8817c19442d480352" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-DI/PHP-DI/zipball/f88054cc052e40dbe7b383c8817c19442d480352", + "reference": "f88054cc052e40dbe7b383c8817c19442d480352", + "shasum": "" + }, + "require": { + "laravel/serializable-closure": "^1.0 || ^2.0", + "php": ">=8.0", + "php-di/invoker": "^2.0", + "psr/container": "^1.1 || ^2.0" + }, + "provide": { + "psr/container-implementation": "^1.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3", + "friendsofphp/proxy-manager-lts": "^1", + "mnapoli/phpunit-easymock": "^1.3", + "phpunit/phpunit": "^9.6 || ^10 || ^11", + "vimeo/psalm": "^5|^6" + }, + "suggest": { + "friendsofphp/proxy-manager-lts": "Install it if you want to use lazy injection (version ^1)" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "DI\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "The dependency injection container for humans", + "homepage": "https://php-di.org/", + "keywords": [ + "PSR-11", + "container", + "container-interop", + "dependency injection", + "di", + "ioc", + "psr11" + ], + "support": { + "issues": "https://github.com/PHP-DI/PHP-DI/issues", + "source": "https://github.com/PHP-DI/PHP-DI/tree/7.1.1" + }, + "funding": [ + { + "url": "https://github.com/mnapoli", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/php-di/php-di", + "type": "tidelift" + } + ], + "time": "2025-08-16T11:10:48+00:00" + }, + { + "name": "phpoption/phpoption", + "version": "1.9.4", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/php-option.git", + "reference": "638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d", + "reference": "638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.44 || ^9.6.25 || ^10.5.53 || ^11.5.34" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpOption\\": "src/PhpOption/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "https://github.com/schmittjoh" + }, + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "Option Type for PHP", + "keywords": [ + "language", + "option", + "php", + "type" + ], + "support": { + "issues": "https://github.com/schmittjoh/php-option/issues", + "source": "https://github.com/schmittjoh/php-option/tree/1.9.4" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption", + "type": "tidelift" + } + ], + "time": "2025-08-21T11:53:16+00:00" + }, + { + "name": "psr/container", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/2.0.2" + }, + "time": "2021-11-05T16:47:00+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory" + }, + "time": "2024-04-15T12:06:14+00:00" + }, + { + "name": "psr/http-message", + "version": "2.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/2.0" + }, + "time": "2023-04-04T09:54:51+00:00" + }, + { + "name": "psr/http-server-handler", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-server-handler.git", + "reference": "84c4fb66179be4caaf8e97bd239203245302e7d4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-server-handler/zipball/84c4fb66179be4caaf8e97bd239203245302e7d4", + "reference": "84c4fb66179be4caaf8e97bd239203245302e7d4", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Server\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP server-side request handler", + "keywords": [ + "handler", + "http", + "http-interop", + "psr", + "psr-15", + "psr-7", + "request", + "response", + "server" + ], + "support": { + "source": "https://github.com/php-fig/http-server-handler/tree/1.0.2" + }, + "time": "2023-04-10T20:06:20+00:00" + }, + { + "name": "psr/http-server-middleware", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-server-middleware.git", + "reference": "c1481f747daaa6a0782775cd6a8c26a1bf4a3829" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-server-middleware/zipball/c1481f747daaa6a0782775cd6a8c26a1bf4a3829", + "reference": "c1481f747daaa6a0782775cd6a8c26a1bf4a3829", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "psr/http-message": "^1.0 || ^2.0", + "psr/http-server-handler": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Server\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP server-side middleware", + "keywords": [ + "http", + "http-interop", + "middleware", + "psr", + "psr-15", + "psr-7", + "request", + "response" + ], + "support": { + "issues": "https://github.com/php-fig/http-server-middleware/issues", + "source": "https://github.com/php-fig/http-server-middleware/tree/1.0.2" + }, + "time": "2023-04-11T06:14:47+00:00" + }, + { + "name": "psr/log", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "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/3.0.2" + }, + "time": "2024-09-11T13:17:53+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "slim/psr7", + "version": "1.7.1", + "source": { + "type": "git", + "url": "https://github.com/slimphp/Slim-Psr7.git", + "reference": "fe98653e7983010aa85c1d137c9b9ad5a1cd187d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slimphp/Slim-Psr7/zipball/fe98653e7983010aa85c1d137c9b9ad5a1cd187d", + "reference": "fe98653e7983010aa85c1d137c9b9ad5a1cd187d", + "shasum": "" + }, + "require": { + "fig/http-message-util": "^1.1.5", + "php": "^8.0", + "psr/http-factory": "^1.1", + "psr/http-message": "^1.0 || ^2.0", + "ralouphie/getallheaders": "^3.0", + "symfony/polyfill-php80": "^1.29" + }, + "provide": { + "psr/http-factory-implementation": "^1.0", + "psr/http-message-implementation": "^1.0 || ^2.0" + }, + "require-dev": { + "adriansuter/php-autoload-override": "^1.4", + "ext-json": "*", + "http-interop/http-factory-tests": "^1.0 || ^2.0", + "php-http/psr7-integration-tests": "^1.4", + "phpspec/prophecy": "^1.19", + "phpspec/prophecy-phpunit": "^2.2", + "phpstan/phpstan": "^2.1", + "phpunit/phpunit": "^9.6 || ^10", + "squizlabs/php_codesniffer": "^3.10" + }, + "type": "library", + "autoload": { + "psr-4": { + "Slim\\Psr7\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Josh Lockhart", + "email": "hello@joshlockhart.com", + "homepage": "https://joshlockhart.com" + }, + { + "name": "Andrew Smith", + "email": "a.smith@silentworks.co.uk", + "homepage": "https://silentworks.co.uk" + }, + { + "name": "Rob Allen", + "email": "rob@akrabat.com", + "homepage": "https://akrabat.com" + }, + { + "name": "Pierre Berube", + "email": "pierre@lgse.com", + "homepage": "https://www.lgse.com" + } + ], + "description": "Strict PSR-7 implementation", + "homepage": "https://www.slimframework.com", + "keywords": [ + "http", + "psr-7", + "psr7" + ], + "support": { + "issues": "https://github.com/slimphp/Slim-Psr7/issues", + "source": "https://github.com/slimphp/Slim-Psr7/tree/1.7.1" + }, + "time": "2025-05-13T14:24:12+00:00" + }, + { + "name": "slim/slim", + "version": "4.15.0", + "source": { + "type": "git", + "url": "https://github.com/slimphp/Slim.git", + "reference": "17eba5182975878a0ab9b27982cd2e2cfcb67ea2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slimphp/Slim/zipball/17eba5182975878a0ab9b27982cd2e2cfcb67ea2", + "reference": "17eba5182975878a0ab9b27982cd2e2cfcb67ea2", + "shasum": "" + }, + "require": { + "ext-json": "*", + "nikic/fast-route": "^1.3", + "php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", + "psr/container": "^1.0 || ^2.0", + "psr/http-factory": "^1.1", + "psr/http-message": "^1.1 || ^2.0", + "psr/http-server-handler": "^1.0", + "psr/http-server-middleware": "^1.0", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "require-dev": { + "adriansuter/php-autoload-override": "^1.4 || ^2", + "ext-simplexml": "*", + "guzzlehttp/psr7": "^2.6", + "httpsoft/http-message": "^1.1", + "httpsoft/http-server-request": "^1.1", + "laminas/laminas-diactoros": "^2.17 || ^3", + "nyholm/psr7": "^1.8", + "nyholm/psr7-server": "^1.1", + "phpspec/prophecy": "^1.19", + "phpspec/prophecy-phpunit": "^2.1", + "phpstan/phpstan": "^1 || ^2", + "phpunit/phpunit": "^9.6", + "slim/http": "^1.3", + "slim/psr7": "^1.6", + "squizlabs/php_codesniffer": "^3.10", + "vimeo/psalm": "^5 || ^6" + }, + "suggest": { + "ext-simplexml": "Needed to support XML format in BodyParsingMiddleware", + "ext-xml": "Needed to support XML format in BodyParsingMiddleware", + "php-di/php-di": "PHP-DI is the recommended container library to be used with Slim", + "slim/psr7": "Slim PSR-7 implementation. See https://www.slimframework.com/docs/v4/start/installation.html for more information." + }, + "type": "library", + "autoload": { + "psr-4": { + "Slim\\": "Slim" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Josh Lockhart", + "email": "hello@joshlockhart.com", + "homepage": "https://joshlockhart.com" + }, + { + "name": "Andrew Smith", + "email": "a.smith@silentworks.co.uk", + "homepage": "https://silentworks.co.uk" + }, + { + "name": "Rob Allen", + "email": "rob@akrabat.com", + "homepage": "https://akrabat.com" + }, + { + "name": "Pierre Berube", + "email": "pierre@lgse.com", + "homepage": "https://www.lgse.com" + }, + { + "name": "Gabriel Manricks", + "email": "gmanricks@me.com", + "homepage": "http://gabrielmanricks.com" + } + ], + "description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs", + "homepage": "https://www.slimframework.com", + "keywords": [ + "api", + "framework", + "micro", + "router" + ], + "support": { + "docs": "https://www.slimframework.com/docs/v4/", + "forum": "https://discourse.slimframework.com/", + "irc": "irc://irc.freenode.net:6667/slimphp", + "issues": "https://github.com/slimphp/Slim/issues", + "rss": "https://www.slimframework.com/blog/feed.rss", + "slack": "https://slimphp.slack.com/", + "source": "https://github.com/slimphp/Slim", + "wiki": "https://github.com/slimphp/Slim/wiki" + }, + "funding": [ + { + "url": "https://opencollective.com/slimphp", + "type": "open_collective" + }, + { + "url": "https://tidelift.com/funding/github/packagist/slim/slim", + "type": "tidelift" + } + ], + "time": "2025-08-20T18:16:16+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "php": ">=7.2" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-12-23T08:48:59+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "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.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-01-02T08:10:11+00:00" + }, + { + "name": "vlucas/phpdotenv", + "version": "v5.6.2", + "source": { + "type": "git", + "url": "https://github.com/vlucas/phpdotenv.git", + "reference": "24ac4c74f91ee2c193fa1aaa5c249cb0822809af" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/24ac4c74f91ee2c193fa1aaa5c249cb0822809af", + "reference": "24ac4c74f91ee2c193fa1aaa5c249cb0822809af", + "shasum": "" + }, + "require": { + "ext-pcre": "*", + "graham-campbell/result-type": "^1.1.3", + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.3", + "symfony/polyfill-ctype": "^1.24", + "symfony/polyfill-mbstring": "^1.24", + "symfony/polyfill-php80": "^1.24" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-filter": "*", + "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" + }, + "suggest": { + "ext-filter": "Required to use the boolean validator." + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "5.6-dev" + } + }, + "autoload": { + "psr-4": { + "Dotenv\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Vance Lucas", + "email": "vance@vancelucas.com", + "homepage": "https://github.com/vlucas" + } + ], + "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "support": { + "issues": "https://github.com/vlucas/phpdotenv/issues", + "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.2" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", + "type": "tidelift" + } + ], + "time": "2025-04-30T23:37:27+00:00" + }, + { + "name": "zounar/php-proxy", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/zounar/php-proxy.git", + "reference": "67e83a8bd7489b220a94402664fa22d9e21e3d40" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zounar/php-proxy/zipball/67e83a8bd7489b220a94402664fa22d9e21e3d40", + "reference": "67e83a8bd7489b220a94402664fa22d9e21e3d40", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-zlib": "*", + "php": ">=5.6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Zounar\\PHPProxy\\": "./" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "unlicense" + ], + "authors": [ + { + "name": "Robin Zounar", + "homepage": "https://zounar.me" + } + ], + "description": "Forward your HTTP/HTTPS requests to another server.", + "homepage": "https://github.com/zounar/php-proxy", + "keywords": [ + "curl", + "curlphp", + "http", + "http-proxy", + "php", + "php-proxy", + "proxy", + "proxy-script" + ], + "support": { + "docs": "https://github.com/zounar/php-proxy/blob/master/README.md", + "issues": "https://github.com/zounar/php-proxy/issues", + "source": "https://github.com/zounar/php-proxy" + }, + "time": "2021-03-28T19:22:45+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [], + "plugin-api-version": "2.6.0" +} diff --git a/api/config.json b/api/config.json index 82f42f1..c3933c5 100644 --- a/api/config.json +++ b/api/config.json @@ -1,3 +1,3 @@ { - "lxdapp.local": "testone" + "auftrag.local": "auftrag" } \ No newline at end of file diff --git a/api/public/index.php b/api/public/index.php index d1ec258..7a653e7 100644 --- a/api/public/index.php +++ b/api/public/index.php @@ -6,14 +6,9 @@ use DI\ContainerBuilder; use Slim\Factory\AppFactory; use Dotenv\Dotenv; use App\Middleware\CorsMiddleware; -use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Http\Message\ResponseInterface as Response; use App\Controllers\CaptchaController; use App\Controllers\LoginController; -use App\Controllers\HandoffController; -use App\Services\LxdService; -use Zounar\PHPProxy\Proxy; -use App\Utils\LogWriterHelper; require __DIR__ . '/../vendor/autoload.php'; @@ -25,7 +20,6 @@ $domain = $_ENV['MAIN_COOKIE_DOMAIN'] ?? '.lxdapp.local'; session_set_cookie_params([ 'lifetime' => 0, 'path' => '/', -// 'domain' => $domain, 'secure' => false, // set true if using HTTPS 'httponly' => true, 'samesite' => 'Lax', @@ -72,7 +66,6 @@ $app->group('/api', function ($group) { $group->get('/captcha', [CaptchaController::class, 'get']); $group->post('/login', [LoginController::class, 'index']); $group->get('/status', [LoginController::class, 'status']); - $group->get('/handoff/post', [HandoffController::class, 'post']); }); /** diff --git a/api/src/Controllers/HandoffController.php b/api/src/Controllers/HandoffController.php deleted file mode 100644 index 744f69a..0000000 --- a/api/src/Controllers/HandoffController.php +++ /dev/null @@ -1,85 +0,0 @@ -getQueryParams(); - $name = (string)($q['name'] ?? ''); - $id = (string)($q['handoff'] ?? ''); - $path = (string)($q['path'] ?? '/login'); - - if (!$name || !$id) { - return $this->html($res, 400, '

Bad request

'); - } - - $lxd = new LxdService(); - $ip = $lxd->getContainerIP($name); - if (!$ip) { - return $this->html($res, 503, '

Container not ready

'); - } - - $key = "handoff:$name:$id"; - $data = $_SESSION[$key] ?? null; - unset($_SESSION[$key]); // one-time use - - if (!$data || empty($data['username']) || empty($data['password'])) { - return $this->html($res, 410, '

Handoff expired

'); - } - - // Restrict to relative paths - $path = $this->sanitizePath($path); - - // If your container has TLS, prefer https:// - $action = 'http://' . $ip . $path; - - $html = << - - Signing you in… - -
- - -
- - - - -HTML; - - return $this->html($res, 200, $html); - } - - private function e(string $s): string - { - return htmlspecialchars($s, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); - } - - private function html(ResponseInterface $res, int $code, string $html): ResponseInterface - { - $res->getBody()->write($html); - return $res->withHeader('Content-Type', 'text/html; charset=utf-8')->withStatus($code); - } - - private function sanitizePath(string $raw): string - { - if (preg_match('#^https?://#i', $raw)) return '/login'; - if (!str_starts_with($raw, '/')) return '/login'; - $path = parse_url($raw, PHP_URL_PATH) ?? '/login'; - $allow = ['/', '/login', '/signin']; - return in_array($path, $allow, true) ? $path : '/login'; - } -} - \ No newline at end of file diff --git a/api/src/Controllers/LoginController.php b/api/src/Controllers/LoginController.php index 49b4af4..4c8b4f9 100644 --- a/api/src/Controllers/LoginController.php +++ b/api/src/Controllers/LoginController.php @@ -7,6 +7,7 @@ use App\Services\LxdService; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use App\Utils\LogWriterHelper; +use App\Utils\ContainerHelper; class LoginController { @@ -16,12 +17,7 @@ class LoginController public function index(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface { try { - $origin = $request->getHeaderLine('Origin'); - $domain = !empty($origin) ? parse_url($origin, PHP_URL_HOST) : $request->getHeaderLine('Host'); - - $configPath = __DIR__ . '/../../config.json'; - $config = file_exists($configPath) ? json_decode(file_get_contents($configPath), true) : []; - $name = $config[$domain] ?? null; + $name = ContainerHelper::getName($request); $params = (array)$request->getParsedBody(); @@ -42,31 +38,12 @@ class LoginController if ($status !== 'Running') { $lxd->startContainer($name); } - - // Log path only (avoid leaking query in logs) - $uri = $request->getUri(); - LogWriterHelper::write($name, $uri->getPath()); - - // ---- NEW: create one-time handoff and store creds server-side ---- - $handoffId = bin2hex(random_bytes(16)); - $_SESSION["handoff:$name:$handoffId"] = [ - 'username' => (string)($params['username'] ?? ''), - 'password' => (string)($params['password'] ?? ''), - 'created_at' => time(), - ]; - - // sanitize the container path (not a full URL!) - $path = $this->sanitizeRedirectPath($params['redirect'] ?? '/login'); - - // Client goes to waiting page; when ready it will be sent to the bridge - $redirect = '/waiting?name=' . rawurlencode($name) - . '&handoff=' . rawurlencode($handoffId) - . '&path=' . rawurlencode($path); + + LogWriterHelper::write($name); return $this->json($response, [ 'status' => 'success', - 'message' => 'Container started!', - 'redirect' => $redirect + 'message' => 'Container gestartet!' ]); } catch (\Throwable $e) { return $this->json($response, [ @@ -78,8 +55,7 @@ class LoginController public function status(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface { - $queryParams = $request->getQueryParams(); - $name = $queryParams['name'] ?? ''; + $name = ContainerHelper::getName($request); if (empty($name)) { return $this->json($response, [ @@ -115,6 +91,7 @@ class LoginController return $this->json($response, [ 'status' => 'ready', 'ip' => $ip, + 'name' => $name, 'message' => 'Container is ready', ]); } diff --git a/api/src/Scripts/auto-stop-containers.php b/api/src/Scripts/auto-stop-containers.php index 6294602..5d3d893 100755 --- a/api/src/Scripts/auto-stop-containers.php +++ b/api/src/Scripts/auto-stop-containers.php @@ -8,7 +8,7 @@ use App\Services\LxdService; $lxdService = new LxdService(); // Define the directory containing access logs -$logDir = realpath(__DIR__ . '/../../public/last-access-logs'); // Adjust if you're in /app/src/Cron or similar +$logDir = $_ENV['STATEDIR'] ?? "/var/www/html/lxd-app/api/public/last-access-logs"; // Define the idle threshold in minutes $thresholdMinutes = 30; @@ -18,23 +18,15 @@ foreach (glob($logDir . '/*.txt') as $filePath) { // Extract the container name from the file name $containerName = basename($filePath, '.txt'); - // Get the last line from the log file - $lastLine = getLastLine($filePath); - if (!$lastLine) { - echo "No access logs found for $containerName.\n"; + // Get the last modified time of the file + $lastModified = filemtime($filePath); + if (!$lastModified) { + echo "Failed to get modification time for $containerName.\n"; continue; } - // Parse the timestamp from the last log entry - $parts = explode(' : ', $lastLine); - if (!isset($parts[0])) continue; - - $lastAccess = DateTime::createFromFormat('Y-m-d H:i:s', trim($parts[0])); - if (!$lastAccess) continue; - - // Calculate the idle time in seconds - $now = new DateTime(); - $interval = $now->getTimestamp() - $lastAccess->getTimestamp(); + $now = time(); + $interval = $now - $lastModified; // Check if the container has been idle for longer than the threshold if ($interval > $thresholdMinutes * 60) { @@ -49,20 +41,7 @@ foreach (glob($logDir . '/*.txt') as $filePath) { echo "Container $containerName does not exist.\n"; } } catch (Throwable $e) { - // Handle any errors that occur while stopping the container echo "Error stopping $containerName: " . $e->getMessage() . "\n"; } } } - -/** - * Get the last non-empty line from a file. - * - * @param string $filePath Path to the file. - * @return string|null The last line, or null if the file is empty. - */ -function getLastLine(string $filePath): ?string -{ - $lines = file($filePath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); - return $lines ? end($lines) : null; -} diff --git a/api/src/Services/LxdService.php b/api/src/Services/LxdService.php index 9345895..d6ae289 100644 --- a/api/src/Services/LxdService.php +++ b/api/src/Services/LxdService.php @@ -36,7 +36,7 @@ class LxdService curl_setopt($ch, CURLOPT_SSLCERT, $clientCert); curl_setopt($ch, CURLOPT_SSLKEY, $clientKey); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); - curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); diff --git a/api/src/Utils/ContainerHelper.php b/api/src/Utils/ContainerHelper.php new file mode 100644 index 0000000..ceca7ed --- /dev/null +++ b/api/src/Utils/ContainerHelper.php @@ -0,0 +1,33 @@ +getHeaderLine('Origin'); + $domain = !empty($origin) ? parse_url($origin, PHP_URL_HOST) : $request->getHeaderLine('Host'); + + // Load config.json once + $config = self::getConfig(); + return $config[$domain] ?? null; + } + + protected static function getConfig(): array + { + static $config = null; + + if ($config !== null) { + return $config; + } + + $configPath = __DIR__ . '/../../config.json'; + + return file_exists($configPath) ? json_decode(file_get_contents($configPath), true) : []; + } +} diff --git a/api/src/Utils/LogWriterHelper.php b/api/src/Utils/LogWriterHelper.php index 74d461f..4c897ff 100644 --- a/api/src/Utils/LogWriterHelper.php +++ b/api/src/Utils/LogWriterHelper.php @@ -3,19 +3,7 @@ namespace App\Utils; class LogWriterHelper { - public static function write(string $name, string $uri): void { - // Dynamically resolve the log directory relative to the current file - $logDir = realpath(__DIR__ . '/../../public/last-access-logs'); - - // If the resolved path doesn't exist (e.g., public dir was missing), create it - if (!$logDir) { - $logDir = __DIR__ . '/../../public/last-access-logs'; - if (!file_exists($logDir)) { - mkdir($logDir, 0777, true); - } - } - - $logLine = date("Y-m-d H:i:s") . " : " . $uri . "\n"; - file_put_contents($logDir . '/' . $name . '.txt', $logLine, FILE_APPEND); + public static function write(string $name): void { + touch($_ENV['STATEDIR']."/".$name); } } \ No newline at end of file diff --git a/api/vendor/autoload.php b/api/vendor/autoload.php new file mode 100644 index 0000000..77486a9 --- /dev/null +++ b/api/vendor/autoload.php @@ -0,0 +1,25 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @see https://www.php-fig.org/psr/psr-0/ + * @see https://www.php-fig.org/psr/psr-4/ + */ +class ClassLoader +{ + /** @var \Closure(string):void */ + private static $includeFile; + + /** @var string|null */ + private $vendorDir; + + // PSR-4 + /** + * @var array> + */ + private $prefixLengthsPsr4 = array(); + /** + * @var array> + */ + private $prefixDirsPsr4 = array(); + /** + * @var list + */ + private $fallbackDirsPsr4 = array(); + + // PSR-0 + /** + * List of PSR-0 prefixes + * + * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2'))) + * + * @var array>> + */ + private $prefixesPsr0 = array(); + /** + * @var list + */ + private $fallbackDirsPsr0 = array(); + + /** @var bool */ + private $useIncludePath = false; + + /** + * @var array + */ + private $classMap = array(); + + /** @var bool */ + private $classMapAuthoritative = false; + + /** + * @var array + */ + private $missingClasses = array(); + + /** @var string|null */ + private $apcuPrefix; + + /** + * @var array + */ + private static $registeredLoaders = array(); + + /** + * @param string|null $vendorDir + */ + public function __construct($vendorDir = null) + { + $this->vendorDir = $vendorDir; + self::initializeIncludeClosure(); + } + + /** + * @return array> + */ + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); + } + + return array(); + } + + /** + * @return array> + */ + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + /** + * @return list + */ + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + /** + * @return list + */ + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + /** + * @return array Array of classname => path + */ + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param array $classMap Class to filename map + * + * @return void + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param list|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + * + * @return void + */ + public function add($prefix, $paths, $prepend = false) + { + $paths = (array) $paths; + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param list|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + * + * @return void + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + $paths = (array) $paths; + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param list|string $paths The PSR-0 base directories + * + * @return void + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param list|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + * + * @return void + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + * + * @return void + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + * + * @return void + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * APCu prefix to use to cache found/not-found classes, if the extension is enabled. + * + * @param string|null $apcuPrefix + * + * @return void + */ + public function setApcuPrefix($apcuPrefix) + { + $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + * + * @return void + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + + if (null === $this->vendorDir) { + return; + } + + if ($prepend) { + self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; + } else { + unset(self::$registeredLoaders[$this->vendorDir]); + self::$registeredLoaders[$this->vendorDir] = $this; + } + } + + /** + * Unregisters this instance as an autoloader. + * + * @return void + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + + if (null !== $this->vendorDir) { + unset(self::$registeredLoaders[$this->vendorDir]); + } + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return true|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + $includeFile = self::$includeFile; + $includeFile($file); + + return true; + } + + return null; + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + return $file; + } + + /** + * Returns the currently registered loaders keyed by their corresponding vendor directories. + * + * @return array + */ + public static function getRegisteredLoaders() + { + return self::$registeredLoaders; + } + + /** + * @param string $class + * @param string $ext + * @return string|false + */ + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath . '\\'; + if (isset($this->prefixDirsPsr4[$search])) { + $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); + foreach ($this->prefixDirsPsr4[$search] as $dir) { + if (file_exists($file = $dir . $pathEnd)) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } + + /** + * @return void + */ + private static function initializeIncludeClosure() + { + if (self::$includeFile !== null) { + return; + } + + /** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + * + * @param string $file + * @return void + */ + self::$includeFile = \Closure::bind(static function($file) { + include $file; + }, null, null); + } +} diff --git a/api/vendor/composer/InstalledVersions.php b/api/vendor/composer/InstalledVersions.php new file mode 100644 index 0000000..51e734a --- /dev/null +++ b/api/vendor/composer/InstalledVersions.php @@ -0,0 +1,359 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer; + +use Composer\Autoload\ClassLoader; +use Composer\Semver\VersionParser; + +/** + * This class is copied in every Composer installed project and available to all + * + * See also https://getcomposer.org/doc/07-runtime.md#installed-versions + * + * To require its presence, you can require `composer-runtime-api ^2.0` + * + * @final + */ +class InstalledVersions +{ + /** + * @var mixed[]|null + * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array}|array{}|null + */ + private static $installed; + + /** + * @var bool|null + */ + private static $canGetVendors; + + /** + * @var array[] + * @psalm-var array}> + */ + private static $installedByVendor = array(); + + /** + * Returns a list of all package names which are present, either by being installed, replaced or provided + * + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackages() + { + $packages = array(); + foreach (self::getInstalled() as $installed) { + $packages[] = array_keys($installed['versions']); + } + + if (1 === \count($packages)) { + return $packages[0]; + } + + return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); + } + + /** + * Returns a list of all package names with a specific type e.g. 'library' + * + * @param string $type + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackagesByType($type) + { + $packagesByType = array(); + + foreach (self::getInstalled() as $installed) { + foreach ($installed['versions'] as $name => $package) { + if (isset($package['type']) && $package['type'] === $type) { + $packagesByType[] = $name; + } + } + } + + return $packagesByType; + } + + /** + * Checks whether the given package is installed + * + * This also returns true if the package name is provided or replaced by another package + * + * @param string $packageName + * @param bool $includeDevRequirements + * @return bool + */ + public static function isInstalled($packageName, $includeDevRequirements = true) + { + foreach (self::getInstalled() as $installed) { + if (isset($installed['versions'][$packageName])) { + return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false; + } + } + + return false; + } + + /** + * Checks whether the given package satisfies a version constraint + * + * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call: + * + * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3') + * + * @param VersionParser $parser Install composer/semver to have access to this class and functionality + * @param string $packageName + * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package + * @return bool + */ + public static function satisfies(VersionParser $parser, $packageName, $constraint) + { + $constraint = $parser->parseConstraints((string) $constraint); + $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); + + return $provided->matches($constraint); + } + + /** + * Returns a version constraint representing all the range(s) which are installed for a given package + * + * It is easier to use this via isInstalled() with the $constraint argument if you need to check + * whether a given version of a package is installed, and not just whether it exists + * + * @param string $packageName + * @return string Version constraint usable with composer/semver + */ + public static function getVersionRanges($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + $ranges = array(); + if (isset($installed['versions'][$packageName]['pretty_version'])) { + $ranges[] = $installed['versions'][$packageName]['pretty_version']; + } + if (array_key_exists('aliases', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); + } + if (array_key_exists('replaced', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); + } + if (array_key_exists('provided', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); + } + + return implode(' || ', $ranges); + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['version'])) { + return null; + } + + return $installed['versions'][$packageName]['version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getPrettyVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['pretty_version'])) { + return null; + } + + return $installed['versions'][$packageName]['pretty_version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference + */ + public static function getReference($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['reference'])) { + return null; + } + + return $installed['versions'][$packageName]['reference']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path. + */ + public static function getInstallPath($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @return array + * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool} + */ + public static function getRootPackage() + { + $installed = self::getInstalled(); + + return $installed[0]['root']; + } + + /** + * Returns the raw installed.php data for custom implementations + * + * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. + * @return array[] + * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} + */ + public static function getRawData() + { + @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED); + + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + self::$installed = include __DIR__ . '/installed.php'; + } else { + self::$installed = array(); + } + } + + return self::$installed; + } + + /** + * Returns the raw data of all installed.php which are currently loaded for custom implementations + * + * @return array[] + * @psalm-return list}> + */ + public static function getAllRawData() + { + return self::getInstalled(); + } + + /** + * Lets you reload the static array from another file + * + * This is only useful for complex integrations in which a project needs to use + * this class but then also needs to execute another project's autoloader in process, + * and wants to ensure both projects have access to their version of installed.php. + * + * A typical case would be PHPUnit, where it would need to make sure it reads all + * the data it needs from this class, then call reload() with + * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure + * the project in which it runs can then also use this class safely, without + * interference between PHPUnit's dependencies and the project's dependencies. + * + * @param array[] $data A vendor/composer/installed.php data set + * @return void + * + * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $data + */ + public static function reload($data) + { + self::$installed = $data; + self::$installedByVendor = array(); + } + + /** + * @return array[] + * @psalm-return list}> + */ + private static function getInstalled() + { + if (null === self::$canGetVendors) { + self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); + } + + $installed = array(); + + if (self::$canGetVendors) { + foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { + if (isset(self::$installedByVendor[$vendorDir])) { + $installed[] = self::$installedByVendor[$vendorDir]; + } elseif (is_file($vendorDir.'/composer/installed.php')) { + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ + $required = require $vendorDir.'/composer/installed.php'; + $installed[] = self::$installedByVendor[$vendorDir] = $required; + if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { + self::$installed = $installed[count($installed) - 1]; + } + } + } + } + + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ + $required = require __DIR__ . '/installed.php'; + self::$installed = $required; + } else { + self::$installed = array(); + } + } + + if (self::$installed !== array()) { + $installed[] = self::$installed; + } + + return $installed; + } +} diff --git a/api/vendor/composer/LICENSE b/api/vendor/composer/LICENSE new file mode 100644 index 0000000..62ecfd8 --- /dev/null +++ b/api/vendor/composer/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) Nils Adermann, Jordi Boggiano + +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. diff --git a/api/vendor/composer/autoload_classmap.php b/api/vendor/composer/autoload_classmap.php new file mode 100644 index 0000000..5490b88 --- /dev/null +++ b/api/vendor/composer/autoload_classmap.php @@ -0,0 +1,15 @@ + $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php', + 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php', + 'PhpToken' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php', + 'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php', + 'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php', + 'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php', +); diff --git a/api/vendor/composer/autoload_files.php b/api/vendor/composer/autoload_files.php new file mode 100644 index 0000000..b2c6d7b --- /dev/null +++ b/api/vendor/composer/autoload_files.php @@ -0,0 +1,15 @@ + $vendorDir . '/symfony/polyfill-php80/bootstrap.php', + '253c157292f75eb38082b5acb06f3f01' => $vendorDir . '/nikic/fast-route/src/functions.php', + '7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php', + '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php', + '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php', + 'b33e3d135e5d9e47d845c576147bda89' => $vendorDir . '/php-di/php-di/src/functions.php', +); diff --git a/api/vendor/composer/autoload_namespaces.php b/api/vendor/composer/autoload_namespaces.php new file mode 100644 index 0000000..15a2ff3 --- /dev/null +++ b/api/vendor/composer/autoload_namespaces.php @@ -0,0 +1,9 @@ + array($vendorDir . '/zounar/php-proxy'), + 'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'), + 'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'), + 'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'), + 'Slim\\Psr7\\' => array($vendorDir . '/slim/psr7/src'), + 'Slim\\' => array($vendorDir . '/slim/slim/Slim'), + 'Psr\\Log\\' => array($vendorDir . '/psr/log/src'), + 'Psr\\Http\\Server\\' => array($vendorDir . '/psr/http-server-handler/src', $vendorDir . '/psr/http-server-middleware/src'), + 'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src', $vendorDir . '/psr/http-factory/src'), + 'Psr\\Container\\' => array($vendorDir . '/psr/container/src'), + 'PhpOption\\' => array($vendorDir . '/phpoption/phpoption/src/PhpOption'), + 'Laravel\\SerializableClosure\\' => array($vendorDir . '/laravel/serializable-closure/src'), + 'Invoker\\' => array($vendorDir . '/php-di/invoker/src'), + 'GrahamCampbell\\ResultType\\' => array($vendorDir . '/graham-campbell/result-type/src'), + 'Fig\\Http\\Message\\' => array($vendorDir . '/fig/http-message-util/src'), + 'FastRoute\\' => array($vendorDir . '/nikic/fast-route/src'), + 'Dotenv\\' => array($vendorDir . '/vlucas/phpdotenv/src'), + 'DI\\' => array($vendorDir . '/php-di/php-di/src'), + 'App\\' => array($baseDir . '/src'), +); diff --git a/api/vendor/composer/autoload_real.php b/api/vendor/composer/autoload_real.php new file mode 100644 index 0000000..a13d610 --- /dev/null +++ b/api/vendor/composer/autoload_real.php @@ -0,0 +1,50 @@ +register(true); + + $filesToLoad = \Composer\Autoload\ComposerStaticInit922ee7e3fd54ca2747cf5ce18d09b50c::$files; + $requireFile = \Closure::bind(static function ($fileIdentifier, $file) { + if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { + $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; + + require $file; + } + }, null, null); + foreach ($filesToLoad as $fileIdentifier => $file) { + $requireFile($fileIdentifier, $file); + } + + return $loader; + } +} diff --git a/api/vendor/composer/autoload_static.php b/api/vendor/composer/autoload_static.php new file mode 100644 index 0000000..4041889 --- /dev/null +++ b/api/vendor/composer/autoload_static.php @@ -0,0 +1,166 @@ + __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php', + '253c157292f75eb38082b5acb06f3f01' => __DIR__ . '/..' . '/nikic/fast-route/src/functions.php', + '7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php', + '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php', + '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php', + 'b33e3d135e5d9e47d845c576147bda89' => __DIR__ . '/..' . '/php-di/php-di/src/functions.php', + ); + + public static $prefixLengthsPsr4 = array ( + 'Z' => + array ( + 'Zounar\\PHPProxy\\' => 16, + ), + 'S' => + array ( + 'Symfony\\Polyfill\\Php80\\' => 23, + 'Symfony\\Polyfill\\Mbstring\\' => 26, + 'Symfony\\Polyfill\\Ctype\\' => 23, + 'Slim\\Psr7\\' => 10, + 'Slim\\' => 5, + ), + 'P' => + array ( + 'Psr\\Log\\' => 8, + 'Psr\\Http\\Server\\' => 16, + 'Psr\\Http\\Message\\' => 17, + 'Psr\\Container\\' => 14, + 'PhpOption\\' => 10, + ), + 'L' => + array ( + 'Laravel\\SerializableClosure\\' => 28, + ), + 'I' => + array ( + 'Invoker\\' => 8, + ), + 'G' => + array ( + 'GrahamCampbell\\ResultType\\' => 26, + ), + 'F' => + array ( + 'Fig\\Http\\Message\\' => 17, + 'FastRoute\\' => 10, + ), + 'D' => + array ( + 'Dotenv\\' => 7, + 'DI\\' => 3, + ), + 'A' => + array ( + 'App\\' => 4, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'Zounar\\PHPProxy\\' => + array ( + 0 => __DIR__ . '/..' . '/zounar/php-proxy', + ), + 'Symfony\\Polyfill\\Php80\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-php80', + ), + 'Symfony\\Polyfill\\Mbstring\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring', + ), + 'Symfony\\Polyfill\\Ctype\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-ctype', + ), + 'Slim\\Psr7\\' => + array ( + 0 => __DIR__ . '/..' . '/slim/psr7/src', + ), + 'Slim\\' => + array ( + 0 => __DIR__ . '/..' . '/slim/slim/Slim', + ), + 'Psr\\Log\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/log/src', + ), + 'Psr\\Http\\Server\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/http-server-handler/src', + 1 => __DIR__ . '/..' . '/psr/http-server-middleware/src', + ), + 'Psr\\Http\\Message\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/http-message/src', + 1 => __DIR__ . '/..' . '/psr/http-factory/src', + ), + 'Psr\\Container\\' => + array ( + 0 => __DIR__ . '/..' . '/psr/container/src', + ), + 'PhpOption\\' => + array ( + 0 => __DIR__ . '/..' . '/phpoption/phpoption/src/PhpOption', + ), + 'Laravel\\SerializableClosure\\' => + array ( + 0 => __DIR__ . '/..' . '/laravel/serializable-closure/src', + ), + 'Invoker\\' => + array ( + 0 => __DIR__ . '/..' . '/php-di/invoker/src', + ), + 'GrahamCampbell\\ResultType\\' => + array ( + 0 => __DIR__ . '/..' . '/graham-campbell/result-type/src', + ), + 'Fig\\Http\\Message\\' => + array ( + 0 => __DIR__ . '/..' . '/fig/http-message-util/src', + ), + 'FastRoute\\' => + array ( + 0 => __DIR__ . '/..' . '/nikic/fast-route/src', + ), + 'Dotenv\\' => + array ( + 0 => __DIR__ . '/..' . '/vlucas/phpdotenv/src', + ), + 'DI\\' => + array ( + 0 => __DIR__ . '/..' . '/php-di/php-di/src', + ), + 'App\\' => + array ( + 0 => __DIR__ . '/../..' . '/src', + ), + ); + + public static $classMap = array ( + 'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php', + 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', + 'PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php', + 'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php', + 'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php', + 'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php', + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticInit922ee7e3fd54ca2747cf5ce18d09b50c::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInit922ee7e3fd54ca2747cf5ce18d09b50c::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInit922ee7e3fd54ca2747cf5ce18d09b50c::$classMap; + + }, null, ClassLoader::class); + } +} diff --git a/api/vendor/composer/installed.json b/api/vendor/composer/installed.json new file mode 100644 index 0000000..cf90aee --- /dev/null +++ b/api/vendor/composer/installed.json @@ -0,0 +1,1457 @@ +{ + "packages": [ + { + "name": "fig/http-message-util", + "version": "1.1.5", + "version_normalized": "1.1.5.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message-util.git", + "reference": "9d94dc0154230ac39e5bf89398b324a86f63f765" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message-util/zipball/9d94dc0154230ac39e5bf89398b324a86f63f765", + "reference": "9d94dc0154230ac39e5bf89398b324a86f63f765", + "shasum": "" + }, + "require": { + "php": "^5.3 || ^7.0 || ^8.0" + }, + "suggest": { + "psr/http-message": "The package containing the PSR-7 interfaces" + }, + "time": "2020-11-24T22:02:12+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Fig\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Utility classes and constants for use with PSR-7 (psr/http-message)", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "issues": "https://github.com/php-fig/http-message-util/issues", + "source": "https://github.com/php-fig/http-message-util/tree/1.1.5" + }, + "install-path": "../fig/http-message-util" + }, + { + "name": "graham-campbell/result-type", + "version": "v1.1.3", + "version_normalized": "1.1.3.0", + "source": { + "type": "git", + "url": "https://github.com/GrahamCampbell/Result-Type.git", + "reference": "3ba905c11371512af9d9bdd27d99b782216b6945" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/3ba905c11371512af9d9bdd27d99b782216b6945", + "reference": "3ba905c11371512af9d9bdd27d99b782216b6945", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.3" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" + }, + "time": "2024-07-20T21:45:45+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "GrahamCampbell\\ResultType\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "An Implementation Of The Result Type", + "keywords": [ + "Graham Campbell", + "GrahamCampbell", + "Result Type", + "Result-Type", + "result" + ], + "support": { + "issues": "https://github.com/GrahamCampbell/Result-Type/issues", + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type", + "type": "tidelift" + } + ], + "install-path": "../graham-campbell/result-type" + }, + { + "name": "laravel/serializable-closure", + "version": "v2.0.4", + "version_normalized": "2.0.4.0", + "source": { + "type": "git", + "url": "https://github.com/laravel/serializable-closure.git", + "reference": "b352cf0534aa1ae6b4d825d1e762e35d43f8a841" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/b352cf0534aa1ae6b4d825d1e762e35d43f8a841", + "reference": "b352cf0534aa1ae6b4d825d1e762e35d43f8a841", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "illuminate/support": "^10.0|^11.0|^12.0", + "nesbot/carbon": "^2.67|^3.0", + "pestphp/pest": "^2.36|^3.0", + "phpstan/phpstan": "^2.0", + "symfony/var-dumper": "^6.2.0|^7.0.0" + }, + "time": "2025-03-19T13:51:03+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Laravel\\SerializableClosure\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + }, + { + "name": "Nuno Maduro", + "email": "nuno@laravel.com" + } + ], + "description": "Laravel Serializable Closure provides an easy and secure way to serialize closures in PHP.", + "keywords": [ + "closure", + "laravel", + "serializable" + ], + "support": { + "issues": "https://github.com/laravel/serializable-closure/issues", + "source": "https://github.com/laravel/serializable-closure" + }, + "install-path": "../laravel/serializable-closure" + }, + { + "name": "nikic/fast-route", + "version": "v1.3.0", + "version_normalized": "1.3.0.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/FastRoute.git", + "reference": "181d480e08d9476e61381e04a71b34dc0432e812" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/FastRoute/zipball/181d480e08d9476e61381e04a71b34dc0432e812", + "reference": "181d480e08d9476e61381e04a71b34dc0432e812", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35|~5.7" + }, + "time": "2018-02-13T20:26:39+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "FastRoute\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov", + "email": "nikic@php.net" + } + ], + "description": "Fast request router for PHP", + "keywords": [ + "router", + "routing" + ], + "support": { + "issues": "https://github.com/nikic/FastRoute/issues", + "source": "https://github.com/nikic/FastRoute/tree/master" + }, + "install-path": "../nikic/fast-route" + }, + { + "name": "php-di/invoker", + "version": "2.3.7", + "version_normalized": "2.3.7.0", + "source": { + "type": "git", + "url": "https://github.com/PHP-DI/Invoker.git", + "reference": "3c1ddfdef181431fbc4be83378f6d036d59e81e1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-DI/Invoker/zipball/3c1ddfdef181431fbc4be83378f6d036d59e81e1", + "reference": "3c1ddfdef181431fbc4be83378f6d036d59e81e1", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "psr/container": "^1.0|^2.0" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "mnapoli/hard-mode": "~0.3.0", + "phpunit/phpunit": "^9.0 || ^10 || ^11 || ^12" + }, + "time": "2025-08-30T10:22:22+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Invoker\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Generic and extensible callable invoker", + "homepage": "https://github.com/PHP-DI/Invoker", + "keywords": [ + "callable", + "dependency", + "dependency-injection", + "injection", + "invoke", + "invoker" + ], + "support": { + "issues": "https://github.com/PHP-DI/Invoker/issues", + "source": "https://github.com/PHP-DI/Invoker/tree/2.3.7" + }, + "funding": [ + { + "url": "https://github.com/mnapoli", + "type": "github" + } + ], + "install-path": "../php-di/invoker" + }, + { + "name": "php-di/php-di", + "version": "7.1.1", + "version_normalized": "7.1.1.0", + "source": { + "type": "git", + "url": "https://github.com/PHP-DI/PHP-DI.git", + "reference": "f88054cc052e40dbe7b383c8817c19442d480352" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-DI/PHP-DI/zipball/f88054cc052e40dbe7b383c8817c19442d480352", + "reference": "f88054cc052e40dbe7b383c8817c19442d480352", + "shasum": "" + }, + "require": { + "laravel/serializable-closure": "^1.0 || ^2.0", + "php": ">=8.0", + "php-di/invoker": "^2.0", + "psr/container": "^1.1 || ^2.0" + }, + "provide": { + "psr/container-implementation": "^1.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3", + "friendsofphp/proxy-manager-lts": "^1", + "mnapoli/phpunit-easymock": "^1.3", + "phpunit/phpunit": "^9.6 || ^10 || ^11", + "vimeo/psalm": "^5|^6" + }, + "suggest": { + "friendsofphp/proxy-manager-lts": "Install it if you want to use lazy injection (version ^1)" + }, + "time": "2025-08-16T11:10:48+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "DI\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "The dependency injection container for humans", + "homepage": "https://php-di.org/", + "keywords": [ + "PSR-11", + "container", + "container-interop", + "dependency injection", + "di", + "ioc", + "psr11" + ], + "support": { + "issues": "https://github.com/PHP-DI/PHP-DI/issues", + "source": "https://github.com/PHP-DI/PHP-DI/tree/7.1.1" + }, + "funding": [ + { + "url": "https://github.com/mnapoli", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/php-di/php-di", + "type": "tidelift" + } + ], + "install-path": "../php-di/php-di" + }, + { + "name": "phpoption/phpoption", + "version": "1.9.4", + "version_normalized": "1.9.4.0", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/php-option.git", + "reference": "638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d", + "reference": "638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.44 || ^9.6.25 || ^10.5.53 || ^11.5.34" + }, + "time": "2025-08-21T11:53:16+00:00", + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "PhpOption\\": "src/PhpOption/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "https://github.com/schmittjoh" + }, + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "Option Type for PHP", + "keywords": [ + "language", + "option", + "php", + "type" + ], + "support": { + "issues": "https://github.com/schmittjoh/php-option/issues", + "source": "https://github.com/schmittjoh/php-option/tree/1.9.4" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption", + "type": "tidelift" + } + ], + "install-path": "../phpoption/phpoption" + }, + { + "name": "psr/container", + "version": "2.0.2", + "version_normalized": "2.0.2.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "time": "2021-11-05T16:47:00+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/2.0.2" + }, + "install-path": "../psr/container" + }, + { + "name": "psr/http-factory", + "version": "1.1.0", + "version_normalized": "1.1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "psr/http-message": "^1.0 || ^2.0" + }, + "time": "2024-04-15T12:06:14+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory" + }, + "install-path": "../psr/http-factory" + }, + { + "name": "psr/http-message", + "version": "2.0", + "version_normalized": "2.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "time": "2023-04-04T09:54:51+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/2.0" + }, + "install-path": "../psr/http-message" + }, + { + "name": "psr/http-server-handler", + "version": "1.0.2", + "version_normalized": "1.0.2.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-server-handler.git", + "reference": "84c4fb66179be4caaf8e97bd239203245302e7d4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-server-handler/zipball/84c4fb66179be4caaf8e97bd239203245302e7d4", + "reference": "84c4fb66179be4caaf8e97bd239203245302e7d4", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "time": "2023-04-10T20:06:20+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Http\\Server\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP server-side request handler", + "keywords": [ + "handler", + "http", + "http-interop", + "psr", + "psr-15", + "psr-7", + "request", + "response", + "server" + ], + "support": { + "source": "https://github.com/php-fig/http-server-handler/tree/1.0.2" + }, + "install-path": "../psr/http-server-handler" + }, + { + "name": "psr/http-server-middleware", + "version": "1.0.2", + "version_normalized": "1.0.2.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-server-middleware.git", + "reference": "c1481f747daaa6a0782775cd6a8c26a1bf4a3829" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-server-middleware/zipball/c1481f747daaa6a0782775cd6a8c26a1bf4a3829", + "reference": "c1481f747daaa6a0782775cd6a8c26a1bf4a3829", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "psr/http-message": "^1.0 || ^2.0", + "psr/http-server-handler": "^1.0" + }, + "time": "2023-04-11T06:14:47+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Http\\Server\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP server-side middleware", + "keywords": [ + "http", + "http-interop", + "middleware", + "psr", + "psr-15", + "psr-7", + "request", + "response" + ], + "support": { + "issues": "https://github.com/php-fig/http-server-middleware/issues", + "source": "https://github.com/php-fig/http-server-middleware/tree/1.0.2" + }, + "install-path": "../psr/http-server-middleware" + }, + { + "name": "psr/log", + "version": "3.0.2", + "version_normalized": "3.0.2.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "time": "2024-09-11T13:17:53+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "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/3.0.2" + }, + "install-path": "../psr/log" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "version_normalized": "3.0.3.0", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "time": "2019-03-08T08:55:37+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "install-path": "../ralouphie/getallheaders" + }, + { + "name": "slim/psr7", + "version": "1.7.1", + "version_normalized": "1.7.1.0", + "source": { + "type": "git", + "url": "https://github.com/slimphp/Slim-Psr7.git", + "reference": "fe98653e7983010aa85c1d137c9b9ad5a1cd187d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slimphp/Slim-Psr7/zipball/fe98653e7983010aa85c1d137c9b9ad5a1cd187d", + "reference": "fe98653e7983010aa85c1d137c9b9ad5a1cd187d", + "shasum": "" + }, + "require": { + "fig/http-message-util": "^1.1.5", + "php": "^8.0", + "psr/http-factory": "^1.1", + "psr/http-message": "^1.0 || ^2.0", + "ralouphie/getallheaders": "^3.0", + "symfony/polyfill-php80": "^1.29" + }, + "provide": { + "psr/http-factory-implementation": "^1.0", + "psr/http-message-implementation": "^1.0 || ^2.0" + }, + "require-dev": { + "adriansuter/php-autoload-override": "^1.4", + "ext-json": "*", + "http-interop/http-factory-tests": "^1.0 || ^2.0", + "php-http/psr7-integration-tests": "^1.4", + "phpspec/prophecy": "^1.19", + "phpspec/prophecy-phpunit": "^2.2", + "phpstan/phpstan": "^2.1", + "phpunit/phpunit": "^9.6 || ^10", + "squizlabs/php_codesniffer": "^3.10" + }, + "time": "2025-05-13T14:24:12+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Slim\\Psr7\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Josh Lockhart", + "email": "hello@joshlockhart.com", + "homepage": "https://joshlockhart.com" + }, + { + "name": "Andrew Smith", + "email": "a.smith@silentworks.co.uk", + "homepage": "https://silentworks.co.uk" + }, + { + "name": "Rob Allen", + "email": "rob@akrabat.com", + "homepage": "https://akrabat.com" + }, + { + "name": "Pierre Berube", + "email": "pierre@lgse.com", + "homepage": "https://www.lgse.com" + } + ], + "description": "Strict PSR-7 implementation", + "homepage": "https://www.slimframework.com", + "keywords": [ + "http", + "psr-7", + "psr7" + ], + "support": { + "issues": "https://github.com/slimphp/Slim-Psr7/issues", + "source": "https://github.com/slimphp/Slim-Psr7/tree/1.7.1" + }, + "install-path": "../slim/psr7" + }, + { + "name": "slim/slim", + "version": "4.15.0", + "version_normalized": "4.15.0.0", + "source": { + "type": "git", + "url": "https://github.com/slimphp/Slim.git", + "reference": "17eba5182975878a0ab9b27982cd2e2cfcb67ea2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slimphp/Slim/zipball/17eba5182975878a0ab9b27982cd2e2cfcb67ea2", + "reference": "17eba5182975878a0ab9b27982cd2e2cfcb67ea2", + "shasum": "" + }, + "require": { + "ext-json": "*", + "nikic/fast-route": "^1.3", + "php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", + "psr/container": "^1.0 || ^2.0", + "psr/http-factory": "^1.1", + "psr/http-message": "^1.1 || ^2.0", + "psr/http-server-handler": "^1.0", + "psr/http-server-middleware": "^1.0", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "require-dev": { + "adriansuter/php-autoload-override": "^1.4 || ^2", + "ext-simplexml": "*", + "guzzlehttp/psr7": "^2.6", + "httpsoft/http-message": "^1.1", + "httpsoft/http-server-request": "^1.1", + "laminas/laminas-diactoros": "^2.17 || ^3", + "nyholm/psr7": "^1.8", + "nyholm/psr7-server": "^1.1", + "phpspec/prophecy": "^1.19", + "phpspec/prophecy-phpunit": "^2.1", + "phpstan/phpstan": "^1 || ^2", + "phpunit/phpunit": "^9.6", + "slim/http": "^1.3", + "slim/psr7": "^1.6", + "squizlabs/php_codesniffer": "^3.10", + "vimeo/psalm": "^5 || ^6" + }, + "suggest": { + "ext-simplexml": "Needed to support XML format in BodyParsingMiddleware", + "ext-xml": "Needed to support XML format in BodyParsingMiddleware", + "php-di/php-di": "PHP-DI is the recommended container library to be used with Slim", + "slim/psr7": "Slim PSR-7 implementation. See https://www.slimframework.com/docs/v4/start/installation.html for more information." + }, + "time": "2025-08-20T18:16:16+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Slim\\": "Slim" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Josh Lockhart", + "email": "hello@joshlockhart.com", + "homepage": "https://joshlockhart.com" + }, + { + "name": "Andrew Smith", + "email": "a.smith@silentworks.co.uk", + "homepage": "https://silentworks.co.uk" + }, + { + "name": "Rob Allen", + "email": "rob@akrabat.com", + "homepage": "https://akrabat.com" + }, + { + "name": "Pierre Berube", + "email": "pierre@lgse.com", + "homepage": "https://www.lgse.com" + }, + { + "name": "Gabriel Manricks", + "email": "gmanricks@me.com", + "homepage": "http://gabrielmanricks.com" + } + ], + "description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs", + "homepage": "https://www.slimframework.com", + "keywords": [ + "api", + "framework", + "micro", + "router" + ], + "support": { + "docs": "https://www.slimframework.com/docs/v4/", + "forum": "https://discourse.slimframework.com/", + "irc": "irc://irc.freenode.net:6667/slimphp", + "issues": "https://github.com/slimphp/Slim/issues", + "rss": "https://www.slimframework.com/blog/feed.rss", + "slack": "https://slimphp.slack.com/", + "source": "https://github.com/slimphp/Slim", + "wiki": "https://github.com/slimphp/Slim/wiki" + }, + "funding": [ + { + "url": "https://opencollective.com/slimphp", + "type": "open_collective" + }, + { + "url": "https://tidelift.com/funding/github/packagist/slim/slim", + "type": "tidelift" + } + ], + "install-path": "../slim/slim" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.33.0", + "version_normalized": "1.33.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "time": "2024-09-09T11:45:10+00:00", + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-ctype" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.33.0", + "version_normalized": "1.33.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "php": ">=7.2" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "time": "2024-12-23T08:48:59+00:00", + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-mbstring" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.33.0", + "version_normalized": "1.33.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "time": "2025-01-02T08:10:11+00:00", + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "installation-source": "dist", + "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.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "install-path": "../symfony/polyfill-php80" + }, + { + "name": "vlucas/phpdotenv", + "version": "v5.6.2", + "version_normalized": "5.6.2.0", + "source": { + "type": "git", + "url": "https://github.com/vlucas/phpdotenv.git", + "reference": "24ac4c74f91ee2c193fa1aaa5c249cb0822809af" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/24ac4c74f91ee2c193fa1aaa5c249cb0822809af", + "reference": "24ac4c74f91ee2c193fa1aaa5c249cb0822809af", + "shasum": "" + }, + "require": { + "ext-pcre": "*", + "graham-campbell/result-type": "^1.1.3", + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.3", + "symfony/polyfill-ctype": "^1.24", + "symfony/polyfill-mbstring": "^1.24", + "symfony/polyfill-php80": "^1.24" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-filter": "*", + "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" + }, + "suggest": { + "ext-filter": "Required to use the boolean validator." + }, + "time": "2025-04-30T23:37:27+00:00", + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "5.6-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Dotenv\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Vance Lucas", + "email": "vance@vancelucas.com", + "homepage": "https://github.com/vlucas" + } + ], + "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "support": { + "issues": "https://github.com/vlucas/phpdotenv/issues", + "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.2" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", + "type": "tidelift" + } + ], + "install-path": "../vlucas/phpdotenv" + }, + { + "name": "zounar/php-proxy", + "version": "1.1.0", + "version_normalized": "1.1.0.0", + "source": { + "type": "git", + "url": "https://github.com/zounar/php-proxy.git", + "reference": "67e83a8bd7489b220a94402664fa22d9e21e3d40" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zounar/php-proxy/zipball/67e83a8bd7489b220a94402664fa22d9e21e3d40", + "reference": "67e83a8bd7489b220a94402664fa22d9e21e3d40", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-zlib": "*", + "php": ">=5.6.0" + }, + "time": "2021-03-28T19:22:45+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Zounar\\PHPProxy\\": "./" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "unlicense" + ], + "authors": [ + { + "name": "Robin Zounar", + "homepage": "https://zounar.me" + } + ], + "description": "Forward your HTTP/HTTPS requests to another server.", + "homepage": "https://github.com/zounar/php-proxy", + "keywords": [ + "curl", + "curlphp", + "http", + "http-proxy", + "php", + "php-proxy", + "proxy", + "proxy-script" + ], + "support": { + "docs": "https://github.com/zounar/php-proxy/blob/master/README.md", + "issues": "https://github.com/zounar/php-proxy/issues", + "source": "https://github.com/zounar/php-proxy" + }, + "install-path": "../zounar/php-proxy" + } + ], + "dev": true, + "dev-package-names": [] +} diff --git a/api/vendor/composer/installed.php b/api/vendor/composer/installed.php new file mode 100644 index 0000000..1b58d14 --- /dev/null +++ b/api/vendor/composer/installed.php @@ -0,0 +1,230 @@ + array( + 'name' => '__root__', + 'pretty_version' => 'dev-main', + 'version' => 'dev-main', + 'reference' => 'a3f5b5a0cf9cf2b9b6c979be8bbe2d440d15cd10', + 'type' => 'library', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'dev' => true, + ), + 'versions' => array( + '__root__' => array( + 'pretty_version' => 'dev-main', + 'version' => 'dev-main', + 'reference' => 'a3f5b5a0cf9cf2b9b6c979be8bbe2d440d15cd10', + 'type' => 'library', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'fig/http-message-util' => array( + 'pretty_version' => '1.1.5', + 'version' => '1.1.5.0', + 'reference' => '9d94dc0154230ac39e5bf89398b324a86f63f765', + 'type' => 'library', + 'install_path' => __DIR__ . '/../fig/http-message-util', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'graham-campbell/result-type' => array( + 'pretty_version' => 'v1.1.3', + 'version' => '1.1.3.0', + 'reference' => '3ba905c11371512af9d9bdd27d99b782216b6945', + 'type' => 'library', + 'install_path' => __DIR__ . '/../graham-campbell/result-type', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'laravel/serializable-closure' => array( + 'pretty_version' => 'v2.0.4', + 'version' => '2.0.4.0', + 'reference' => 'b352cf0534aa1ae6b4d825d1e762e35d43f8a841', + 'type' => 'library', + 'install_path' => __DIR__ . '/../laravel/serializable-closure', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'nikic/fast-route' => array( + 'pretty_version' => 'v1.3.0', + 'version' => '1.3.0.0', + 'reference' => '181d480e08d9476e61381e04a71b34dc0432e812', + 'type' => 'library', + 'install_path' => __DIR__ . '/../nikic/fast-route', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'php-di/invoker' => array( + 'pretty_version' => '2.3.7', + 'version' => '2.3.7.0', + 'reference' => '3c1ddfdef181431fbc4be83378f6d036d59e81e1', + 'type' => 'library', + 'install_path' => __DIR__ . '/../php-di/invoker', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'php-di/php-di' => array( + 'pretty_version' => '7.1.1', + 'version' => '7.1.1.0', + 'reference' => 'f88054cc052e40dbe7b383c8817c19442d480352', + 'type' => 'library', + 'install_path' => __DIR__ . '/../php-di/php-di', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'phpoption/phpoption' => array( + 'pretty_version' => '1.9.4', + 'version' => '1.9.4.0', + 'reference' => '638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d', + 'type' => 'library', + 'install_path' => __DIR__ . '/../phpoption/phpoption', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/container' => array( + 'pretty_version' => '2.0.2', + 'version' => '2.0.2.0', + 'reference' => 'c71ecc56dfe541dbd90c5360474fbc405f8d5963', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/container', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/container-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '^1.0', + ), + ), + 'psr/http-factory' => array( + 'pretty_version' => '1.1.0', + 'version' => '1.1.0.0', + 'reference' => '2b4765fddfe3b508ac62f829e852b1501d3f6e8a', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/http-factory', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/http-factory-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '^1.0', + ), + ), + 'psr/http-message' => array( + 'pretty_version' => '2.0', + 'version' => '2.0.0.0', + 'reference' => '402d35bcb92c70c026d1a6a9883f06b2ead23d71', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/http-message', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/http-message-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '^1.0 || ^2.0', + ), + ), + 'psr/http-server-handler' => array( + 'pretty_version' => '1.0.2', + 'version' => '1.0.2.0', + 'reference' => '84c4fb66179be4caaf8e97bd239203245302e7d4', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/http-server-handler', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/http-server-middleware' => array( + 'pretty_version' => '1.0.2', + 'version' => '1.0.2.0', + 'reference' => 'c1481f747daaa6a0782775cd6a8c26a1bf4a3829', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/http-server-middleware', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'psr/log' => array( + 'pretty_version' => '3.0.2', + 'version' => '3.0.2.0', + 'reference' => 'f16e1d5863e37f8d8c2a01719f5b34baa2b714d3', + 'type' => 'library', + 'install_path' => __DIR__ . '/../psr/log', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'ralouphie/getallheaders' => array( + 'pretty_version' => '3.0.3', + 'version' => '3.0.3.0', + 'reference' => '120b605dfeb996808c31b6477290a714d356e822', + 'type' => 'library', + 'install_path' => __DIR__ . '/../ralouphie/getallheaders', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'slim/psr7' => array( + 'pretty_version' => '1.7.1', + 'version' => '1.7.1.0', + 'reference' => 'fe98653e7983010aa85c1d137c9b9ad5a1cd187d', + 'type' => 'library', + 'install_path' => __DIR__ . '/../slim/psr7', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'slim/slim' => array( + 'pretty_version' => '4.15.0', + 'version' => '4.15.0.0', + 'reference' => '17eba5182975878a0ab9b27982cd2e2cfcb67ea2', + 'type' => 'library', + 'install_path' => __DIR__ . '/../slim/slim', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/polyfill-ctype' => array( + 'pretty_version' => 'v1.33.0', + 'version' => '1.33.0.0', + 'reference' => 'a3cc8b044a6ea513310cbd48ef7333b384945638', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-ctype', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/polyfill-mbstring' => array( + 'pretty_version' => 'v1.33.0', + 'version' => '1.33.0.0', + 'reference' => '6d857f4d76bd4b343eac26d6b539585d2bc56493', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-mbstring', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/polyfill-php80' => array( + 'pretty_version' => 'v1.33.0', + 'version' => '1.33.0.0', + 'reference' => '0cc9dd0f17f61d8131e7df6b84bd344899fe2608', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-php80', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'vlucas/phpdotenv' => array( + 'pretty_version' => 'v5.6.2', + 'version' => '5.6.2.0', + 'reference' => '24ac4c74f91ee2c193fa1aaa5c249cb0822809af', + 'type' => 'library', + 'install_path' => __DIR__ . '/../vlucas/phpdotenv', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'zounar/php-proxy' => array( + 'pretty_version' => '1.1.0', + 'version' => '1.1.0.0', + 'reference' => '67e83a8bd7489b220a94402664fa22d9e21e3d40', + 'type' => 'library', + 'install_path' => __DIR__ . '/../zounar/php-proxy', + 'aliases' => array(), + 'dev_requirement' => false, + ), + ), +); diff --git a/api/vendor/composer/platform_check.php b/api/vendor/composer/platform_check.php new file mode 100644 index 0000000..4c3a5d6 --- /dev/null +++ b/api/vendor/composer/platform_check.php @@ -0,0 +1,26 @@ += 80100)) { + $issues[] = 'Your Composer dependencies require a PHP version ">= 8.1.0". You are running ' . PHP_VERSION . '.'; +} + +if ($issues) { + if (!headers_sent()) { + header('HTTP/1.1 500 Internal Server Error'); + } + if (!ini_get('display_errors')) { + if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { + fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL); + } elseif (!headers_sent()) { + echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL; + } + } + trigger_error( + 'Composer detected issues in your platform: ' . implode(' ', $issues), + E_USER_ERROR + ); +} diff --git a/api/vendor/fig/http-message-util/.gitignore b/api/vendor/fig/http-message-util/.gitignore new file mode 100644 index 0000000..48b8bf9 --- /dev/null +++ b/api/vendor/fig/http-message-util/.gitignore @@ -0,0 +1 @@ +vendor/ diff --git a/api/vendor/fig/http-message-util/CHANGELOG.md b/api/vendor/fig/http-message-util/CHANGELOG.md new file mode 100644 index 0000000..1a02e54 --- /dev/null +++ b/api/vendor/fig/http-message-util/CHANGELOG.md @@ -0,0 +1,147 @@ +# Changelog + +All notable changes to this project will be documented in this file, in reverse chronological order by release. + +## 1.1.5 - 2020-11-24 + +### Added + +- [#19](https://github.com/php-fig/http-message-util/pull/19) adds support for PHP 8. + +### Changed + +- Nothing. + +### Deprecated + +- Nothing. + +### Removed + +- Nothing. + +### Fixed + +- Nothing. + +## 1.1.4 - 2020-02-05 + +### Added + +- Nothing. + +### Changed + +- Nothing. + +### Deprecated + +- Nothing. + +### Removed + +- [#15](https://github.com/php-fig/http-message-util/pull/15) removes the dependency on psr/http-message, as it is not technically necessary for usage of this package. + +### Fixed + +- Nothing. + +## 1.1.3 - 2018-11-19 + +### Added + +- [#10](https://github.com/php-fig/http-message-util/pull/10) adds the constants `StatusCodeInterface::STATUS_EARLY_HINTS` (103) and + `StatusCodeInterface::STATUS_TOO_EARLY` (425). + +### Changed + +- Nothing. + +### Deprecated + +- Nothing. + +### Removed + +- Nothing. + +### Fixed + +- Nothing. + +## 1.1.2 - 2017-02-09 + +### Added + +- [#4](https://github.com/php-fig/http-message-util/pull/4) adds the constant + `StatusCodeInterface::STATUS_MISDIRECTED_REQUEST` (421). + +### Deprecated + +- Nothing. + +### Removed + +- Nothing. + +### Fixed + +- Nothing. + +## 1.1.1 - 2017-02-06 + +### Added + +- [#3](https://github.com/php-fig/http-message-util/pull/3) adds the constant + `StatusCodeInterface::STATUS_IM_A_TEAPOT` (418). + +### Deprecated + +- Nothing. + +### Removed + +- Nothing. + +### Fixed + +- Nothing. + +## 1.1.0 - 2016-09-19 + +### Added + +- [#1](https://github.com/php-fig/http-message-util/pull/1) adds + `Fig\Http\Message\StatusCodeInterface`, with constants named after common + status reason phrases, with values indicating the status codes themselves. + +### Deprecated + +- Nothing. + +### Removed + +- Nothing. + +### Fixed + +- Nothing. + +## 1.0.0 - 2017-08-05 + +### Added + +- Adds `Fig\Http\Message\RequestMethodInterface`, with constants covering the + most common HTTP request methods as specified by the IETF. + +### Deprecated + +- Nothing. + +### Removed + +- Nothing. + +### Fixed + +- Nothing. diff --git a/api/vendor/fig/http-message-util/LICENSE b/api/vendor/fig/http-message-util/LICENSE new file mode 100644 index 0000000..e2fa347 --- /dev/null +++ b/api/vendor/fig/http-message-util/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2016 PHP Framework Interoperability Group + +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. diff --git a/api/vendor/fig/http-message-util/README.md b/api/vendor/fig/http-message-util/README.md new file mode 100644 index 0000000..ea5b5aa --- /dev/null +++ b/api/vendor/fig/http-message-util/README.md @@ -0,0 +1,17 @@ +# PSR Http Message Util + +This repository holds utility classes and constants to facilitate common +operations of [PSR-7](https://www.php-fig.org/psr/psr-7/); the primary purpose is +to provide constants for referring to request methods, response status codes and +messages, and potentially common headers. + +Implementation of PSR-7 interfaces is **not** within the scope of this package. + +## Installation + +Install by adding the package as a [Composer](https://getcomposer.org) +requirement: + +```bash +$ composer require fig/http-message-util +``` diff --git a/api/vendor/fig/http-message-util/composer.json b/api/vendor/fig/http-message-util/composer.json new file mode 100644 index 0000000..8645893 --- /dev/null +++ b/api/vendor/fig/http-message-util/composer.json @@ -0,0 +1,28 @@ +{ + "name": "fig/http-message-util", + "description": "Utility classes and constants for use with PSR-7 (psr/http-message)", + "keywords": ["psr", "psr-7", "http", "http-message", "request", "response"], + "license": "MIT", + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "require": { + "php": "^5.3 || ^7.0 || ^8.0" + }, + "suggest": { + "psr/http-message": "The package containing the PSR-7 interfaces" + }, + "autoload": { + "psr-4": { + "Fig\\Http\\Message\\": "src/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + } +} diff --git a/api/vendor/fig/http-message-util/src/RequestMethodInterface.php b/api/vendor/fig/http-message-util/src/RequestMethodInterface.php new file mode 100644 index 0000000..97d9a93 --- /dev/null +++ b/api/vendor/fig/http-message-util/src/RequestMethodInterface.php @@ -0,0 +1,34 @@ + + * class RequestFactory implements RequestMethodInterface + * { + * public static function factory( + * $uri = '/', + * $method = self::METHOD_GET, + * $data = [] + * ) { + * } + * } + * + */ +interface RequestMethodInterface +{ + const METHOD_HEAD = 'HEAD'; + const METHOD_GET = 'GET'; + const METHOD_POST = 'POST'; + const METHOD_PUT = 'PUT'; + const METHOD_PATCH = 'PATCH'; + const METHOD_DELETE = 'DELETE'; + const METHOD_PURGE = 'PURGE'; + const METHOD_OPTIONS = 'OPTIONS'; + const METHOD_TRACE = 'TRACE'; + const METHOD_CONNECT = 'CONNECT'; +} diff --git a/api/vendor/fig/http-message-util/src/StatusCodeInterface.php b/api/vendor/fig/http-message-util/src/StatusCodeInterface.php new file mode 100644 index 0000000..99b7e78 --- /dev/null +++ b/api/vendor/fig/http-message-util/src/StatusCodeInterface.php @@ -0,0 +1,107 @@ + + * class ResponseFactory implements StatusCodeInterface + * { + * public function createResponse($code = self::STATUS_OK) + * { + * } + * } + * + */ +interface StatusCodeInterface +{ + // Informational 1xx + const STATUS_CONTINUE = 100; + const STATUS_SWITCHING_PROTOCOLS = 101; + const STATUS_PROCESSING = 102; + const STATUS_EARLY_HINTS = 103; + // Successful 2xx + const STATUS_OK = 200; + const STATUS_CREATED = 201; + const STATUS_ACCEPTED = 202; + const STATUS_NON_AUTHORITATIVE_INFORMATION = 203; + const STATUS_NO_CONTENT = 204; + const STATUS_RESET_CONTENT = 205; + const STATUS_PARTIAL_CONTENT = 206; + const STATUS_MULTI_STATUS = 207; + const STATUS_ALREADY_REPORTED = 208; + const STATUS_IM_USED = 226; + // Redirection 3xx + const STATUS_MULTIPLE_CHOICES = 300; + const STATUS_MOVED_PERMANENTLY = 301; + const STATUS_FOUND = 302; + const STATUS_SEE_OTHER = 303; + const STATUS_NOT_MODIFIED = 304; + const STATUS_USE_PROXY = 305; + const STATUS_RESERVED = 306; + const STATUS_TEMPORARY_REDIRECT = 307; + const STATUS_PERMANENT_REDIRECT = 308; + // Client Errors 4xx + const STATUS_BAD_REQUEST = 400; + const STATUS_UNAUTHORIZED = 401; + const STATUS_PAYMENT_REQUIRED = 402; + const STATUS_FORBIDDEN = 403; + const STATUS_NOT_FOUND = 404; + const STATUS_METHOD_NOT_ALLOWED = 405; + const STATUS_NOT_ACCEPTABLE = 406; + const STATUS_PROXY_AUTHENTICATION_REQUIRED = 407; + const STATUS_REQUEST_TIMEOUT = 408; + const STATUS_CONFLICT = 409; + const STATUS_GONE = 410; + const STATUS_LENGTH_REQUIRED = 411; + const STATUS_PRECONDITION_FAILED = 412; + const STATUS_PAYLOAD_TOO_LARGE = 413; + const STATUS_URI_TOO_LONG = 414; + const STATUS_UNSUPPORTED_MEDIA_TYPE = 415; + const STATUS_RANGE_NOT_SATISFIABLE = 416; + const STATUS_EXPECTATION_FAILED = 417; + const STATUS_IM_A_TEAPOT = 418; + const STATUS_MISDIRECTED_REQUEST = 421; + const STATUS_UNPROCESSABLE_ENTITY = 422; + const STATUS_LOCKED = 423; + const STATUS_FAILED_DEPENDENCY = 424; + const STATUS_TOO_EARLY = 425; + const STATUS_UPGRADE_REQUIRED = 426; + const STATUS_PRECONDITION_REQUIRED = 428; + const STATUS_TOO_MANY_REQUESTS = 429; + const STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE = 431; + const STATUS_UNAVAILABLE_FOR_LEGAL_REASONS = 451; + // Server Errors 5xx + const STATUS_INTERNAL_SERVER_ERROR = 500; + const STATUS_NOT_IMPLEMENTED = 501; + const STATUS_BAD_GATEWAY = 502; + const STATUS_SERVICE_UNAVAILABLE = 503; + const STATUS_GATEWAY_TIMEOUT = 504; + const STATUS_VERSION_NOT_SUPPORTED = 505; + const STATUS_VARIANT_ALSO_NEGOTIATES = 506; + const STATUS_INSUFFICIENT_STORAGE = 507; + const STATUS_LOOP_DETECTED = 508; + const STATUS_NOT_EXTENDED = 510; + const STATUS_NETWORK_AUTHENTICATION_REQUIRED = 511; +} diff --git a/api/vendor/graham-campbell/result-type/LICENSE b/api/vendor/graham-campbell/result-type/LICENSE new file mode 100644 index 0000000..8e7c898 --- /dev/null +++ b/api/vendor/graham-campbell/result-type/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2020-2024 Graham Campbell + +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. diff --git a/api/vendor/graham-campbell/result-type/composer.json b/api/vendor/graham-campbell/result-type/composer.json new file mode 100644 index 0000000..32bfc81 --- /dev/null +++ b/api/vendor/graham-campbell/result-type/composer.json @@ -0,0 +1,33 @@ +{ + "name": "graham-campbell/result-type", + "description": "An Implementation Of The Result Type", + "keywords": ["result", "result-type", "Result", "Result Type", "Result-Type", "Graham Campbell", "GrahamCampbell"], + "license": "MIT", + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "require": { + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.3" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" + }, + "autoload": { + "psr-4": { + "GrahamCampbell\\ResultType\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "GrahamCampbell\\Tests\\ResultType\\": "tests/" + } + }, + "config": { + "preferred-install": "dist" + } +} diff --git a/api/vendor/graham-campbell/result-type/src/Error.php b/api/vendor/graham-campbell/result-type/src/Error.php new file mode 100644 index 0000000..2c37c3e --- /dev/null +++ b/api/vendor/graham-campbell/result-type/src/Error.php @@ -0,0 +1,121 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace GrahamCampbell\ResultType; + +use PhpOption\None; +use PhpOption\Some; + +/** + * @template T + * @template E + * + * @extends \GrahamCampbell\ResultType\Result + */ +final class Error extends Result +{ + /** + * @var E + */ + private $value; + + /** + * Internal constructor for an error value. + * + * @param E $value + * + * @return void + */ + private function __construct($value) + { + $this->value = $value; + } + + /** + * Create a new error value. + * + * @template F + * + * @param F $value + * + * @return \GrahamCampbell\ResultType\Result + */ + public static function create($value) + { + return new self($value); + } + + /** + * Get the success option value. + * + * @return \PhpOption\Option + */ + public function success() + { + return None::create(); + } + + /** + * Map over the success value. + * + * @template S + * + * @param callable(T):S $f + * + * @return \GrahamCampbell\ResultType\Result + */ + public function map(callable $f) + { + return self::create($this->value); + } + + /** + * Flat map over the success value. + * + * @template S + * @template F + * + * @param callable(T):\GrahamCampbell\ResultType\Result $f + * + * @return \GrahamCampbell\ResultType\Result + */ + public function flatMap(callable $f) + { + /** @var \GrahamCampbell\ResultType\Result */ + return self::create($this->value); + } + + /** + * Get the error option value. + * + * @return \PhpOption\Option + */ + public function error() + { + return Some::create($this->value); + } + + /** + * Map over the error value. + * + * @template F + * + * @param callable(E):F $f + * + * @return \GrahamCampbell\ResultType\Result + */ + public function mapError(callable $f) + { + return self::create($f($this->value)); + } +} diff --git a/api/vendor/graham-campbell/result-type/src/Result.php b/api/vendor/graham-campbell/result-type/src/Result.php new file mode 100644 index 0000000..8c67bcd --- /dev/null +++ b/api/vendor/graham-campbell/result-type/src/Result.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace GrahamCampbell\ResultType; + +/** + * @template T + * @template E + */ +abstract class Result +{ + /** + * Get the success option value. + * + * @return \PhpOption\Option + */ + abstract public function success(); + + /** + * Map over the success value. + * + * @template S + * + * @param callable(T):S $f + * + * @return \GrahamCampbell\ResultType\Result + */ + abstract public function map(callable $f); + + /** + * Flat map over the success value. + * + * @template S + * @template F + * + * @param callable(T):\GrahamCampbell\ResultType\Result $f + * + * @return \GrahamCampbell\ResultType\Result + */ + abstract public function flatMap(callable $f); + + /** + * Get the error option value. + * + * @return \PhpOption\Option + */ + abstract public function error(); + + /** + * Map over the error value. + * + * @template F + * + * @param callable(E):F $f + * + * @return \GrahamCampbell\ResultType\Result + */ + abstract public function mapError(callable $f); +} diff --git a/api/vendor/graham-campbell/result-type/src/Success.php b/api/vendor/graham-campbell/result-type/src/Success.php new file mode 100644 index 0000000..27cd85e --- /dev/null +++ b/api/vendor/graham-campbell/result-type/src/Success.php @@ -0,0 +1,120 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace GrahamCampbell\ResultType; + +use PhpOption\None; +use PhpOption\Some; + +/** + * @template T + * @template E + * + * @extends \GrahamCampbell\ResultType\Result + */ +final class Success extends Result +{ + /** + * @var T + */ + private $value; + + /** + * Internal constructor for a success value. + * + * @param T $value + * + * @return void + */ + private function __construct($value) + { + $this->value = $value; + } + + /** + * Create a new error value. + * + * @template S + * + * @param S $value + * + * @return \GrahamCampbell\ResultType\Result + */ + public static function create($value) + { + return new self($value); + } + + /** + * Get the success option value. + * + * @return \PhpOption\Option + */ + public function success() + { + return Some::create($this->value); + } + + /** + * Map over the success value. + * + * @template S + * + * @param callable(T):S $f + * + * @return \GrahamCampbell\ResultType\Result + */ + public function map(callable $f) + { + return self::create($f($this->value)); + } + + /** + * Flat map over the success value. + * + * @template S + * @template F + * + * @param callable(T):\GrahamCampbell\ResultType\Result $f + * + * @return \GrahamCampbell\ResultType\Result + */ + public function flatMap(callable $f) + { + return $f($this->value); + } + + /** + * Get the error option value. + * + * @return \PhpOption\Option + */ + public function error() + { + return None::create(); + } + + /** + * Map over the error value. + * + * @template F + * + * @param callable(E):F $f + * + * @return \GrahamCampbell\ResultType\Result + */ + public function mapError(callable $f) + { + return self::create($this->value); + } +} diff --git a/api/vendor/laravel/serializable-closure/LICENSE.md b/api/vendor/laravel/serializable-closure/LICENSE.md new file mode 100644 index 0000000..79810c8 --- /dev/null +++ b/api/vendor/laravel/serializable-closure/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) Taylor Otwell + +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. diff --git a/api/vendor/laravel/serializable-closure/README.md b/api/vendor/laravel/serializable-closure/README.md new file mode 100644 index 0000000..ee0d01a --- /dev/null +++ b/api/vendor/laravel/serializable-closure/README.md @@ -0,0 +1,73 @@ +# Serializable Closure + + + Build Status + + + Total Downloads + + + Latest Stable Version + + + License + + +## Introduction + +> This project is a fork of the excellent [opis/closure: 3.x](https://github.com/opis/closure) package. At Laravel, we decided to fork this package as the upcoming version [4.x](https://github.com/opis/closure) is a complete rewrite on top of the [FFI extension](https://www.php.net/manual/en/book.ffi.php). As Laravel is a web framework, and FFI is not enabled by default in web requests, this fork allows us to keep using the `3.x` series while adding support for new PHP versions. + +Laravel Serializable Closure provides an easy and secure way to **serialize closures in PHP**. + +## Official Documentation + +### Installation + +> **Requires [PHP 7.4+](https://php.net/releases/)** + +First, install Laravel Serializable Closure via the [Composer](https://getcomposer.org/) package manager: + +```bash +composer require laravel/serializable-closure +``` + +### Usage + +You may serialize a closure this way: + +```php +use Laravel\SerializableClosure\SerializableClosure; + +$closure = fn () => 'james'; + +// Recommended +SerializableClosure::setSecretKey('secret'); + +$serialized = serialize(new SerializableClosure($closure)); +$closure = unserialize($serialized)->getClosure(); + +echo $closure(); // james; +``` + +### Caveats + +* Anonymous classes cannot be created within closures. +* Attributes cannot be used within closures. +* Serializing closures on REPL environments like Laravel Tinker is not supported. +* Serializing closures that reference objects with readonly properties is not supported. + +## Contributing + +Thank you for considering contributing to Serializable Closure! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions). + +## Code of Conduct + +In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct). + +## Security Vulnerabilities + +Please review [our security policy](https://github.com/laravel/serializable-closure/security/policy) on how to report security vulnerabilities. + +## License + +Serializable Closure is open-sourced software licensed under the [MIT license](LICENSE.md). diff --git a/api/vendor/laravel/serializable-closure/composer.json b/api/vendor/laravel/serializable-closure/composer.json new file mode 100644 index 0000000..db744e9 --- /dev/null +++ b/api/vendor/laravel/serializable-closure/composer.json @@ -0,0 +1,53 @@ +{ + "name": "laravel/serializable-closure", + "description": "Laravel Serializable Closure provides an easy and secure way to serialize closures in PHP.", + "keywords": ["laravel", "Serializable", "closure"], + "license": "MIT", + "support": { + "issues": "https://github.com/laravel/serializable-closure/issues", + "source": "https://github.com/laravel/serializable-closure" + }, + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + }, + { + "name": "Nuno Maduro", + "email": "nuno@laravel.com" + } + ], + "require": { + "php": "^8.1" + }, + "require-dev": { + "illuminate/support": "^10.0|^11.0|^12.0", + "nesbot/carbon": "^2.67|^3.0", + "pestphp/pest": "^2.36|^3.0", + "phpstan/phpstan": "^2.0", + "symfony/var-dumper": "^6.2.0|^7.0.0" + }, + "autoload": { + "psr-4": { + "Laravel\\SerializableClosure\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Tests\\": "tests/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "config": { + "sort-packages": true, + "allow-plugins": { + "pestphp/pest-plugin": true + } + }, + "minimum-stability": "dev", + "prefer-stable": true +} diff --git a/api/vendor/laravel/serializable-closure/src/Contracts/Serializable.php b/api/vendor/laravel/serializable-closure/src/Contracts/Serializable.php new file mode 100644 index 0000000..1a62922 --- /dev/null +++ b/api/vendor/laravel/serializable-closure/src/Contracts/Serializable.php @@ -0,0 +1,20 @@ +serializable = Serializers\Signed::$signer + ? new Serializers\Signed($closure) + : new Serializers\Native($closure); + } + + /** + * Resolve the closure with the given arguments. + * + * @return mixed + */ + public function __invoke() + { + return call_user_func_array($this->serializable, func_get_args()); + } + + /** + * Gets the closure. + * + * @return \Closure + */ + public function getClosure() + { + return $this->serializable->getClosure(); + } + + /** + * Create a new unsigned serializable closure instance. + * + * @param Closure $closure + * @return \Laravel\SerializableClosure\UnsignedSerializableClosure + */ + public static function unsigned(Closure $closure) + { + return new UnsignedSerializableClosure($closure); + } + + /** + * Sets the serializable closure secret key. + * + * @param string|null $secret + * @return void + */ + public static function setSecretKey($secret) + { + Serializers\Signed::$signer = $secret + ? new Hmac($secret) + : null; + } + + /** + * Sets the serializable closure secret key. + * + * @param \Closure|null $transformer + * @return void + */ + public static function transformUseVariablesUsing($transformer) + { + Serializers\Native::$transformUseVariables = $transformer; + } + + /** + * Sets the serializable closure secret key. + * + * @param \Closure|null $resolver + * @return void + */ + public static function resolveUseVariablesUsing($resolver) + { + Serializers\Native::$resolveUseVariables = $resolver; + } + + /** + * Get the serializable representation of the closure. + * + * @return array{serializable: \Laravel\SerializableClosure\Serializers\Signed|\Laravel\SerializableClosure\Contracts\Serializable} + */ + public function __serialize() + { + return [ + 'serializable' => $this->serializable, + ]; + } + + /** + * Restore the closure after serialization. + * + * @param array{serializable: \Laravel\SerializableClosure\Serializers\Signed|\Laravel\SerializableClosure\Contracts\Serializable} $data + * @return void + * + * @throws \Laravel\SerializableClosure\Exceptions\InvalidSignatureException + */ + public function __unserialize($data) + { + if (Signed::$signer && ! $data['serializable'] instanceof Signed) { + throw new InvalidSignatureException(); + } + + $this->serializable = $data['serializable']; + } +} diff --git a/api/vendor/laravel/serializable-closure/src/Serializers/Native.php b/api/vendor/laravel/serializable-closure/src/Serializers/Native.php new file mode 100644 index 0000000..6fe884b --- /dev/null +++ b/api/vendor/laravel/serializable-closure/src/Serializers/Native.php @@ -0,0 +1,526 @@ +closure = $closure; + } + + /** + * Resolve the closure with the given arguments. + * + * @return mixed + */ + public function __invoke() + { + return call_user_func_array($this->closure, func_get_args()); + } + + /** + * Gets the closure. + * + * @return \Closure + */ + public function getClosure() + { + return $this->closure; + } + + /** + * Get the serializable representation of the closure. + * + * @return array + */ + public function __serialize() + { + if ($this->scope === null) { + $this->scope = new ClosureScope(); + $this->scope->toSerialize++; + } + + $this->scope->serializations++; + + $scope = $object = null; + $reflector = $this->getReflector(); + + if ($reflector->isBindingRequired()) { + $object = $reflector->getClosureThis(); + + static::wrapClosures($object, $this->scope); + } + + if ($scope = $reflector->getClosureScopeClass()) { + $scope = $scope->name; + } + + $this->reference = spl_object_hash($this->closure); + + $this->scope[$this->closure] = $this; + + $use = $reflector->getUseVariables(); + + if (static::$transformUseVariables) { + $use = call_user_func(static::$transformUseVariables, $reflector->getUseVariables()); + } + + $code = $reflector->getCode(); + + $this->mapByReference($use); + + $data = [ + 'use' => $use, + 'function' => $code, + 'scope' => $scope, + 'this' => $object, + 'self' => $this->reference, + ]; + + if (! --$this->scope->serializations && ! --$this->scope->toSerialize) { + $this->scope = null; + } + + return $data; + } + + /** + * Restore the closure after serialization. + * + * @param array $data + * @return void + */ + public function __unserialize($data) + { + ClosureStream::register(); + + $this->code = $data; + unset($data); + + $this->code['objects'] = []; + + if ($this->code['use']) { + $this->scope = new ClosureScope(); + + if (static::$resolveUseVariables) { + $this->code['use'] = call_user_func(static::$resolveUseVariables, $this->code['use']); + } + + $this->mapPointers($this->code['use']); + + extract($this->code['use'], EXTR_OVERWRITE | EXTR_REFS); + + $this->scope = null; + } + + $this->closure = include ClosureStream::STREAM_PROTO.'://'.$this->code['function']; + + if ($this->code['this'] === $this) { + $this->code['this'] = null; + } + + $this->closure = $this->closure->bindTo($this->code['this'], $this->code['scope']); + + if (! empty($this->code['objects'])) { + foreach ($this->code['objects'] as $item) { + $item['property']->setValue($item['instance'], $item['object']->getClosure()); + } + } + + $this->code = $this->code['function']; + } + + /** + * Ensures the given closures are serializable. + * + * @param mixed $data + * @param \Laravel\SerializableClosure\Support\ClosureScope $storage + * @return void + */ + public static function wrapClosures(&$data, $storage) + { + if ($data instanceof Closure) { + $data = new static($data); + } elseif (is_array($data)) { + if (isset($data[self::ARRAY_RECURSIVE_KEY])) { + return; + } + + $data[self::ARRAY_RECURSIVE_KEY] = true; + + foreach ($data as $key => &$value) { + if ($key === self::ARRAY_RECURSIVE_KEY) { + continue; + } + static::wrapClosures($value, $storage); + } + + unset($value); + unset($data[self::ARRAY_RECURSIVE_KEY]); + } elseif ($data instanceof \stdClass) { + if (isset($storage[$data])) { + $data = $storage[$data]; + + return; + } + + $data = $storage[$data] = clone $data; + + foreach ($data as &$value) { + static::wrapClosures($value, $storage); + } + + unset($value); + } elseif (is_object($data) && ! $data instanceof static && ! $data instanceof UnitEnum) { + if (isset($storage[$data])) { + $data = $storage[$data]; + + return; + } + + $instance = $data; + $reflection = new ReflectionObject($instance); + + if (! $reflection->isUserDefined()) { + $storage[$instance] = $data; + + return; + } + + $storage[$instance] = $data = $reflection->newInstanceWithoutConstructor(); + + do { + if (! $reflection->isUserDefined()) { + break; + } + + foreach ($reflection->getProperties() as $property) { + if ($property->isStatic() || ! $property->getDeclaringClass()->isUserDefined()) { + continue; + } + + $property->setAccessible(true); + + if (! $property->isInitialized($instance)) { + continue; + } + + $value = $property->getValue($instance); + + if (is_array($value) || is_object($value)) { + static::wrapClosures($value, $storage); + } + + $property->setValue($data, $value); + } + } while ($reflection = $reflection->getParentClass()); + } + } + + /** + * Gets the closure's reflector. + * + * @return \Laravel\SerializableClosure\Support\ReflectionClosure + */ + public function getReflector() + { + if ($this->reflector === null) { + $this->code = null; + $this->reflector = new ReflectionClosure($this->closure); + } + + return $this->reflector; + } + + /** + * Internal method used to map closure pointers. + * + * @param mixed $data + * @return void + */ + protected function mapPointers(&$data) + { + $scope = $this->scope; + + if ($data instanceof static) { + $data = &$data->closure; + } elseif (is_array($data)) { + if (isset($data[self::ARRAY_RECURSIVE_KEY])) { + return; + } + + $data[self::ARRAY_RECURSIVE_KEY] = true; + + foreach ($data as $key => &$value) { + if ($key === self::ARRAY_RECURSIVE_KEY) { + continue; + } elseif ($value instanceof static) { + $data[$key] = &$value->closure; + } elseif ($value instanceof SelfReference && $value->hash === $this->code['self']) { + $data[$key] = &$this->closure; + } else { + $this->mapPointers($value); + } + } + + unset($value); + unset($data[self::ARRAY_RECURSIVE_KEY]); + } elseif ($data instanceof \stdClass) { + if (isset($scope[$data])) { + return; + } + + $scope[$data] = true; + + foreach ($data as $key => &$value) { + if ($value instanceof SelfReference && $value->hash === $this->code['self']) { + $data->{$key} = &$this->closure; + } elseif (is_array($value) || is_object($value)) { + $this->mapPointers($value); + } + } + + unset($value); + } elseif (is_object($data) && ! ($data instanceof Closure)) { + if (isset($scope[$data])) { + return; + } + + $scope[$data] = true; + $reflection = new ReflectionObject($data); + + do { + if (! $reflection->isUserDefined()) { + break; + } + + foreach ($reflection->getProperties() as $property) { + if ($property->isStatic() || ! $property->getDeclaringClass()->isUserDefined()) { + continue; + } + + $property->setAccessible(true); + + if (! $property->isInitialized($data) || $property->isReadOnly()) { + continue; + } + + $item = $property->getValue($data); + + if ($item instanceof SerializableClosure || $item instanceof UnsignedSerializableClosure || ($item instanceof SelfReference && $item->hash === $this->code['self'])) { + $this->code['objects'][] = [ + 'instance' => $data, + 'property' => $property, + 'object' => $item instanceof SelfReference ? $this : $item, + ]; + } elseif (is_array($item) || is_object($item)) { + $this->mapPointers($item); + $property->setValue($data, $item); + } + } + } while ($reflection = $reflection->getParentClass()); + } + } + + /** + * Internal method used to map closures by reference. + * + * @param mixed $data + * @return void + */ + protected function mapByReference(&$data) + { + if ($data instanceof Closure) { + if ($data === $this->closure) { + $data = new SelfReference($this->reference); + + return; + } + + if (isset($this->scope[$data])) { + $data = $this->scope[$data]; + + return; + } + + $instance = new static($data); + + $instance->scope = $this->scope; + + $data = $this->scope[$data] = $instance; + } elseif (is_array($data)) { + if (isset($data[self::ARRAY_RECURSIVE_KEY])) { + return; + } + + $data[self::ARRAY_RECURSIVE_KEY] = true; + + foreach ($data as $key => &$value) { + if ($key === self::ARRAY_RECURSIVE_KEY) { + continue; + } + + $this->mapByReference($value); + } + + unset($value); + unset($data[self::ARRAY_RECURSIVE_KEY]); + } elseif ($data instanceof \stdClass) { + if (isset($this->scope[$data])) { + $data = $this->scope[$data]; + + return; + } + + $instance = $data; + $this->scope[$instance] = $data = clone $data; + + foreach ($data as &$value) { + $this->mapByReference($value); + } + + unset($value); + } elseif (is_object($data) && ! $data instanceof SerializableClosure && ! $data instanceof UnsignedSerializableClosure) { + if (isset($this->scope[$data])) { + $data = $this->scope[$data]; + + return; + } + + $instance = $data; + + if ($data instanceof DateTimeInterface) { + $this->scope[$instance] = $data; + + return; + } + + if ($data instanceof UnitEnum) { + $this->scope[$instance] = $data; + + return; + } + + $reflection = new ReflectionObject($data); + + if (! $reflection->isUserDefined()) { + $this->scope[$instance] = $data; + + return; + } + + $this->scope[$instance] = $data = $reflection->newInstanceWithoutConstructor(); + + do { + if (! $reflection->isUserDefined()) { + break; + } + + foreach ($reflection->getProperties() as $property) { + if ($property->isStatic() || ! $property->getDeclaringClass()->isUserDefined() || $this->isVirtualProperty($property)) { + continue; + } + + $property->setAccessible(true); + + if (! $property->isInitialized($instance) || ($property->isReadOnly() && $property->class !== $reflection->name)) { + continue; + } + + $value = $property->getValue($instance); + + if (is_array($value) || is_object($value)) { + $this->mapByReference($value); + } + + $property->setValue($data, $value); + } + } while ($reflection = $reflection->getParentClass()); + } + } + + /** + * Determine is virtual property. + * + * @param \ReflectionProperty $property + * @return bool + */ + protected function isVirtualProperty(ReflectionProperty $property): bool + { + return method_exists($property, 'isVirtual') && $property->isVirtual(); + } +} diff --git a/api/vendor/laravel/serializable-closure/src/Serializers/Signed.php b/api/vendor/laravel/serializable-closure/src/Serializers/Signed.php new file mode 100644 index 0000000..16f9593 --- /dev/null +++ b/api/vendor/laravel/serializable-closure/src/Serializers/Signed.php @@ -0,0 +1,91 @@ +closure = $closure; + } + + /** + * Resolve the closure with the given arguments. + * + * @return mixed + */ + public function __invoke() + { + return call_user_func_array($this->closure, func_get_args()); + } + + /** + * Gets the closure. + * + * @return \Closure + */ + public function getClosure() + { + return $this->closure; + } + + /** + * Get the serializable representation of the closure. + * + * @return array + */ + public function __serialize() + { + if (! static::$signer) { + throw new MissingSecretKeyException(); + } + + return static::$signer->sign( + serialize(new Native($this->closure)) + ); + } + + /** + * Restore the closure after serialization. + * + * @param array{serializable: string, hash: string} $signature + * @return void + * + * @throws \Laravel\SerializableClosure\Exceptions\InvalidSignatureException + */ + public function __unserialize($signature) + { + if (static::$signer && ! static::$signer->verify($signature)) { + throw new InvalidSignatureException(); + } + + /** @var \Laravel\SerializableClosure\Contracts\Serializable $serializable */ + $serializable = unserialize($signature['serializable']); + + $this->closure = $serializable->getClosure(); + } +} diff --git a/api/vendor/laravel/serializable-closure/src/Signers/Hmac.php b/api/vendor/laravel/serializable-closure/src/Signers/Hmac.php new file mode 100644 index 0000000..41ed01a --- /dev/null +++ b/api/vendor/laravel/serializable-closure/src/Signers/Hmac.php @@ -0,0 +1,53 @@ +secret = $secret; + } + + /** + * Sign the given serializable. + * + * @param string $serialized + * @return array + */ + public function sign($serialized) + { + return [ + 'serializable' => $serialized, + 'hash' => base64_encode(hash_hmac('sha256', $serialized, $this->secret, true)), + ]; + } + + /** + * Verify the given signature. + * + * @param array{serializable: string, hash: string} $signature + * @return bool + */ + public function verify($signature) + { + return hash_equals(base64_encode( + hash_hmac('sha256', $signature['serializable'], $this->secret, true) + ), $signature['hash']); + } +} diff --git a/api/vendor/laravel/serializable-closure/src/Support/ClosureScope.php b/api/vendor/laravel/serializable-closure/src/Support/ClosureScope.php new file mode 100644 index 0000000..64ca19a --- /dev/null +++ b/api/vendor/laravel/serializable-closure/src/Support/ClosureScope.php @@ -0,0 +1,22 @@ +content = "length = strlen($this->content); + + return true; + } + + /** + * Read from stream. + * + * @param int $count + * @return string + */ + public function stream_read($count) + { + $value = substr($this->content, $this->pointer, $count); + + $this->pointer += $count; + + return $value; + } + + /** + * Tests for end-of-file on a file pointer. + * + * @return bool + */ + public function stream_eof() + { + return $this->pointer >= $this->length; + } + + /** + * Change stream options. + * + * @param int $option + * @param int $arg1 + * @param int $arg2 + * @return bool + */ + public function stream_set_option($option, $arg1, $arg2) + { + return false; + } + + /** + * Retrieve information about a file resource. + * + * @return array|bool + */ + public function stream_stat() + { + $stat = stat(__FILE__); + // @phpstan-ignore-next-line + $stat[7] = $stat['size'] = $this->length; + + return $stat; + } + + /** + * Retrieve information about a file. + * + * @param string $path + * @param int $flags + * @return array|bool + */ + public function url_stat($path, $flags) + { + $stat = stat(__FILE__); + // @phpstan-ignore-next-line + $stat[7] = $stat['size'] = $this->length; + + return $stat; + } + + /** + * Seeks to specific location in a stream. + * + * @param int $offset + * @param int $whence + * @return bool + */ + public function stream_seek($offset, $whence = SEEK_SET) + { + $crt = $this->pointer; + + switch ($whence) { + case SEEK_SET: + $this->pointer = $offset; + break; + case SEEK_CUR: + $this->pointer += $offset; + break; + case SEEK_END: + $this->pointer = $this->length + $offset; + break; + } + + if ($this->pointer < 0 || $this->pointer >= $this->length) { + $this->pointer = $crt; + + return false; + } + + return true; + } + + /** + * Retrieve the current position of a stream. + * + * @return int + */ + public function stream_tell() + { + return $this->pointer; + } + + /** + * Registers the stream. + * + * @return void + */ + public static function register() + { + if (! static::$isRegistered) { + static::$isRegistered = stream_wrapper_register(static::STREAM_PROTO, __CLASS__); + } + } +} diff --git a/api/vendor/laravel/serializable-closure/src/Support/ReflectionClosure.php b/api/vendor/laravel/serializable-closure/src/Support/ReflectionClosure.php new file mode 100644 index 0000000..fb90bef --- /dev/null +++ b/api/vendor/laravel/serializable-closure/src/Support/ReflectionClosure.php @@ -0,0 +1,1243 @@ +isStaticClosure === null) { + $this->isStaticClosure = strtolower(substr($this->getCode(), 0, 6)) === 'static'; + } + + return $this->isStaticClosure; + } + + /** + * Checks if the closure is a "short closure". + * + * @return bool + */ + public function isShortClosure() + { + if ($this->isShortClosure === null) { + $code = $this->getCode(); + + if ($this->isStatic()) { + $code = substr($code, 6); + } + + $this->isShortClosure = strtolower(substr(trim($code), 0, 2)) === 'fn'; + } + + return $this->isShortClosure; + } + + /** + * Get the closure's code. + * + * @return string + */ + public function getCode() + { + if ($this->code !== null) { + return $this->code; + } + + $fileName = $this->getFileName(); + $line = $this->getStartLine() - 1; + + $className = null; + + if (null !== $className = $this->getClosureScopeClass()) { + $className = '\\'.trim($className->getName(), '\\'); + } + + $builtin_types = self::getBuiltinTypes(); + $class_keywords = ['self', 'static', 'parent']; + + $ns = $this->getClosureNamespaceName(); + $nsf = $ns == '' ? '' : ($ns[0] == '\\' ? $ns : '\\'.$ns); + + $_file = var_export($fileName, true); + $_dir = var_export(dirname($fileName), true); + $_namespace = var_export($ns, true); + $_class = var_export(trim($className ?: '', '\\'), true); + $_function = $ns.($ns == '' ? '' : '\\').'{closure}'; + $_method = ($className == '' ? '' : trim($className, '\\').'::').$_function; + $_function = var_export($_function, true); + $_method = var_export($_method, true); + $_trait = null; + + $tokens = $this->getTokens(); + $state = $lastState = 'start'; + $inside_structure = false; + $isFirstClassCallable = false; + $isShortClosure = false; + + $inside_structure_mark = 0; + $open = 0; + $code = ''; + $id_start = $id_start_ci = $id_name = $context = ''; + $classes = $functions = $constants = null; + $use = []; + $lineAdd = 0; + $isUsingScope = false; + $isUsingThisObject = false; + + for ($i = 0, $l = count($tokens); $i < $l; $i++) { + $token = $tokens[$i]; + + switch ($state) { + case 'start': + if ($token[0] === T_FUNCTION || $token[0] === T_STATIC) { + $code .= $token[1]; + + $state = $token[0] === T_FUNCTION ? 'function' : 'static'; + } elseif ($token[0] === T_FN) { + $isShortClosure = true; + $code .= $token[1]; + $state = 'closure_args'; + } elseif ($token[0] === T_PUBLIC || $token[0] === T_PROTECTED || $token[0] === T_PRIVATE) { + $code = ''; + $isFirstClassCallable = true; + } + break; + case 'static': + if ($token[0] === T_WHITESPACE || $token[0] === T_COMMENT || $token[0] === T_FUNCTION) { + $code .= $token[1]; + if ($token[0] === T_FUNCTION) { + $state = 'function'; + } + } elseif ($token[0] === T_FN) { + $isShortClosure = true; + $code .= $token[1]; + $state = 'closure_args'; + } else { + $code = ''; + $state = 'start'; + } + break; + case 'function': + switch ($token[0]) { + case T_STRING: + if ($isFirstClassCallable) { + $state = 'closure_args'; + break; + } + + $code = ''; + $state = 'named_function'; + break; + case '(': + $code .= '('; + $state = 'closure_args'; + break; + default: + $code .= is_array($token) ? $token[1] : $token; + } + break; + case 'named_function': + if ($token[0] === T_FUNCTION || $token[0] === T_STATIC) { + $code = $token[1]; + $state = $token[0] === T_FUNCTION ? 'function' : 'static'; + } elseif ($token[0] === T_FN) { + $isShortClosure = true; + $code .= $token[1]; + $state = 'closure_args'; + } + break; + case 'closure_args': + switch ($token[0]) { + case T_NAME_QUALIFIED: + [$id_start, $id_start_ci, $id_name] = $this->parseNameQualified($token[1]); + $context = 'args'; + $state = 'id_name'; + $lastState = 'closure_args'; + break; + case T_NS_SEPARATOR: + case T_STRING: + $id_start = $token[1]; + $id_start_ci = strtolower($id_start); + $id_name = ''; + $context = 'args'; + $state = 'id_name'; + $lastState = 'closure_args'; + break; + case T_USE: + $code .= $token[1]; + $state = 'use'; + break; + case T_DOUBLE_ARROW: + $code .= $token[1]; + if ($isShortClosure) { + $state = 'closure'; + } + break; + case ':': + $code .= ':'; + $state = 'return'; + break; + case '{': + $code .= '{'; + $state = 'closure'; + $open++; + break; + default: + $code .= is_array($token) ? $token[1] : $token; + } + break; + case 'use': + switch ($token[0]) { + case T_VARIABLE: + $use[] = substr($token[1], 1); + $code .= $token[1]; + break; + case '{': + $code .= '{'; + $state = 'closure'; + $open++; + break; + case ':': + $code .= ':'; + $state = 'return'; + break; + default: + $code .= is_array($token) ? $token[1] : $token; + break; + } + break; + case 'return': + switch ($token[0]) { + case T_WHITESPACE: + case T_COMMENT: + case T_DOC_COMMENT: + $code .= $token[1]; + break; + case T_NS_SEPARATOR: + case T_STRING: + $id_start = $token[1]; + $id_start_ci = strtolower($id_start); + $id_name = ''; + $context = 'return_type'; + $state = 'id_name'; + $lastState = 'return'; + break 2; + case T_NAME_QUALIFIED: + [$id_start, $id_start_ci, $id_name] = $this->parseNameQualified($token[1]); + $context = 'return_type'; + $state = 'id_name'; + $lastState = 'return'; + break 2; + case T_DOUBLE_ARROW: + $code .= $token[1]; + if ($isShortClosure) { + $state = 'closure'; + } + break; + case '{': + $code .= '{'; + $state = 'closure'; + $open++; + break; + default: + $code .= is_array($token) ? $token[1] : $token; + break; + } + break; + case 'closure': + switch ($token[0]) { + case T_CURLY_OPEN: + case T_DOLLAR_OPEN_CURLY_BRACES: + case '{': + $code .= is_array($token) ? $token[1] : $token; + $open++; + break; + case '}': + $code .= '}'; + if (--$open === 0 && ! $isShortClosure) { + break 3; + } elseif ($inside_structure) { + $inside_structure = ! ($open === $inside_structure_mark); + } + break; + case '(': + case '[': + $code .= $token[0]; + if ($isShortClosure) { + $open++; + } + break; + case ')': + case ']': + if ($isShortClosure) { + if ($open === 0) { + break 3; + } + $open--; + } + $code .= $token[0]; + break; + case ',': + case ';': + if ($isShortClosure && $open === 0) { + break 3; + } + $code .= $token[0]; + break; + case T_LINE: + $code .= $token[2] - $line + $lineAdd; + break; + case T_FILE: + $code .= $_file; + break; + case T_DIR: + $code .= $_dir; + break; + case T_NS_C: + $code .= $_namespace; + break; + case T_CLASS_C: + $code .= $inside_structure ? $token[1] : $_class; + break; + case T_FUNC_C: + $code .= $inside_structure ? $token[1] : $_function; + break; + case T_METHOD_C: + $code .= $inside_structure ? $token[1] : $_method; + break; + case T_COMMENT: + if (substr($token[1], 0, 8) === '#trackme') { + $timestamp = time(); + $code .= '/**'.PHP_EOL; + $code .= '* Date : '.date(DATE_W3C, $timestamp).PHP_EOL; + $code .= '* Timestamp : '.$timestamp.PHP_EOL; + $code .= '* Line : '.($line + 1).PHP_EOL; + $code .= '* File : '.$_file.PHP_EOL.'*/'.PHP_EOL; + $lineAdd += 5; + } else { + $code .= $token[1]; + } + break; + case T_VARIABLE: + if ($token[1] == '$this' && ! $inside_structure) { + $isUsingThisObject = true; + } + $code .= $token[1]; + break; + case T_STATIC: + case T_NS_SEPARATOR: + case T_STRING: + $id_start = $token[1]; + $id_start_ci = strtolower($id_start); + $id_name = ''; + $context = 'root'; + $state = 'id_name'; + $lastState = 'closure'; + break 2; + case T_NAME_QUALIFIED: + [$id_start, $id_start_ci, $id_name] = $this->parseNameQualified($token[1]); + $context = 'root'; + $state = 'id_name'; + $lastState = 'closure'; + break 2; + case T_NEW: + $code .= $token[1]; + $context = 'new'; + $state = 'id_start'; + $lastState = 'closure'; + break 2; + case T_USE: + $code .= $token[1]; + $context = 'use'; + $state = 'id_start'; + $lastState = 'closure'; + break; + case T_INSTANCEOF: + case T_INSTEADOF: + $code .= $token[1]; + $context = 'instanceof'; + $state = 'id_start'; + $lastState = 'closure'; + break; + case T_OBJECT_OPERATOR: + case T_NULLSAFE_OBJECT_OPERATOR: + case T_DOUBLE_COLON: + $code .= $token[1]; + $lastState = 'closure'; + $state = 'ignore_next'; + break; + case T_FUNCTION: + $code .= $token[1]; + $state = 'closure_args'; + if (! $inside_structure) { + $inside_structure = true; + $inside_structure_mark = $open; + } + break; + case T_TRAIT_C: + if ($_trait === null) { + $startLine = $this->getStartLine(); + $endLine = $this->getEndLine(); + $structures = $this->getStructures(); + + $_trait = ''; + + foreach ($structures as &$struct) { + if ($struct['type'] === 'trait' && + $struct['start'] <= $startLine && + $struct['end'] >= $endLine + ) { + $_trait = ($ns == '' ? '' : $ns.'\\').$struct['name']; + break; + } + } + + $_trait = var_export($_trait, true); + } + + $code .= $_trait; + break; + default: + $code .= is_array($token) ? $token[1] : $token; + } + break; + case 'ignore_next': + switch ($token[0]) { + case T_WHITESPACE: + case T_COMMENT: + case T_DOC_COMMENT: + $code .= $token[1]; + break; + case T_CLASS: + case T_NEW: + case T_STATIC: + case T_VARIABLE: + case T_STRING: + case T_CLASS_C: + case T_FILE: + case T_DIR: + case T_METHOD_C: + case T_FUNC_C: + case T_FUNCTION: + case T_INSTANCEOF: + case T_LINE: + case T_NS_C: + case T_TRAIT_C: + case T_USE: + $code .= $token[1]; + $state = $lastState; + break; + default: + $state = $lastState; + $i--; + } + break; + case 'id_start': + switch ($token[0]) { + case T_WHITESPACE: + case T_COMMENT: + case T_DOC_COMMENT: + $code .= $token[1]; + break; + case T_NS_SEPARATOR: + case T_NAME_FULLY_QUALIFIED: + case T_STRING: + case T_STATIC: + $id_start = $token[1]; + $id_start_ci = strtolower($id_start); + $id_name = ''; + $state = 'id_name'; + break 2; + case T_NAME_QUALIFIED: + [$id_start, $id_start_ci, $id_name] = $this->parseNameQualified($token[1]); + $state = 'id_name'; + break 2; + case T_VARIABLE: + $code .= $token[1]; + $state = $lastState; + break; + case T_CLASS: + $code .= $token[1]; + $state = 'anonymous'; + break; + default: + $i--; //reprocess last + $state = 'id_name'; + } + break; + case 'id_name': + switch ($token[0]) { + case $token[0] === ':' && ! in_array($context, ['instanceof', 'new'], true): + if ($lastState === 'closure' && $context === 'root') { + $state = 'closure'; + $code .= $id_start.$token; + } + + break; + case T_NAME_QUALIFIED: + case T_NS_SEPARATOR: + case T_STRING: + case T_WHITESPACE: + case T_COMMENT: + case T_DOC_COMMENT: + $id_name .= $token[1]; + break; + case '(': + if ($isShortClosure) { + $open++; + } + if ($context === 'new' || false !== strpos($id_name, '\\')) { + if ($id_start_ci === 'self' || $id_start_ci === 'static') { + if (! $inside_structure) { + $isUsingScope = true; + } + } elseif ($id_start !== '\\' && ! in_array($id_start_ci, $class_keywords)) { + if ($classes === null) { + $classes = $this->getClasses(); + } + if (isset($classes[$id_start_ci])) { + $id_start = $classes[$id_start_ci]; + } + if ($id_start[0] !== '\\') { + $id_start = $nsf.'\\'.$id_start; + } + } + } else { + if ($id_start !== '\\') { + if ($functions === null) { + $functions = $this->getFunctions(); + } + if (isset($functions[$id_start_ci])) { + $id_start = $functions[$id_start_ci]; + } elseif ($nsf !== '\\' && function_exists($nsf.'\\'.$id_start)) { + $id_start = $nsf.'\\'.$id_start; + // Cache it to functions array + $functions[$id_start_ci] = $id_start; + } + } + } + $code .= $id_start.$id_name.'('; + $state = $lastState; + break; + case T_VARIABLE: + case T_DOUBLE_COLON: + if ($id_start !== '\\') { + if ($id_start_ci === 'self' || $id_start_ci === 'parent') { + if (! $inside_structure) { + $isUsingScope = true; + } + } elseif ($id_start_ci === 'static') { + if (! $inside_structure) { + $isUsingScope = $token[0] === T_DOUBLE_COLON; + } + } elseif (! (\PHP_MAJOR_VERSION >= 7 && in_array($id_start_ci, $builtin_types))) { + if ($classes === null) { + $classes = $this->getClasses(); + } + if (isset($classes[$id_start_ci])) { + $id_start = $classes[$id_start_ci]; + } + if ($id_start[0] !== '\\') { + $id_start = $nsf.'\\'.$id_start; + } + } + } + + $code .= $id_start.$id_name.$token[1]; + $state = $token[0] === T_DOUBLE_COLON ? 'ignore_next' : $lastState; + break; + default: + if ($id_start !== '\\' && ! defined($id_start)) { + if ($constants === null) { + $constants = $this->getConstants(); + } + if (isset($constants[$id_start])) { + $id_start = $constants[$id_start]; + } elseif ($context === 'new') { + if (in_array($id_start_ci, $class_keywords)) { + if (! $inside_structure) { + $isUsingScope = true; + } + } else { + if ($classes === null) { + $classes = $this->getClasses(); + } + if (isset($classes[$id_start_ci])) { + $id_start = $classes[$id_start_ci]; + } + if ($id_start[0] !== '\\') { + $id_start = $nsf.'\\'.$id_start; + } + } + } elseif ($context === 'use' || + $context === 'instanceof' || + $context === 'args' || + $context === 'return_type' || + $context === 'extends' || + $context === 'root' + ) { + if (in_array($id_start_ci, $class_keywords)) { + if (! $inside_structure && ! $id_start_ci === 'static') { + $isUsingScope = true; + } + } elseif (! (\PHP_MAJOR_VERSION >= 7 && in_array($id_start_ci, $builtin_types))) { + if ($classes === null) { + $classes = $this->getClasses(); + } + if (isset($classes[$id_start_ci])) { + $id_start = $classes[$id_start_ci]; + } + if ($id_start[0] !== '\\') { + $id_start = $nsf.'\\'.$id_start; + } + } + } + } + $code .= $id_start.$id_name; + $state = $lastState; + $i--; //reprocess last token + } + break; + case 'anonymous': + switch ($token[0]) { + case T_NAME_QUALIFIED: + [$id_start, $id_start_ci, $id_name] = $this->parseNameQualified($token[1]); + $state = 'id_name'; + $lastState = 'anonymous'; + break 2; + case T_NS_SEPARATOR: + case T_STRING: + $id_start = $token[1]; + $id_start_ci = strtolower($id_start); + $id_name = ''; + $state = 'id_name'; + $context = 'extends'; + $lastState = 'anonymous'; + break; + case '{': + $state = 'closure'; + if (! $inside_structure) { + $inside_structure = true; + $inside_structure_mark = $open; + } + $i--; + break; + default: + $code .= is_array($token) ? $token[1] : $token; + } + break; + } + } + + if ($isShortClosure) { + $this->useVariables = $this->getStaticVariables(); + } else { + $this->useVariables = empty($use) ? $use : array_intersect_key($this->getStaticVariables(), array_flip($use)); + } + + $this->isShortClosure = $isShortClosure; + $this->isBindingRequired = $isUsingThisObject; + $this->isScopeRequired = $isUsingScope; + + $attributesCode = array_map(function ($attribute) { + $arguments = $attribute->getArguments(); + + $name = $attribute->getName(); + $arguments = implode(', ', array_map(function ($argument, $key) { + $argument = sprintf("'%s'", str_replace("'", "\\'", $argument)); + + if (is_string($key)) { + $argument = sprintf('%s: %s', $key, $argument); + } + + return $argument; + }, $arguments, array_keys($arguments))); + + return "#[$name($arguments)]"; + }, $this->getAttributes()); + + if (! empty($attributesCode)) { + $code = implode("\n", array_merge($attributesCode, [$code])); + } + + $this->code = $code; + + return $this->code; + } + + /** + * Get PHP native built in types. + * + * @return array + */ + protected static function getBuiltinTypes() + { + return ['array', 'callable', 'string', 'int', 'bool', 'float', 'iterable', 'void', 'object', 'mixed', 'false', 'null', 'never']; + } + + /** + * Gets the use variables by the closure. + * + * @return array + */ + public function getUseVariables() + { + if ($this->useVariables !== null) { + return $this->useVariables; + } + + $tokens = $this->getTokens(); + $use = []; + $state = 'start'; + + foreach ($tokens as &$token) { + $is_array = is_array($token); + + switch ($state) { + case 'start': + if ($is_array && $token[0] === T_USE) { + $state = 'use'; + } + break; + case 'use': + if ($is_array) { + if ($token[0] === T_VARIABLE) { + $use[] = substr($token[1], 1); + } + } elseif ($token == ')') { + break 2; + } + break; + } + } + + $this->useVariables = empty($use) ? $use : array_intersect_key($this->getStaticVariables(), array_flip($use)); + + return $this->useVariables; + } + + /** + * Checks if binding is required. + * + * @return bool + */ + public function isBindingRequired() + { + if ($this->isBindingRequired === null) { + $this->getCode(); + } + + return $this->isBindingRequired; + } + + /** + * Checks if access to the scope is required. + * + * @return bool + */ + public function isScopeRequired() + { + if ($this->isScopeRequired === null) { + $this->getCode(); + } + + return $this->isScopeRequired; + } + + /** + * The hash of the current file name. + * + * @return string + */ + protected function getHashedFileName() + { + if ($this->hashedName === null) { + $this->hashedName = sha1($this->getFileName()); + } + + return $this->hashedName; + } + + /** + * Get the file tokens. + * + * @return array + */ + protected function getFileTokens() + { + $key = $this->getHashedFileName(); + + if (! isset(static::$files[$key])) { + static::$files[$key] = token_get_all(file_get_contents($this->getFileName())); + } + + return static::$files[$key]; + } + + /** + * Get the tokens. + * + * @return array + */ + protected function getTokens() + { + if ($this->tokens === null) { + $tokens = $this->getFileTokens(); + $startLine = $this->getStartLine(); + $endLine = $this->getEndLine(); + $results = []; + $start = false; + + foreach ($tokens as &$token) { + if (! is_array($token)) { + if ($start) { + $results[] = $token; + } + + continue; + } + + $line = $token[2]; + + if ($line <= $endLine) { + if ($line >= $startLine) { + $start = true; + $results[] = $token; + } + + continue; + } + + break; + } + + $this->tokens = $results; + } + + return $this->tokens; + } + + /** + * Get the classes. + * + * @return array + */ + protected function getClasses() + { + $line = $this->getStartLine(); + + foreach ($this->getStructures() as $struct) { + if ($struct['type'] === 'namespace' && + $struct['start'] <= $line && + $struct['end'] >= $line + ) { + return $struct['classes']; + } + } + + return []; + } + + /** + * Get the functions. + * + * @return array + */ + protected function getFunctions() + { + $key = $this->getHashedFileName(); + + if (! isset(static::$functions[$key])) { + $this->fetchItems(); + } + + return static::$functions[$key]; + } + + /** + * Gets the constants. + * + * @return array + */ + protected function getConstants() + { + $key = $this->getHashedFileName(); + + if (! isset(static::$constants[$key])) { + $this->fetchItems(); + } + + return static::$constants[$key]; + } + + /** + * Get the structures. + * + * @return array + */ + protected function getStructures() + { + $key = $this->getHashedFileName(); + + if (! isset(static::$structures[$key])) { + $this->fetchItems(); + } + + return static::$structures[$key]; + } + + /** + * Fetch the items. + * + * @return void. + */ + protected function fetchItems() + { + $key = $this->getHashedFileName(); + + $classes = []; + $functions = []; + $constants = []; + $structures = []; + $tokens = $this->getFileTokens(); + + $open = 0; + $state = 'start'; + $lastState = ''; + $prefix = ''; + $name = ''; + $alias = ''; + $isFunc = $isConst = false; + + $startLine = $lastKnownLine = 0; + $structType = $structName = ''; + $structIgnore = false; + + $namespace = ''; + $namespaceStartLine = 0; + $namespaceBraced = false; + $namespaceClasses = []; + + foreach ($tokens as $token) { + if (is_array($token)) { + $lastKnownLine = $token[2]; + } + + switch ($state) { + case 'start': + switch ($token[0]) { + case T_NAMESPACE: + $structures[] = [ + 'type' => 'namespace', + 'name' => $namespace, + 'start' => $namespaceStartLine, + 'end' => $token[2] - 1, + 'classes' => $namespaceClasses, + ]; + $namespace = ''; + $namespaceClasses = []; + $state = 'namespace'; + $namespaceStartLine = $token[2]; + break; + case T_CLASS: + case T_INTERFACE: + case T_TRAIT: + $state = 'before_structure'; + $startLine = $token[2]; + $structType = $token[0] == T_CLASS + ? 'class' + : ($token[0] == T_INTERFACE ? 'interface' : 'trait'); + break; + case T_USE: + $state = 'use'; + $prefix = $name = $alias = ''; + $isFunc = $isConst = false; + break; + case T_FUNCTION: + $state = 'structure'; + $structIgnore = true; + break; + case T_NEW: + $state = 'new'; + break; + case T_OBJECT_OPERATOR: + case T_DOUBLE_COLON: + $state = 'invoke'; + break; + case '}': + if ($namespaceBraced) { + $structures[] = [ + 'type' => 'namespace', + 'name' => $namespace, + 'start' => $namespaceStartLine, + 'end' => $lastKnownLine, + 'classes' => $namespaceClasses, + ]; + $namespaceBraced = false; + $namespace = ''; + $namespaceClasses = []; + } + break; + } + break; + case 'namespace': + switch ($token[0]) { + case T_STRING: + case T_NAME_QUALIFIED: + $namespace = $token[1]; + break; + case ';': + case '{': + $state = 'start'; + $namespaceBraced = $token[0] === '{'; + break; + } + break; + case 'use': + switch ($token[0]) { + case T_FUNCTION: + $isFunc = true; + break; + case T_CONST: + $isConst = true; + break; + case T_NS_SEPARATOR: + $name .= $token[1]; + break; + case T_STRING: + $name .= $token[1]; + $alias = $token[1]; + break; + case T_NAME_QUALIFIED: + $name .= $token[1]; + $pieces = explode('\\', $token[1]); + $alias = end($pieces); + break; + case T_AS: + $lastState = 'use'; + $state = 'alias'; + break; + case '{': + $prefix = $name; + $name = $alias = ''; + $state = 'use-group'; + break; + case ',': + case ';': + if ($name === '' || $name[0] !== '\\') { + $name = '\\'.$name; + } + + if ($alias !== '') { + if ($isFunc) { + $functions[strtolower($alias)] = $name; + } elseif ($isConst) { + $constants[$alias] = $name; + } else { + $classes[strtolower($alias)] = $name; + $namespaceClasses[strtolower($alias)] = $name; + } + } + $name = $alias = ''; + $state = $token === ';' ? 'start' : 'use'; + break; + } + break; + case 'use-group': + switch ($token[0]) { + case T_NS_SEPARATOR: + $name .= $token[1]; + break; + case T_NAME_QUALIFIED: + $name .= $token[1]; + $pieces = explode('\\', $token[1]); + $alias = end($pieces); + break; + case T_STRING: + $name .= $token[1]; + $alias = $token[1]; + break; + case T_AS: + $lastState = 'use-group'; + $state = 'alias'; + break; + case ',': + case '}': + + if ($prefix === '' || $prefix[0] !== '\\') { + $prefix = '\\'.$prefix; + } + + if ($alias !== '') { + if ($isFunc) { + $functions[strtolower($alias)] = $prefix.$name; + } elseif ($isConst) { + $constants[$alias] = $prefix.$name; + } else { + $classes[strtolower($alias)] = $prefix.$name; + $namespaceClasses[strtolower($alias)] = $prefix.$name; + } + } + $name = $alias = ''; + $state = $token === '}' ? 'use' : 'use-group'; + break; + } + break; + case 'alias': + if ($token[0] === T_STRING) { + $alias = $token[1]; + $state = $lastState; + } + break; + case 'new': + switch ($token[0]) { + case T_WHITESPACE: + case T_COMMENT: + case T_DOC_COMMENT: + break 2; + case T_CLASS: + $state = 'structure'; + $structIgnore = true; + break; + default: + $state = 'start'; + } + break; + case 'invoke': + switch ($token[0]) { + case T_WHITESPACE: + case T_COMMENT: + case T_DOC_COMMENT: + break 2; + default: + $state = 'start'; + } + break; + case 'before_structure': + if ($token[0] == T_STRING) { + $structName = $token[1]; + $state = 'structure'; + } + break; + case 'structure': + switch ($token[0]) { + case '{': + case T_CURLY_OPEN: + case T_DOLLAR_OPEN_CURLY_BRACES: + $open++; + break; + case '}': + if (--$open == 0) { + if (! $structIgnore) { + $structures[] = [ + 'type' => $structType, + 'name' => $structName, + 'start' => $startLine, + 'end' => $lastKnownLine, + ]; + } + $structIgnore = false; + $state = 'start'; + } + break; + } + break; + } + } + + $structures[] = [ + 'type' => 'namespace', + 'name' => $namespace, + 'start' => $namespaceStartLine, + 'end' => PHP_INT_MAX, + 'classes' => $namespaceClasses, + ]; + + static::$classes[$key] = $classes; + static::$functions[$key] = $functions; + static::$constants[$key] = $constants; + static::$structures[$key] = $structures; + } + + /** + * Returns the namespace associated to the closure. + * + * @return string + */ + protected function getClosureNamespaceName() + { + $startLine = $this->getStartLine(); + $endLine = $this->getEndLine(); + + foreach ($this->getStructures() as $struct) { + if ($struct['type'] === 'namespace' && + $struct['start'] <= $startLine && + $struct['end'] >= $endLine + ) { + return $struct['name']; + } + } + + return ''; + } + + /** + * Parse the given token. + * + * @param string $token + * @return array + */ + protected function parseNameQualified($token) + { + $pieces = explode('\\', $token); + + $id_start = array_shift($pieces); + + $id_start_ci = strtolower($id_start); + + $id_name = '\\'.implode('\\', $pieces); + + return [$id_start, $id_start_ci, $id_name]; + } +} diff --git a/api/vendor/laravel/serializable-closure/src/Support/SelfReference.php b/api/vendor/laravel/serializable-closure/src/Support/SelfReference.php new file mode 100644 index 0000000..5831950 --- /dev/null +++ b/api/vendor/laravel/serializable-closure/src/Support/SelfReference.php @@ -0,0 +1,24 @@ +hash = $hash; + } +} diff --git a/api/vendor/laravel/serializable-closure/src/UnsignedSerializableClosure.php b/api/vendor/laravel/serializable-closure/src/UnsignedSerializableClosure.php new file mode 100644 index 0000000..afc2127 --- /dev/null +++ b/api/vendor/laravel/serializable-closure/src/UnsignedSerializableClosure.php @@ -0,0 +1,69 @@ +serializable = new Serializers\Native($closure); + } + + /** + * Resolve the closure with the given arguments. + * + * @return mixed + */ + public function __invoke() + { + return call_user_func_array($this->serializable, func_get_args()); + } + + /** + * Gets the closure. + * + * @return \Closure + */ + public function getClosure() + { + return $this->serializable->getClosure(); + } + + /** + * Get the serializable representation of the closure. + * + * @return array{serializable: \Laravel\SerializableClosure\Contracts\Serializable} + */ + public function __serialize() + { + return [ + 'serializable' => $this->serializable, + ]; + } + + /** + * Restore the closure after serialization. + * + * @param array{serializable: \Laravel\SerializableClosure\Contracts\Serializable} $data + * @return void + */ + public function __unserialize($data) + { + $this->serializable = $data['serializable']; + } +} diff --git a/api/vendor/nikic/fast-route/.gitignore b/api/vendor/nikic/fast-route/.gitignore new file mode 100644 index 0000000..e378a07 --- /dev/null +++ b/api/vendor/nikic/fast-route/.gitignore @@ -0,0 +1,5 @@ +/vendor/ +.idea/ + +# ignore lock file since we have no extra dependencies +composer.lock diff --git a/api/vendor/nikic/fast-route/.hhconfig b/api/vendor/nikic/fast-route/.hhconfig new file mode 100644 index 0000000..0c2153c --- /dev/null +++ b/api/vendor/nikic/fast-route/.hhconfig @@ -0,0 +1 @@ +assume_php=false diff --git a/api/vendor/nikic/fast-route/.travis.yml b/api/vendor/nikic/fast-route/.travis.yml new file mode 100644 index 0000000..10f8381 --- /dev/null +++ b/api/vendor/nikic/fast-route/.travis.yml @@ -0,0 +1,20 @@ +sudo: false +language: php + +php: + - 5.4 + - 5.5 + - 5.6 + - 7.0 + - 7.1 + - 7.2 + - hhvm + +script: + - ./vendor/bin/phpunit + +before_install: + - travis_retry composer self-update + +install: + - composer install diff --git a/api/vendor/nikic/fast-route/FastRoute.hhi b/api/vendor/nikic/fast-route/FastRoute.hhi new file mode 100644 index 0000000..8d50738 --- /dev/null +++ b/api/vendor/nikic/fast-route/FastRoute.hhi @@ -0,0 +1,126 @@ +; + } + + class RouteCollector { + public function __construct(RouteParser $routeParser, DataGenerator $dataGenerator); + public function addRoute(mixed $httpMethod, string $route, mixed $handler): void; + public function getData(): array; + } + + class Route { + public function __construct(string $httpMethod, mixed $handler, string $regex, array $variables); + public function matches(string $str): bool; + } + + interface DataGenerator { + public function addRoute(string $httpMethod, array $routeData, mixed $handler); + public function getData(): array; + } + + interface Dispatcher { + const int NOT_FOUND = 0; + const int FOUND = 1; + const int METHOD_NOT_ALLOWED = 2; + public function dispatch(string $httpMethod, string $uri): array; + } + + function simpleDispatcher( + (function(RouteCollector): void) $routeDefinitionCallback, + shape( + ?'routeParser' => classname, + ?'dataGenerator' => classname, + ?'dispatcher' => classname, + ?'routeCollector' => classname, + ) $options = shape()): Dispatcher; + + function cachedDispatcher( + (function(RouteCollector): void) $routeDefinitionCallback, + shape( + ?'routeParser' => classname, + ?'dataGenerator' => classname, + ?'dispatcher' => classname, + ?'routeCollector' => classname, + ?'cacheDisabled' => bool, + ?'cacheFile' => string, + ) $options = shape()): Dispatcher; +} + +namespace FastRoute\DataGenerator { + abstract class RegexBasedAbstract implements \FastRoute\DataGenerator { + protected abstract function getApproxChunkSize(); + protected abstract function processChunk($regexToRoutesMap); + + public function addRoute(string $httpMethod, array $routeData, mixed $handler): void; + public function getData(): array; + } + + class CharCountBased extends RegexBasedAbstract { + protected function getApproxChunkSize(): int; + protected function processChunk(array $regexToRoutesMap): array; + } + + class GroupCountBased extends RegexBasedAbstract { + protected function getApproxChunkSize(): int; + protected function processChunk(array $regexToRoutesMap): array; + } + + class GroupPosBased extends RegexBasedAbstract { + protected function getApproxChunkSize(): int; + protected function processChunk(array $regexToRoutesMap): array; + } + + class MarkBased extends RegexBasedAbstract { + protected function getApproxChunkSize(): int; + protected function processChunk(array $regexToRoutesMap): array; + } +} + +namespace FastRoute\Dispatcher { + abstract class RegexBasedAbstract implements \FastRoute\Dispatcher { + protected abstract function dispatchVariableRoute(array $routeData, string $uri): array; + + public function dispatch(string $httpMethod, string $uri): array; + } + + class GroupPosBased extends RegexBasedAbstract { + public function __construct(array $data); + protected function dispatchVariableRoute(array $routeData, string $uri): array; + } + + class GroupCountBased extends RegexBasedAbstract { + public function __construct(array $data); + protected function dispatchVariableRoute(array $routeData, string $uri): array; + } + + class CharCountBased extends RegexBasedAbstract { + public function __construct(array $data); + protected function dispatchVariableRoute(array $routeData, string $uri): array; + } + + class MarkBased extends RegexBasedAbstract { + public function __construct(array $data); + protected function dispatchVariableRoute(array $routeData, string $uri): array; + } +} + +namespace FastRoute\RouteParser { + class Std implements \FastRoute\RouteParser { + const string VARIABLE_REGEX = <<<'REGEX' +\{ + \s* ([a-zA-Z][a-zA-Z0-9_]*) \s* + (?: + : \s* ([^{}]*(?:\{(?-1)\}[^{}]*)*) + )? +\} +REGEX; + const string DEFAULT_DISPATCH_REGEX = '[^/]+'; + public function parse(string $route): array; + } +} diff --git a/api/vendor/nikic/fast-route/LICENSE b/api/vendor/nikic/fast-route/LICENSE new file mode 100644 index 0000000..478e764 --- /dev/null +++ b/api/vendor/nikic/fast-route/LICENSE @@ -0,0 +1,31 @@ +Copyright (c) 2013 by Nikita Popov. + +Some rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * The names of the contributors may not be used to endorse or + promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/api/vendor/nikic/fast-route/README.md b/api/vendor/nikic/fast-route/README.md new file mode 100644 index 0000000..91bd466 --- /dev/null +++ b/api/vendor/nikic/fast-route/README.md @@ -0,0 +1,313 @@ +FastRoute - Fast request router for PHP +======================================= + +This library provides a fast implementation of a regular expression based router. [Blog post explaining how the +implementation works and why it is fast.][blog_post] + +Install +------- + +To install with composer: + +```sh +composer require nikic/fast-route +``` + +Requires PHP 5.4 or newer. + +Usage +----- + +Here's a basic usage example: + +```php +addRoute('GET', '/users', 'get_all_users_handler'); + // {id} must be a number (\d+) + $r->addRoute('GET', '/user/{id:\d+}', 'get_user_handler'); + // The /{title} suffix is optional + $r->addRoute('GET', '/articles/{id:\d+}[/{title}]', 'get_article_handler'); +}); + +// Fetch method and URI from somewhere +$httpMethod = $_SERVER['REQUEST_METHOD']; +$uri = $_SERVER['REQUEST_URI']; + +// Strip query string (?foo=bar) and decode URI +if (false !== $pos = strpos($uri, '?')) { + $uri = substr($uri, 0, $pos); +} +$uri = rawurldecode($uri); + +$routeInfo = $dispatcher->dispatch($httpMethod, $uri); +switch ($routeInfo[0]) { + case FastRoute\Dispatcher::NOT_FOUND: + // ... 404 Not Found + break; + case FastRoute\Dispatcher::METHOD_NOT_ALLOWED: + $allowedMethods = $routeInfo[1]; + // ... 405 Method Not Allowed + break; + case FastRoute\Dispatcher::FOUND: + $handler = $routeInfo[1]; + $vars = $routeInfo[2]; + // ... call $handler with $vars + break; +} +``` + +### Defining routes + +The routes are defined by calling the `FastRoute\simpleDispatcher()` function, which accepts +a callable taking a `FastRoute\RouteCollector` instance. The routes are added by calling +`addRoute()` on the collector instance: + +```php +$r->addRoute($method, $routePattern, $handler); +``` + +The `$method` is an uppercase HTTP method string for which a certain route should match. It +is possible to specify multiple valid methods using an array: + +```php +// These two calls +$r->addRoute('GET', '/test', 'handler'); +$r->addRoute('POST', '/test', 'handler'); +// Are equivalent to this one call +$r->addRoute(['GET', 'POST'], '/test', 'handler'); +``` + +By default the `$routePattern` uses a syntax where `{foo}` specifies a placeholder with name `foo` +and matching the regex `[^/]+`. To adjust the pattern the placeholder matches, you can specify +a custom pattern by writing `{bar:[0-9]+}`. Some examples: + +```php +// Matches /user/42, but not /user/xyz +$r->addRoute('GET', '/user/{id:\d+}', 'handler'); + +// Matches /user/foobar, but not /user/foo/bar +$r->addRoute('GET', '/user/{name}', 'handler'); + +// Matches /user/foo/bar as well +$r->addRoute('GET', '/user/{name:.+}', 'handler'); +``` + +Custom patterns for route placeholders cannot use capturing groups. For example `{lang:(en|de)}` +is not a valid placeholder, because `()` is a capturing group. Instead you can use either +`{lang:en|de}` or `{lang:(?:en|de)}`. + +Furthermore parts of the route enclosed in `[...]` are considered optional, so that `/foo[bar]` +will match both `/foo` and `/foobar`. Optional parts are only supported in a trailing position, +not in the middle of a route. + +```php +// This route +$r->addRoute('GET', '/user/{id:\d+}[/{name}]', 'handler'); +// Is equivalent to these two routes +$r->addRoute('GET', '/user/{id:\d+}', 'handler'); +$r->addRoute('GET', '/user/{id:\d+}/{name}', 'handler'); + +// Multiple nested optional parts are possible as well +$r->addRoute('GET', '/user[/{id:\d+}[/{name}]]', 'handler'); + +// This route is NOT valid, because optional parts can only occur at the end +$r->addRoute('GET', '/user[/{id:\d+}]/{name}', 'handler'); +``` + +The `$handler` parameter does not necessarily have to be a callback, it could also be a controller +class name or any other kind of data you wish to associate with the route. FastRoute only tells you +which handler corresponds to your URI, how you interpret it is up to you. + +#### Shorcut methods for common request methods + +For the `GET`, `POST`, `PUT`, `PATCH`, `DELETE` and `HEAD` request methods shortcut methods are available. For example: + +```php +$r->get('/get-route', 'get_handler'); +$r->post('/post-route', 'post_handler'); +``` + +Is equivalent to: + +```php +$r->addRoute('GET', '/get-route', 'get_handler'); +$r->addRoute('POST', '/post-route', 'post_handler'); +``` + +#### Route Groups + +Additionally, you can specify routes inside of a group. All routes defined inside a group will have a common prefix. + +For example, defining your routes as: + +```php +$r->addGroup('/admin', function (RouteCollector $r) { + $r->addRoute('GET', '/do-something', 'handler'); + $r->addRoute('GET', '/do-another-thing', 'handler'); + $r->addRoute('GET', '/do-something-else', 'handler'); +}); +``` + +Will have the same result as: + + ```php +$r->addRoute('GET', '/admin/do-something', 'handler'); +$r->addRoute('GET', '/admin/do-another-thing', 'handler'); +$r->addRoute('GET', '/admin/do-something-else', 'handler'); + ``` + +Nested groups are also supported, in which case the prefixes of all the nested groups are combined. + +### Caching + +The reason `simpleDispatcher` accepts a callback for defining the routes is to allow seamless +caching. By using `cachedDispatcher` instead of `simpleDispatcher` you can cache the generated +routing data and construct the dispatcher from the cached information: + +```php +addRoute('GET', '/user/{name}/{id:[0-9]+}', 'handler0'); + $r->addRoute('GET', '/user/{id:[0-9]+}', 'handler1'); + $r->addRoute('GET', '/user/{name}', 'handler2'); +}, [ + 'cacheFile' => __DIR__ . '/route.cache', /* required */ + 'cacheDisabled' => IS_DEBUG_ENABLED, /* optional, enabled by default */ +]); +``` + +The second parameter to the function is an options array, which can be used to specify the cache +file location, among other things. + +### Dispatching a URI + +A URI is dispatched by calling the `dispatch()` method of the created dispatcher. This method +accepts the HTTP method and a URI. Getting those two bits of information (and normalizing them +appropriately) is your job - this library is not bound to the PHP web SAPIs. + +The `dispatch()` method returns an array whose first element contains a status code. It is one +of `Dispatcher::NOT_FOUND`, `Dispatcher::METHOD_NOT_ALLOWED` and `Dispatcher::FOUND`. For the +method not allowed status the second array element contains a list of HTTP methods allowed for +the supplied URI. For example: + + [FastRoute\Dispatcher::METHOD_NOT_ALLOWED, ['GET', 'POST']] + +> **NOTE:** The HTTP specification requires that a `405 Method Not Allowed` response include the +`Allow:` header to detail available methods for the requested resource. Applications using FastRoute +should use the second array element to add this header when relaying a 405 response. + +For the found status the second array element is the handler that was associated with the route +and the third array element is a dictionary of placeholder names to their values. For example: + + /* Routing against GET /user/nikic/42 */ + + [FastRoute\Dispatcher::FOUND, 'handler0', ['name' => 'nikic', 'id' => '42']] + +### Overriding the route parser and dispatcher + +The routing process makes use of three components: A route parser, a data generator and a +dispatcher. The three components adhere to the following interfaces: + +```php + 'FastRoute\\RouteParser\\Std', + 'dataGenerator' => 'FastRoute\\DataGenerator\\GroupCountBased', + 'dispatcher' => 'FastRoute\\Dispatcher\\GroupCountBased', +]); +``` + +The above options array corresponds to the defaults. By replacing `GroupCountBased` by +`GroupPosBased` you could switch to a different dispatching strategy. + +### A Note on HEAD Requests + +The HTTP spec requires servers to [support both GET and HEAD methods][2616-511]: + +> The methods GET and HEAD MUST be supported by all general-purpose servers + +To avoid forcing users to manually register HEAD routes for each resource we fallback to matching an +available GET route for a given resource. The PHP web SAPI transparently removes the entity body +from HEAD responses so this behavior has no effect on the vast majority of users. + +However, implementers using FastRoute outside the web SAPI environment (e.g. a custom server) MUST +NOT send entity bodies generated in response to HEAD requests. If you are a non-SAPI user this is +*your responsibility*; FastRoute has no purview to prevent you from breaking HTTP in such cases. + +Finally, note that applications MAY always specify their own HEAD method route for a given +resource to bypass this behavior entirely. + +### Credits + +This library is based on a router that [Levi Morrison][levi] implemented for the Aerys server. + +A large number of tests, as well as HTTP compliance considerations, were provided by [Daniel Lowrey][rdlowrey]. + + +[2616-511]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.1 "RFC 2616 Section 5.1.1" +[blog_post]: http://nikic.github.io/2014/02/18/Fast-request-routing-using-regular-expressions.html +[levi]: https://github.com/morrisonlevi +[rdlowrey]: https://github.com/rdlowrey diff --git a/api/vendor/nikic/fast-route/composer.json b/api/vendor/nikic/fast-route/composer.json new file mode 100644 index 0000000..fb446a2 --- /dev/null +++ b/api/vendor/nikic/fast-route/composer.json @@ -0,0 +1,24 @@ +{ + "name": "nikic/fast-route", + "description": "Fast request router for PHP", + "keywords": ["routing", "router"], + "license": "BSD-3-Clause", + "authors": [ + { + "name": "Nikita Popov", + "email": "nikic@php.net" + } + ], + "autoload": { + "psr-4": { + "FastRoute\\": "src/" + }, + "files": ["src/functions.php"] + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35|~5.7" + } +} diff --git a/api/vendor/nikic/fast-route/phpunit.xml b/api/vendor/nikic/fast-route/phpunit.xml new file mode 100644 index 0000000..3c807b6 --- /dev/null +++ b/api/vendor/nikic/fast-route/phpunit.xml @@ -0,0 +1,24 @@ + + + + + + ./test/ + + + + + + ./src/ + + + diff --git a/api/vendor/nikic/fast-route/psalm.xml b/api/vendor/nikic/fast-route/psalm.xml new file mode 100644 index 0000000..0dca5d7 --- /dev/null +++ b/api/vendor/nikic/fast-route/psalm.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/api/vendor/nikic/fast-route/src/BadRouteException.php b/api/vendor/nikic/fast-route/src/BadRouteException.php new file mode 100644 index 0000000..62262ec --- /dev/null +++ b/api/vendor/nikic/fast-route/src/BadRouteException.php @@ -0,0 +1,7 @@ + $route) { + $suffixLen++; + $suffix .= "\t"; + + $regexes[] = '(?:' . $regex . '/(\t{' . $suffixLen . '})\t{' . ($count - $suffixLen) . '})'; + $routeMap[$suffix] = [$route->handler, $route->variables]; + } + + $regex = '~^(?|' . implode('|', $regexes) . ')$~'; + return ['regex' => $regex, 'suffix' => '/' . $suffix, 'routeMap' => $routeMap]; + } +} diff --git a/api/vendor/nikic/fast-route/src/DataGenerator/GroupCountBased.php b/api/vendor/nikic/fast-route/src/DataGenerator/GroupCountBased.php new file mode 100644 index 0000000..54d9a05 --- /dev/null +++ b/api/vendor/nikic/fast-route/src/DataGenerator/GroupCountBased.php @@ -0,0 +1,30 @@ + $route) { + $numVariables = count($route->variables); + $numGroups = max($numGroups, $numVariables); + + $regexes[] = $regex . str_repeat('()', $numGroups - $numVariables); + $routeMap[$numGroups + 1] = [$route->handler, $route->variables]; + + ++$numGroups; + } + + $regex = '~^(?|' . implode('|', $regexes) . ')$~'; + return ['regex' => $regex, 'routeMap' => $routeMap]; + } +} diff --git a/api/vendor/nikic/fast-route/src/DataGenerator/GroupPosBased.php b/api/vendor/nikic/fast-route/src/DataGenerator/GroupPosBased.php new file mode 100644 index 0000000..fc4dc0a --- /dev/null +++ b/api/vendor/nikic/fast-route/src/DataGenerator/GroupPosBased.php @@ -0,0 +1,27 @@ + $route) { + $regexes[] = $regex; + $routeMap[$offset] = [$route->handler, $route->variables]; + + $offset += count($route->variables); + } + + $regex = '~^(?:' . implode('|', $regexes) . ')$~'; + return ['regex' => $regex, 'routeMap' => $routeMap]; + } +} diff --git a/api/vendor/nikic/fast-route/src/DataGenerator/MarkBased.php b/api/vendor/nikic/fast-route/src/DataGenerator/MarkBased.php new file mode 100644 index 0000000..0aebed9 --- /dev/null +++ b/api/vendor/nikic/fast-route/src/DataGenerator/MarkBased.php @@ -0,0 +1,27 @@ + $route) { + $regexes[] = $regex . '(*MARK:' . $markName . ')'; + $routeMap[$markName] = [$route->handler, $route->variables]; + + ++$markName; + } + + $regex = '~^(?|' . implode('|', $regexes) . ')$~'; + return ['regex' => $regex, 'routeMap' => $routeMap]; + } +} diff --git a/api/vendor/nikic/fast-route/src/DataGenerator/RegexBasedAbstract.php b/api/vendor/nikic/fast-route/src/DataGenerator/RegexBasedAbstract.php new file mode 100644 index 0000000..6457290 --- /dev/null +++ b/api/vendor/nikic/fast-route/src/DataGenerator/RegexBasedAbstract.php @@ -0,0 +1,186 @@ +isStaticRoute($routeData)) { + $this->addStaticRoute($httpMethod, $routeData, $handler); + } else { + $this->addVariableRoute($httpMethod, $routeData, $handler); + } + } + + /** + * @return mixed[] + */ + public function getData() + { + if (empty($this->methodToRegexToRoutesMap)) { + return [$this->staticRoutes, []]; + } + + return [$this->staticRoutes, $this->generateVariableRouteData()]; + } + + /** + * @return mixed[] + */ + private function generateVariableRouteData() + { + $data = []; + foreach ($this->methodToRegexToRoutesMap as $method => $regexToRoutesMap) { + $chunkSize = $this->computeChunkSize(count($regexToRoutesMap)); + $chunks = array_chunk($regexToRoutesMap, $chunkSize, true); + $data[$method] = array_map([$this, 'processChunk'], $chunks); + } + return $data; + } + + /** + * @param int + * @return int + */ + private function computeChunkSize($count) + { + $numParts = max(1, round($count / $this->getApproxChunkSize())); + return (int) ceil($count / $numParts); + } + + /** + * @param mixed[] + * @return bool + */ + private function isStaticRoute($routeData) + { + return count($routeData) === 1 && is_string($routeData[0]); + } + + private function addStaticRoute($httpMethod, $routeData, $handler) + { + $routeStr = $routeData[0]; + + if (isset($this->staticRoutes[$httpMethod][$routeStr])) { + throw new BadRouteException(sprintf( + 'Cannot register two routes matching "%s" for method "%s"', + $routeStr, $httpMethod + )); + } + + if (isset($this->methodToRegexToRoutesMap[$httpMethod])) { + foreach ($this->methodToRegexToRoutesMap[$httpMethod] as $route) { + if ($route->matches($routeStr)) { + throw new BadRouteException(sprintf( + 'Static route "%s" is shadowed by previously defined variable route "%s" for method "%s"', + $routeStr, $route->regex, $httpMethod + )); + } + } + } + + $this->staticRoutes[$httpMethod][$routeStr] = $handler; + } + + private function addVariableRoute($httpMethod, $routeData, $handler) + { + list($regex, $variables) = $this->buildRegexForRoute($routeData); + + if (isset($this->methodToRegexToRoutesMap[$httpMethod][$regex])) { + throw new BadRouteException(sprintf( + 'Cannot register two routes matching "%s" for method "%s"', + $regex, $httpMethod + )); + } + + $this->methodToRegexToRoutesMap[$httpMethod][$regex] = new Route( + $httpMethod, $handler, $regex, $variables + ); + } + + /** + * @param mixed[] + * @return mixed[] + */ + private function buildRegexForRoute($routeData) + { + $regex = ''; + $variables = []; + foreach ($routeData as $part) { + if (is_string($part)) { + $regex .= preg_quote($part, '~'); + continue; + } + + list($varName, $regexPart) = $part; + + if (isset($variables[$varName])) { + throw new BadRouteException(sprintf( + 'Cannot use the same placeholder "%s" twice', $varName + )); + } + + if ($this->regexHasCapturingGroups($regexPart)) { + throw new BadRouteException(sprintf( + 'Regex "%s" for parameter "%s" contains a capturing group', + $regexPart, $varName + )); + } + + $variables[$varName] = $varName; + $regex .= '(' . $regexPart . ')'; + } + + return [$regex, $variables]; + } + + /** + * @param string + * @return bool + */ + private function regexHasCapturingGroups($regex) + { + if (false === strpos($regex, '(')) { + // Needs to have at least a ( to contain a capturing group + return false; + } + + // Semi-accurate detection for capturing groups + return (bool) preg_match( + '~ + (?: + \(\?\( + | \[ [^\]\\\\]* (?: \\\\ . [^\]\\\\]* )* \] + | \\\\ . + ) (*SKIP)(*FAIL) | + \( + (?! + \? (?! <(?![!=]) | P< | \' ) + | \* + ) + ~x', + $regex + ); + } +} diff --git a/api/vendor/nikic/fast-route/src/Dispatcher.php b/api/vendor/nikic/fast-route/src/Dispatcher.php new file mode 100644 index 0000000..4ae72a3 --- /dev/null +++ b/api/vendor/nikic/fast-route/src/Dispatcher.php @@ -0,0 +1,26 @@ + 'value', ...]] + * + * @param string $httpMethod + * @param string $uri + * + * @return array + */ + public function dispatch($httpMethod, $uri); +} diff --git a/api/vendor/nikic/fast-route/src/Dispatcher/CharCountBased.php b/api/vendor/nikic/fast-route/src/Dispatcher/CharCountBased.php new file mode 100644 index 0000000..ef1eec1 --- /dev/null +++ b/api/vendor/nikic/fast-route/src/Dispatcher/CharCountBased.php @@ -0,0 +1,31 @@ +staticRouteMap, $this->variableRouteData) = $data; + } + + protected function dispatchVariableRoute($routeData, $uri) + { + foreach ($routeData as $data) { + if (!preg_match($data['regex'], $uri . $data['suffix'], $matches)) { + continue; + } + + list($handler, $varNames) = $data['routeMap'][end($matches)]; + + $vars = []; + $i = 0; + foreach ($varNames as $varName) { + $vars[$varName] = $matches[++$i]; + } + return [self::FOUND, $handler, $vars]; + } + + return [self::NOT_FOUND]; + } +} diff --git a/api/vendor/nikic/fast-route/src/Dispatcher/GroupCountBased.php b/api/vendor/nikic/fast-route/src/Dispatcher/GroupCountBased.php new file mode 100644 index 0000000..493e7a9 --- /dev/null +++ b/api/vendor/nikic/fast-route/src/Dispatcher/GroupCountBased.php @@ -0,0 +1,31 @@ +staticRouteMap, $this->variableRouteData) = $data; + } + + protected function dispatchVariableRoute($routeData, $uri) + { + foreach ($routeData as $data) { + if (!preg_match($data['regex'], $uri, $matches)) { + continue; + } + + list($handler, $varNames) = $data['routeMap'][count($matches)]; + + $vars = []; + $i = 0; + foreach ($varNames as $varName) { + $vars[$varName] = $matches[++$i]; + } + return [self::FOUND, $handler, $vars]; + } + + return [self::NOT_FOUND]; + } +} diff --git a/api/vendor/nikic/fast-route/src/Dispatcher/GroupPosBased.php b/api/vendor/nikic/fast-route/src/Dispatcher/GroupPosBased.php new file mode 100644 index 0000000..498220e --- /dev/null +++ b/api/vendor/nikic/fast-route/src/Dispatcher/GroupPosBased.php @@ -0,0 +1,33 @@ +staticRouteMap, $this->variableRouteData) = $data; + } + + protected function dispatchVariableRoute($routeData, $uri) + { + foreach ($routeData as $data) { + if (!preg_match($data['regex'], $uri, $matches)) { + continue; + } + + // find first non-empty match + for ($i = 1; '' === $matches[$i]; ++$i); + + list($handler, $varNames) = $data['routeMap'][$i]; + + $vars = []; + foreach ($varNames as $varName) { + $vars[$varName] = $matches[$i++]; + } + return [self::FOUND, $handler, $vars]; + } + + return [self::NOT_FOUND]; + } +} diff --git a/api/vendor/nikic/fast-route/src/Dispatcher/MarkBased.php b/api/vendor/nikic/fast-route/src/Dispatcher/MarkBased.php new file mode 100644 index 0000000..22eb09b --- /dev/null +++ b/api/vendor/nikic/fast-route/src/Dispatcher/MarkBased.php @@ -0,0 +1,31 @@ +staticRouteMap, $this->variableRouteData) = $data; + } + + protected function dispatchVariableRoute($routeData, $uri) + { + foreach ($routeData as $data) { + if (!preg_match($data['regex'], $uri, $matches)) { + continue; + } + + list($handler, $varNames) = $data['routeMap'][$matches['MARK']]; + + $vars = []; + $i = 0; + foreach ($varNames as $varName) { + $vars[$varName] = $matches[++$i]; + } + return [self::FOUND, $handler, $vars]; + } + + return [self::NOT_FOUND]; + } +} diff --git a/api/vendor/nikic/fast-route/src/Dispatcher/RegexBasedAbstract.php b/api/vendor/nikic/fast-route/src/Dispatcher/RegexBasedAbstract.php new file mode 100644 index 0000000..206e879 --- /dev/null +++ b/api/vendor/nikic/fast-route/src/Dispatcher/RegexBasedAbstract.php @@ -0,0 +1,88 @@ +staticRouteMap[$httpMethod][$uri])) { + $handler = $this->staticRouteMap[$httpMethod][$uri]; + return [self::FOUND, $handler, []]; + } + + $varRouteData = $this->variableRouteData; + if (isset($varRouteData[$httpMethod])) { + $result = $this->dispatchVariableRoute($varRouteData[$httpMethod], $uri); + if ($result[0] === self::FOUND) { + return $result; + } + } + + // For HEAD requests, attempt fallback to GET + if ($httpMethod === 'HEAD') { + if (isset($this->staticRouteMap['GET'][$uri])) { + $handler = $this->staticRouteMap['GET'][$uri]; + return [self::FOUND, $handler, []]; + } + if (isset($varRouteData['GET'])) { + $result = $this->dispatchVariableRoute($varRouteData['GET'], $uri); + if ($result[0] === self::FOUND) { + return $result; + } + } + } + + // If nothing else matches, try fallback routes + if (isset($this->staticRouteMap['*'][$uri])) { + $handler = $this->staticRouteMap['*'][$uri]; + return [self::FOUND, $handler, []]; + } + if (isset($varRouteData['*'])) { + $result = $this->dispatchVariableRoute($varRouteData['*'], $uri); + if ($result[0] === self::FOUND) { + return $result; + } + } + + // Find allowed methods for this URI by matching against all other HTTP methods as well + $allowedMethods = []; + + foreach ($this->staticRouteMap as $method => $uriMap) { + if ($method !== $httpMethod && isset($uriMap[$uri])) { + $allowedMethods[] = $method; + } + } + + foreach ($varRouteData as $method => $routeData) { + if ($method === $httpMethod) { + continue; + } + + $result = $this->dispatchVariableRoute($routeData, $uri); + if ($result[0] === self::FOUND) { + $allowedMethods[] = $method; + } + } + + // If there are no allowed methods the route simply does not exist + if ($allowedMethods) { + return [self::METHOD_NOT_ALLOWED, $allowedMethods]; + } + + return [self::NOT_FOUND]; + } +} diff --git a/api/vendor/nikic/fast-route/src/Route.php b/api/vendor/nikic/fast-route/src/Route.php new file mode 100644 index 0000000..e1bf7dd --- /dev/null +++ b/api/vendor/nikic/fast-route/src/Route.php @@ -0,0 +1,47 @@ +httpMethod = $httpMethod; + $this->handler = $handler; + $this->regex = $regex; + $this->variables = $variables; + } + + /** + * Tests whether this route matches the given string. + * + * @param string $str + * + * @return bool + */ + public function matches($str) + { + $regex = '~^' . $this->regex . '$~'; + return (bool) preg_match($regex, $str); + } +} diff --git a/api/vendor/nikic/fast-route/src/RouteCollector.php b/api/vendor/nikic/fast-route/src/RouteCollector.php new file mode 100644 index 0000000..c1c1762 --- /dev/null +++ b/api/vendor/nikic/fast-route/src/RouteCollector.php @@ -0,0 +1,152 @@ +routeParser = $routeParser; + $this->dataGenerator = $dataGenerator; + $this->currentGroupPrefix = ''; + } + + /** + * Adds a route to the collection. + * + * The syntax used in the $route string depends on the used route parser. + * + * @param string|string[] $httpMethod + * @param string $route + * @param mixed $handler + */ + public function addRoute($httpMethod, $route, $handler) + { + $route = $this->currentGroupPrefix . $route; + $routeDatas = $this->routeParser->parse($route); + foreach ((array) $httpMethod as $method) { + foreach ($routeDatas as $routeData) { + $this->dataGenerator->addRoute($method, $routeData, $handler); + } + } + } + + /** + * Create a route group with a common prefix. + * + * All routes created in the passed callback will have the given group prefix prepended. + * + * @param string $prefix + * @param callable $callback + */ + public function addGroup($prefix, callable $callback) + { + $previousGroupPrefix = $this->currentGroupPrefix; + $this->currentGroupPrefix = $previousGroupPrefix . $prefix; + $callback($this); + $this->currentGroupPrefix = $previousGroupPrefix; + } + + /** + * Adds a GET route to the collection + * + * This is simply an alias of $this->addRoute('GET', $route, $handler) + * + * @param string $route + * @param mixed $handler + */ + public function get($route, $handler) + { + $this->addRoute('GET', $route, $handler); + } + + /** + * Adds a POST route to the collection + * + * This is simply an alias of $this->addRoute('POST', $route, $handler) + * + * @param string $route + * @param mixed $handler + */ + public function post($route, $handler) + { + $this->addRoute('POST', $route, $handler); + } + + /** + * Adds a PUT route to the collection + * + * This is simply an alias of $this->addRoute('PUT', $route, $handler) + * + * @param string $route + * @param mixed $handler + */ + public function put($route, $handler) + { + $this->addRoute('PUT', $route, $handler); + } + + /** + * Adds a DELETE route to the collection + * + * This is simply an alias of $this->addRoute('DELETE', $route, $handler) + * + * @param string $route + * @param mixed $handler + */ + public function delete($route, $handler) + { + $this->addRoute('DELETE', $route, $handler); + } + + /** + * Adds a PATCH route to the collection + * + * This is simply an alias of $this->addRoute('PATCH', $route, $handler) + * + * @param string $route + * @param mixed $handler + */ + public function patch($route, $handler) + { + $this->addRoute('PATCH', $route, $handler); + } + + /** + * Adds a HEAD route to the collection + * + * This is simply an alias of $this->addRoute('HEAD', $route, $handler) + * + * @param string $route + * @param mixed $handler + */ + public function head($route, $handler) + { + $this->addRoute('HEAD', $route, $handler); + } + + /** + * Returns the collected route data, as provided by the data generator. + * + * @return array + */ + public function getData() + { + return $this->dataGenerator->getData(); + } +} diff --git a/api/vendor/nikic/fast-route/src/RouteParser.php b/api/vendor/nikic/fast-route/src/RouteParser.php new file mode 100644 index 0000000..6a7685c --- /dev/null +++ b/api/vendor/nikic/fast-route/src/RouteParser.php @@ -0,0 +1,37 @@ + $segment) { + if ($segment === '' && $n !== 0) { + throw new BadRouteException('Empty optional part'); + } + + $currentRoute .= $segment; + $routeDatas[] = $this->parsePlaceholders($currentRoute); + } + return $routeDatas; + } + + /** + * Parses a route string that does not contain optional segments. + * + * @param string + * @return mixed[] + */ + private function parsePlaceholders($route) + { + if (!preg_match_all( + '~' . self::VARIABLE_REGEX . '~x', $route, $matches, + PREG_OFFSET_CAPTURE | PREG_SET_ORDER + )) { + return [$route]; + } + + $offset = 0; + $routeData = []; + foreach ($matches as $set) { + if ($set[0][1] > $offset) { + $routeData[] = substr($route, $offset, $set[0][1] - $offset); + } + $routeData[] = [ + $set[1][0], + isset($set[2]) ? trim($set[2][0]) : self::DEFAULT_DISPATCH_REGEX + ]; + $offset = $set[0][1] + strlen($set[0][0]); + } + + if ($offset !== strlen($route)) { + $routeData[] = substr($route, $offset); + } + + return $routeData; + } +} diff --git a/api/vendor/nikic/fast-route/src/bootstrap.php b/api/vendor/nikic/fast-route/src/bootstrap.php new file mode 100644 index 0000000..0bce3a4 --- /dev/null +++ b/api/vendor/nikic/fast-route/src/bootstrap.php @@ -0,0 +1,12 @@ + 'FastRoute\\RouteParser\\Std', + 'dataGenerator' => 'FastRoute\\DataGenerator\\GroupCountBased', + 'dispatcher' => 'FastRoute\\Dispatcher\\GroupCountBased', + 'routeCollector' => 'FastRoute\\RouteCollector', + ]; + + /** @var RouteCollector $routeCollector */ + $routeCollector = new $options['routeCollector']( + new $options['routeParser'], new $options['dataGenerator'] + ); + $routeDefinitionCallback($routeCollector); + + return new $options['dispatcher']($routeCollector->getData()); + } + + /** + * @param callable $routeDefinitionCallback + * @param array $options + * + * @return Dispatcher + */ + function cachedDispatcher(callable $routeDefinitionCallback, array $options = []) + { + $options += [ + 'routeParser' => 'FastRoute\\RouteParser\\Std', + 'dataGenerator' => 'FastRoute\\DataGenerator\\GroupCountBased', + 'dispatcher' => 'FastRoute\\Dispatcher\\GroupCountBased', + 'routeCollector' => 'FastRoute\\RouteCollector', + 'cacheDisabled' => false, + ]; + + if (!isset($options['cacheFile'])) { + throw new \LogicException('Must specify "cacheFile" option'); + } + + if (!$options['cacheDisabled'] && file_exists($options['cacheFile'])) { + $dispatchData = require $options['cacheFile']; + if (!is_array($dispatchData)) { + throw new \RuntimeException('Invalid cache file "' . $options['cacheFile'] . '"'); + } + return new $options['dispatcher']($dispatchData); + } + + $routeCollector = new $options['routeCollector']( + new $options['routeParser'], new $options['dataGenerator'] + ); + $routeDefinitionCallback($routeCollector); + + /** @var RouteCollector $routeCollector */ + $dispatchData = $routeCollector->getData(); + if (!$options['cacheDisabled']) { + file_put_contents( + $options['cacheFile'], + ' $this->getDataGeneratorClass(), + 'dispatcher' => $this->getDispatcherClass() + ]; + } + + /** + * @dataProvider provideFoundDispatchCases + */ + public function testFoundDispatches($method, $uri, $callback, $handler, $argDict) + { + $dispatcher = \FastRoute\simpleDispatcher($callback, $this->generateDispatcherOptions()); + $info = $dispatcher->dispatch($method, $uri); + $this->assertSame($dispatcher::FOUND, $info[0]); + $this->assertSame($handler, $info[1]); + $this->assertSame($argDict, $info[2]); + } + + /** + * @dataProvider provideNotFoundDispatchCases + */ + public function testNotFoundDispatches($method, $uri, $callback) + { + $dispatcher = \FastRoute\simpleDispatcher($callback, $this->generateDispatcherOptions()); + $routeInfo = $dispatcher->dispatch($method, $uri); + $this->assertArrayNotHasKey(1, $routeInfo, + 'NOT_FOUND result must only contain a single element in the returned info array' + ); + $this->assertSame($dispatcher::NOT_FOUND, $routeInfo[0]); + } + + /** + * @dataProvider provideMethodNotAllowedDispatchCases + */ + public function testMethodNotAllowedDispatches($method, $uri, $callback, $availableMethods) + { + $dispatcher = \FastRoute\simpleDispatcher($callback, $this->generateDispatcherOptions()); + $routeInfo = $dispatcher->dispatch($method, $uri); + $this->assertArrayHasKey(1, $routeInfo, + 'METHOD_NOT_ALLOWED result must return an array of allowed methods at index 1' + ); + + list($routedStatus, $methodArray) = $dispatcher->dispatch($method, $uri); + $this->assertSame($dispatcher::METHOD_NOT_ALLOWED, $routedStatus); + $this->assertSame($availableMethods, $methodArray); + } + + /** + * @expectedException \FastRoute\BadRouteException + * @expectedExceptionMessage Cannot use the same placeholder "test" twice + */ + public function testDuplicateVariableNameError() + { + \FastRoute\simpleDispatcher(function (RouteCollector $r) { + $r->addRoute('GET', '/foo/{test}/{test:\d+}', 'handler0'); + }, $this->generateDispatcherOptions()); + } + + /** + * @expectedException \FastRoute\BadRouteException + * @expectedExceptionMessage Cannot register two routes matching "/user/([^/]+)" for method "GET" + */ + public function testDuplicateVariableRoute() + { + \FastRoute\simpleDispatcher(function (RouteCollector $r) { + $r->addRoute('GET', '/user/{id}', 'handler0'); // oops, forgot \d+ restriction ;) + $r->addRoute('GET', '/user/{name}', 'handler1'); + }, $this->generateDispatcherOptions()); + } + + /** + * @expectedException \FastRoute\BadRouteException + * @expectedExceptionMessage Cannot register two routes matching "/user" for method "GET" + */ + public function testDuplicateStaticRoute() + { + \FastRoute\simpleDispatcher(function (RouteCollector $r) { + $r->addRoute('GET', '/user', 'handler0'); + $r->addRoute('GET', '/user', 'handler1'); + }, $this->generateDispatcherOptions()); + } + + /** + * @expectedException \FastRoute\BadRouteException + * @expectedExceptionMessage Static route "/user/nikic" is shadowed by previously defined variable route "/user/([^/]+)" for method "GET" + */ + public function testShadowedStaticRoute() + { + \FastRoute\simpleDispatcher(function (RouteCollector $r) { + $r->addRoute('GET', '/user/{name}', 'handler0'); + $r->addRoute('GET', '/user/nikic', 'handler1'); + }, $this->generateDispatcherOptions()); + } + + /** + * @expectedException \FastRoute\BadRouteException + * @expectedExceptionMessage Regex "(en|de)" for parameter "lang" contains a capturing group + */ + public function testCapturing() + { + \FastRoute\simpleDispatcher(function (RouteCollector $r) { + $r->addRoute('GET', '/{lang:(en|de)}', 'handler0'); + }, $this->generateDispatcherOptions()); + } + + public function provideFoundDispatchCases() + { + $cases = []; + + // 0 --------------------------------------------------------------------------------------> + + $callback = function (RouteCollector $r) { + $r->addRoute('GET', '/resource/123/456', 'handler0'); + }; + + $method = 'GET'; + $uri = '/resource/123/456'; + $handler = 'handler0'; + $argDict = []; + + $cases[] = [$method, $uri, $callback, $handler, $argDict]; + + // 1 --------------------------------------------------------------------------------------> + + $callback = function (RouteCollector $r) { + $r->addRoute('GET', '/handler0', 'handler0'); + $r->addRoute('GET', '/handler1', 'handler1'); + $r->addRoute('GET', '/handler2', 'handler2'); + }; + + $method = 'GET'; + $uri = '/handler2'; + $handler = 'handler2'; + $argDict = []; + + $cases[] = [$method, $uri, $callback, $handler, $argDict]; + + // 2 --------------------------------------------------------------------------------------> + + $callback = function (RouteCollector $r) { + $r->addRoute('GET', '/user/{name}/{id:[0-9]+}', 'handler0'); + $r->addRoute('GET', '/user/{id:[0-9]+}', 'handler1'); + $r->addRoute('GET', '/user/{name}', 'handler2'); + }; + + $method = 'GET'; + $uri = '/user/rdlowrey'; + $handler = 'handler2'; + $argDict = ['name' => 'rdlowrey']; + + $cases[] = [$method, $uri, $callback, $handler, $argDict]; + + // 3 --------------------------------------------------------------------------------------> + + // reuse $callback from #2 + + $method = 'GET'; + $uri = '/user/12345'; + $handler = 'handler1'; + $argDict = ['id' => '12345']; + + $cases[] = [$method, $uri, $callback, $handler, $argDict]; + + // 4 --------------------------------------------------------------------------------------> + + // reuse $callback from #3 + + $method = 'GET'; + $uri = '/user/NaN'; + $handler = 'handler2'; + $argDict = ['name' => 'NaN']; + + $cases[] = [$method, $uri, $callback, $handler, $argDict]; + + // 5 --------------------------------------------------------------------------------------> + + // reuse $callback from #4 + + $method = 'GET'; + $uri = '/user/rdlowrey/12345'; + $handler = 'handler0'; + $argDict = ['name' => 'rdlowrey', 'id' => '12345']; + + $cases[] = [$method, $uri, $callback, $handler, $argDict]; + + // 6 --------------------------------------------------------------------------------------> + + $callback = function (RouteCollector $r) { + $r->addRoute('GET', '/user/{id:[0-9]+}', 'handler0'); + $r->addRoute('GET', '/user/12345/extension', 'handler1'); + $r->addRoute('GET', '/user/{id:[0-9]+}.{extension}', 'handler2'); + }; + + $method = 'GET'; + $uri = '/user/12345.svg'; + $handler = 'handler2'; + $argDict = ['id' => '12345', 'extension' => 'svg']; + + $cases[] = [$method, $uri, $callback, $handler, $argDict]; + + // 7 ----- Test GET method fallback on HEAD route miss ------------------------------------> + + $callback = function (RouteCollector $r) { + $r->addRoute('GET', '/user/{name}', 'handler0'); + $r->addRoute('GET', '/user/{name}/{id:[0-9]+}', 'handler1'); + $r->addRoute('GET', '/static0', 'handler2'); + $r->addRoute('GET', '/static1', 'handler3'); + $r->addRoute('HEAD', '/static1', 'handler4'); + }; + + $method = 'HEAD'; + $uri = '/user/rdlowrey'; + $handler = 'handler0'; + $argDict = ['name' => 'rdlowrey']; + + $cases[] = [$method, $uri, $callback, $handler, $argDict]; + + // 8 ----- Test GET method fallback on HEAD route miss ------------------------------------> + + // reuse $callback from #7 + + $method = 'HEAD'; + $uri = '/user/rdlowrey/1234'; + $handler = 'handler1'; + $argDict = ['name' => 'rdlowrey', 'id' => '1234']; + + $cases[] = [$method, $uri, $callback, $handler, $argDict]; + + // 9 ----- Test GET method fallback on HEAD route miss ------------------------------------> + + // reuse $callback from #8 + + $method = 'HEAD'; + $uri = '/static0'; + $handler = 'handler2'; + $argDict = []; + + $cases[] = [$method, $uri, $callback, $handler, $argDict]; + + // 10 ---- Test existing HEAD route used if available (no fallback) -----------------------> + + // reuse $callback from #9 + + $method = 'HEAD'; + $uri = '/static1'; + $handler = 'handler4'; + $argDict = []; + + $cases[] = [$method, $uri, $callback, $handler, $argDict]; + + // 11 ---- More specified routes are not shadowed by less specific of another method ------> + + $callback = function (RouteCollector $r) { + $r->addRoute('GET', '/user/{name}', 'handler0'); + $r->addRoute('POST', '/user/{name:[a-z]+}', 'handler1'); + }; + + $method = 'POST'; + $uri = '/user/rdlowrey'; + $handler = 'handler1'; + $argDict = ['name' => 'rdlowrey']; + + $cases[] = [$method, $uri, $callback, $handler, $argDict]; + + // 12 ---- Handler of more specific routes is used, if it occurs first --------------------> + + $callback = function (RouteCollector $r) { + $r->addRoute('GET', '/user/{name}', 'handler0'); + $r->addRoute('POST', '/user/{name:[a-z]+}', 'handler1'); + $r->addRoute('POST', '/user/{name}', 'handler2'); + }; + + $method = 'POST'; + $uri = '/user/rdlowrey'; + $handler = 'handler1'; + $argDict = ['name' => 'rdlowrey']; + + $cases[] = [$method, $uri, $callback, $handler, $argDict]; + + // 13 ---- Route with constant suffix -----------------------------------------------------> + + $callback = function (RouteCollector $r) { + $r->addRoute('GET', '/user/{name}', 'handler0'); + $r->addRoute('GET', '/user/{name}/edit', 'handler1'); + }; + + $method = 'GET'; + $uri = '/user/rdlowrey/edit'; + $handler = 'handler1'; + $argDict = ['name' => 'rdlowrey']; + + $cases[] = [$method, $uri, $callback, $handler, $argDict]; + + // 14 ---- Handle multiple methods with the same handler ----------------------------------> + + $callback = function (RouteCollector $r) { + $r->addRoute(['GET', 'POST'], '/user', 'handlerGetPost'); + $r->addRoute(['DELETE'], '/user', 'handlerDelete'); + $r->addRoute([], '/user', 'handlerNone'); + }; + + $argDict = []; + $cases[] = ['GET', '/user', $callback, 'handlerGetPost', $argDict]; + $cases[] = ['POST', '/user', $callback, 'handlerGetPost', $argDict]; + $cases[] = ['DELETE', '/user', $callback, 'handlerDelete', $argDict]; + + // 17 ---- + + $callback = function (RouteCollector $r) { + $r->addRoute('POST', '/user.json', 'handler0'); + $r->addRoute('GET', '/{entity}.json', 'handler1'); + }; + + $cases[] = ['GET', '/user.json', $callback, 'handler1', ['entity' => 'user']]; + + // 18 ---- + + $callback = function (RouteCollector $r) { + $r->addRoute('GET', '', 'handler0'); + }; + + $cases[] = ['GET', '', $callback, 'handler0', []]; + + // 19 ---- + + $callback = function (RouteCollector $r) { + $r->addRoute('HEAD', '/a/{foo}', 'handler0'); + $r->addRoute('GET', '/b/{foo}', 'handler1'); + }; + + $cases[] = ['HEAD', '/b/bar', $callback, 'handler1', ['foo' => 'bar']]; + + // 20 ---- + + $callback = function (RouteCollector $r) { + $r->addRoute('HEAD', '/a', 'handler0'); + $r->addRoute('GET', '/b', 'handler1'); + }; + + $cases[] = ['HEAD', '/b', $callback, 'handler1', []]; + + // 21 ---- + + $callback = function (RouteCollector $r) { + $r->addRoute('GET', '/foo', 'handler0'); + $r->addRoute('HEAD', '/{bar}', 'handler1'); + }; + + $cases[] = ['HEAD', '/foo', $callback, 'handler1', ['bar' => 'foo']]; + + // 22 ---- + + $callback = function (RouteCollector $r) { + $r->addRoute('*', '/user', 'handler0'); + $r->addRoute('*', '/{user}', 'handler1'); + $r->addRoute('GET', '/user', 'handler2'); + }; + + $cases[] = ['GET', '/user', $callback, 'handler2', []]; + + // 23 ---- + + $callback = function (RouteCollector $r) { + $r->addRoute('*', '/user', 'handler0'); + $r->addRoute('GET', '/user', 'handler1'); + }; + + $cases[] = ['POST', '/user', $callback, 'handler0', []]; + + // 24 ---- + + $cases[] = ['HEAD', '/user', $callback, 'handler1', []]; + + // 25 ---- + + $callback = function (RouteCollector $r) { + $r->addRoute('GET', '/{bar}', 'handler0'); + $r->addRoute('*', '/foo', 'handler1'); + }; + + $cases[] = ['GET', '/foo', $callback, 'handler0', ['bar' => 'foo']]; + + // 26 ---- + + $callback = function(RouteCollector $r) { + $r->addRoute('GET', '/user', 'handler0'); + $r->addRoute('*', '/{foo:.*}', 'handler1'); + }; + + $cases[] = ['POST', '/bar', $callback, 'handler1', ['foo' => 'bar']]; + + // x --------------------------------------------------------------------------------------> + + return $cases; + } + + public function provideNotFoundDispatchCases() + { + $cases = []; + + // 0 --------------------------------------------------------------------------------------> + + $callback = function (RouteCollector $r) { + $r->addRoute('GET', '/resource/123/456', 'handler0'); + }; + + $method = 'GET'; + $uri = '/not-found'; + + $cases[] = [$method, $uri, $callback]; + + // 1 --------------------------------------------------------------------------------------> + + // reuse callback from #0 + $method = 'POST'; + $uri = '/not-found'; + + $cases[] = [$method, $uri, $callback]; + + // 2 --------------------------------------------------------------------------------------> + + // reuse callback from #1 + $method = 'PUT'; + $uri = '/not-found'; + + $cases[] = [$method, $uri, $callback]; + + // 3 --------------------------------------------------------------------------------------> + + $callback = function (RouteCollector $r) { + $r->addRoute('GET', '/handler0', 'handler0'); + $r->addRoute('GET', '/handler1', 'handler1'); + $r->addRoute('GET', '/handler2', 'handler2'); + }; + + $method = 'GET'; + $uri = '/not-found'; + + $cases[] = [$method, $uri, $callback]; + + // 4 --------------------------------------------------------------------------------------> + + $callback = function (RouteCollector $r) { + $r->addRoute('GET', '/user/{name}/{id:[0-9]+}', 'handler0'); + $r->addRoute('GET', '/user/{id:[0-9]+}', 'handler1'); + $r->addRoute('GET', '/user/{name}', 'handler2'); + }; + + $method = 'GET'; + $uri = '/not-found'; + + $cases[] = [$method, $uri, $callback]; + + // 5 --------------------------------------------------------------------------------------> + + // reuse callback from #4 + $method = 'GET'; + $uri = '/user/rdlowrey/12345/not-found'; + + $cases[] = [$method, $uri, $callback]; + + // 6 --------------------------------------------------------------------------------------> + + // reuse callback from #5 + $method = 'HEAD'; + + $cases[] = [$method, $uri, $callback]; + + // x --------------------------------------------------------------------------------------> + + return $cases; + } + + public function provideMethodNotAllowedDispatchCases() + { + $cases = []; + + // 0 --------------------------------------------------------------------------------------> + + $callback = function (RouteCollector $r) { + $r->addRoute('GET', '/resource/123/456', 'handler0'); + }; + + $method = 'POST'; + $uri = '/resource/123/456'; + $allowedMethods = ['GET']; + + $cases[] = [$method, $uri, $callback, $allowedMethods]; + + // 1 --------------------------------------------------------------------------------------> + + $callback = function (RouteCollector $r) { + $r->addRoute('GET', '/resource/123/456', 'handler0'); + $r->addRoute('POST', '/resource/123/456', 'handler1'); + $r->addRoute('PUT', '/resource/123/456', 'handler2'); + $r->addRoute('*', '/', 'handler3'); + }; + + $method = 'DELETE'; + $uri = '/resource/123/456'; + $allowedMethods = ['GET', 'POST', 'PUT']; + + $cases[] = [$method, $uri, $callback, $allowedMethods]; + + // 2 --------------------------------------------------------------------------------------> + + $callback = function (RouteCollector $r) { + $r->addRoute('GET', '/user/{name}/{id:[0-9]+}', 'handler0'); + $r->addRoute('POST', '/user/{name}/{id:[0-9]+}', 'handler1'); + $r->addRoute('PUT', '/user/{name}/{id:[0-9]+}', 'handler2'); + $r->addRoute('PATCH', '/user/{name}/{id:[0-9]+}', 'handler3'); + }; + + $method = 'DELETE'; + $uri = '/user/rdlowrey/42'; + $allowedMethods = ['GET', 'POST', 'PUT', 'PATCH']; + + $cases[] = [$method, $uri, $callback, $allowedMethods]; + + // 3 --------------------------------------------------------------------------------------> + + $callback = function (RouteCollector $r) { + $r->addRoute('POST', '/user/{name}', 'handler1'); + $r->addRoute('PUT', '/user/{name:[a-z]+}', 'handler2'); + $r->addRoute('PATCH', '/user/{name:[a-z]+}', 'handler3'); + }; + + $method = 'GET'; + $uri = '/user/rdlowrey'; + $allowedMethods = ['POST', 'PUT', 'PATCH']; + + $cases[] = [$method, $uri, $callback, $allowedMethods]; + + // 4 --------------------------------------------------------------------------------------> + + $callback = function (RouteCollector $r) { + $r->addRoute(['GET', 'POST'], '/user', 'handlerGetPost'); + $r->addRoute(['DELETE'], '/user', 'handlerDelete'); + $r->addRoute([], '/user', 'handlerNone'); + }; + + $cases[] = ['PUT', '/user', $callback, ['GET', 'POST', 'DELETE']]; + + // 5 + + $callback = function (RouteCollector $r) { + $r->addRoute('POST', '/user.json', 'handler0'); + $r->addRoute('GET', '/{entity}.json', 'handler1'); + }; + + $cases[] = ['PUT', '/user.json', $callback, ['POST', 'GET']]; + + // x --------------------------------------------------------------------------------------> + + return $cases; + } +} diff --git a/api/vendor/nikic/fast-route/test/Dispatcher/GroupCountBasedTest.php b/api/vendor/nikic/fast-route/test/Dispatcher/GroupCountBasedTest.php new file mode 100644 index 0000000..f821ef5 --- /dev/null +++ b/api/vendor/nikic/fast-route/test/Dispatcher/GroupCountBasedTest.php @@ -0,0 +1,16 @@ +markTestSkipped('PHP 5.6 required for MARK support'); + } + } + + protected function getDispatcherClass() + { + return 'FastRoute\\Dispatcher\\MarkBased'; + } + + protected function getDataGeneratorClass() + { + return 'FastRoute\\DataGenerator\\MarkBased'; + } +} diff --git a/api/vendor/nikic/fast-route/test/HackTypechecker/HackTypecheckerTest.php b/api/vendor/nikic/fast-route/test/HackTypechecker/HackTypecheckerTest.php new file mode 100644 index 0000000..b6fc53f --- /dev/null +++ b/api/vendor/nikic/fast-route/test/HackTypechecker/HackTypecheckerTest.php @@ -0,0 +1,44 @@ +markTestSkipped('HHVM only'); + } + if (!version_compare(HHVM_VERSION, '3.9.0', '>=')) { + $this->markTestSkipped('classname requires HHVM 3.9+'); + } + + // The typechecker recurses the whole tree, so it makes sure + // that everything in fixtures/ is valid when this runs. + + $output = []; + $exit_code = null; + exec( + 'hh_server --check ' . escapeshellarg(__DIR__ . '/../../') . ' 2>&1', + $output, + $exit_code + ); + if ($exit_code === self::SERVER_ALREADY_RUNNING_CODE) { + $this->assertTrue( + $recurse, + 'Typechecker still running after running hh_client stop' + ); + // Server already running - 3.10 => 3.11 regression: + // https://github.com/facebook/hhvm/issues/6646 + exec('hh_client stop 2>/dev/null'); + $this->testTypechecks(/* recurse = */ false); + return; + + } + $this->assertSame(0, $exit_code, implode("\n", $output)); + } +} diff --git a/api/vendor/nikic/fast-route/test/HackTypechecker/fixtures/all_options.php b/api/vendor/nikic/fast-route/test/HackTypechecker/fixtures/all_options.php new file mode 100644 index 0000000..05a9af2 --- /dev/null +++ b/api/vendor/nikic/fast-route/test/HackTypechecker/fixtures/all_options.php @@ -0,0 +1,29 @@ + {}, + shape( + 'routeParser' => \FastRoute\RouteParser\Std::class, + 'dataGenerator' => \FastRoute\DataGenerator\GroupCountBased::class, + 'dispatcher' => \FastRoute\Dispatcher\GroupCountBased::class, + 'routeCollector' => \FastRoute\RouteCollector::class, + ), + ); +} + +function all_options_cached(): \FastRoute\Dispatcher { + return \FastRoute\cachedDispatcher( + $collector ==> {}, + shape( + 'routeParser' => \FastRoute\RouteParser\Std::class, + 'dataGenerator' => \FastRoute\DataGenerator\GroupCountBased::class, + 'dispatcher' => \FastRoute\Dispatcher\GroupCountBased::class, + 'routeCollector' => \FastRoute\RouteCollector::class, + 'cacheFile' => '/dev/null', + 'cacheDisabled' => false, + ), + ); +} diff --git a/api/vendor/nikic/fast-route/test/HackTypechecker/fixtures/empty_options.php b/api/vendor/nikic/fast-route/test/HackTypechecker/fixtures/empty_options.php new file mode 100644 index 0000000..61eb541 --- /dev/null +++ b/api/vendor/nikic/fast-route/test/HackTypechecker/fixtures/empty_options.php @@ -0,0 +1,11 @@ + {}, shape()); +} + +function empty_options_cached(): \FastRoute\Dispatcher { + return \FastRoute\cachedDispatcher($collector ==> {}, shape()); +} diff --git a/api/vendor/nikic/fast-route/test/HackTypechecker/fixtures/no_options.php b/api/vendor/nikic/fast-route/test/HackTypechecker/fixtures/no_options.php new file mode 100644 index 0000000..44b5422 --- /dev/null +++ b/api/vendor/nikic/fast-route/test/HackTypechecker/fixtures/no_options.php @@ -0,0 +1,11 @@ + {}); +} + +function no_options_cached(): \FastRoute\Dispatcher { + return \FastRoute\cachedDispatcher($collector ==> {}); +} diff --git a/api/vendor/nikic/fast-route/test/RouteCollectorTest.php b/api/vendor/nikic/fast-route/test/RouteCollectorTest.php new file mode 100644 index 0000000..cc54407 --- /dev/null +++ b/api/vendor/nikic/fast-route/test/RouteCollectorTest.php @@ -0,0 +1,108 @@ +delete('/delete', 'delete'); + $r->get('/get', 'get'); + $r->head('/head', 'head'); + $r->patch('/patch', 'patch'); + $r->post('/post', 'post'); + $r->put('/put', 'put'); + + $expected = [ + ['DELETE', '/delete', 'delete'], + ['GET', '/get', 'get'], + ['HEAD', '/head', 'head'], + ['PATCH', '/patch', 'patch'], + ['POST', '/post', 'post'], + ['PUT', '/put', 'put'], + ]; + + $this->assertSame($expected, $r->routes); + } + + public function testGroups() + { + $r = new DummyRouteCollector(); + + $r->delete('/delete', 'delete'); + $r->get('/get', 'get'); + $r->head('/head', 'head'); + $r->patch('/patch', 'patch'); + $r->post('/post', 'post'); + $r->put('/put', 'put'); + + $r->addGroup('/group-one', function (DummyRouteCollector $r) { + $r->delete('/delete', 'delete'); + $r->get('/get', 'get'); + $r->head('/head', 'head'); + $r->patch('/patch', 'patch'); + $r->post('/post', 'post'); + $r->put('/put', 'put'); + + $r->addGroup('/group-two', function (DummyRouteCollector $r) { + $r->delete('/delete', 'delete'); + $r->get('/get', 'get'); + $r->head('/head', 'head'); + $r->patch('/patch', 'patch'); + $r->post('/post', 'post'); + $r->put('/put', 'put'); + }); + }); + + $r->addGroup('/admin', function (DummyRouteCollector $r) { + $r->get('-some-info', 'admin-some-info'); + }); + $r->addGroup('/admin-', function (DummyRouteCollector $r) { + $r->get('more-info', 'admin-more-info'); + }); + + $expected = [ + ['DELETE', '/delete', 'delete'], + ['GET', '/get', 'get'], + ['HEAD', '/head', 'head'], + ['PATCH', '/patch', 'patch'], + ['POST', '/post', 'post'], + ['PUT', '/put', 'put'], + ['DELETE', '/group-one/delete', 'delete'], + ['GET', '/group-one/get', 'get'], + ['HEAD', '/group-one/head', 'head'], + ['PATCH', '/group-one/patch', 'patch'], + ['POST', '/group-one/post', 'post'], + ['PUT', '/group-one/put', 'put'], + ['DELETE', '/group-one/group-two/delete', 'delete'], + ['GET', '/group-one/group-two/get', 'get'], + ['HEAD', '/group-one/group-two/head', 'head'], + ['PATCH', '/group-one/group-two/patch', 'patch'], + ['POST', '/group-one/group-two/post', 'post'], + ['PUT', '/group-one/group-two/put', 'put'], + ['GET', '/admin-some-info', 'admin-some-info'], + ['GET', '/admin-more-info', 'admin-more-info'], + ]; + + $this->assertSame($expected, $r->routes); + } +} + +class DummyRouteCollector extends RouteCollector +{ + public $routes = []; + + public function __construct() + { + } + + public function addRoute($method, $route, $handler) + { + $route = $this->currentGroupPrefix . $route; + $this->routes[] = [$method, $route, $handler]; + } +} diff --git a/api/vendor/nikic/fast-route/test/RouteParser/StdTest.php b/api/vendor/nikic/fast-route/test/RouteParser/StdTest.php new file mode 100644 index 0000000..e13e4de --- /dev/null +++ b/api/vendor/nikic/fast-route/test/RouteParser/StdTest.php @@ -0,0 +1,154 @@ +parse($routeString); + $this->assertSame($expectedRouteDatas, $routeDatas); + } + + /** @dataProvider provideTestParseError */ + public function testParseError($routeString, $expectedExceptionMessage) + { + $parser = new Std(); + $this->setExpectedException('FastRoute\\BadRouteException', $expectedExceptionMessage); + $parser->parse($routeString); + } + + public function provideTestParse() + { + return [ + [ + '/test', + [ + ['/test'], + ] + ], + [ + '/test/{param}', + [ + ['/test/', ['param', '[^/]+']], + ] + ], + [ + '/te{ param }st', + [ + ['/te', ['param', '[^/]+'], 'st'] + ] + ], + [ + '/test/{param1}/test2/{param2}', + [ + ['/test/', ['param1', '[^/]+'], '/test2/', ['param2', '[^/]+']] + ] + ], + [ + '/test/{param:\d+}', + [ + ['/test/', ['param', '\d+']] + ] + ], + [ + '/test/{ param : \d{1,9} }', + [ + ['/test/', ['param', '\d{1,9}']] + ] + ], + [ + '/test[opt]', + [ + ['/test'], + ['/testopt'], + ] + ], + [ + '/test[/{param}]', + [ + ['/test'], + ['/test/', ['param', '[^/]+']], + ] + ], + [ + '/{param}[opt]', + [ + ['/', ['param', '[^/]+']], + ['/', ['param', '[^/]+'], 'opt'] + ] + ], + [ + '/test[/{name}[/{id:[0-9]+}]]', + [ + ['/test'], + ['/test/', ['name', '[^/]+']], + ['/test/', ['name', '[^/]+'], '/', ['id', '[0-9]+']], + ] + ], + [ + '', + [ + [''], + ] + ], + [ + '[test]', + [ + [''], + ['test'], + ] + ], + [ + '/{foo-bar}', + [ + ['/', ['foo-bar', '[^/]+']] + ] + ], + [ + '/{_foo:.*}', + [ + ['/', ['_foo', '.*']] + ] + ], + ]; + } + + public function provideTestParseError() + { + return [ + [ + '/test[opt', + "Number of opening '[' and closing ']' does not match" + ], + [ + '/test[opt[opt2]', + "Number of opening '[' and closing ']' does not match" + ], + [ + '/testopt]', + "Number of opening '[' and closing ']' does not match" + ], + [ + '/test[]', + 'Empty optional part' + ], + [ + '/test[[opt]]', + 'Empty optional part' + ], + [ + '[[test]]', + 'Empty optional part' + ], + [ + '/test[/opt]/required', + 'Optional segments can only occur at the end of a route' + ], + ]; + } +} diff --git a/api/vendor/nikic/fast-route/test/bootstrap.php b/api/vendor/nikic/fast-route/test/bootstrap.php new file mode 100644 index 0000000..3023f41 --- /dev/null +++ b/api/vendor/nikic/fast-route/test/bootstrap.php @@ -0,0 +1,11 @@ +get('/project/{project}/issue/{issue}', function ($project, $issue) { + // ... +}); +``` + +Or this command defined with [Silly](https://github.com/mnapoli/silly#usage): + +```php +$app->command('greet [name] [--yell]', function ($name, $yell) { + // ... +}); +``` + +Same pattern in [Slim](https://www.slimframework.com): + +```php +$app->get('/hello/:name', function ($name) { + // ... +}); +``` + +You get the point. These frameworks invoke the controller/command/handler using something akin to named parameters: whatever the order of the parameters, they are matched by their name. + +**This library allows to invoke callables with named parameters in a generic and extensible way.** + +### Dependency injection + +Anyone familiar with AngularJS is familiar with how dependency injection is performed: + +```js +angular.controller('MyController', ['dep1', 'dep2', function(dep1, dep2) { + // ... +}]); +``` + +In PHP we find this pattern again in some frameworks and DI containers with partial to full support. For example in Silex you can type-hint the application to get it injected, but it only works with `Silex\Application`: + +```php +$app->get('/hello/{name}', function (Silex\Application $app, $name) { + // ... +}); +``` + +In Silly, it only works with `OutputInterface` to inject the application output: + +```php +$app->command('greet [name]', function ($name, OutputInterface $output) { + // ... +}); +``` + +[PHP-DI](https://php-di.org/doc/container.html) provides a way to invoke a callable and resolve all dependencies from the container using type-hints: + +```php +$container->call(function (Logger $logger, EntityManager $em) { + // ... +}); +``` + +**This library provides clear extension points to let frameworks implement any kind of dependency injection support they want.** + +### TL/DR + +In short, this library is meant to be a base building block for calling a function with named parameters and/or dependency injection. + +## Installation + +```sh +$ composer require PHP-DI/invoker +``` + +## Usage + +### Default behavior + +By default the `Invoker` can call using named parameters: + +```php +$invoker = new Invoker\Invoker; + +$invoker->call(function () { + echo 'Hello world!'; +}); + +// Simple parameter array +$invoker->call(function ($name) { + echo 'Hello ' . $name; +}, ['John']); + +// Named parameters +$invoker->call(function ($name) { + echo 'Hello ' . $name; +}, [ + 'name' => 'John' +]); + +// Use the default value +$invoker->call(function ($name = 'world') { + echo 'Hello ' . $name; +}); + +// Invoke any PHP callable +$invoker->call(['MyClass', 'myStaticMethod']); + +// Using Class::method syntax +$invoker->call('MyClass::myStaticMethod'); +``` + +Dependency injection in parameters is supported but needs to be configured with your container. Read on or jump to [*Built-in support for dependency injection*](#built-in-support-for-dependency-injection) if you are impatient. + +Additionally, callables can also be resolved from your container. Read on or jump to [*Resolving callables from a container*](#resolving-callables-from-a-container) if you are impatient. + +### Parameter resolvers + +Extending the behavior of the `Invoker` is easy and is done by implementing a [`ParameterResolver`](https://github.com/PHP-DI/Invoker/blob/master/src/ParameterResolver/ParameterResolver.php). + +This is explained in details the [Parameter resolvers documentation](doc/parameter-resolvers.md). + +#### Built-in support for dependency injection + +Rather than have you re-implement support for dependency injection with different containers every time, this package ships with 2 optional resolvers: + +- [`TypeHintContainerResolver`](https://github.com/PHP-DI/Invoker/blob/master/src/ParameterResolver/Container/TypeHintContainerResolver.php) + + This resolver will inject container entries by searching for the class name using the type-hint: + + ```php + $invoker->call(function (Psr\Logger\LoggerInterface $logger) { + // ... + }); + ``` + + In this example it will `->get('Psr\Logger\LoggerInterface')` from the container and inject it. + + This resolver is only useful if you store objects in your container using the class (or interface) name. Silex or Symfony for example store services under a custom name (e.g. `twig`, `db`, etc.) instead of the class name: in that case use the resolver shown below. + +- [`ParameterNameContainerResolver`](https://github.com/PHP-DI/Invoker/blob/master/src/ParameterResolver/Container/ParameterNameContainerResolver.php) + + This resolver will inject container entries by searching for the name of the parameter: + + ```php + $invoker->call(function ($twig) { + // ... + }); + ``` + + In this example it will `->get('twig')` from the container and inject it. + +These resolvers can work with any dependency injection container compliant with [PSR-11](http://www.php-fig.org/psr/psr-11/). + +Setting up those resolvers is simple: + +```php +// $container must be an instance of Psr\Container\ContainerInterface +$container = ... + +$containerResolver = new TypeHintContainerResolver($container); +// or +$containerResolver = new ParameterNameContainerResolver($container); + +$invoker = new Invoker\Invoker; +// Register it before all the other parameter resolvers +$invoker->getParameterResolver()->prependResolver($containerResolver); +``` + +You can also register both resolvers at the same time if you wish by prepending both. Implementing support for more tricky things is easy and up to you! + +### Resolving callables from a container + +The `Invoker` can be wired to your DI container to resolve the callables. + +For example with an invokable class: + +```php +class MyHandler +{ + public function __invoke() + { + // ... + } +} + +// By default this doesn't work: an instance of the class should be provided +$invoker->call('MyHandler'); + +// If we set up the container to use +$invoker = new Invoker\Invoker(null, $container); +// Now 'MyHandler' is resolved using the container! +$invoker->call('MyHandler'); +``` + +The same works for a class method: + +```php +class WelcomeController +{ + public function home() + { + // ... + } +} + +// By default this doesn't work: home() is not a static method +$invoker->call(['WelcomeController', 'home']); + +// If we set up the container to use +$invoker = new Invoker\Invoker(null, $container); +// Now 'WelcomeController' is resolved using the container! +$invoker->call(['WelcomeController', 'home']); +// Alternatively we can use the Class::method syntax +$invoker->call('WelcomeController::home'); +``` + +That feature can be used as the base building block for a framework's dispatcher. + +Again, any [PSR-11](https://www.php-fig.org/psr/psr-11/) compliant container can be provided. + diff --git a/api/vendor/php-di/invoker/composer.json b/api/vendor/php-di/invoker/composer.json new file mode 100644 index 0000000..3d15969 --- /dev/null +++ b/api/vendor/php-di/invoker/composer.json @@ -0,0 +1,32 @@ +{ + "name": "php-di/invoker", + "description": "Generic and extensible callable invoker", + "keywords": ["invoker", "dependency-injection", "dependency", "injection", "callable", "invoke"], + "homepage": "https://github.com/PHP-DI/Invoker", + "license": "MIT", + "type": "library", + "autoload": { + "psr-4": { + "Invoker\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Invoker\\Test\\": "tests/" + } + }, + "require": { + "php": ">=7.3", + "psr/container": "^1.0|^2.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.0 || ^10 || ^11 || ^12", + "athletic/athletic": "~0.1.8", + "mnapoli/hard-mode": "~0.3.0" + }, + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + } + } +} diff --git a/api/vendor/php-di/invoker/src/CallableResolver.php b/api/vendor/php-di/invoker/src/CallableResolver.php new file mode 100644 index 0000000..e3b11b2 --- /dev/null +++ b/api/vendor/php-di/invoker/src/CallableResolver.php @@ -0,0 +1,124 @@ +container = $container; + } + + /** + * Resolve the given callable into a real PHP callable. + * + * @param callable|string|array $callable + * @return callable Real PHP callable. + * @throws NotCallableException|ReflectionException + */ + public function resolve($callable): callable + { + if (is_string($callable) && strpos($callable, '::') !== false) { + $callable = explode('::', $callable, 2); + } + + $callable = $this->resolveFromContainer($callable); + + if (! is_callable($callable)) { + throw NotCallableException::fromInvalidCallable($callable, true); + } + + return $callable; + } + + /** + * @param callable|string|array $callable + * @return callable|mixed + * @throws NotCallableException|ReflectionException + */ + private function resolveFromContainer($callable) + { + // Shortcut for a very common use case + if ($callable instanceof Closure) { + return $callable; + } + + // If it's already a callable there is nothing to do + if (is_callable($callable)) { + // TODO with PHP 8 that should not be necessary to check this anymore + if (! $this->isStaticCallToNonStaticMethod($callable)) { + return $callable; + } + } + + // The callable is a container entry name + if (is_string($callable)) { + try { + return $this->container->get($callable); + } catch (NotFoundExceptionInterface $e) { + if ($this->container->has($callable)) { + throw $e; + } + throw NotCallableException::fromInvalidCallable($callable, true); + } + } + + // The callable is an array whose first item is a container entry name + // e.g. ['some-container-entry', 'methodToCall'] + if (is_array($callable) && is_string($callable[0])) { + try { + // Replace the container entry name by the actual object + $callable[0] = $this->container->get($callable[0]); + return $callable; + } catch (NotFoundExceptionInterface $e) { + if ($this->container->has($callable[0])) { + throw $e; + } + throw new NotCallableException(sprintf( + 'Cannot call %s() on %s because it is not a class nor a valid container entry', + $callable[1], + $callable[0] + )); + } + } + + // Unrecognized stuff, we let it fail later + return $callable; + } + + /** + * Check if the callable represents a static call to a non-static method. + * + * @param mixed $callable + * @throws ReflectionException + */ + private function isStaticCallToNonStaticMethod($callable): bool + { + if (is_array($callable) && is_string($callable[0])) { + [$class, $method] = $callable; + + if (! method_exists($class, $method)) { + return false; + } + + $reflection = new ReflectionMethod($class, $method); + + return ! $reflection->isStatic(); + } + + return false; + } +} diff --git a/api/vendor/php-di/invoker/src/Exception/InvocationException.php b/api/vendor/php-di/invoker/src/Exception/InvocationException.php new file mode 100644 index 0000000..90f6585 --- /dev/null +++ b/api/vendor/php-di/invoker/src/Exception/InvocationException.php @@ -0,0 +1,10 @@ +parameterResolver = $parameterResolver ?: $this->createParameterResolver(); + $this->container = $container; + + if ($container) { + $this->callableResolver = new CallableResolver($container); + } + } + + /** + * {@inheritdoc} + */ + public function call($callable, array $parameters = []) + { + if ($this->callableResolver) { + $callable = $this->callableResolver->resolve($callable); + } + + if (! is_callable($callable)) { + throw new NotCallableException(sprintf( + '%s is not a callable', + is_object($callable) ? 'Instance of ' . get_class($callable) : var_export($callable, true) + )); + } + + $callableReflection = CallableReflection::create($callable); + + $args = $this->parameterResolver->getParameters($callableReflection, $parameters, []); + + // Sort by array key because call_user_func_array ignores numeric keys + ksort($args); + + // Check all parameters are resolved + $diff = array_diff_key($callableReflection->getParameters(), $args); + $parameter = reset($diff); + if ($parameter && \assert($parameter instanceof ReflectionParameter) && ! $parameter->isVariadic()) { + throw new NotEnoughParametersException(sprintf( + 'Unable to invoke the callable because no value was given for parameter %d ($%s)', + $parameter->getPosition() + 1, + $parameter->name + )); + } + + return call_user_func_array($callable, $args); + } + + /** + * Create the default parameter resolver. + */ + private function createParameterResolver(): ParameterResolver + { + return new ResolverChain([ + new NumericArrayResolver, + new AssociativeArrayResolver, + new DefaultValueResolver, + ]); + } + + /** + * @return ParameterResolver By default it's a ResolverChain + */ + public function getParameterResolver(): ParameterResolver + { + return $this->parameterResolver; + } + + public function getContainer(): ?ContainerInterface + { + return $this->container; + } + + /** + * @return CallableResolver|null Returns null if no container was given in the constructor. + */ + public function getCallableResolver(): ?CallableResolver + { + return $this->callableResolver; + } +} diff --git a/api/vendor/php-di/invoker/src/InvokerInterface.php b/api/vendor/php-di/invoker/src/InvokerInterface.php new file mode 100644 index 0000000..06f0064 --- /dev/null +++ b/api/vendor/php-di/invoker/src/InvokerInterface.php @@ -0,0 +1,25 @@ +call($callable, ['foo' => 'bar'])` will inject the string `'bar'` + * in the parameter named `$foo`. + * + * Parameters that are not indexed by a string are ignored. + */ +class AssociativeArrayResolver implements ParameterResolver +{ + public function getParameters( + ReflectionFunctionAbstract $reflection, + array $providedParameters, + array $resolvedParameters + ): array { + $parameters = $reflection->getParameters(); + + // Skip parameters already resolved + if (! empty($resolvedParameters)) { + $parameters = array_diff_key($parameters, $resolvedParameters); + } + + foreach ($parameters as $index => $parameter) { + if (array_key_exists($parameter->name, $providedParameters)) { + $resolvedParameters[$index] = $providedParameters[$parameter->name]; + } + } + + return $resolvedParameters; + } +} diff --git a/api/vendor/php-di/invoker/src/ParameterResolver/Container/ParameterNameContainerResolver.php b/api/vendor/php-di/invoker/src/ParameterResolver/Container/ParameterNameContainerResolver.php new file mode 100644 index 0000000..126e14c --- /dev/null +++ b/api/vendor/php-di/invoker/src/ParameterResolver/Container/ParameterNameContainerResolver.php @@ -0,0 +1,47 @@ +container = $container; + } + + public function getParameters( + ReflectionFunctionAbstract $reflection, + array $providedParameters, + array $resolvedParameters + ): array { + $parameters = $reflection->getParameters(); + + // Skip parameters already resolved + if (! empty($resolvedParameters)) { + $parameters = array_diff_key($parameters, $resolvedParameters); + } + + foreach ($parameters as $index => $parameter) { + $name = $parameter->name; + + if ($name && $this->container->has($name)) { + $resolvedParameters[$index] = $this->container->get($name); + } + } + + return $resolvedParameters; + } +} diff --git a/api/vendor/php-di/invoker/src/ParameterResolver/Container/TypeHintContainerResolver.php b/api/vendor/php-di/invoker/src/ParameterResolver/Container/TypeHintContainerResolver.php new file mode 100644 index 0000000..014956e --- /dev/null +++ b/api/vendor/php-di/invoker/src/ParameterResolver/Container/TypeHintContainerResolver.php @@ -0,0 +1,65 @@ +container = $container; + } + + public function getParameters( + ReflectionFunctionAbstract $reflection, + array $providedParameters, + array $resolvedParameters + ): array { + $parameters = $reflection->getParameters(); + + // Skip parameters already resolved + if (! empty($resolvedParameters)) { + $parameters = array_diff_key($parameters, $resolvedParameters); + } + + foreach ($parameters as $index => $parameter) { + $parameterType = $parameter->getType(); + if (! $parameterType) { + // No type + continue; + } + if (! $parameterType instanceof ReflectionNamedType) { + // Union types are not supported + continue; + } + if ($parameterType->isBuiltin()) { + // Primitive types are not supported + continue; + } + + $parameterClass = $parameterType->getName(); + if ($parameterClass === 'self') { + $parameterClass = $parameter->getDeclaringClass()->getName(); + } + + if ($this->container->has($parameterClass)) { + $resolvedParameters[$index] = $this->container->get($parameterClass); + } + } + + return $resolvedParameters; + } +} diff --git a/api/vendor/php-di/invoker/src/ParameterResolver/DefaultValueResolver.php b/api/vendor/php-di/invoker/src/ParameterResolver/DefaultValueResolver.php new file mode 100644 index 0000000..3fdf7b7 --- /dev/null +++ b/api/vendor/php-di/invoker/src/ParameterResolver/DefaultValueResolver.php @@ -0,0 +1,43 @@ +getParameters(); + + // Skip parameters already resolved + if (! empty($resolvedParameters)) { + $parameters = array_diff_key($parameters, $resolvedParameters); + } + + foreach ($parameters as $index => $parameter) { + \assert($parameter instanceof \ReflectionParameter); + if ($parameter->isDefaultValueAvailable()) { + try { + $resolvedParameters[$index] = $parameter->getDefaultValue(); + } catch (ReflectionException $e) { + // Can't get default values from PHP internal classes and functions + } + } else { + $parameterType = $parameter->getType(); + if ($parameterType && $parameterType->allowsNull()) { + $resolvedParameters[$index] = null; + } + } + } + + return $resolvedParameters; + } +} diff --git a/api/vendor/php-di/invoker/src/ParameterResolver/NumericArrayResolver.php b/api/vendor/php-di/invoker/src/ParameterResolver/NumericArrayResolver.php new file mode 100644 index 0000000..07d8ece --- /dev/null +++ b/api/vendor/php-di/invoker/src/ParameterResolver/NumericArrayResolver.php @@ -0,0 +1,37 @@ +call($callable, ['foo', 'bar'])` will simply resolve the parameters + * to `['foo', 'bar']`. + * + * Parameters that are not indexed by a number (i.e. parameter position) + * will be ignored. + */ +class NumericArrayResolver implements ParameterResolver +{ + public function getParameters( + ReflectionFunctionAbstract $reflection, + array $providedParameters, + array $resolvedParameters + ): array { + // Skip parameters already resolved + if (! empty($resolvedParameters)) { + $providedParameters = array_diff_key($providedParameters, $resolvedParameters); + } + + foreach ($providedParameters as $key => $value) { + if (is_int($key)) { + $resolvedParameters[$key] = $value; + } + } + + return $resolvedParameters; + } +} diff --git a/api/vendor/php-di/invoker/src/ParameterResolver/ParameterResolver.php b/api/vendor/php-di/invoker/src/ParameterResolver/ParameterResolver.php new file mode 100644 index 0000000..85046c3 --- /dev/null +++ b/api/vendor/php-di/invoker/src/ParameterResolver/ParameterResolver.php @@ -0,0 +1,30 @@ +resolvers = $resolvers; + } + + public function getParameters( + ReflectionFunctionAbstract $reflection, + array $providedParameters, + array $resolvedParameters + ): array { + $reflectionParameters = $reflection->getParameters(); + + foreach ($this->resolvers as $resolver) { + $resolvedParameters = $resolver->getParameters( + $reflection, + $providedParameters, + $resolvedParameters + ); + + $diff = array_diff_key($reflectionParameters, $resolvedParameters); + if (empty($diff)) { + // Stop traversing: all parameters are resolved + return $resolvedParameters; + } + } + + return $resolvedParameters; + } + + /** + * Push a parameter resolver after the ones already registered. + */ + public function appendResolver(ParameterResolver $resolver): void + { + $this->resolvers[] = $resolver; + } + + /** + * Insert a parameter resolver before the ones already registered. + */ + public function prependResolver(ParameterResolver $resolver): void + { + array_unshift($this->resolvers, $resolver); + } +} diff --git a/api/vendor/php-di/invoker/src/ParameterResolver/TypeHintResolver.php b/api/vendor/php-di/invoker/src/ParameterResolver/TypeHintResolver.php new file mode 100644 index 0000000..3ccc2e0 --- /dev/null +++ b/api/vendor/php-di/invoker/src/ParameterResolver/TypeHintResolver.php @@ -0,0 +1,54 @@ +getParameters(); + + // Skip parameters already resolved + if (! empty($resolvedParameters)) { + $parameters = array_diff_key($parameters, $resolvedParameters); + } + + foreach ($parameters as $index => $parameter) { + $parameterType = $parameter->getType(); + if (! $parameterType) { + // No type + continue; + } + if (! $parameterType instanceof ReflectionNamedType) { + // Union types are not supported + continue; + } + if ($parameterType->isBuiltin()) { + // Primitive types are not supported + continue; + } + + $parameterClass = $parameterType->getName(); + if ($parameterClass === 'self') { + $parameterClass = $parameter->getDeclaringClass()->getName(); + } + + if (array_key_exists($parameterClass, $providedParameters)) { + $resolvedParameters[$index] = $providedParameters[$parameterClass]; + } + } + + return $resolvedParameters; + } +} diff --git a/api/vendor/php-di/invoker/src/Reflection/CallableReflection.php b/api/vendor/php-di/invoker/src/Reflection/CallableReflection.php new file mode 100644 index 0000000..3f19f33 --- /dev/null +++ b/api/vendor/php-di/invoker/src/Reflection/CallableReflection.php @@ -0,0 +1,56 @@ + DI\factory(function ($host) {...}) + ->parameter('host', DI\get('db.host')), + ]; + ``` + Read the [factories documentation](https://php-di.org/doc/php-definitions.html#factories) to learn more. Feature implemented by [@predakanga](https://github.com/predakanga). + +Improvements: + +- [#429](https://github.com/PHP-DI/PHP-DI/pull/429): performance improvements in definition resolution (by [@mnapoli](https://github.com/mnapoli)) +- [#421](https://github.com/PHP-DI/PHP-DI/issues/421): once a `ContainerBuilder` has built a container, it is locked to prevent confusion when adding new definitions to it (by [@mnapoli](https://github.com/mnapoli)) +- [#423](https://github.com/PHP-DI/PHP-DI/pull/423): improved exception messages (by [@mnapoli](https://github.com/mnapoli)) + +## 5.3 + +Read the [news entry](news/19-php-di-5-3-released.md). + +- release of the [2.0 version](https://github.com/PHP-DI/Symfony-Bridge/releases/tag/2.0.0) of the Symfony bridge (by [@mnapoli](https://github.com/mnapoli)) +- PHP 5.5 or above is now required +- a lot of documentation improvements by 9 different contributors +- [#389](https://github.com/PHP-DI/PHP-DI/pull/389): exception message improvement by [@mopahle](https://github.com/mopahle) +- [#359](https://github.com/PHP-DI/PHP-DI/issues/359), [#411](https://github.com/PHP-DI/PHP-DI/issues/411), [#414](https://github.com/PHP-DI/PHP-DI/pull/414), [#412](https://github.com/PHP-DI/PHP-DI/pull/412): compatibility with ProxyManager 1.* and 2.* (by [@holtkamp](https://github.com/holtkamp) and [@mnapoli](https://github.com/mnapoli)) +- [#416](https://github.com/PHP-DI/PHP-DI/pull/416): dumping definitions was refactored into a more lightweight and simple solution; definition "dumpers" have been removed (internal classes), definitions can now be cast to string directly (by [@mnapoli](https://github.com/mnapoli)) + +## 5.2 + +Read the [news entry](news/17-php-di-5-2-released.md). + +Improvements: + +- [#347](https://github.com/PHP-DI/PHP-DI/pull/347) (includes [#333](https://github.com/PHP-DI/PHP-DI/pull/333) and [#345](https://github.com/PHP-DI/PHP-DI/pull/345)): by [@jdreesen](https://github.com/jdreesen), [@quimcalpe](https://github.com/quimcalpe) and [@mnapoli](https://github.com/mnapoli) + - Allow injection of any container object as factory parameter via type hinting + - Allow injection of a `DI\Factory\RequestedEntry` object to get the requested entry name +- [#272](https://github.com/PHP-DI/PHP-DI/issues/272): Support `"Class::method""` syntax for callables (by [@jdreesen](https://github.com/jdreesen)) +- [#332](https://github.com/PHP-DI/PHP-DI/issues/332): IDE support (plugin and documentation) (by [@pulyaevskiy](https://github.com/pulyaevskiy), [@avant1](https://github.com/avant1) and [@mnapoli](https://github.com/mnapoli)) +- [#326](https://github.com/PHP-DI/PHP-DI/pull/326): Exception messages are simpler and more consistent (by [@mnapoli](https://github.com/mnapoli)) +- [#325](https://github.com/PHP-DI/PHP-DI/pull/325): Add a "Edit this page" button in the website to encourage users to improve the documentation (by [@jdreesen](https://github.com/jdreesen)) + +Bugfixes: + +- [#321](https://github.com/PHP-DI/PHP-DI/pull/321): Allow factory definitions to reference arbitrary container entries as callables (by [@jdreesen](https://github.com/jdreesen)) +- [#335](https://github.com/PHP-DI/PHP-DI/issues/335): Class imports in traits are now considered when parsing annotations (by [@thebigb](https://github.com/thebigb)) + +## 5.1 + +Read the [news entry](news/16-php-di-5-1-released.md). + +Improvements: + +- [Zend Framework 2 integration](https://github.com/PHP-DI/ZF2-Bridge) (by @Rastusik) +- [#308](https://github.com/PHP-DI/PHP-DI/pull/308): Instantiate factories using the container (`DI\factory(['FooFactory', 'create'])`) +- Many performances improvements - some benchmarks show up to 35% performance improvements, real results may vary of course +- Many documentation improvements (@jdreesen, @mindplay-dk, @mnapoli, @holtkamp, @Rastusik) +- [#296](https://github.com/PHP-DI/PHP-DI/issues/296): Provide a faster `ArrayCache` implementation, mostly useful in micro-benchmarks + +Bugfixes: + +- [#257](https://github.com/PHP-DI/PHP-DI/issues/257) & [#274](https://github.com/PHP-DI/PHP-DI/issues/274): Private properties of parent classes are not injected when using annotations +- [#300](https://github.com/PHP-DI/PHP-DI/pull/300): Exception if object definition extends an incompatible definition +- [#306](https://github.com/PHP-DI/PHP-DI/issues/306): Errors when using parameters passed by reference (fixed by @bradynpoulsen) +- [#318](https://github.com/PHP-DI/PHP-DI/issues/318): `Container::call()` ignores parameter's default value + +Internal changes: + +- [#276](https://github.com/PHP-DI/PHP-DI/pull/276): Tests now pass on Windows (@bgaillard) + +## 5.0 + +This is the complete change log. You can also read the [migration guide](doc/migration/5.0.md) for upgrading, or [the news article](news/15-php-di-5-0-released.md) for a nicer introduction to this new version. + +Improvements: + +- Moved to an organization on GitHub: [github.com/PHP-DI/PHP-DI](https://github.com/PHP-DI/PHP-DI) +- The package has been renamed to: from `mnapoli/php-di` to [`php-di/php-di`](https://packagist.org/packages/php-di/php-di) +- New [Silex integration](doc/frameworks/silex.md) +- Lighter package: from 10 to 3 Composer dependencies! +- [#235](https://github.com/PHP-DI/PHP-DI/issues/235): `DI\link()` is now deprecated in favor of `DI\get()`. There is no BC break as `DI\link()` still works. +- [#207](https://github.com/PHP-DI/PHP-DI/issues/207): Support for `DI\link()` in arrays +- [#203](https://github.com/PHP-DI/PHP-DI/issues/203): New `DI\string()` helper ([documentation](doc/php-definitions.md)) +- [#208](https://github.com/PHP-DI/PHP-DI/issues/208): Support for nested definitions +- [#226](https://github.com/PHP-DI/PHP-DI/pull/226): `DI\factory()` can now be omitted with closures: + + ```php + // before + 'My\Class' => DI\factory(function () { ... }) + // now (optional shortcut) + 'My\Class' => function () { ... } + ``` +- [#193](https://github.com/PHP-DI/PHP-DI/issues/193): `DI\object()->method()` now supports calling the same method twice (or more). +- [#248](https://github.com/PHP-DI/PHP-DI/issues/248): New `DI\decorate()` helper to decorate a previously defined entry ([documentation](doc/definition-overriding.md)) +- [#215](https://github.com/PHP-DI/PHP-DI/pull/215): New `DI\add()` helper to add entries to an existing array ([documentation](doc/definition-overriding.md)) +- [#218](https://github.com/PHP-DI/PHP-DI/issues/218): `ContainerBuilder::addDefinitions()` can now take an array of definitions +- [#211](https://github.com/PHP-DI/PHP-DI/pull/211): `ContainerBuilder::addDefinitions()` is now fluent (return `$this`) +- [#250](https://github.com/PHP-DI/PHP-DI/issues/250): `Container::call()` now also accepts parameters not indexed by name as well as embedded definitions ([documentation](doc/container.md)) +- Various performance improvements, e.g. lower the number of files loaded, simpler architecture, … + +BC breaks: + +- PHP-DI now requires a version of PHP >= 5.4.0 +- The package is lighter by default: + - [#251](https://github.com/PHP-DI/PHP-DI/issues/251): Annotations are disabled by default, if you use annotations enable them with `$containerBuilder->useAnnotations(true)`. Additionally the `doctrine/annotations` package isn't required by default anymore, so you also need to run `composer require doctrine/annotations`. + - `doctrine/cache` is not installed by default anymore, you need to require it in `composer.json` (`~1.0`) if you want to configure a cache for PHP-DI + - [#198](https://github.com/PHP-DI/PHP-DI/issues/198): `ocramius/proxy-manager` is not installed by default anymore, you need to require it in `composer.json` (`~1.0`) if you want to use **lazy injection** +- Closures are now converted into factory definitions automatically. If you ever defined a closure as a value (e.g. to have the closure injected in a class), you need to wrap the closure with the new `DI\value()` helper. +- [#223](https://github.com/PHP-DI/PHP-DI/issues/223): `DI\ContainerInterface` was deprecated since v4.1 and has been removed + +Internal changes in case you were replacing/extending some parts: + +- the definition sources architecture has been refactored, if you defined custom definition sources you will need to update your code (it should be much easier now) +- [#252](https://github.com/PHP-DI/PHP-DI/pull/252): `DI\Scope` internal implementation has changed. You are encouraged to use the constants (`DI\Scope::SINGLETON` and `DI\Scope::PROTOTYPE`) instead of the static methods, but backward compatibility is kept (static methods still work). +- [#241](https://github.com/PHP-DI/PHP-DI/issues/241): `Container::call()` now uses the *Invoker* external library + +## 4.4 + +Read the [news entry](news/13-php-di-4-4-released.md). + +- [#185](https://github.com/PHP-DI/PHP-DI/issues/185) Support for invokable objects in `Container::call()` +- [#192](https://github.com/PHP-DI/PHP-DI/pull/192) Support for invokable classes in `Container::call()` (will instantiate the class) +- [#184](https://github.com/PHP-DI/PHP-DI/pull/184) Option to ignore phpdoc errors + +## 4.3 + +Read the [news entry](news/11-php-di-4-3-released.md). + +- [#176](https://github.com/PHP-DI/PHP-DI/pull/176) New definition type for reading environment variables: `DI\env()` +- [#181](https://github.com/PHP-DI/PHP-DI/pull/181) `DI\FactoryInterface` and `DI\InvokerInterface` are now auto-registered inside the container so that you can inject them without any configuration needed +- [#173](https://github.com/PHP-DI/PHP-DI/pull/173) `$container->call(['MyClass', 'method]);` will get `MyClass` from the container if `method()` is not a static method + +## 4.2.2 + +- Fixed [#180](https://github.com/PHP-DI/PHP-DI/pull/180): `Container::call()` with object methods (`[$object, 'method']`) is now supported + +## 4.2.1 + +- Support for PHP 5.3.3, which was previously incomplete because of a bug in the reflection (there is now a workaround for this bug) + +But if you can, seriously avoid this (really old) PHP version and upgrade. + +## 4.2 + +Read the [news entry](news/10-php-di-4-2-released.md). + +**Minor BC-break**: Optional parameters (that were not configured) were injected, they are now ignored, which is what naturally makes sense since they are optional. +Example: + +```php + public function __construct(Bar $bar = null) + { + $this->bar = $bar ?: $this->createDefaultBar(); + } +``` + +Before 4.2, PHP-DI would try to inject a `Bar` instance. From 4.2 and onwards, it will inject `null`. + +Of course, you can still explicitly define an injection for the optional parameters and that will work. + +All changes: + +* [#162](https://github.com/PHP-DI/PHP-DI/pull/162) Added `Container::call()` to call functions with dependency injection +* [#156](https://github.com/PHP-DI/PHP-DI/issues/156) Wildcards (`*`) in definitions +* [#164](https://github.com/PHP-DI/PHP-DI/issues/164) Prototype scope is now available for `factory()` definitions too +* FIXED [#168](https://github.com/PHP-DI/PHP-DI/pull/168) `Container::has()` now returns false for interfaces and abstract classes that are not mapped in the definitions +* FIXED [#171](https://github.com/PHP-DI/PHP-DI/issues/171) Optional parameters are now ignored (not injected) if not set in the definitions (see the BC-break warning above) + +## 4.1 + +Read the [news entry](news/09-php-di-4-1-released.md). + +BC-breaks: None. + +* [#138](https://github.com/PHP-DI/PHP-DI/issues/138) [Container-interop](https://github.com/container-interop/container-interop) compliance +* [#143](https://github.com/PHP-DI/PHP-DI/issues/143) Much more explicit exception messages +* [#157](https://github.com/PHP-DI/PHP-DI/issues/157) HHVM support +* [#158](https://github.com/PHP-DI/PHP-DI/issues/158) Improved the documentation for [Symfony 2 integration](https://php-di.org/doc/frameworks/symfony2.html) + +## 4.0 + +Major changes: + +* The configuration format has changed ([read more here to understand why](news/06-php-di-4-0-new-definitions.md)) + +Read the migration guide if you are using 3.x: [Migration guide from 3.x to 4.0](doc/migration/4.0.md). + +BC-breaks: + +* YAML, XML and JSON definitions have been removed, and the PHP definition format has changed (see above) +* `ContainerSingleton` has been removed +* You cannot configure an injection as lazy anymore, you can only configure a container entry as lazy +* The Container constructor now takes mandatory parameters. Use the ContainerBuilder to create a Container. +* Removed `ContainerBuilder::setDefinitionsValidation()` (no definition validation anymore) +* `ContainerBuilder::useReflection()` is now named: `ContainerBuilder::useAutowiring()` +* `ContainerBuilder::addDefinitionsFromFile()` is now named: `ContainerBuilder::addDefinitions()` +* The `$proxy` parameter in `Container::get($name, $proxy = true)` hase been removed. To get a proxy, you now need to define an entry as "lazy". + +Other changes: + +* Added `ContainerInterface` and `FactoryInterface`, both implemented by the container. +* [#115](https://github.com/PHP-DI/PHP-DI/issues/115) Added `Container::has()` +* [#142](https://github.com/PHP-DI/PHP-DI/issues/142) Added `Container::make()` to resolve an entry +* [#127](https://github.com/PHP-DI/PHP-DI/issues/127) Added support for cases where PHP-DI is wrapped by another container (like Acclimate): PHP-DI can now use the wrapping container to perform injections +* [#128](https://github.com/PHP-DI/PHP-DI/issues/128) Configure entry aliases +* [#110](https://github.com/PHP-DI/PHP-DI/issues/110) XML definitions are not supported anymore +* [#122](https://github.com/PHP-DI/PHP-DI/issues/122) JSON definitions are not supported anymore +* `ContainerSingleton` has finally been removed +* Added `ContainerBuilder::buildDevContainer()` to get started with a default container very easily. +* [#99](https://github.com/PHP-DI/PHP-DI/issues/99) Fixed "`@param` with PHP internal type throws exception" + +## 3.5.1 + +* FIXED [#126](https://github.com/PHP-DI/PHP-DI/issues/126): `Container::set` without effect if a value has already been set and retrieved + +## 3.5 + +Read the [news entry](news/05-php-di-3-5.md). + +* Importing `@Inject` and `@Injectable` annotations is now optional! It means that you don't have to write `use DI\Annotation\Inject` anymore +* FIXED [#124](https://github.com/PHP-DI/PHP-DI/issues/124): `@Injects` annotation conflicts with other annotations + +## 3.4 + +Read the [news entry](news/04-php-di-3-4.md). + +* [#106](https://github.com/PHP-DI/PHP-DI/pull/106) You can now define arrays of values (in YAML, PHP, …) thanks to [@unkind](https://github.com/unkind) +* [#98](https://github.com/PHP-DI/PHP-DI/issues/98) `ContainerBuilder` is now fluent thanks to [@drdamour](https://github.com/drdamour) +* [#101](https://github.com/PHP-DI/PHP-DI/pull/101) Optional parameters are now supported: if you don't define a value to inject, their default value will be used +* XML definitions have been deprecated, there weren't even documented and were not maintained. They will be removed in 4.0. +* FIXED [#100](https://github.com/PHP-DI/PHP-DI/issues/100): bug for lazy injection in constructors + +## 3.3 + +Read the [news entry](news/03-php-di-3-3.md). + +* Inject dependencies on an existing instance with `Container::injectOn` (work from [Jeff Flitton](https://github.com/jflitton): [#89](https://github.com/PHP-DI/PHP-DI/pull/89)). +* [#86](https://github.com/PHP-DI/PHP-DI/issues/86): Optimized definition lookup (faster) +* FIXED [#87](https://github.com/PHP-DI/PHP-DI/issues/87): Rare bug in the `PhpDocParser`, fixed by [drdamour](https://github.com/drdamour) + +## 3.2 + +Read the [news entry](news/02-php-di-3-2.md). + +Small BC-break: PHP-DI 3.0 and 3.1 injected properties before calling the constructor. This was confusing and [not supported for internal classes](https://github.com/PHP-DI/PHP-DI/issues/74). +From 3.2 and on, properties are injected after calling the constructor. + +* **[Lazy injection](doc/lazy-injection.md)**: it is now possible to use lazy injection on properties and methods (setters and constructors). +* Lazy dependencies are now proxies that extend the class they proxy, so type-hinting works. +* Addition of the **`ContainerBuilder`** object, that helps to [create and configure a `Container`](doc/container-configuration.md). +* Some methods for configuring the Container have gone **deprecated** in favor of the `ContainerBuilder`. Fear not, these deprecated methods will remain until next major version (4.0). + * `Container::useReflection`, use ContainerBuilder::useReflection instead + * `Container::useAnnotations`, use ContainerBuilder::useAnnotations instead + * `Container::setDefinitionCache`, use ContainerBuilder::setDefinitionCache instead + * `Container::setDefinitionsValidation`, use ContainerBuilder::setDefinitionsValidation instead +* The container is now auto-registered (as 'DI\Container'). You can now inject the container without registering it. + +## 3.1.1 + +* Value definitions (`$container->set('foo', 80)`) are not cached anymore +* FIXED [#82](https://github.com/PHP-DI/PHP-DI/issues/82): Serialization error when using a cache + +## 3.1 + +Read the [news entry](news/01-php-di-3-1.md). + +* Zend Framework 1 integration through the [PHP-DI-ZF1 project](https://github.com/PHP-DI/PHP-DI-ZF1) +* Fixed the order of priorities when you mix different definition sources (reflection, annotations, files, …). See [Definition overriding](doc/definition-overriding.md) +* Now possible to define null values with `$container->set('foo', null)` (see [#79](https://github.com/PHP-DI/PHP-DI/issues/79)). +* Deprecated usage of `ContainerSingleton`, will be removed in next major version (4.0) + +## 3.0.6 + +* FIXED [#76](https://github.com/PHP-DI/PHP-DI/issues/76): Definition conflict when setting a closure for a class name + +## 3.0.5 + +* FIXED [#70](https://github.com/PHP-DI/PHP-DI/issues/70): Definition conflict when setting a value for a class name + +## 3.0.4 + +* FIXED [#69](https://github.com/PHP-DI/PHP-DI/issues/69): YamlDefinitionFileLoader crashes if YAML file is empty + +## 3.0.3 + +* Fixed over-restrictive dependencies in composer.json + +## 3.0.2 + +* [#64](https://github.com/PHP-DI/PHP-DI/issues/64): Non PHP-DI exceptions are not captured-rethrown anymore when injecting dependencies (cleaner stack trace) + +## 3.0.1 + +* [#62](https://github.com/PHP-DI/PHP-DI/issues/62): When using aliases, definitions are now merged + +## 3.0 + +Major compatibility breaks with 2.x. + +* The container is no longer a Singleton (but `ContainerSingleton::getInstance()` is available for fools who like it) +* Setter injection +* Constructor injection +* Scopes: singleton (share the same instance of the class) or prototype (create a new instance each time it is fetched). Defined at class level. +* Configuration is reworked from scratch. Now every configuration backend can do 100% of the job. +* Provided configuration backends: + * Reflection + * Annotations: @Inject, @Injectable + * PHP code (`Container::set()`) + * PHP array + * YAML file +* As a consequence, annotations are not mandatory anymore, all functionalities can be used with or without annotations. +* Renamed `DI\Annotations\` to `DI\Annotation\` +* `Container` no longer implements ArrayAccess, use only `$container->get($key)` now +* ZF1 integration broken and removed (work in progress for next releases) +* Code now follows PSR1 and PSR2 coding styles +* FIXED: [#58](https://github.com/PHP-DI/PHP-DI/issues/58) Getting a proxy of an alias didn't work + +## 2.1 + +* `use` statements to import classes from other namespaces are now taken into account with the `@var` annotation +* Updated and lightened the dependencies : `doctrine/common` has been replaced with more specific `doctrine/annotations` and `doctrine/cache` + +## 2.0 + +Major compatibility breaks with 1.x. + +* `Container::resolveDependencies()` has been renamed to `Container::injectAll()` +* Dependencies are now injected **before** the constructor is called, and thus are available in the constructor +* Merged `@Value` annotation with `@Inject`: no difference between value and bean injection anymore +* Container implements ArrayAccess for get() and set() (`$container['db.host'] = 'localhost';`) +* Ini configuration files removed: configuration is done in PHP +* Allow to define beans within closures for lazy-loading +* Switched to MIT License + +Warning: + +* If you use PHP 5.3 and __wakeup() methods, they will be called when PHP-DI creates new instances of those classes. + +## 1.1 + +* Caching of annotations based on Doctrine caches + +## 1.0 + +* DependencyManager renamed to Container +* Refactored basic Container usage with `get` and `set` +* Allow named injection `@Inject(name="")` +* Zend Framework integration diff --git a/api/vendor/php-di/php-di/composer.json b/api/vendor/php-di/php-di/composer.json new file mode 100644 index 0000000..0e6adef --- /dev/null +++ b/api/vendor/php-di/php-di/composer.json @@ -0,0 +1,45 @@ +{ + "name": "php-di/php-di", + "type": "library", + "description": "The dependency injection container for humans", + "keywords": ["di", "dependency injection", "container", "ioc", "psr-11", "psr11", "container-interop"], + "homepage": "https://php-di.org/", + "license": "MIT", + "autoload": { + "psr-4": { + "DI\\": "src/" + }, + "files": [ + "src/functions.php" + ] + }, + "autoload-dev": { + "psr-4": { + "DI\\Test\\IntegrationTest\\": "tests/IntegrationTest/", + "DI\\Test\\UnitTest\\": "tests/UnitTest/" + } + }, + "scripts": { + "test": "phpunit", + "format-code": "php-cs-fixer fix --allow-risky=yes" + }, + "require": { + "php": ">=8.0", + "psr/container": "^1.1 || ^2.0", + "php-di/invoker": "^2.0", + "laravel/serializable-closure": "^1.0 || ^2.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^10 || ^11", + "mnapoli/phpunit-easymock": "^1.3", + "friendsofphp/proxy-manager-lts": "^1", + "friendsofphp/php-cs-fixer": "^3", + "vimeo/psalm": "^5|^6" + }, + "provide": { + "psr/container-implementation": "^1.0" + }, + "suggest": { + "friendsofphp/proxy-manager-lts": "Install it if you want to use lazy injection (version ^1)" + } +} diff --git a/api/vendor/php-di/php-di/src/Attribute/Inject.php b/api/vendor/php-di/php-di/src/Attribute/Inject.php new file mode 100644 index 0000000..6a88f15 --- /dev/null +++ b/api/vendor/php-di/php-di/src/Attribute/Inject.php @@ -0,0 +1,74 @@ + + */ +#[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_METHOD | Attribute::TARGET_PARAMETER)] +class Inject +{ + /** + * Entry name. + */ + private ?string $name = null; + + /** + * Parameters, indexed by the parameter number (index) or name. + * + * Used if the attribute is set on a method + */ + private array $parameters = []; + + /** + * @throws InvalidAttribute + */ + public function __construct(string|array|null $name = null) + { + // #[Inject('foo')] or #[Inject(name: 'foo')] + if (is_string($name)) { + $this->name = $name; + } + + // #[Inject([...])] on a method + if (is_array($name)) { + foreach ($name as $key => $value) { + if (! is_string($value)) { + throw new InvalidAttribute(sprintf( + "#[Inject(['param' => 'value'])] expects \"value\" to be a string, %s given.", + json_encode($value, \JSON_THROW_ON_ERROR) + )); + } + + $this->parameters[$key] = $value; + } + } + } + + /** + * @return string|null Name of the entry to inject + */ + public function getName() : ?string + { + return $this->name; + } + + /** + * @return array Parameters, indexed by the parameter number (index) or name + */ + public function getParameters() : array + { + return $this->parameters; + } +} diff --git a/api/vendor/php-di/php-di/src/Attribute/Injectable.php b/api/vendor/php-di/php-di/src/Attribute/Injectable.php new file mode 100644 index 0000000..af68b4c --- /dev/null +++ b/api/vendor/php-di/php-di/src/Attribute/Injectable.php @@ -0,0 +1,34 @@ + + * @author Matthieu Napoli + */ +#[Attribute(Attribute::TARGET_CLASS)] +class Injectable +{ + /** + * @param bool|null $lazy Should the object be lazy-loaded. + */ + public function __construct( + private ?bool $lazy = null, + ) { + } + + public function isLazy() : ?bool + { + return $this->lazy; + } +} diff --git a/api/vendor/php-di/php-di/src/CompiledContainer.php b/api/vendor/php-di/php-di/src/CompiledContainer.php new file mode 100644 index 0000000..632e5d5 --- /dev/null +++ b/api/vendor/php-di/php-di/src/CompiledContainer.php @@ -0,0 +1,116 @@ + + */ +abstract class CompiledContainer extends Container +{ + /** + * This const is overridden in child classes (compiled containers). + * @var array + */ + protected const METHOD_MAPPING = []; + + private ?InvokerInterface $factoryInvoker = null; + + public function get(string $id) : mixed + { + // Try to find the entry in the singleton map + if (isset($this->resolvedEntries[$id]) || array_key_exists($id, $this->resolvedEntries)) { + return $this->resolvedEntries[$id]; + } + + /** @psalm-suppress UndefinedConstant */ + $method = static::METHOD_MAPPING[$id] ?? null; + + // If it's a compiled entry, then there is a method in this class + if ($method !== null) { + // Check if we are already getting this entry -> circular dependency + if (isset($this->entriesBeingResolved[$id])) { + $idList = implode(' -> ', [...array_keys($this->entriesBeingResolved), $id]); + throw new DependencyException("Circular dependency detected while trying to resolve entry '$id': Dependencies: " . $idList); + } + $this->entriesBeingResolved[$id] = true; + + try { + $value = $this->$method(); + } finally { + unset($this->entriesBeingResolved[$id]); + } + + // Store the entry to always return it without recomputing it + $this->resolvedEntries[$id] = $value; + + return $value; + } + + return parent::get($id); + } + + public function has(string $id) : bool + { + // The parent method is overridden to check in our array, it avoids resolving definitions + /** @psalm-suppress UndefinedConstant */ + if (isset(static::METHOD_MAPPING[$id])) { + return true; + } + + return parent::has($id); + } + + protected function setDefinition(string $name, Definition $definition) : void + { + // It needs to be forbidden because that would mean get() must go through the definitions + // every time, which kinds of defeats the performance gains of the compiled container + throw new \LogicException('You cannot set a definition at runtime on a compiled container. You can either put your definitions in a file, disable compilation or ->set() a raw value directly (PHP object, string, int, ...) instead of a PHP-DI definition.'); + } + + /** + * Invoke the given callable. + */ + protected function resolveFactory($callable, $entryName, array $extraParameters = []) : mixed + { + // Initialize the factory resolver + if (! $this->factoryInvoker) { + $parameterResolver = new ResolverChain([ + new AssociativeArrayResolver, + new FactoryParameterResolver($this->delegateContainer), + new NumericArrayResolver, + new DefaultValueResolver, + ]); + + $this->factoryInvoker = new Invoker($parameterResolver, $this->delegateContainer); + } + + $parameters = [$this->delegateContainer, new RequestedEntryHolder($entryName)]; + + $parameters = array_merge($parameters, $extraParameters); + + try { + return $this->factoryInvoker->call($callable, $parameters); + } catch (NotCallableException $e) { + throw new InvalidDefinition("Entry \"$entryName\" cannot be resolved: factory " . $e->getMessage()); + } catch (NotEnoughParametersException $e) { + throw new InvalidDefinition("Entry \"$entryName\" cannot be resolved: " . $e->getMessage()); + } + } +} diff --git a/api/vendor/php-di/php-di/src/Compiler/Compiler.php b/api/vendor/php-di/php-di/src/Compiler/Compiler.php new file mode 100644 index 0000000..4f5e4b1 --- /dev/null +++ b/api/vendor/php-di/php-di/src/Compiler/Compiler.php @@ -0,0 +1,402 @@ + + */ +class Compiler +{ + private string $containerClass; + + private string $containerParentClass; + + /** + * Definitions indexed by the entry name. The value can be null if the definition needs to be fetched. + * + * Keys are strings, values are `Definition` objects or null. + */ + private \ArrayIterator $entriesToCompile; + + /** + * Progressive counter for definitions. + * + * Each key in $entriesToCompile is defined as 'SubEntry' + counter + * and each definition has always the same key in the CompiledContainer + * if PHP-DI configuration does not change. + */ + private int $subEntryCounter = 0; + + /** + * Progressive counter for CompiledContainer get methods. + * + * Each CompiledContainer method name is defined as 'get' + counter + * and remains the same after each recompilation + * if PHP-DI configuration does not change. + */ + private int $methodMappingCounter = 0; + + /** + * Map of entry names to method names. + * + * @var string[] + */ + private array $entryToMethodMapping = []; + + /** + * @var string[] + */ + private array $methods = []; + + private bool $autowiringEnabled; + + public function __construct( + private ProxyFactoryInterface $proxyFactory, + ) { + } + + public function getProxyFactory() : ProxyFactoryInterface + { + return $this->proxyFactory; + } + + /** + * Compile the container. + * + * @return string The compiled container file name. + */ + public function compile( + DefinitionSource $definitionSource, + string $directory, + string $className, + string $parentClassName, + bool $autowiringEnabled, + ) : string { + $fileName = rtrim($directory, '/') . '/' . $className . '.php'; + + if (file_exists($fileName)) { + // The container is already compiled + return $fileName; + } + + $this->autowiringEnabled = $autowiringEnabled; + + // Validate that a valid class name was provided + $validClassName = preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*$/', $className); + if (!$validClassName) { + throw new InvalidArgumentException("The container cannot be compiled: `$className` is not a valid PHP class name"); + } + + $this->entriesToCompile = new \ArrayIterator($definitionSource->getDefinitions()); + + // We use an ArrayIterator so that we can keep adding new items to the list while we compile entries + foreach ($this->entriesToCompile as $entryName => $definition) { + $silenceErrors = false; + // This is an entry found by reference during autowiring + if (!$definition) { + $definition = $definitionSource->getDefinition($entryName); + // We silence errors for those entries because type-hints may reference interfaces/abstract classes + // which could later be defined, or even not used (we don't want to block the compilation for those) + $silenceErrors = true; + } + if (!$definition) { + // We do not throw a `NotFound` exception here because the dependency + // could be defined at runtime + continue; + } + // Check that the definition can be compiled + $errorMessage = $this->isCompilable($definition); + if ($errorMessage !== true) { + continue; + } + try { + $this->compileDefinition($entryName, $definition); + } catch (InvalidDefinition $e) { + if ($silenceErrors) { + // forget the entry + unset($this->entryToMethodMapping[$entryName]); + } else { + throw $e; + } + } + } + + $this->containerClass = $className; + $this->containerParentClass = $parentClassName; + + ob_start(); + require __DIR__ . '/Template.php'; + $fileContent = ob_get_clean(); + + $fileContent = "createCompilationDirectory(dirname($fileName)); + $this->writeFileAtomic($fileName, $fileContent); + + return $fileName; + } + + private function writeFileAtomic(string $fileName, string $content) : void + { + $tmpFile = @tempnam(dirname($fileName), 'swap-compile'); + if ($tmpFile === false) { + throw new InvalidArgumentException( + sprintf('Error while creating temporary file in %s', dirname($fileName)) + ); + } + @chmod($tmpFile, 0666); + + $written = file_put_contents($tmpFile, $content); + if ($written === false) { + @unlink($tmpFile); + + throw new InvalidArgumentException(sprintf('Error while writing to %s', $tmpFile)); + } + + @chmod($tmpFile, 0666); + $renamed = @rename($tmpFile, $fileName); + if (!$renamed) { + @unlink($tmpFile); + + throw new InvalidArgumentException(sprintf('Error while renaming %s to %s', $tmpFile, $fileName)); + } + } + + /** + * @return string The method name + * @throws DependencyException + * @throws InvalidDefinition + */ + private function compileDefinition(string $entryName, Definition $definition) : string + { + // Generate a unique method name + $methodName = 'get' . (++$this->methodMappingCounter); + $this->entryToMethodMapping[$entryName] = $methodName; + + switch (true) { + case $definition instanceof ValueDefinition: + $value = $definition->getValue(); + $code = 'return ' . $this->compileValue($value) . ';'; + break; + case $definition instanceof Reference: + $targetEntryName = $definition->getTargetEntryName(); + $code = 'return $this->delegateContainer->get(' . $this->compileValue($targetEntryName) . ');'; + // If this method is not yet compiled we store it for compilation + if (!isset($this->entriesToCompile[$targetEntryName])) { + $this->entriesToCompile[$targetEntryName] = null; + } + break; + case $definition instanceof StringDefinition: + $entryName = $this->compileValue($definition->getName()); + $expression = $this->compileValue($definition->getExpression()); + $code = 'return \DI\Definition\StringDefinition::resolveExpression(' . $entryName . ', ' . $expression . ', $this->delegateContainer);'; + break; + case $definition instanceof EnvironmentVariableDefinition: + $variableName = $this->compileValue($definition->getVariableName()); + $isOptional = $this->compileValue($definition->isOptional()); + $defaultValue = $this->compileValue($definition->getDefaultValue()); + $code = <<getVariableName()}' has not been defined"); + } + return $defaultValue; + PHP; + break; + case $definition instanceof ArrayDefinition: + try { + $code = 'return ' . $this->compileValue($definition->getValues()) . ';'; + } catch (\Exception $e) { + throw new DependencyException(sprintf( + 'Error while compiling %s. %s', + $definition->getName(), + $e->getMessage() + ), 0, $e); + } + break; + case $definition instanceof ObjectDefinition: + $compiler = new ObjectCreationCompiler($this); + $code = $compiler->compile($definition); + $code .= "\n return \$object;"; + break; + case $definition instanceof DecoratorDefinition: + $decoratedDefinition = $definition->getDecoratedDefinition(); + if (! $decoratedDefinition instanceof Definition) { + if (! $definition->getName()) { + throw new InvalidDefinition('Decorators cannot be nested in another definition'); + } + throw new InvalidDefinition(sprintf( + 'Entry "%s" decorates nothing: no previous definition with the same name was found', + $definition->getName() + )); + } + $code = sprintf( + 'return call_user_func(%s, %s, $this->delegateContainer);', + $this->compileValue($definition->getCallable()), + $this->compileValue($decoratedDefinition) + ); + break; + case $definition instanceof FactoryDefinition: + $value = $definition->getCallable(); + + // Custom error message to help debugging + $isInvokableClass = is_string($value) && class_exists($value) && method_exists($value, '__invoke'); + if ($isInvokableClass && !$this->autowiringEnabled) { + throw new InvalidDefinition(sprintf( + 'Entry "%s" cannot be compiled. Invokable classes cannot be automatically resolved if autowiring is disabled on the container, you need to enable autowiring or define the entry manually.', + $entryName + )); + } + + $definitionParameters = ''; + if (!empty($definition->getParameters())) { + $definitionParameters = ', ' . $this->compileValue($definition->getParameters()); + } + + $code = sprintf( + 'return $this->resolveFactory(%s, %s%s);', + $this->compileValue($value), + var_export($entryName, true), + $definitionParameters + ); + + break; + default: + // This case should not happen (so it cannot be tested) + throw new \Exception('Cannot compile definition of type ' . $definition::class); + } + + $this->methods[$methodName] = $code; + + return $methodName; + } + + public function compileValue(mixed $value) : string + { + // Check that the value can be compiled + $errorMessage = $this->isCompilable($value); + if ($errorMessage !== true) { + throw new InvalidDefinition($errorMessage); + } + + if ($value instanceof Definition) { + // Give it an arbitrary unique name + $subEntryName = 'subEntry' . (++$this->subEntryCounter); + // Compile the sub-definition in another method + $methodName = $this->compileDefinition($subEntryName, $value); + + // The value is now a method call to that method (which returns the value) + return "\$this->$methodName()"; + } + + if (is_array($value)) { + $value = array_map(function ($value, $key) { + $compiledValue = $this->compileValue($value); + $key = var_export($key, true); + + return " $key => $compiledValue,\n"; + }, $value, array_keys($value)); + $value = implode('', $value); + + return "[\n$value ]"; + } + + if ($value instanceof \Closure) { + return $this->compileClosure($value); + } + + return var_export($value, true); + } + + private function createCompilationDirectory(string $directory) : void + { + if (!is_dir($directory) && !@mkdir($directory, 0777, true) && !is_dir($directory)) { + throw new InvalidArgumentException(sprintf('Compilation directory does not exist and cannot be created: %s.', $directory)); + } + if (!is_writable($directory)) { + throw new InvalidArgumentException(sprintf('Compilation directory is not writable: %s.', $directory)); + } + } + + /** + * @return string|true If true is returned that means that the value is compilable. + */ + private function isCompilable($value) : string|bool + { + if ($value instanceof ValueDefinition) { + return $this->isCompilable($value->getValue()); + } + if (($value instanceof DecoratorDefinition) && empty($value->getName())) { + return 'Decorators cannot be nested in another definition'; + } + // All other definitions are compilable + if ($value instanceof Definition) { + return true; + } + if ($value instanceof \Closure) { + return true; + } + /** @psalm-suppress UndefinedClass */ + if ((\PHP_VERSION_ID >= 80100) && ($value instanceof \UnitEnum)) { + return true; + } + if (is_object($value)) { + return 'An object was found but objects cannot be compiled'; + } + if (is_resource($value)) { + return 'A resource was found but resources cannot be compiled'; + } + + return true; + } + + /** + * @throws InvalidDefinition + */ + private function compileClosure(\Closure $closure) : string + { + $reflector = new ReflectionClosure($closure); + + if ($reflector->getUseVariables()) { + throw new InvalidDefinition('Cannot compile closures which import variables using the `use` keyword'); + } + + if ($reflector->isBindingRequired() || $reflector->isScopeRequired()) { + throw new InvalidDefinition('Cannot compile closures which use $this or self/static/parent references'); + } + + // Force all closures to be static (add the `static` keyword), i.e. they can't use + // $this, which makes sense since their code is copied into another class. + $code = ($reflector->isStatic() ? '' : 'static ') . $reflector->getCode(); + + return trim($code, "\t\n\r;"); + } +} diff --git a/api/vendor/php-di/php-di/src/Compiler/ObjectCreationCompiler.php b/api/vendor/php-di/php-di/src/Compiler/ObjectCreationCompiler.php new file mode 100644 index 0000000..f951cb0 --- /dev/null +++ b/api/vendor/php-di/php-di/src/Compiler/ObjectCreationCompiler.php @@ -0,0 +1,198 @@ + + */ +class ObjectCreationCompiler +{ + public function __construct( + private Compiler $compiler, + ) { + } + + public function compile(ObjectDefinition $definition) : string + { + $this->assertClassIsNotAnonymous($definition); + $this->assertClassIsInstantiable($definition); + /** @var class-string $className At this point we have checked the class is valid */ + $className = $definition->getClassName(); + + // Lazy? + if ($definition->isLazy()) { + return $this->compileLazyDefinition($definition); + } + + try { + $classReflection = new ReflectionClass($className); + $constructorArguments = $this->resolveParameters($definition->getConstructorInjection(), $classReflection->getConstructor()); + $dumpedConstructorArguments = array_map(function ($value) { + return $this->compiler->compileValue($value); + }, $constructorArguments); + + $code = []; + $code[] = sprintf( + '$object = new %s(%s);', + $className, + implode(', ', $dumpedConstructorArguments) + ); + + // Property injections + foreach ($definition->getPropertyInjections() as $propertyInjection) { + $value = $propertyInjection->getValue(); + $value = $this->compiler->compileValue($value); + + $propertyClassName = $propertyInjection->getClassName() ?: $className; + $property = new ReflectionProperty($propertyClassName, $propertyInjection->getPropertyName()); + if ($property->isPublic() && !(\PHP_VERSION_ID >= 80100 && $property->isReadOnly())) { + $code[] = sprintf('$object->%s = %s;', $propertyInjection->getPropertyName(), $value); + } else { + // Private/protected/readonly property + $code[] = sprintf( + '\DI\Definition\Resolver\ObjectCreator::setPrivatePropertyValue(%s, $object, \'%s\', %s);', + var_export($propertyInjection->getClassName(), true), + $propertyInjection->getPropertyName(), + $value + ); + } + } + + // Method injections + foreach ($definition->getMethodInjections() as $methodInjection) { + $methodReflection = new ReflectionMethod($className, $methodInjection->getMethodName()); + $parameters = $this->resolveParameters($methodInjection, $methodReflection); + + $dumpedParameters = array_map(function ($value) { + return $this->compiler->compileValue($value); + }, $parameters); + + $code[] = sprintf( + '$object->%s(%s);', + $methodInjection->getMethodName(), + implode(', ', $dumpedParameters) + ); + } + } catch (InvalidDefinition $e) { + throw InvalidDefinition::create($definition, sprintf( + 'Entry "%s" cannot be compiled: %s', + $definition->getName(), + $e->getMessage() + )); + } + + return implode("\n ", $code); + } + + public function resolveParameters(?MethodInjection $definition, ?ReflectionMethod $method) : array + { + $args = []; + + if (! $method) { + return $args; + } + + $definitionParameters = $definition ? $definition->getParameters() : []; + + foreach ($method->getParameters() as $index => $parameter) { + if (array_key_exists($index, $definitionParameters)) { + // Look in the definition + $value = &$definitionParameters[$index]; + } elseif ($parameter->isOptional()) { + // If the parameter is optional and wasn't specified, we take its default value + $args[] = $this->getParameterDefaultValue($parameter, $method); + continue; + } else { + throw new InvalidDefinition(sprintf( + 'Parameter $%s of %s has no value defined or guessable', + $parameter->getName(), + $this->getFunctionName($method) + )); + } + + $args[] = &$value; + } + + return $args; + } + + private function compileLazyDefinition(ObjectDefinition $definition) : string + { + $subDefinition = clone $definition; + $subDefinition->setLazy(false); + $subDefinition = $this->compiler->compileValue($subDefinition); + + /** @var class-string $className At this point we have checked the class is valid */ + $className = $definition->getClassName(); + + $this->compiler->getProxyFactory()->generateProxyClass($className); + + return <<proxyFactory->createProxy( + '{$definition->getClassName()}', + function () { + return $subDefinition; + } + ); + STR; + } + + /** + * Returns the default value of a function parameter. + * + * @throws InvalidDefinition Can't get default values from PHP internal classes and functions + */ + private function getParameterDefaultValue(ReflectionParameter $parameter, ReflectionMethod $function) : mixed + { + try { + return $parameter->getDefaultValue(); + } catch (\ReflectionException) { + throw new InvalidDefinition(sprintf( + 'The parameter "%s" of %s has no type defined or guessable. It has a default value, ' + . 'but the default value can\'t be read through Reflection because it is a PHP internal class.', + $parameter->getName(), + $this->getFunctionName($function) + )); + } + } + + private function getFunctionName(ReflectionMethod $method) : string + { + return $method->getName() . '()'; + } + + private function assertClassIsNotAnonymous(ObjectDefinition $definition) : void + { + if (str_contains($definition->getClassName(), '@')) { + throw InvalidDefinition::create($definition, sprintf( + 'Entry "%s" cannot be compiled: anonymous classes cannot be compiled', + $definition->getName() + )); + } + } + + private function assertClassIsInstantiable(ObjectDefinition $definition) : void + { + if ($definition->isInstantiable()) { + return; + } + + $message = ! $definition->classExists() + ? 'Entry "%s" cannot be compiled: the class doesn\'t exist' + : 'Entry "%s" cannot be compiled: the class is not instantiable'; + + throw InvalidDefinition::create($definition, sprintf($message, $definition->getName())); + } +} diff --git a/api/vendor/php-di/php-di/src/Compiler/RequestedEntryHolder.php b/api/vendor/php-di/php-di/src/Compiler/RequestedEntryHolder.php new file mode 100644 index 0000000..2d9cba9 --- /dev/null +++ b/api/vendor/php-di/php-di/src/Compiler/RequestedEntryHolder.php @@ -0,0 +1,23 @@ + + */ +class RequestedEntryHolder implements RequestedEntry +{ + public function __construct( + private string $name, + ) { + } + + public function getName() : string + { + return $this->name; + } +} diff --git a/api/vendor/php-di/php-di/src/Compiler/Template.php b/api/vendor/php-di/php-di/src/Compiler/Template.php new file mode 100644 index 0000000..b63b9b8 --- /dev/null +++ b/api/vendor/php-di/php-di/src/Compiler/Template.php @@ -0,0 +1,16 @@ +/** + * This class has been auto-generated by PHP-DI. + */ +class containerClass; ?> extends containerParentClass; ?> +{ + const METHOD_MAPPING = entryToMethodMapping); ?>; + +methods as $methodName => $methodContent) { ?> + protected function () + { + + + } + + +} diff --git a/api/vendor/php-di/php-di/src/Container.php b/api/vendor/php-di/php-di/src/Container.php new file mode 100644 index 0000000..3bfb28a --- /dev/null +++ b/api/vendor/php-di/php-di/src/Container.php @@ -0,0 +1,404 @@ + + */ +class Container implements ContainerInterface, FactoryInterface, InvokerInterface +{ + /** + * Map of entries that are already resolved. + */ + protected array $resolvedEntries = []; + + private MutableDefinitionSource $definitionSource; + + private DefinitionResolver $definitionResolver; + + /** + * Map of definitions that are already fetched (local cache). + * + * @var array + */ + private array $fetchedDefinitions = []; + + /** + * Array of entries being resolved. Used to avoid circular dependencies and infinite loops. + */ + protected array $entriesBeingResolved = []; + + private ?InvokerInterface $invoker = null; + + /** + * Container that wraps this container. If none, points to $this. + */ + protected ContainerInterface $delegateContainer; + + protected ProxyFactoryInterface $proxyFactory; + + public static function create( + array $definitions, + ) : static { + $source = new SourceChain([new ReflectionBasedAutowiring]); + $source->setMutableDefinitionSource(new DefinitionArray($definitions, new ReflectionBasedAutowiring)); + + return new static($definitions); + } + + /** + * Use `$container = new Container()` if you want a container with the default configuration. + * + * If you want to customize the container's behavior, you are discouraged to create and pass the + * dependencies yourself, the ContainerBuilder class is here to help you instead. + * + * @see ContainerBuilder + * + * @param ContainerInterface $wrapperContainer If the container is wrapped by another container. + */ + public function __construct( + array|MutableDefinitionSource $definitions = [], + ?ProxyFactoryInterface $proxyFactory = null, + ?ContainerInterface $wrapperContainer = null, + ) { + if (is_array($definitions)) { + $this->definitionSource = $this->createDefaultDefinitionSource($definitions); + } else { + $this->definitionSource = $definitions; + } + + $this->delegateContainer = $wrapperContainer ?: $this; + + if ($proxyFactory === null) { + $proxyFactory = (\PHP_VERSION_ID >= 80400) ? new NativeProxyFactory : new ProxyFactory; + } + $this->proxyFactory = $proxyFactory; + $this->definitionResolver = new ResolverDispatcher($this->delegateContainer, $this->proxyFactory); + + // Auto-register the container + $this->resolvedEntries = [ + self::class => $this, + ContainerInterface::class => $this->delegateContainer, + FactoryInterface::class => $this, + InvokerInterface::class => $this, + ]; + } + + /** + * Returns an entry of the container by its name. + * + * @template T + * @param string|class-string $id Entry name or a class name. + * + * @return mixed|T + * @throws DependencyException Error while resolving the entry. + * @throws NotFoundException No entry found for the given name. + */ + public function get(string $id) : mixed + { + // If the entry is already resolved we return it + if (isset($this->resolvedEntries[$id]) || array_key_exists($id, $this->resolvedEntries)) { + return $this->resolvedEntries[$id]; + } + + $definition = $this->getDefinition($id); + if (! $definition) { + throw new NotFoundException("No entry or class found for '$id'"); + } + + $value = $this->resolveDefinition($definition); + + $this->resolvedEntries[$id] = $value; + + return $value; + } + + private function getDefinition(string $name) : ?Definition + { + // Local cache that avoids fetching the same definition twice + if (!array_key_exists($name, $this->fetchedDefinitions)) { + $this->fetchedDefinitions[$name] = $this->definitionSource->getDefinition($name); + } + + return $this->fetchedDefinitions[$name]; + } + + /** + * Build an entry of the container by its name. + * + * This method behave like get() except resolves the entry again every time. + * For example if the entry is a class then a new instance will be created each time. + * + * This method makes the container behave like a factory. + * + * @template T + * @param string|class-string $name Entry name or a class name. + * @param array $parameters Optional parameters to use to build the entry. Use this to force + * specific parameters to specific values. Parameters not defined in this + * array will be resolved using the container. + * + * @return mixed|T + * @throws InvalidArgumentException The name parameter must be of type string. + * @throws DependencyException Error while resolving the entry. + * @throws NotFoundException No entry found for the given name. + */ + public function make(string $name, array $parameters = []) : mixed + { + $definition = $this->getDefinition($name); + if (! $definition) { + // If the entry is already resolved we return it + if (array_key_exists($name, $this->resolvedEntries)) { + return $this->resolvedEntries[$name]; + } + + throw new NotFoundException("No entry or class found for '$name'"); + } + + return $this->resolveDefinition($definition, $parameters); + } + + public function has(string $id) : bool + { + if (array_key_exists($id, $this->resolvedEntries)) { + return true; + } + + $definition = $this->getDefinition($id); + if ($definition === null) { + return false; + } + + return $this->definitionResolver->isResolvable($definition); + } + + /** + * Inject all dependencies on an existing instance. + * + * @template T + * @param object|T $instance Object to perform injection upon + * @return object|T $instance Returns the same instance + * @throws InvalidArgumentException + * @throws DependencyException Error while injecting dependencies + */ + public function injectOn(object $instance) : object + { + $className = $instance::class; + + // If the class is anonymous, don't cache its definition + // Checking for anonymous classes is cleaner via Reflection, but also slower + $objectDefinition = str_contains($className, '@anonymous') + ? $this->definitionSource->getDefinition($className) + : $this->getDefinition($className); + + if (! $objectDefinition instanceof ObjectDefinition) { + return $instance; + } + + $definition = new InstanceDefinition($instance, $objectDefinition); + + $this->definitionResolver->resolve($definition); + + return $instance; + } + + /** + * Call the given function using the given parameters. + * + * Missing parameters will be resolved from the container. + * + * @param callable|array|string $callable Function to call. + * @param array $parameters Parameters to use. Can be indexed by the parameter names + * or not indexed (same order as the parameters). + * The array can also contain DI definitions, e.g. DI\get(). + * + * @return mixed Result of the function. + */ + public function call($callable, array $parameters = []) : mixed + { + return $this->getInvoker()->call($callable, $parameters); + } + + /** + * Define an object or a value in the container. + * + * @param string $name Entry name + * @param mixed|DefinitionHelper $value Value, use definition helpers to define objects + */ + public function set(string $name, mixed $value) : void + { + if ($value instanceof DefinitionHelper) { + $value = $value->getDefinition($name); + } elseif ($value instanceof \Closure) { + $value = new FactoryDefinition($name, $value); + } + + if ($value instanceof ValueDefinition) { + $this->resolvedEntries[$name] = $value->getValue(); + } elseif ($value instanceof Definition) { + $value->setName($name); + $this->setDefinition($name, $value); + } else { + $this->resolvedEntries[$name] = $value; + } + } + + /** + * Get defined container entries. + * + * @return string[] + */ + public function getKnownEntryNames() : array + { + $entries = array_unique(array_merge( + array_keys($this->definitionSource->getDefinitions()), + array_keys($this->resolvedEntries) + )); + sort($entries); + + return $entries; + } + + /** + * Get entry debug information. + * + * @param string $name Entry name + * + * @throws InvalidDefinition + * @throws NotFoundException + */ + public function debugEntry(string $name) : string + { + $definition = $this->definitionSource->getDefinition($name); + if ($definition instanceof Definition) { + return (string) $definition; + } + + if (array_key_exists($name, $this->resolvedEntries)) { + return $this->getEntryType($this->resolvedEntries[$name]); + } + + throw new NotFoundException("No entry or class found for '$name'"); + } + + /** + * Get formatted entry type. + */ + private function getEntryType(mixed $entry) : string + { + if (is_object($entry)) { + return sprintf("Object (\n class = %s\n)", $entry::class); + } + + if (is_array($entry)) { + return preg_replace(['/^array \(/', '/\)$/'], ['[', ']'], var_export($entry, true)); + } + + if (is_string($entry)) { + return sprintf('Value (\'%s\')', $entry); + } + + if (is_bool($entry)) { + return sprintf('Value (%s)', $entry === true ? 'true' : 'false'); + } + + return sprintf('Value (%s)', is_scalar($entry) ? (string) $entry : ucfirst(gettype($entry))); + } + + /** + * Resolves a definition. + * + * Checks for circular dependencies while resolving the definition. + * + * @throws DependencyException Error while resolving the entry. + */ + private function resolveDefinition(Definition $definition, array $parameters = []) : mixed + { + $entryName = $definition->getName(); + + // Check if we are already getting this entry -> circular dependency + if (isset($this->entriesBeingResolved[$entryName])) { + $entryList = implode(' -> ', [...array_keys($this->entriesBeingResolved), $entryName]); + throw new DependencyException("Circular dependency detected while trying to resolve entry '$entryName': Dependencies: " . $entryList); + } + $this->entriesBeingResolved[$entryName] = true; + + // Resolve the definition + try { + $value = $this->definitionResolver->resolve($definition, $parameters); + } finally { + unset($this->entriesBeingResolved[$entryName]); + } + + return $value; + } + + protected function setDefinition(string $name, Definition $definition) : void + { + // Clear existing entry if it exists + if (array_key_exists($name, $this->resolvedEntries)) { + unset($this->resolvedEntries[$name]); + } + $this->fetchedDefinitions = []; // Completely clear this local cache + + $this->definitionSource->addDefinition($definition); + } + + private function getInvoker() : InvokerInterface + { + if (! $this->invoker) { + $parameterResolver = new ResolverChain([ + new DefinitionParameterResolver($this->definitionResolver), + new NumericArrayResolver, + new AssociativeArrayResolver, + new DefaultValueResolver, + new TypeHintContainerResolver($this->delegateContainer), + ]); + + $this->invoker = new Invoker($parameterResolver, $this); + } + + return $this->invoker; + } + + private function createDefaultDefinitionSource(array $definitions) : SourceChain + { + $autowiring = new ReflectionBasedAutowiring; + $source = new SourceChain([$autowiring]); + $source->setMutableDefinitionSource(new DefinitionArray($definitions, $autowiring)); + + return $source; + } +} diff --git a/api/vendor/php-di/php-di/src/ContainerBuilder.php b/api/vendor/php-di/php-di/src/ContainerBuilder.php new file mode 100644 index 0000000..393c7a0 --- /dev/null +++ b/api/vendor/php-di/php-di/src/ContainerBuilder.php @@ -0,0 +1,336 @@ +build(); + * + * @api + * + * @since 3.2 + * @author Matthieu Napoli + * + * @psalm-template ContainerClass of Container + */ +class ContainerBuilder +{ + /** + * Name of the container class, used to create the container. + * @var class-string + * @psalm-var class-string + */ + private string $containerClass; + + /** + * Name of the container parent class, used on compiled container. + * @var class-string + * @psalm-var class-string + */ + private string $containerParentClass; + + private bool $useAutowiring = true; + + private bool $useAttributes = false; + + /** + * If set, write the proxies to disk in this directory to improve performances. + */ + private ?string $proxyDirectory = null; + + /** + * If PHP-DI is wrapped in another container, this references the wrapper. + */ + private ?ContainerInterface $wrapperContainer = null; + + /** + * @var DefinitionSource[]|string[]|array[] + */ + private array $definitionSources = []; + + /** + * Whether the container has already been built. + */ + private bool $locked = false; + + private ?string $compileToDirectory = null; + + private bool $sourceCache = false; + + protected string $sourceCacheNamespace = ''; + + /** + * @param class-string $containerClass Name of the container class, used to create the container. + * @psalm-param class-string $containerClass + */ + public function __construct(string $containerClass = Container::class) + { + $this->containerClass = $containerClass; + } + + /** + * Build and return a container. + * + * @return Container + * @psalm-return ContainerClass + */ + public function build() + { + $sources = array_reverse($this->definitionSources); + + if ($this->useAttributes) { + $autowiring = new AttributeBasedAutowiring; + $sources[] = $autowiring; + } elseif ($this->useAutowiring) { + $autowiring = new ReflectionBasedAutowiring; + $sources[] = $autowiring; + } else { + $autowiring = new NoAutowiring; + } + + $sources = array_map(function ($definitions) use ($autowiring) { + if (is_string($definitions)) { + // File + return new DefinitionFile($definitions, $autowiring); + } + if (is_array($definitions)) { + return new DefinitionArray($definitions, $autowiring); + } + + return $definitions; + }, $sources); + $source = new SourceChain($sources); + + // Mutable definition source + $source->setMutableDefinitionSource(new DefinitionArray([], $autowiring)); + + if ($this->sourceCache) { + if (!SourceCache::isSupported()) { + throw new \Exception('APCu is not enabled, PHP-DI cannot use it as a cache'); + } + // Wrap the source with the cache decorator + $source = new SourceCache($source, $this->sourceCacheNamespace); + } + + $proxyFactory = (\PHP_VERSION_ID >= 80400) + ? new NativeProxyFactory() + : new ProxyFactory($this->proxyDirectory); + + $this->locked = true; + + $containerClass = $this->containerClass; + + if ($this->compileToDirectory) { + $compiler = new Compiler($proxyFactory); + $compiledContainerFile = $compiler->compile( + $source, + $this->compileToDirectory, + $containerClass, + $this->containerParentClass, + $this->useAutowiring + ); + // Only load the file if it hasn't been already loaded + // (the container can be created multiple times in the same process) + if (!class_exists($containerClass, false)) { + require $compiledContainerFile; + } + } + + return new $containerClass($source, $proxyFactory, $this->wrapperContainer); + } + + /** + * Compile the container for optimum performances. + * + * Be aware that the container is compiled once and never updated! + * + * Therefore: + * + * - in production you should clear that directory every time you deploy + * - in development you should not compile the container + * + * @see https://php-di.org/doc/performances.html + * + * @psalm-template T of CompiledContainer + * + * @param string $directory Directory in which to put the compiled container. + * @param string $containerClass Name of the compiled class. Customize only if necessary. + * @param class-string $containerParentClass Name of the compiled container parent class. Customize only if necessary. + * @psalm-param class-string $containerParentClass + * + * @psalm-return self + */ + public function enableCompilation( + string $directory, + string $containerClass = 'CompiledContainer', + string $containerParentClass = CompiledContainer::class, + ) : self { + $this->ensureNotLocked(); + + $this->compileToDirectory = $directory; + $this->containerClass = $containerClass; + $this->containerParentClass = $containerParentClass; + + return $this; + } + + /** + * Enable or disable the use of autowiring to guess injections. + * + * Enabled by default. + * + * @return $this + */ + public function useAutowiring(bool $bool) : self + { + $this->ensureNotLocked(); + + $this->useAutowiring = $bool; + + return $this; + } + + /** + * Enable or disable the use of PHP 8 attributes to configure injections. + * + * Disabled by default. + * + * @return $this + */ + public function useAttributes(bool $bool) : self + { + $this->ensureNotLocked(); + + $this->useAttributes = $bool; + + return $this; + } + + /** + * Configure the proxy generation. + * + * For dev environment, use `writeProxiesToFile(false)` (default configuration) + * For production environment, use `writeProxiesToFile(true, 'tmp/proxies')` + * + * @see https://php-di.org/doc/lazy-injection.html + * + * @param bool $writeToFile If true, write the proxies to disk to improve performances + * @param string|null $proxyDirectory Directory where to write the proxies + * @return $this + * @throws InvalidArgumentException when writeToFile is set to true and the proxy directory is null + */ + public function writeProxiesToFile(bool $writeToFile, ?string $proxyDirectory = null) : self + { + $this->ensureNotLocked(); + + if ($writeToFile && $proxyDirectory === null) { + throw new InvalidArgumentException( + 'The proxy directory must be specified if you want to write proxies on disk' + ); + } + $this->proxyDirectory = $writeToFile ? $proxyDirectory : null; + + return $this; + } + + /** + * If PHP-DI's container is wrapped by another container, we can + * set this so that PHP-DI will use the wrapper rather than itself for building objects. + * + * @return $this + */ + public function wrapContainer(ContainerInterface $otherContainer) : self + { + $this->ensureNotLocked(); + + $this->wrapperContainer = $otherContainer; + + return $this; + } + + /** + * Add definitions to the container. + * + * @param string|array|DefinitionSource ...$definitions Can be an array of definitions, the + * name of a file containing definitions + * or a DefinitionSource object. + * @return $this + */ + public function addDefinitions(string|array|DefinitionSource ...$definitions) : self + { + $this->ensureNotLocked(); + + foreach ($definitions as $definition) { + $this->definitionSources[] = $definition; + } + + return $this; + } + + /** + * Enables the use of APCu to cache definitions. + * + * You must have APCu enabled to use it. + * + * Before using this feature, you should try these steps first: + * - enable compilation if not already done (see `enableCompilation()`) + * - if you use autowiring or attributes, add all the classes you are using into your configuration so that + * PHP-DI knows about them and compiles them + * Once this is done, you can try to optimize performances further with APCu. It can also be useful if you use + * `Container::make()` instead of `get()` (`make()` calls cannot be compiled so they are not optimized). + * + * Remember to clear APCu on each deploy else your application will have a stale cache. Do not enable the cache + * in development environment: any change you will make to the code will be ignored because of the cache. + * + * @see https://php-di.org/doc/performances.html + * + * @param string $cacheNamespace use unique namespace per container when sharing a single APC memory pool to prevent cache collisions + * @return $this + */ + public function enableDefinitionCache(string $cacheNamespace = '') : self + { + $this->ensureNotLocked(); + + $this->sourceCache = true; + $this->sourceCacheNamespace = $cacheNamespace; + + return $this; + } + + /** + * Are we building a compiled container? + */ + public function isCompilationEnabled() : bool + { + return (bool) $this->compileToDirectory; + } + + private function ensureNotLocked() : void + { + if ($this->locked) { + throw new \LogicException('The ContainerBuilder cannot be modified after the container has been built'); + } + } +} diff --git a/api/vendor/php-di/php-di/src/Definition/ArrayDefinition.php b/api/vendor/php-di/php-di/src/Definition/ArrayDefinition.php new file mode 100644 index 0000000..fd0f8b4 --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/ArrayDefinition.php @@ -0,0 +1,65 @@ + + */ +class ArrayDefinition implements Definition +{ + /** Entry name. */ + private string $name = ''; + + public function __construct( + private array $values, + ) { + } + + public function getName() : string + { + return $this->name; + } + + public function setName(string $name) : void + { + $this->name = $name; + } + + public function getValues() : array + { + return $this->values; + } + + public function replaceNestedDefinitions(callable $replacer) : void + { + $this->values = array_map($replacer, $this->values); + } + + public function __toString() : string + { + $str = '[' . \PHP_EOL; + + foreach ($this->values as $key => $value) { + if (is_string($key)) { + $key = "'" . $key . "'"; + } + + $str .= ' ' . $key . ' => '; + + if ($value instanceof Definition) { + $str .= str_replace(\PHP_EOL, \PHP_EOL . ' ', (string) $value); + } else { + $str .= var_export($value, true); + } + + $str .= ',' . \PHP_EOL; + } + + return $str . ']'; + } +} diff --git a/api/vendor/php-di/php-di/src/Definition/ArrayDefinitionExtension.php b/api/vendor/php-di/php-di/src/Definition/ArrayDefinitionExtension.php new file mode 100644 index 0000000..d55f124 --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/ArrayDefinitionExtension.php @@ -0,0 +1,39 @@ + + */ +class ArrayDefinitionExtension extends ArrayDefinition implements ExtendsPreviousDefinition +{ + private ?ArrayDefinition $subDefinition = null; + + public function getValues() : array + { + if (! $this->subDefinition) { + return parent::getValues(); + } + + return array_merge($this->subDefinition->getValues(), parent::getValues()); + } + + public function setExtendedDefinition(Definition $definition) : void + { + if (! $definition instanceof ArrayDefinition) { + throw new InvalidDefinition(sprintf( + 'Definition %s tries to add array entries but the previous definition is not an array', + $this->getName() + )); + } + + $this->subDefinition = $definition; + } +} diff --git a/api/vendor/php-di/php-di/src/Definition/AutowireDefinition.php b/api/vendor/php-di/php-di/src/Definition/AutowireDefinition.php new file mode 100644 index 0000000..25dc3ec --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/AutowireDefinition.php @@ -0,0 +1,12 @@ + + */ +class AutowireDefinition extends ObjectDefinition +{ +} diff --git a/api/vendor/php-di/php-di/src/Definition/DecoratorDefinition.php b/api/vendor/php-di/php-di/src/Definition/DecoratorDefinition.php new file mode 100644 index 0000000..c84ed37 --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/DecoratorDefinition.php @@ -0,0 +1,36 @@ + + */ +class DecoratorDefinition extends FactoryDefinition implements Definition, ExtendsPreviousDefinition +{ + private ?Definition $decorated = null; + + public function setExtendedDefinition(Definition $definition) : void + { + $this->decorated = $definition; + } + + public function getDecoratedDefinition() : ?Definition + { + return $this->decorated; + } + + public function replaceNestedDefinitions(callable $replacer) : void + { + // no nested definitions + } + + public function __toString() : string + { + return 'Decorate(' . $this->getName() . ')'; + } +} diff --git a/api/vendor/php-di/php-di/src/Definition/Definition.php b/api/vendor/php-di/php-di/src/Definition/Definition.php new file mode 100644 index 0000000..8ceb9c6 --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/Definition.php @@ -0,0 +1,37 @@ + + */ +interface Definition extends RequestedEntry, \Stringable +{ + /** + * Returns the name of the entry in the container. + */ + public function getName() : string; + + /** + * Set the name of the entry in the container. + */ + public function setName(string $name) : void; + + /** + * Apply a callable that replaces the definitions nested in this definition. + */ + public function replaceNestedDefinitions(callable $replacer) : void; + + /** + * Definitions can be cast to string for debugging information. + */ + public function __toString() : string; +} diff --git a/api/vendor/php-di/php-di/src/Definition/Dumper/ObjectDefinitionDumper.php b/api/vendor/php-di/php-di/src/Definition/Dumper/ObjectDefinitionDumper.php new file mode 100644 index 0000000..c59c510 --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/Dumper/ObjectDefinitionDumper.php @@ -0,0 +1,144 @@ + + */ +class ObjectDefinitionDumper +{ + /** + * Returns the definition as string representation. + */ + public function dump(ObjectDefinition $definition) : string + { + $className = $definition->getClassName(); + $classExist = class_exists($className) || interface_exists($className); + + // Class + if (! $classExist) { + $warning = '#UNKNOWN# '; + } else { + $class = new \ReflectionClass($className); + $warning = $class->isInstantiable() ? '' : '#NOT INSTANTIABLE# '; + } + $str = sprintf(' class = %s%s', $warning, $className); + + // Lazy + $str .= \PHP_EOL . ' lazy = ' . var_export($definition->isLazy(), true); + + if ($classExist) { + // Constructor + $str .= $this->dumpConstructor($className, $definition); + + // Properties + $str .= $this->dumpProperties($definition); + + // Methods + $str .= $this->dumpMethods($className, $definition); + } + + return sprintf('Object (' . \PHP_EOL . '%s' . \PHP_EOL . ')', $str); + } + + /** + * @param class-string $className + */ + private function dumpConstructor(string $className, ObjectDefinition $definition) : string + { + $str = ''; + + $constructorInjection = $definition->getConstructorInjection(); + + if ($constructorInjection !== null) { + $parameters = $this->dumpMethodParameters($className, $constructorInjection); + + $str .= sprintf(\PHP_EOL . ' __construct(' . \PHP_EOL . ' %s' . \PHP_EOL . ' )', $parameters); + } + + return $str; + } + + private function dumpProperties(ObjectDefinition $definition) : string + { + $str = ''; + + foreach ($definition->getPropertyInjections() as $propertyInjection) { + $value = $propertyInjection->getValue(); + $valueStr = $value instanceof Definition ? (string) $value : var_export($value, true); + + $str .= sprintf(\PHP_EOL . ' $%s = %s', $propertyInjection->getPropertyName(), $valueStr); + } + + return $str; + } + + /** + * @param class-string $className + */ + private function dumpMethods(string $className, ObjectDefinition $definition) : string + { + $str = ''; + + foreach ($definition->getMethodInjections() as $methodInjection) { + $parameters = $this->dumpMethodParameters($className, $methodInjection); + + $str .= sprintf(\PHP_EOL . ' %s(' . \PHP_EOL . ' %s' . \PHP_EOL . ' )', $methodInjection->getMethodName(), $parameters); + } + + return $str; + } + + /** + * @param class-string $className + */ + private function dumpMethodParameters(string $className, MethodInjection $methodInjection) : string + { + $methodReflection = new \ReflectionMethod($className, $methodInjection->getMethodName()); + + $args = []; + + $definitionParameters = $methodInjection->getParameters(); + + foreach ($methodReflection->getParameters() as $index => $parameter) { + if (array_key_exists($index, $definitionParameters)) { + $value = $definitionParameters[$index]; + $valueStr = $value instanceof Definition ? (string) $value : var_export($value, true); + + $args[] = sprintf('$%s = %s', $parameter->getName(), $valueStr); + + continue; + } + + // If the parameter is optional and wasn't specified, we take its default value + if ($parameter->isOptional()) { + try { + $value = $parameter->getDefaultValue(); + + $args[] = sprintf( + '$%s = (default value) %s', + $parameter->getName(), + var_export($value, true) + ); + continue; + } catch (ReflectionException) { + // The default value can't be read through Reflection because it is a PHP internal class + } + } + + $args[] = sprintf('$%s = #UNDEFINED#', $parameter->getName()); + } + + return implode(\PHP_EOL . ' ', $args); + } +} diff --git a/api/vendor/php-di/php-di/src/Definition/EnvironmentVariableDefinition.php b/api/vendor/php-di/php-di/src/Definition/EnvironmentVariableDefinition.php new file mode 100644 index 0000000..5b42096 --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/EnvironmentVariableDefinition.php @@ -0,0 +1,87 @@ + + */ +class EnvironmentVariableDefinition implements Definition +{ + /** Entry name. */ + private string $name = ''; + + /** + * @param string $variableName The name of the environment variable + * @param bool $isOptional Whether or not the environment variable definition is optional. If true and the environment variable given by $variableName has not been defined, $defaultValue is used. + * @param mixed $defaultValue The default value to use if the environment variable is optional and not provided + */ + public function __construct( + private string $variableName, + private bool $isOptional = false, + private mixed $defaultValue = null, + ) { + } + + public function getName() : string + { + return $this->name; + } + + public function setName(string $name) : void + { + $this->name = $name; + } + + /** + * @return string The name of the environment variable + */ + public function getVariableName() : string + { + return $this->variableName; + } + + /** + * @return bool Whether or not the environment variable definition is optional + */ + public function isOptional() : bool + { + return $this->isOptional; + } + + /** + * @return mixed The default value to use if the environment variable is optional and not provided + */ + public function getDefaultValue() : mixed + { + return $this->defaultValue; + } + + public function replaceNestedDefinitions(callable $replacer) : void + { + $this->defaultValue = $replacer($this->defaultValue); + } + + public function __toString() : string + { + $str = ' variable = ' . $this->variableName . \PHP_EOL + . ' optional = ' . ($this->isOptional ? 'yes' : 'no'); + + if ($this->isOptional) { + if ($this->defaultValue instanceof Definition) { + $nestedDefinition = (string) $this->defaultValue; + $defaultValueStr = str_replace(\PHP_EOL, \PHP_EOL . ' ', $nestedDefinition); + } else { + $defaultValueStr = var_export($this->defaultValue, true); + } + + $str .= \PHP_EOL . ' default = ' . $defaultValueStr; + } + + return sprintf('Environment variable (' . \PHP_EOL . '%s' . \PHP_EOL . ')', $str); + } +} diff --git a/api/vendor/php-di/php-di/src/Definition/Exception/InvalidAttribute.php b/api/vendor/php-di/php-di/src/Definition/Exception/InvalidAttribute.php new file mode 100644 index 0000000..4504f18 --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/Exception/InvalidAttribute.php @@ -0,0 +1,14 @@ + + */ +class InvalidAttribute extends InvalidDefinition +{ +} diff --git a/api/vendor/php-di/php-di/src/Definition/Exception/InvalidDefinition.php b/api/vendor/php-di/php-di/src/Definition/Exception/InvalidDefinition.php new file mode 100644 index 0000000..f88aa69 --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/Exception/InvalidDefinition.php @@ -0,0 +1,25 @@ + + */ +class InvalidDefinition extends \Exception implements ContainerExceptionInterface +{ + public static function create(Definition $definition, string $message, ?\Exception $previous = null) : self + { + return new self(sprintf( + '%s' . \PHP_EOL . 'Full definition:' . \PHP_EOL . '%s', + $message, + (string) $definition + ), 0, $previous); + } +} diff --git a/api/vendor/php-di/php-di/src/Definition/ExtendsPreviousDefinition.php b/api/vendor/php-di/php-di/src/Definition/ExtendsPreviousDefinition.php new file mode 100644 index 0000000..ac2a7ab --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/ExtendsPreviousDefinition.php @@ -0,0 +1,15 @@ + + */ +interface ExtendsPreviousDefinition extends Definition +{ + public function setExtendedDefinition(Definition $definition) : void; +} diff --git a/api/vendor/php-di/php-di/src/Definition/FactoryDefinition.php b/api/vendor/php-di/php-di/src/Definition/FactoryDefinition.php new file mode 100644 index 0000000..5044c91 --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/FactoryDefinition.php @@ -0,0 +1,78 @@ + + */ +class FactoryDefinition implements Definition +{ + /** + * Entry name. + */ + private string $name; + + /** + * Callable that returns the value. + * @var callable + */ + private $factory; + + /** + * Factory parameters. + * @var mixed[] + */ + private array $parameters; + + /** + * @param string $name Entry name + * @param callable|array|string $factory Callable that returns the value associated to the entry name. + * @param array $parameters Parameters to be passed to the callable + */ + public function __construct(string $name, callable|array|string $factory, array $parameters = []) + { + $this->name = $name; + $this->factory = $factory; + $this->parameters = $parameters; + } + + public function getName() : string + { + return $this->name; + } + + public function setName(string $name) : void + { + $this->name = $name; + } + + /** + * @return callable|array|string Callable that returns the value associated to the entry name. + */ + public function getCallable() : callable|array|string + { + return $this->factory; + } + + /** + * @return array Array containing the parameters to be passed to the callable, indexed by name. + */ + public function getParameters() : array + { + return $this->parameters; + } + + public function replaceNestedDefinitions(callable $replacer) : void + { + $this->parameters = array_map($replacer, $this->parameters); + } + + public function __toString() : string + { + return 'Factory'; + } +} diff --git a/api/vendor/php-di/php-di/src/Definition/Helper/AutowireDefinitionHelper.php b/api/vendor/php-di/php-di/src/Definition/Helper/AutowireDefinitionHelper.php new file mode 100644 index 0000000..01b59e8 --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/Helper/AutowireDefinitionHelper.php @@ -0,0 +1,72 @@ + + */ +class AutowireDefinitionHelper extends CreateDefinitionHelper +{ + public const DEFINITION_CLASS = AutowireDefinition::class; + + /** + * Defines a value for a specific argument of the constructor. + * + * This method is usually used together with attributes or autowiring, when a parameter + * is not (or cannot be) type-hinted. Using this method instead of constructor() allows to + * avoid defining all the parameters (letting them being resolved using attributes or autowiring) + * and only define one. + * + * @param string|int $parameter Parameter name of position for which the value will be given. + * @param mixed $value Value to give to this parameter. + * + * @return $this + */ + public function constructorParameter(string|int $parameter, mixed $value) : self + { + $this->constructor[$parameter] = $value; + + return $this; + } + + /** + * Defines a method to call and a value for a specific argument. + * + * This method is usually used together with attributes or autowiring, when a parameter + * is not (or cannot be) type-hinted. Using this method instead of method() allows to + * avoid defining all the parameters (letting them being resolved using attributes or + * autowiring) and only define one. + * + * If multiple calls to the method have been configured already (e.g. in a previous definition) + * then this method only overrides the parameter for the *first* call. + * + * @param string $method Name of the method to call. + * @param string|int $parameter Parameter name of position for which the value will be given. + * @param mixed $value Value to give to this parameter. + * + * @return $this + */ + public function methodParameter(string $method, string|int $parameter, mixed $value) : self + { + // Special case for the constructor + if ($method === '__construct') { + $this->constructor[$parameter] = $value; + + return $this; + } + + if (! isset($this->methods[$method])) { + $this->methods[$method] = [0 => []]; + } + + $this->methods[$method][0][$parameter] = $value; + + return $this; + } +} diff --git a/api/vendor/php-di/php-di/src/Definition/Helper/CreateDefinitionHelper.php b/api/vendor/php-di/php-di/src/Definition/Helper/CreateDefinitionHelper.php new file mode 100644 index 0000000..5d21905 --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/Helper/CreateDefinitionHelper.php @@ -0,0 +1,189 @@ + + */ +class CreateDefinitionHelper implements DefinitionHelper +{ + private const DEFINITION_CLASS = ObjectDefinition::class; + + private ?string $className; + + private ?bool $lazy = null; + + /** + * Array of constructor parameters. + */ + protected array $constructor = []; + + /** + * Array of properties and their value. + */ + private array $properties = []; + + /** + * Array of methods and their parameters. + */ + protected array $methods = []; + + /** + * Helper for defining an object. + * + * @param string|null $className Class name of the object. + * If null, the name of the entry (in the container) will be used as class name. + */ + public function __construct(?string $className = null) + { + $this->className = $className; + } + + /** + * Define the entry as lazy. + * + * A lazy entry is created only when it is used, a proxy is injected instead. + * + * @return $this + */ + public function lazy() : self + { + $this->lazy = true; + + return $this; + } + + /** + * Defines the arguments to use to call the constructor. + * + * This method takes a variable number of arguments, example: + * ->constructor($param1, $param2, $param3) + * + * @param mixed ...$parameters Parameters to use for calling the constructor of the class. + * + * @return $this + */ + public function constructor(mixed ...$parameters) : self + { + $this->constructor = $parameters; + + return $this; + } + + /** + * Defines a value to inject in a property of the object. + * + * @param string $property Entry in which to inject the value. + * @param mixed $value Value to inject in the property. + * + * @return $this + */ + public function property(string $property, mixed $value) : self + { + $this->properties[$property] = $value; + + return $this; + } + + /** + * Defines a method to call and the arguments to use. + * + * This method takes a variable number of arguments after the method name, example: + * + * ->method('myMethod', $param1, $param2) + * + * Can be used multiple times to declare multiple calls. + * + * @param string $method Name of the method to call. + * @param mixed ...$parameters Parameters to use for calling the method. + * + * @return $this + */ + public function method(string $method, mixed ...$parameters) : self + { + if (! isset($this->methods[$method])) { + $this->methods[$method] = []; + } + + $this->methods[$method][] = $parameters; + + return $this; + } + + public function getDefinition(string $entryName) : ObjectDefinition + { + $class = $this::DEFINITION_CLASS; + /** @var ObjectDefinition $definition */ + $definition = new $class($entryName, $this->className); + + if ($this->lazy !== null) { + $definition->setLazy($this->lazy); + } + + if (! empty($this->constructor)) { + $parameters = $this->fixParameters($definition, '__construct', $this->constructor); + $constructorInjection = MethodInjection::constructor($parameters); + $definition->setConstructorInjection($constructorInjection); + } + + if (! empty($this->properties)) { + foreach ($this->properties as $property => $value) { + $definition->addPropertyInjection( + new PropertyInjection($property, $value) + ); + } + } + + if (! empty($this->methods)) { + foreach ($this->methods as $method => $calls) { + foreach ($calls as $parameters) { + $parameters = $this->fixParameters($definition, $method, $parameters); + $methodInjection = new MethodInjection($method, $parameters); + $definition->addMethodInjection($methodInjection); + } + } + } + + return $definition; + } + + /** + * Fixes parameters indexed by the parameter name -> reindex by position. + * + * This is necessary so that merging definitions between sources is possible. + * + * @throws InvalidDefinition + */ + private function fixParameters(ObjectDefinition $definition, string $method, array $parameters) : array + { + $fixedParameters = []; + + foreach ($parameters as $index => $parameter) { + // Parameter indexed by the parameter name, we reindex it with its position + if (is_string($index)) { + $callable = [$definition->getClassName(), $method]; + + try { + $reflectionParameter = new \ReflectionParameter($callable, $index); + } catch (\ReflectionException $e) { + throw InvalidDefinition::create($definition, sprintf("Parameter with name '%s' could not be found. %s.", $index, $e->getMessage())); + } + + $index = $reflectionParameter->getPosition(); + } + + $fixedParameters[$index] = $parameter; + } + + return $fixedParameters; + } +} diff --git a/api/vendor/php-di/php-di/src/Definition/Helper/DefinitionHelper.php b/api/vendor/php-di/php-di/src/Definition/Helper/DefinitionHelper.php new file mode 100644 index 0000000..327167e --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/Helper/DefinitionHelper.php @@ -0,0 +1,20 @@ + + */ +interface DefinitionHelper +{ + /** + * @param string $entryName Container entry name + */ + public function getDefinition(string $entryName) : Definition; +} diff --git a/api/vendor/php-di/php-di/src/Definition/Helper/FactoryDefinitionHelper.php b/api/vendor/php-di/php-di/src/Definition/Helper/FactoryDefinitionHelper.php new file mode 100644 index 0000000..85e1ba5 --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/Helper/FactoryDefinitionHelper.php @@ -0,0 +1,63 @@ + + */ +class FactoryDefinitionHelper implements DefinitionHelper +{ + /** + * @var callable + */ + private $factory; + + private bool $decorate; + + private array $parameters = []; + + /** + * @param bool $decorate Is the factory decorating a previous definition? + */ + public function __construct(callable|array|string $factory, bool $decorate = false) + { + $this->factory = $factory; + $this->decorate = $decorate; + } + + public function getDefinition(string $entryName) : FactoryDefinition + { + if ($this->decorate) { + return new DecoratorDefinition($entryName, $this->factory, $this->parameters); + } + + return new FactoryDefinition($entryName, $this->factory, $this->parameters); + } + + /** + * Defines arguments to pass to the factory. + * + * Because factory methods do not yet support attributes or autowiring, this method + * should be used to define all parameters except the ContainerInterface and RequestedEntry. + * + * Multiple calls can be made to the method to override individual values. + * + * @param string $parameter Name or index of the parameter for which the value will be given. + * @param mixed $value Value to give to this parameter. + * + * @return $this + */ + public function parameter(string $parameter, mixed $value) : self + { + $this->parameters[$parameter] = $value; + + return $this; + } +} diff --git a/api/vendor/php-di/php-di/src/Definition/InstanceDefinition.php b/api/vendor/php-di/php-di/src/Definition/InstanceDefinition.php new file mode 100644 index 0000000..51bf42e --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/InstanceDefinition.php @@ -0,0 +1,54 @@ + + */ +class InstanceDefinition implements Definition +{ + /** + * @param object $instance Instance on which to inject dependencies. + */ + public function __construct( + private object $instance, + private ObjectDefinition $objectDefinition, + ) { + } + + public function getName() : string + { + // Name are superfluous for instance definitions + return ''; + } + + public function setName(string $name) : void + { + // Name are superfluous for instance definitions + } + + public function getInstance() : object + { + return $this->instance; + } + + public function getObjectDefinition() : ObjectDefinition + { + return $this->objectDefinition; + } + + public function replaceNestedDefinitions(callable $replacer) : void + { + $this->objectDefinition->replaceNestedDefinitions($replacer); + } + + public function __toString() : string + { + return 'Instance'; + } +} diff --git a/api/vendor/php-di/php-di/src/Definition/ObjectDefinition.php b/api/vendor/php-di/php-di/src/Definition/ObjectDefinition.php new file mode 100644 index 0000000..bf571b4 --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/ObjectDefinition.php @@ -0,0 +1,242 @@ + + */ +class ObjectDefinition implements Definition +{ + /** + * Entry name (most of the time, same as $classname). + */ + private string $name; + + /** + * Class name (if null, then the class name is $name). + */ + protected ?string $className = null; + + protected ?MethodInjection $constructorInjection = null; + + protected array $propertyInjections = []; + + /** + * Method calls. + * @var MethodInjection[][] + */ + protected array $methodInjections = []; + + protected ?bool $lazy = null; + + /** + * Store if the class exists. Storing it (in cache) avoids recomputing this. + */ + private bool $classExists; + + /** + * Store if the class is instantiable. Storing it (in cache) avoids recomputing this. + */ + private bool $isInstantiable; + + /** + * @param string $name Entry name + */ + public function __construct(string $name, ?string $className = null) + { + $this->name = $name; + $this->setClassName($className); + } + + public function getName() : string + { + return $this->name; + } + + public function setName(string $name) : void + { + $this->name = $name; + } + + public function setClassName(?string $className) : void + { + $this->className = $className; + + $this->updateCache(); + } + + public function getClassName() : string + { + return $this->className ?? $this->name; + } + + public function getConstructorInjection() : ?MethodInjection + { + return $this->constructorInjection; + } + + public function setConstructorInjection(MethodInjection $constructorInjection) : void + { + $this->constructorInjection = $constructorInjection; + } + + public function completeConstructorInjection(MethodInjection $injection) : void + { + if ($this->constructorInjection !== null) { + // Merge + $this->constructorInjection->merge($injection); + } else { + // Set + $this->constructorInjection = $injection; + } + } + + /** + * @return PropertyInjection[] Property injections + */ + public function getPropertyInjections() : array + { + return $this->propertyInjections; + } + + public function addPropertyInjection(PropertyInjection $propertyInjection) : void + { + $className = $propertyInjection->getClassName(); + if ($className) { + // Index with the class name to avoid collisions between parent and + // child private properties with the same name + $key = $className . '::' . $propertyInjection->getPropertyName(); + } else { + $key = $propertyInjection->getPropertyName(); + } + + $this->propertyInjections[$key] = $propertyInjection; + } + + /** + * @return MethodInjection[] Method injections + */ + public function getMethodInjections() : array + { + // Return array leafs + $injections = []; + array_walk_recursive($this->methodInjections, function ($injection) use (&$injections) { + $injections[] = $injection; + }); + + return $injections; + } + + public function addMethodInjection(MethodInjection $methodInjection) : void + { + $method = $methodInjection->getMethodName(); + if (! isset($this->methodInjections[$method])) { + $this->methodInjections[$method] = []; + } + $this->methodInjections[$method][] = $methodInjection; + } + + public function completeFirstMethodInjection(MethodInjection $injection) : void + { + $method = $injection->getMethodName(); + + if (isset($this->methodInjections[$method][0])) { + // Merge + $this->methodInjections[$method][0]->merge($injection); + } else { + // Set + $this->addMethodInjection($injection); + } + } + + public function setLazy(?bool $lazy = null) : void + { + $this->lazy = $lazy; + } + + public function isLazy() : bool + { + if ($this->lazy !== null) { + return $this->lazy; + } + + // Default value + return false; + } + + public function classExists() : bool + { + return $this->classExists; + } + + public function isInstantiable() : bool + { + return $this->isInstantiable; + } + + public function replaceNestedDefinitions(callable $replacer) : void + { + array_walk($this->propertyInjections, function (PropertyInjection $propertyInjection) use ($replacer) { + $propertyInjection->replaceNestedDefinition($replacer); + }); + + $this->constructorInjection?->replaceNestedDefinitions($replacer); + + array_walk($this->methodInjections, function ($injectionArray) use ($replacer) { + array_walk($injectionArray, function (MethodInjection $methodInjection) use ($replacer) { + $methodInjection->replaceNestedDefinitions($replacer); + }); + }); + } + + /** + * Replaces all the wildcards in the string with the given replacements. + * + * @param string[] $replacements + */ + public function replaceWildcards(array $replacements) : void + { + $className = $this->getClassName(); + + foreach ($replacements as $replacement) { + $pos = strpos($className, DefinitionArray::WILDCARD); + if ($pos !== false) { + $className = substr_replace($className, $replacement, $pos, 1); + } + } + + $this->setClassName($className); + } + + public function __toString() : string + { + return (new ObjectDefinitionDumper)->dump($this); + } + + private function updateCache() : void + { + $className = $this->getClassName(); + + $this->classExists = class_exists($className) || interface_exists($className); + + if (! $this->classExists) { + $this->isInstantiable = false; + + return; + } + + /** @var class-string $className */ + $class = new ReflectionClass($className); + $this->isInstantiable = $class->isInstantiable(); + } +} diff --git a/api/vendor/php-di/php-di/src/Definition/ObjectDefinition/MethodInjection.php b/api/vendor/php-di/php-di/src/Definition/ObjectDefinition/MethodInjection.php new file mode 100644 index 0000000..72b8b5c --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/ObjectDefinition/MethodInjection.php @@ -0,0 +1,76 @@ + + */ +class MethodInjection implements Definition +{ + /** + * @param mixed[] $parameters + */ + public function __construct( + private string $methodName, + private array $parameters = [], + ) { + } + + public static function constructor(array $parameters = []) : self + { + return new self('__construct', $parameters); + } + + public function getMethodName() : string + { + return $this->methodName; + } + + /** + * @return mixed[] + */ + public function getParameters() : array + { + return $this->parameters; + } + + /** + * Replace the parameters of the definition by a new array of parameters. + */ + public function replaceParameters(array $parameters) : void + { + $this->parameters = $parameters; + } + + public function merge(self $definition) : void + { + // In case of conflicts, the current definition prevails. + $this->parameters += $definition->parameters; + } + + public function getName() : string + { + return ''; + } + + public function setName(string $name) : void + { + // The name does not matter for method injections + } + + public function replaceNestedDefinitions(callable $replacer) : void + { + $this->parameters = array_map($replacer, $this->parameters); + } + + public function __toString() : string + { + return sprintf('method(%s)', $this->methodName); + } +} diff --git a/api/vendor/php-di/php-di/src/Definition/ObjectDefinition/PropertyInjection.php b/api/vendor/php-di/php-di/src/Definition/ObjectDefinition/PropertyInjection.php new file mode 100644 index 0000000..9457986 --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/ObjectDefinition/PropertyInjection.php @@ -0,0 +1,61 @@ + + */ +class PropertyInjection +{ + private string $propertyName; + + /** + * Value that should be injected in the property. + */ + private mixed $value; + + /** + * Use for injecting in properties of parent classes: the class name + * must be the name of the parent class because private properties + * can be attached to the parent classes, not the one we are resolving. + */ + private ?string $className; + + /** + * @param string $propertyName Property name + * @param mixed $value Value that should be injected in the property + */ + public function __construct(string $propertyName, mixed $value, ?string $className = null) + { + $this->propertyName = $propertyName; + $this->value = $value; + $this->className = $className; + } + + public function getPropertyName() : string + { + return $this->propertyName; + } + + /** + * @return mixed Value that should be injected in the property + */ + public function getValue() : mixed + { + return $this->value; + } + + public function getClassName() : ?string + { + return $this->className; + } + + public function replaceNestedDefinition(callable $replacer) : void + { + $this->value = $replacer($this->value); + } +} diff --git a/api/vendor/php-di/php-di/src/Definition/Reference.php b/api/vendor/php-di/php-di/src/Definition/Reference.php new file mode 100644 index 0000000..839e7aa --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/Reference.php @@ -0,0 +1,64 @@ + + */ +class Reference implements Definition, SelfResolvingDefinition +{ + /** Entry name. */ + private string $name = ''; + + /** + * @param string $targetEntryName Name of the target entry + */ + public function __construct( + private string $targetEntryName, + ) { + } + + public function getName() : string + { + return $this->name; + } + + public function setName(string $name) : void + { + $this->name = $name; + } + + public function getTargetEntryName() : string + { + return $this->targetEntryName; + } + + public function resolve(ContainerInterface $container) : mixed + { + return $container->get($this->getTargetEntryName()); + } + + public function isResolvable(ContainerInterface $container) : bool + { + return $container->has($this->getTargetEntryName()); + } + + public function replaceNestedDefinitions(callable $replacer) : void + { + // no nested definitions + } + + public function __toString() : string + { + return sprintf( + 'get(%s)', + $this->targetEntryName + ); + } +} diff --git a/api/vendor/php-di/php-di/src/Definition/Resolver/ArrayResolver.php b/api/vendor/php-di/php-di/src/Definition/Resolver/ArrayResolver.php new file mode 100644 index 0000000..2c6a1c3 --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/Resolver/ArrayResolver.php @@ -0,0 +1,76 @@ + + * + * @since 5.0 + * @author Matthieu Napoli + */ +class ArrayResolver implements DefinitionResolver +{ + /** + * @param DefinitionResolver $definitionResolver Used to resolve nested definitions. + */ + public function __construct( + private DefinitionResolver $definitionResolver, + ) { + } + + /** + * {@inheritDoc} + * + * Resolve an array definition to a value. + * + * An array definition can contain simple values or references to other entries. + * + * @param ArrayDefinition $definition + */ + public function resolve(Definition $definition, array $parameters = []) : array + { + $values = $definition->getValues(); + + // Resolve nested definitions + array_walk_recursive($values, function (& $value, $key) use ($definition) { + if ($value instanceof Definition) { + $value = $this->resolveDefinition($value, $definition, $key); + } + }); + + return $values; + } + + public function isResolvable(Definition $definition, array $parameters = []) : bool + { + return true; + } + + /** + * @throws DependencyException + */ + private function resolveDefinition(Definition $value, ArrayDefinition $definition, int|string $key) : mixed + { + try { + return $this->definitionResolver->resolve($value); + } catch (DependencyException $e) { + throw $e; + } catch (Exception $e) { + throw new DependencyException(sprintf( + 'Error while resolving %s[%s]. %s', + $definition->getName(), + $key, + $e->getMessage() + ), 0, $e); + } + } +} diff --git a/api/vendor/php-di/php-di/src/Definition/Resolver/DecoratorResolver.php b/api/vendor/php-di/php-di/src/Definition/Resolver/DecoratorResolver.php new file mode 100644 index 0000000..945f6be --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/Resolver/DecoratorResolver.php @@ -0,0 +1,74 @@ + + * + * @since 5.0 + * @author Matthieu Napoli + */ +class DecoratorResolver implements DefinitionResolver +{ + /** + * The resolver needs a container. This container will be passed to the factory as a parameter + * so that the factory can access other entries of the container. + * + * @param DefinitionResolver $definitionResolver Used to resolve nested definitions. + */ + public function __construct( + private ContainerInterface $container, + private DefinitionResolver $definitionResolver, + ) { + } + + /** + * Resolve a decorator definition to a value. + * + * This will call the callable of the definition and pass it the decorated entry. + * + * @param DecoratorDefinition $definition + */ + public function resolve(Definition $definition, array $parameters = []) : mixed + { + $callable = $definition->getCallable(); + + if (! is_callable($callable)) { + throw new InvalidDefinition(sprintf( + 'The decorator "%s" is not callable', + $definition->getName() + )); + } + + $decoratedDefinition = $definition->getDecoratedDefinition(); + + if (! $decoratedDefinition instanceof Definition) { + if (! $definition->getName()) { + throw new InvalidDefinition('Decorators cannot be nested in another definition'); + } + + throw new InvalidDefinition(sprintf( + 'Entry "%s" decorates nothing: no previous definition with the same name was found', + $definition->getName() + )); + } + + $decorated = $this->definitionResolver->resolve($decoratedDefinition, $parameters); + + return $callable($decorated, $this->container); + } + + public function isResolvable(Definition $definition, array $parameters = []) : bool + { + return true; + } +} diff --git a/api/vendor/php-di/php-di/src/Definition/Resolver/DefinitionResolver.php b/api/vendor/php-di/php-di/src/Definition/Resolver/DefinitionResolver.php new file mode 100644 index 0000000..54d50bd --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/Resolver/DefinitionResolver.php @@ -0,0 +1,42 @@ + + * + * @template T of Definition + */ +interface DefinitionResolver +{ + /** + * Resolve a definition to a value. + * + * @param Definition $definition Object that defines how the value should be obtained. + * @psalm-param T $definition + * @param array $parameters Optional parameters to use to build the entry. + * @return mixed Value obtained from the definition. + * + * @throws InvalidDefinition If the definition cannot be resolved. + * @throws DependencyException + */ + public function resolve(Definition $definition, array $parameters = []) : mixed; + + /** + * Check if a definition can be resolved. + * + * @param Definition $definition Object that defines how the value should be obtained. + * @psalm-param T $definition + * @param array $parameters Optional parameters to use to build the entry. + */ + public function isResolvable(Definition $definition, array $parameters = []) : bool; +} diff --git a/api/vendor/php-di/php-di/src/Definition/Resolver/EnvironmentVariableResolver.php b/api/vendor/php-di/php-di/src/Definition/Resolver/EnvironmentVariableResolver.php new file mode 100644 index 0000000..e328bf3 --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/Resolver/EnvironmentVariableResolver.php @@ -0,0 +1,69 @@ + + * + * @author James Harris + */ +class EnvironmentVariableResolver implements DefinitionResolver +{ + /** @var callable */ + private $variableReader; + + public function __construct( + private DefinitionResolver $definitionResolver, + $variableReader = null, + ) { + $this->variableReader = $variableReader ?? [$this, 'getEnvVariable']; + } + + /** + * Resolve an environment variable definition to a value. + * + * @param EnvironmentVariableDefinition $definition + */ + public function resolve(Definition $definition, array $parameters = []) : mixed + { + $value = call_user_func($this->variableReader, $definition->getVariableName()); + + if (false !== $value) { + return $value; + } + + if (!$definition->isOptional()) { + throw new InvalidDefinition(sprintf( + "The environment variable '%s' has not been defined", + $definition->getVariableName() + )); + } + + $value = $definition->getDefaultValue(); + + // Nested definition + if ($value instanceof Definition) { + return $this->definitionResolver->resolve($value); + } + + return $value; + } + + public function isResolvable(Definition $definition, array $parameters = []) : bool + { + return true; + } + + protected function getEnvVariable(string $variableName) + { + return $_ENV[$variableName] ?? $_SERVER[$variableName] ?? getenv($variableName); + } +} diff --git a/api/vendor/php-di/php-di/src/Definition/Resolver/FactoryResolver.php b/api/vendor/php-di/php-di/src/Definition/Resolver/FactoryResolver.php new file mode 100644 index 0000000..d08bc5d --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/Resolver/FactoryResolver.php @@ -0,0 +1,112 @@ + + * + * @since 4.0 + * @author Matthieu Napoli + */ +class FactoryResolver implements DefinitionResolver +{ + private ?Invoker $invoker = null; + + /** + * The resolver needs a container. This container will be passed to the factory as a parameter + * so that the factory can access other entries of the container. + */ + public function __construct( + private ContainerInterface $container, + private DefinitionResolver $resolver, + ) { + } + + /** + * Resolve a factory definition to a value. + * + * This will call the callable of the definition. + * + * @param FactoryDefinition $definition + */ + public function resolve(Definition $definition, array $parameters = []) : mixed + { + if (! $this->invoker) { + $parameterResolver = new ResolverChain([ + new AssociativeArrayResolver, + new FactoryParameterResolver($this->container), + new NumericArrayResolver, + new DefaultValueResolver, + ]); + + $this->invoker = new Invoker($parameterResolver, $this->container); + } + + $callable = $definition->getCallable(); + + try { + $providedParams = [$this->container, $definition]; + $extraParams = $this->resolveExtraParams($definition->getParameters()); + $providedParams = array_merge($providedParams, $extraParams, $parameters); + + return $this->invoker->call($callable, $providedParams); + } catch (NotCallableException $e) { + // Custom error message to help debugging + if (is_string($callable) && class_exists($callable) && method_exists($callable, '__invoke')) { + throw new InvalidDefinition(sprintf( + 'Entry "%s" cannot be resolved: factory %s. Invokable classes cannot be automatically resolved if autowiring is disabled on the container, you need to enable autowiring or define the entry manually.', + $definition->getName(), + $e->getMessage() + )); + } + + throw new InvalidDefinition(sprintf( + 'Entry "%s" cannot be resolved: factory %s', + $definition->getName(), + $e->getMessage() + )); + } catch (NotEnoughParametersException $e) { + throw new InvalidDefinition(sprintf( + 'Entry "%s" cannot be resolved: %s', + $definition->getName(), + $e->getMessage() + )); + } + } + + public function isResolvable(Definition $definition, array $parameters = []) : bool + { + return true; + } + + private function resolveExtraParams(array $params) : array + { + $resolved = []; + foreach ($params as $key => $value) { + // Nested definitions + if ($value instanceof Definition) { + $value = $this->resolver->resolve($value); + } + $resolved[$key] = $value; + } + + return $resolved; + } +} diff --git a/api/vendor/php-di/php-di/src/Definition/Resolver/InstanceInjector.php b/api/vendor/php-di/php-di/src/Definition/Resolver/InstanceInjector.php new file mode 100644 index 0000000..81c3f63 --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/Resolver/InstanceInjector.php @@ -0,0 +1,50 @@ + + * + * @since 5.0 + * @author Matthieu Napoli + */ +class InstanceInjector extends ObjectCreator implements DefinitionResolver +{ + /** + * Injects dependencies on an existing instance. + * + * @param InstanceDefinition $definition + * @psalm-suppress ImplementedParamTypeMismatch + */ + public function resolve(Definition $definition, array $parameters = []) : ?object + { + /** @psalm-suppress InvalidCatch */ + try { + $this->injectMethodsAndProperties($definition->getInstance(), $definition->getObjectDefinition()); + } catch (NotFoundExceptionInterface $e) { + $message = sprintf( + 'Error while injecting dependencies into %s: %s', + get_class($definition->getInstance()), + $e->getMessage() + ); + + throw new DependencyException($message, 0, $e); + } + + return $definition; + } + + public function isResolvable(Definition $definition, array $parameters = []) : bool + { + return true; + } +} diff --git a/api/vendor/php-di/php-di/src/Definition/Resolver/ObjectCreator.php b/api/vendor/php-di/php-di/src/Definition/Resolver/ObjectCreator.php new file mode 100644 index 0000000..3d4738c --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/Resolver/ObjectCreator.php @@ -0,0 +1,203 @@ + + * + * @since 4.0 + * @author Matthieu Napoli + */ +class ObjectCreator implements DefinitionResolver +{ + private ParameterResolver $parameterResolver; + + /** + * @param DefinitionResolver $definitionResolver Used to resolve nested definitions. + * @param ProxyFactoryInterface $proxyFactory Used to create proxies for lazy injections. + */ + public function __construct( + private DefinitionResolver $definitionResolver, + private ProxyFactoryInterface $proxyFactory, + ) { + $this->parameterResolver = new ParameterResolver($definitionResolver); + } + + /** + * Resolve a class definition to a value. + * + * This will create a new instance of the class using the injections points defined. + * + * @param ObjectDefinition $definition + */ + public function resolve(Definition $definition, array $parameters = []) : ?object + { + // Lazy? + if ($definition->isLazy()) { + return $this->createProxy($definition, $parameters); + } + + return $this->createInstance($definition, $parameters); + } + + /** + * The definition is not resolvable if the class is not instantiable (interface or abstract) + * or if the class doesn't exist. + * + * @param ObjectDefinition $definition + */ + public function isResolvable(Definition $definition, array $parameters = []) : bool + { + return $definition->isInstantiable(); + } + + /** + * Returns a proxy instance. + */ + private function createProxy(ObjectDefinition $definition, array $parameters) : object + { + /** @var class-string $className */ + $className = $definition->getClassName(); + + return $this->proxyFactory->createProxy( + $className, + function () use ($definition, $parameters) { + return $this->createInstance($definition, $parameters); + } + ); + } + + /** + * Creates an instance of the class and injects dependencies.. + * + * @param array $parameters Optional parameters to use to create the instance. + * + * @throws DependencyException + * @throws InvalidDefinition + */ + private function createInstance(ObjectDefinition $definition, array $parameters) : object + { + // Check that the class is instantiable + if (! $definition->isInstantiable()) { + // Check that the class exists + if (! $definition->classExists()) { + throw InvalidDefinition::create($definition, sprintf( + 'Entry "%s" cannot be resolved: the class doesn\'t exist', + $definition->getName() + )); + } + + throw InvalidDefinition::create($definition, sprintf( + 'Entry "%s" cannot be resolved: the class is not instantiable', + $definition->getName() + )); + } + + /** @psalm-var class-string $classname */ + $classname = $definition->getClassName(); + $classReflection = new ReflectionClass($classname); + + $constructorInjection = $definition->getConstructorInjection(); + + /** @psalm-suppress InvalidCatch */ + try { + $args = $this->parameterResolver->resolveParameters( + $constructorInjection, + $classReflection->getConstructor(), + $parameters + ); + + $object = new $classname(...$args); + + $this->injectMethodsAndProperties($object, $definition); + } catch (NotFoundExceptionInterface $e) { + throw new DependencyException(sprintf( + 'Error while injecting dependencies into %s: %s', + $classReflection->getName(), + $e->getMessage() + ), 0, $e); + } catch (InvalidDefinition $e) { + throw InvalidDefinition::create($definition, sprintf( + 'Entry "%s" cannot be resolved: %s', + $definition->getName(), + $e->getMessage() + )); + } + + return $object; + } + + protected function injectMethodsAndProperties(object $object, ObjectDefinition $objectDefinition) : void + { + // Property injections + foreach ($objectDefinition->getPropertyInjections() as $propertyInjection) { + $this->injectProperty($object, $propertyInjection); + } + + // Method injections + foreach ($objectDefinition->getMethodInjections() as $methodInjection) { + $methodReflection = new \ReflectionMethod($object, $methodInjection->getMethodName()); + $args = $this->parameterResolver->resolveParameters($methodInjection, $methodReflection); + + $methodReflection->invokeArgs($object, $args); + } + } + + /** + * Inject dependencies into properties. + * + * @param object $object Object to inject dependencies into + * @param PropertyInjection $propertyInjection Property injection definition + * + * @throws DependencyException + */ + private function injectProperty(object $object, PropertyInjection $propertyInjection) : void + { + $propertyName = $propertyInjection->getPropertyName(); + + $value = $propertyInjection->getValue(); + + if ($value instanceof Definition) { + try { + $value = $this->definitionResolver->resolve($value); + } catch (DependencyException $e) { + throw $e; + } catch (Exception $e) { + throw new DependencyException(sprintf( + 'Error while injecting in %s::%s. %s', + $object::class, + $propertyName, + $e->getMessage() + ), 0, $e); + } + } + + self::setPrivatePropertyValue($propertyInjection->getClassName(), $object, $propertyName, $value); + } + + public static function setPrivatePropertyValue(?string $className, $object, string $propertyName, mixed $propertyValue) : void + { + $className = $className ?: $object::class; + + $property = new ReflectionProperty($className, $propertyName); + if (! $property->isPublic() && \PHP_VERSION_ID < 80100) { + $property->setAccessible(true); + } + $property->setValue($object, $propertyValue); + } +} diff --git a/api/vendor/php-di/php-di/src/Definition/Resolver/ParameterResolver.php b/api/vendor/php-di/php-di/src/Definition/Resolver/ParameterResolver.php new file mode 100644 index 0000000..2f46d1f --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/Resolver/ParameterResolver.php @@ -0,0 +1,106 @@ + + */ +class ParameterResolver +{ + /** + * @param DefinitionResolver $definitionResolver Will be used to resolve nested definitions. + */ + public function __construct( + private DefinitionResolver $definitionResolver, + ) { + } + + /** + * @return array Parameters to use to call the function. + * @throws InvalidDefinition A parameter has no value defined or guessable. + */ + public function resolveParameters( + ?MethodInjection $definition = null, + ?ReflectionMethod $method = null, + array $parameters = [], + ) : array { + $args = []; + + if (! $method) { + return $args; + } + + $definitionParameters = $definition ? $definition->getParameters() : []; + + foreach ($method->getParameters() as $index => $parameter) { + if (array_key_exists($parameter->getName(), $parameters)) { + // Look in the $parameters array + $value = &$parameters[$parameter->getName()]; + } elseif (array_key_exists($index, $definitionParameters)) { + // Look in the definition + $value = &$definitionParameters[$index]; + } else { + // If the parameter is optional and wasn't specified, we take its default value + if ($parameter->isDefaultValueAvailable() || $parameter->isOptional()) { + $args[] = $this->getParameterDefaultValue($parameter, $method); + continue; + } + + throw new InvalidDefinition(sprintf( + 'Parameter $%s of %s has no value defined or guessable', + $parameter->getName(), + $this->getFunctionName($method) + )); + } + + // Nested definitions + if ($value instanceof Definition) { + // If the container cannot produce the entry, we can use the default parameter value + if ($parameter->isOptional() && ! $this->definitionResolver->isResolvable($value)) { + $value = $this->getParameterDefaultValue($parameter, $method); + } else { + $value = $this->definitionResolver->resolve($value); + } + } + + $args[] = &$value; + } + + return $args; + } + + /** + * Returns the default value of a function parameter. + * + * @throws InvalidDefinition Can't get default values from PHP internal classes and functions + */ + private function getParameterDefaultValue(ReflectionParameter $parameter, ReflectionMethod $function) : mixed + { + try { + return $parameter->getDefaultValue(); + } catch (\ReflectionException) { + throw new InvalidDefinition(sprintf( + 'The parameter "%s" of %s has no type defined or guessable. It has a default value, ' + . 'but the default value can\'t be read through Reflection because it is a PHP internal class.', + $parameter->getName(), + $this->getFunctionName($function) + )); + } + } + + private function getFunctionName(ReflectionMethod $method) : string + { + return $method->getName() . '()'; + } +} diff --git a/api/vendor/php-di/php-di/src/Definition/Resolver/ResolverDispatcher.php b/api/vendor/php-di/php-di/src/Definition/Resolver/ResolverDispatcher.php new file mode 100644 index 0000000..70e2bfc --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/Resolver/ResolverDispatcher.php @@ -0,0 +1,125 @@ + + * + * @psalm-suppress MissingTemplateParam + */ +class ResolverDispatcher implements DefinitionResolver +{ + private ?ArrayResolver $arrayResolver = null; + private ?FactoryResolver $factoryResolver = null; + private ?DecoratorResolver $decoratorResolver = null; + private ?ObjectCreator $objectResolver = null; + private ?InstanceInjector $instanceResolver = null; + private ?EnvironmentVariableResolver $envVariableResolver = null; + + public function __construct( + private ContainerInterface $container, + private ProxyFactoryInterface $proxyFactory, + ) { + } + + /** + * Resolve a definition to a value. + * + * @param Definition $definition Object that defines how the value should be obtained. + * @param array $parameters Optional parameters to use to build the entry. + * + * @return mixed Value obtained from the definition. + * @throws InvalidDefinition If the definition cannot be resolved. + */ + public function resolve(Definition $definition, array $parameters = []) : mixed + { + // Special case, tested early for speed + if ($definition instanceof SelfResolvingDefinition) { + return $definition->resolve($this->container); + } + + $definitionResolver = $this->getDefinitionResolver($definition); + + return $definitionResolver->resolve($definition, $parameters); + } + + public function isResolvable(Definition $definition, array $parameters = []) : bool + { + // Special case, tested early for speed + if ($definition instanceof SelfResolvingDefinition) { + return $definition->isResolvable($this->container); + } + + $definitionResolver = $this->getDefinitionResolver($definition); + + return $definitionResolver->isResolvable($definition, $parameters); + } + + /** + * Returns a resolver capable of handling the given definition. + * + * @throws \RuntimeException No definition resolver was found for this type of definition. + */ + private function getDefinitionResolver(Definition $definition) : DefinitionResolver + { + switch (true) { + case $definition instanceof ObjectDefinition: + if (! $this->objectResolver) { + $this->objectResolver = new ObjectCreator($this, $this->proxyFactory); + } + + return $this->objectResolver; + case $definition instanceof DecoratorDefinition: + if (! $this->decoratorResolver) { + $this->decoratorResolver = new DecoratorResolver($this->container, $this); + } + + return $this->decoratorResolver; + case $definition instanceof FactoryDefinition: + if (! $this->factoryResolver) { + $this->factoryResolver = new FactoryResolver($this->container, $this); + } + + return $this->factoryResolver; + case $definition instanceof ArrayDefinition: + if (! $this->arrayResolver) { + $this->arrayResolver = new ArrayResolver($this); + } + + return $this->arrayResolver; + case $definition instanceof EnvironmentVariableDefinition: + if (! $this->envVariableResolver) { + $this->envVariableResolver = new EnvironmentVariableResolver($this); + } + + return $this->envVariableResolver; + case $definition instanceof InstanceDefinition: + if (! $this->instanceResolver) { + $this->instanceResolver = new InstanceInjector($this, $this->proxyFactory); + } + + return $this->instanceResolver; + default: + throw new \RuntimeException('No definition resolver was configured for definition of type ' . $definition::class); + } + } +} diff --git a/api/vendor/php-di/php-di/src/Definition/SelfResolvingDefinition.php b/api/vendor/php-di/php-di/src/Definition/SelfResolvingDefinition.php new file mode 100644 index 0000000..be2f274 --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/SelfResolvingDefinition.php @@ -0,0 +1,25 @@ + + */ +interface SelfResolvingDefinition +{ + /** + * Resolve the definition and return the resulting value. + */ + public function resolve(ContainerInterface $container) : mixed; + + /** + * Check if a definition can be resolved. + */ + public function isResolvable(ContainerInterface $container) : bool; +} diff --git a/api/vendor/php-di/php-di/src/Definition/Source/AttributeBasedAutowiring.php b/api/vendor/php-di/php-di/src/Definition/Source/AttributeBasedAutowiring.php new file mode 100644 index 0000000..7ef5ca9 --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/Source/AttributeBasedAutowiring.php @@ -0,0 +1,263 @@ + + */ +class AttributeBasedAutowiring implements DefinitionSource, Autowiring +{ + /** + * @throws InvalidAttribute + */ + public function autowire(string $name, ?ObjectDefinition $definition = null) : ?ObjectDefinition + { + $className = $definition ? $definition->getClassName() : $name; + + if (!class_exists($className) && !interface_exists($className)) { + return $definition; + } + + $definition = $definition ?: new ObjectDefinition($name); + + $class = new ReflectionClass($className); + + $this->readInjectableAttribute($class, $definition); + + // Browse the class properties looking for annotated properties + $this->readProperties($class, $definition); + + // Browse the object's methods looking for annotated methods + $this->readMethods($class, $definition); + + return $definition; + } + + /** + * @throws InvalidAttribute + * @throws InvalidArgumentException The class doesn't exist + */ + public function getDefinition(string $name) : ?ObjectDefinition + { + return $this->autowire($name); + } + + /** + * Autowiring cannot guess all existing definitions. + */ + public function getDefinitions() : array + { + return []; + } + + /** + * Browse the class properties looking for annotated properties. + */ + private function readProperties(ReflectionClass $class, ObjectDefinition $definition) : void + { + foreach ($class->getProperties() as $property) { + $this->readProperty($property, $definition); + } + + // Read also the *private* properties of the parent classes + /** @noinspection PhpAssignmentInConditionInspection */ + while ($class = $class->getParentClass()) { + foreach ($class->getProperties(ReflectionProperty::IS_PRIVATE) as $property) { + $this->readProperty($property, $definition, $class->getName()); + } + } + } + + /** + * @throws InvalidAttribute + */ + private function readProperty(ReflectionProperty $property, ObjectDefinition $definition, ?string $classname = null) : void + { + if ($property->isStatic() || $property->isPromoted()) { + return; + } + + // Look for #[Inject] attribute + try { + $attribute = $property->getAttributes(Inject::class)[0] ?? null; + if (! $attribute) { + return; + } + /** @var Inject $inject */ + $inject = $attribute->newInstance(); + } catch (Throwable $e) { + throw new InvalidAttribute(sprintf( + '#[Inject] annotation on property %s::%s is malformed. %s', + $property->getDeclaringClass()->getName(), + $property->getName(), + $e->getMessage() + ), 0, $e); + } + + // Try to #[Inject("name")] or look for the property type + $entryName = $inject->getName(); + + // Try using typed properties + $propertyType = $property->getType(); + if ($entryName === null && $propertyType instanceof ReflectionNamedType) { + if (! class_exists($propertyType->getName()) && ! interface_exists($propertyType->getName())) { + throw new InvalidAttribute(sprintf( + '#[Inject] found on property %s::%s but unable to guess what to inject, the type of the property does not look like a valid class or interface name', + $property->getDeclaringClass()->getName(), + $property->getName() + )); + } + $entryName = $propertyType->getName(); + } + + if ($entryName === null) { + throw new InvalidAttribute(sprintf( + '#[Inject] found on property %s::%s but unable to guess what to inject, please add a type to the property', + $property->getDeclaringClass()->getName(), + $property->getName() + )); + } + + $definition->addPropertyInjection( + new PropertyInjection($property->getName(), new Reference($entryName), $classname) + ); + } + + /** + * Browse the object's methods looking for annotated methods. + */ + private function readMethods(ReflectionClass $class, ObjectDefinition $objectDefinition) : void + { + // This will look in all the methods, including those of the parent classes + foreach ($class->getMethods(ReflectionMethod::IS_PUBLIC) as $method) { + if ($method->isStatic()) { + continue; + } + + $methodInjection = $this->getMethodInjection($method); + + if (! $methodInjection) { + continue; + } + + if ($method->isConstructor()) { + $objectDefinition->completeConstructorInjection($methodInjection); + } else { + $objectDefinition->completeFirstMethodInjection($methodInjection); + } + } + } + + private function getMethodInjection(ReflectionMethod $method) : ?MethodInjection + { + // Look for #[Inject] attribute + $attribute = $method->getAttributes(Inject::class)[0] ?? null; + + if ($attribute) { + /** @var Inject $inject */ + $inject = $attribute->newInstance(); + $annotationParameters = $inject->getParameters(); + } elseif ($method->isConstructor()) { + // #[Inject] on constructor is implicit, we continue + $annotationParameters = []; + } else { + return null; + } + + $parameters = []; + foreach ($method->getParameters() as $index => $parameter) { + $entryName = $this->getMethodParameter($index, $parameter, $annotationParameters); + + if ($entryName !== null) { + $parameters[$index] = new Reference($entryName); + } + } + + if ($method->isConstructor()) { + return MethodInjection::constructor($parameters); + } + + return new MethodInjection($method->getName(), $parameters); + } + + /** + * @return string|null Entry name or null if not found. + */ + private function getMethodParameter(int $parameterIndex, ReflectionParameter $parameter, array $annotationParameters) : ?string + { + // Let's check if this parameter has an #[Inject] attribute + $attribute = $parameter->getAttributes(Inject::class)[0] ?? null; + if ($attribute) { + /** @var Inject $inject */ + $inject = $attribute->newInstance(); + + return $inject->getName(); + } + + // #[Inject] has definition for this parameter (by index, or by name) + if (isset($annotationParameters[$parameterIndex])) { + return $annotationParameters[$parameterIndex]; + } + if (isset($annotationParameters[$parameter->getName()])) { + return $annotationParameters[$parameter->getName()]; + } + + // Skip optional parameters if not explicitly defined + if ($parameter->isOptional()) { + return null; + } + + // Look for the property type + $parameterType = $parameter->getType(); + if ($parameterType instanceof ReflectionNamedType && !$parameterType->isBuiltin()) { + return $parameterType->getName(); + } + + return null; + } + + /** + * @throws InvalidAttribute + */ + private function readInjectableAttribute(ReflectionClass $class, ObjectDefinition $definition) : void + { + try { + $attribute = $class->getAttributes(Injectable::class)[0] ?? null; + if (! $attribute) { + return; + } + $attribute = $attribute->newInstance(); + } catch (Throwable $e) { + throw new InvalidAttribute(sprintf( + 'Error while reading #[Injectable] on %s: %s', + $class->getName(), + $e->getMessage() + ), 0, $e); + } + + if ($attribute->isLazy() !== null) { + $definition->setLazy($attribute->isLazy()); + } + } +} diff --git a/api/vendor/php-di/php-di/src/Definition/Source/Autowiring.php b/api/vendor/php-di/php-di/src/Definition/Source/Autowiring.php new file mode 100644 index 0000000..e5392f3 --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/Source/Autowiring.php @@ -0,0 +1,23 @@ + + */ +interface Autowiring +{ + /** + * Autowire the given definition. + * + * @throws InvalidDefinition An invalid definition was found. + */ + public function autowire(string $name, ?ObjectDefinition $definition = null) : ?ObjectDefinition; +} diff --git a/api/vendor/php-di/php-di/src/Definition/Source/DefinitionArray.php b/api/vendor/php-di/php-di/src/Definition/Source/DefinitionArray.php new file mode 100644 index 0000000..150f2b7 --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/Source/DefinitionArray.php @@ -0,0 +1,112 @@ + + */ +class DefinitionArray implements DefinitionSource, MutableDefinitionSource +{ + public const WILDCARD = '*'; + /** + * Matches anything except "\". + */ + private const WILDCARD_PATTERN = '([^\\\\]+)'; + + /** DI definitions in a PHP array. */ + private array $definitions; + + /** Cache of wildcard definitions. */ + private ?array $wildcardDefinitions = null; + + private DefinitionNormalizer $normalizer; + + public function __construct(array $definitions = [], ?Autowiring $autowiring = null) + { + if (isset($definitions[0])) { + throw new \Exception('The PHP-DI definition is not indexed by an entry name in the definition array'); + } + + $this->definitions = $definitions; + + $this->normalizer = new DefinitionNormalizer($autowiring ?: new NoAutowiring); + } + + /** + * @param array $definitions DI definitions in a PHP array indexed by the definition name. + */ + public function addDefinitions(array $definitions) : void + { + if (isset($definitions[0])) { + throw new \Exception('The PHP-DI definition is not indexed by an entry name in the definition array'); + } + + // The newly added data prevails + // "for keys that exist in both arrays, the elements from the left-hand array will be used" + $this->definitions = $definitions + $this->definitions; + + // Clear cache + $this->wildcardDefinitions = null; + } + + public function addDefinition(Definition $definition) : void + { + $this->definitions[$definition->getName()] = $definition; + + // Clear cache + $this->wildcardDefinitions = null; + } + + public function getDefinition(string $name) : ?Definition + { + // Look for the definition by name + if (array_key_exists($name, $this->definitions)) { + $definition = $this->definitions[$name]; + + return $this->normalizer->normalizeRootDefinition($definition, $name); + } + + // Build the cache of wildcard definitions + if ($this->wildcardDefinitions === null) { + $this->wildcardDefinitions = []; + foreach ($this->definitions as $key => $definition) { + if (str_contains($key, self::WILDCARD)) { + $this->wildcardDefinitions[$key] = $definition; + } + } + } + + // Look in wildcards definitions + foreach ($this->wildcardDefinitions as $key => $definition) { + // Turn the pattern into a regex + $key = preg_quote($key, '#'); + $key = '#^' . str_replace('\\' . self::WILDCARD, self::WILDCARD_PATTERN, $key) . '#'; + if (preg_match($key, $name, $matches) === 1) { + array_shift($matches); + + return $this->normalizer->normalizeRootDefinition($definition, $name, $matches); + } + } + + return null; + } + + public function getDefinitions() : array + { + // Return all definitions except wildcard definitions + $definitions = []; + foreach ($this->definitions as $key => $definition) { + if (! str_contains($key, self::WILDCARD)) { + $definitions[$key] = $definition; + } + } + + return $definitions; + } +} diff --git a/api/vendor/php-di/php-di/src/Definition/Source/DefinitionFile.php b/api/vendor/php-di/php-di/src/Definition/Source/DefinitionFile.php new file mode 100644 index 0000000..99e4d8a --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/Source/DefinitionFile.php @@ -0,0 +1,62 @@ + + */ +class DefinitionFile extends DefinitionArray +{ + private bool $initialized = false; + + /** + * @param string $file File in which the definitions are returned as an array. + */ + public function __construct( + private string $file, + ?Autowiring $autowiring = null, + ) { + // Lazy-loading to improve performances + parent::__construct([], $autowiring); + } + + public function getDefinition(string $name) : ?Definition + { + $this->initialize(); + + return parent::getDefinition($name); + } + + public function getDefinitions() : array + { + $this->initialize(); + + return parent::getDefinitions(); + } + + /** + * Lazy-loading of the definitions. + */ + private function initialize() : void + { + if ($this->initialized === true) { + return; + } + + $definitions = require $this->file; + + if (! is_array($definitions)) { + throw new \Exception("File $this->file should return an array of definitions"); + } + + $this->addDefinitions($definitions); + + $this->initialized = true; + } +} diff --git a/api/vendor/php-di/php-di/src/Definition/Source/DefinitionNormalizer.php b/api/vendor/php-di/php-di/src/Definition/Source/DefinitionNormalizer.php new file mode 100644 index 0000000..8f89095 --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/Source/DefinitionNormalizer.php @@ -0,0 +1,112 @@ + + */ +class DefinitionNormalizer +{ + public function __construct( + private Autowiring $autowiring, + ) { + } + + /** + * Normalize a definition that is *not* nested in another one. + * + * This is usually a definition declared at the root of a definition array. + * + * @param string $name The definition name. + * @param string[] $wildcardsReplacements Replacements for wildcard definitions. + * + * @throws InvalidDefinition + */ + public function normalizeRootDefinition(mixed $definition, string $name, ?array $wildcardsReplacements = null) : Definition + { + if ($definition instanceof DefinitionHelper) { + $definition = $definition->getDefinition($name); + } elseif (is_array($definition)) { + $definition = new ArrayDefinition($definition); + } elseif ($definition instanceof \Closure) { + $definition = new FactoryDefinition($name, $definition); + } elseif (! $definition instanceof Definition) { + $definition = new ValueDefinition($definition); + } + + // For a class definition, we replace * in the class name with the matches + // *Interface -> *Impl => FooInterface -> FooImpl + if ($wildcardsReplacements && $definition instanceof ObjectDefinition) { + $definition->replaceWildcards($wildcardsReplacements); + } + + if ($definition instanceof AutowireDefinition) { + /** @var AutowireDefinition $definition */ + $definition = $this->autowiring->autowire($name, $definition); + } + + $definition->setName($name); + + try { + $definition->replaceNestedDefinitions([$this, 'normalizeNestedDefinition']); + } catch (InvalidDefinition $e) { + throw InvalidDefinition::create($definition, sprintf( + 'Definition "%s" contains an error: %s', + $definition->getName(), + $e->getMessage() + ), $e); + } + + return $definition; + } + + /** + * Normalize a definition that is nested in another one. + * + * @throws InvalidDefinition + */ + public function normalizeNestedDefinition(mixed $definition) : mixed + { + $name = ''; + + if ($definition instanceof DefinitionHelper) { + $definition = $definition->getDefinition($name); + } elseif (is_array($definition)) { + $definition = new ArrayDefinition($definition); + } elseif ($definition instanceof \Closure) { + $definition = new FactoryDefinition($name, $definition); + } + + if ($definition instanceof DecoratorDefinition) { + throw new InvalidDefinition('Decorators cannot be nested in another definition'); + } + + if ($definition instanceof AutowireDefinition) { + $definition = $this->autowiring->autowire($name, $definition); + } + + if ($definition instanceof Definition) { + $definition->setName($name); + + // Recursively traverse nested definitions + $definition->replaceNestedDefinitions([$this, 'normalizeNestedDefinition']); + } + + return $definition; + } +} diff --git a/api/vendor/php-di/php-di/src/Definition/Source/DefinitionSource.php b/api/vendor/php-di/php-di/src/Definition/Source/DefinitionSource.php new file mode 100644 index 0000000..2595195 --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/Source/DefinitionSource.php @@ -0,0 +1,28 @@ + + */ +interface DefinitionSource +{ + /** + * Returns the DI definition for the entry name. + * + * @throws InvalidDefinition An invalid definition was found. + */ + public function getDefinition(string $name) : ?Definition; + + /** + * @return array Definitions indexed by their name. + */ + public function getDefinitions() : array; +} diff --git a/api/vendor/php-di/php-di/src/Definition/Source/MutableDefinitionSource.php b/api/vendor/php-di/php-di/src/Definition/Source/MutableDefinitionSource.php new file mode 100644 index 0000000..28b41d3 --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/Source/MutableDefinitionSource.php @@ -0,0 +1,17 @@ + + */ +interface MutableDefinitionSource extends DefinitionSource +{ + public function addDefinition(Definition $definition) : void; +} diff --git a/api/vendor/php-di/php-di/src/Definition/Source/NoAutowiring.php b/api/vendor/php-di/php-di/src/Definition/Source/NoAutowiring.php new file mode 100644 index 0000000..42ee81e --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/Source/NoAutowiring.php @@ -0,0 +1,24 @@ + + */ +class NoAutowiring implements Autowiring +{ + public function autowire(string $name, ?ObjectDefinition $definition = null) : ?ObjectDefinition + { + throw new InvalidDefinition(sprintf( + 'Cannot autowire entry "%s" because autowiring is disabled', + $name + )); + } +} diff --git a/api/vendor/php-di/php-di/src/Definition/Source/ReflectionBasedAutowiring.php b/api/vendor/php-di/php-di/src/Definition/Source/ReflectionBasedAutowiring.php new file mode 100644 index 0000000..5b0e112 --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/Source/ReflectionBasedAutowiring.php @@ -0,0 +1,85 @@ + + */ +class ReflectionBasedAutowiring implements DefinitionSource, Autowiring +{ + public function autowire(string $name, ?ObjectDefinition $definition = null) : ?ObjectDefinition + { + $className = $definition ? $definition->getClassName() : $name; + + if (!class_exists($className) && !interface_exists($className)) { + return $definition; + } + + $definition = $definition ?: new ObjectDefinition($name); + + // Constructor + $class = new \ReflectionClass($className); + $constructor = $class->getConstructor(); + if ($constructor && $constructor->isPublic()) { + $constructorInjection = MethodInjection::constructor($this->getParametersDefinition($constructor)); + $definition->completeConstructorInjection($constructorInjection); + } + + return $definition; + } + + public function getDefinition(string $name) : ?ObjectDefinition + { + return $this->autowire($name); + } + + /** + * Autowiring cannot guess all existing definitions. + */ + public function getDefinitions() : array + { + return []; + } + + /** + * Read the type-hinting from the parameters of the function. + */ + private function getParametersDefinition(\ReflectionFunctionAbstract $constructor) : array + { + $parameters = []; + + foreach ($constructor->getParameters() as $index => $parameter) { + // Skip optional parameters + if ($parameter->isOptional()) { + continue; + } + + $parameterType = $parameter->getType(); + if (!$parameterType) { + // No type + continue; + } + if (!$parameterType instanceof ReflectionNamedType) { + // Union types are not supported + continue; + } + if ($parameterType->isBuiltin()) { + // Primitive types are not supported + continue; + } + + $parameters[$index] = new Reference($parameterType->getName()); + } + + return $parameters; + } +} diff --git a/api/vendor/php-di/php-di/src/Definition/Source/SourceCache.php b/api/vendor/php-di/php-di/src/Definition/Source/SourceCache.php new file mode 100644 index 0000000..245f9d7 --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/Source/SourceCache.php @@ -0,0 +1,77 @@ + + */ +class SourceCache implements DefinitionSource, MutableDefinitionSource +{ + public const CACHE_KEY = 'php-di.definitions.'; + + public function __construct( + private DefinitionSource $cachedSource, + private string $cacheNamespace = '', + ) { + } + + public function getDefinition(string $name) : ?Definition + { + $definition = apcu_fetch($this->getCacheKey($name)); + + if ($definition === false) { + $definition = $this->cachedSource->getDefinition($name); + + // Update the cache + if ($this->shouldBeCached($definition)) { + apcu_store($this->getCacheKey($name), $definition); + } + } + + return $definition; + } + + /** + * Used only for the compilation so we can skip the cache safely. + */ + public function getDefinitions() : array + { + return $this->cachedSource->getDefinitions(); + } + + public static function isSupported() : bool + { + return function_exists('apcu_fetch') + && ini_get('apc.enabled') + && ! ('cli' === \PHP_SAPI && ! ini_get('apc.enable_cli')); + } + + public function getCacheKey(string $name) : string + { + return self::CACHE_KEY . $this->cacheNamespace . $name; + } + + public function addDefinition(Definition $definition) : void + { + throw new \LogicException('You cannot set a definition at runtime on a container that has caching enabled. Doing so would risk caching the definition for the next execution, where it might be different. You can either put your definitions in a file, remove the cache or ->set() a raw value directly (PHP object, string, int, ...) instead of a PHP-DI definition.'); + } + + private function shouldBeCached(?Definition $definition = null) : bool + { + return + // Cache missing definitions + ($definition === null) + // Object definitions are used with `make()` + || ($definition instanceof ObjectDefinition) + // Autowired definitions cannot be all compiled and are used with `make()` + || ($definition instanceof AutowireDefinition); + } +} diff --git a/api/vendor/php-di/php-di/src/Definition/Source/SourceChain.php b/api/vendor/php-di/php-di/src/Definition/Source/SourceChain.php new file mode 100644 index 0000000..a636ce6 --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/Source/SourceChain.php @@ -0,0 +1,90 @@ + + */ +class SourceChain implements DefinitionSource, MutableDefinitionSource +{ + private ?MutableDefinitionSource $mutableSource; + + /** + * @param list $sources + */ + public function __construct( + private array $sources, + ) { + } + + /** + * @param int $startIndex Use this parameter to start looking from a specific + * point in the source chain. + */ + public function getDefinition(string $name, int $startIndex = 0) : ?Definition + { + $count = count($this->sources); + for ($i = $startIndex; $i < $count; ++$i) { + $source = $this->sources[$i]; + + $definition = $source->getDefinition($name); + + if ($definition) { + if ($definition instanceof ExtendsPreviousDefinition) { + $this->resolveExtendedDefinition($definition, $i); + } + + return $definition; + } + } + + return null; + } + + public function getDefinitions() : array + { + $allDefinitions = array_merge(...array_map(fn ($source) => $source->getDefinitions(), $this->sources)); + + /** @var string[] $allNames */ + $allNames = array_keys($allDefinitions); + + $allValues = array_filter(array_map(fn ($name) => $this->getDefinition($name), $allNames)); + + return array_combine($allNames, $allValues); + } + + public function addDefinition(Definition $definition) : void + { + if (! $this->mutableSource) { + throw new \LogicException("The container's definition source has not been initialized correctly"); + } + + $this->mutableSource->addDefinition($definition); + } + + private function resolveExtendedDefinition(ExtendsPreviousDefinition $definition, int $currentIndex) + { + // Look in the next sources only (else infinite recursion, and we can only extend + // entries defined in the previous definition files - a previous == next here because + // the array was reversed ;) ) + $subDefinition = $this->getDefinition($definition->getName(), $currentIndex + 1); + + if ($subDefinition) { + $definition->setExtendedDefinition($subDefinition); + } + } + + public function setMutableDefinitionSource(MutableDefinitionSource $mutableSource) : void + { + $this->mutableSource = $mutableSource; + + array_unshift($this->sources, $mutableSource); + } +} diff --git a/api/vendor/php-di/php-di/src/Definition/StringDefinition.php b/api/vendor/php-di/php-di/src/Definition/StringDefinition.php new file mode 100644 index 0000000..1031be8 --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/StringDefinition.php @@ -0,0 +1,90 @@ + + */ +class StringDefinition implements Definition, SelfResolvingDefinition +{ + /** Entry name. */ + private string $name = ''; + + public function __construct( + private string $expression, + ) { + } + + public function getName() : string + { + return $this->name; + } + + public function setName(string $name) : void + { + $this->name = $name; + } + + public function getExpression() : string + { + return $this->expression; + } + + public function resolve(ContainerInterface $container) : string + { + return self::resolveExpression($this->name, $this->expression, $container); + } + + public function isResolvable(ContainerInterface $container) : bool + { + return true; + } + + public function replaceNestedDefinitions(callable $replacer) : void + { + // no nested definitions + } + + public function __toString() : string + { + return $this->expression; + } + + /** + * Resolve a string expression. + */ + public static function resolveExpression( + string $entryName, + string $expression, + ContainerInterface $container, + ) : string { + $callback = function (array $matches) use ($entryName, $container) { + /** @psalm-suppress InvalidCatch */ + try { + return $container->get($matches[1]); + } catch (NotFoundExceptionInterface $e) { + throw new DependencyException(sprintf( + "Error while parsing string expression for entry '%s': %s", + $entryName, + $e->getMessage() + ), 0, $e); + } + }; + + $result = preg_replace_callback('#\{([^{}]+)}#', $callback, $expression); + if ($result === null) { + throw new \RuntimeException(sprintf('An unknown error occurred while parsing the string definition: \'%s\'', $expression)); + } + + return $result; + } +} diff --git a/api/vendor/php-di/php-di/src/Definition/ValueDefinition.php b/api/vendor/php-di/php-di/src/Definition/ValueDefinition.php new file mode 100644 index 0000000..7d8f23c --- /dev/null +++ b/api/vendor/php-di/php-di/src/Definition/ValueDefinition.php @@ -0,0 +1,60 @@ + + */ +class ValueDefinition implements Definition, SelfResolvingDefinition +{ + /** + * Entry name. + */ + private string $name = ''; + + public function __construct( + private mixed $value, + ) { + } + + public function getName() : string + { + return $this->name; + } + + public function setName(string $name) : void + { + $this->name = $name; + } + + public function getValue() : mixed + { + return $this->value; + } + + public function resolve(ContainerInterface $container) : mixed + { + return $this->getValue(); + } + + public function isResolvable(ContainerInterface $container) : bool + { + return true; + } + + public function replaceNestedDefinitions(callable $replacer) : void + { + // no nested definitions + } + + public function __toString() : string + { + return sprintf('Value (%s)', var_export($this->value, true)); + } +} diff --git a/api/vendor/php-di/php-di/src/DependencyException.php b/api/vendor/php-di/php-di/src/DependencyException.php new file mode 100644 index 0000000..63b5fdd --- /dev/null +++ b/api/vendor/php-di/php-di/src/DependencyException.php @@ -0,0 +1,14 @@ + + */ +interface RequestedEntry +{ + /** + * Returns the name of the entry that was requested by the container. + */ + public function getName() : string; +} diff --git a/api/vendor/php-di/php-di/src/FactoryInterface.php b/api/vendor/php-di/php-di/src/FactoryInterface.php new file mode 100644 index 0000000..3486b90 --- /dev/null +++ b/api/vendor/php-di/php-di/src/FactoryInterface.php @@ -0,0 +1,30 @@ + + */ +interface FactoryInterface +{ + /** + * Resolves an entry by its name. If given a class name, it will return a new instance of that class. + * + * @param string $name Entry name or a class name. + * @param array $parameters Optional parameters to use to build the entry. Use this to force specific + * parameters to specific values. Parameters not defined in this array will + * be automatically resolved. + * + * @throws \InvalidArgumentException The name parameter must be of type string. + * @throws DependencyException Error while resolving the entry. + * @throws NotFoundException No entry or class found for the given name. + */ + public function make(string $name, array $parameters = []) : mixed; +} diff --git a/api/vendor/php-di/php-di/src/Invoker/DefinitionParameterResolver.php b/api/vendor/php-di/php-di/src/Invoker/DefinitionParameterResolver.php new file mode 100644 index 0000000..6e7e52f --- /dev/null +++ b/api/vendor/php-di/php-di/src/Invoker/DefinitionParameterResolver.php @@ -0,0 +1,64 @@ + + */ +class DefinitionParameterResolver implements ParameterResolver +{ + public function __construct( + private DefinitionResolver $definitionResolver, + ) { + } + + public function getParameters( + ReflectionFunctionAbstract $reflection, + array $providedParameters, + array $resolvedParameters, + ) : array { + // Skip parameters already resolved + if (! empty($resolvedParameters)) { + $providedParameters = array_diff_key($providedParameters, $resolvedParameters); + } + + foreach ($providedParameters as $key => $value) { + if ($value instanceof DefinitionHelper) { + $value = $value->getDefinition(''); + } + + if (! $value instanceof Definition) { + continue; + } + + $value = $this->definitionResolver->resolve($value); + + if (is_int($key)) { + // Indexed by position + $resolvedParameters[$key] = $value; + } else { + // Indexed by parameter name + // TODO optimize? + $reflectionParameters = $reflection->getParameters(); + foreach ($reflectionParameters as $reflectionParameter) { + if ($key === $reflectionParameter->name) { + $resolvedParameters[$reflectionParameter->getPosition()] = $value; + } + } + } + } + + return $resolvedParameters; + } +} diff --git a/api/vendor/php-di/php-di/src/Invoker/FactoryParameterResolver.php b/api/vendor/php-di/php-di/src/Invoker/FactoryParameterResolver.php new file mode 100644 index 0000000..d325800 --- /dev/null +++ b/api/vendor/php-di/php-di/src/Invoker/FactoryParameterResolver.php @@ -0,0 +1,69 @@ + + * @author Matthieu Napoli + */ +class FactoryParameterResolver implements ParameterResolver +{ + public function __construct( + private ContainerInterface $container, + ) { + } + + public function getParameters( + ReflectionFunctionAbstract $reflection, + array $providedParameters, + array $resolvedParameters, + ) : array { + $parameters = $reflection->getParameters(); + + // Skip parameters already resolved + if (! empty($resolvedParameters)) { + $parameters = array_diff_key($parameters, $resolvedParameters); + } + + foreach ($parameters as $index => $parameter) { + $parameterType = $parameter->getType(); + if (!$parameterType) { + // No type + continue; + } + if (!$parameterType instanceof ReflectionNamedType) { + // Union types are not supported + continue; + } + if ($parameterType->isBuiltin()) { + // Primitive types are not supported + continue; + } + + $parameterClass = $parameterType->getName(); + + if ($parameterClass === 'Psr\Container\ContainerInterface') { + $resolvedParameters[$index] = $this->container; + } elseif ($parameterClass === 'DI\Factory\RequestedEntry') { + // By convention the second parameter is the definition + $resolvedParameters[$index] = $providedParameters[1]; + } elseif ($this->container->has($parameterClass)) { + $resolvedParameters[$index] = $this->container->get($parameterClass); + } + } + + return $resolvedParameters; + } +} diff --git a/api/vendor/php-di/php-di/src/NotFoundException.php b/api/vendor/php-di/php-di/src/NotFoundException.php new file mode 100644 index 0000000..67dbacd --- /dev/null +++ b/api/vendor/php-di/php-di/src/NotFoundException.php @@ -0,0 +1,14 @@ + + */ +class NativeProxyFactory implements ProxyFactoryInterface +{ + /** + * Creates a new lazy proxy instance of the given class with + * the given initializer. + * + * {@inheritDoc} + */ + public function createProxy(string $className, \Closure $createFunction) : object + { + if (\PHP_VERSION_ID < 80400) { + throw new LogicException('Lazy loading proxies require PHP 8.4 or higher.'); + } + + $reflector = new \ReflectionClass($className); + + return $reflector->newLazyProxy($createFunction); + } + + public function generateProxyClass(string $className) : void + { + // Noop for this type. + } +} diff --git a/api/vendor/php-di/php-di/src/Proxy/ProxyFactory.php b/api/vendor/php-di/php-di/src/Proxy/ProxyFactory.php new file mode 100644 index 0000000..83adb68 --- /dev/null +++ b/api/vendor/php-di/php-di/src/Proxy/ProxyFactory.php @@ -0,0 +1,91 @@ + + */ +class ProxyFactory implements ProxyFactoryInterface +{ + private ?LazyLoadingValueHolderFactory $proxyManager = null; + + /** + * @param string|null $proxyDirectory If set, write the proxies to disk in this directory to improve performances. + */ + public function __construct( + private ?string $proxyDirectory = null, + ) { + } + + /** + * Creates a new lazy proxy instance of the given class with + * the given initializer. + * + * {@inheritDoc} + */ + public function createProxy(string $className, \Closure $createFunction): object + { + return $this->proxyManager()->createProxy( + $className, + function (& $wrappedObject, $proxy, $method, $params, & $initializer) use ($createFunction) { + $wrappedObject = $createFunction(); + $initializer = null; // turning off further lazy initialization + + return true; + } + ); + } + + /** + * Generates and writes the proxy class to file. + * + * @param class-string $className name of the class to be proxied + */ + public function generateProxyClass(string $className) : void + { + // If proxy classes a written to file then we pre-generate the class + // If they are not written to file then there is no point to do this + if ($this->proxyDirectory) { + $this->createProxy($className, function () {}); + } + } + + private function proxyManager() : LazyLoadingValueHolderFactory + { + if ($this->proxyManager === null) { + if (! class_exists(Configuration::class)) { + throw new \RuntimeException('The ocramius/proxy-manager library is not installed. Lazy injection requires that library to be installed with Composer in order to work. Run "composer require ocramius/proxy-manager:~2.0".'); + } + + $config = new Configuration(); + + if ($this->proxyDirectory) { + $config->setProxiesTargetDir($this->proxyDirectory); + $config->setGeneratorStrategy(new FileWriterGeneratorStrategy(new FileLocator($this->proxyDirectory))); + // @phpstan-ignore-next-line + spl_autoload_register($config->getProxyAutoloader()); + } else { + $config->setGeneratorStrategy(new EvaluatingGeneratorStrategy()); + } + + $this->proxyManager = new LazyLoadingValueHolderFactory($config); + } + + return $this->proxyManager; + } +} diff --git a/api/vendor/php-di/php-di/src/Proxy/ProxyFactoryInterface.php b/api/vendor/php-di/php-di/src/Proxy/ProxyFactoryInterface.php new file mode 100644 index 0000000..f541f12 --- /dev/null +++ b/api/vendor/php-di/php-di/src/Proxy/ProxyFactoryInterface.php @@ -0,0 +1,32 @@ + + */ +interface ProxyFactoryInterface +{ + /** + * Creates a new lazy proxy instance of the given class with + * the given initializer. + * + * @param class-string $className name of the class to be proxied + * @param \Closure $createFunction initializer to be passed to the proxy initializer to be passed to the proxy + */ + public function createProxy(string $className, \Closure $createFunction) : object; + + /** + * If the proxy generator depends on a filesystem component, + * this step writes the proxy for that class to file. Otherwise, + * it is a no-op. + * + * @param class-string $className name of the class to be proxied + */ + public function generateProxyClass(string $className) : void; +} diff --git a/api/vendor/php-di/php-di/src/functions.php b/api/vendor/php-di/php-di/src/functions.php new file mode 100644 index 0000000..43aa9d9 --- /dev/null +++ b/api/vendor/php-di/php-di/src/functions.php @@ -0,0 +1,154 @@ + decorate(function ($foo, $container) { + * return new CachedFoo($foo, $container->get('cache')); + * }) + * + * @param callable $callable The callable takes the decorated object as first parameter and + * the container as second. + */ + function decorate(callable|array|string $callable) : FactoryDefinitionHelper + { + return new FactoryDefinitionHelper($callable, true); + } +} + +if (! function_exists('DI\get')) { + /** + * Helper for referencing another container entry in an object definition. + */ + function get(string $entryName) : Reference + { + return new Reference($entryName); + } +} + +if (! function_exists('DI\env')) { + /** + * Helper for referencing environment variables. + * + * @param string $variableName The name of the environment variable. + * @param mixed $defaultValue The default value to be used if the environment variable is not defined. + */ + function env(string $variableName, mixed $defaultValue = null) : EnvironmentVariableDefinition + { + // Only mark as optional if the default value was *explicitly* provided. + $isOptional = 2 === func_num_args(); + + return new EnvironmentVariableDefinition($variableName, $isOptional, $defaultValue); + } +} + +if (! function_exists('DI\add')) { + /** + * Helper for extending another definition. + * + * Example: + * + * 'log.backends' => DI\add(DI\get('My\Custom\LogBackend')) + * + * or: + * + * 'log.backends' => DI\add([ + * DI\get('My\Custom\LogBackend') + * ]) + * + * @param mixed|array $values A value or an array of values to add to the array. + * + * @since 5.0 + */ + function add($values) : ArrayDefinitionExtension + { + if (! is_array($values)) { + $values = [$values]; + } + + return new ArrayDefinitionExtension($values); + } +} + +if (! function_exists('DI\string')) { + /** + * Helper for concatenating strings. + * + * Example: + * + * 'log.filename' => DI\string('{app.path}/app.log') + * + * @param string $expression A string expression. Use the `{}` placeholders to reference other container entries. + * + * @since 5.0 + */ + function string(string $expression) : StringDefinition + { + return new StringDefinition($expression); + } +} diff --git a/api/vendor/php-di/php-di/support.md b/api/vendor/php-di/php-di/support.md new file mode 100644 index 0000000..22dd39a --- /dev/null +++ b/api/vendor/php-di/php-di/support.md @@ -0,0 +1,42 @@ +--- +layout: documentation +current_menu: enterprise-support +title: Enterprise support for PHP-DI +--- + +# PHP-DI for Enterprise + +> *Available as part of the Tidelift Subscription* + +Tidelift is working with the maintainers of PHP-DI and thousands of other +open source projects to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. + +#### [Learn more](https://tidelift.com/subscription/pkg/packagist-php-di-php-di?utm_source=packagist-php-di-php-di&utm_medium=referral&utm_campaign=enterprise) | [**Request a demo**](https://tidelift.com/subscription/request-a-demo?utm_source=packagist-php-di-php-di&utm_medium=referral&utm_campaign=enterprise) + +## Enterprise-ready open source software—managed for you + +The Tidelift Subscription is a managed open source subscription for application dependencies covering millions of open source projects across JavaScript, Python, Java, PHP, Ruby, .NET, and more. + +Your subscription includes: + +- **Security updates** + Tidelift’s security response team coordinates patches for new breaking security vulnerabilities and alerts immediately through a private channel, so your software supply chain is always secure. + +- **Licensing verification and indemnification** + Tidelift verifies license information to enable easy policy enforcement and adds intellectual property indemnification to cover creators and users in case something goes wrong. You always have a 100% up-to-date bill of materials for your dependencies to share with your legal team, customers, or partners. + +- **Maintenance and code improvement** + Tidelift ensures the software you rely on keeps working as long as you need it to work. Your managed dependencies are actively maintained and we recruit additional maintainers where required. + +- **Package selection and version guidance** + We help you choose the best open source packages from the start—and then guide you through updates to stay on the best releases as new issues arise. + +- **Roadmap input** + Take a seat at the table with the creators behind the software you use. Tidelift’s participating maintainers earn more income as their software is used by more subscribers, so they’re interested in knowing what you need. + +- **Tooling and cloud integration** + Tidelift works with GitHub, GitLab, BitBucket, and more. We support every cloud platform (and other deployment targets, too). + +The end result? All of the capabilities you expect from commercial-grade software, for the full breadth of open source you use. That means less time grappling with esoteric open source trivia, and more time building your own applications—and your business. + +[Learn more](https://tidelift.com/subscription/pkg/packagist-php-di-php-di?utm_source=packagist-php-di-php-di&utm_medium=referral&utm_campaign=enterprise) | [**Request a demo**](https://tidelift.com/subscription/request-a-demo?utm_source=packagist-php-di-php-di&utm_medium=referral&utm_campaign=enterprise) diff --git a/api/vendor/phpoption/phpoption/LICENSE b/api/vendor/phpoption/phpoption/LICENSE new file mode 100644 index 0000000..f49a4e1 --- /dev/null +++ b/api/vendor/phpoption/phpoption/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. \ No newline at end of file diff --git a/api/vendor/phpoption/phpoption/composer.json b/api/vendor/phpoption/phpoption/composer.json new file mode 100644 index 0000000..c077040 --- /dev/null +++ b/api/vendor/phpoption/phpoption/composer.json @@ -0,0 +1,50 @@ +{ + "name": "phpoption/phpoption", + "description": "Option Type for PHP", + "keywords": ["php", "option", "language", "type"], + "license": "Apache-2.0", + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "https://github.com/schmittjoh" + }, + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.44 || ^9.6.25 || ^10.5.53 || ^11.5.34" + }, + "autoload": { + "psr-4": { + "PhpOption\\": "src/PhpOption/" + } + }, + "autoload-dev": { + "psr-4": { + "PhpOption\\Tests\\": "tests/PhpOption/Tests/" + } + }, + "config": { + "allow-plugins": { + "bamarni/composer-bin-plugin": true + }, + "preferred-install": "dist" + }, + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "1.9-dev" + } + } +} diff --git a/api/vendor/phpoption/phpoption/src/PhpOption/LazyOption.php b/api/vendor/phpoption/phpoption/src/PhpOption/LazyOption.php new file mode 100644 index 0000000..9cb77c8 --- /dev/null +++ b/api/vendor/phpoption/phpoption/src/PhpOption/LazyOption.php @@ -0,0 +1,175 @@ + + * + * 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. + */ + +namespace PhpOption; + +use Traversable; + +/** + * @template T + * + * @extends Option + */ +final class LazyOption extends Option +{ + /** @var callable(mixed...):(Option) */ + private $callback; + + /** @var array */ + private $arguments; + + /** @var Option|null */ + private $option; + + /** + * @template S + * @param callable(mixed...):(Option) $callback + * @param array $arguments + * + * @return LazyOption + */ + public static function create($callback, array $arguments = []): self + { + return new self($callback, $arguments); + } + + /** + * @param callable(mixed...):(Option) $callback + * @param array $arguments + */ + public function __construct($callback, array $arguments = []) + { + if (!is_callable($callback)) { + throw new \InvalidArgumentException('Invalid callback given'); + } + + $this->callback = $callback; + $this->arguments = $arguments; + } + + public function isDefined(): bool + { + return $this->option()->isDefined(); + } + + public function isEmpty(): bool + { + return $this->option()->isEmpty(); + } + + public function get() + { + return $this->option()->get(); + } + + public function getOrElse($default) + { + return $this->option()->getOrElse($default); + } + + public function getOrCall($callable) + { + return $this->option()->getOrCall($callable); + } + + public function getOrThrow(\Exception $ex) + { + return $this->option()->getOrThrow($ex); + } + + public function orElse(Option $else) + { + return $this->option()->orElse($else); + } + + public function ifDefined($callable) + { + $this->option()->forAll($callable); + } + + public function forAll($callable) + { + return $this->option()->forAll($callable); + } + + public function map($callable) + { + return $this->option()->map($callable); + } + + public function flatMap($callable) + { + return $this->option()->flatMap($callable); + } + + public function filter($callable) + { + return $this->option()->filter($callable); + } + + public function filterNot($callable) + { + return $this->option()->filterNot($callable); + } + + public function select($value) + { + return $this->option()->select($value); + } + + public function reject($value) + { + return $this->option()->reject($value); + } + + /** + * @return Traversable + */ + public function getIterator(): Traversable + { + return $this->option()->getIterator(); + } + + public function foldLeft($initialValue, $callable) + { + return $this->option()->foldLeft($initialValue, $callable); + } + + public function foldRight($initialValue, $callable) + { + return $this->option()->foldRight($initialValue, $callable); + } + + /** + * @return Option + */ + private function option(): Option + { + if (null === $this->option) { + /** @var mixed */ + $option = call_user_func_array($this->callback, $this->arguments); + if ($option instanceof Option) { + $this->option = $option; + } else { + throw new \RuntimeException(sprintf('Expected instance of %s', Option::class)); + } + } + + return $this->option; + } +} diff --git a/api/vendor/phpoption/phpoption/src/PhpOption/None.php b/api/vendor/phpoption/phpoption/src/PhpOption/None.php new file mode 100644 index 0000000..4b85d22 --- /dev/null +++ b/api/vendor/phpoption/phpoption/src/PhpOption/None.php @@ -0,0 +1,136 @@ + + * + * 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. + */ + +namespace PhpOption; + +use EmptyIterator; + +/** + * @extends Option + */ +final class None extends Option +{ + /** @var None|null */ + private static $instance; + + /** + * @return None + */ + public static function create(): self + { + if (null === self::$instance) { + self::$instance = new self(); + } + + return self::$instance; + } + + public function get() + { + throw new \RuntimeException('None has no value.'); + } + + public function getOrCall($callable) + { + return $callable(); + } + + public function getOrElse($default) + { + return $default; + } + + public function getOrThrow(\Exception $ex) + { + throw $ex; + } + + public function isEmpty(): bool + { + return true; + } + + public function isDefined(): bool + { + return false; + } + + public function orElse(Option $else) + { + return $else; + } + + public function ifDefined($callable) + { + // Just do nothing in that case. + } + + public function forAll($callable) + { + return $this; + } + + public function map($callable) + { + return $this; + } + + public function flatMap($callable) + { + return $this; + } + + public function filter($callable) + { + return $this; + } + + public function filterNot($callable) + { + return $this; + } + + public function select($value) + { + return $this; + } + + public function reject($value) + { + return $this; + } + + public function getIterator(): EmptyIterator + { + return new EmptyIterator(); + } + + public function foldLeft($initialValue, $callable) + { + return $initialValue; + } + + public function foldRight($initialValue, $callable) + { + return $initialValue; + } + + private function __construct() + { + } +} diff --git a/api/vendor/phpoption/phpoption/src/PhpOption/Option.php b/api/vendor/phpoption/phpoption/src/PhpOption/Option.php new file mode 100644 index 0000000..91fab9c --- /dev/null +++ b/api/vendor/phpoption/phpoption/src/PhpOption/Option.php @@ -0,0 +1,434 @@ + + * + * 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. + */ + +namespace PhpOption; + +use ArrayAccess; +use IteratorAggregate; + +/** + * @template T + * + * @implements IteratorAggregate + */ +abstract class Option implements IteratorAggregate +{ + /** + * Creates an option given a return value. + * + * This is intended for consuming existing APIs and allows you to easily + * convert them to an option. By default, we treat ``null`` as the None + * case, and everything else as Some. + * + * @template S + * + * @param S $value The actual return value. + * @param S $noneValue The value which should be considered "None"; null by + * default. + * + * @return Option + */ + public static function fromValue($value, $noneValue = null) + { + if ($value === $noneValue) { + return None::create(); + } + + return new Some($value); + } + + /** + * Creates an option from an array's value. + * + * If the key does not exist in the array, the array is not actually an + * array, or the array's value at the given key is null, None is returned. + * Otherwise, Some is returned wrapping the value at the given key. + * + * @template S + * + * @param array|ArrayAccess|null $array A potential array or \ArrayAccess value. + * @param string|int|null $key The key to check. + * + * @return Option + */ + public static function fromArraysValue($array, $key) + { + if ($key === null || !(is_array($array) || $array instanceof ArrayAccess) || !isset($array[$key])) { + return None::create(); + } + + return new Some($array[$key]); + } + + /** + * Creates a lazy-option with the given callback. + * + * This is also a helper constructor for lazy-consuming existing APIs where + * the return value is not yet an option. By default, we treat ``null`` as + * None case, and everything else as Some. + * + * @template S + * + * @param callable $callback The callback to evaluate. + * @param array $arguments The arguments for the callback. + * @param S $noneValue The value which should be considered "None"; + * null by default. + * + * @return LazyOption + */ + public static function fromReturn($callback, array $arguments = [], $noneValue = null) + { + return new LazyOption(static function () use ($callback, $arguments, $noneValue) { + /** @var mixed */ + $return = call_user_func_array($callback, $arguments); + + if ($return === $noneValue) { + return None::create(); + } + + return new Some($return); + }); + } + + /** + * Option factory, which creates new option based on passed value. + * + * If value is already an option, it simply returns. If value is callable, + * LazyOption with passed callback created and returned. If Option + * returned from callback, it returns directly. On other case value passed + * to Option::fromValue() method. + * + * @template S + * + * @param Option|callable|S $value + * @param S $noneValue Used when $value is mixed or + * callable, for None-check. + * + * @return Option|LazyOption + */ + public static function ensure($value, $noneValue = null) + { + if ($value instanceof self) { + return $value; + } elseif (is_callable($value)) { + return new LazyOption(static function () use ($value, $noneValue) { + /** @var mixed */ + $return = $value(); + + if ($return instanceof self) { + return $return; + } else { + return self::fromValue($return, $noneValue); + } + }); + } else { + return self::fromValue($value, $noneValue); + } + } + + /** + * Lift a function so that it accepts Option as parameters. + * + * We return a new closure that wraps the original callback. If any of the + * parameters passed to the lifted function is empty, the function will + * return a value of None. Otherwise, we will pass all parameters to the + * original callback and return the value inside a new Option, unless an + * Option is returned from the function, in which case, we use that. + * + * @template S + * + * @param callable $callback + * @param mixed $noneValue + * + * @return callable + */ + public static function lift($callback, $noneValue = null) + { + return static function () use ($callback, $noneValue) { + /** @var array */ + $args = func_get_args(); + + $reduced_args = array_reduce( + $args, + /** @param bool $status */ + static function ($status, self $o) { + return $o->isEmpty() ? true : $status; + }, + false + ); + // if at least one parameter is empty, return None + if ($reduced_args) { + return None::create(); + } + + $args = array_map( + /** @return T */ + static function (self $o) { + // it is safe to do so because the fold above checked + // that all arguments are of type Some + /** @var T */ + return $o->get(); + }, + $args + ); + + return self::ensure(call_user_func_array($callback, $args), $noneValue); + }; + } + + /** + * Returns the value if available, or throws an exception otherwise. + * + * @throws \RuntimeException If value is not available. + * + * @return T + */ + abstract public function get(); + + /** + * Returns the value if available, or the default value if not. + * + * @template S + * + * @param S $default + * + * @return T|S + */ + abstract public function getOrElse($default); + + /** + * Returns the value if available, or the results of the callable. + * + * This is preferable over ``getOrElse`` if the computation of the default + * value is expensive. + * + * @template S + * + * @param callable():S $callable + * + * @return T|S + */ + abstract public function getOrCall($callable); + + /** + * Returns the value if available, or throws the passed exception. + * + * @param \Exception $ex + * + * @return T + */ + abstract public function getOrThrow(\Exception $ex); + + /** + * Returns true if no value is available, false otherwise. + * + * @return bool + */ + abstract public function isEmpty(); + + /** + * Returns true if a value is available, false otherwise. + * + * @return bool + */ + abstract public function isDefined(); + + /** + * Returns this option if non-empty, or the passed option otherwise. + * + * This can be used to try multiple alternatives, and is especially useful + * with lazy evaluating options: + * + * ```php + * $repo->findSomething() + * ->orElse(new LazyOption(array($repo, 'findSomethingElse'))) + * ->orElse(new LazyOption(array($repo, 'createSomething'))); + * ``` + * + * @param Option $else + * + * @return Option + */ + abstract public function orElse(self $else); + + /** + * This is similar to map() below except that the return value has no meaning; + * the passed callable is simply executed if the option is non-empty, and + * ignored if the option is empty. + * + * In all cases, the return value of the callable is discarded. + * + * ```php + * $comment->getMaybeFile()->ifDefined(function($file) { + * // Do something with $file here. + * }); + * ``` + * + * If you're looking for something like ``ifEmpty``, you can use ``getOrCall`` + * and ``getOrElse`` in these cases. + * + * @deprecated Use forAll() instead. + * + * @param callable(T):mixed $callable + * + * @return void + */ + abstract public function ifDefined($callable); + + /** + * This is similar to map() except that the return value of the callable has no meaning. + * + * The passed callable is simply executed if the option is non-empty, and ignored if the + * option is empty. This method is preferred for callables with side-effects, while map() + * is intended for callables without side-effects. + * + * @param callable(T):mixed $callable + * + * @return Option + */ + abstract public function forAll($callable); + + /** + * Applies the callable to the value of the option if it is non-empty, + * and returns the return value of the callable wrapped in Some(). + * + * If the option is empty, then the callable is not applied. + * + * ```php + * (new Some("foo"))->map('strtoupper')->get(); // "FOO" + * ``` + * + * @template S + * + * @param callable(T):S $callable + * + * @return Option + */ + abstract public function map($callable); + + /** + * Applies the callable to the value of the option if it is non-empty, and + * returns the return value of the callable directly. + * + * In contrast to ``map``, the return value of the callable is expected to + * be an Option itself; it is not automatically wrapped in Some(). + * + * @template S + * + * @param callable(T):Option $callable must return an Option + * + * @return Option + */ + abstract public function flatMap($callable); + + /** + * If the option is empty, it is returned immediately without applying the callable. + * + * If the option is non-empty, the callable is applied, and if it returns true, + * the option itself is returned; otherwise, None is returned. + * + * @param callable(T):bool $callable + * + * @return Option + */ + abstract public function filter($callable); + + /** + * If the option is empty, it is returned immediately without applying the callable. + * + * If the option is non-empty, the callable is applied, and if it returns false, + * the option itself is returned; otherwise, None is returned. + * + * @param callable(T):bool $callable + * + * @return Option + */ + abstract public function filterNot($callable); + + /** + * If the option is empty, it is returned immediately. + * + * If the option is non-empty, and its value does not equal the passed value + * (via a shallow comparison ===), then None is returned. Otherwise, the + * Option is returned. + * + * In other words, this will filter all but the passed value. + * + * @param T $value + * + * @return Option + */ + abstract public function select($value); + + /** + * If the option is empty, it is returned immediately. + * + * If the option is non-empty, and its value does equal the passed value (via + * a shallow comparison ===), then None is returned; otherwise, the Option is + * returned. + * + * In other words, this will let all values through except the passed value. + * + * @param T $value + * + * @return Option + */ + abstract public function reject($value); + + /** + * Binary operator for the initial value and the option's value. + * + * If empty, the initial value is returned. If non-empty, the callable + * receives the initial value and the option's value as arguments. + * + * ```php + * + * $some = new Some(5); + * $none = None::create(); + * $result = $some->foldLeft(1, function($a, $b) { return $a + $b; }); // int(6) + * $result = $none->foldLeft(1, function($a, $b) { return $a + $b; }); // int(1) + * + * // This can be used instead of something like the following: + * $option = Option::fromValue($integerOrNull); + * $result = 1; + * if ( ! $option->isEmpty()) { + * $result += $option->get(); + * } + * ``` + * + * @template S + * + * @param S $initialValue + * @param callable(S, T):S $callable + * + * @return S + */ + abstract public function foldLeft($initialValue, $callable); + + /** + * foldLeft() but with reversed arguments for the callable. + * + * @template S + * + * @param S $initialValue + * @param callable(T, S):S $callable + * + * @return S + */ + abstract public function foldRight($initialValue, $callable); +} diff --git a/api/vendor/phpoption/phpoption/src/PhpOption/Some.php b/api/vendor/phpoption/phpoption/src/PhpOption/Some.php new file mode 100644 index 0000000..032632e --- /dev/null +++ b/api/vendor/phpoption/phpoption/src/PhpOption/Some.php @@ -0,0 +1,169 @@ + + * + * 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. + */ + +namespace PhpOption; + +use ArrayIterator; + +/** + * @template T + * + * @extends Option + */ +final class Some extends Option +{ + /** @var T */ + private $value; + + /** + * @param T $value + */ + public function __construct($value) + { + $this->value = $value; + } + + /** + * @template U + * + * @param U $value + * + * @return Some + */ + public static function create($value): self + { + return new self($value); + } + + public function isDefined(): bool + { + return true; + } + + public function isEmpty(): bool + { + return false; + } + + public function get() + { + return $this->value; + } + + public function getOrElse($default) + { + return $this->value; + } + + public function getOrCall($callable) + { + return $this->value; + } + + public function getOrThrow(\Exception $ex) + { + return $this->value; + } + + public function orElse(Option $else) + { + return $this; + } + + public function ifDefined($callable) + { + $this->forAll($callable); + } + + public function forAll($callable) + { + $callable($this->value); + + return $this; + } + + public function map($callable) + { + return new self($callable($this->value)); + } + + public function flatMap($callable) + { + /** @var mixed */ + $rs = $callable($this->value); + if (!$rs instanceof Option) { + throw new \RuntimeException('Callables passed to flatMap() must return an Option. Maybe you should use map() instead?'); + } + + return $rs; + } + + public function filter($callable) + { + if (true === $callable($this->value)) { + return $this; + } + + return None::create(); + } + + public function filterNot($callable) + { + if (false === $callable($this->value)) { + return $this; + } + + return None::create(); + } + + public function select($value) + { + if ($this->value === $value) { + return $this; + } + + return None::create(); + } + + public function reject($value) + { + if ($this->value === $value) { + return None::create(); + } + + return $this; + } + + /** + * @return ArrayIterator + */ + public function getIterator(): ArrayIterator + { + return new ArrayIterator([$this->value]); + } + + public function foldLeft($initialValue, $callable) + { + return $callable($initialValue, $this->value); + } + + public function foldRight($initialValue, $callable) + { + return $callable($this->value, $initialValue); + } +} diff --git a/api/vendor/psr/container/.gitignore b/api/vendor/psr/container/.gitignore new file mode 100644 index 0000000..b2395aa --- /dev/null +++ b/api/vendor/psr/container/.gitignore @@ -0,0 +1,3 @@ +composer.lock +composer.phar +/vendor/ diff --git a/api/vendor/psr/container/LICENSE b/api/vendor/psr/container/LICENSE new file mode 100644 index 0000000..2877a48 --- /dev/null +++ b/api/vendor/psr/container/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013-2016 container-interop +Copyright (c) 2016 PHP Framework Interoperability Group + +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. diff --git a/api/vendor/psr/container/README.md b/api/vendor/psr/container/README.md new file mode 100644 index 0000000..1b9d9e5 --- /dev/null +++ b/api/vendor/psr/container/README.md @@ -0,0 +1,13 @@ +Container interface +============== + +This repository holds all interfaces related to [PSR-11 (Container Interface)][psr-url]. + +Note that this is not a Container implementation of its own. It is merely abstractions that describe the components of a Dependency Injection Container. + +The installable [package][package-url] and [implementations][implementation-url] are listed on Packagist. + +[psr-url]: https://www.php-fig.org/psr/psr-11/ +[package-url]: https://packagist.org/packages/psr/container +[implementation-url]: https://packagist.org/providers/psr/container-implementation + diff --git a/api/vendor/psr/container/composer.json b/api/vendor/psr/container/composer.json new file mode 100644 index 0000000..baf6cd1 --- /dev/null +++ b/api/vendor/psr/container/composer.json @@ -0,0 +1,27 @@ +{ + "name": "psr/container", + "type": "library", + "description": "Common Container Interface (PHP FIG PSR-11)", + "keywords": ["psr", "psr-11", "container", "container-interop", "container-interface"], + "homepage": "https://github.com/php-fig/container", + "license": "MIT", + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "require": { + "php": ">=7.4.0" + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + } +} diff --git a/api/vendor/psr/container/src/ContainerExceptionInterface.php b/api/vendor/psr/container/src/ContainerExceptionInterface.php new file mode 100644 index 0000000..0f213f2 --- /dev/null +++ b/api/vendor/psr/container/src/ContainerExceptionInterface.php @@ -0,0 +1,12 @@ +=7.1", + "psr/http-message": "^1.0 || ^2.0" + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + } +} diff --git a/api/vendor/psr/http-factory/src/RequestFactoryInterface.php b/api/vendor/psr/http-factory/src/RequestFactoryInterface.php new file mode 100644 index 0000000..cb39a08 --- /dev/null +++ b/api/vendor/psr/http-factory/src/RequestFactoryInterface.php @@ -0,0 +1,18 @@ + `RequestInterface`, `ServerRequestInterface`, `ResponseInterface` extend `MessageInterface` because the `Request` and the `Response` are `HTTP Messages`. +> When using `ServerRequestInterface`, both `RequestInterface` and `Psr\Http\Message\MessageInterface` methods are considered. + diff --git a/api/vendor/psr/http-message/docs/PSR7-Usage.md b/api/vendor/psr/http-message/docs/PSR7-Usage.md new file mode 100644 index 0000000..b6d048a --- /dev/null +++ b/api/vendor/psr/http-message/docs/PSR7-Usage.md @@ -0,0 +1,159 @@ +### PSR-7 Usage + +All PSR-7 applications comply with these interfaces +They were created to establish a standard between middleware implementations. + +> `RequestInterface`, `ServerRequestInterface`, `ResponseInterface` extend `MessageInterface` because the `Request` and the `Response` are `HTTP Messages`. +> When using `ServerRequestInterface`, both `RequestInterface` and `Psr\Http\Message\MessageInterface` methods are considered. + + +The following examples will illustrate how basic operations are done in PSR-7. + +##### Examples + + +For this examples to work (at least) a PSR-7 implementation package is required. (eg: zendframework/zend-diactoros, guzzlehttp/psr7, slim/slim, etc) +All PSR-7 implementations should have the same behaviour. + +The following will be assumed: +`$request` is an object of `Psr\Http\Message\RequestInterface` and + +`$response` is an object implementing `Psr\Http\Message\RequestInterface` + + +### Working with HTTP Headers + +#### Adding headers to response: + +```php +$response->withHeader('My-Custom-Header', 'My Custom Message'); +``` + +#### Appending values to headers + +```php +$response->withAddedHeader('My-Custom-Header', 'The second message'); +``` + +#### Checking if header exists: + +```php +$request->hasHeader('My-Custom-Header'); // will return false +$response->hasHeader('My-Custom-Header'); // will return true +``` + +> Note: My-Custom-Header was only added in the Response + +#### Getting comma-separated values from a header (also applies to request) + +```php +// getting value from request headers +$request->getHeaderLine('Content-Type'); // will return: "text/html; charset=UTF-8" +// getting value from response headers +$response->getHeaderLine('My-Custom-Header'); // will return: "My Custom Message; The second message" +``` + +#### Getting array of value from a header (also applies to request) +```php +// getting value from request headers +$request->getHeader('Content-Type'); // will return: ["text/html", "charset=UTF-8"] +// getting value from response headers +$response->getHeader('My-Custom-Header'); // will return: ["My Custom Message", "The second message"] +``` + +#### Removing headers from HTTP Messages +```php +// removing a header from Request, removing deprecated "Content-MD5" header +$request->withoutHeader('Content-MD5'); + +// removing a header from Response +// effect: the browser won't know the size of the stream +// the browser will download the stream till it ends +$response->withoutHeader('Content-Length'); +``` + +### Working with HTTP Message Body + +When working with the PSR-7 there are two methods of implementation: +#### 1. Getting the body separately + +> This method makes the body handling easier to understand and is useful when repeatedly calling body methods. (You only call `getBody()` once). Using this method mistakes like `$response->write()` are also prevented. + +```php +$body = $response->getBody(); +// operations on body, eg. read, write, seek +// ... +// replacing the old body +$response->withBody($body); +// this last statement is optional as we working with objects +// in this case the "new" body is same with the "old" one +// the $body variable has the same value as the one in $request, only the reference is passed +``` + +#### 2. Working directly on response + +> This method is useful when only performing few operations as the `$request->getBody()` statement fragment is required + +```php +$response->getBody()->write('hello'); +``` + +### Getting the body contents + +The following snippet gets the contents of a stream contents. +> Note: Streams must be rewinded, if content was written into streams, it will be ignored when calling `getContents()` because the stream pointer is set to the last character, which is `\0` - meaning end of stream. +```php +$body = $response->getBody(); +$body->rewind(); // or $body->seek(0); +$bodyText = $body->getContents(); +``` +> Note: If `$body->seek(1)` is called before `$body->getContents()`, the first character will be ommited as the starting pointer is set to `1`, not `0`. This is why using `$body->rewind()` is recommended. + +### Append to body + +```php +$response->getBody()->write('Hello'); // writing directly +$body = $request->getBody(); // which is a `StreamInterface` +$body->write('xxxxx'); +``` + +### Prepend to body +Prepending is different when it comes to streams. The content must be copied before writing the content to be prepended. +The following example will explain the behaviour of streams. + +```php +// assuming our response is initially empty +$body = $repsonse->getBody(); +// writing the string "abcd" +$body->write('abcd'); + +// seeking to start of stream +$body->seek(0); +// writing 'ef' +$body->write('ef'); // at this point the stream contains "efcd" +``` + +#### Prepending by rewriting separately + +```php +// assuming our response body stream only contains: "abcd" +$body = $response->getBody(); +$body->rewind(); +$contents = $body->getContents(); // abcd +// seeking the stream to beginning +$body->rewind(); +$body->write('ef'); // stream contains "efcd" +$body->write($contents); // stream contains "efabcd" +``` + +> Note: `getContents()` seeks the stream while reading it, therefore if the second `rewind()` method call was not present the stream would have resulted in `abcdefabcd` because the `write()` method appends to stream if not preceeded by `rewind()` or `seek(0)`. + +#### Prepending by using contents as a string +```php +$body = $response->getBody(); +$body->rewind(); +$contents = $body->getContents(); // efabcd +$contents = 'ef'.$contents; +$body->rewind(); +$body->write($contents); +``` diff --git a/api/vendor/psr/http-message/src/MessageInterface.php b/api/vendor/psr/http-message/src/MessageInterface.php new file mode 100644 index 0000000..a83c985 --- /dev/null +++ b/api/vendor/psr/http-message/src/MessageInterface.php @@ -0,0 +1,187 @@ +getHeaders() as $name => $values) { + * echo $name . ": " . implode(", ", $values); + * } + * + * // Emit headers iteratively: + * foreach ($message->getHeaders() as $name => $values) { + * foreach ($values as $value) { + * header(sprintf('%s: %s', $name, $value), false); + * } + * } + * + * While header names are not case-sensitive, getHeaders() will preserve the + * exact case in which headers were originally specified. + * + * @return string[][] Returns an associative array of the message's headers. Each + * key MUST be a header name, and each value MUST be an array of strings + * for that header. + */ + public function getHeaders(): array; + + /** + * Checks if a header exists by the given case-insensitive name. + * + * @param string $name Case-insensitive header field name. + * @return bool Returns true if any header names match the given header + * name using a case-insensitive string comparison. Returns false if + * no matching header name is found in the message. + */ + public function hasHeader(string $name): bool; + + /** + * Retrieves a message header value by the given case-insensitive name. + * + * This method returns an array of all the header values of the given + * case-insensitive header name. + * + * If the header does not appear in the message, this method MUST return an + * empty array. + * + * @param string $name Case-insensitive header field name. + * @return string[] An array of string values as provided for the given + * header. If the header does not appear in the message, this method MUST + * return an empty array. + */ + public function getHeader(string $name): array; + + /** + * Retrieves a comma-separated string of the values for a single header. + * + * This method returns all of the header values of the given + * case-insensitive header name as a string concatenated together using + * a comma. + * + * NOTE: Not all header values may be appropriately represented using + * comma concatenation. For such headers, use getHeader() instead + * and supply your own delimiter when concatenating. + * + * If the header does not appear in the message, this method MUST return + * an empty string. + * + * @param string $name Case-insensitive header field name. + * @return string A string of values as provided for the given header + * concatenated together using a comma. If the header does not appear in + * the message, this method MUST return an empty string. + */ + public function getHeaderLine(string $name): string; + + /** + * Return an instance with the provided value replacing the specified header. + * + * While header names are case-insensitive, the casing of the header will + * be preserved by this function, and returned from getHeaders(). + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return an instance that has the + * new and/or updated header and value. + * + * @param string $name Case-insensitive header field name. + * @param string|string[] $value Header value(s). + * @return static + * @throws \InvalidArgumentException for invalid header names or values. + */ + public function withHeader(string $name, $value): MessageInterface; + + /** + * Return an instance with the specified header appended with the given value. + * + * Existing values for the specified header will be maintained. The new + * value(s) will be appended to the existing list. If the header did not + * exist previously, it will be added. + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return an instance that has the + * new header and/or value. + * + * @param string $name Case-insensitive header field name to add. + * @param string|string[] $value Header value(s). + * @return static + * @throws \InvalidArgumentException for invalid header names or values. + */ + public function withAddedHeader(string $name, $value): MessageInterface; + + /** + * Return an instance without the specified header. + * + * Header resolution MUST be done without case-sensitivity. + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return an instance that removes + * the named header. + * + * @param string $name Case-insensitive header field name to remove. + * @return static + */ + public function withoutHeader(string $name): MessageInterface; + + /** + * Gets the body of the message. + * + * @return StreamInterface Returns the body as a stream. + */ + public function getBody(): StreamInterface; + + /** + * Return an instance with the specified message body. + * + * The body MUST be a StreamInterface object. + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return a new instance that has the + * new body stream. + * + * @param StreamInterface $body Body. + * @return static + * @throws \InvalidArgumentException When the body is not valid. + */ + public function withBody(StreamInterface $body): MessageInterface; +} diff --git a/api/vendor/psr/http-message/src/RequestInterface.php b/api/vendor/psr/http-message/src/RequestInterface.php new file mode 100644 index 0000000..33f85e5 --- /dev/null +++ b/api/vendor/psr/http-message/src/RequestInterface.php @@ -0,0 +1,130 @@ +getQuery()` + * or from the `QUERY_STRING` server param. + * + * @return array + */ + public function getQueryParams(): array; + + /** + * Return an instance with the specified query string arguments. + * + * These values SHOULD remain immutable over the course of the incoming + * request. They MAY be injected during instantiation, such as from PHP's + * $_GET superglobal, or MAY be derived from some other value such as the + * URI. In cases where the arguments are parsed from the URI, the data + * MUST be compatible with what PHP's parse_str() would return for + * purposes of how duplicate query parameters are handled, and how nested + * sets are handled. + * + * Setting query string arguments MUST NOT change the URI stored by the + * request, nor the values in the server params. + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return an instance that has the + * updated query string arguments. + * + * @param array $query Array of query string arguments, typically from + * $_GET. + * @return static + */ + public function withQueryParams(array $query): ServerRequestInterface; + + /** + * Retrieve normalized file upload data. + * + * This method returns upload metadata in a normalized tree, with each leaf + * an instance of Psr\Http\Message\UploadedFileInterface. + * + * These values MAY be prepared from $_FILES or the message body during + * instantiation, or MAY be injected via withUploadedFiles(). + * + * @return array An array tree of UploadedFileInterface instances; an empty + * array MUST be returned if no data is present. + */ + public function getUploadedFiles(): array; + + /** + * Create a new instance with the specified uploaded files. + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return an instance that has the + * updated body parameters. + * + * @param array $uploadedFiles An array tree of UploadedFileInterface instances. + * @return static + * @throws \InvalidArgumentException if an invalid structure is provided. + */ + public function withUploadedFiles(array $uploadedFiles): ServerRequestInterface; + + /** + * Retrieve any parameters provided in the request body. + * + * If the request Content-Type is either application/x-www-form-urlencoded + * or multipart/form-data, and the request method is POST, this method MUST + * return the contents of $_POST. + * + * Otherwise, this method may return any results of deserializing + * the request body content; as parsing returns structured content, the + * potential types MUST be arrays or objects only. A null value indicates + * the absence of body content. + * + * @return null|array|object The deserialized body parameters, if any. + * These will typically be an array or object. + */ + public function getParsedBody(); + + /** + * Return an instance with the specified body parameters. + * + * These MAY be injected during instantiation. + * + * If the request Content-Type is either application/x-www-form-urlencoded + * or multipart/form-data, and the request method is POST, use this method + * ONLY to inject the contents of $_POST. + * + * The data IS NOT REQUIRED to come from $_POST, but MUST be the results of + * deserializing the request body content. Deserialization/parsing returns + * structured data, and, as such, this method ONLY accepts arrays or objects, + * or a null value if nothing was available to parse. + * + * As an example, if content negotiation determines that the request data + * is a JSON payload, this method could be used to create a request + * instance with the deserialized parameters. + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return an instance that has the + * updated body parameters. + * + * @param null|array|object $data The deserialized body data. This will + * typically be in an array or object. + * @return static + * @throws \InvalidArgumentException if an unsupported argument type is + * provided. + */ + public function withParsedBody($data): ServerRequestInterface; + + /** + * Retrieve attributes derived from the request. + * + * The request "attributes" may be used to allow injection of any + * parameters derived from the request: e.g., the results of path + * match operations; the results of decrypting cookies; the results of + * deserializing non-form-encoded message bodies; etc. Attributes + * will be application and request specific, and CAN be mutable. + * + * @return array Attributes derived from the request. + */ + public function getAttributes(): array; + + /** + * Retrieve a single derived request attribute. + * + * Retrieves a single derived request attribute as described in + * getAttributes(). If the attribute has not been previously set, returns + * the default value as provided. + * + * This method obviates the need for a hasAttribute() method, as it allows + * specifying a default value to return if the attribute is not found. + * + * @see getAttributes() + * @param string $name The attribute name. + * @param mixed $default Default value to return if the attribute does not exist. + * @return mixed + */ + public function getAttribute(string $name, $default = null); + + /** + * Return an instance with the specified derived request attribute. + * + * This method allows setting a single derived request attribute as + * described in getAttributes(). + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return an instance that has the + * updated attribute. + * + * @see getAttributes() + * @param string $name The attribute name. + * @param mixed $value The value of the attribute. + * @return static + */ + public function withAttribute(string $name, $value): ServerRequestInterface; + + /** + * Return an instance that removes the specified derived request attribute. + * + * This method allows removing a single derived request attribute as + * described in getAttributes(). + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return an instance that removes + * the attribute. + * + * @see getAttributes() + * @param string $name The attribute name. + * @return static + */ + public function withoutAttribute(string $name): ServerRequestInterface; +} diff --git a/api/vendor/psr/http-message/src/StreamInterface.php b/api/vendor/psr/http-message/src/StreamInterface.php new file mode 100644 index 0000000..a62aabb --- /dev/null +++ b/api/vendor/psr/http-message/src/StreamInterface.php @@ -0,0 +1,158 @@ + + * [user-info@]host[:port] + * + * + * If the port component is not set or is the standard port for the current + * scheme, it SHOULD NOT be included. + * + * @see https://tools.ietf.org/html/rfc3986#section-3.2 + * @return string The URI authority, in "[user-info@]host[:port]" format. + */ + public function getAuthority(): string; + + /** + * Retrieve the user information component of the URI. + * + * If no user information is present, this method MUST return an empty + * string. + * + * If a user is present in the URI, this will return that value; + * additionally, if the password is also present, it will be appended to the + * user value, with a colon (":") separating the values. + * + * The trailing "@" character is not part of the user information and MUST + * NOT be added. + * + * @return string The URI user information, in "username[:password]" format. + */ + public function getUserInfo(): string; + + /** + * Retrieve the host component of the URI. + * + * If no host is present, this method MUST return an empty string. + * + * The value returned MUST be normalized to lowercase, per RFC 3986 + * Section 3.2.2. + * + * @see http://tools.ietf.org/html/rfc3986#section-3.2.2 + * @return string The URI host. + */ + public function getHost(): string; + + /** + * Retrieve the port component of the URI. + * + * If a port is present, and it is non-standard for the current scheme, + * this method MUST return it as an integer. If the port is the standard port + * used with the current scheme, this method SHOULD return null. + * + * If no port is present, and no scheme is present, this method MUST return + * a null value. + * + * If no port is present, but a scheme is present, this method MAY return + * the standard port for that scheme, but SHOULD return null. + * + * @return null|int The URI port. + */ + public function getPort(): ?int; + + /** + * Retrieve the path component of the URI. + * + * The path can either be empty or absolute (starting with a slash) or + * rootless (not starting with a slash). Implementations MUST support all + * three syntaxes. + * + * Normally, the empty path "" and absolute path "/" are considered equal as + * defined in RFC 7230 Section 2.7.3. But this method MUST NOT automatically + * do this normalization because in contexts with a trimmed base path, e.g. + * the front controller, this difference becomes significant. It's the task + * of the user to handle both "" and "/". + * + * The value returned MUST be percent-encoded, but MUST NOT double-encode + * any characters. To determine what characters to encode, please refer to + * RFC 3986, Sections 2 and 3.3. + * + * As an example, if the value should include a slash ("/") not intended as + * delimiter between path segments, that value MUST be passed in encoded + * form (e.g., "%2F") to the instance. + * + * @see https://tools.ietf.org/html/rfc3986#section-2 + * @see https://tools.ietf.org/html/rfc3986#section-3.3 + * @return string The URI path. + */ + public function getPath(): string; + + /** + * Retrieve the query string of the URI. + * + * If no query string is present, this method MUST return an empty string. + * + * The leading "?" character is not part of the query and MUST NOT be + * added. + * + * The value returned MUST be percent-encoded, but MUST NOT double-encode + * any characters. To determine what characters to encode, please refer to + * RFC 3986, Sections 2 and 3.4. + * + * As an example, if a value in a key/value pair of the query string should + * include an ampersand ("&") not intended as a delimiter between values, + * that value MUST be passed in encoded form (e.g., "%26") to the instance. + * + * @see https://tools.ietf.org/html/rfc3986#section-2 + * @see https://tools.ietf.org/html/rfc3986#section-3.4 + * @return string The URI query string. + */ + public function getQuery(): string; + + /** + * Retrieve the fragment component of the URI. + * + * If no fragment is present, this method MUST return an empty string. + * + * The leading "#" character is not part of the fragment and MUST NOT be + * added. + * + * The value returned MUST be percent-encoded, but MUST NOT double-encode + * any characters. To determine what characters to encode, please refer to + * RFC 3986, Sections 2 and 3.5. + * + * @see https://tools.ietf.org/html/rfc3986#section-2 + * @see https://tools.ietf.org/html/rfc3986#section-3.5 + * @return string The URI fragment. + */ + public function getFragment(): string; + + /** + * Return an instance with the specified scheme. + * + * This method MUST retain the state of the current instance, and return + * an instance that contains the specified scheme. + * + * Implementations MUST support the schemes "http" and "https" case + * insensitively, and MAY accommodate other schemes if required. + * + * An empty scheme is equivalent to removing the scheme. + * + * @param string $scheme The scheme to use with the new instance. + * @return static A new instance with the specified scheme. + * @throws \InvalidArgumentException for invalid or unsupported schemes. + */ + public function withScheme(string $scheme): UriInterface; + + /** + * Return an instance with the specified user information. + * + * This method MUST retain the state of the current instance, and return + * an instance that contains the specified user information. + * + * Password is optional, but the user information MUST include the + * user; an empty string for the user is equivalent to removing user + * information. + * + * @param string $user The user name to use for authority. + * @param null|string $password The password associated with $user. + * @return static A new instance with the specified user information. + */ + public function withUserInfo(string $user, ?string $password = null): UriInterface; + + /** + * Return an instance with the specified host. + * + * This method MUST retain the state of the current instance, and return + * an instance that contains the specified host. + * + * An empty host value is equivalent to removing the host. + * + * @param string $host The hostname to use with the new instance. + * @return static A new instance with the specified host. + * @throws \InvalidArgumentException for invalid hostnames. + */ + public function withHost(string $host): UriInterface; + + /** + * Return an instance with the specified port. + * + * This method MUST retain the state of the current instance, and return + * an instance that contains the specified port. + * + * Implementations MUST raise an exception for ports outside the + * established TCP and UDP port ranges. + * + * A null value provided for the port is equivalent to removing the port + * information. + * + * @param null|int $port The port to use with the new instance; a null value + * removes the port information. + * @return static A new instance with the specified port. + * @throws \InvalidArgumentException for invalid ports. + */ + public function withPort(?int $port): UriInterface; + + /** + * Return an instance with the specified path. + * + * This method MUST retain the state of the current instance, and return + * an instance that contains the specified path. + * + * The path can either be empty or absolute (starting with a slash) or + * rootless (not starting with a slash). Implementations MUST support all + * three syntaxes. + * + * If the path is intended to be domain-relative rather than path relative then + * it must begin with a slash ("/"). Paths not starting with a slash ("/") + * are assumed to be relative to some base path known to the application or + * consumer. + * + * Users can provide both encoded and decoded path characters. + * Implementations ensure the correct encoding as outlined in getPath(). + * + * @param string $path The path to use with the new instance. + * @return static A new instance with the specified path. + * @throws \InvalidArgumentException for invalid paths. + */ + public function withPath(string $path): UriInterface; + + /** + * Return an instance with the specified query string. + * + * This method MUST retain the state of the current instance, and return + * an instance that contains the specified query string. + * + * Users can provide both encoded and decoded query characters. + * Implementations ensure the correct encoding as outlined in getQuery(). + * + * An empty query string value is equivalent to removing the query string. + * + * @param string $query The query string to use with the new instance. + * @return static A new instance with the specified query string. + * @throws \InvalidArgumentException for invalid query strings. + */ + public function withQuery(string $query): UriInterface; + + /** + * Return an instance with the specified URI fragment. + * + * This method MUST retain the state of the current instance, and return + * an instance that contains the specified URI fragment. + * + * Users can provide both encoded and decoded fragment characters. + * Implementations ensure the correct encoding as outlined in getFragment(). + * + * An empty fragment value is equivalent to removing the fragment. + * + * @param string $fragment The fragment to use with the new instance. + * @return static A new instance with the specified fragment. + */ + public function withFragment(string $fragment): UriInterface; + + /** + * Return the string representation as a URI reference. + * + * Depending on which components of the URI are present, the resulting + * string is either a full URI or relative reference according to RFC 3986, + * Section 4.1. The method concatenates the various components of the URI, + * using the appropriate delimiters: + * + * - If a scheme is present, it MUST be suffixed by ":". + * - If an authority is present, it MUST be prefixed by "//". + * - The path can be concatenated without delimiters. But there are two + * cases where the path has to be adjusted to make the URI reference + * valid as PHP does not allow to throw an exception in __toString(): + * - If the path is rootless and an authority is present, the path MUST + * be prefixed by "/". + * - If the path is starting with more than one "/" and no authority is + * present, the starting slashes MUST be reduced to one. + * - If a query is present, it MUST be prefixed by "?". + * - If a fragment is present, it MUST be prefixed by "#". + * + * @see http://tools.ietf.org/html/rfc3986#section-4.1 + * @return string + */ + public function __toString(): string; +} diff --git a/api/vendor/psr/http-server-handler/LICENSE b/api/vendor/psr/http-server-handler/LICENSE new file mode 100644 index 0000000..b71ec5d --- /dev/null +++ b/api/vendor/psr/http-server-handler/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 PHP Framework Interoperability Group + +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. diff --git a/api/vendor/psr/http-server-handler/README.md b/api/vendor/psr/http-server-handler/README.md new file mode 100644 index 0000000..111a9ed --- /dev/null +++ b/api/vendor/psr/http-server-handler/README.md @@ -0,0 +1,12 @@ +HTTP Server Request Handlers for Middleware +=========================================== + +This repository holds the `RequestHandlerInterface` related to [PSR-15 (HTTP Server Request Handlers)][psr-url]. + +Note that this is not a Server Request Handler implementation of its own. It is merely the interface that describe a Server Request Handler. + +The installable [package][package-url] and [implementations][implementation-url] are listed on Packagist. + +[psr-url]: https://www.php-fig.org/psr/psr-15/ +[package-url]: https://packagist.org/packages/psr/http-server-handler +[implementation-url]: https://packagist.org/providers/psr/http-server-handler-implementation diff --git a/api/vendor/psr/http-server-handler/composer.json b/api/vendor/psr/http-server-handler/composer.json new file mode 100644 index 0000000..c54b2de --- /dev/null +++ b/api/vendor/psr/http-server-handler/composer.json @@ -0,0 +1,36 @@ +{ + "name": "psr/http-server-handler", + "description": "Common interface for HTTP server-side request handler", + "keywords": [ + "psr", + "psr-7", + "psr-15", + "http-interop", + "http", + "server", + "handler", + "request", + "response" + ], + "license": "MIT", + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "require": { + "php": ">=7.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Server\\": "src/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + } +} diff --git a/api/vendor/psr/http-server-handler/src/RequestHandlerInterface.php b/api/vendor/psr/http-server-handler/src/RequestHandlerInterface.php new file mode 100644 index 0000000..83911e2 --- /dev/null +++ b/api/vendor/psr/http-server-handler/src/RequestHandlerInterface.php @@ -0,0 +1,22 @@ +=7.0", + "psr/http-message": "^1.0 || ^2.0", + "psr/http-server-handler": "^1.0" + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Server\\": "src/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + } +} diff --git a/api/vendor/psr/http-server-middleware/src/MiddlewareInterface.php b/api/vendor/psr/http-server-middleware/src/MiddlewareInterface.php new file mode 100644 index 0000000..a6c14f8 --- /dev/null +++ b/api/vendor/psr/http-server-middleware/src/MiddlewareInterface.php @@ -0,0 +1,25 @@ +logger = $logger; + } + + public function doSomething() + { + if ($this->logger) { + $this->logger->info('Doing work'); + } + + try { + $this->doSomethingElse(); + } catch (Exception $exception) { + $this->logger->error('Oh no!', array('exception' => $exception)); + } + + // do something useful + } +} +``` + +You can then pick one of the implementations of the interface to get a logger. + +If you want to implement the interface, you can require this package and +implement `Psr\Log\LoggerInterface` in your code. Please read the +[specification text](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md) +for details. diff --git a/api/vendor/psr/log/composer.json b/api/vendor/psr/log/composer.json new file mode 100644 index 0000000..879fc6f --- /dev/null +++ b/api/vendor/psr/log/composer.json @@ -0,0 +1,26 @@ +{ + "name": "psr/log", + "description": "Common interface for logging libraries", + "keywords": ["psr", "psr-3", "log"], + "homepage": "https://github.com/php-fig/log", + "license": "MIT", + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "require": { + "php": ">=8.0.0" + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + } +} diff --git a/api/vendor/psr/log/src/AbstractLogger.php b/api/vendor/psr/log/src/AbstractLogger.php new file mode 100644 index 0000000..d60a091 --- /dev/null +++ b/api/vendor/psr/log/src/AbstractLogger.php @@ -0,0 +1,15 @@ +logger = $logger; + } +} diff --git a/api/vendor/psr/log/src/LoggerInterface.php b/api/vendor/psr/log/src/LoggerInterface.php new file mode 100644 index 0000000..cb4cf64 --- /dev/null +++ b/api/vendor/psr/log/src/LoggerInterface.php @@ -0,0 +1,98 @@ +log(LogLevel::EMERGENCY, $message, $context); + } + + /** + * Action must be taken immediately. + * + * Example: Entire website down, database unavailable, etc. This should + * trigger the SMS alerts and wake you up. + */ + public function alert(string|\Stringable $message, array $context = []): void + { + $this->log(LogLevel::ALERT, $message, $context); + } + + /** + * Critical conditions. + * + * Example: Application component unavailable, unexpected exception. + */ + public function critical(string|\Stringable $message, array $context = []): void + { + $this->log(LogLevel::CRITICAL, $message, $context); + } + + /** + * Runtime errors that do not require immediate action but should typically + * be logged and monitored. + */ + public function error(string|\Stringable $message, array $context = []): void + { + $this->log(LogLevel::ERROR, $message, $context); + } + + /** + * Exceptional occurrences that are not errors. + * + * Example: Use of deprecated APIs, poor use of an API, undesirable things + * that are not necessarily wrong. + */ + public function warning(string|\Stringable $message, array $context = []): void + { + $this->log(LogLevel::WARNING, $message, $context); + } + + /** + * Normal but significant events. + */ + public function notice(string|\Stringable $message, array $context = []): void + { + $this->log(LogLevel::NOTICE, $message, $context); + } + + /** + * Interesting events. + * + * Example: User logs in, SQL logs. + */ + public function info(string|\Stringable $message, array $context = []): void + { + $this->log(LogLevel::INFO, $message, $context); + } + + /** + * Detailed debug information. + */ + public function debug(string|\Stringable $message, array $context = []): void + { + $this->log(LogLevel::DEBUG, $message, $context); + } + + /** + * Logs with an arbitrary level. + * + * @param mixed $level + * + * @throws \Psr\Log\InvalidArgumentException + */ + abstract public function log($level, string|\Stringable $message, array $context = []): void; +} diff --git a/api/vendor/psr/log/src/NullLogger.php b/api/vendor/psr/log/src/NullLogger.php new file mode 100644 index 0000000..de0561e --- /dev/null +++ b/api/vendor/psr/log/src/NullLogger.php @@ -0,0 +1,26 @@ +logger) { }` + * blocks. + */ +class NullLogger extends AbstractLogger +{ + /** + * Logs with an arbitrary level. + * + * @param mixed[] $context + * + * @throws \Psr\Log\InvalidArgumentException + */ + public function log($level, string|\Stringable $message, array $context = []): void + { + // noop + } +} diff --git a/api/vendor/ralouphie/getallheaders/LICENSE b/api/vendor/ralouphie/getallheaders/LICENSE new file mode 100644 index 0000000..be5540c --- /dev/null +++ b/api/vendor/ralouphie/getallheaders/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Ralph Khattar + +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. diff --git a/api/vendor/ralouphie/getallheaders/README.md b/api/vendor/ralouphie/getallheaders/README.md new file mode 100644 index 0000000..9430d76 --- /dev/null +++ b/api/vendor/ralouphie/getallheaders/README.md @@ -0,0 +1,27 @@ +getallheaders +============= + +PHP `getallheaders()` polyfill. Compatible with PHP >= 5.3. + +[![Build Status](https://travis-ci.org/ralouphie/getallheaders.svg?branch=master)](https://travis-ci.org/ralouphie/getallheaders) +[![Coverage Status](https://coveralls.io/repos/ralouphie/getallheaders/badge.png?branch=master)](https://coveralls.io/r/ralouphie/getallheaders?branch=master) +[![Latest Stable Version](https://poser.pugx.org/ralouphie/getallheaders/v/stable.png)](https://packagist.org/packages/ralouphie/getallheaders) +[![Latest Unstable Version](https://poser.pugx.org/ralouphie/getallheaders/v/unstable.png)](https://packagist.org/packages/ralouphie/getallheaders) +[![License](https://poser.pugx.org/ralouphie/getallheaders/license.png)](https://packagist.org/packages/ralouphie/getallheaders) + + +This is a simple polyfill for [`getallheaders()`](http://www.php.net/manual/en/function.getallheaders.php). + +## Install + +For PHP version **`>= 5.6`**: + +``` +composer require ralouphie/getallheaders +``` + +For PHP version **`< 5.6`**: + +``` +composer require ralouphie/getallheaders "^2" +``` diff --git a/api/vendor/ralouphie/getallheaders/composer.json b/api/vendor/ralouphie/getallheaders/composer.json new file mode 100644 index 0000000..de8ce62 --- /dev/null +++ b/api/vendor/ralouphie/getallheaders/composer.json @@ -0,0 +1,26 @@ +{ + "name": "ralouphie/getallheaders", + "description": "A polyfill for getallheaders.", + "license": "MIT", + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "require": { + "php": ">=5.6" + }, + "require-dev": { + "phpunit/phpunit": "^5 || ^6.5", + "php-coveralls/php-coveralls": "^2.1" + }, + "autoload": { + "files": ["src/getallheaders.php"] + }, + "autoload-dev": { + "psr-4": { + "getallheaders\\Tests\\": "tests/" + } + } +} diff --git a/api/vendor/ralouphie/getallheaders/src/getallheaders.php b/api/vendor/ralouphie/getallheaders/src/getallheaders.php new file mode 100644 index 0000000..c7285a5 --- /dev/null +++ b/api/vendor/ralouphie/getallheaders/src/getallheaders.php @@ -0,0 +1,46 @@ + 'Content-Type', + 'CONTENT_LENGTH' => 'Content-Length', + 'CONTENT_MD5' => 'Content-Md5', + ); + + foreach ($_SERVER as $key => $value) { + if (substr($key, 0, 5) === 'HTTP_') { + $key = substr($key, 5); + if (!isset($copy_server[$key]) || !isset($_SERVER[$key])) { + $key = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', $key)))); + $headers[$key] = $value; + } + } elseif (isset($copy_server[$key])) { + $headers[$copy_server[$key]] = $value; + } + } + + if (!isset($headers['Authorization'])) { + if (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) { + $headers['Authorization'] = $_SERVER['REDIRECT_HTTP_AUTHORIZATION']; + } elseif (isset($_SERVER['PHP_AUTH_USER'])) { + $basic_pass = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : ''; + $headers['Authorization'] = 'Basic ' . base64_encode($_SERVER['PHP_AUTH_USER'] . ':' . $basic_pass); + } elseif (isset($_SERVER['PHP_AUTH_DIGEST'])) { + $headers['Authorization'] = $_SERVER['PHP_AUTH_DIGEST']; + } + } + + return $headers; + } + +} diff --git a/api/vendor/slim/psr7/LICENSE.md b/api/vendor/slim/psr7/LICENSE.md new file mode 100644 index 0000000..2bd2d5a --- /dev/null +++ b/api/vendor/slim/psr7/LICENSE.md @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Slim Framework + +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. + diff --git a/api/vendor/slim/psr7/composer.json b/api/vendor/slim/psr7/composer.json new file mode 100644 index 0000000..b96da46 --- /dev/null +++ b/api/vendor/slim/psr7/composer.json @@ -0,0 +1,76 @@ +{ + "name": "slim/psr7", + "type": "library", + "description": "Strict PSR-7 implementation", + "keywords": ["psr7","psr-7","http"], + "homepage": "https://www.slimframework.com", + "license": "MIT", + "authors": [ + { + "name": "Josh Lockhart", + "email": "hello@joshlockhart.com", + "homepage": "https://joshlockhart.com" + }, + { + "name": "Andrew Smith", + "email": "a.smith@silentworks.co.uk", + "homepage": "https://silentworks.co.uk" + }, + { + "name": "Rob Allen", + "email": "rob@akrabat.com", + "homepage": "https://akrabat.com" + }, + { + "name": "Pierre Berube", + "email": "pierre@lgse.com", + "homepage": "https://www.lgse.com" + } + ], + "require": { + "php": "^8.0", + "fig/http-message-util": "^1.1.5", + "psr/http-factory": "^1.1", + "psr/http-message": "^1.0 || ^2.0", + "ralouphie/getallheaders": "^3.0", + "symfony/polyfill-php80": "^1.29" + }, + "require-dev": { + "ext-json": "*", + "adriansuter/php-autoload-override": "^1.4", + "http-interop/http-factory-tests": "^1.0 || ^2.0", + "php-http/psr7-integration-tests": "^1.4", + "phpspec/prophecy": "^1.19", + "phpspec/prophecy-phpunit": "^2.2", + "phpstan/phpstan": "^2.1", + "phpunit/phpunit": "^9.6 || ^10", + "squizlabs/php_codesniffer": "^3.10" + }, + "provide": { + "psr/http-message-implementation": "^1.0 || ^2.0", + "psr/http-factory-implementation": "^1.0" + }, + "autoload": { + "psr-4": { + "Slim\\Psr7\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "Slim\\Tests\\Psr7\\": "tests" + } + }, + "scripts": { + "test": [ + "@phpunit", + "@phpcs", + "@phpstan" + ], + "phpunit": "@php phpunit", + "phpcs": "@php phpcs", + "phpstan": "@php phpstan --memory-limit=-1" + }, + "config": { + "sort-packages": true + } +} diff --git a/api/vendor/slim/psr7/phpunit.xml.dist b/api/vendor/slim/psr7/phpunit.xml.dist new file mode 100644 index 0000000..a65dc57 --- /dev/null +++ b/api/vendor/slim/psr7/phpunit.xml.dist @@ -0,0 +1,23 @@ + + + + + tests + + + + + + src + + + + + + diff --git a/api/vendor/slim/psr7/src/Cookies.php b/api/vendor/slim/psr7/src/Cookies.php new file mode 100644 index 0000000..044d438 --- /dev/null +++ b/api/vendor/slim/psr7/src/Cookies.php @@ -0,0 +1,218 @@ + '', + 'domain' => null, + 'hostonly' => null, + 'path' => null, + 'expires' => null, + 'secure' => false, + 'httponly' => false, + 'samesite' => null + ]; + + /** + * @param array $cookies + */ + public function __construct(array $cookies = []) + { + $this->requestCookies = $cookies; + } + + /** + * Set default cookie properties + * + * @param array $settings + * + * @return static + */ + public function setDefaults(array $settings): self + { + $this->defaults = array_replace($this->defaults, $settings); + + return $this; + } + + /** + * Get cookie + * + * @param string $name + * @param string|array|null $default + * @return mixed|null + */ + public function get(string $name, $default = null) + { + return array_key_exists($name, $this->requestCookies) ? $this->requestCookies[$name] : $default; + } + + /** + * Set cookie + * + * @param string $name + * @param string|array $value + * @return static + */ + public function set(string $name, $value): self + { + if (!is_array($value)) { + $value = ['value' => $value]; + } + + $this->responseCookies[$name] = array_replace($this->defaults, $value); + + return $this; + } + + /** + * Convert all response cookies into an associate array of header values + * + * @return array + */ + public function toHeaders(): array + { + $headers = []; + + foreach ($this->responseCookies as $name => $properties) { + $headers[] = $this->toHeader($name, $properties); + } + + return $headers; + } + + /** + * Convert to `Set-Cookie` header + * + * @param string $name Cookie name + * @param array $properties Cookie properties + * + * @return string + */ + protected function toHeader(string $name, array $properties): string + { + $result = urlencode($name) . '=' . urlencode($properties['value']); + + if (isset($properties['domain'])) { + $result .= '; domain=' . $properties['domain']; + } + + if (isset($properties['path'])) { + $result .= '; path=' . $properties['path']; + } + + if (isset($properties['expires'])) { + if (is_string($properties['expires'])) { + $timestamp = strtotime($properties['expires']); + } else { + $timestamp = (int) $properties['expires']; + } + if ($timestamp && $timestamp !== 0) { + $result .= '; expires=' . gmdate('D, d-M-Y H:i:s e', $timestamp); + } + } + + if (isset($properties['secure']) && $properties['secure']) { + $result .= '; secure'; + } + + if (isset($properties['hostonly']) && $properties['hostonly']) { + $result .= '; HostOnly'; + } + + if (isset($properties['httponly']) && $properties['httponly']) { + $result .= '; HttpOnly'; + } + + if ( + isset($properties['samesite']) + && in_array(strtolower($properties['samesite']), ['lax', 'strict', 'none'], true) + ) { + // While strtolower is needed for correct comparison, the RFC doesn't care about case + $result .= '; SameSite=' . $properties['samesite']; + } + + return $result; + } + + /** + * Parse cookie values from header value + * + * Returns an associative array of cookie names and values + * + * @param string|array $header + * + * @return array + */ + public static function parseHeader($header): array + { + if (is_array($header)) { + $header = $header[0] ?? ''; + } + + if (!is_string($header)) { + throw new InvalidArgumentException('Cannot parse Cookie data. Header value must be a string.'); + } + + $header = rtrim($header, "\r\n"); + $pieces = preg_split('@[;]\s*@', $header); + $cookies = []; + + if (is_array($pieces)) { + foreach ($pieces as $cookie) { + $cookie = explode('=', $cookie, 2); + + if (count($cookie) === 2) { + $key = urldecode($cookie[0]); + $value = urldecode($cookie[1]); + + if (!isset($cookies[$key])) { + $cookies[$key] = $value; + } + } + } + } + + return $cookies; + } +} diff --git a/api/vendor/slim/psr7/src/Environment.php b/api/vendor/slim/psr7/src/Environment.php new file mode 100644 index 0000000..55f187b --- /dev/null +++ b/api/vendor/slim/psr7/src/Environment.php @@ -0,0 +1,55 @@ + 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', + 'HTTP_ACCEPT_CHARSET' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.3', + 'HTTP_ACCEPT_LANGUAGE' => 'en-US,en;q=0.8', + 'HTTP_USER_AGENT' => 'Slim Framework', + 'QUERY_STRING' => '', + 'REMOTE_ADDR' => '127.0.0.1', + 'REQUEST_METHOD' => 'GET', + 'REQUEST_SCHEME' => $scheme, + 'REQUEST_TIME' => time(), + 'REQUEST_TIME_FLOAT' => microtime(true), + 'REQUEST_URI' => '', + 'SCRIPT_NAME' => '', + 'SERVER_NAME' => 'localhost', + 'SERVER_PORT' => $port, + 'SERVER_PROTOCOL' => 'HTTP/1.1', + ], $data); + } +} diff --git a/api/vendor/slim/psr7/src/Factory/RequestFactory.php b/api/vendor/slim/psr7/src/Factory/RequestFactory.php new file mode 100644 index 0000000..e825ee3 --- /dev/null +++ b/api/vendor/slim/psr7/src/Factory/RequestFactory.php @@ -0,0 +1,59 @@ +streamFactory = $streamFactory ?? new StreamFactory(); + $this->uriFactory = $uriFactory ?? new UriFactory(); + } + + /** + * {@inheritdoc} + */ + public function createRequest(string $method, $uri): RequestInterface + { + if (is_string($uri)) { + $uri = $this->uriFactory->createUri($uri); + } + + if (!$uri instanceof UriInterface) { + throw new InvalidArgumentException( + 'Parameter 2 of RequestFactory::createRequest() must be a string or a compatible UriInterface.' + ); + } + + $body = $this->streamFactory->createStream(); + + return new Request($method, $uri, new Headers(), [], [], $body); + } +} diff --git a/api/vendor/slim/psr7/src/Factory/ResponseFactory.php b/api/vendor/slim/psr7/src/Factory/ResponseFactory.php new file mode 100644 index 0000000..c1a23a7 --- /dev/null +++ b/api/vendor/slim/psr7/src/Factory/ResponseFactory.php @@ -0,0 +1,35 @@ +withStatus($code, $reasonPhrase); + } + + return $res; + } +} diff --git a/api/vendor/slim/psr7/src/Factory/ServerRequestFactory.php b/api/vendor/slim/psr7/src/Factory/ServerRequestFactory.php new file mode 100644 index 0000000..5d1225d --- /dev/null +++ b/api/vendor/slim/psr7/src/Factory/ServerRequestFactory.php @@ -0,0 +1,111 @@ +streamFactory = $streamFactory ?? new StreamFactory(); + $this->uriFactory = $uriFactory ?? new UriFactory(); + } + + /** + * {@inheritdoc} + */ + public function createServerRequest(string $method, $uri, array $serverParams = []): ServerRequestInterface + { + if (is_string($uri)) { + $uri = $this->uriFactory->createUri($uri); + } + + if (!$uri instanceof UriInterface) { + throw new InvalidArgumentException('URI must either be string or instance of ' . UriInterface::class); + } + + $body = $this->streamFactory->createStream(); + $headers = new Headers(); + $cookies = []; + + if (!empty($serverParams)) { + $headers = Headers::createFromGlobals(); + $cookies = Cookies::parseHeader($headers->getHeader('Cookie', [])); + } + + return new Request($method, $uri, $headers, $cookies, $serverParams, $body); + } + + /** + * Create new ServerRequest from environment. + * + * @internal This method is not part of PSR-17 + * + * @return Request + */ + public static function createFromGlobals(): Request + { + /** @var string $method */ + $method = $_SERVER['REQUEST_METHOD'] ?? 'GET'; + $uri = (new UriFactory())->createFromGlobals($_SERVER); + + $headers = Headers::createFromGlobals(); + $cookies = Cookies::parseHeader($headers->getHeader('Cookie', [])); + + // Cache the php://input stream as it cannot be re-read + $cacheResource = fopen('php://temp', 'wb+'); + $cache = $cacheResource ? new Stream($cacheResource) : null; + + $body = (new StreamFactory())->createStreamFromFile('php://input', 'r', $cache); + $uploadedFiles = UploadedFile::createFromGlobals($_SERVER); + + $request = new Request($method, $uri, $headers, $cookies, $_SERVER, $body, $uploadedFiles); + $contentTypes = $request->getHeader('Content-Type'); + + $parsedContentType = ''; + foreach ($contentTypes as $contentType) { + $fragments = explode(';', $contentType); + $parsedContentType = current($fragments); + } + + $contentTypesWithParsedBodies = ['application/x-www-form-urlencoded', 'multipart/form-data']; + if ($method === 'POST' && in_array($parsedContentType, $contentTypesWithParsedBodies)) { + return $request->withParsedBody($_POST); + } + + return $request; + } +} diff --git a/api/vendor/slim/psr7/src/Factory/StreamFactory.php b/api/vendor/slim/psr7/src/Factory/StreamFactory.php new file mode 100644 index 0000000..04d22a1 --- /dev/null +++ b/api/vendor/slim/psr7/src/Factory/StreamFactory.php @@ -0,0 +1,95 @@ +createStreamFromResource($resource); + } + + /** + * {@inheritdoc} + */ + public function createStreamFromFile( + string $filename, + string $mode = 'r', + ?StreamInterface $cache = null + ): StreamInterface { + set_error_handler( + static function (int $errno, string $errstr) use ($filename, $mode): void { + throw new RuntimeException( + "Unable to open $filename using mode $mode: $errstr", + $errno + ); + } + ); + + try { + $resource = fopen($filename, $mode); + } catch (ValueError $exception) { + throw new RuntimeException("Unable to open $filename using mode $mode: " . $exception->getMessage()); + } finally { + restore_error_handler(); + } + + if (!is_resource($resource)) { + throw new RuntimeException( + "StreamFactory::createStreamFromFile() could not create resource from file `$filename`" + ); + } + + return new Stream($resource, $cache); + } + + /** + * {@inheritdoc} + */ + public function createStreamFromResource($resource, ?StreamInterface $cache = null): StreamInterface + { + if (!is_resource($resource)) { + throw new InvalidArgumentException( + 'Parameter 1 of StreamFactory::createStreamFromResource() must be a resource.' + ); + } + + return new Stream($resource, $cache); + } +} diff --git a/api/vendor/slim/psr7/src/Factory/UploadedFileFactory.php b/api/vendor/slim/psr7/src/Factory/UploadedFileFactory.php new file mode 100644 index 0000000..5699e96 --- /dev/null +++ b/api/vendor/slim/psr7/src/Factory/UploadedFileFactory.php @@ -0,0 +1,47 @@ +getMetadata('uri'); + + if (!is_string($file) || !$stream->isReadable()) { + throw new InvalidArgumentException('File is not readable.'); + } + + if ($size === null) { + $size = $stream->getSize(); + } + + return new UploadedFile($stream, $clientFilename, $clientMediaType, $size, $error); + } +} diff --git a/api/vendor/slim/psr7/src/Factory/UriFactory.php b/api/vendor/slim/psr7/src/Factory/UriFactory.php new file mode 100644 index 0000000..74ab377 --- /dev/null +++ b/api/vendor/slim/psr7/src/Factory/UriFactory.php @@ -0,0 +1,113 @@ + 1) { + $queryString = parse_url('https://www.example.com' . $globals['REQUEST_URI'], PHP_URL_QUERY) ?? ''; + } + } + + // Build Uri and return + return new Uri($scheme, $host, $port, $requestUri, $queryString, '', $username, $password); + } +} diff --git a/api/vendor/slim/psr7/src/Header.php b/api/vendor/slim/psr7/src/Header.php new file mode 100644 index 0000000..ef9e196 --- /dev/null +++ b/api/vendor/slim/psr7/src/Header.php @@ -0,0 +1,63 @@ +originalName = $originalName; + $this->normalizedName = $normalizedName; + $this->values = $values; + } + + public function getOriginalName(): string + { + return $this->originalName; + } + + public function getNormalizedName(): string + { + return $this->normalizedName; + } + + public function addValue(string $value): self + { + $this->values[] = $value; + + return $this; + } + + public function addValues(array|string $values): self + { + if (is_string($values)) { + return $this->addValue($values); + } + + $this->values = array_merge($this->values, $values); + + return $this; + } + + public function getValues(): array + { + return $this->values; + } +} diff --git a/api/vendor/slim/psr7/src/Headers.php b/api/vendor/slim/psr7/src/Headers.php new file mode 100644 index 0000000..cc345dd --- /dev/null +++ b/api/vendor/slim/psr7/src/Headers.php @@ -0,0 +1,318 @@ +globals = $globals ?? $_SERVER; + $this->setHeaders($headers); + } + + /** + * {@inheritdoc} + */ + public function addHeader($name, $value): HeadersInterface + { + [$values, $originalName, $normalizedName] = $this->prepareHeader($name, $value); + + if (isset($this->headers[$normalizedName])) { + $header = $this->headers[$normalizedName]; + $header->addValues($values); + } else { + $this->headers[$normalizedName] = new Header($originalName, $normalizedName, $values); + } + + return $this; + } + + /** + * {@inheritdoc} + */ + public function removeHeader(string $name): HeadersInterface + { + $name = $this->normalizeHeaderName($name); + unset($this->headers[$name]); + return $this; + } + + /** + * {@inheritdoc} + */ + public function getHeader(string $name, $default = []): array + { + $name = $this->normalizeHeaderName($name); + + if (isset($this->headers[$name])) { + $header = $this->headers[$name]; + return $header->getValues(); + } + + if (empty($default)) { + return $default; + } + + $this->validateHeader($name, $default); + return $this->trimHeaderValue($default); + } + + /** + * {@inheritdoc} + */ + public function setHeader($name, $value): HeadersInterface + { + [$values, $originalName, $normalizedName] = $this->prepareHeader($name, $value); + + // Ensure we preserve original case if the header already exists in the stack + if (isset($this->headers[$normalizedName])) { + $existingHeader = $this->headers[$normalizedName]; + $originalName = $existingHeader->getOriginalName(); + } + + $this->headers[$normalizedName] = new Header($originalName, $normalizedName, $values); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function setHeaders(array $headers): HeadersInterface + { + $this->headers = []; + + foreach ($this->parseAuthorizationHeader($headers) as $name => $value) { + $this->addHeader($name, $value); + } + + return $this; + } + + /** + * {@inheritdoc} + */ + public function hasHeader(string $name): bool + { + $name = $this->normalizeHeaderName($name); + return isset($this->headers[$name]); + } + + /** + * {@inheritdoc} + */ + public function getHeaders(bool $originalCase = false): array + { + $headers = []; + + foreach ($this->headers as $header) { + $name = $originalCase ? $header->getOriginalName() : $header->getNormalizedName(); + $headers[$name] = $header->getValues(); + } + + return $headers; + } + + /** + * @param string $name + * @param bool $preserveCase + * @return string + */ + protected function normalizeHeaderName(string $name, bool $preserveCase = false): string + { + $name = strtr($name, '_', '-'); + + if (!$preserveCase) { + $name = strtolower($name); + } + + if (strpos(strtolower($name), 'http-') === 0) { + $name = substr($name, 5); + } + + return $name; + } + + /** + * Parse incoming headers and determine Authorization header from original headers + * + * @param array $headers + * @return array + */ + protected function parseAuthorizationHeader(array $headers): array + { + $hasAuthorizationHeader = false; + foreach ($headers as $name => $value) { + if (strtolower((string) $name) === 'authorization') { + $hasAuthorizationHeader = true; + break; + } + } + + if (!$hasAuthorizationHeader) { + if (isset($this->globals['REDIRECT_HTTP_AUTHORIZATION'])) { + $headers['Authorization'] = $this->globals['REDIRECT_HTTP_AUTHORIZATION']; + } elseif (isset($this->globals['PHP_AUTH_USER'])) { + $pw = $this->globals['PHP_AUTH_PW'] ?? ''; + $headers['Authorization'] = 'Basic ' . base64_encode($this->globals['PHP_AUTH_USER'] . ':' . $pw); + } elseif (isset($this->globals['PHP_AUTH_DIGEST'])) { + $headers['Authorization'] = $this->globals['PHP_AUTH_DIGEST']; + } + } + + return $headers; + } + + /** + * @param array|string $value + * + * @return array + */ + protected function trimHeaderValue($value): array + { + $items = is_array($value) ? $value : [$value]; + $result = []; + foreach ($items as $item) { + $result[] = trim((string) $item, " \t"); + } + return $result; + } + + /** + * @param string $name + * @param array|string $value + * + * @throws InvalidArgumentException + * + * @return array + */ + protected function prepareHeader($name, $value): array + { + $this->validateHeader($name, $value); + $values = $this->trimHeaderValue($value); + $originalName = $this->normalizeHeaderName($name, true); + $normalizedName = $this->normalizeHeaderName($name); + return [$values, $originalName, $normalizedName]; + } + + /** + * Make sure the header complies with RFC 7230. + * + * Header names must be a non-empty string consisting of token characters. + * + * Header values must be strings consisting of visible characters with all optional + * leading and trailing whitespace stripped. This method will always strip such + * optional whitespace. Note that the method does not allow folding whitespace within + * the values as this was deprecated for almost all instances by the RFC. + * + * header-field = field-name ":" OWS field-value OWS + * field-name = 1*( "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." / "^" + * / "_" / "`" / "|" / "~" / %x30-39 / ( %x41-5A / %x61-7A ) ) + * OWS = *( SP / HTAB ) + * field-value = *( ( %x21-7E / %x80-FF ) [ 1*( SP / HTAB ) ( %x21-7E / %x80-FF ) ] ) + * + * @see https://tools.ietf.org/html/rfc7230#section-3.2.4 + * + * @param string $name + * @param array|string $value + * + * @throws InvalidArgumentException + */ + protected function validateHeader($name, $value): void + { + $this->validateHeaderName($name); + $this->validateHeaderValue($value); + } + + /** + * @param mixed $name + * + * @throws InvalidArgumentException + */ + protected function validateHeaderName($name): void + { + if (!is_string($name) || preg_match("@^[!#$%&'*+.^_`|~0-9A-Za-z-]+$@D", $name) !== 1) { + throw new InvalidArgumentException('Header name must be an RFC 7230 compatible string.'); + } + } + + /** + * @param mixed $value + * + * @throws InvalidArgumentException + */ + protected function validateHeaderValue($value): void + { + $items = is_array($value) ? $value : [$value]; + + if (empty($items)) { + throw new InvalidArgumentException( + 'Header values must be a string or an array of strings, empty array given.' + ); + } + + $pattern = "@^[ \t\x21-\x7E\x80-\xFF]*$@D"; + foreach ($items as $item) { + $hasInvalidType = !is_numeric($item) && !is_string($item); + $rejected = $hasInvalidType || preg_match($pattern, (string) $item) !== 1; + if ($rejected) { + throw new InvalidArgumentException( + 'Header values must be RFC 7230 compatible strings.' + ); + } + } + } + + /** + * @return static + */ + public static function createFromGlobals() + { + $headers = null; + + if (function_exists('getallheaders')) { + $headers = getallheaders(); + } + + if (!is_array($headers)) { + $headers = []; + } + + return new static($headers); + } +} diff --git a/api/vendor/slim/psr7/src/Interfaces/HeadersInterface.php b/api/vendor/slim/psr7/src/Interfaces/HeadersInterface.php new file mode 100644 index 0000000..3f486f1 --- /dev/null +++ b/api/vendor/slim/psr7/src/Interfaces/HeadersInterface.php @@ -0,0 +1,90 @@ + true, + '1.1' => true, + '2.0' => true, + '2' => true, + ]; + + /** + * @var HeadersInterface + */ + protected $headers; + + /** + * @var StreamInterface + */ + protected $body; + + /** + * Disable magic setter to ensure immutability + * + * @param string $name The property name + * @param mixed $value The property value + * + * @return void + */ + public function __set($name, $value): void + { + // Do nothing + } + + /** + * {@inheritdoc} + */ + public function getProtocolVersion(): string + { + return $this->protocolVersion; + } + + /** + * @return static + * {@inheritdoc} + */ + public function withProtocolVersion($version): MessageInterface + { + if (!isset(self::$validProtocolVersions[$version])) { + throw new InvalidArgumentException( + 'Invalid HTTP version. Must be one of: ' + . implode(', ', array_keys(self::$validProtocolVersions)) + ); + } + + $clone = clone $this; + $clone->protocolVersion = $version; + + return $clone; + } + + /** + * {@inheritdoc} + */ + public function getHeaders(): array + { + return $this->headers->getHeaders(true); + } + + /** + * {@inheritdoc} + */ + public function hasHeader($name): bool + { + return $this->headers->hasHeader($name); + } + + /** + * {@inheritdoc} + */ + public function getHeader($name): array + { + return $this->headers->getHeader($name); + } + + /** + * {@inheritdoc} + */ + public function getHeaderLine($name): string + { + $values = $this->headers->getHeader($name); + return implode(',', $values); + } + + /** + * @return static + * {@inheritdoc} + */ + public function withHeader($name, $value): MessageInterface + { + $clone = clone $this; + $clone->headers->setHeader($name, $value); + + if ($this instanceof Response && $this->body instanceof NonBufferedBody) { + header(sprintf('%s: %s', $name, $clone->getHeaderLine($name))); + } + + return $clone; + } + + /** + * @return static + * {@inheritdoc} + */ + public function withAddedHeader($name, $value): MessageInterface + { + $clone = clone $this; + $clone->headers->addHeader($name, $value); + + if ($this instanceof Response && $this->body instanceof NonBufferedBody) { + header(sprintf('%s: %s', $name, $clone->getHeaderLine($name))); + } + + return $clone; + } + + /** + * @return static + * {@inheritdoc} + */ + public function withoutHeader($name): MessageInterface + { + $clone = clone $this; + $clone->headers->removeHeader($name); + + if ($this instanceof Response && $this->body instanceof NonBufferedBody) { + header_remove($name); + } + + return $clone; + } + + /** + * {@inheritdoc} + */ + public function getBody(): StreamInterface + { + return $this->body; + } + + /** + * @return static + * {@inheritdoc} + */ + public function withBody(StreamInterface $body): MessageInterface + { + $clone = clone $this; + $clone->body = $body; + + return $clone; + } +} diff --git a/api/vendor/slim/psr7/src/NonBufferedBody.php b/api/vendor/slim/psr7/src/NonBufferedBody.php new file mode 100644 index 0000000..ad22c2d --- /dev/null +++ b/api/vendor/slim/psr7/src/NonBufferedBody.php @@ -0,0 +1,153 @@ +method = $this->filterMethod($method); + $this->uri = $uri; + $this->headers = $headers; + $this->cookies = $cookies; + $this->serverParams = $serverParams; + $this->attributes = []; + $this->body = $body; + $this->uploadedFiles = $uploadedFiles; + + if (isset($serverParams['SERVER_PROTOCOL'])) { + $this->protocolVersion = str_replace('HTTP/', '', $serverParams['SERVER_PROTOCOL']); + } + + if (!$this->headers->hasHeader('Host') || $this->uri->getHost() !== '') { + $this->headers->setHeader('Host', $this->uri->getHost()); + } + } + + /** + * This method is applied to the cloned object after PHP performs an initial shallow-copy. + * This method completes a deep-copy by creating new objects for the cloned object's internal reference pointers. + */ + public function __clone() + { + $this->headers = clone $this->headers; + $this->body = clone $this->body; + } + + /** + * {@inheritdoc} + */ + public function getMethod(): string + { + return $this->method; + } + + /** + * {@inheritdoc} + * @return static + */ + public function withMethod($method): RequestInterface + { + $method = $this->filterMethod($method); + $clone = clone $this; + $clone->method = $method; + + return $clone; + } + + /** + * Validate the HTTP method + * + * @param string $method + * + * @return string + * + * @throws InvalidArgumentException on invalid HTTP method. + */ + protected function filterMethod($method): string + { + /** @var mixed $method */ + if (!is_string($method)) { + throw new InvalidArgumentException(sprintf( + 'Unsupported HTTP method; must be a string, received %s', + (is_object($method) ? get_class($method) : gettype($method)) + )); + } + + if (preg_match("/^[!#$%&'*+.^_`|~0-9a-z-]+$/i", $method) !== 1) { + throw new InvalidArgumentException(sprintf( + 'Unsupported HTTP method "%s" provided', + $method + )); + } + + return $method; + } + + /** + * {@inheritdoc} + */ + public function getRequestTarget(): string + { + if ($this->requestTarget) { + return $this->requestTarget; + } + + if ($this->uri === null) { + return '/'; + } + + $path = $this->uri->getPath(); + $path = '/' . ltrim($path, '/'); + + $query = $this->uri->getQuery(); + if ($query) { + $path .= '?' . $query; + } + + return $path; + } + + /** + * {@inheritdoc} + * @return static + */ + public function withRequestTarget($requestTarget): RequestInterface + { + if (!is_string($requestTarget) || preg_match('#\s#', $requestTarget)) { + throw new InvalidArgumentException( + 'Invalid request target provided; must be a string and cannot contain whitespace' + ); + } + + $clone = clone $this; + $clone->requestTarget = $requestTarget; + + return $clone; + } + + /** + * {@inheritdoc} + */ + public function getUri(): UriInterface + { + return $this->uri; + } + + /** + * {@inheritdoc} + * @return static + */ + public function withUri(UriInterface $uri, $preserveHost = false): RequestInterface + { + $clone = clone $this; + $clone->uri = $uri; + + if (!$preserveHost && $uri->getHost() !== '') { + $clone->headers->setHeader('Host', $uri->getHost()); + return $clone; + } + + if (($uri->getHost() !== '' && !$this->hasHeader('Host') || $this->getHeaderLine('Host') === '')) { + $clone->headers->setHeader('Host', $uri->getHost()); + return $clone; + } + + return $clone; + } + + /** + * {@inheritdoc} + */ + public function getCookieParams(): array + { + return $this->cookies; + } + + /** + * {@inheritdoc} + * @return static + */ + public function withCookieParams(array $cookies): ServerRequestInterface + { + $clone = clone $this; + $clone->cookies = $cookies; + + return $clone; + } + + /** + * {@inheritdoc} + */ + public function getQueryParams(): array + { + if (is_array($this->queryParams)) { + return $this->queryParams; + } + + if ($this->uri === null) { + return []; + } + + // Decode URL data + parse_str($this->uri->getQuery(), $this->queryParams); + + return is_array($this->queryParams) ? $this->queryParams : []; + } + + /** + * {@inheritdoc} + * @return static + */ + public function withQueryParams(array $query): ServerRequestInterface + { + $clone = clone $this; + $clone->queryParams = $query; + + return $clone; + } + + /** + * {@inheritdoc} + */ + public function getUploadedFiles(): array + { + return $this->uploadedFiles; + } + + /** + * {@inheritdoc} + * @return static + */ + public function withUploadedFiles(array $uploadedFiles): ServerRequestInterface + { + $clone = clone $this; + $clone->uploadedFiles = $uploadedFiles; + + return $clone; + } + + /** + * {@inheritdoc} + */ + public function getServerParams(): array + { + return $this->serverParams; + } + + /** + * {@inheritdoc} + */ + public function getAttributes(): array + { + return $this->attributes; + } + + /** + * {@inheritdoc} + * @return mixed + */ + public function getAttribute($name, $default = null) + { + return $this->attributes[$name] ?? $default; + } + + /** + * {@inheritdoc} + * @return static + */ + public function withAttribute($name, $value): ServerRequestInterface + { + $clone = clone $this; + $clone->attributes[$name] = $value; + + return $clone; + } + + /** + * {@inheritdoc} + * @return static + */ + public function withoutAttribute($name): ServerRequestInterface + { + $clone = clone $this; + + unset($clone->attributes[$name]); + + return $clone; + } + + /** + * {@inheritdoc} + */ + public function getParsedBody() + { + return $this->parsedBody; + } + + /** + * {@inheritdoc} + * @return static + */ + public function withParsedBody($data): ServerRequestInterface + { + /** @var mixed $data */ + if (!is_null($data) && !is_object($data) && !is_array($data)) { + throw new InvalidArgumentException('Parsed body value must be an array, an object, or null'); + } + + $clone = clone $this; + $clone->parsedBody = $data; + + return $clone; + } +} diff --git a/api/vendor/slim/psr7/src/Response.php b/api/vendor/slim/psr7/src/Response.php new file mode 100644 index 0000000..980e3b5 --- /dev/null +++ b/api/vendor/slim/psr7/src/Response.php @@ -0,0 +1,216 @@ + 'Continue', + StatusCodeInterface::STATUS_SWITCHING_PROTOCOLS => 'Switching Protocols', + StatusCodeInterface::STATUS_PROCESSING => 'Processing', + + // Successful 2xx + StatusCodeInterface::STATUS_OK => 'OK', + StatusCodeInterface::STATUS_CREATED => 'Created', + StatusCodeInterface::STATUS_ACCEPTED => 'Accepted', + StatusCodeInterface::STATUS_NON_AUTHORITATIVE_INFORMATION => 'Non-Authoritative Information', + StatusCodeInterface::STATUS_NO_CONTENT => 'No Content', + StatusCodeInterface::STATUS_RESET_CONTENT => 'Reset Content', + StatusCodeInterface::STATUS_PARTIAL_CONTENT => 'Partial Content', + StatusCodeInterface::STATUS_MULTI_STATUS => 'Multi-Status', + StatusCodeInterface::STATUS_ALREADY_REPORTED => 'Already Reported', + StatusCodeInterface::STATUS_IM_USED => 'IM Used', + + // Redirection 3xx + StatusCodeInterface::STATUS_MULTIPLE_CHOICES => 'Multiple Choices', + StatusCodeInterface::STATUS_MOVED_PERMANENTLY => 'Moved Permanently', + StatusCodeInterface::STATUS_FOUND => 'Found', + StatusCodeInterface::STATUS_SEE_OTHER => 'See Other', + StatusCodeInterface::STATUS_NOT_MODIFIED => 'Not Modified', + StatusCodeInterface::STATUS_USE_PROXY => 'Use Proxy', + StatusCodeInterface::STATUS_RESERVED => '(Unused)', + StatusCodeInterface::STATUS_TEMPORARY_REDIRECT => 'Temporary Redirect', + StatusCodeInterface::STATUS_PERMANENT_REDIRECT => 'Permanent Redirect', + + // Client Error 4xx + StatusCodeInterface::STATUS_BAD_REQUEST => 'Bad Request', + StatusCodeInterface::STATUS_UNAUTHORIZED => 'Unauthorized', + StatusCodeInterface::STATUS_PAYMENT_REQUIRED => 'Payment Required', + StatusCodeInterface::STATUS_FORBIDDEN => 'Forbidden', + StatusCodeInterface::STATUS_NOT_FOUND => 'Not Found', + StatusCodeInterface::STATUS_METHOD_NOT_ALLOWED => 'Method Not Allowed', + StatusCodeInterface::STATUS_NOT_ACCEPTABLE => 'Not Acceptable', + StatusCodeInterface::STATUS_PROXY_AUTHENTICATION_REQUIRED => 'Proxy Authentication Required', + StatusCodeInterface::STATUS_REQUEST_TIMEOUT => 'Request Timeout', + StatusCodeInterface::STATUS_CONFLICT => 'Conflict', + StatusCodeInterface::STATUS_GONE => 'Gone', + StatusCodeInterface::STATUS_LENGTH_REQUIRED => 'Length Required', + StatusCodeInterface::STATUS_PRECONDITION_FAILED => 'Precondition Failed', + StatusCodeInterface::STATUS_PAYLOAD_TOO_LARGE => 'Request Entity Too Large', + StatusCodeInterface::STATUS_URI_TOO_LONG => 'Request-URI Too Long', + StatusCodeInterface::STATUS_UNSUPPORTED_MEDIA_TYPE => 'Unsupported Media Type', + StatusCodeInterface::STATUS_RANGE_NOT_SATISFIABLE => 'Requested Range Not Satisfiable', + StatusCodeInterface::STATUS_EXPECTATION_FAILED => 'Expectation Failed', + StatusCodeInterface::STATUS_IM_A_TEAPOT => 'I\'m a teapot', + StatusCodeInterface::STATUS_MISDIRECTED_REQUEST => 'Misdirected Request', + StatusCodeInterface::STATUS_UNPROCESSABLE_ENTITY => 'Unprocessable Entity', + StatusCodeInterface::STATUS_LOCKED => 'Locked', + StatusCodeInterface::STATUS_FAILED_DEPENDENCY => 'Failed Dependency', + StatusCodeInterface::STATUS_UPGRADE_REQUIRED => 'Upgrade Required', + StatusCodeInterface::STATUS_PRECONDITION_REQUIRED => 'Precondition Required', + StatusCodeInterface::STATUS_TOO_MANY_REQUESTS => 'Too Many Requests', + StatusCodeInterface::STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE => 'Request Header Fields Too Large', + 444 => 'Connection Closed Without Response', + StatusCodeInterface::STATUS_UNAVAILABLE_FOR_LEGAL_REASONS => 'Unavailable For Legal Reasons', + 499 => 'Client Closed Request', + + // Server Error 5xx + StatusCodeInterface::STATUS_INTERNAL_SERVER_ERROR => 'Internal Server Error', + StatusCodeInterface::STATUS_NOT_IMPLEMENTED => 'Not Implemented', + StatusCodeInterface::STATUS_BAD_GATEWAY => 'Bad Gateway', + StatusCodeInterface::STATUS_SERVICE_UNAVAILABLE => 'Service Unavailable', + StatusCodeInterface::STATUS_GATEWAY_TIMEOUT => 'Gateway Timeout', + StatusCodeInterface::STATUS_VERSION_NOT_SUPPORTED => 'HTTP Version Not Supported', + StatusCodeInterface::STATUS_VARIANT_ALSO_NEGOTIATES => 'Variant Also Negotiates', + StatusCodeInterface::STATUS_INSUFFICIENT_STORAGE => 'Insufficient Storage', + StatusCodeInterface::STATUS_LOOP_DETECTED => 'Loop Detected', + StatusCodeInterface::STATUS_NOT_EXTENDED => 'Not Extended', + StatusCodeInterface::STATUS_NETWORK_AUTHENTICATION_REQUIRED => 'Network Authentication Required', + 599 => 'Network Connect Timeout Error', + ]; + + /** + * @param int $status The response status code. + * @param HeadersInterface|null $headers The response headers. + * @param StreamInterface|null $body The response body. + */ + public function __construct( + int $status = StatusCodeInterface::STATUS_OK, + ?HeadersInterface $headers = null, + ?StreamInterface $body = null + ) { + $this->status = $this->filterStatus($status); + $this->headers = $headers ?: new Headers([], []); + $this->body = $body ?: (new StreamFactory())->createStream(); + } + + /** + * This method is applied to the cloned object after PHP performs an initial shallow-copy. + * This method completes a deep-copy by creating new objects for the cloned object's internal reference pointers. + */ + public function __clone() + { + $this->headers = clone $this->headers; + } + + /** + * {@inheritdoc} + */ + public function getStatusCode(): int + { + return $this->status; + } + + /** + * {@inheritdoc} + * @return static + */ + public function withStatus($code, $reasonPhrase = ''): ResponseInterface + { + $code = $this->filterStatus($code); + $reasonPhrase = $this->filterReasonPhrase($reasonPhrase); + + $clone = clone $this; + $clone->status = $code; + $clone->reasonPhrase = $reasonPhrase; + + return $clone; + } + + /** + * {@inheritdoc} + */ + public function getReasonPhrase(): string + { + if ($this->reasonPhrase !== '') { + return $this->reasonPhrase; + } + + if (isset(static::$messages[$this->status])) { + return static::$messages[$this->status]; + } + + return ''; + } + + /** + * Filter HTTP status code. + * + * @param int $status HTTP status code. + * + * @return int + * + * @throws InvalidArgumentException If an invalid HTTP status code is provided. + */ + protected function filterStatus($status): int + { + if (!is_integer($status) || $status < StatusCodeInterface::STATUS_CONTINUE || $status > 599) { + throw new InvalidArgumentException('Invalid HTTP status code.'); + } + + return $status; + } + + /** + * Filter Reason Phrase + * + * @param mixed $reasonPhrase + * + * @return string + * + * @throws InvalidArgumentException + */ + protected function filterReasonPhrase($reasonPhrase = ''): string + { + if (is_object($reasonPhrase) && method_exists($reasonPhrase, '__toString')) { + $reasonPhrase = (string) $reasonPhrase; + } + + if (!is_string($reasonPhrase)) { + throw new InvalidArgumentException('Response reason phrase must be a string.'); + } + + if (strpos($reasonPhrase, "\r") !== false || strpos($reasonPhrase, "\n") !== false) { + throw new InvalidArgumentException( + 'Reason phrase contains one of the following prohibited characters: \r \n' + ); + } + + return $reasonPhrase; + } +} diff --git a/api/vendor/slim/psr7/src/Stream.php b/api/vendor/slim/psr7/src/Stream.php new file mode 100644 index 0000000..0431ff0 --- /dev/null +++ b/api/vendor/slim/psr7/src/Stream.php @@ -0,0 +1,396 @@ +attach($stream); + + if ($cache && (!$cache->isSeekable() || !$cache->isWritable())) { + throw new RuntimeException('Cache stream must be seekable and writable'); + } + $this->cache = $cache; + } + + /** + * {@inheritdoc} + * @return array|mixed + */ + public function getMetadata($key = null) + { + if (!$this->stream) { + return null; + } + + $this->meta = stream_get_meta_data($this->stream); + + if (!$key) { + return $this->meta; + } + + return $this->meta[$key] ?? null; + } + + /** + * Attach new resource to this object. + * + * @internal This method is not part of the PSR-7 standard. + * + * @param resource $stream A PHP resource handle. + * + * @throws InvalidArgumentException If argument is not a valid PHP resource. + * + * @return void + */ + protected function attach($stream): void + { + if (!is_resource($stream)) { + throw new InvalidArgumentException(__METHOD__ . ' argument must be a valid PHP resource'); + } + + if ($this->stream) { + $this->detach(); + } + + $this->stream = $stream; + } + + /** + * {@inheritdoc} + */ + public function detach() + { + $oldResource = $this->stream; + $this->stream = null; + $this->meta = null; + $this->readable = null; + $this->writable = null; + $this->seekable = null; + $this->size = null; + $this->isPipe = null; + + $this->cache = null; + $this->finished = false; + + return $oldResource; + } + + /** + * {@inheritdoc} + */ + public function __toString(): string + { + if (!$this->stream) { + return ''; + } + if ($this->cache && $this->finished) { + $this->cache->rewind(); + return $this->cache->getContents(); + } + if ($this->isSeekable()) { + $this->rewind(); + } + return $this->getContents(); + } + + /** + * {@inheritdoc} + */ + public function close(): void + { + if ($this->stream) { + if ($this->isPipe()) { + pclose($this->stream); + } else { + fclose($this->stream); + } + } + + $this->detach(); + } + + /** + * {@inheritdoc} + */ + public function getSize(): ?int + { + if ($this->stream && !$this->size) { + $stats = fstat($this->stream); + + if ($stats) { + $this->size = !$this->isPipe() ? $stats['size'] : null; + } + } + + return $this->size; + } + + /** + * {@inheritdoc} + */ + public function tell(): int + { + $position = false; + + if ($this->stream) { + $position = ftell($this->stream); + } + + if ($position === false || $this->isPipe()) { + throw new RuntimeException('Could not get the position of the pointer in stream.'); + } + + return $position; + } + + /** + * {@inheritdoc} + */ + public function eof(): bool + { + return !$this->stream || feof($this->stream); + } + + /** + * {@inheritdoc} + */ + public function isReadable(): bool + { + if ($this->readable !== null) { + return $this->readable; + } + + $this->readable = false; + + if ($this->stream) { + $mode = $this->getMetadata('mode'); + + if (is_string($mode) && (strstr($mode, 'r') !== false || strstr($mode, '+') !== false)) { + $this->readable = true; + } + } + + return $this->readable; + } + + /** + * {@inheritdoc} + */ + public function isWritable(): bool + { + if ($this->writable === null) { + $this->writable = false; + + if ($this->stream) { + $mode = $this->getMetadata('mode'); + + if (is_string($mode) && (strstr($mode, 'w') !== false || strstr($mode, '+') !== false)) { + $this->writable = true; + } + } + } + + return $this->writable; + } + + /** + * {@inheritdoc} + */ + public function isSeekable(): bool + { + if ($this->seekable === null) { + $this->seekable = false; + + if ($this->stream) { + $this->seekable = !$this->isPipe() && $this->getMetadata('seekable'); + } + } + + return $this->seekable; + } + + /** + * {@inheritdoc} + */ + public function seek($offset, $whence = SEEK_SET): void + { + if (!$this->isSeekable() || $this->stream && fseek($this->stream, $offset, $whence) === -1) { + throw new RuntimeException('Could not seek in stream.'); + } + } + + /** + * {@inheritdoc} + */ + public function rewind(): void + { + if (!$this->isSeekable() || $this->stream && rewind($this->stream) === false) { + throw new RuntimeException('Could not rewind stream.'); + } + } + + /** + * {@inheritdoc} + */ + public function read($length): string + { + $data = false; + + if ($this->isReadable() && $this->stream && $length > 0) { + $data = fread($this->stream, $length); + } + + if (is_string($data)) { + if ($this->cache) { + $this->cache->write($data); + } + if ($this->eof()) { + $this->finished = true; + } + return $data; + } + + throw new RuntimeException('Could not read from stream.'); + } + + /** + * {@inheritdoc} + * @return int + */ + public function write($string): int + { + $written = false; + + if ($this->isWritable() && $this->stream) { + $written = fwrite($this->stream, $string); + } + + if ($written !== false) { + $this->size = null; + return $written; + } + + throw new RuntimeException('Could not write to stream.'); + } + + /** + * {@inheritdoc} + */ + public function getContents(): string + { + if ($this->cache && $this->finished) { + $this->cache->rewind(); + return $this->cache->getContents(); + } + + $contents = false; + + if ($this->stream) { + $contents = stream_get_contents($this->stream); + } + + if (is_string($contents)) { + if ($this->cache) { + $this->cache->write($contents); + } + if ($this->eof()) { + $this->finished = true; + } + return $contents; + } + + throw new RuntimeException('Could not get contents of stream.'); + } + + /** + * Returns whether or not the stream is a pipe. + * + * @internal This method is not part of the PSR-7 standard. + * + * @return bool + */ + public function isPipe(): bool + { + if ($this->isPipe === null) { + $this->isPipe = false; + + if ($this->stream) { + $stats = fstat($this->stream); + + if (is_array($stats)) { + $this->isPipe = ($stats['mode'] & self::FSTAT_MODE_S_IFIFO) !== 0; + } + } + } + + return $this->isPipe; + } +} diff --git a/api/vendor/slim/psr7/src/UploadedFile.php b/api/vendor/slim/psr7/src/UploadedFile.php new file mode 100644 index 0000000..d8d6ad6 --- /dev/null +++ b/api/vendor/slim/psr7/src/UploadedFile.php @@ -0,0 +1,279 @@ +getMetadata('uri'); + if (!is_string($file)) { + throw new InvalidArgumentException('No URI associated with the stream.'); + } + $this->file = $file; + $this->stream = $fileNameOrStream; + } elseif (is_string($fileNameOrStream)) { + $this->file = $fileNameOrStream; + } else { + throw new InvalidArgumentException( + 'Please provide a string (full path to the uploaded file) or an instance of StreamInterface.' + ); + } + $this->name = $name; + $this->type = $type; + $this->size = $size; + $this->error = $error; + $this->sapi = $sapi; + } + + /** + * {@inheritdoc} + * @return StreamInterface + */ + public function getStream(): StreamInterface + { + if ($this->moved) { + throw new RuntimeException(sprintf('Uploaded file %s has already been moved', $this->name)); + } + + if (!$this->stream) { + $this->stream = (new StreamFactory())->createStreamFromFile($this->file); + } + + return $this->stream; + } + + /** + * {@inheritdoc} + */ + public function moveTo($targetPath): void + { + if ($this->moved) { + throw new RuntimeException('Uploaded file already moved'); + } + + $targetIsStream = strpos($targetPath, '://') > 0; + if (!$targetIsStream && !is_writable(dirname($targetPath))) { + throw new InvalidArgumentException('Upload target path is not writable'); + } + + if ($targetIsStream) { + if (!copy($this->file, $targetPath)) { + throw new RuntimeException(sprintf('Error moving uploaded file %s to %s', $this->name, $targetPath)); + } + + if (!unlink($this->file)) { + throw new RuntimeException(sprintf('Error removing uploaded file %s', $this->name)); + } + } elseif ($this->sapi) { + if (!is_uploaded_file($this->file)) { + throw new RuntimeException(sprintf('%s is not a valid uploaded file', $this->file)); + } + + if (!move_uploaded_file($this->file, $targetPath)) { + throw new RuntimeException(sprintf('Error moving uploaded file %s to %s', $this->name, $targetPath)); + } + } else { + if (!rename($this->file, $targetPath)) { + throw new RuntimeException(sprintf('Error moving uploaded file %s to %s', $this->name, $targetPath)); + } + } + + $this->moved = true; + } + + /** + * {@inheritdoc} + */ + public function getError(): int + { + return $this->error; + } + + /** + * {@inheritdoc} + */ + public function getClientFilename(): ?string + { + return $this->name; + } + + /** + * {@inheritdoc} + */ + public function getClientMediaType(): ?string + { + return $this->type; + } + + /** + * {@inheritdoc} + */ + public function getSize(): ?int + { + return $this->size; + } + + /** + * Returns the client-provided full path to the file + * + * @internal This method is not part of the PSR-7 standard + * + * @return string + */ + public function getFilePath(): string + { + return $this->file; + } + + /** + * Create a normalized tree of UploadedFile instances from the Environment. + * + * @internal This method is not part of the PSR-7 standard. + * + * @param array $globals The global server variables. + * + * @return array A normalized tree of UploadedFile instances or null if none are provided. + */ + public static function createFromGlobals(array $globals): array + { + if (isset($globals['slim.files']) && is_array($globals['slim.files'])) { + return $globals['slim.files']; + } + + if (!empty($_FILES)) { + return self::parseUploadedFiles($_FILES); + } + + return []; + } + + /** + * Parse a non-normalized, i.e. $_FILES superglobal, tree of uploaded file data. + * + * @internal This method is not part of the PSR-7 standard. + * + * @param array $uploadedFiles The non-normalized tree of uploaded file data. + * + * @return array A normalized tree of UploadedFile instances. + */ + private static function parseUploadedFiles(array $uploadedFiles): array + { + $parsed = []; + foreach ($uploadedFiles as $field => $uploadedFile) { + if (!isset($uploadedFile['error'])) { + if (is_array($uploadedFile)) { + $parsed[$field] = self::parseUploadedFiles($uploadedFile); + } + continue; + } + + $parsed[$field] = []; + if (!is_array($uploadedFile['error'])) { + $parsed[$field] = new static( + $uploadedFile['tmp_name'], + $uploadedFile['name'] ?? null, + $uploadedFile['type'] ?? null, + $uploadedFile['size'] ?? null, + $uploadedFile['error'], + true + ); + } else { + $subArray = []; + foreach ($uploadedFile['error'] as $fileIdx => $error) { + // Normalize sub array and re-parse to move the input's key name up a level + $subArray[$fileIdx]['name'] = $uploadedFile['name'][$fileIdx]; + $subArray[$fileIdx]['type'] = $uploadedFile['type'][$fileIdx]; + $subArray[$fileIdx]['tmp_name'] = $uploadedFile['tmp_name'][$fileIdx]; + $subArray[$fileIdx]['error'] = $uploadedFile['error'][$fileIdx]; + $subArray[$fileIdx]['size'] = $uploadedFile['size'][$fileIdx]; + + $parsed[$field] = self::parseUploadedFiles($subArray); + } + } + } + + return $parsed; + } +} diff --git a/api/vendor/slim/psr7/src/Uri.php b/api/vendor/slim/psr7/src/Uri.php new file mode 100644 index 0000000..6fbe47c --- /dev/null +++ b/api/vendor/slim/psr7/src/Uri.php @@ -0,0 +1,505 @@ + null, + 'http' => 80, + 'https' => 443 + ]; + + /** + * Uri scheme (without "://" suffix) + */ + protected string $scheme = ''; + + protected string $user = ''; + + protected string $password = ''; + + protected string $host = ''; + + protected ?int $port; + + protected string $path = ''; + + /** + * Uri query string (without "?" prefix) + */ + protected string $query = ''; + + /** + * Uri fragment string (without "#" prefix) + */ + protected string $fragment = ''; + + /** + * @param string $scheme Uri scheme. + * @param string $host Uri host. + * @param int|null $port Uri port number. + * @param string $path Uri path. + * @param string $query Uri query string. + * @param string $fragment Uri fragment. + * @param string $user Uri user. + * @param string $password Uri password. + */ + public function __construct( + string $scheme, + string $host, + ?int $port = null, + string $path = '/', + string $query = '', + string $fragment = '', + string $user = '', + string $password = '' + ) { + $this->scheme = $this->filterScheme($scheme); + $this->host = $this->filterHost($host); + $this->port = $this->filterPort($port); + $this->path = $this->filterPath($path); + $this->query = $this->filterQuery($query); + $this->fragment = $this->filterFragment($fragment); + $this->user = $this->filterUserInfo($user); + $this->password = $this->filterUserInfo($password); + } + + /** + * {@inheritdoc} + */ + public function getScheme(): string + { + return $this->scheme; + } + + /** + * {@inheritdoc} + * @return static + */ + public function withScheme($scheme): UriInterface + { + $scheme = $this->filterScheme($scheme); + $clone = clone $this; + $clone->scheme = $scheme; + + return $clone; + } + + /** + * Filter Uri scheme. + * + * @param mixed $scheme Raw Uri scheme. + * + * @return string + * + * @throws InvalidArgumentException If the Uri scheme is not a string. + * @throws InvalidArgumentException If Uri scheme is not exists in SUPPORTED_SCHEMES + */ + protected function filterScheme($scheme): string + { + if (!is_string($scheme)) { + throw new InvalidArgumentException('Uri scheme must be a string.'); + } + + $scheme = str_replace('://', '', strtolower($scheme)); + if (!key_exists($scheme, static::SUPPORTED_SCHEMES)) { + throw new InvalidArgumentException( + 'Uri scheme must be one of: "' . implode('", "', array_keys(static::SUPPORTED_SCHEMES)) . '"' + ); + } + + return $scheme; + } + + /** + * {@inheritdoc} + */ + public function getAuthority(): string + { + $userInfo = $this->getUserInfo(); + $host = $this->getHost(); + $port = $this->getPort(); + + return ($userInfo !== '' ? $userInfo . '@' : '') . $host . ($port !== null ? ':' . $port : ''); + } + + /** + * {@inheritdoc} + */ + public function getUserInfo(): string + { + $info = $this->user; + + if ($this->password !== '') { + $info .= ':' . $this->password; + } + + return $info; + } + + /** + * {@inheritdoc} + * @return static + */ + public function withUserInfo($user, $password = null): UriInterface + { + $clone = clone $this; + $clone->user = $this->filterUserInfo($user); + + if ($clone->user !== '') { + $clone->password = $this->filterUserInfo($password); + } else { + $clone->password = ''; + } + + return $clone; + } + + /** + * Filters the user info string. + * + * Returns the percent-encoded query string. + * + * @param string|null $info The raw uri query string. + * + * @return string + */ + protected function filterUserInfo(?string $info = null): string + { + if (!is_string($info)) { + return ''; + } + + $match = preg_replace_callback( + '/(?:[^%a-zA-Z0-9_\-\.~\pL!\$&\'\(\)\*\+,;=]+|%(?![A-Fa-f0-9]{2}))/', + function ($match) { + return rawurlencode($match[0]); + }, + $info + ); + + return is_string($match) ? $match : ''; + } + + /** + * {@inheritdoc} + */ + public function getHost(): string + { + return $this->host; + } + + /** + * {@inheritdoc} + * @return static + */ + public function withHost($host): UriInterface + { + $clone = clone $this; + $clone->host = $this->filterHost($host); + + return $clone; + } + + /** + * Filter Uri host. + * + * If the supplied host is an IPv6 address, then it is converted to a reference + * as per RFC 2373. + * + * @param mixed $host The host to filter. + * + * @return string + * + * @throws InvalidArgumentException for invalid host names. + */ + protected function filterHost($host): string + { + if (is_object($host) && method_exists($host, '__toString')) { + $host = (string) $host; + } + + if (!is_string($host)) { + throw new InvalidArgumentException('Uri host must be a string'); + } + + if (filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { + $host = '[' . $host . ']'; + } + + return strtolower($host); + } + + /** + * {@inheritdoc} + */ + public function getPort(): ?int + { + return $this->port && !$this->hasStandardPort() ? $this->port : null; + } + + /** + * {@inheritdoc} + * @return static + */ + public function withPort($port): UriInterface + { + $port = $this->filterPort($port); + $clone = clone $this; + $clone->port = $port; + + return $clone; + } + + /** + * Does this Uri use a standard port? + * + * @return bool + */ + protected function hasStandardPort(): bool + { + return static::SUPPORTED_SCHEMES[$this->scheme] === $this->port; + } + + /** + * Filter Uri port. + * + * @param int|string|null $port The Uri port number. + * + * @return int|null + * + * @throws InvalidArgumentException If the port is invalid. + */ + protected function filterPort($port): ?int + { + if (is_null($port)) { + return null; + } + + $port = (int) $port; + + if ($port >= 1 && $port <= 65535) { + return $port; + } + + throw new InvalidArgumentException('Uri port must be null or an integer between 1 and 65535 (inclusive)'); + } + + /** + * {@inheritdoc} + */ + public function getPath(): string + { + if (str_starts_with($this->path, '/')) { + // Use only one leading slash to prevent XSS attempts. + return '/' . ltrim($this->path, '/'); + } + + return $this->path; + } + + /** + * {@inheritdoc} + * @return static + */ + public function withPath($path): UriInterface + { + if (!is_string($path)) { + throw new InvalidArgumentException('Uri path must be a string'); + } + + $clone = clone $this; + $clone->path = $this->filterPath($path); + + return $clone; + } + + /** + * Filter Uri path. + * + * This method percent-encodes all reserved characters in the provided path string. + * This method will NOT double-encode characters that are already percent-encoded. + * + * @param string $path The raw uri path. + * + * @return string The RFC 3986 percent-encoded uri path. + * + * @link http://www.faqs.org/rfcs/rfc3986.html + */ + protected function filterPath($path): string + { + $match = preg_replace_callback( + '/(?:[^a-zA-Z0-9_\-\.~:@&=\+\$,\/;%]+|%(?![A-Fa-f0-9]{2}))/', + fn (array $match) => rawurlencode($match[0]), + $path + ); + + return is_string($match) ? $match : ''; + } + + /** + * {@inheritdoc} + */ + public function getQuery(): string + { + return $this->query; + } + + /** + * {@inheritdoc} + * @return static + */ + public function withQuery($query): UriInterface + { + $query = ltrim($this->filterQuery($query), '?'); + $clone = clone $this; + $clone->query = $query; + + return $clone; + } + + /** + * Filters the query string of a URI. + * + * Returns the percent-encoded query string. + * + * @param mixed $query The raw uri query string. + * + * @return string + */ + protected function filterQuery($query): string + { + if (is_object($query) && method_exists($query, '__toString')) { + $query = (string) $query; + } + + if (!is_string($query)) { + throw new InvalidArgumentException('Uri query must be a string.'); + } + + $match = preg_replace_callback( + '/(?:[^a-zA-Z0-9_\-\.~!\$&\'\(\)\*\+,;=%:@\/\?]+|%(?![A-Fa-f0-9]{2}))/', + function ($match) { + return rawurlencode($match[0]); + }, + $query + ); + + return is_string($match) ? $match : ''; + } + + /** + * {@inheritdoc} + */ + public function getFragment(): string + { + return $this->fragment; + } + + /** + * {@inheritdoc} + * @return static + */ + public function withFragment($fragment): UriInterface + { + $fragment = $this->filterFragment($fragment); + $clone = clone $this; + $clone->fragment = $fragment; + + return $clone; + } + + /** + * Filters fragment of a URI. + * + * Returns the percent-encoded fragment. + * + * @param mixed $fragment The raw uri query string. + * + * @return string + */ + protected function filterFragment($fragment): string + { + if (is_object($fragment) && method_exists($fragment, '__toString')) { + $fragment = (string) $fragment; + } + + if (!is_string($fragment)) { + throw new InvalidArgumentException('Uri fragment must be a string.'); + } + + $fragment = ltrim($fragment, '#'); + + $match = preg_replace_callback( + '/(?:[^a-zA-Z0-9_\-\.~!\$&\'\(\)\*\+,;=%:@\/\?]+|%(?![A-Fa-f0-9]{2}))/', + function ($match) { + return rawurlencode($match[0]); + }, + $fragment + ); + + return is_string($match) ? $match : ''; + } + + /** + * {@inheritdoc} + */ + public function __toString(): string + { + $scheme = $this->getScheme(); + $authority = $this->getAuthority(); + $path = $this->path; + $query = $this->getQuery(); + $fragment = $this->getFragment(); + + if ($path !== '') { + if ($path[0] !== '/') { + if ($authority !== '') { + // If the path is rootless and an authority is present, the path MUST be prefixed by "/". + $path = '/' . $path; + } + } elseif (isset($path[1]) && $path[1] === '/') { + if ($authority === '') { + // If the path is starting with more than one "/" and no authority is present, + // the starting slashes MUST be reduced to one. + $path = ltrim($path, '/'); + $path = '/' . $path; + } + } + } + + return ($scheme !== '' ? $scheme . ':' : '') + . ($authority !== '' ? '//' . $authority : '') + . $path + . ($query !== '' ? '?' . $query : '') + . ($fragment !== '' ? '#' . $fragment : ''); + } +} diff --git a/api/vendor/slim/psr7/tests/Assets/HeaderStack.php b/api/vendor/slim/psr7/tests/Assets/HeaderStack.php new file mode 100644 index 0000000..b07daea --- /dev/null +++ b/api/vendor/slim/psr7/tests/Assets/HeaderStack.php @@ -0,0 +1,95 @@ + $item) { + if (false !== strpos($item['header'], "$header:")) { + unset(self::$data[$key]); + } + } + } +} diff --git a/api/vendor/slim/psr7/tests/BodyTest.php b/api/vendor/slim/psr7/tests/BodyTest.php new file mode 100644 index 0000000..de1d8de --- /dev/null +++ b/api/vendor/slim/psr7/tests/BodyTest.php @@ -0,0 +1,422 @@ +stream) === true) { + fclose($this->stream); + } + } + + /** + * @param string $mode + * + * @return resource + */ + public function resourceFactory(string $mode = 'r+') + { + $stream = fopen('php://temp', $mode); + fwrite($stream, $this->text); + rewind($stream); + + return $stream; + } + + public function testConstructorAttachesStream() + { + $this->stream = $this->resourceFactory(); + $body = new Stream($this->stream); + $bodyStream = new ReflectionProperty($body, 'stream'); + $bodyStream->setAccessible(true); + + $this->assertSame($this->stream, $bodyStream->getValue($body)); + } + + public function testConstructorInvalidStream() + { + $this->expectException(InvalidArgumentException::class); + + $this->stream = 'foo'; + $body = new Stream($this->stream); + } + + public function testGetMetadata() + { + $this->stream = $this->resourceFactory(); + $body = new Stream($this->stream); + + $this->assertTrue(is_array($body->getMetadata())); + } + + public function testGetMetadataKey() + { + $this->stream = $this->resourceFactory(); + $body = new Stream($this->stream); + + $this->assertEquals('php://temp', $body->getMetadata('uri')); + } + + public function testGetMetadataKeyNotFound() + { + $this->stream = $this->resourceFactory(); + $body = new Stream($this->stream); + + $this->assertNull($body->getMetadata('foo')); + } + + public function testDetach() + { + $this->stream = $this->resourceFactory(); + $body = new Stream($this->stream); + + $bodyStream = new ReflectionProperty($body, 'stream'); + $bodyStream->setAccessible(true); + + $bodyMetadata = new ReflectionProperty($body, 'meta'); + $bodyMetadata->setAccessible(true); + + $bodyReadable = new ReflectionProperty($body, 'readable'); + $bodyReadable->setAccessible(true); + + $bodyWritable = new ReflectionProperty($body, 'writable'); + $bodyWritable->setAccessible(true); + + $bodySeekable = new ReflectionProperty($body, 'seekable'); + $bodySeekable->setAccessible(true); + + $result = $body->detach(); + + $this->assertSame($this->stream, $result); + $this->assertNull($bodyStream->getValue($body)); + $this->assertNull($bodyMetadata->getValue($body)); + $this->assertNull($bodyReadable->getValue($body)); + $this->assertNull($bodyWritable->getValue($body)); + $this->assertNull($bodySeekable->getValue($body)); + } + + public function testToStringAttached() + { + $this->stream = $this->resourceFactory(); + $body = new Stream($this->stream); + + $this->assertEquals($this->text, (string) $body); + } + + public function testToStringAttachedRewindsFirst() + { + $this->stream = $this->resourceFactory(); + $body = new Stream($this->stream); + + $this->assertEquals($this->text, (string) $body); + $this->assertEquals($this->text, (string) $body); + $this->assertEquals($this->text, (string) $body); + } + + public function testToStringDetached() + { + $this->stream = $this->resourceFactory(); + $body = new Stream($this->stream); + $bodyStream = new ReflectionProperty($body, 'stream'); + $bodyStream->setAccessible(true); + $bodyStream->setValue($body, null); + + $this->assertEquals('', (string) $body); + } + + public function testClose() + { + $this->stream = $this->resourceFactory(); + $body = new Stream($this->stream); + $body->close(); + + $bodyStream = new ReflectionProperty($body, 'stream'); + $bodyStream->setAccessible(true); + + $this->assertNull($bodyStream->getValue($body)); + } + + public function testGetSizeAttached() + { + $this->stream = $this->resourceFactory(); + $body = new Stream($this->stream); + + $this->assertEquals(mb_strlen($this->text), $body->getSize()); + } + + public function testGetSizeDetached() + { + $this->stream = $this->resourceFactory(); + $body = new Stream($this->stream); + $bodyStream = new ReflectionProperty($body, 'stream'); + $bodyStream->setAccessible(true); + $bodyStream->setValue($body, null); + + $this->assertNull($body->getSize()); + } + + public function testTellAttached() + { + $this->stream = $this->resourceFactory(); + $body = new Stream($this->stream); + fseek($this->stream, 10); + + $this->assertEquals(10, $body->tell()); + } + + public function testTellDetachedThrowsRuntimeException() + { + $this->expectException(RuntimeException::class); + + $this->stream = $this->resourceFactory(); + $body = new Stream($this->stream); + $bodyStream = new ReflectionProperty($body, 'stream'); + $bodyStream->setAccessible(true); + $bodyStream->setValue($body, null); + + $body->tell(); + } + + public function testEofAttachedFalse() + { + $this->stream = $this->resourceFactory(); + $body = new Stream($this->stream); + fseek($this->stream, 10); + + $this->assertFalse($body->eof()); + } + + public function testEofAttachedTrue() + { + $this->stream = $this->resourceFactory(); + $body = new Stream($this->stream); + while (feof($this->stream) === false) { + fread($this->stream, 1024); + } + + $this->assertTrue($body->eof()); + } + + public function testEofDetached() + { + $this->stream = $this->resourceFactory(); + $body = new Stream($this->stream); + $bodyStream = new ReflectionProperty($body, 'stream'); + $bodyStream->setAccessible(true); + $bodyStream->setValue($body, null); + + $this->assertTrue($body->eof()); + } + + public function isReadableAttachedTrue() + { + $this->stream = $this->resourceFactory(); + $body = new Stream($this->stream); + + $this->assertTrue($body->isReadable()); + } + + public function isReadableAttachedFalse() + { + $stream = fopen('php://temp', 'w'); + $body = new Stream($this->stream); + + $this->assertFalse($body->isReadable()); + fclose($stream); + } + + public function testIsReadableDetached() + { + $this->stream = $this->resourceFactory(); + $body = new Stream($this->stream); + $body->detach(); + + $this->assertFalse($body->isReadable()); + } + + public function isWritableAttachedTrue() + { + $this->stream = $this->resourceFactory(); + $body = new Stream($this->stream); + + $this->assertTrue($body->isWritable()); + } + + public function isWritableAttachedFalse() + { + $stream = fopen('php://temp', 'r'); + $body = new Stream($this->stream); + + $this->assertFalse($body->isWritable()); + fclose($stream); + } + + public function testIsWritableDetached() + { + $this->stream = $this->resourceFactory(); + $body = new Stream($this->stream); + $body->detach(); + + $this->assertFalse($body->isWritable()); + } + + public function isSeekableAttachedTrue() + { + $this->stream = $this->resourceFactory(); + $body = new Stream($this->stream); + + $this->assertTrue($body->isSeekable()); + } + + // TODO: Is seekable is false when attached... how? + + public function testIsSeekableDetached() + { + $this->stream = $this->resourceFactory(); + $body = new Stream($this->stream); + $body->detach(); + + $this->assertFalse($body->isSeekable()); + } + + public function testSeekAttached() + { + $this->stream = $this->resourceFactory(); + $body = new Stream($this->stream); + $body->seek(10); + + $this->assertEquals(10, ftell($this->stream)); + } + + public function testSeekDetachedThrowsRuntimeException() + { + $this->expectException(RuntimeException::class); + + $this->stream = $this->resourceFactory(); + $body = new Stream($this->stream); + $body->detach(); + + $body->seek(10); + } + + public function testRewindAttached() + { + $this->stream = $this->resourceFactory(); + $body = new Stream($this->stream); + fseek($this->stream, 10); + $body->rewind(); + + $this->assertEquals(0, ftell($this->stream)); + } + + public function testRewindDetachedThrowsRuntimeException() + { + $this->expectException(RuntimeException::class); + + $this->stream = $this->resourceFactory(); + $body = new Stream($this->stream); + $body->detach(); + + $body->rewind(); + } + + public function testReadAttached() + { + $this->stream = $this->resourceFactory(); + $body = new Stream($this->stream); + + $this->assertEquals(substr($this->text, 0, 10), $body->read(10)); + } + + public function testReadDetachedThrowsRuntimeException() + { + $this->expectException(RuntimeException::class); + + $this->stream = $this->resourceFactory(); + $body = new Stream($this->stream); + $body->detach(); + + $body->read(10); + } + + public function testWriteAttached() + { + $this->stream = $this->resourceFactory(); + $body = new Stream($this->stream); + while (feof($this->stream) === false) { + fread($this->stream, 1024); + } + $body->write('foo'); + + $this->assertEquals($this->text . 'foo', (string) $body); + } + + public function testWriteDetachedThrowsRuntimeException() + { + $this->expectException(RuntimeException::class); + + $this->stream = $this->resourceFactory(); + $body = new Stream($this->stream); + $body->detach(); + + $body->write('foo'); + } + + public function testGetContentsAttached() + { + $this->stream = $this->resourceFactory(); + $body = new Stream($this->stream); + fseek($this->stream, 10); + + $this->assertEquals(substr($this->text, 10), $body->getContents()); + } + + public function testGetContentsDetachedThrowsRuntimeException() + { + $this->expectException(RuntimeException::class); + + $this->stream = $this->resourceFactory(); + $body = new Stream($this->stream); + $body->detach(); + + $body->getContents(); + } +} diff --git a/api/vendor/slim/psr7/tests/CookiesTest.php b/api/vendor/slim/psr7/tests/CookiesTest.php new file mode 100644 index 0000000..8a1cc86 --- /dev/null +++ b/api/vendor/slim/psr7/tests/CookiesTest.php @@ -0,0 +1,283 @@ + 'Works', + ]); + $prop = new ReflectionProperty($cookies, 'requestCookies'); + $prop->setAccessible(true); + $this->assertNotEmpty($prop->getValue($cookies)['test']); + $this->assertEquals('Works', $prop->getValue($cookies)['test']); + } + + public function testSetDefaults() + { + $defaults = [ + 'value' => 'toast', + 'domain' => null, + 'hostonly' => null, + 'path' => null, + 'expires' => null, + 'secure' => true, + 'httponly' => true, + 'samesite' => null + ]; + + $cookies = new Cookies(); + + $prop = new ReflectionProperty($cookies, 'defaults'); + $prop->setAccessible(true); + + $origDefaults = $prop->getValue($cookies); + + $cookies->setDefaults($defaults); + + $this->assertEquals($defaults, $prop->getValue($cookies)); + $this->assertNotEquals($origDefaults, $prop->getValue($cookies)); + } + + public function testSetCookieValues() + { + $cookies = new Cookies(); + $cookies->set('foo', 'bar'); + + $prop = new ReflectionProperty($cookies, 'responseCookies'); + $prop->setAccessible(true); + + $expectedValue = [ + 'foo' => [ + 'value' => 'bar', + 'domain' => null, + 'hostonly' => null, + 'path' => null, + 'expires' => null, + 'secure' => false, + 'httponly' => false, + 'samesite' => null + ] + ]; + + $this->assertEquals($expectedValue, $prop->getValue($cookies)); + } + + public function testSetCookieValuesContainDefaults() + { + $cookies = new Cookies(); + $defaults = [ + 'value' => 'toast', + 'domain' => null, + 'hostonly' => null, + 'path' => null, + 'expires' => null, + 'secure' => true, + 'httponly' => true, + 'samesite' => 'lax' + ]; + + $cookies->setDefaults($defaults); + $cookies->set('foo', 'bar'); + + $prop = new ReflectionProperty($cookies, 'responseCookies'); + $prop->setAccessible(true); + + $expectedValue = [ + 'foo' => [ + 'value' => 'bar', + 'domain' => null, + 'hostonly' => null, + 'path' => null, + 'expires' => null, + 'secure' => true, + 'httponly' => true, + 'samesite' => 'lax' + ] + ]; + + $this->assertEquals($expectedValue, $prop->getValue($cookies)); + } + + public function testSetCookieValuesCanOverrideDefaults() + { + $cookies = new Cookies(); + $defaults = [ + 'value' => 'toast', + 'domain' => null, + 'hostonly' => null, + 'path' => null, + 'expires' => null, + 'secure' => true, + 'httponly' => true, + 'samesite' => 'lax' + ]; + + $cookies->setDefaults($defaults); + $cookies->set('foo', ['value' => 'bar', 'secure' => false, 'samesite' => 'strict']); + + $prop = new ReflectionProperty($cookies, 'responseCookies'); + $prop->setAccessible(true); + + $expectedValue = [ + 'foo' => [ + 'value' => 'bar', + 'domain' => null, + 'hostonly' => null, + 'path' => null, + 'expires' => null, + 'secure' => false, + 'httponly' => true, + 'samesite' => 'strict' + ] + ]; + + $this->assertEquals($expectedValue, $prop->getValue($cookies)); + } + + public function testSetSameSiteCookieValuesAreCaseInsensitive() + { + $cookies = new Cookies(); + $defaults = [ + 'value' => 'bacon', + 'samesite' => 'lax' + ]; + + $cookies->setDefaults($defaults); + $cookies->set('breakfast', ['samesite' => 'StricT']); + + $prop = new ReflectionProperty($cookies, 'responseCookies'); + $prop->setAccessible(true); + + $expectedValue = [ + 'breakfast' => [ + 'value' => 'bacon', + 'domain' => null, + 'hostonly' => null, + 'path' => null, + 'expires' => null, + 'secure' => false, + 'httponly' => false, + 'samesite' => 'StricT', + ] + ]; + + $this->assertEquals($expectedValue, $prop->getValue($cookies)); + } + + public function testGet() + { + $cookies = new Cookies(['foo' => 'bar', 'baz' => null]); + $this->assertEquals('bar', $cookies->get('foo')); + $this->assertNull($cookies->get('baz', 'defaultValue')); + $this->assertNull($cookies->get('missing')); + $this->assertEquals('defaultValue', $cookies->get('missing', 'defaultValue')); + } + + public function testParseHeader() + { + $cookies = Cookies::parseHeader('foo=bar; name=Josh'); + $this->assertEquals('bar', $cookies['foo']); + $this->assertEquals('Josh', $cookies['name']); + } + + public function testParseHeaderWithJsonArray() + { + $cookies = Cookies::parseHeader('foo=bar; testarray=["someVar1","someVar2","someVar3"]'); + $this->assertEquals('bar', $cookies['foo']); + $this->assertContains('someVar3', json_decode($cookies['testarray'])); + } + + public function testToHeaders() + { + $cookies = new Cookies(); + $cookies->set('test', 'Works'); + $cookies->set('test_array', ['value' => 'bar', 'domain' => 'example.com']); + $this->assertEquals('test=Works', $cookies->toHeaders()[0]); + $this->assertEquals('test_array=bar; domain=example.com', $cookies->toHeaders()[1]); + } + + public function testToHeader() + { + $cookies = new Cookies(); + $class = new ReflectionClass($cookies); + $method = $class->getMethod('toHeader'); + $method->setAccessible(true); + $properties = [ + 'name' => 'test', + 'properties' => [ + 'value' => 'Works' + ] + ]; + $time = time(); + $formattedDate = gmdate('D, d-M-Y H:i:s e', $time); + $propertiesComplex = [ + 'name' => 'test_complex', + 'properties' => [ + 'value' => 'Works', + 'domain' => 'example.com', + 'expires' => $time, + 'path' => '/', + 'secure' => true, + 'hostonly' => true, + 'httponly' => true, + 'samesite' => 'lax' + ] + ]; + $stringDate = '2016-01-01 12:00:00'; + $formattedStringDate = gmdate('D, d-M-Y H:i:s e', strtotime($stringDate)); + $propertiesStringDate = [ + 'name' => 'test_date', + 'properties' => [ + 'value' => 'Works', + 'expires' => $stringDate, + ] + ]; + $cookie = $method->invokeArgs($cookies, $properties); + $cookieComplex = $method->invokeArgs($cookies, $propertiesComplex); + $cookieStringDate = $method->invokeArgs($cookies, $propertiesStringDate); + $this->assertEquals('test=Works', $cookie); + $this->assertEquals( + 'test_complex=Works; domain=example.com; path=/; expires=' + . $formattedDate . '; secure; HostOnly; HttpOnly; SameSite=lax', + $cookieComplex + ); + $this->assertEquals('test_date=Works; expires=' . $formattedStringDate, $cookieStringDate); + } + + public function testParseHeaderException() + { + $this->expectException(InvalidArgumentException::class); + + Cookies::parseHeader(new stdClass()); + } + + public function testSetSameSiteNoneToHeaders() + { + $cookies = new Cookies(); + $cookies->set('foo', ['value' => 'bar', 'samesite' => 'None']); + $this->assertEquals('foo=bar; SameSite=None', $cookies->toHeaders()[0]); + } +} diff --git a/api/vendor/slim/psr7/tests/EnvironmentTest.php b/api/vendor/slim/psr7/tests/EnvironmentTest.php new file mode 100644 index 0000000..ba32e18 --- /dev/null +++ b/api/vendor/slim/psr7/tests/EnvironmentTest.php @@ -0,0 +1,48 @@ + '/foo/bar/index.php', + 'REQUEST_URI' => '/foo/bar?abc=123', + ]); + + $this->assertEquals('/foo/bar/index.php', $env['SCRIPT_NAME']); + $this->assertEquals('/foo/bar?abc=123', $env['REQUEST_URI']); + } + + public function testMockHttps() + { + $env = Environment::mock([ + 'HTTPS' => 'on' + ]); + + $this->assertEquals('on', $env['HTTPS']); + $this->assertEquals(443, $env['SERVER_PORT']); + } + + public function testMockRequestScheme() + { + $env = Environment::mock([ + 'REQUEST_SCHEME' => 'https' + ]); + + $this->assertEquals('https', $env['REQUEST_SCHEME']); + $this->assertEquals(443, $env['SERVER_PORT']); + } +} diff --git a/api/vendor/slim/psr7/tests/Factory/RequestFactoryTest.php b/api/vendor/slim/psr7/tests/Factory/RequestFactoryTest.php new file mode 100644 index 0000000..02f16e5 --- /dev/null +++ b/api/vendor/slim/psr7/tests/Factory/RequestFactoryTest.php @@ -0,0 +1,42 @@ +createUri($uri); + } + + public function testCreateRequestThrowsExceptionWithInvalidUri() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Parameter 2 of RequestFactory::createRequest() must be a string' . + ' or a compatible UriInterface.'); + + $factory = $this->createRequestFactory(); + + $factory->createRequest('GET', new stdClass()); + } +} diff --git a/api/vendor/slim/psr7/tests/Factory/ResponseFactoryTest.php b/api/vendor/slim/psr7/tests/Factory/ResponseFactoryTest.php new file mode 100644 index 0000000..7dc557a --- /dev/null +++ b/api/vendor/slim/psr7/tests/Factory/ResponseFactoryTest.php @@ -0,0 +1,42 @@ +assertInstanceOf(ResponseInterface::class, $response); + $this->assertSame($code, $response->getStatusCode()); + $this->assertSame($reasonPhrase, $response->getReasonPhrase()); + } + + /** + * @dataProvider dataCodes + * + * @param int $code + */ + public function testCreateResponseWithReasonPhrase(int $code) + { + $response = $this->factory->createResponse($code, 'Reason'); + $this->assertResponse($response, $code); + $this->assertResponseCodeAndReasonPhrase($response, $code, 'Reason'); + } +} diff --git a/api/vendor/slim/psr7/tests/Factory/ServerRequestFactoryTest.php b/api/vendor/slim/psr7/tests/Factory/ServerRequestFactoryTest.php new file mode 100644 index 0000000..d46be55 --- /dev/null +++ b/api/vendor/slim/psr7/tests/Factory/ServerRequestFactoryTest.php @@ -0,0 +1,208 @@ +createUri($uri); + } + + public function testGetProtocolVersion() + { + $env = Environment::mock(['SERVER_PROTOCOL' => 'HTTP/1.0']); + $request = $this->createServerRequestFactory()->createServerRequest('GET', '', $env); + + $this->assertEquals('1.0', $request->getProtocolVersion()); + } + + public function testCreateFromGlobals() + { + $GLOBALS['getallheaders_return'] = [ + 'ACCEPT' => 'application/json', + 'ACCEPT-CHARSET' => 'utf-8', + 'ACCEPT-LANGUAGE' => 'en-US', + 'CONTENT-TYPE' => 'multipart/form-data', + 'HOST' => 'example.com', + 'USER-AGENT' => 'Slim Framework', + ]; + + $_SERVER = Environment::mock([ + 'HTTP_HOST' => 'example.com', + 'PHP_AUTH_PW' => 'sekrit', + 'PHP_AUTH_USER' => 'josh', + 'QUERY_STRING' => 'abc=123', + 'REMOTE_ADDR' => '127.0.0.1', + 'REQUEST_METHOD' => 'GET', + 'REQUEST_TIME' => time(), + 'REQUEST_TIME_FLOAT' => microtime(true), + 'REQUEST_URI' => '/foo/bar', + 'SCRIPT_NAME' => '/index.php', + 'SERVER_NAME' => 'localhost', + 'SERVER_PORT' => 8080, + 'SERVER_PROTOCOL' => 'HTTP/1.1', + ]); + + $request = ServerRequestFactory::createFromGlobals(); + + unset($GLOBALS['getallheaders_return']); + + $this->assertEquals('GET', $request->getMethod()); + $this->assertEquals('1.1', $request->getProtocolVersion()); + + $this->assertEquals('application/json', $request->getHeaderLine('Accept')); + $this->assertEquals('utf-8', $request->getHeaderLine('Accept-Charset')); + $this->assertEquals('en-US', $request->getHeaderLine('Accept-Language')); + $this->assertEquals('multipart/form-data', $request->getHeaderLine('Content-Type')); + + $uri = $request->getUri(); + $this->assertEquals('josh:sekrit', $uri->getUserInfo()); + $this->assertEquals('example.com', $uri->getHost()); + $this->assertEquals('8080', $uri->getPort()); + $this->assertEquals('/foo/bar', $uri->getPath()); + $this->assertEquals('abc=123', $uri->getQuery()); + $this->assertEquals('', $uri->getFragment()); + } + + public function testCreateFromGlobalsWithParsedBody() + { + $_SERVER = Environment::mock([ + 'HTTP_CONTENT_TYPE' => 'multipart/form-data', + 'REQUEST_METHOD' => 'POST', + ]); + + $_POST = [ + 'def' => '456', + ]; + + $request = ServerRequestFactory::createFromGlobals(); + + // $_POST should be placed into the parsed body + $this->assertEquals($_POST, $request->getParsedBody()); + } + + public function testCreateFromGlobalsBodyPointsToPhpInput() + { + $request = ServerRequestFactory::createFromGlobals(); + + $this->assertEquals('php://input', $request->getBody()->getMetadata('uri')); + } + + public function testCreateFromGlobalsSetsACache() + { + $request = ServerRequestFactory::createFromGlobals(); + + // ensure that the Stream's $cache property has been set for this php://input stream + $stream = $request->getBody(); + $class = new ReflectionClass($stream); + $property = $class->getProperty('cache'); + $property->setAccessible(true); + $cacheStreamValue = $property->getValue($stream); + $this->assertNotNull($cacheStreamValue); + } + + public function testCreateFromGlobalsWithUploadedFiles() + { + $_SERVER = Environment::mock([ + 'HTTP_CONTENT_TYPE' => 'multipart/form-data', + 'REQUEST_METHOD' => 'POST', + ]); + + $_FILES = [ + 'uploaded_file' => [ + 'name' => [ + 0 => 'foo.jpg', + 1 => 'bar.jpg', + ], + + 'type' => [ + 0 => 'image/jpeg', + 1 => 'image/jpeg', + ], + + 'tmp_name' => [ + 0 => '/tmp/phpUA3XUw', + 1 => '/tmp/phpXUFS0x', + ], + + 'error' => [ + 0 => 0, + 1 => 0, + ], + + 'size' => [ + 0 => 358708, + 1 => 236162, + ], + ] + ]; + + $request = ServerRequestFactory::createFromGlobals(); + + // $_FILES should be mapped to an array of UploadedFile objects + $uploadedFiles = $request->getUploadedFiles(); + $this->assertCount(1, $uploadedFiles); + $this->assertArrayHasKey('uploaded_file', $uploadedFiles); + $this->assertInstanceOf(UploadedFile::class, $uploadedFiles['uploaded_file'][0]); + $this->assertInstanceOf(UploadedFile::class, $uploadedFiles['uploaded_file'][1]); + } + + public function testCreateFromGlobalsParsesBodyWithFragmentedContentType() + { + $_SERVER = Environment::mock([ + 'HTTP_CONTENT_TYPE' => 'application/x-www-form-urlencoded;charset=utf-8', + 'REQUEST_METHOD' => 'POST', + ]); + + $_POST = [ + 'def' => '456', + ]; + + $request = ServerRequestFactory::createFromGlobals(); + + $this->assertEquals($_POST, $request->getParsedBody()); + } + + public function testCreateServerRequestWithNullAsUri() + { + $this->expectException(InvalidArgumentException::class); + + $env = Environment::mock(); + $this->createServerRequestFactory()->createServerRequest('GET', null, $env); + } + + public function testCreateServerRequestWithInvalidUriObject() + { + $this->expectException(InvalidArgumentException::class); + + $env = Environment::mock(); + $this->createServerRequestFactory()->createServerRequest('GET', new stdClass(), $env); + } +} diff --git a/api/vendor/slim/psr7/tests/Factory/StreamFactoryTest.php b/api/vendor/slim/psr7/tests/Factory/StreamFactoryTest.php new file mode 100644 index 0000000..e10d38d --- /dev/null +++ b/api/vendor/slim/psr7/tests/Factory/StreamFactoryTest.php @@ -0,0 +1,66 @@ +expectException(RuntimeException::class); + $this->expectExceptionMessage('StreamFactory::createStream() could not open temporary file stream.'); + + $GLOBALS['fopen_return'] = false; + + $factory = $this->createStreamFactory(); + + $factory->createStream(); + } + + public function testCreateStreamFromFileThrowsRuntimeException() + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('StreamFactory::createStreamFromFile() could not create resource' + . ' from file `non-readable`'); + + $GLOBALS['fopen_return'] = false; + + $factory = $this->createStreamFactory(); + + $factory->createStreamFromFile('non-readable'); + } + + public function testCreateStreamFromResourceThrowsRuntimeException() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Parameter 1 of StreamFactory::createStreamFromResource() must be a resource.'); + + $factory = $this->createStreamFactory(); + + $factory->createStreamFromResource('not-resource'); + } +} diff --git a/api/vendor/slim/psr7/tests/Factory/UploadedFileFactoryTest.php b/api/vendor/slim/psr7/tests/Factory/UploadedFileFactoryTest.php new file mode 100644 index 0000000..1f46b79 --- /dev/null +++ b/api/vendor/slim/psr7/tests/Factory/UploadedFileFactoryTest.php @@ -0,0 +1,114 @@ +createStreamFromResource($resource); + } + + /** + * Prophesize a `\Psr\Http\Message\StreamInterface` with a `getMetadata` method prophecy. + * + * @param string $argKey Argument for the method prophecy. + * @param mixed $returnValue Return value of the `getMetadata` method. + * + * @return StreamInterface + */ + protected function prophesizeStreamInterfaceWithGetMetadataMethod(string $argKey, $returnValue): StreamInterface + { + $streamProphecy = $this->prophesize(StreamInterface::class); + + /** @noinspection PhpUndefinedMethodInspection */ + $streamProphecy + ->getMetadata($argKey) + ->willReturn($returnValue) + ->shouldBeCalled(); + + /** @var StreamInterface $stream */ + $stream = $streamProphecy->reveal(); + + return $stream; + } + + public function testCreateUploadedFileWithInvalidUri() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('File is not readable.'); + + // Prophesize a `\Psr\Http\Message\StreamInterface` with a `getMetadata` method prophecy. + $streamProphecy = $this->prophesize(StreamInterface::class); + + /** @noinspection PhpUndefinedMethodInspection */ + $streamProphecy + ->getMetadata('uri') + ->willReturn(null) + ->shouldBeCalled(); + + /** @var StreamInterface $stream */ + $stream = $streamProphecy->reveal(); + + $this->factory->createUploadedFile($stream); + } + + public function testCreateUploadedFileWithNonReadableFile() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('File is not readable.'); + + // Prophesize a `\Psr\Http\Message\StreamInterface` with a `getMetadata` and `isReadable` method prophecies. + $streamProphecy = $this->prophesize(StreamInterface::class); + + /** @noinspection PhpUndefinedMethodInspection */ + $streamProphecy + ->getMetadata('uri') + ->willReturn('non-readable') + ->shouldBeCalled(); + + /** @noinspection PhpUndefinedMethodInspection */ + $streamProphecy + ->isReadable() + ->willReturn(false) + ->shouldBeCalled(); + + /** @var StreamInterface $stream */ + $stream = $streamProphecy->reveal(); + + $this->factory->createUploadedFile($stream); + } +} diff --git a/api/vendor/slim/psr7/tests/Factory/UriFactoryTest.php b/api/vendor/slim/psr7/tests/Factory/UriFactoryTest.php new file mode 100644 index 0000000..1927569 --- /dev/null +++ b/api/vendor/slim/psr7/tests/Factory/UriFactoryTest.php @@ -0,0 +1,243 @@ +createUriFactory()->createUri('https://josh@example.com/foo/bar?abc=123#section3'); + + $this->assertEquals('josh@example.com', $uri->getAuthority()); + } + + public function testGetAuthority() + { + $uri = $this->createUriFactory()->createUri('https://example.com/foo/bar?abc=123#section3'); + + $this->assertEquals('example.com', $uri->getAuthority()); + } + + public function testGetAuthorityWithNonStandardPort() + { + $uri = $this->createUriFactory()->createUri('https://example.com:400/foo/bar?abc=123#section3'); + + $this->assertEquals('example.com:400', $uri->getAuthority()); + } + + public function testGetUserInfoWithUsernameAndPassword() + { + $uri = $this->createUriFactory()->createUri('https://josh:sekrit@example.com:443/foo/bar?abc=123#section3'); + + $this->assertEquals('josh:sekrit', $uri->getUserInfo()); + } + + public function testGetUserInfoWithUsernameAndPasswordEncodesCorrectly() + { + $uri = $this + ->createUriFactory() + ->createUri('https://bob@example.com:pass:word@example.com:443/foo/bar?abc=123#section3'); + + $this->assertEquals('bob%40example.com:pass%3Aword', $uri->getUserInfo()); + } + + public function testGetUserInfoWithUsername() + { + $uri = $this->createUriFactory()->createUri('http://josh@example.com/foo/bar?abc=123#section3'); + + $this->assertEquals('josh', $uri->getUserInfo()); + } + + public function testGetUserInfoNone() + { + $uri = $this->createUriFactory()->createUri('https://example.com/foo/bar?abc=123#section3'); + + $this->assertEquals('', $uri->getUserInfo()); + } + + public function testCreateFromString() + { + $uri = $this->createUriFactory()->createUri('https://example.com:8080/foo/bar?abc=123'); + + $this->assertEquals('https', $uri->getScheme()); + $this->assertEquals('example.com', $uri->getHost()); + $this->assertEquals('8080', $uri->getPort()); + $this->assertEquals('/foo/bar', $uri->getPath()); + $this->assertEquals('abc=123', $uri->getQuery()); + } + + public function testCreateFromGlobals() + { + $globals = Environment::mock([ + 'SCRIPT_NAME' => '/index.php', + 'REQUEST_URI' => '/foo/bar?baz=1', + 'PHP_AUTH_USER' => 'josh', + 'PHP_AUTH_PW' => 'sekrit', + 'QUERY_STRING' => 'abc=123', + 'HTTP_HOST' => 'example.com:8080', + 'SERVER_PORT' => 8080, + ]); + + $uri = $this->createUriFactory()->createFromGlobals($globals); + + $this->assertEquals('josh:sekrit', $uri->getUserInfo()); + $this->assertEquals('example.com', $uri->getHost()); + $this->assertEquals('8080', $uri->getPort()); + $this->assertEquals('/foo/bar', $uri->getPath()); + $this->assertEquals('abc=123', $uri->getQuery()); + $this->assertEquals('', $uri->getFragment()); + } + + public function testCreateFromGlobalsWithHttps() + { + $globals = Environment::mock( + [ + 'HTTPS' => 'on', + 'HTTP_HOST' => 'example.com' + ] + ); + + // Make the 'SERVER_PORT' empty as we want to test if the default server port gets set correctly. + $globals['SERVER_PORT'] = ''; + + $uri = $this->createUriFactory()->createFromGlobals($globals); + + $this->assertEquals('https', $uri->getScheme()); + $this->assertEquals('example.com', $uri->getHost()); + + // The port is expected to be NULL as the server port is the default standard (443 in case of https). + $this->assertNull($uri->getPort()); + } + + public function testCreateFromGlobalsUsesServerNameAsHostIfHostHeaderIsNotPresent() + { + $globals = Environment::mock([ + 'SERVER_NAME' => 'example.com', + ]); + + $uri = $this->createUriFactory()->createFromGlobals($globals); + + $this->assertEquals('example.com', $uri->getHost()); + } + + public function testCreateFromGlobalWithIPv6HostNoPort() + { + $environment = Environment::mock([ + 'SCRIPT_NAME' => '/index.php', + 'REQUEST_URI' => '/foo/bar', + 'PHP_AUTH_USER' => 'josh', + 'PHP_AUTH_PW' => 'sekrit', + 'QUERY_STRING' => 'abc=123', + 'HTTP_HOST' => '[2001:db8::1]', + 'REMOTE_ADDR' => '2001:db8::1', + 'SERVER_PORT' => 8080, + ]); + $uri = $this->createUriFactory()->createFromGlobals($environment); + + $this->assertEquals('josh:sekrit', $uri->getUserInfo()); + $this->assertEquals('[2001:db8::1]', $uri->getHost()); + $this->assertEquals('8080', $uri->getPort()); + $this->assertEquals('/foo/bar', $uri->getPath()); + $this->assertEquals('abc=123', $uri->getQuery()); + $this->assertEquals('', $uri->getFragment()); + } + + public function testCreateFromGlobalsWithIPv6HostWithPort() + { + $globals = Environment::mock([ + 'SCRIPT_NAME' => '/index.php', + 'REQUEST_URI' => '/foo/bar', + 'PHP_AUTH_USER' => 'josh', + 'PHP_AUTH_PW' => 'sekrit', + 'QUERY_STRING' => 'abc=123', + 'HTTP_HOST' => '[2001:db8::1]:8080', + 'REMOTE_ADDR' => '2001:db8::1', + 'SERVER_PORT' => 8080, + ]); + + $uri = $this->createUriFactory()->createFromGlobals($globals); + + $this->assertEquals('josh:sekrit', $uri->getUserInfo()); + $this->assertEquals('[2001:db8::1]', $uri->getHost()); + $this->assertEquals('8080', $uri->getPort()); + $this->assertEquals('/foo/bar', $uri->getPath()); + $this->assertEquals('abc=123', $uri->getQuery()); + $this->assertEquals('', $uri->getFragment()); + } + + public function testCreateFromGlobalsWithBasePathContainingSpace() + { + $globals = Environment::mock([ + 'SCRIPT_NAME' => "/f'oo bar/index.php", + 'REQUEST_URI' => "/f%27oo%20bar/baz", + ]); + $uri = $this->createUriFactory()->createFromGlobals($globals); + + $this->assertEquals('/f%27oo%20bar/baz', $uri->getPath()); + } + + public function testWithPathWhenBaseRootIsEmpty() + { + $globals = Environment::mock([ + 'SCRIPT_NAME' => '/index.php', + 'REQUEST_URI' => '/bar', + ]); + $uri = $this->createUriFactory()->createFromGlobals($globals); + + $this->assertEquals('http://localhost/test', (string) $uri->withPath('test')); + } + + /** + * When the URL is /foo/index.php/bar/baz, we need the baseURL to be + * /foo/index.php so that routing works correctly. + * + * @ticket 1639 as a fix to 1590 broke this. + */ + public function testRequestURIContainsIndexDotPhp() + { + $uri = $this->createUriFactory()->createFromGlobals( + Environment::mock( + [ + 'SCRIPT_NAME' => '/foo/index.php', + 'REQUEST_URI' => '/foo/index.php/bar/baz', + ] + ) + ); + $this->assertSame('/foo/index.php/bar/baz', $uri->getPath()); + } + + public function testRequestURICanContainParams() + { + $uri = $this->createUriFactory()->createFromGlobals( + Environment::mock( + [ + 'REQUEST_URI' => '/foo?abc=123', + ] + ) + ); + $this->assertEquals('abc=123', $uri->getQuery()); + } + + public function testUriDistinguishZeroFromEmptyString() + { + $expected = 'https://0:0@0:1/0?0#0'; + $this->assertSame($expected, (string) $this->createUriFactory()->createUri($expected)); + } +} diff --git a/api/vendor/slim/psr7/tests/HeaderTest.php b/api/vendor/slim/psr7/tests/HeaderTest.php new file mode 100644 index 0000000..d062768 --- /dev/null +++ b/api/vendor/slim/psr7/tests/HeaderTest.php @@ -0,0 +1,61 @@ +headerFactory(); + $this->assertEquals('ACCEPT', $header->getOriginalName()); + } + + public function testGetNormalizedName(): void + { + $header = $this->headerFactory(); + $this->assertEquals('accept', $header->getNormalizedName()); + } + + public function testAddValue(): void + { + $header = $this->headerFactory(); + $header2 = $header->addValue('text/html'); + + $this->assertEquals(['application/json', 'text/html'], $header->getValues()); + $this->assertSame($header2, $header); + } + + public function testAddValuesString(): void + { + $header = $this->headerFactory(); + $header2 = $header->addValues('text/html'); + + $this->assertEquals(['application/json', 'text/html'], $header->getValues()); + $this->assertSame($header2, $header); + } +} diff --git a/api/vendor/slim/psr7/tests/HeadersTest.php b/api/vendor/slim/psr7/tests/HeadersTest.php new file mode 100644 index 0000000..0642058 --- /dev/null +++ b/api/vendor/slim/psr7/tests/HeadersTest.php @@ -0,0 +1,288 @@ + 'application/json', + ]; + + $headers = Headers::createFromGlobals(); + + unset($GLOBALS['getallheaders_return']); + + $this->assertEquals(['accept' => ['application/json']], $headers->getHeaders()); + $this->assertEquals(['ACCEPT' => ['application/json']], $headers->getHeaders(true)); + } + + public function testCreateFromGlobalsUsesEmptyArrayIfGetAllHeadersReturnsFalse() + { + $GLOBALS['getallheaders_return'] = false; + + $headers = Headers::createFromGlobals(); + + unset($GLOBALS['getallheaders_return']); + + $this->assertEquals([], $headers->getHeaders()); + } + + public function testAddHeader() + { + $headers = new Headers([ + 'Accept' => 'application/json', + ]); + + $headers->addHeader('Accept', 'text/html'); + + $this->assertEquals(['application/json', 'text/html'], $headers->getHeader('Accept')); + $this->assertEquals(['accept' => ['application/json', 'text/html']], $headers->getHeaders()); + $this->assertEquals(['Accept' => ['application/json', 'text/html']], $headers->getHeaders(true)); + } + + public function testAddHeaderValueEmptyArray() + { + $this->expectException(InvalidArgumentException::class); + + $headers = new Headers(); + $headers->addHeader('Header', []); + } + + public function testRemoveHeader() + { + $headers = new Headers([ + 'Accept' => 'application/json', + ]); + + $headers->removeHeader('Accept'); + + $this->assertEquals([], $headers->getHeader('Accept')); + $this->assertEquals([], $headers->getHeaders()); + } + + /** + * @doesNotPerformAssertions + */ + public function testRemoveHeaderByIncompatibleStringWithRFC() + { + $headers = new Headers(); + $headers->removeHeader(''); + } + + public function testGetHeader() + { + $headers = new Headers([ + 'Accept' => ['application/json', 'text/html'], + ]); + + $this->assertEquals(['application/json', 'text/html'], $headers->getHeader('accept')); + $this->assertEquals(['application/json', 'text/html'], $headers->getHeader('Accept')); + $this->assertEquals(['application/json', 'text/html'], $headers->getHeader('HTTP_ACCEPT')); + } + + public function testGetHeaderReturnsValidatedAndTrimedHeaderDefaultValue() + { + $headers = new Headers([]); + + $this->assertEquals(['application/json'], $headers->getHeader('accept', ' application/json')); + } + + public function testGetHeaderThrowsExceptionWithInvalidDefaultArgument() + { + $this->expectException(InvalidArgumentException::class); + + $headers = new Headers([]); + + $headers->getHeader('accept', new stdClass()); + } + + public function testSetHeader() + { + $headers = new Headers([ + 'Content-Length' => 0, + ]); + + $headers->setHeader('Content-Length', 100); + + $this->assertSame(['100'], $headers->getHeader('Content-Length')); + $this->assertEquals(['content-length' => ['100']], $headers->getHeaders()); + $this->assertEquals(['Content-Length' => ['100']], $headers->getHeaders(true)); + } + + public function testSetHeaderPreservesOriginalCaseIfHeaderAlreadyExists() + { + $headers = new Headers([ + 'CONTENT-LENGTH' => 0, + ]); + + $headers->setHeader('Content-Length', 100); + + $this->assertEquals(['content-length' => ['100']], $headers->getHeaders()); + $this->assertEquals(['CONTENT-LENGTH' => ['100']], $headers->getHeaders(true)); + } + + public function testSetHeaders() + { + $headers = new Headers([ + 'Content-Length' => 0, + ]); + + $headers->setHeaders([ + 'Accept' => 'application/json', + ]); + + $this->assertEquals(['accept' => ['application/json']], $headers->getHeaders()); + $this->assertEquals(['Accept' => ['application/json']], $headers->getHeaders(true)); + } + + public function testHasHeader() + { + $headers = new Headers([ + 'Accept' => 'application/json', + ]); + + $this->assertTrue($headers->hasHeader('accept')); + $this->assertTrue($headers->hasHeader('Accept')); + $this->assertTrue($headers->hasHeader('HTTP_ACCEPT')); + } + + public function testGetHeaders() + { + $headers = new Headers([ + 'HTTP_ACCEPT' => 'text/html', + 'HTTP_CONTENT_TYPE' => 'application/json', + ]); + + $expectedNormalizedHeaders = [ + 'accept' => ['text/html'], + 'content-type' => ['application/json'], + ]; + + $this->assertEquals($expectedNormalizedHeaders, $headers->getHeaders()); + } + + public function testGetHeadersPreservesOriginalCase() + { + $headers = new Headers([ + 'HTTP_ACCEPT' => 'text/html', + 'HTTP_CONTENT_TYPE' => 'application/json', + ]); + + $expectedOriginalHeaders = [ + 'ACCEPT' => ['text/html'], + 'CONTENT-TYPE' => ['application/json'], + ]; + + $this->assertEquals($expectedOriginalHeaders, $headers->getHeaders(true)); + } + + public function testParseAuthorizationHeader() + { + $expectedValue = 'Basic ' . base64_encode('user:password'); + + $headers = new Headers(['Authorization' => $expectedValue]); + $this->assertEquals([$expectedValue], $headers->getHeader('Authorization')); + + $headers = new Headers([], ['REDIRECT_HTTP_AUTHORIZATION' => 'cookie']); + $this->assertEquals(['cookie'], $headers->getHeader('Authorization')); + + $headers = new Headers([], ['PHP_AUTH_USER' => 'user', 'PHP_AUTH_PW' => 'password']); + $this->assertEquals([$expectedValue], $headers->getHeader('Authorization')); + + $headers = new Headers([], ['PHP_AUTH_DIGEST' => 'digest']); + $this->assertEquals(['digest'], $headers->getHeader('Authorization')); + } + + /** + * @dataProvider provideInvalidHeaderNames + */ + public function testWithInvalidHeaderName($headerName): void + { + $headers = new Headers(); + + $this->expectException(\InvalidArgumentException::class); + + $headers->setHeader($headerName, 'foo'); + } + + public static function provideInvalidHeaderNames(): array + { + return [ + [[]], + [false], + [new \stdClass()], + ["Content-Type\r\n\r\n"], + ["Content-Type\r\n"], + ["Content-Type\n"], + ["\r\nContent-Type"], + ["\nContent-Type"], + ["\n"], + ["\r\n"], + ["\t"], + ]; + } + + /** + * @dataProvider provideInvalidHeaderValues + */ + public function testSetInvalidHeaderValue($headerValue) + { + $headers = new Headers(); + + $this->expectException(\InvalidArgumentException::class); + + $headers->setHeader('Content-Type', $headerValue); + } + + public static function provideInvalidHeaderValues(): array + { + // Explicit tests for newlines as the most common exploit vector. + $tests = [ + ["new\nline"], + ["new\r\nline"], + ["new\rline"], + ["new\r\n line"], + ["newline\n"], + ["\nnewline"], + ["newline\r\n"], + ["\n\rnewline"], + ]; + + for ($i = 0; $i <= 0xff; $i++) { + if (\chr($i) == "\t") { + continue; + } + if (\chr($i) == " ") { + continue; + } + if ($i >= 0x21 && $i <= 0x7e) { + continue; + } + if ($i >= 0x80) { + continue; + } + + $tests[] = ["foo" . \chr($i) . "bar"]; + $tests[] = ["foo" . \chr($i)]; + } + + return $tests; + } +} diff --git a/api/vendor/slim/psr7/tests/Integration/BaseTestFactories.php b/api/vendor/slim/psr7/tests/Integration/BaseTestFactories.php new file mode 100644 index 0000000..1aa31d8 --- /dev/null +++ b/api/vendor/slim/psr7/tests/Integration/BaseTestFactories.php @@ -0,0 +1,57 @@ +createUri($uri); + } + + /** + * @param $data + * @return Stream + */ + protected function buildStream($data): Stream + { + if (!is_resource($data)) { + $h = fopen('php://temp', 'w+'); + fwrite($h, $data); + + $data = $h; + } + + return new Stream($data); + } + + /** + * @param $data + * @return UploadedFile + */ + protected function buildUploadableFile($data): UploadedFile + { + return new UploadedFile($this->buildStream($data)); + } +} diff --git a/api/vendor/slim/psr7/tests/Integration/RequestTest.php b/api/vendor/slim/psr7/tests/Integration/RequestTest.php new file mode 100644 index 0000000..0ea00bc --- /dev/null +++ b/api/vendor/slim/psr7/tests/Integration/RequestTest.php @@ -0,0 +1,36 @@ +buildUri('/'), + new Headers(), + [], + [], + $this->buildStream('') + ); + } +} diff --git a/api/vendor/slim/psr7/tests/Integration/ResponseTest.php b/api/vendor/slim/psr7/tests/Integration/ResponseTest.php new file mode 100644 index 0000000..7bd45fe --- /dev/null +++ b/api/vendor/slim/psr7/tests/Integration/ResponseTest.php @@ -0,0 +1,27 @@ +buildUri('/'), + new Headers(), + $_COOKIE, + $_SERVER, + $this->buildStream('') + ); + } +} diff --git a/api/vendor/slim/psr7/tests/Integration/StreamTest.php b/api/vendor/slim/psr7/tests/Integration/StreamTest.php new file mode 100644 index 0000000..e70af71 --- /dev/null +++ b/api/vendor/slim/psr7/tests/Integration/StreamTest.php @@ -0,0 +1,46 @@ +tempFilename = tempnam(sys_get_temp_dir(), 'Slim_Http_UploadedFileTest_'); + if (!$this->tempFilename) { + throw new \RuntimeException("Unable to create temporary file"); + } + file_put_contents($this->tempFilename, '12345'); + + return new UploadedFile( + $this->tempFilename, + basename($this->tempFilename), + 'text/plain', + (int)filesize($this->tempFilename) + ); + } + + protected function tearDown(): void + { + if (is_file($this->tempFilename)) { + unlink($this->tempFilename); + } + } +} diff --git a/api/vendor/slim/psr7/tests/Integration/UriTest.php b/api/vendor/slim/psr7/tests/Integration/UriTest.php new file mode 100644 index 0000000..525052a --- /dev/null +++ b/api/vendor/slim/psr7/tests/Integration/UriTest.php @@ -0,0 +1,30 @@ +createUri($uri); + } +} diff --git a/api/vendor/slim/psr7/tests/MessageTest.php b/api/vendor/slim/psr7/tests/MessageTest.php new file mode 100644 index 0000000..eced34f --- /dev/null +++ b/api/vendor/slim/psr7/tests/MessageTest.php @@ -0,0 +1,186 @@ +protocolVersion = '1.0'; + + $this->assertEquals('1.0', $message->getProtocolVersion()); + } + + public function testWithProtocolVersion() + { + $message = new MessageStub(); + $clone = $message->withProtocolVersion('1.0'); + + $this->assertEquals('1.0', $clone->protocolVersion); + } + + public function testWithProtocolVersionInvalidThrowsException() + { + $this->expectException(InvalidArgumentException::class); + + $message = new MessageStub(); + $message->withProtocolVersion('3.0'); + } + + public function testGetHeaders() + { + $headers = new Headers(); + $headers->addHeader('X-Foo', 'one'); + $headers->addHeader('X-Foo', 'two'); + $headers->addHeader('X-Foo', 'three'); + + $message = new MessageStub(); + $message->headers = $headers; + + $shouldBe = [ + 'X-Foo' => [ + 'one', + 'two', + 'three', + ], + ]; + + $this->assertEquals($shouldBe, $message->getHeaders()); + } + + public function testHasHeader() + { + $headers = new Headers(); + $headers->addHeader('X-Foo', 'one'); + + $message = new MessageStub(); + $message->headers = $headers; + + $this->assertTrue($message->hasHeader('X-Foo')); + $this->assertFalse($message->hasHeader('X-Bar')); + } + + public function testGetHeaderLine() + { + $headers = new Headers(); + $headers->addHeader('X-Foo', 'one'); + $headers->addHeader('X-Foo', 'two'); + $headers->addHeader('X-Foo', 'three'); + + $message = new MessageStub(); + $message->headers = $headers; + + $this->assertEquals('one,two,three', $message->getHeaderLine('X-Foo')); + $this->assertEquals('', $message->getHeaderLine('X-Bar')); + } + + public function testGetHeader() + { + $headers = new Headers(); + $headers->addHeader('X-Foo', 'one'); + $headers->addHeader('X-Foo', 'two'); + $headers->addHeader('X-Foo', 'three'); + + $message = new MessageStub(); + $message->headers = $headers; + + $this->assertEquals(['one', 'two', 'three'], $message->getHeader('X-Foo')); + $this->assertEquals([], $message->getHeader('X-Bar')); + } + + public function testWithHeader() + { + $headers = new Headers(); + $headers->addHeader('X-Foo', 'one'); + $message = new MessageStub(); + $message->headers = $headers; + $clone = $message->withHeader('X-Foo', 'bar'); + + $this->assertEquals('bar', $clone->getHeaderLine('X-Foo')); + } + + public function testWithAddedHeader() + { + $headers = new Headers(); + $headers->addHeader('X-Foo', 'one'); + $message = new MessageStub(); + $message->headers = $headers; + $clone = $message->withAddedHeader('X-Foo', 'two'); + + $this->assertEquals('one,two', $clone->getHeaderLine('X-Foo')); + } + + public function testWithoutHeader() + { + $headers = new Headers(); + $headers->addHeader('X-Foo', 'one'); + $headers->addHeader('X-Bar', 'two'); + $response = new MessageStub(); + $response->headers = $headers; + $clone = $response->withoutHeader('X-Foo'); + $shouldBe = [ + 'X-Bar' => ['two'], + ]; + + $this->assertEquals($shouldBe, $clone->getHeaders()); + } + + /** + * @doesNotPerformAssertions + */ + public function testWithoutHeaderByIncompatibleStringWithRFC() + { + $headers = new Headers(); + $response = new MessageStub(); + $response->headers = $headers; + $response->withoutHeader('getBody(); + $message = new MessageStub(); + $message->body = $body; + + $this->assertSame($body, $message->getBody()); + } + + public function testWithBody() + { + $body = $this->getBody(); + $body2 = $this->getBody(); + $message = new MessageStub(); + $message->body = $body; + $clone = $message->withBody($body2); + + $this->assertSame($body, $message->body); + $this->assertSame($body2, $clone->body); + } + + /** + * @return MockObject|Stream + */ + protected function getBody() + { + return $this + ->getMockBuilder(Stream::class) + ->disableOriginalConstructor() + ->getMock(); + } +} diff --git a/api/vendor/slim/psr7/tests/Mocks/MessageStub.php b/api/vendor/slim/psr7/tests/Mocks/MessageStub.php new file mode 100644 index 0000000..3672d84 --- /dev/null +++ b/api/vendor/slim/psr7/tests/Mocks/MessageStub.php @@ -0,0 +1,37 @@ +detach(), 'Returns null since there is no such underlying stream'); + self::assertNull($body->getSize(), 'Current size is undefined'); + self::assertSame(0, $body->tell(), 'Pointer is considered to be at position 0 to conform'); + self::assertTrue($body->eof(), 'Always considered to be at EOF'); + self::assertFalse($body->isSeekable(), 'Cannot seek'); + self::assertTrue($body->isWritable(), 'Body is writable'); + self::assertFalse($body->isReadable(), 'Body is not readable'); + self::assertSame('', $body->getContents(), 'Data cannot be retrieved once written'); + self::assertNull($body->getMetadata(), 'Metadata mechanism is not implemented'); + } + + public function testWrite() + { + $ob_initial_level = ob_get_level(); + + // Start output buffering. + ob_start(); + + // Start output buffering again to test the while-loop in the `write()` + // method that calls `ob_get_clean()` as long as the ob level is bigger + // than 0. + ob_start(); + echo 'buffer content: '; + + // Set the ob level shift that should be applied in the `ob_get_level()` + // function override. That way, the `write()` method would only flush + // the second ob, not the first one. We will add the initial ob level + // because phpunit may have started ob too. + $GLOBALS['ob_get_level_shift'] = -($ob_initial_level + 1); + + $body = new NonBufferedBody(); + $length0 = $body->write('hello '); + $length1 = $body->write('world'); + + unset($GLOBALS['ob_get_level_shift']); + $contents = ob_get_clean(); + + $this->assertEquals(strlen('buffer content: ') + strlen('hello '), $length0); + $this->assertEquals(strlen('world'), $length1); + $this->assertEquals('buffer content: hello world', $contents); + } + + public function testWithHeader() + { + (new Response()) + ->withBody(new NonBufferedBody()) + ->withHeader('Foo', 'Bar'); + + self::assertSame([ + [ + 'header' => 'Foo: Bar', + 'replace' => true, + 'status_code' => null + ] + ], HeaderStack::stack()); + } + + public function testWithAddedHeader() + { + (new Response()) + ->withBody(new NonBufferedBody()) + ->withHeader('Foo', 'Bar') + ->withAddedHeader('Foo', 'Baz'); + + self::assertSame([ + [ + 'header' => 'Foo: Bar', + 'replace' => true, + 'status_code' => null + ], + [ + 'header' => 'Foo: Bar,Baz', + 'replace' => true, + 'status_code' => null + ] + ], HeaderStack::stack()); + } + + public function testWithoutHeader() + { + (new Response()) + ->withBody(new NonBufferedBody()) + ->withHeader('Foo', 'Bar') + ->withoutHeader('Foo'); + + self::assertSame([], HeaderStack::stack()); + } + + public function testCloseThrowsRuntimeException() + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('A NonBufferedBody is not closable.'); + + (new NonBufferedBody())->close(); + } + + public function testSeekThrowsRuntimeException() + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('A NonBufferedBody is not seekable.'); + + (new NonBufferedBody())->seek(10); + } + + public function testRewindThrowsRuntimeException() + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('A NonBufferedBody is not rewindable.'); + + (new NonBufferedBody())->rewind(); + } + + public function testReadThrowsRuntimeException() + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('A NonBufferedBody is not readable.'); + + (new NonBufferedBody())->read(10); + } +} diff --git a/api/vendor/slim/psr7/tests/RequestTest.php b/api/vendor/slim/psr7/tests/RequestTest.php new file mode 100644 index 0000000..da54f98 --- /dev/null +++ b/api/vendor/slim/psr7/tests/RequestTest.php @@ -0,0 +1,458 @@ +createUri('https://example.com:443/foo/bar?abc=123'); + $headers = Headers::createFromGlobals($env); + $cookies = [ + 'user' => 'john', + 'id' => '123', + ]; + $serverParams = $env; + $body = (new StreamFactory())->createStream(); + $uploadedFiles = UploadedFile::createFromGlobals($env); + $request = new Request('GET', $uri, $headers, $cookies, $serverParams, $body, $uploadedFiles); + + return $request; + } + + public function testDisableSetter() + { + $request = $this->requestFactory(); + $request->foo = 'bar'; + + $this->assertFalse(property_exists($request, 'foo')); + } + + public function testAddsHostHeaderFromUri() + { + $request = $this->requestFactory(); + $this->assertEquals('example.com', $request->getHeaderLine('Host')); + } + + public function testGetMethod() + { + $this->assertEquals('GET', $this->requestFactory()->getMethod()); + } + + public function testWithMethod() + { + $request = $this->requestFactory()->withMethod('PUT'); + + $this->assertEquals('PUT', $request->getMethod()); + } + + public function testWithMethodCaseSensitive() + { + $request = $this->requestFactory()->withMethod('pOsT'); + + $this->assertEquals('pOsT', $request->getMethod()); + } + + public function testWithAllAllowedCharactersMethod() + { + $request = $this->requestFactory()->withMethod("!#$%&'*+.^_`|~09AZ-"); + + $this->assertEquals("!#$%&'*+.^_`|~09AZ-", $request->getMethod()); + } + + public function testWithMethodInvalid() + { + $this->expectException(InvalidArgumentException::class); + + $this->requestFactory()->withMethod('B@R'); + } + + public function testCreateRequestWithInvalidMethodString() + { + $this->expectException(InvalidArgumentException::class); + + $uri = (new UriFactory())->createUri('https://example.com:443/foo/bar?abc=123'); + $headers = new Headers(); + $cookies = []; + $serverParams = []; + $body = (new StreamFactory())->createStream(); + + new Request('B@R', $uri, $headers, $cookies, $serverParams, $body); + } + + public function testCreateRequestWithInvalidMethodOther() + { + $this->expectException(InvalidArgumentException::class); + + $uri = (new UriFactory())->createUri('https://example.com:443/foo/bar?abc=123'); + $headers = new Headers(); + $cookies = []; + $serverParams = []; + $body = (new StreamFactory())->createStream(); + + new Request(10, $uri, $headers, $cookies, $serverParams, $body); + } + + public function testGetRequestTarget() + { + $this->assertEquals('/foo/bar?abc=123', $this->requestFactory()->getRequestTarget()); + } + + public function testGetRequestTargetAlreadySet() + { + $request = $this->requestFactory(); + $prop = new ReflectionProperty($request, 'requestTarget'); + $prop->setAccessible(true); + $prop->setValue($request, '/foo/bar?abc=123'); + + $this->assertEquals('/foo/bar?abc=123', $request->getRequestTarget()); + } + + public function testGetRequestTargetIfNoUri() + { + $request = $this->requestFactory(); + $prop = new ReflectionProperty($request, 'uri'); + $prop->setAccessible(true); + $prop->setValue($request, null); + + $this->assertEquals('/', $request->getRequestTarget()); + } + + public function testWithRequestTarget() + { + $clone = $this->requestFactory()->withRequestTarget('/test?user=1'); + + $this->assertEquals('/test?user=1', $clone->getRequestTarget()); + } + + public function testWithRequestTargetThatHasSpaces() + { + $this->expectException(InvalidArgumentException::class); + + $this->requestFactory()->withRequestTarget('/test/m ore/stuff?user=1'); + } + + public function testGetUri() + { + $uri = (new UriFactory())->createUri('https://example.com:443/foo/bar?abc=123'); + $headers = new Headers(); + $cookies = []; + $serverParams = []; + $body = (new StreamFactory())->createStream(); + $request = new Request('GET', $uri, $headers, $cookies, $serverParams, $body); + + $this->assertSame($uri, $request->getUri()); + } + + public function testWithUri() + { + // Uris + $uri1 = (new UriFactory())->createUri('https://example.com:443/foo/bar?abc=123'); + $uri2 = (new UriFactory())->createUri('https://example2.com:443/test?xyz=123'); + + // Request + $headers = new Headers(); + $cookies = []; + $serverParams = []; + $body = (new StreamFactory())->createStream(); + $request = new Request('GET', $uri1, $headers, $cookies, $serverParams, $body); + $clone = $request->withUri($uri2); + + $this->assertSame($uri2, $clone->getUri()); + } + + public function testWithUriPreservesHost() + { + // When `$preserveHost` is set to `true`, this method interacts with + // the Host header in the following ways: + + // - If the Host header is missing or empty, and the new URI contains + // a host component, this method MUST update the Host header in the returned + // request. + $uri1 = (new UriFactory())->createUri(''); + $uri2 = (new UriFactory())->createUri('http://example2.com/test'); + + // Request + $headers = new Headers(); + $cookies = []; + $serverParams = []; + $body = (new StreamFactory())->createStream(); + $request = new Request('GET', $uri1, $headers, $cookies, $serverParams, $body); + + $clone = $request->withUri($uri2, true); + $this->assertSame('example2.com', $clone->getHeaderLine('Host')); + + // - If the Host header is missing or empty, and the new URI does not contain a + // host component, this method MUST NOT update the Host header in the returned + // request. + $uri3 = (new UriFactory())->createUri(''); + + $clone = $request->withUri($uri3, true); + $this->assertSame('', $clone->getHeaderLine('Host')); + + // - If a Host header is present and non-empty, this method MUST NOT update + // the Host header in the returned request. + $request = $request->withHeader('Host', 'example.com'); + $clone = $request->withUri($uri2, true); + $this->assertSame('example.com', $clone->getHeaderLine('Host')); + } + + public function testGetCookieParams() + { + $shouldBe = [ + 'user' => 'john', + 'id' => '123', + ]; + + $this->assertEquals($shouldBe, $this->requestFactory()->getCookieParams()); + } + + public function testWithCookieParams() + { + $request = $this->requestFactory(); + $clone = $request->withCookieParams(['type' => 'framework']); + + $this->assertEquals(['type' => 'framework'], $clone->getCookieParams()); + } + + public function testGetQueryParams() + { + $this->assertEquals(['abc' => '123'], $this->requestFactory()->getQueryParams()); + } + + public function testGetQueryParamsAlreadySet() + { + $request = $this->requestFactory(); + $prop = new ReflectionProperty($request, 'queryParams'); + $prop->setAccessible(true); + $prop->setValue($request, ['foo' => 'bar']); + + $this->assertEquals(['foo' => 'bar'], $request->getQueryParams()); + } + + public function testWithQueryParams() + { + $request = $this->requestFactory(); + $clone = $request->withQueryParams(['foo' => 'bar']); + $cloneUri = $clone->getUri(); + + $this->assertEquals('abc=123', $cloneUri->getQuery()); // <-- Unchanged + $this->assertEquals(['foo' => 'bar'], $clone->getQueryParams()); // <-- Changed + } + + public function testWithQueryParamsEmptyArray() + { + $request = $this->requestFactory(); + $clone = $request->withQueryParams([]); + $cloneUri = $clone->getUri(); + + $this->assertEquals('abc=123', $cloneUri->getQuery()); // <-- Unchanged + $this->assertEquals([], $clone->getQueryParams()); // <-- Changed + } + + public function testGetQueryParamsWithoutUri() + { + $request = $this->requestFactory(); + $prop = new ReflectionProperty($request, 'uri'); + $prop->setAccessible(true); + $prop->setValue($request, null); + + $this->assertEquals([], $request->getQueryParams()); + } + + public function testWithUploadedFiles() + { + $files = [new UploadedFile('foo.txt'), new UploadedFile('bar.txt')]; + + $request = $this->requestFactory(); + $prevUploaded = $request->getUploadedFiles(); + $clone = $request->withUploadedFiles($files); + + $this->assertEquals($prevUploaded, $request->getUploadedFiles()); + $this->assertEquals($files, $clone->getUploadedFiles()); + } + + public function testGetServerParams() + { + $mockEnv = Environment::mock(["HTTP_AUTHORIZATION" => "test"]); + $request = $this->requestFactory(["HTTP_AUTHORIZATION" => "test"]); + + $serverParams = $request->getServerParams(); + foreach ($serverParams as $key => $value) { + if ($key == 'REQUEST_TIME' || $key == 'REQUEST_TIME_FLOAT') { + $this->assertGreaterThanOrEqual( + $mockEnv[$key], + $value, + sprintf("%s value of %s was less than expected value of %s", $key, $value, $mockEnv[$key]) + ); + } else { + $this->assertEquals( + $mockEnv[$key], + $value, + sprintf("%s value of %s did not equal expected value of %s", $key, $value, $mockEnv[$key]) + ); + } + } + } + + public function testGetAttributes() + { + $request = $this->requestFactory(); + $attrProp = new ReflectionProperty($request, 'attributes'); + $attrProp->setAccessible(true); + $attrProp->setValue($request, ['foo' => 'bar']); + + $this->assertEquals(['foo' => 'bar'], $request->getAttributes()); + } + + public function testGetAttribute() + { + $request = $this->requestFactory(); + $attrProp = new ReflectionProperty($request, 'attributes'); + $attrProp->setAccessible(true); + $attrProp->setValue($request, ['foo' => 'bar']); + + $this->assertEquals('bar', $request->getAttribute('foo')); + $this->assertNull($request->getAttribute('bar')); + $this->assertEquals(2, $request->getAttribute('bar', 2)); + } + + public function testWithAttribute() + { + $request = $this->requestFactory(); + $attrProp = new ReflectionProperty($request, 'attributes'); + $attrProp->setAccessible(true); + $attrProp->setValue($request, ['foo' => 'bar']); + $clone = $request->withAttribute('test', '123'); + + $this->assertEquals('123', $clone->getAttribute('test')); + } + + public function testWithoutAttribute() + { + $request = $this->requestFactory(); + $attrProp = new ReflectionProperty($request, 'attributes'); + $attrProp->setAccessible(true); + $attrProp->setValue($request, ['foo' => 'bar']); + $clone = $request->withoutAttribute('foo'); + + $this->assertNull($clone->getAttribute('foo')); + } + + public function testGetParsedBodyWhenAlreadyParsed() + { + $request = $this->requestFactory(); + $prop = new ReflectionProperty($request, 'parsedBody'); + $prop->setAccessible(true); + $prop->setValue($request, ['foo' => 'bar']); + + $this->assertEquals(['foo' => 'bar'], $request->getParsedBody()); + } + + public function testGetParsedBodyWhenBodyDoesNotExist() + { + $request = $this->requestFactory(); + $prop = new ReflectionProperty($request, 'body'); + $prop->setAccessible(true); + $prop->setValue($request, null); + + $this->assertNull($request->getParsedBody()); + } + + public function testWithParsedBody() + { + $clone = $this->requestFactory()->withParsedBody(['xyz' => '123']); + + $this->assertEquals(['xyz' => '123'], $clone->getParsedBody()); + } + + public function testWithParsedBodyEmptyArray() + { + $method = 'GET'; + $uri = new Uri('https', 'example.com', 443, '/foo/bar', 'abc=123', '', ''); + $headers = new Headers(); + $headers->setHeader('Content-Type', 'application/x-www-form-urlencoded;charset=utf8'); + $cookies = []; + $serverParams = []; + $body = (new StreamFactory())->createStream(); + $body->write('foo=bar'); + $request = new Request($method, $uri, $headers, $cookies, $serverParams, $body); + + $clone = $request->withParsedBody([]); + + $this->assertEquals([], $clone->getParsedBody()); + } + + public function testWithParsedBodyNull() + { + $method = 'GET'; + $uri = new Uri('https', 'example.com', 443, '/foo/bar', 'abc=123', '', ''); + $headers = new Headers(); + $headers->setHeader('Content-Type', 'application/x-www-form-urlencoded;charset=utf8'); + $cookies = []; + $serverParams = []; + $body = (new StreamFactory())->createStream(); + $body->write('foo=bar'); + $request = new Request($method, $uri, $headers, $cookies, $serverParams, $body); + + $clone = $request->withParsedBody(null); + + $this->assertNull($clone->getParsedBody()); + } + + public function testGetParsedBodyReturnsNullWhenThereIsNoBodyData() + { + $request = $this->requestFactory(['REQUEST_METHOD' => 'POST']); + + $this->assertNull($request->getParsedBody()); + } + + public function testGetParsedBodyReturnsNullWhenThereIsNoMediaTypeParserRegistered() + { + $request = $this->requestFactory([ + 'REQUEST_METHOD' => 'POST', + 'CONTENT_TYPE' => 'text/csv', + ]); + $request->getBody()->write('foo,bar,baz'); + + $this->assertNull($request->getParsedBody()); + } + + public function testWithParsedBodyInvalid() + { + $this->expectException(InvalidArgumentException::class); + + $this->requestFactory()->withParsedBody(2); + } + + public function testWithParsedBodyInvalidFalseValue() + { + $this->expectException(InvalidArgumentException::class); + + $this->requestFactory()->withParsedBody(false); + } +} diff --git a/api/vendor/slim/psr7/tests/ResponseTest.php b/api/vendor/slim/psr7/tests/ResponseTest.php new file mode 100644 index 0000000..7b73488 --- /dev/null +++ b/api/vendor/slim/psr7/tests/ResponseTest.php @@ -0,0 +1,191 @@ +setAccessible(true); + + $bodyReflection = new ReflectionProperty($response, 'body'); + $bodyReflection->setAccessible(true); + + $this->assertEquals(200, $response->getStatusCode()); + $this->assertInstanceOf(Headers::class, $headersReflection->getValue($response)); + $this->assertInstanceOf(Stream::class, $bodyReflection->getValue($response)); + } + + public function testConstructorWithCustomArgs() + { + $headers = new Headers(); + $body = new Stream(fopen('php://temp', 'r+')); + $response = new Response(404, $headers, $body); + + $headersReflection = new ReflectionProperty($response, 'headers'); + $headersReflection->setAccessible(true); + + $bodyReflection = new ReflectionProperty($response, 'body'); + $bodyReflection->setAccessible(true); + + $this->assertEquals(404, $response->getStatusCode()); + $this->assertSame($headers, $headersReflection->getValue($response)); + $this->assertSame($body, $bodyReflection->getValue($response)); + } + + public function testDeepCopyClone() + { + $headers = new Headers(); + $body = new Stream(fopen('php://temp', 'r+')); + $response = new Response(404, $headers, $body); + $clone = clone $response; + + $headersReflection = new ReflectionProperty($response, 'headers'); + $headersReflection->setAccessible(true); + + $this->assertEquals(404, $clone->getStatusCode()); + $this->assertEquals('1.1', $clone->getProtocolVersion()); + $this->assertNotSame($headers, $headersReflection->getValue($clone)); + } + + public function testDisableSetter() + { + $response = new Response(); + $response->foo = 'bar'; + + $this->assertFalse(property_exists($response, 'foo')); + } + + public function testGetStatusCode() + { + $response = new Response(); + $responseStatus = new ReflectionProperty($response, 'status'); + $responseStatus->setAccessible(true); + $responseStatus->setValue($response, 404); + + $this->assertEquals(404, $response->getStatusCode()); + } + + public function testWithStatus() + { + $response = new Response(); + $clone = $response->withStatus(302); + + $this->assertEquals(302, $clone->getStatusCode()); + } + + public function testWithStatusInvalidStatusCodeThrowsException() + { + $this->expectException(InvalidArgumentException::class); + + $response = new Response(); + $response->withStatus(800); + } + + public function testWithStatusInvalidReasonPhraseThrowsException() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Response reason phrase must be a string'); + + $response = new Response(); + $response->withStatus(200, null); + } + + public function testWithStatusEmptyReasonPhrase() + { + $responseWithNoMessage = new Response(310); + + $this->assertEquals('', $responseWithNoMessage->getReasonPhrase()); + } + + public function testReasonPhraseContainsCarriageReturn() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Reason phrase contains one of the following prohibited characters: \r \n'); + + $response = new Response(); + $response = $response->withStatus(404, "Not Found\r"); + } + + public function testReasonPhraseContainsLineFeed() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Reason phrase contains one of the following prohibited characters: \r \n'); + + $response = new Response(); + $response = $response->withStatus(404, "Not Found\n"); + } + + public function testWithStatusValidReasonPhraseObject() + { + $response = new Response(); + $response = $response->withStatus(200, new StringableTestObject('Slim OK')); + $this->assertEquals('Slim OK', $response->getReasonPhrase()); + } + + public function testGetReasonPhrase() + { + $response = new Response(404); + + $this->assertEquals('Not Found', $response->getReasonPhrase()); + } + + public function testEmptyReasonPhraseForUnrecognisedCode() + { + $response = new Response(); + $response = $response->withStatus(199); + + $this->assertSame('', $response->getReasonPhrase()); + } + + public function testSetReasonPhraseForUnrecognisedCode() + { + $response = new Response(); + $response = $response->withStatus(199, 'Random Message'); + + $this->assertEquals('Random Message', $response->getReasonPhrase()); + } + + public function testGetCustomReasonPhrase() + { + $response = new Response(); + $clone = $response->withStatus(200, 'Custom Phrase'); + + $this->assertEquals('Custom Phrase', $clone->getReasonPhrase()); + } + + public function testResponseHeadersDoNotContainAuthorizationHeader() + { + $_SERVER = Environment::mock( + [ + 'PHP_AUTH_USER' => 'foo' + ] + ); + + $response = new Response(); + $this->assertEmpty($response->getHeaders()); + } +} diff --git a/api/vendor/slim/psr7/tests/StreamTest.php b/api/vendor/slim/psr7/tests/StreamTest.php new file mode 100644 index 0000000..0a97197 --- /dev/null +++ b/api/vendor/slim/psr7/tests/StreamTest.php @@ -0,0 +1,284 @@ +pipeFh != null) { + // prevent broken pipe error message + stream_get_contents($this->pipeFh); + } + } + + public function testIsPipe() + { + $this->openPipeStream(); + + $this->assertTrue($this->pipeStream->isPipe()); + + $this->pipeStream->detach(); + $this->assertFalse($this->pipeStream->isPipe()); + + $fhFile = fopen(__FILE__, 'r'); + $fileStream = new Stream($fhFile); + $this->assertFalse($fileStream->isPipe()); + } + + public function testIsPipeReadable() + { + $this->openPipeStream(); + + $this->assertTrue($this->pipeStream->isReadable()); + } + + public function testPipeIsNotSeekable() + { + $this->openPipeStream(); + + $this->assertFalse($this->pipeStream->isSeekable()); + } + + public function testCannotSeekPipe() + { + $this->expectException(RuntimeException::class); + + $this->openPipeStream(); + + $this->pipeStream->seek(0); + } + + public function testCannotTellPipe() + { + $this->expectException(RuntimeException::class); + + $this->openPipeStream(); + + $this->pipeStream->tell(); + } + + public function testCannotRewindPipe() + { + $this->expectException(RuntimeException::class); + + $this->openPipeStream(); + + $this->pipeStream->rewind(); + } + + public function testPipeGetSizeYieldsNull() + { + $this->openPipeStream(); + + $this->assertNull($this->pipeStream->getSize()); + } + + public function testClosePipe() + { + $this->openPipeStream(); + + // prevent broken pipe error message + stream_get_contents($this->pipeFh); + + $this->pipeStream->close(); + $this->pipeFh = null; + + $this->assertFalse($this->pipeStream->isPipe()); + } + + public function testPipeToString() + { + $this->openPipeStream(); + $content = trim((string) $this->pipeStream); + + $this->assertSame('12', $content); + } + + public function testConvertsToStringPartiallyReadNonSeekableStream() + { + $this->openPipeStream(); + $head = $this->pipeStream->read(1); + $tail = trim((string) $this->pipeStream); + + $this->assertSame('1', $head); + $this->assertSame('2', $tail); + } + + public function testPipeGetContents() + { + $this->openPipeStream(); + + $contents = trim($this->pipeStream->getContents()); + $this->assertSame('12', $contents); + } + + public function testIsWriteable() + { + $resource = fopen('php://temp', 'w'); + $stream = new Stream($resource); + + $this->assertEquals(13, $stream->write('Hello, world!')); + + $this->assertTrue($stream->isWritable()); + } + + public function testIsReadable() + { + $resource = fopen('php://temp', 'r'); + $stream = new Stream($resource); + + $this->assertTrue($stream->isReadable()); + $this->assertFalse($stream->isWritable()); + } + + public function testIsWritableAndReadable() + { + $resource = fopen('php://temp', 'w+'); + $stream = new Stream($resource); + + $stream->write('Hello, world!'); + + $this->assertEquals('Hello, world!', $stream); + + $this->assertTrue($stream->isWritable()); + $this->assertTrue($stream->isReadable()); + } + + /** + * Test that a call to the protected method `attach` would invoke `detach`. + * + * @throws ReflectionException + */ + public function testAttachAgain() + { + $this->openPipeStream(); + + $streamProphecy = $this->prophesize(Stream::class); + + /** @noinspection PhpUndefinedMethodInspection */ + $streamProphecy->detach()->shouldBeCalled(); + + /** @var Stream $stream */ + $stream = $streamProphecy->reveal(); + + $streamProperty = new ReflectionProperty(Stream::class, 'stream'); + $streamProperty->setAccessible(true); + $streamProperty->setValue($stream, $this->pipeFh); + + $attachMethod = new ReflectionMethod(Stream::class, 'attach'); + $attachMethod->setAccessible(true); + $attachMethod->invoke($stream, $this->pipeFh); + } + + public function testGetMetaDataReturnsNullIfStreamIsDetached() + { + $resource = fopen('php://temp', 'rw+'); + $stream = new Stream($resource); + $stream->detach(); + + $this->assertNull($stream->getMetadata()); + } + + private function openPipeStream() + { + $this->pipeFh = popen('echo 12', 'r'); + $this->pipeStream = new Stream($this->pipeFh); + } + + public function testReadOnlyCachedStreamsAreDisallowed() + { + $resource = fopen('php://temp', 'w+'); + $cache = new Stream(fopen('php://temp', 'r')); + + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Cache stream must be seekable and writable'); + new Stream($resource, $cache); + } + + public function testNonSeekableCachedStreamsAreDisallowed() + { + $resource = fopen('php://temp', 'w+'); + $cache = new Stream(fopen('php://output', 'w')); + + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Cache stream must be seekable and writable'); + + new Stream($resource, $cache); + } + + public function testCachedStreamsGetsContentFromTheCache() + { + $resource = popen('echo HelloWorld', 'r'); + $stream = new Stream($resource, new Stream(fopen('php://temp', 'w+'))); + + $this->assertEquals("HelloWorld\n", $stream->getContents()); + $this->assertEquals("HelloWorld\n", $stream->getContents()); + } + + public function testCachedStreamsFillsCacheOnRead() + { + $resource = fopen('data://,0', 'r'); + $stream = new Stream($resource, new Stream(fopen('php://temp', 'w+'))); + + $this->assertEquals("0", $stream->read(100)); + $this->assertEquals("0", $stream->__toString()); + } + + public function testDetachingStreamDropsCache() + { + $cache = new Stream(fopen('php://temp', 'w+')); + $resource = fopen('data://,foo', 'r'); + $stream = new Stream($resource, $cache); + + $stream->detach(); + + $cacheProperty = new ReflectionProperty(Stream::class, 'cache'); + $cacheProperty->setAccessible(true); + $finishedProperty = new ReflectionProperty(Stream::class, 'finished'); + $finishedProperty->setAccessible(true); + + $this->assertNull($cacheProperty->getValue($stream)); + $this->assertFalse($finishedProperty->getValue($stream)); + } + + public function testCachedStreamsRewindIfFinishedOnToString() + { + $resource = fopen('data://,foo', 'r'); + + $stream = new Stream($resource, new Stream(fopen('php://temp', 'w+'))); + + $this->assertEquals('foo', (string)$stream); + $this->assertEquals('foo', (string)$stream); + } +} diff --git a/api/vendor/slim/psr7/tests/StringableTestObject.php b/api/vendor/slim/psr7/tests/StringableTestObject.php new file mode 100644 index 0000000..36a6785 --- /dev/null +++ b/api/vendor/slim/psr7/tests/StringableTestObject.php @@ -0,0 +1,23 @@ +value; + } +} diff --git a/api/vendor/slim/psr7/tests/UploadedFileTest.php b/api/vendor/slim/psr7/tests/UploadedFileTest.php new file mode 100644 index 0000000..fa13a0c --- /dev/null +++ b/api/vendor/slim/psr7/tests/UploadedFileTest.php @@ -0,0 +1,676 @@ +assertEquals($expected, $uploadedFile); + } + + /** + * @param array $input The input array to parse. + * + * @dataProvider providerCreateFromGlobals + */ + public function testCreateFromGlobalsFromUserData(array $input) + { + //If slim.files provided - it will return what was provided + $userData['slim.files'] = $input; + + $uploadedFile = UploadedFile::createFromGlobals(Environment::mock($userData)); + $this->assertEquals($input, $uploadedFile); + } + + public function testCreateFromGlobalsWithoutFile() + { + unset($_FILES); + + $uploadedFile = UploadedFile::createFromGlobals(Environment::mock()); + $this->assertEquals([], $uploadedFile); + } + + public function testConstructor(): UploadedFile + { + $attr = [ + 'tmp_name' => self::$filename, + 'name' => 'my-avatar.txt', + 'size' => 8, + 'type' => 'text/plain', + 'error' => 0, + ]; + + $uploadedFile = new UploadedFile( + $attr['tmp_name'], + $attr['name'], + $attr['type'], + $attr['size'], + $attr['error'], + false + ); + + $this->assertEquals($attr['name'], $uploadedFile->getClientFilename()); + $this->assertEquals($attr['type'], $uploadedFile->getClientMediaType()); + $this->assertEquals($attr['size'], $uploadedFile->getSize()); + $this->assertEquals($attr['error'], $uploadedFile->getError()); + $this->assertEquals($attr['tmp_name'], $uploadedFile->getFilePath()); + + return $uploadedFile; + } + + public function testConstructorSapi(): UploadedFile + { + $attr = [ + 'tmp_name' => self::$filename, + 'name' => 'my-avatar.txt', + 'size' => 8, + 'type' => 'text/plain', + 'error' => 0, + ]; + + $uploadedFile = new UploadedFile( + $attr['tmp_name'], + $attr['name'], + $attr['type'], + $attr['size'], + $attr['error'], + true + ); + + $this->assertEquals($attr['name'], $uploadedFile->getClientFilename()); + $this->assertEquals($attr['type'], $uploadedFile->getClientMediaType()); + $this->assertEquals($attr['size'], $uploadedFile->getSize()); + $this->assertEquals($attr['error'], $uploadedFile->getError()); + $this->assertEquals($attr['tmp_name'], $uploadedFile->getFilePath()); + + return $uploadedFile; + } + + /** + * @depends testConstructor + * + * @param UploadedFile $uploadedFile + * + * @return UploadedFile + */ + public function testGetStream(UploadedFile $uploadedFile): UploadedFile + { + $stream = $uploadedFile->getStream(); + $this->assertEquals(true, $uploadedFile->getStream() instanceof Stream); + $stream->close(); + + return $uploadedFile; + } + + /** + * @depends testConstructor + * + * @param UploadedFile $uploadedFile + * + */ + public function testMoveToNotWritable(UploadedFile $uploadedFile) + { + $this->expectException(InvalidArgumentException::class); + + $tempName = uniqid('file-'); + $path = 'some_random_dir' . DIRECTORY_SEPARATOR . $tempName; + $uploadedFile->moveTo($path); + } + + /** + * @depends testConstructor + * + * @param UploadedFile $uploadedFile + * + * @return UploadedFile + */ + public function testMoveTo(UploadedFile $uploadedFile): UploadedFile + { + $tempName = uniqid('file-'); + $path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . $tempName; + $uploadedFile->moveTo($path); + + $this->assertFileExists($path); + + unlink($path); + + return $uploadedFile; + } + + public function testMoveToRenameFailure() + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessageMatches('/^Error moving uploaded file .* to .*$/'); + + $uploadedFile = $this->generateNewTmpFile(); + + $tempName = uniqid('file-'); + $path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . $tempName; + + $GLOBALS['rename_return'] = false; + $uploadedFile->moveTo($path); + } + + /** + * @depends testConstructorSapi + * + * @param UploadedFile $uploadedFile + * + */ + public function testMoveToSapiNonUploadedFile(UploadedFile $uploadedFile) + { + $this->expectException(RuntimeException::class); + + $tempName = uniqid('file-'); + $path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . $tempName; + $uploadedFile->moveTo($path); + } + + /** + * @depends testConstructorSapi + * + * @param UploadedFile $uploadedFile + * + */ + public function testMoveToSapiMoveUploadedFileFails(UploadedFile $uploadedFile) + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessageMatches('~Error moving uploaded file.*~'); + + $GLOBALS['is_uploaded_file_return'] = true; + + $tempName = uniqid('file-'); + $path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . $tempName; + $uploadedFile->moveTo($path); + } + + /** + * @depends testMoveTo + * + * @param UploadedFile $uploadedFile + * + */ + public function testMoveToCannotBeDoneTwice(UploadedFile $uploadedFile) + { + $this->expectException(RuntimeException::class); + + $tempName = uniqid('file-'); + $path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . $tempName; + $uploadedFile->moveTo($path); + $this->assertFileExists($path); + unlink($path); + + $uploadedFile->moveTo($path); + } + + /** + * This test must run after testMoveTo + * + * @depends testConstructor + * + * @param UploadedFile $uploadedFile + * + */ + public function testMoveToAgain(UploadedFile $uploadedFile) + { + $this->expectException(RuntimeException::class); + + $tempName = uniqid('file-'); + $path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . $tempName; + $uploadedFile->moveTo($path); + } + + /** + * This test must run after testMoveTo + * + * @depends testConstructor + * + * @param UploadedFile $uploadedFile + * + */ + public function testMovedStream(UploadedFile $uploadedFile) + { + $this->expectException(RuntimeException::class); + + $uploadedFile->getStream(); + } + + public function testMoveToStream() + { + $uploadedFile = $this->generateNewTmpFile(); + + $fileProperty = new ReflectionProperty($uploadedFile, 'file'); + $fileProperty->setAccessible(true); + $fileName = $fileProperty->getValue($uploadedFile); + + $contents = file_get_contents($fileName); + + ob_start(); + $uploadedFile->moveTo('php://output'); + $movedFileContents = ob_get_clean(); + + $this->assertEquals($contents, $movedFileContents); + $this->assertFileDoesNotExist($fileName); + } + + public function testMoveToStreamCopyFailure() + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Error moving uploaded file to php://output'); + + $uploadedFile = $this->generateNewTmpFile(); + + $GLOBALS['copy_return'] = false; + $uploadedFile->moveTo('php://output'); + } + + public function testFileUploadWithTempStream() + { + $streamFactory = function (...$args) { + return (new StreamFactory())->createStream(...$args); + }; + $uploadedFileFactory = function (...$args) { + return (new UploadedFileFactory())->createUploadedFile(...$args); + }; + $this->runFileUploadWithTempStreamTest($streamFactory, $uploadedFileFactory); + } + + /** + * This test sequence has been inspired by UploadedFileFactoryTestCase from http-interop/http-factory-tests package. + * + * @param callable $streamFactory + * @param callable $uploadedFileFactory + */ + private function runFileUploadWithTempStreamTest(callable $streamFactory, callable $uploadedFileFactory) + { + $content = 'this is your capitan speaking'; + $error = UPLOAD_ERR_OK; + $clientFilename = 'test.txt'; + $clientMediaType = 'text/plain'; + + $stream = call_user_func($streamFactory, $content); + $file = call_user_func( + $uploadedFileFactory, + $stream, + strlen($content), + $error, + $clientFilename, + $clientMediaType + ); + + $this->assertInstanceOf(UploadedFileInterface::class, $file); + $this->assertSame($content, (string)$file->getStream()); + $this->assertSame(strlen($content), $file->getSize()); + $this->assertSame($error, $file->getError()); + $this->assertSame($clientFilename, $file->getClientFilename()); + $this->assertSame($clientMediaType, $file->getClientMediaType()); + $this->assertSame($stream->getMetadata('uri'), $file->getFilePath()); + } + + public function testCreateUploadedFileWithInvalidArguments() + { + $this->expectException(InvalidArgumentException::class); + + new UploadedFile(42); // a random value that is neither a string nor an instance of StreamInterface + } + + public function testCreateUploadedFileWithInvalidUri() + { + $this->expectException(InvalidArgumentException::class); + + $streamProphecy = $this->prophesize(StreamInterface::class); + + /** @noinspection PhpUndefinedMethodInspection */ + $streamProphecy + ->getMetadata('uri') + ->willReturn(null) + ->shouldBeCalled(); + $stream = $streamProphecy->reveal(); + + // Test with a StreamInterface that returns `null` + // when `$stream->getMetadata('uri')` is called (which is an invalid case). + new UploadedFile($stream); + } + + public static function providerCreateFromGlobals(): array + { + return [ + // no nest: + [ + // $_FILES array + [ + 'avatar' => [ + 'tmp_name' => 'phpUxcOty', + 'name' => 'my-avatar.png', + 'size' => 90996, + 'type' => 'image/png', + 'error' => 0, + ], + ], + // expected format of array + [ + 'avatar' => new UploadedFile('phpUxcOty', 'my-avatar.png', 'image/png', 90996, UPLOAD_ERR_OK, true) + ] + ], + // no nest, with error: + [ + // $_FILES array + [ + 'avatar' => [ + 'tmp_name' => 'phpUxcOty', + 'name' => 'my-avatar.png', + 'size' => 90996, + 'type' => 'image/png', + 'error' => 7, + ], + ], + // expected format of array + [ + 'avatar' => new UploadedFile( + 'phpUxcOty', + 'my-avatar.png', + 'image/png', + 90996, + UPLOAD_ERR_CANT_WRITE, + true + ) + ] + ], + + // array of files: + [ + // $_FILES array + [ + 'avatars' => [ + 'tmp_name' => [ + 0 => __DIR__ . DIRECTORY_SEPARATOR . 'file0.txt', + 1 => __DIR__ . DIRECTORY_SEPARATOR . 'file1.html', + ], + 'name' => [ + 0 => 'file0.txt', + 1 => 'file1.html', + ], + 'type' => [ + 0 => 'text/plain', + 1 => 'text/html', + ], + 'error' => [ + 0 => 0, + 1 => 0 + ], + 'size' => [ + 0 => 0, + 1 => 0 + ] + ], + ], + // expected format of array + [ + 'avatars' => [ + 0 => new UploadedFile( + __DIR__ . DIRECTORY_SEPARATOR . 'file0.txt', + 'file0.txt', + 'text/plain', + null, + UPLOAD_ERR_OK, + true + ), + 1 => new UploadedFile( + __DIR__ . DIRECTORY_SEPARATOR . 'file1.html', + 'file1.html', + 'text/html', + null, + UPLOAD_ERR_OK, + true + ), + ], + ] + ], + // array of files as multidimensional array: + [ + // $_FILES array + [ + [ + 'avatars' => [ + 'tmp_name' => [ + 0 => __DIR__ . DIRECTORY_SEPARATOR . 'file0.txt', + 1 => __DIR__ . DIRECTORY_SEPARATOR . 'file1.html', + ], + 'name' => [ + 0 => 'file0.txt', + 1 => 'file1.html', + ], + 'type' => [ + 0 => 'text/plain', + 1 => 'text/html', + ], + 'size' => [ + 0 => 0, + 1 => 0, + ], + ], + ], + ], + // expected format of array + [ + 0 => + [ + 'avatars' => + [ + 'tmp_name' => [], + 'name' => [], + 'type' => [], + 'size' => [], + ], + ], + ], + ], + // single nested file: + [ + // $_FILES array + [ + 'details' => [ + 'tmp_name' => [ + 'avatar' => __DIR__ . DIRECTORY_SEPARATOR . 'file0.txt', + ], + 'name' => [ + 'avatar' => 'file0.txt', + ], + 'type' => [ + 'avatar' => 'text/plain', + ], + 'error' => [ + 'avatar' => 0, + ], + 'size' => [ + 'avatar' => 0, + ], + ], + ], + // expected format of array + [ + 'details' => [ + 'avatar' => new UploadedFile( + __DIR__ . DIRECTORY_SEPARATOR . 'file0.txt', + 'file0.txt', + 'text/plain', + null, + UPLOAD_ERR_OK, + true + ), + ], + ] + ], + // nested array of files: + [ + [ + 'files' => [ + 'tmp_name' => [ + 'details' => [ + 'avatar' => [ + 0 => __DIR__ . DIRECTORY_SEPARATOR . 'file0.txt', + 1 => __DIR__ . DIRECTORY_SEPARATOR . 'file1.html', + ], + ], + ], + 'name' => [ + 'details' => [ + 'avatar' => [ + 0 => 'file0.txt', + 1 => 'file1.html', + ], + ], + ], + 'type' => [ + 'details' => [ + 'avatar' => [ + 0 => 'text/plain', + 1 => 'text/html', + ], + ], + ], + 'error' => [ + 'details' => [ + 'avatar' => [ + 0 => 0, + 1 => 0 + ], + ], + ], + 'size' => [ + 'details' => [ + 'avatar' => [ + 0 => 0, + 1 => 0 + ], + ], + ], + ], + ], + // expected format of array + [ + 'files' => [ + 'details' => [ + 'avatar' => [ + 0 => new UploadedFile( + __DIR__ . DIRECTORY_SEPARATOR . 'file0.txt', + 'file0.txt', + 'text/plain', + null, + UPLOAD_ERR_OK, + true + ), + 1 => new UploadedFile( + __DIR__ . DIRECTORY_SEPARATOR . 'file1.html', + 'file1.html', + 'text/html', + null, + UPLOAD_ERR_OK, + true + ), + ], + ], + ], + ] + ], + ]; + } +} diff --git a/api/vendor/slim/psr7/tests/UriTest.php b/api/vendor/slim/psr7/tests/UriTest.php new file mode 100644 index 0000000..aeb3a85 --- /dev/null +++ b/api/vendor/slim/psr7/tests/UriTest.php @@ -0,0 +1,383 @@ + 80, + 'wss' => 443, + ]; + }; + + $this->assertEquals('ws', $wsUri->getScheme()); + } + + public function testGetScheme() + { + $this->assertEquals('https', $this->uriFactory()->getScheme()); + } + + public function testWithScheme() + { + $uri = $this->uriFactory()->withScheme('http'); + + $this->assertEquals('http', $uri->getScheme()); + } + + public function testWithSchemeRemovesSuffix() + { + $uri = $this->uriFactory()->withScheme('http://'); + + $this->assertEquals('http', $uri->getScheme()); + } + + public function testWithSchemeEmpty() + { + $uri = $this->uriFactory()->withScheme(''); + + $this->assertEquals('', $uri->getScheme()); + } + + public function testWithSchemeInvalid() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessageMatches('/^Uri scheme must be one of:.*$/'); + + $this->uriFactory()->withScheme('ftp'); + } + + public function testWithSchemeInvalidType() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Uri scheme must be a string'); + + $this->uriFactory()->withScheme([]); + } + + public function testGetAuthorityWithUsernameAndPassword() + { + $this->assertEquals('josh:sekrit@example.com', $this->uriFactory()->getAuthority()); + } + + public function testWithUserInfo() + { + $uri = $this->uriFactory()->withUserInfo('bob', 'pass'); + + $this->assertEquals('bob:pass', $uri->getUserInfo()); + } + + public function testWithUserInfoEncodesCorrectly() + { + $uri = $this->uriFactory()->withUserInfo('bob@example.com', 'pass:word'); + + $this->assertEquals('bob%40example.com:pass%3Aword', $uri->getUserInfo()); + } + + public function testWithUserInfoRemovesPassword() + { + $uri = $this->uriFactory()->withUserInfo('bob'); + + $this->assertEquals('bob', $uri->getUserInfo()); + } + + public function testWithUserInfoRemovesInfo() + { + $uri = $this->uriFactory()->withUserInfo('bob', 'password'); + $uri = $uri->withUserInfo(''); + + $this->assertEquals('', $uri->getUserInfo()); + } + + public function testGetHost() + { + $this->assertEquals('example.com', $this->uriFactory()->getHost()); + } + + public function testWithHost() + { + $uri = $this->uriFactory()->withHost('slimframework.com'); + + $this->assertEquals('slimframework.com', $uri->getHost()); + } + + public function testWithHostValidObject() + { + $mock = new StringableTestObject('host.test'); + + $uri = $this->uriFactory()->withHost($mock); + $this->assertEquals('host.test', $uri->getHost()); + } + + public function testWithHostInvalidObject() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Uri host must be a string'); + + $this->uriFactory()->withHost(new stdClass()); + } + + public function testFilterHost() + { + $uri = new Uri('http', '2001:db8::1'); + + $this->assertEquals('[2001:db8::1]', $uri->getHost()); + } + + public function testGetPortWithSchemeAndNonDefaultPort() + { + $uri = new Uri('https', 'www.example.com', 4000); + + $this->assertEquals(4000, $uri->getPort()); + } + + public function testGetPortWithSchemeAndDefaultPort() + { + $uriHttp = new Uri('http', 'www.example.com', 80); + $uriHttps = new Uri('https', 'www.example.com', 443); + + $this->assertNull($uriHttp->getPort()); + $this->assertNull($uriHttps->getPort()); + } + + public function testGetPortWithoutSchemeAndPort() + { + $uri = new Uri('', 'www.example.com'); + + $this->assertNull($uri->getPort()); + } + + public function testGetPortWithSchemeWithoutPort() + { + $uri = new Uri('http', 'www.example.com'); + + $this->assertNull($uri->getPort()); + } + + public function testWithPort() + { + $uri = $this->uriFactory()->withPort(8000); + + $this->assertEquals(8000, $uri->getPort()); + } + + public function testWithPortNull() + { + $uri = $this->uriFactory()->withPort(null); + + $this->assertEquals(null, $uri->getPort()); + } + + public function testWithPortInvalidInt() + { + $this->expectException(InvalidArgumentException::class); + + $this->uriFactory()->withPort(70000); + } + + public function testWithPortInvalidString() + { + $this->expectException(InvalidArgumentException::class); + + $this->uriFactory()->withPort('Foo'); + } + + public function testWithPortIntegerAsString() + { + $uri = $this->uriFactory()->withPort("199"); + + $this->assertEquals(199, $uri->getPort()); + } + + public function testGetPath() + { + $this->assertEquals('/foo/bar', $this->uriFactory()->getPath()); + } + + public function testWithPath() + { + $uri = $this->uriFactory()->withPath('/new'); + + $this->assertEquals('/new', $uri->getPath()); + } + + public function testWithPathWithoutPrefix() + { + $uri = $this->uriFactory()->withPath('new'); + + $this->assertEquals('new', $uri->getPath()); + } + + public function testWithPathEmptyValue() + { + $uri = $this->uriFactory()->withPath(''); + + $this->assertEquals('', $uri->getPath()); + } + + public function testWithPathUrlEncodesInput() + { + $uri = $this->uriFactory()->withPath('/includes?/new'); + + $this->assertEquals('/includes%3F/new', $uri->getPath()); + } + + public function testWithPathDoesNotDoubleEncodeInput() + { + $uri = $this->uriFactory()->withPath('/include%25s/new'); + + $this->assertEquals('/include%25s/new', $uri->getPath()); + } + + public function testWithPathInvalidType() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Uri path must be a string'); + + $this->uriFactory()->withPath(['foo']); + } + + public function testGetQuery() + { + $this->assertEquals('abc=123', $this->uriFactory()->getQuery()); + } + + public function testWithQuery() + { + $uri = $this->uriFactory()->withQuery('xyz=123'); + + $this->assertEquals('xyz=123', $uri->getQuery()); + } + + public function testWithQueryRemovesPrefix() + { + $uri = $this->uriFactory()->withQuery('?xyz=123'); + + $this->assertEquals('xyz=123', $uri->getQuery()); + } + + public function testWithQueryEmpty() + { + $uri = $this->uriFactory()->withQuery(''); + + $this->assertEquals('', $uri->getQuery()); + } + + public function testWithQueryValidObject() + { + $mock = new StringableTestObject('xyz=123'); + + $uri = $this->uriFactory()->withQuery($mock); + $this->assertEquals('xyz=123', $uri->getQuery()); + } + + public function testFilterQuery() + { + $uri = $this->uriFactory()->withQuery('?foobar=%match'); + + $this->assertEquals('foobar=%25match', $uri->getQuery()); + } + + public function testWithQueryInvalidType() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Uri query must be a string'); + + $this->uriFactory()->withQuery(['foo']); + } + + public function testGetFragment() + { + $this->assertEquals('section3', $this->uriFactory()->getFragment()); + } + + public function testWithFragment() + { + $uri = $this->uriFactory()->withFragment('other-fragment'); + + $this->assertEquals('other-fragment', $uri->getFragment()); + } + + public function testWithFragmentRemovesPrefix() + { + $uri = $this->uriFactory()->withFragment('#other-fragment'); + + $this->assertEquals('other-fragment', $uri->getFragment()); + } + + public function testWithFragmentEmpty() + { + $uri = $this->uriFactory()->withFragment(''); + + $this->assertEquals('', $uri->getFragment()); + } + + public function testWithFragmentValidObject() + { + $mock = new StringableTestObject('other-fragment'); + + $uri = $this->uriFactory()->withFragment($mock); + $this->assertEquals('other-fragment', $uri->getFragment()); + } + + public function testWithFragmentUrlEncode() + { + $uri = $this->uriFactory()->withFragment('^a'); + + $this->assertEquals('%5Ea', $uri->getFragment()); + } + + public function testWithFragmentInvalidType() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Uri fragment must be a string'); + + $this->uriFactory()->withFragment(['foo']); + } + + public function testToString() + { + $uri = $this->uriFactory(); + + $this->assertEquals('https://josh:sekrit@example.com/foo/bar?abc=123#section3', (string) $uri); + + $uri = $uri->withPath('bar'); + $this->assertEquals('https://josh:sekrit@example.com/bar?abc=123#section3', (string) $uri); + + $uri = $uri->withPath('/bar'); + $this->assertEquals('https://josh:sekrit@example.com/bar?abc=123#section3', (string) $uri); + + $uri = $uri->withScheme('')->withHost('')->withPort(null)->withUserInfo('')->withPath('//bar'); + $this->assertEquals('/bar?abc=123#section3', (string) $uri); + } +} diff --git a/api/vendor/slim/psr7/tests/bootstrap.php b/api/vendor/slim/psr7/tests/bootstrap.php new file mode 100644 index 0000000..eee5637 --- /dev/null +++ b/api/vendor/slim/psr7/tests/bootstrap.php @@ -0,0 +1,99 @@ + [ + 'getallheaders' => function () { + if (array_key_exists('getallheaders_return', $GLOBALS)) { + return $GLOBALS['getallheaders_return']; + } + + return getallheaders(); + } + ], + Message::class => [ + 'header' => function (string $string, bool $replace = true, ?int $statusCode = null): void { + HeaderStack::push( + [ + 'header' => $string, + 'replace' => $replace, + 'status_code' => $statusCode, + ] + ); + }, + 'header_remove' => function ($name = null): void { + HeaderStack::remove($name); + } + ], + NonBufferedBody::class => [ + 'ob_get_level' => function (): int { + if (isset($GLOBALS['ob_get_level_shift'])) { + return ob_get_level() + $GLOBALS['ob_get_level_shift']; + } + + return ob_get_level(); + } + ], + UploadedFile::class => [ + 'copy' => function (string $source, string $destination, $context = null): bool { + if (isset($GLOBALS['copy_return'])) { + return $GLOBALS['copy_return']; + } + + if ($context === null) { + return copy($source, $destination); + } + return copy($source, $destination, $context); + }, + 'is_uploaded_file' => function (string $filename): bool { + if (isset($GLOBALS['is_uploaded_file_return'])) { + return $GLOBALS['is_uploaded_file_return']; + } + + return is_uploaded_file($filename); + }, + 'rename' => function (string $oldName, string $newName, $context = null): bool { + if (isset($GLOBALS['rename_return'])) { + return $GLOBALS['rename_return']; + } + + if ($context === null) { + return rename($oldName, $newName); + } + return rename($oldName, $newName, $context = null); + } + ], + Factory\StreamFactory::class => [ + 'fopen' => function (string $filename, string $mode) { + if (isset($GLOBALS['fopen_return'])) { + return isset($GLOBALS['fopen_return']); + } + + return fopen($filename, $mode); + }, + 'is_readable' => function (string $filename) { + if ($filename === 'non-readable') { + return false; + } + + return is_readable($filename); + } + ] +]); diff --git a/api/vendor/slim/slim/CHANGELOG.md b/api/vendor/slim/slim/CHANGELOG.md new file mode 100644 index 0000000..97c8b07 --- /dev/null +++ b/api/vendor/slim/slim/CHANGELOG.md @@ -0,0 +1,339 @@ +# Changelog + +## [Unreleased] + +### Fixed + +### Added + +### Changed + +### Removed + +## 4.15.0 - 2025-08-24 + +### Fixed + +- Fix DocBlocks for callable route handlers (#3389) +- Change class keyword to lowercase (#3346) +- Fix tests for PHP 8.3 +- Fixes the build status badge in Readme (#3331) +- Fix text and eol attributes for * selector in .gitattributes (#3391) +- Deprecate setArgument/s (#3383) + +### Added + +- Add support for PHP 8.4 +- Add phpstan v2 + +### Changed + +- Update http urls in composer.json (#3399) + +**Full Changelog**: https://github.com/slimphp/Slim/compare/4.14.0...4.15.0 + +## 4.14.0 - 2024-06-13 + +### Changed + +- Do not HTML entity encode in PlainTextErrorRenderer by @akrabat in https://github.com/slimphp/Slim/pull/3319 +- Only render tip to error log if plain text renderer is used by @akrabat in https://github.com/slimphp/Slim/pull/3321 +- Add template generics for PSR-11 implementations in PHPStan and Psalm by @limarkxx in https://github.com/slimphp/Slim/pull/3322 +- Update squizlabs/php_codesniffer requirement from ^3.9 to ^3.10 by @dependabot in https://github.com/slimphp/Slim/pull/3324 +- Update phpstan/phpstan requirement from ^1.10 to ^1.11 by @dependabot in https://github.com/slimphp/Slim/pull/3325 +- Update psr/http-factory requirement from ^1.0 to ^1.1 by @dependabot in https://github.com/slimphp/Slim/pull/3326 + +#### Type hinting with template generics + +With the introduction of template generics, if you type-hint `Slim\App` instance variable using `/** @var \Slim\App $app */`, then you will need to change it to either: + +* `/** @var \Slim\App $app */` if you are not using a DI container, or +* `/** @var \Slim\App<\Psr\Container\ContainerInterface> $app */` if you are + +You can also type-hint to the concrete instance of the container you are using too. For example, if you are using [PHP-DI](https://php-di.org), then you can use: `/** @var \Slim\App $app */`. + +### New Contributors + +* @limarkxx made their first contribution in https://github.com/slimphp/Slim/pull/3322 + +**Full Changelog**: https://github.com/slimphp/Slim/compare/4.13.0...4.14.0 + +# 4.13.0 - 2024-03-03 + +- [3277: Create HttpTooManyRequestsException.php](https://github.com/slimphp/Slim/pull/3277) thanks to @flavioheleno +- [3278: Remove HttpGoneException executable flag](https://github.com/slimphp/Slim/pull/3278) thanks to @flavioheleno +- [3285: Update guzzlehttp/psr7 requirement from ^2.5 to ^2.6](https://github.com/slimphp/Slim/pull/3285) thanks to @dependabot[bot] +- [3290: Bump actions/checkout from 3 to 4](https://github.com/slimphp/Slim/pull/3290) thanks to @dependabot[bot] +- [3291: Fix line length](https://github.com/slimphp/Slim/pull/3291) thanks to @l0gicgate +- [3296: PSR 7 http-message version requirement](https://github.com/slimphp/Slim/issues/3296) thanks to @rotexdegba +- [3297: Allow Diactoros 3](https://github.com/slimphp/Slim/pull/3297) thanks to @derrabus +- [3299: Update tests and add PHP 8.3 to the CI matrix](https://github.com/slimphp/Slim/pull/3299) thanks to @akrabat +- [3301: Update nyholm/psr7-server requirement from ^1.0 to ^1.1](https://github.com/slimphp/Slim/pull/3301) thanks to @dependabot[bot] +- [3302: Add support for psr/http-message ^2.0](https://github.com/slimphp/Slim/pull/3302) thanks to @rotexdegba +- [3305: Update phpspec/prophecy-phpunit requirement from ^2.0 to ^2.1](https://github.com/slimphp/Slim/pull/3305) thanks to @dependabot[bot] +- [3306: Update phpspec/prophecy requirement from ^1.17 to ^1.18](https://github.com/slimphp/Slim/pull/3306) thanks to @dependabot[bot] +- [3308: Update squizlabs/php_codesniffer requirement from ^3.7 to ^3.8](https://github.com/slimphp/Slim/pull/3308) thanks to @dependabot[bot] +- [3313: Bump ramsey/composer-install from 2 to 3](https://github.com/slimphp/Slim/pull/3313) thanks to @dependabot[bot] +- [3314: Update phpspec/prophecy requirement from ^1.18 to ^1.19](https://github.com/slimphp/Slim/pull/3314) thanks to @dependabot[bot] +- [3315: Update squizlabs/php_codesniffer requirement from ^3.8 to ^3.9](https://github.com/slimphp/Slim/pull/3315) thanks to @dependabot[bot] + +# 4.12.0 - 2023-07-23 + +- [3220: Refactor](https://github.com/slimphp/Slim/pull/3220) thanks to @amirkhodabande +- [3237: Update phpstan/phpstan requirement from ^1.8 to ^1.9](https://github.com/slimphp/Slim/pull/3237) thanks to @dependabot[bot] +- [3238: Update slim/http requirement from ^1.2 to ^1.3](https://github.com/slimphp/Slim/pull/3238) thanks to @dependabot[bot] +- [3239: Update slim/psr7 requirement from ^1.5 to ^1.6](https://github.com/slimphp/Slim/pull/3239) thanks to @dependabot[bot] +- [3240: Update phpspec/prophecy requirement from ^1.15 to ^1.16](https://github.com/slimphp/Slim/pull/3240) thanks to @dependabot[bot] +- [3241: Update adriansuter/php-autoload-override requirement from ^1.3 to ^1.4](https://github.com/slimphp/Slim/pull/3241) thanks to @dependabot[bot] +- [3245: New ability to override RouteGroupInterface in the Route class](https://github.com/slimphp/Slim/pull/3245) thanks to @githubjeka +- [3253: Fix HttpBadRequestException description](https://github.com/slimphp/Slim/pull/3253) thanks to @jsanahuja +- [3254: Update phpunit/phpunit requirement from ^9.5 to ^9.6](https://github.com/slimphp/Slim/pull/3254) thanks to @dependabot[bot] +- [3255: Update phpstan/phpstan requirement from ^1.9 to ^1.10](https://github.com/slimphp/Slim/pull/3255) thanks to @dependabot[bot] +- [3256: Update phpspec/prophecy requirement from ^1.16 to ^1.17](https://github.com/slimphp/Slim/pull/3256) thanks to @dependabot[bot] +- [3264: Update psr/http-message requirement from ^1.0 to ^1.1](https://github.com/slimphp/Slim/pull/3264) thanks to @dependabot[bot] +- [3265: Update nyholm/psr7 requirement from ^1.5 to ^1.7](https://github.com/slimphp/Slim/pull/3265) thanks to @dependabot[bot] +- [3266: Update guzzlehttp/psr7 requirement from ^2.4 to ^2.5](https://github.com/slimphp/Slim/pull/3266) thanks to @dependabot[bot] +- [3267: Update nyholm/psr7 requirement from ^1.7 to ^1.8](https://github.com/slimphp/Slim/pull/3267) thanks to @dependabot[bot] +- [3269: Update httpsoft/http-server-request requirement from ^1.0 to ^1.1](https://github.com/slimphp/Slim/pull/3269) thanks to @dependabot[bot] +- [3270: Update httpsoft/http-message requirement from ^1.0 to ^1.1](https://github.com/slimphp/Slim/pull/3270) thanks to @dependabot[bot] +- [3271: prevent multiple entries of same methode in FastRouteDispatcher](https://github.com/slimphp/Slim/pull/3271) thanks to @papparazzo + +## 4.11.0 - 2022-11-06 + +- [3180: Declare types](https://github.com/slimphp/Slim/pull/3180) thanks to @nbayramberdiyev +- [3181: Update laminas/laminas-diactoros requirement from ^2.8 to ^2.9](https://github.com/slimphp/Slim/pull/3181) thanks to @dependabot[bot] +- [3182: Update guzzlehttp/psr7 requirement from ^2.1 to ^2.2](https://github.com/slimphp/Slim/pull/3182) thanks to @dependabot[bot] +- [3183: Update phpstan/phpstan requirement from ^1.4 to ^1.5](https://github.com/slimphp/Slim/pull/3183) thanks to @dependabot[bot] +- [3184: Update adriansuter/php-autoload-override requirement from ^1.2 to ^1.3](https://github.com/slimphp/Slim/pull/3184) thanks to @dependabot[bot] +- [3189: Update phpstan/phpstan requirement from ^1.5 to ^1.6](https://github.com/slimphp/Slim/pull/3189) thanks to @dependabot[bot] +- [3191: Adding property types to Middleware classes](https://github.com/slimphp/Slim/pull/3191) thanks to @ashleycoles +- [3193: Handlers types](https://github.com/slimphp/Slim/pull/3193) thanks to @ashleycoles +- [3194: Adding types to AbstractErrorRenderer](https://github.com/slimphp/Slim/pull/3194) thanks to @ashleycoles +- [3195: Adding prop types for Exception classes](https://github.com/slimphp/Slim/pull/3195) thanks to @ashleycoles +- [3196: Adding property type declarations for Factory classes](https://github.com/slimphp/Slim/pull/3196) thanks to @ashleycoles +- [3197: Remove redundant docblock types](https://github.com/slimphp/Slim/pull/3197) thanks to @theodorejb +- [3199: Update laminas/laminas-diactoros requirement from ^2.9 to ^2.11](https://github.com/slimphp/Slim/pull/3199) thanks to @dependabot[bot] +- [3200: Update phpstan/phpstan requirement from ^1.6 to ^1.7](https://github.com/slimphp/Slim/pull/3200) thanks to @dependabot[bot] +- [3205: Update guzzlehttp/psr7 requirement from ^2.2 to ^2.4](https://github.com/slimphp/Slim/pull/3205) thanks to @dependabot[bot] +- [3206: Update squizlabs/php_codesniffer requirement from ^3.6 to ^3.7](https://github.com/slimphp/Slim/pull/3206) thanks to @dependabot[bot] +- [3207: Update phpstan/phpstan requirement from ^1.7 to ^1.8](https://github.com/slimphp/Slim/pull/3207) thanks to @dependabot[bot] +- [3211: Assign null coalescing to coalesce equal](https://github.com/slimphp/Slim/pull/3211) thanks to @MathiasReker +- [3213: Void return](https://github.com/slimphp/Slim/pull/3213) thanks to @MathiasReker +- [3214: Is null](https://github.com/slimphp/Slim/pull/3214) thanks to @MathiasReker +- [3216: Refactor](https://github.com/slimphp/Slim/pull/3216) thanks to @mehdihasanpour +- [3218: Refactor some code](https://github.com/slimphp/Slim/pull/3218) thanks to @mehdihasanpour +- [3221: Cleanup](https://github.com/slimphp/Slim/pull/3221) thanks to @mehdihasanpour +- [3225: Update laminas/laminas-diactoros requirement from ^2.11 to ^2.14](https://github.com/slimphp/Slim/pull/3225) thanks to @dependabot[bot] +- [3228: Using assertSame to let assert equal be restricted](https://github.com/slimphp/Slim/pull/3228) thanks to @peter279k +- [3229: Update laminas/laminas-diactoros requirement from ^2.14 to ^2.17](https://github.com/slimphp/Slim/pull/3229) thanks to @dependabot[bot] +- [3235: Persist routes indexed by name in RouteCollector for improved performance.](https://github.com/slimphp/Slim/pull/3235) thanks to @BusterNeece + +## 4.10.0 - 2022-03-14 + +- [3120: Add a new PSR-17 factory to Psr17FactoryProvider](https://github.com/slimphp/Slim/pull/3120) thanks to @solventt +- [3123: Replace deprecated setMethods() in tests](https://github.com/slimphp/Slim/pull/3123) thanks to @solventt +- [3126: Update guzzlehttp/psr7 requirement from ^2.0 to ^2.1](https://github.com/slimphp/Slim/pull/3126) thanks to @dependabot[bot] +- [3127: PHPStan v1.0](https://github.com/slimphp/Slim/pull/3127) thanks to @t0mmy742 +- [3128: Update phpstan/phpstan requirement from ^1.0 to ^1.2](https://github.com/slimphp/Slim/pull/3128) thanks to @dependabot[bot] +- [3129: Deprecate PHP 7.3](https://github.com/slimphp/Slim/pull/3129) thanks to @l0gicgate +- [3130: Removed double defined PHP 7.4](https://github.com/slimphp/Slim/pull/3130) thanks to @flangofas +- [3132: Add new `RequestResponseNamedArgs` route strategy](https://github.com/slimphp/Slim/pull/3132) thanks to @adoy +- [3133: Improve typehinting for `RouteParserInterface`](https://github.com/slimphp/Slim/pull/3133) thanks to @jerowork +- [3135: Update phpstan/phpstan requirement from ^1.2 to ^1.3](https://github.com/slimphp/Slim/pull/3135) thanks to @dependabot[bot] +- [3137: Update phpspec/prophecy requirement from ^1.14 to ^1.15](https://github.com/slimphp/Slim/pull/3137) thanks to @dependabot[bot] +- [3138: Update license year](https://github.com/slimphp/Slim/pull/3138) thanks to @Awilum +- [3139: Fixed #1730 (reintroduced in 4.x)](https://github.com/slimphp/Slim/pull/3139) thanks to @adoy +- [3145: Update phpstan/phpstan requirement from ^1.3 to ^1.4](https://github.com/slimphp/Slim/pull/3145) thanks to @dependabot[bot] +- [3146: Inherit HttpException from RuntimeException](https://github.com/slimphp/Slim/pull/3146) thanks to @nbayramberdiyev +- [3148: Upgrade to HTML5](https://github.com/slimphp/Slim/pull/3148) thanks to @nbayramberdiyev +- [3172: Update nyholm/psr7 requirement from ^1.4 to ^1.5](https://github.com/slimphp/Slim/pull/3172) thanks to @dependabot[bot] + +## 4.9.0 - 2021-10-05 + +- [3058: Implement exception class for Gone Http error](https://github.com/slimphp/Slim/pull/3058) thanks to @TheKernelPanic +- [3086: Update slim/psr7 requirement from ^1.3 to ^1.4](https://github.com/slimphp/Slim/pull/3086) thanks to @dependabot[bot] +- [3087: Update nyholm/psr7-server requirement from ^1.0.1 to ^1.0.2](https://github.com/slimphp/Slim/pull/3087) thanks to @dependabot[bot] +- [3093: Update phpstan/phpstan requirement from ^0.12.85 to ^0.12.90](https://github.com/slimphp/Slim/pull/3093) thanks to @dependabot[bot] +- [3099: Allow updated psr log](https://github.com/slimphp/Slim/pull/3099) thanks to @t0mmy742 +- [3104: Drop php7.2](https://github.com/slimphp/Slim/pull/3104) thanks to @t0mmy742 +- [3106: Use PSR-17 factory from Guzzle/psr7 2.0](https://github.com/slimphp/Slim/pull/3106) thanks to @t0mmy742 +- [3108: Update README file](https://github.com/slimphp/Slim/pull/3108) thanks to @t0mmy742 +- [3112: Update laminas/laminas-diactoros requirement from ^2.6 to ^2.8](https://github.com/slimphp/Slim/pull/3112) thanks to @dependabot[bot] +- [3114: Update slim/psr7 requirement from ^1.4 to ^1.5](https://github.com/slimphp/Slim/pull/3114) thanks to @dependabot[bot] +- [3115: Update phpstan/phpstan requirement from ^0.12.96 to ^0.12.99](https://github.com/slimphp/Slim/pull/3115) thanks to @dependabot[bot] +- [3116: Remove Zend Diactoros references](https://github.com/slimphp/Slim/pull/3116) thanks to @l0gicgate + +## 4.8.0 - 2021-05-19 + +- [3034: Fix phpunit dependency version](https://github.com/slimphp/Slim/pull/3034) thanks to @l0gicgate +- [3037: Replace Travis by GitHub Actions](https://github.com/slimphp/Slim/pull/3037) thanks to @t0mmy742 +- [3043: Cover App creation from AppFactory with empty Container](https://github.com/slimphp/Slim/pull/3043) thanks to @t0mmy742 +- [3045: Update phpstan/phpstan requirement from ^0.12.58 to ^0.12.64](https://github.com/slimphp/Slim/pull/3045) thanks to @dependabot-preview[bot] +- [3047: documentation: min php 7.2 required](https://github.com/slimphp/Slim/pull/3047) thanks to @Rotzbua +- [3054: Update phpstan/phpstan requirement from ^0.12.64 to ^0.12.70](https://github.com/slimphp/Slim/pull/3054) thanks to @dependabot-preview[bot] +- [3056: Fix docblock in ErrorMiddleware](https://github.com/slimphp/Slim/pull/3056) thanks to @piotr-cz +- [3060: Update phpstan/phpstan requirement from ^0.12.70 to ^0.12.80](https://github.com/slimphp/Slim/pull/3060) thanks to @dependabot-preview[bot] +- [3061: Update nyholm/psr7 requirement from ^1.3 to ^1.4](https://github.com/slimphp/Slim/pull/3061) thanks to @dependabot-preview[bot] +- [3063: Allow ^1.0 || ^2.0 in psr/container](https://github.com/slimphp/Slim/pull/3063) thanks to @Ayesh +- [3069: Classname/Method Callable Arrays](https://github.com/slimphp/Slim/pull/3069) thanks to @ddrv +- [3078: Update squizlabs/php_codesniffer requirement from ^3.5 to ^3.6](https://github.com/slimphp/Slim/pull/3078) thanks to @dependabot[bot] +- [3079: Update phpspec/prophecy requirement from ^1.12 to ^1.13](https://github.com/slimphp/Slim/pull/3079) thanks to @dependabot[bot] +- [3080: Update guzzlehttp/psr7 requirement from ^1.7 to ^1.8](https://github.com/slimphp/Slim/pull/3080) thanks to @dependabot[bot] +- [3082: Update phpstan/phpstan requirement from ^0.12.80 to ^0.12.85](https://github.com/slimphp/Slim/pull/3082) thanks to @dependabot[bot] + +## 4.7.0 - 2020-11-30 + +### Fixed +- [3027: Fix: FastRoute dispatcher and data generator should match](https://github.com/slimphp/Slim/pull/3027) thanks to @edudobay + +### Added +- [3015: PHP 8 support](https://github.com/slimphp/Slim/pull/3015) thanks to @edudobay + +### Optimizations +- [3024: Randomize tests](https://github.com/slimphp/Slim/pull/3024) thanks to @pawel-slowik + +## 4.6.0 - 2020-11-15 + +### Fixed +- [2942: Fix PHPdoc for error handlers in ErrorMiddleware ](https://github.com/slimphp/Slim/pull/2942) thanks to @TiMESPLiNTER +- [2944: Remove unused function in ErrorHandler](https://github.com/slimphp/Slim/pull/2944) thanks to @l0gicgate +- [2960: Fix phpstan 0.12 errors](https://github.com/slimphp/Slim/pull/2960) thanks to @adriansuter +- [2982: Removing cloning statements in tests](https://github.com/slimphp/Slim/pull/2982) thanks to @l0gicgate +- [3017: Fix request creator factory test](https://github.com/slimphp/Slim/pull/3017) thanks to @pawel-slowik +- [3022: Ensure RouteParser Always Present After Routing](https://github.com/slimphp/Slim/pull/3022) thanks to @l0gicgate + +### Added +- [2949: Add the support in composer.json](https://github.com/slimphp/Slim/pull/2949) thanks to @ddrv +- [2958: Strict empty string content type checking in BodyParsingMiddleware::getMediaType](https://github.com/slimphp/Slim/pull/2958) thanks to @Ayesh +- [2997: Add hints to methods](https://github.com/slimphp/Slim/pull/2997) thanks to @evgsavosin - [3000: Fix route controller test](https://github.com/slimphp/Slim/pull/3000) thanks to @pawel-slowik +- [3001: Add missing `$strategy` parameter in a Route test](https://github.com/slimphp/Slim/pull/3001) thanks to @pawel-slowik + +### Optimizations +- [2951: Minor optimizations in if() blocks](https://github.com/slimphp/Slim/pull/2951) thanks to @Ayesh +- [2959: Micro optimization: Declare closures in BodyParsingMiddleware as static](https://github.com/slimphp/Slim/pull/2959) thanks to @Ayesh +- [2978: Split the routing results to its own function.](https://github.com/slimphp/Slim/pull/2978) thanks to @dlundgren + +### Dependencies Updated +- [2953: Update nyholm/psr7-server requirement from ^0.4.1](https://github.com/slimphp/Slim/pull/2953) thanks to @dependabot-preview[bot] +- [2954: Update laminas/laminas-diactoros requirement from ^2.1 to ^2.3](https://github.com/slimphp/Slim/pull/2954) thanks to @dependabot-preview[bot] +- [2955: Update guzzlehttp/psr7 requirement from ^1.5 to ^1.6](https://github.com/slimphp/Slim/pull/2955) thanks to @dependabot-preview[bot] +- [2956: Update slim/psr7 requirement from ^1.0 to ^1.1](https://github.com/slimphp/Slim/pull/2956) thanks to @dependabot-preview[bot] +- [2957: Update nyholm/psr7 requirement from ^1.1 to ^1.2](https://github.com/slimphp/Slim/pull/2957) thanks to @dependabot-preview[bot] +- [2963: Update phpstan/phpstan requirement from ^0.12.23 to ^0.12.25](https://github.com/slimphp/Slim/pull/2963) thanks to @dependabot-preview[bot] +- [2965: Update adriansuter/php-autoload-override requirement from ^1.0 to ^1.1](https://github.com/slimphp/Slim/pull/2965) thanks to @dependabot-preview[bot] +- [2967: Update nyholm/psr7 requirement from ^1.2 to ^1.3](https://github.com/slimphp/Slim/pull/2967) thanks to @dependabot-preview[bot] +- [2969: Update nyholm/psr7-server requirement from ^0.4.1 to ^1.0.0](https://github.com/slimphp/Slim/pull/2969) thanks to @dependabot-preview[bot] +- [2970: Update phpstan/phpstan requirement from ^0.12.25 to ^0.12.26](https://github.com/slimphp/Slim/pull/2970) thanks to @dependabot-preview[bot] +- [2971: Update phpstan/phpstan requirement from ^0.12.26 to ^0.12.27](https://github.com/slimphp/Slim/pull/2971) thanks to @dependabot-preview[bot] +- [2972: Update phpstan/phpstan requirement from ^0.12.27 to ^0.12.28](https://github.com/slimphp/Slim/pull/2972) thanks to @dependabot-preview[bot] +- [2973: Update phpstan/phpstan requirement from ^0.12.28 to ^0.12.29](https://github.com/slimphp/Slim/pull/2973) thanks to @dependabot-preview[bot] +- [2975: Update phpstan/phpstan requirement from ^0.12.29 to ^0.12.30](https://github.com/slimphp/Slim/pull/2975) thanks to @dependabot-preview[bot] +- [2976: Update phpstan/phpstan requirement from ^0.12.30 to ^0.12.31](https://github.com/slimphp/Slim/pull/2976) thanks to @dependabot-preview[bot] +- [2980: Update phpstan/phpstan requirement from ^0.12.31 to ^0.12.32](https://github.com/slimphp/Slim/pull/2980) thanks to @dependabot-preview[bot] +- [2981: Update phpspec/prophecy requirement from ^1.10 to ^1.11](https://github.com/slimphp/Slim/pull/2981) thanks to @dependabot-preview[bot] +- [2986: Update phpstan/phpstan requirement from ^0.12.32 to ^0.12.33](https://github.com/slimphp/Slim/pull/2986) thanks to @dependabot-preview[bot] +- [2990: Update phpstan/phpstan requirement from ^0.12.33 to ^0.12.34](https://github.com/slimphp/Slim/pull/2990) thanks to @dependabot-preview[bot] +- [2991: Update phpstan/phpstan requirement from ^0.12.34 to ^0.12.35](https://github.com/slimphp/Slim/pull/2991) thanks to @dependabot-preview[bot] +- [2993: Update phpstan/phpstan requirement from ^0.12.35 to ^0.12.36](https://github.com/slimphp/Slim/pull/2993) thanks to @dependabot-preview[bot] +- [2995: Update phpstan/phpstan requirement from ^0.12.36 to ^0.12.37](https://github.com/slimphp/Slim/pull/2995) thanks to @dependabot-preview[bot] +- [3010: Update guzzlehttp/psr7 requirement from ^1.6 to ^1.7](https://github.com/slimphp/Slim/pull/3010) thanks to @dependabot-preview[bot] +- [3011: Update phpspec/prophecy requirement from ^1.11 to ^1.12](https://github.com/slimphp/Slim/pull/3011) thanks to @dependabot-preview[bot] +- [3012: Update slim/http requirement from ^1.0 to ^1.1](https://github.com/slimphp/Slim/pull/3012) thanks to @dependabot-preview[bot] +- [3013: Update slim/psr7 requirement from ^1.1 to ^1.2](https://github.com/slimphp/Slim/pull/3013) thanks to @dependabot-preview[bot] +- [3014: Update laminas/laminas-diactoros requirement from ^2.3 to ^2.4](https://github.com/slimphp/Slim/pull/3014) thanks to @dependabot-preview[bot] +- [3018: Update phpstan/phpstan requirement from ^0.12.37 to ^0.12.54](https://github.com/slimphp/Slim/pull/3018) thanks to @dependabot-preview[bot] + +## 4.5.0 - 2020-04-14 + +### Added +- [2928](https://github.com/slimphp/Slim/pull/2928) Test against PHP 7.4 +- [2937](https://github.com/slimphp/Slim/pull/2937) Add support for PSR-3 + +### Fixed +- [2916](https://github.com/slimphp/Slim/pull/2916) Rename phpcs.xml to phpcs.xml.dist +- [2917](https://github.com/slimphp/Slim/pull/2917) Update .editorconfig +- [2925](https://github.com/slimphp/Slim/pull/2925) ResponseEmitter: Don't remove Content-Type and Content-Length when body is empt +- [2932](https://github.com/slimphp/Slim/pull/2932) Update the Tidelift enterprise language +- [2938](https://github.com/slimphp/Slim/pull/2938) Modify usage of deprecated expectExceptionMessageRegExp() method + +## 4.4.0 - 2020-01-04 + +### Added +- [2862](https://github.com/slimphp/Slim/pull/2862) Optionally handle subclasses of exceptions in custom error handler +- [2869](https://github.com/slimphp/Slim/pull/2869) php-di/php-di added in composer suggestion +- [2874](https://github.com/slimphp/Slim/pull/2874) Add `null` to param type-hints +- [2889](https://github.com/slimphp/Slim/pull/2889) Make `RouteContext` attributes customizable and change default to use private names +- [2907](https://github.com/slimphp/Slim/pull/2907) Migrate to PSR-12 convention +- [2910](https://github.com/slimphp/Slim/pull/2910) Migrate Zend to Laminas +- [2912](https://github.com/slimphp/Slim/pull/2912) Add Laminas PSR17 Factory +- [2913](https://github.com/slimphp/Slim/pull/2913) Update php-autoload-override version +- [2914](https://github.com/slimphp/Slim/pull/2914) Added ability to add handled exceptions as an array + +### Fixed +- [2864](https://github.com/slimphp/Slim/pull/2864) Optimize error message in error handling if displayErrorDetails was not set +- [2876](https://github.com/slimphp/Slim/pull/2876) Update links from http to https +- [2877](https://github.com/slimphp/Slim/pull/2877) Fix docblock for `Slim\Routing\RouteCollector::cacheFile` +- [2878](https://github.com/slimphp/Slim/pull/2878) check body is writable only on ouput buffering append +- [2896](https://github.com/slimphp/Slim/pull/2896) Render errors uniformly +- [2902](https://github.com/slimphp/Slim/pull/2902) Fix prophecies +- [2908](https://github.com/slimphp/Slim/pull/2908) Use autoload-dev for `Slim\Tests` namespace + +### Removed +- [2871](https://github.com/slimphp/Slim/pull/2871) Remove explicit type-hint +- [2872](https://github.com/slimphp/Slim/pull/2872) Remove type-hint + +## 4.3.0 - 2019-10-05 + +### Added +- [2819](https://github.com/slimphp/Slim/pull/2819) Added description to addRoutingMiddleware() +- [2820](https://github.com/slimphp/Slim/pull/2820) Update link to homepage in composer.json +- [2828](https://github.com/slimphp/Slim/pull/2828) Allow URIs with leading multi-slashes +- [2832](https://github.com/slimphp/Slim/pull/2832) Refactor `FastRouteDispatcher` +- [2835](https://github.com/slimphp/Slim/pull/2835) Rename `pathFor` to `urlFor` in docblock +- [2846](https://github.com/slimphp/Slim/pull/2846) Correcting the branch name as per issue-2843 +- [2849](https://github.com/slimphp/Slim/pull/2849) Create class alias for FastRoute\RouteCollector +- [2855](https://github.com/slimphp/Slim/pull/2855) Add list of allowed methods to HttpMethodNotAllowedException +- [2860](https://github.com/slimphp/Slim/pull/2860) Add base path to `$request` and use `RouteContext` to read + +### Fixed +- [2839](https://github.com/slimphp/Slim/pull/2839) Fix description for handler signature in phpdocs +- [2844](https://github.com/slimphp/Slim/pull/2844) Handle base path by routeCollector instead of RouteCollectorProxy +- [2845](https://github.com/slimphp/Slim/pull/2845) Fix composer scripts +- [2851](https://github.com/slimphp/Slim/pull/2851) Fix example of 'Hello World' app +- [2854](https://github.com/slimphp/Slim/pull/2854) Fix undefined property in tests + +### Removed +- [2853](https://github.com/slimphp/Slim/pull/2853) Remove unused classes + +## 4.2.0 - 2019-08-20 + +### Added +- [2787](https://github.com/slimphp/Slim/pull/2787) Add an advanced callable resolver +- [2791](https://github.com/slimphp/Slim/pull/2791) Add `inferPrivatePropertyTypeFromConstructor` to phpstan +- [2793](https://github.com/slimphp/Slim/pull/2793) Add ability to configure application via a container in `AppFactory` +- [2798](https://github.com/slimphp/Slim/pull/2798) Add PSR-7 Agnostic Body Parsing Middleware +- [2801](https://github.com/slimphp/Slim/pull/2801) Add `setLogErrorRenderer()` method to `ErrorHandler` +- [2807](https://github.com/slimphp/Slim/pull/2807) Add check for Slim callable notation if no resolver given +- [2803](https://github.com/slimphp/Slim/pull/2803) Add ability to emit non seekable streams in `ResponseEmitter` +- [2817](https://github.com/slimphp/Slim/pull/2817) Add the ability to pass in a custom `MiddlewareDispatcherInterface` to the `App` + +### Fixed +- [2789](https://github.com/slimphp/Slim/pull/2789) Fix Cookie header detection in `ResponseEmitter` +- [2796](https://github.com/slimphp/Slim/pull/2796) Fix http message format +- [2800](https://github.com/slimphp/Slim/pull/2800) Fix null comparisons more clear in `ErrorHandler` +- [2802](https://github.com/slimphp/Slim/pull/2802) Fix incorrect search of a header in stack +- [2806](https://github.com/slimphp/Slim/pull/2806) Simplify `Route::prepare()` method argument preparation +- [2809](https://github.com/slimphp/Slim/pull/2809) Eliminate a duplicate code via HOF in `MiddlewareDispatcher` +- [2816](https://github.com/slimphp/Slim/pull/2816) Fix RouteCollectorProxy::redirect() bug + +### Removed +- [2811](https://github.com/slimphp/Slim/pull/2811) Remove `DeferredCallable` + +## 4.1.0 - 2019-08-06 + +### Added +- [#2779](https://github.com/slimphp/Slim/pull/2774) Add support for Slim callables `Class:method` resolution & Container Closure auto-binding in `MiddlewareDispatcher` +- [#2774](https://github.com/slimphp/Slim/pull/2774) Add possibility for custom `RequestHandler` invocation strategies + +### Fixed +- [#2776](https://github.com/slimphp/Slim/pull/2774) Fix group middleware on multiple nested groups diff --git a/api/vendor/slim/slim/LICENSE.md b/api/vendor/slim/slim/LICENSE.md new file mode 100644 index 0000000..d6fd559 --- /dev/null +++ b/api/vendor/slim/slim/LICENSE.md @@ -0,0 +1,19 @@ +Copyright (c) 2011-2022 Josh Lockhart + +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. diff --git a/api/vendor/slim/slim/MAINTAINERS.md b/api/vendor/slim/slim/MAINTAINERS.md new file mode 100644 index 0000000..2b8ad04 --- /dev/null +++ b/api/vendor/slim/slim/MAINTAINERS.md @@ -0,0 +1,17 @@ +# Maintainers + +There aren't many rules for maintainers of Slim to remember; what we have is listed here. + +## We don't merge our own PRs + +Our code is better if more than one set of eyes looks at it. Therefore we do not merge our own pull requests unless there is an exceptional circumstance. This helps to spot errors in the patch and also enables us to share information about the project around the maintainer team. + +## PRs tagged `WIP` are not ready to be merged + +Sometimes it's helpful to collaborate on a patch before it's ready to be merged. We use the text `WIP` (for _Work in Progress_) in the title to mark these PRs. + +If a PR has `WIP` in its title, then it is not to be merged. The person who raised the PR will remove the `WIP` text when they are ready for a full review and merge. + +## Assign a merged PR to a milestone + +By ensuring that all merged PRs are assigned to a milestone, we can easily find which PRs were in which release. diff --git a/api/vendor/slim/slim/SECURITY.md b/api/vendor/slim/slim/SECURITY.md new file mode 100644 index 0000000..a5b6df0 --- /dev/null +++ b/api/vendor/slim/slim/SECURITY.md @@ -0,0 +1,14 @@ +# Security Policy + +### Supported Versions + + +| Version | Supported | +| ------- | ------------------ | +| 3.x.x | :white_check_mark: | +| 4.x.x | :white_check_mark: | + + +### Reporting a Vulnerability + +To report a vulnerability please send an email to security@slimframework.com diff --git a/api/vendor/slim/slim/Slim/App.php b/api/vendor/slim/slim/Slim/App.php new file mode 100644 index 0000000..abe83ff --- /dev/null +++ b/api/vendor/slim/slim/Slim/App.php @@ -0,0 +1,226 @@ + + */ +class App extends RouteCollectorProxy implements RequestHandlerInterface +{ + /** + * Current version + * + * @var string + */ + public const VERSION = '4.15.0'; + + protected RouteResolverInterface $routeResolver; + + protected MiddlewareDispatcherInterface $middlewareDispatcher; + + /** + * @param TContainerInterface $container + */ + public function __construct( + ResponseFactoryInterface $responseFactory, + ?ContainerInterface $container = null, + ?CallableResolverInterface $callableResolver = null, + ?RouteCollectorInterface $routeCollector = null, + ?RouteResolverInterface $routeResolver = null, + ?MiddlewareDispatcherInterface $middlewareDispatcher = null + ) { + parent::__construct( + $responseFactory, + $callableResolver ?? new CallableResolver($container), + $container, + $routeCollector + ); + + $this->routeResolver = $routeResolver ?? new RouteResolver($this->routeCollector); + $routeRunner = new RouteRunner($this->routeResolver, $this->routeCollector->getRouteParser(), $this); + + if (!$middlewareDispatcher) { + $middlewareDispatcher = new MiddlewareDispatcher($routeRunner, $this->callableResolver, $container); + } else { + $middlewareDispatcher->seedMiddlewareStack($routeRunner); + } + + $this->middlewareDispatcher = $middlewareDispatcher; + } + + /** + * @return RouteResolverInterface + */ + public function getRouteResolver(): RouteResolverInterface + { + return $this->routeResolver; + } + + /** + * @return MiddlewareDispatcherInterface + */ + public function getMiddlewareDispatcher(): MiddlewareDispatcherInterface + { + return $this->middlewareDispatcher; + } + + /** + * @param MiddlewareInterface|string|callable $middleware + * @return App + */ + public function add($middleware): self + { + $this->middlewareDispatcher->add($middleware); + return $this; + } + + /** + * @param MiddlewareInterface $middleware + * @return App + */ + public function addMiddleware(MiddlewareInterface $middleware): self + { + $this->middlewareDispatcher->addMiddleware($middleware); + return $this; + } + + /** + * Add the Slim built-in routing middleware to the app middleware stack + * + * This method can be used to control middleware order and is not required for default routing operation. + * + * @return RoutingMiddleware + */ + public function addRoutingMiddleware(): RoutingMiddleware + { + $routingMiddleware = new RoutingMiddleware( + $this->getRouteResolver(), + $this->getRouteCollector()->getRouteParser() + ); + $this->add($routingMiddleware); + return $routingMiddleware; + } + + /** + * Add the Slim built-in error middleware to the app middleware stack + * + * @param bool $displayErrorDetails + * @param bool $logErrors + * @param bool $logErrorDetails + * @param LoggerInterface|null $logger + * + * @return ErrorMiddleware + */ + public function addErrorMiddleware( + bool $displayErrorDetails, + bool $logErrors, + bool $logErrorDetails, + ?LoggerInterface $logger = null + ): ErrorMiddleware { + $errorMiddleware = new ErrorMiddleware( + $this->getCallableResolver(), + $this->getResponseFactory(), + $displayErrorDetails, + $logErrors, + $logErrorDetails, + $logger + ); + $this->add($errorMiddleware); + return $errorMiddleware; + } + + /** + * Add the Slim body parsing middleware to the app middleware stack + * + * @param callable[] $bodyParsers + * + * @return BodyParsingMiddleware + */ + public function addBodyParsingMiddleware(array $bodyParsers = []): BodyParsingMiddleware + { + $bodyParsingMiddleware = new BodyParsingMiddleware($bodyParsers); + $this->add($bodyParsingMiddleware); + return $bodyParsingMiddleware; + } + + /** + * Run application + * + * This method traverses the application middleware stack and then sends the + * resultant Response object to the HTTP client. + * + * @param ServerRequestInterface|null $request + * @return void + */ + public function run(?ServerRequestInterface $request = null): void + { + if (!$request) { + $serverRequestCreator = ServerRequestCreatorFactory::create(); + $request = $serverRequestCreator->createServerRequestFromGlobals(); + } + + $response = $this->handle($request); + $responseEmitter = new ResponseEmitter(); + $responseEmitter->emit($response); + } + + /** + * Handle a request + * + * This method traverses the application middleware stack and then returns the + * resultant Response object. + * + * @param ServerRequestInterface $request + * @return ResponseInterface + */ + public function handle(ServerRequestInterface $request): ResponseInterface + { + $response = $this->middlewareDispatcher->handle($request); + + /** + * This is to be in compliance with RFC 2616, Section 9. + * If the incoming request method is HEAD, we need to ensure that the response body + * is empty as the request may fall back on a GET route handler due to FastRoute's + * routing logic which could potentially append content to the response body + * https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.4 + */ + $method = strtoupper($request->getMethod()); + if ($method === 'HEAD') { + $emptyBody = $this->responseFactory->createResponse()->getBody(); + return $response->withBody($emptyBody); + } + + return $response; + } +} diff --git a/api/vendor/slim/slim/Slim/CallableResolver.php b/api/vendor/slim/slim/Slim/CallableResolver.php new file mode 100644 index 0000000..be2acc4 --- /dev/null +++ b/api/vendor/slim/slim/Slim/CallableResolver.php @@ -0,0 +1,200 @@ +container = $container; + } + + /** + * {@inheritdoc} + */ + public function resolve($toResolve): callable + { + $toResolve = $this->prepareToResolve($toResolve); + if (is_callable($toResolve)) { + return $this->bindToContainer($toResolve); + } + $resolved = $toResolve; + if (is_string($toResolve)) { + $resolved = $this->resolveSlimNotation($toResolve); + $resolved[1] ??= '__invoke'; + } + $callable = $this->assertCallable($resolved, $toResolve); + return $this->bindToContainer($callable); + } + + /** + * {@inheritdoc} + */ + public function resolveRoute($toResolve): callable + { + return $this->resolveByPredicate($toResolve, [$this, 'isRoute'], 'handle'); + } + + /** + * {@inheritdoc} + */ + public function resolveMiddleware($toResolve): callable + { + return $this->resolveByPredicate($toResolve, [$this, 'isMiddleware'], 'process'); + } + + /** + * @param callable|array{class-string, string}|string $toResolve + * + * @throws RuntimeException + */ + private function resolveByPredicate($toResolve, callable $predicate, string $defaultMethod): callable + { + $toResolve = $this->prepareToResolve($toResolve); + if (is_callable($toResolve)) { + return $this->bindToContainer($toResolve); + } + $resolved = $toResolve; + if ($predicate($toResolve)) { + $resolved = [$toResolve, $defaultMethod]; + } + if (is_string($toResolve)) { + [$instance, $method] = $this->resolveSlimNotation($toResolve); + if ($method === null && $predicate($instance)) { + $method = $defaultMethod; + } + $resolved = [$instance, $method ?? '__invoke']; + } + $callable = $this->assertCallable($resolved, $toResolve); + return $this->bindToContainer($callable); + } + + /** + * @param mixed $toResolve + */ + private function isRoute($toResolve): bool + { + return $toResolve instanceof RequestHandlerInterface; + } + + /** + * @param mixed $toResolve + */ + private function isMiddleware($toResolve): bool + { + return $toResolve instanceof MiddlewareInterface; + } + + /** + * @throws RuntimeException + * + * @return array{object, string|null} [Instance, Method Name] + */ + private function resolveSlimNotation(string $toResolve): array + { + /** @psalm-suppress ArgumentTypeCoercion */ + preg_match(CallableResolver::$callablePattern, $toResolve, $matches); + [$class, $method] = $matches ? [$matches[1], $matches[2]] : [$toResolve, null]; + + if ($this->container && $this->container->has($class)) { + $instance = $this->container->get($class); + if (!is_object($instance)) { + throw new RuntimeException(sprintf('%s container entry is not an object', $class)); + } + } else { + if (!class_exists($class)) { + if ($method) { + $class .= '::' . $method . '()'; + } + throw new RuntimeException(sprintf('Callable %s does not exist', $class)); + } + $instance = new $class($this->container); + } + return [$instance, $method]; + } + + /** + * @param mixed $resolved + * @param mixed $toResolve + * + * @throws RuntimeException + */ + private function assertCallable($resolved, $toResolve): callable + { + if (!is_callable($resolved)) { + if (is_callable($toResolve) || is_object($toResolve) || is_array($toResolve)) { + $formatedToResolve = ($toResolveJson = json_encode($toResolve)) !== false ? $toResolveJson : ''; + } else { + $formatedToResolve = is_string($toResolve) ? $toResolve : ''; + } + throw new RuntimeException(sprintf('%s is not resolvable', $formatedToResolve)); + } + return $resolved; + } + + private function bindToContainer(callable $callable): callable + { + if (is_array($callable) && $callable[0] instanceof Closure) { + $callable = $callable[0]; + } + if ($this->container && $callable instanceof Closure) { + /** @var Closure $callable */ + $callable = $callable->bindTo($this->container); + } + return $callable; + } + + /** + * @param callable|string|array{class-string, string}|mixed $toResolve + * + * @return callable|string|array{class-string, string}|mixed + */ + private function prepareToResolve($toResolve) + { + if (!is_array($toResolve)) { + return $toResolve; + } + $candidate = $toResolve; + $class = array_shift($candidate); + $method = array_shift($candidate); + if (is_string($class) && is_string($method)) { + return $class . ':' . $method; + } + return $toResolve; + } +} diff --git a/api/vendor/slim/slim/Slim/Error/AbstractErrorRenderer.php b/api/vendor/slim/slim/Slim/Error/AbstractErrorRenderer.php new file mode 100644 index 0000000..90b290d --- /dev/null +++ b/api/vendor/slim/slim/Slim/Error/AbstractErrorRenderer.php @@ -0,0 +1,46 @@ +getTitle(); + } + + return $this->defaultErrorTitle; + } + + protected function getErrorDescription(Throwable $exception): string + { + if ($exception instanceof HttpException) { + return $exception->getDescription(); + } + + return $this->defaultErrorDescription; + } +} diff --git a/api/vendor/slim/slim/Slim/Error/Renderers/HtmlErrorRenderer.php b/api/vendor/slim/slim/Slim/Error/Renderers/HtmlErrorRenderer.php new file mode 100644 index 0000000..8fd838b --- /dev/null +++ b/api/vendor/slim/slim/Slim/Error/Renderers/HtmlErrorRenderer.php @@ -0,0 +1,83 @@ +The application could not run because of the following error:

'; + $html .= '

Details

'; + $html .= $this->renderExceptionFragment($exception); + } else { + $html = "

{$this->getErrorDescription($exception)}

"; + } + + return $this->renderHtmlBody($this->getErrorTitle($exception), $html); + } + + private function renderExceptionFragment(Throwable $exception): string + { + $html = sprintf('
Type: %s
', get_class($exception)); + + $code = $exception->getCode(); + $html .= sprintf('
Code: %s
', $code); + + $html .= sprintf('
Message: %s
', htmlentities($exception->getMessage())); + + $html .= sprintf('
File: %s
', $exception->getFile()); + + $html .= sprintf('
Line: %s
', $exception->getLine()); + + $html .= '

Trace

'; + $html .= sprintf('
%s
', htmlentities($exception->getTraceAsString())); + + return $html; + } + + public function renderHtmlBody(string $title = '', string $html = ''): string + { + return sprintf( + '' . + '' . + ' ' . + ' ' . + ' ' . + ' %s' . + ' ' . + ' ' . + ' ' . + '

%s

' . + '
%s
' . + ' Go Back' . + ' ' . + '', + $title, + $title, + $html + ); + } +} diff --git a/api/vendor/slim/slim/Slim/Error/Renderers/JsonErrorRenderer.php b/api/vendor/slim/slim/Slim/Error/Renderers/JsonErrorRenderer.php new file mode 100644 index 0000000..06085d2 --- /dev/null +++ b/api/vendor/slim/slim/Slim/Error/Renderers/JsonErrorRenderer.php @@ -0,0 +1,55 @@ + $this->getErrorTitle($exception)]; + + if ($displayErrorDetails) { + $error['exception'] = []; + do { + $error['exception'][] = $this->formatExceptionFragment($exception); + } while ($exception = $exception->getPrevious()); + } + + return (string) json_encode($error, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); + } + + /** + * @return array + */ + private function formatExceptionFragment(Throwable $exception): array + { + $code = $exception->getCode(); + return [ + 'type' => get_class($exception), + 'code' => $code, + 'message' => $exception->getMessage(), + 'file' => $exception->getFile(), + 'line' => $exception->getLine(), + ]; + } +} diff --git a/api/vendor/slim/slim/Slim/Error/Renderers/PlainTextErrorRenderer.php b/api/vendor/slim/slim/Slim/Error/Renderers/PlainTextErrorRenderer.php new file mode 100644 index 0000000..fcb6e8a --- /dev/null +++ b/api/vendor/slim/slim/Slim/Error/Renderers/PlainTextErrorRenderer.php @@ -0,0 +1,59 @@ +getErrorTitle($exception)}\n"; + + if ($displayErrorDetails) { + $text .= $this->formatExceptionFragment($exception); + + while ($exception = $exception->getPrevious()) { + $text .= "\nPrevious Error:\n"; + $text .= $this->formatExceptionFragment($exception); + } + } + + return $text; + } + + private function formatExceptionFragment(Throwable $exception): string + { + $text = sprintf("Type: %s\n", get_class($exception)); + + $code = $exception->getCode(); + + $text .= sprintf("Code: %s\n", $code); + + $text .= sprintf("Message: %s\n", $exception->getMessage()); + + $text .= sprintf("File: %s\n", $exception->getFile()); + + $text .= sprintf("Line: %s\n", $exception->getLine()); + + $text .= sprintf('Trace: %s', $exception->getTraceAsString()); + + return $text; + } +} diff --git a/api/vendor/slim/slim/Slim/Error/Renderers/XmlErrorRenderer.php b/api/vendor/slim/slim/Slim/Error/Renderers/XmlErrorRenderer.php new file mode 100644 index 0000000..1171b79 --- /dev/null +++ b/api/vendor/slim/slim/Slim/Error/Renderers/XmlErrorRenderer.php @@ -0,0 +1,54 @@ +\n"; + $xml .= "\n " . $this->createCdataSection($this->getErrorTitle($exception)) . "\n"; + + if ($displayErrorDetails) { + do { + $xml .= " \n"; + $xml .= ' ' . get_class($exception) . "\n"; + $xml .= ' ' . $exception->getCode() . "\n"; + $xml .= ' ' . $this->createCdataSection($exception->getMessage()) . "\n"; + $xml .= ' ' . $exception->getFile() . "\n"; + $xml .= ' ' . $exception->getLine() . "\n"; + $xml .= " \n"; + } while ($exception = $exception->getPrevious()); + } + + $xml .= ''; + + return $xml; + } + + /** + * Returns a CDATA section with the given content. + */ + private function createCdataSection(string $content): string + { + return sprintf('', str_replace(']]>', ']]]]>', $content)); + } +} diff --git a/api/vendor/slim/slim/Slim/Exception/HttpBadRequestException.php b/api/vendor/slim/slim/Slim/Exception/HttpBadRequestException.php new file mode 100644 index 0000000..000c248 --- /dev/null +++ b/api/vendor/slim/slim/Slim/Exception/HttpBadRequestException.php @@ -0,0 +1,29 @@ +request = $request; + } + + public function getRequest(): ServerRequestInterface + { + return $this->request; + } + + public function getTitle(): string + { + return $this->title; + } + + public function setTitle(string $title): self + { + $this->title = $title; + return $this; + } + + public function getDescription(): string + { + return $this->description; + } + + public function setDescription(string $description): self + { + $this->description = $description; + return $this; + } +} diff --git a/api/vendor/slim/slim/Slim/Exception/HttpForbiddenException.php b/api/vendor/slim/slim/Slim/Exception/HttpForbiddenException.php new file mode 100644 index 0000000..d262a63 --- /dev/null +++ b/api/vendor/slim/slim/Slim/Exception/HttpForbiddenException.php @@ -0,0 +1,28 @@ +allowedMethods; + } + + /** + * @param string[] $methods + */ + public function setAllowedMethods(array $methods): self + { + $this->allowedMethods = $methods; + $this->message = 'Method not allowed. Must be one of: ' . implode(', ', $methods); + return $this; + } +} diff --git a/api/vendor/slim/slim/Slim/Exception/HttpNotFoundException.php b/api/vendor/slim/slim/Slim/Exception/HttpNotFoundException.php new file mode 100644 index 0000000..865146d --- /dev/null +++ b/api/vendor/slim/slim/Slim/Exception/HttpNotFoundException.php @@ -0,0 +1,27 @@ +message = $message; + } + + // @phpstan-ignore-next-line + parent::__construct($request, $this->message, $this->code, $previous); + } +} diff --git a/api/vendor/slim/slim/Slim/Exception/HttpTooManyRequestsException.php b/api/vendor/slim/slim/Slim/Exception/HttpTooManyRequestsException.php new file mode 100644 index 0000000..af438ba --- /dev/null +++ b/api/vendor/slim/slim/Slim/Exception/HttpTooManyRequestsException.php @@ -0,0 +1,29 @@ + : App) + */ + public static function create( + ?ResponseFactoryInterface $responseFactory = null, + ?ContainerInterface $container = null, + ?CallableResolverInterface $callableResolver = null, + ?RouteCollectorInterface $routeCollector = null, + ?RouteResolverInterface $routeResolver = null, + ?MiddlewareDispatcherInterface $middlewareDispatcher = null + ): App { + static::$responseFactory = $responseFactory ?? static::$responseFactory; + return new App( + self::determineResponseFactory(), + $container ?? static::$container, + $callableResolver ?? static::$callableResolver, + $routeCollector ?? static::$routeCollector, + $routeResolver ?? static::$routeResolver, + $middlewareDispatcher ?? static::$middlewareDispatcher + ); + } + + /** + * @template TContainerInterface of (ContainerInterface) + * @param TContainerInterface $container + * @return App + */ + public static function createFromContainer(ContainerInterface $container): App + { + $responseFactory = $container->has(ResponseFactoryInterface::class) + && ( + $responseFactoryFromContainer = $container->get(ResponseFactoryInterface::class) + ) instanceof ResponseFactoryInterface + ? $responseFactoryFromContainer + : self::determineResponseFactory(); + + $callableResolver = $container->has(CallableResolverInterface::class) + && ( + $callableResolverFromContainer = $container->get(CallableResolverInterface::class) + ) instanceof CallableResolverInterface + ? $callableResolverFromContainer + : null; + + $routeCollector = $container->has(RouteCollectorInterface::class) + && ( + $routeCollectorFromContainer = $container->get(RouteCollectorInterface::class) + ) instanceof RouteCollectorInterface + ? $routeCollectorFromContainer + : null; + + $routeResolver = $container->has(RouteResolverInterface::class) + && ( + $routeResolverFromContainer = $container->get(RouteResolverInterface::class) + ) instanceof RouteResolverInterface + ? $routeResolverFromContainer + : null; + + $middlewareDispatcher = $container->has(MiddlewareDispatcherInterface::class) + && ( + $middlewareDispatcherFromContainer = $container->get(MiddlewareDispatcherInterface::class) + ) instanceof MiddlewareDispatcherInterface + ? $middlewareDispatcherFromContainer + : null; + + return new App( + $responseFactory, + $container, + $callableResolver, + $routeCollector, + $routeResolver, + $middlewareDispatcher + ); + } + + /** + * @throws RuntimeException + */ + public static function determineResponseFactory(): ResponseFactoryInterface + { + if (static::$responseFactory) { + if (static::$streamFactory) { + return static::attemptResponseFactoryDecoration(static::$responseFactory, static::$streamFactory); + } + return static::$responseFactory; + } + + $psr17FactoryProvider = static::$psr17FactoryProvider ?? new Psr17FactoryProvider(); + + /** @var Psr17Factory $psr17factory */ + foreach ($psr17FactoryProvider->getFactories() as $psr17factory) { + if ($psr17factory::isResponseFactoryAvailable()) { + $responseFactory = $psr17factory::getResponseFactory(); + + if (static::$streamFactory || $psr17factory::isStreamFactoryAvailable()) { + $streamFactory = static::$streamFactory ?? $psr17factory::getStreamFactory(); + return static::attemptResponseFactoryDecoration($responseFactory, $streamFactory); + } + + return $responseFactory; + } + } + + throw new RuntimeException( + "Could not detect any PSR-17 ResponseFactory implementations. " . + "Please install a supported implementation in order to use `AppFactory::create()`. " . + "See https://github.com/slimphp/Slim/blob/4.x/README.md for a list of supported implementations." + ); + } + + protected static function attemptResponseFactoryDecoration( + ResponseFactoryInterface $responseFactory, + StreamFactoryInterface $streamFactory + ): ResponseFactoryInterface { + if ( + static::$slimHttpDecoratorsAutomaticDetectionEnabled + && SlimHttpPsr17Factory::isResponseFactoryAvailable() + ) { + return SlimHttpPsr17Factory::createDecoratedResponseFactory($responseFactory, $streamFactory); + } + + return $responseFactory; + } + + public static function setPsr17FactoryProvider(Psr17FactoryProviderInterface $psr17FactoryProvider): void + { + static::$psr17FactoryProvider = $psr17FactoryProvider; + } + + public static function setResponseFactory(ResponseFactoryInterface $responseFactory): void + { + static::$responseFactory = $responseFactory; + } + + public static function setStreamFactory(StreamFactoryInterface $streamFactory): void + { + static::$streamFactory = $streamFactory; + } + + public static function setContainer(ContainerInterface $container): void + { + static::$container = $container; + } + + public static function setCallableResolver(CallableResolverInterface $callableResolver): void + { + static::$callableResolver = $callableResolver; + } + + public static function setRouteCollector(RouteCollectorInterface $routeCollector): void + { + static::$routeCollector = $routeCollector; + } + + public static function setRouteResolver(RouteResolverInterface $routeResolver): void + { + static::$routeResolver = $routeResolver; + } + + public static function setMiddlewareDispatcher(MiddlewareDispatcherInterface $middlewareDispatcher): void + { + static::$middlewareDispatcher = $middlewareDispatcher; + } + + public static function setSlimHttpDecoratorsAutomaticDetection(bool $enabled): void + { + static::$slimHttpDecoratorsAutomaticDetectionEnabled = $enabled; + } +} diff --git a/api/vendor/slim/slim/Slim/Factory/Psr17/GuzzlePsr17Factory.php b/api/vendor/slim/slim/Slim/Factory/Psr17/GuzzlePsr17Factory.php new file mode 100644 index 0000000..32a548a --- /dev/null +++ b/api/vendor/slim/slim/Slim/Factory/Psr17/GuzzlePsr17Factory.php @@ -0,0 +1,19 @@ +serverRequestCreator = $serverRequestCreator; + $this->serverRequestCreatorMethod = $serverRequestCreatorMethod; + } + + /** + * {@inheritdoc} + */ + public function createServerRequestFromGlobals(): ServerRequestInterface + { + /** @var callable $callable */ + $callable = [$this->serverRequestCreator, $this->serverRequestCreatorMethod]; + + /** @var ServerRequestInterface */ + return (Closure::fromCallable($callable))(); + } +} diff --git a/api/vendor/slim/slim/Slim/Factory/Psr17/SlimHttpPsr17Factory.php b/api/vendor/slim/slim/Slim/Factory/Psr17/SlimHttpPsr17Factory.php new file mode 100644 index 0000000..5d63631 --- /dev/null +++ b/api/vendor/slim/slim/Slim/Factory/Psr17/SlimHttpPsr17Factory.php @@ -0,0 +1,39 @@ +serverRequestCreator = $serverRequestCreator; + } + + /** + * {@inheritdoc} + */ + public function createServerRequestFromGlobals(): ServerRequestInterface + { + if (!static::isServerRequestDecoratorAvailable()) { + throw new RuntimeException('The Slim-Http ServerRequest decorator is not available.'); + } + + $request = $this->serverRequestCreator->createServerRequestFromGlobals(); + + if ( + !(( + $decoratedServerRequest = new static::$serverRequestDecoratorClass($request) + ) instanceof ServerRequestInterface) + ) { + throw new RuntimeException(get_called_class() . ' could not instantiate a decorated server request.'); + } + + return $decoratedServerRequest; + } + + public static function isServerRequestDecoratorAvailable(): bool + { + return class_exists(static::$serverRequestDecoratorClass); + } +} diff --git a/api/vendor/slim/slim/Slim/Factory/Psr17/SlimPsr17Factory.php b/api/vendor/slim/slim/Slim/Factory/Psr17/SlimPsr17Factory.php new file mode 100644 index 0000000..46c46f9 --- /dev/null +++ b/api/vendor/slim/slim/Slim/Factory/Psr17/SlimPsr17Factory.php @@ -0,0 +1,19 @@ +getFactories() as $psr17Factory) { + if ($psr17Factory::isServerRequestCreatorAvailable()) { + $serverRequestCreator = $psr17Factory::getServerRequestCreator(); + return static::attemptServerRequestCreatorDecoration($serverRequestCreator); + } + } + + throw new RuntimeException( + "Could not detect any ServerRequest creator implementations. " . + "Please install a supported implementation in order to use `App::run()` " . + "without having to pass in a `ServerRequest` object. " . + "See https://github.com/slimphp/Slim/blob/4.x/README.md for a list of supported implementations." + ); + } + + protected static function attemptServerRequestCreatorDecoration( + ServerRequestCreatorInterface $serverRequestCreator + ): ServerRequestCreatorInterface { + if ( + static::$slimHttpDecoratorsAutomaticDetectionEnabled + && SlimHttpServerRequestCreator::isServerRequestDecoratorAvailable() + ) { + return new SlimHttpServerRequestCreator($serverRequestCreator); + } + + return $serverRequestCreator; + } + + public static function setPsr17FactoryProvider(Psr17FactoryProviderInterface $psr17FactoryProvider): void + { + static::$psr17FactoryProvider = $psr17FactoryProvider; + } + + public static function setServerRequestCreator(ServerRequestCreatorInterface $serverRequestCreator): void + { + self::$serverRequestCreator = $serverRequestCreator; + } + + public static function setSlimHttpDecoratorsAutomaticDetection(bool $enabled): void + { + static::$slimHttpDecoratorsAutomaticDetectionEnabled = $enabled; + } +} diff --git a/api/vendor/slim/slim/Slim/Handlers/ErrorHandler.php b/api/vendor/slim/slim/Slim/Handlers/ErrorHandler.php new file mode 100644 index 0000000..a6b99ce --- /dev/null +++ b/api/vendor/slim/slim/Slim/Handlers/ErrorHandler.php @@ -0,0 +1,314 @@ + + */ + protected array $errorRenderers = [ + 'application/json' => JsonErrorRenderer::class, + 'application/xml' => XmlErrorRenderer::class, + 'text/xml' => XmlErrorRenderer::class, + 'text/html' => HtmlErrorRenderer::class, + 'text/plain' => PlainTextErrorRenderer::class, + ]; + + protected bool $displayErrorDetails = false; + + protected bool $logErrors; + + protected bool $logErrorDetails = false; + + protected ?string $contentType = null; + + protected ?string $method = null; + + protected ServerRequestInterface $request; + + protected Throwable $exception; + + protected int $statusCode; + + protected CallableResolverInterface $callableResolver; + + protected ResponseFactoryInterface $responseFactory; + + protected LoggerInterface $logger; + + public function __construct( + CallableResolverInterface $callableResolver, + ResponseFactoryInterface $responseFactory, + ?LoggerInterface $logger = null + ) { + $this->callableResolver = $callableResolver; + $this->responseFactory = $responseFactory; + $this->logger = $logger ?: $this->getDefaultLogger(); + } + + /** + * Invoke error handler + * + * @param ServerRequestInterface $request The most recent Request object + * @param Throwable $exception The caught Exception object + * @param bool $displayErrorDetails Whether or not to display the error details + * @param bool $logErrors Whether or not to log errors + * @param bool $logErrorDetails Whether or not to log error details + */ + public function __invoke( + ServerRequestInterface $request, + Throwable $exception, + bool $displayErrorDetails, + bool $logErrors, + bool $logErrorDetails + ): ResponseInterface { + $this->displayErrorDetails = $displayErrorDetails; + $this->logErrors = $logErrors; + $this->logErrorDetails = $logErrorDetails; + $this->request = $request; + $this->exception = $exception; + $this->method = $request->getMethod(); + $this->statusCode = $this->determineStatusCode(); + if ($this->contentType === null) { + $this->contentType = $this->determineContentType($request); + } + + if ($logErrors) { + $this->writeToErrorLog(); + } + + return $this->respond(); + } + + /** + * Force the content type for all error handler responses. + * + * @param string|null $contentType The content type + */ + public function forceContentType(?string $contentType): void + { + $this->contentType = $contentType; + } + + protected function determineStatusCode(): int + { + if ($this->method === 'OPTIONS') { + return 200; + } + + if ($this->exception instanceof HttpException) { + return $this->exception->getCode(); + } + + return 500; + } + + /** + * Determine which content type we know about is wanted using Accept header + * + * Note: This method is a bare-bones implementation designed specifically for + * Slim's error handling requirements. Consider a fully-feature solution such + * as willdurand/negotiation for any other situation. + */ + protected function determineContentType(ServerRequestInterface $request): ?string + { + $acceptHeader = $request->getHeaderLine('Accept'); + $selectedContentTypes = array_intersect( + explode(',', $acceptHeader), + array_keys($this->errorRenderers) + ); + $count = count($selectedContentTypes); + + if ($count) { + $current = current($selectedContentTypes); + + /** + * Ensure other supported content types take precedence over text/plain + * when multiple content types are provided via Accept header. + */ + if ($current === 'text/plain' && $count > 1) { + $next = next($selectedContentTypes); + if (is_string($next)) { + return $next; + } + } + + // @phpstan-ignore-next-line + if (is_string($current)) { + return $current; + } + } + + if (preg_match('/\+(json|xml)/', $acceptHeader, $matches)) { + $mediaType = 'application/' . $matches[1]; + if (array_key_exists($mediaType, $this->errorRenderers)) { + return $mediaType; + } + } + + return null; + } + + /** + * Determine which renderer to use based on content type + * + * @throws RuntimeException + */ + protected function determineRenderer(): callable + { + if ($this->contentType !== null && array_key_exists($this->contentType, $this->errorRenderers)) { + $renderer = $this->errorRenderers[$this->contentType]; + } else { + $renderer = $this->defaultErrorRenderer; + } + + return $this->callableResolver->resolve($renderer); + } + + /** + * Register an error renderer for a specific content-type + * + * @param string $contentType The content-type this renderer should be registered to + * @param ErrorRendererInterface|string|callable $errorRenderer The error renderer + */ + public function registerErrorRenderer(string $contentType, $errorRenderer): void + { + $this->errorRenderers[$contentType] = $errorRenderer; + } + + /** + * Set the default error renderer + * + * @param string $contentType The content type of the default error renderer + * @param ErrorRendererInterface|string|callable $errorRenderer The default error renderer + */ + public function setDefaultErrorRenderer(string $contentType, $errorRenderer): void + { + $this->defaultErrorRendererContentType = $contentType; + $this->defaultErrorRenderer = $errorRenderer; + } + + /** + * Set the renderer for the error logger + * + * @param ErrorRendererInterface|string|callable $logErrorRenderer + */ + public function setLogErrorRenderer($logErrorRenderer): void + { + $this->logErrorRenderer = $logErrorRenderer; + } + + /** + * Write to the error log if $logErrors has been set to true + */ + protected function writeToErrorLog(): void + { + $renderer = $this->callableResolver->resolve($this->logErrorRenderer); + + /** @var string $error */ + $error = $renderer($this->exception, $this->logErrorDetails); + + if ($this->logErrorRenderer === PlainTextErrorRenderer::class && !$this->displayErrorDetails) { + $error .= "\nTips: To display error details in HTTP response "; + $error .= 'set "displayErrorDetails" to true in the ErrorHandler constructor.'; + } + + $this->logError($error); + } + + /** + * Wraps the error_log function so that this can be easily tested + */ + protected function logError(string $error): void + { + $this->logger->error($error); + } + + /** + * Returns a default logger implementation. + */ + protected function getDefaultLogger(): LoggerInterface + { + return new Logger(); + } + + protected function respond(): ResponseInterface + { + $response = $this->responseFactory->createResponse($this->statusCode); + if ($this->contentType !== null && array_key_exists($this->contentType, $this->errorRenderers)) { + $response = $response->withHeader('Content-type', $this->contentType); + } else { + $response = $response->withHeader('Content-type', $this->defaultErrorRendererContentType); + } + + if ($this->exception instanceof HttpMethodNotAllowedException) { + $allowedMethods = implode(', ', $this->exception->getAllowedMethods()); + $response = $response->withHeader('Allow', $allowedMethods); + } + + $renderer = $this->determineRenderer(); + $body = call_user_func($renderer, $this->exception, $this->displayErrorDetails); + if ($body !== false) { + /** @var string $body */ + $response->getBody()->write($body); + } + + return $response; + } +} diff --git a/api/vendor/slim/slim/Slim/Handlers/Strategies/RequestHandler.php b/api/vendor/slim/slim/Slim/Handlers/Strategies/RequestHandler.php new file mode 100644 index 0000000..0792001 --- /dev/null +++ b/api/vendor/slim/slim/Slim/Handlers/Strategies/RequestHandler.php @@ -0,0 +1,49 @@ +appendRouteArgumentsToRequestAttributes = $appendRouteArgumentsToRequestAttributes; + } + + /** + * Invoke a route callable that implements RequestHandlerInterface + * + * @param array $routeArguments + */ + public function __invoke( + callable $callable, + ServerRequestInterface $request, + ResponseInterface $response, + array $routeArguments + ): ResponseInterface { + if ($this->appendRouteArgumentsToRequestAttributes) { + foreach ($routeArguments as $k => $v) { + $request = $request->withAttribute($k, $v); + } + } + + /** @var ResponseInterface */ + return $callable($request); + } +} diff --git a/api/vendor/slim/slim/Slim/Handlers/Strategies/RequestResponse.php b/api/vendor/slim/slim/Slim/Handlers/Strategies/RequestResponse.php new file mode 100644 index 0000000..53326a2 --- /dev/null +++ b/api/vendor/slim/slim/Slim/Handlers/Strategies/RequestResponse.php @@ -0,0 +1,41 @@ + $routeArguments + */ + public function __invoke( + callable $callable, + ServerRequestInterface $request, + ResponseInterface $response, + array $routeArguments + ): ResponseInterface { + foreach ($routeArguments as $k => $v) { + $request = $request->withAttribute($k, $v); + } + + /** @var ResponseInterface */ + return $callable($request, $response, $routeArguments); + } +} diff --git a/api/vendor/slim/slim/Slim/Handlers/Strategies/RequestResponseArgs.php b/api/vendor/slim/slim/Slim/Handlers/Strategies/RequestResponseArgs.php new file mode 100644 index 0000000..d61decb --- /dev/null +++ b/api/vendor/slim/slim/Slim/Handlers/Strategies/RequestResponseArgs.php @@ -0,0 +1,40 @@ + $routeArguments + */ + public function __invoke( + callable $callable, + ServerRequestInterface $request, + ResponseInterface $response, + array $routeArguments + ): ResponseInterface { + /** @var ResponseInterface */ + return $callable($request, $response, ...array_values($routeArguments)); + } +} diff --git a/api/vendor/slim/slim/Slim/Handlers/Strategies/RequestResponseNamedArgs.php b/api/vendor/slim/slim/Slim/Handlers/Strategies/RequestResponseNamedArgs.php new file mode 100644 index 0000000..69f473b --- /dev/null +++ b/api/vendor/slim/slim/Slim/Handlers/Strategies/RequestResponseNamedArgs.php @@ -0,0 +1,39 @@ + $routeArguments + */ + public function __invoke( + callable $callable, + ServerRequestInterface $request, + ResponseInterface $response, + array $routeArguments + ): ResponseInterface { + /** @var ResponseInterface */ + return $callable($request, $response, ...$routeArguments); + } +} diff --git a/api/vendor/slim/slim/Slim/Interfaces/AdvancedCallableResolverInterface.php b/api/vendor/slim/slim/Slim/Interfaces/AdvancedCallableResolverInterface.php new file mode 100644 index 0000000..1145466 --- /dev/null +++ b/api/vendor/slim/slim/Slim/Interfaces/AdvancedCallableResolverInterface.php @@ -0,0 +1,28 @@ + $routeArguments The route's placeholder arguments + * + * @return ResponseInterface The response from the callable. + */ + public function __invoke( + callable $callable, + ServerRequestInterface $request, + ResponseInterface $response, + array $routeArguments + ): ResponseInterface; +} diff --git a/api/vendor/slim/slim/Slim/Interfaces/MiddlewareDispatcherInterface.php b/api/vendor/slim/slim/Slim/Interfaces/MiddlewareDispatcherInterface.php new file mode 100644 index 0000000..9fa34a6 --- /dev/null +++ b/api/vendor/slim/slim/Slim/Interfaces/MiddlewareDispatcherInterface.php @@ -0,0 +1,43 @@ + + */ + public function setBasePath(string $basePath): RouteCollectorProxyInterface; + + /** + * Add GET route + * + * @param string $pattern The route URI pattern + * @param callable|array{class-string, string}|string $callable The route callback routine + */ + public function get(string $pattern, $callable): RouteInterface; + + /** + * Add POST route + * + * @param string $pattern The route URI pattern + * @param callable|array{class-string, string}|string $callable The route callback routine + */ + public function post(string $pattern, $callable): RouteInterface; + + /** + * Add PUT route + * + * @param string $pattern The route URI pattern + * @param callable|array{class-string, string}|string $callable The route callback routine + */ + public function put(string $pattern, $callable): RouteInterface; + + /** + * Add PATCH route + * + * @param string $pattern The route URI pattern + * @param callable|array{class-string, string}|string $callable The route callback routine + */ + public function patch(string $pattern, $callable): RouteInterface; + + /** + * Add DELETE route + * + * @param string $pattern The route URI pattern + * @param callable|array{class-string, string}|string $callable The route callback routine + */ + public function delete(string $pattern, $callable): RouteInterface; + + /** + * Add OPTIONS route + * + * @param string $pattern The route URI pattern + * @param callable|array{class-string, string}|string $callable The route callback routine + */ + public function options(string $pattern, $callable): RouteInterface; + + /** + * Add route for any HTTP method + * + * @param string $pattern The route URI pattern + * @param callable|array{class-string, string}|string $callable The route callback routine + */ + public function any(string $pattern, $callable): RouteInterface; + + /** + * Add route with multiple methods + * + * @param string[] $methods Numeric array of HTTP method names + * @param string $pattern The route URI pattern + * @param callable|array{class-string, string}|string $callable The route callback routine + */ + public function map(array $methods, string $pattern, $callable): RouteInterface; + + /** + * Route Groups + * + * This method accepts a route pattern and a callback. All route + * declarations in the callback will be prepended by the group(s) + * that it is in. + * @param string|callable $callable + */ + public function group(string $pattern, $callable): RouteGroupInterface; + + /** + * Add a route that sends an HTTP redirect + * + * @param string|UriInterface $to + */ + public function redirect(string $from, $to, int $status = 302): RouteInterface; +} diff --git a/api/vendor/slim/slim/Slim/Interfaces/RouteGroupInterface.php b/api/vendor/slim/slim/Slim/Interfaces/RouteGroupInterface.php new file mode 100644 index 0000000..efc1c5a --- /dev/null +++ b/api/vendor/slim/slim/Slim/Interfaces/RouteGroupInterface.php @@ -0,0 +1,43 @@ + $dispatcher + */ + public function appendMiddlewareToDispatcher(MiddlewareDispatcher $dispatcher): RouteGroupInterface; + + /** + * Get the RouteGroup's pattern + */ + public function getPattern(): string; +} diff --git a/api/vendor/slim/slim/Slim/Interfaces/RouteInterface.php b/api/vendor/slim/slim/Slim/Interfaces/RouteInterface.php new file mode 100644 index 0000000..5af81c3 --- /dev/null +++ b/api/vendor/slim/slim/Slim/Interfaces/RouteInterface.php @@ -0,0 +1,128 @@ + + */ + public function getArguments(): array; + + /** + * Set a route argument + * + * @deprecated 4.14.1 Use a middleware for custom route arguments now. + */ + public function setArgument(string $name, string $value): RouteInterface; + + /** + * Replace route arguments + * + * @param array $arguments + * + * @deprecated 4.14.1 Use a middleware for custom route arguments now. + */ + public function setArguments(array $arguments): self; + + /** + * @param MiddlewareInterface|string|callable $middleware + */ + public function add($middleware): self; + + public function addMiddleware(MiddlewareInterface $middleware): self; + + /** + * Prepare the route for use + * + * @param array $arguments + */ + public function prepare(array $arguments): self; + + /** + * Run route + * + * This method traverses the middleware stack, including the route's callable + * and captures the resultant HTTP response object. It then sends the response + * back to the Application. + */ + public function run(ServerRequestInterface $request): ResponseInterface; +} diff --git a/api/vendor/slim/slim/Slim/Interfaces/RouteParserInterface.php b/api/vendor/slim/slim/Slim/Interfaces/RouteParserInterface.php new file mode 100644 index 0000000..12a6e60 --- /dev/null +++ b/api/vendor/slim/slim/Slim/Interfaces/RouteParserInterface.php @@ -0,0 +1,53 @@ + $data Named argument replacement data + * @param array> $queryParams Optional query string parameters + * + * @throws RuntimeException If named route does not exist + * @throws InvalidArgumentException If required data not provided + */ + public function relativeUrlFor(string $routeName, array $data = [], array $queryParams = []): string; + + /** + * Build the path for a named route including the base path + * + * @param string $routeName Route name + * @param array $data Named argument replacement data + * @param array> $queryParams Optional query string parameters + * + * @throws RuntimeException If named route does not exist + * @throws InvalidArgumentException If required data not provided + */ + public function urlFor(string $routeName, array $data = [], array $queryParams = []): string; + + /** + * Get fully qualified URL for named route + * + * @param UriInterface $uri + * @param string $routeName Route name + * @param array $data Named argument replacement data + * @param array> $queryParams Optional query string parameters + */ + public function fullUrlFor(UriInterface $uri, string $routeName, array $data = [], array $queryParams = []): string; +} diff --git a/api/vendor/slim/slim/Slim/Interfaces/RouteResolverInterface.php b/api/vendor/slim/slim/Slim/Interfaces/RouteResolverInterface.php new file mode 100644 index 0000000..256a359 --- /dev/null +++ b/api/vendor/slim/slim/Slim/Interfaces/RouteResolverInterface.php @@ -0,0 +1,17 @@ +getPath() + */ + public function computeRoutingResults(string $uri, string $method): RoutingResults; + + public function resolveRoute(string $identifier): RouteInterface; +} diff --git a/api/vendor/slim/slim/Slim/Interfaces/ServerRequestCreatorInterface.php b/api/vendor/slim/slim/Slim/Interfaces/ServerRequestCreatorInterface.php new file mode 100644 index 0000000..54d231e --- /dev/null +++ b/api/vendor/slim/slim/Slim/Interfaces/ServerRequestCreatorInterface.php @@ -0,0 +1,18 @@ + $context + * + * @throws InvalidArgumentException + */ + public function log($level, $message, array $context = []): void + { + error_log((string) $message); + } +} diff --git a/api/vendor/slim/slim/Slim/Middleware/BodyParsingMiddleware.php b/api/vendor/slim/slim/Slim/Middleware/BodyParsingMiddleware.php new file mode 100644 index 0000000..f04c0ef --- /dev/null +++ b/api/vendor/slim/slim/Slim/Middleware/BodyParsingMiddleware.php @@ -0,0 +1,201 @@ + callable + */ + public function __construct(array $bodyParsers = []) + { + $this->registerDefaultBodyParsers(); + + foreach ($bodyParsers as $mediaType => $parser) { + $this->registerBodyParser($mediaType, $parser); + } + } + + public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface + { + $parsedBody = $request->getParsedBody(); + + if (empty($parsedBody)) { + $parsedBody = $this->parseBody($request); + $request = $request->withParsedBody($parsedBody); + } + + return $handler->handle($request); + } + + /** + * @param string $mediaType A HTTP media type (excluding content-type params). + * @param callable $callable A callable that returns parsed contents for media type. + */ + public function registerBodyParser(string $mediaType, callable $callable): self + { + $this->bodyParsers[$mediaType] = $callable; + return $this; + } + + /** + * @param string $mediaType A HTTP media type (excluding content-type params). + */ + public function hasBodyParser(string $mediaType): bool + { + return isset($this->bodyParsers[$mediaType]); + } + + /** + * @param string $mediaType A HTTP media type (excluding content-type params). + * @throws RuntimeException + */ + public function getBodyParser(string $mediaType): callable + { + if (!isset($this->bodyParsers[$mediaType])) { + throw new RuntimeException('No parser for type ' . $mediaType); + } + return $this->bodyParsers[$mediaType]; + } + + protected function registerDefaultBodyParsers(): void + { + $this->registerBodyParser('application/json', static function ($input) { + /** @var string $input */ + $result = json_decode($input, true); + + if (!is_array($result)) { + return null; + } + + return $result; + }); + + $this->registerBodyParser('application/x-www-form-urlencoded', static function ($input) { + /** @var string $input */ + parse_str($input, $data); + + return $data; + }); + + $xmlCallable = static function ($input) { + /** @var string $input */ + + $backup = self::disableXmlEntityLoader(true); + $backup_errors = libxml_use_internal_errors(true); + $result = simplexml_load_string($input); + + self::disableXmlEntityLoader($backup); + libxml_clear_errors(); + libxml_use_internal_errors($backup_errors); + + if ($result === false) { + return null; + } + + return $result; + }; + + $this->registerBodyParser('application/xml', $xmlCallable); + $this->registerBodyParser('text/xml', $xmlCallable); + } + + /** + * @return null|array|object + */ + protected function parseBody(ServerRequestInterface $request) + { + $mediaType = $this->getMediaType($request); + if ($mediaType === null) { + return null; + } + + // Check if this specific media type has a parser registered first + if (!isset($this->bodyParsers[$mediaType])) { + // If not, look for a media type with a structured syntax suffix (RFC 6839) + $parts = explode('+', $mediaType); + if (count($parts) >= 2) { + $mediaType = 'application/' . $parts[count($parts) - 1]; + } + } + + if (isset($this->bodyParsers[$mediaType])) { + $body = (string)$request->getBody(); + $parsed = $this->bodyParsers[$mediaType]($body); + + if ($parsed !== null && !is_object($parsed) && !is_array($parsed)) { + throw new RuntimeException( + 'Request body media type parser return value must be an array, an object, or null' + ); + } + + return $parsed; + } + + return null; + } + + /** + * @return string|null The serverRequest media type, minus content-type params + */ + protected function getMediaType(ServerRequestInterface $request): ?string + { + $contentType = $request->getHeader('Content-Type')[0] ?? null; + + if (is_string($contentType) && trim($contentType) !== '') { + $contentTypeParts = explode(';', $contentType); + return strtolower(trim($contentTypeParts[0])); + } + + return null; + } + + protected static function disableXmlEntityLoader(bool $disable): bool + { + if (LIBXML_VERSION >= 20900) { + // libxml >= 2.9.0 disables entity loading by default, so it is + // safe to skip the real call (deprecated in PHP 8). + return true; + } + + // @codeCoverageIgnoreStart + return libxml_disable_entity_loader($disable); + // @codeCoverageIgnoreEnd + } +} diff --git a/api/vendor/slim/slim/Slim/Middleware/ContentLengthMiddleware.php b/api/vendor/slim/slim/Slim/Middleware/ContentLengthMiddleware.php new file mode 100644 index 0000000..e289fa3 --- /dev/null +++ b/api/vendor/slim/slim/Slim/Middleware/ContentLengthMiddleware.php @@ -0,0 +1,33 @@ +handle($request); + + // Add Content-Length header if not already added + $size = $response->getBody()->getSize(); + if ($size !== null && !$response->hasHeader('Content-Length')) { + $response = $response->withHeader('Content-Length', (string) $size); + } + + return $response; + } +} diff --git a/api/vendor/slim/slim/Slim/Middleware/ErrorMiddleware.php b/api/vendor/slim/slim/Slim/Middleware/ErrorMiddleware.php new file mode 100644 index 0000000..d6ac641 --- /dev/null +++ b/api/vendor/slim/slim/Slim/Middleware/ErrorMiddleware.php @@ -0,0 +1,215 @@ +callableResolver = $callableResolver; + $this->responseFactory = $responseFactory; + $this->displayErrorDetails = $displayErrorDetails; + $this->logErrors = $logErrors; + $this->logErrorDetails = $logErrorDetails; + $this->logger = $logger; + } + + public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface + { + try { + return $handler->handle($request); + } catch (Throwable $e) { + return $this->handleException($request, $e); + } + } + + public function handleException(ServerRequestInterface $request, Throwable $exception): ResponseInterface + { + if ($exception instanceof HttpException) { + $request = $exception->getRequest(); + } + + $exceptionType = get_class($exception); + $handler = $this->getErrorHandler($exceptionType); + + /** @var ResponseInterface */ + return $handler($request, $exception, $this->displayErrorDetails, $this->logErrors, $this->logErrorDetails); + } + + /** + * Get callable to handle scenarios where an error + * occurs when processing the current request. + * + * @param string $type Exception/Throwable name. ie: RuntimeException::class + * @return callable|ErrorHandler + */ + public function getErrorHandler(string $type) + { + if (isset($this->handlers[$type])) { + return $this->callableResolver->resolve($this->handlers[$type]); + } + + if (isset($this->subClassHandlers[$type])) { + return $this->callableResolver->resolve($this->subClassHandlers[$type]); + } + + foreach ($this->subClassHandlers as $class => $handler) { + if (is_subclass_of($type, $class)) { + return $this->callableResolver->resolve($handler); + } + } + + return $this->getDefaultErrorHandler(); + } + + /** + * Get default error handler + * + * @return ErrorHandler|callable + */ + public function getDefaultErrorHandler() + { + if ($this->defaultErrorHandler === null) { + $this->defaultErrorHandler = new ErrorHandler( + $this->callableResolver, + $this->responseFactory, + $this->logger + ); + } + + return $this->callableResolver->resolve($this->defaultErrorHandler); + } + + /** + * Set callable as the default Slim application error handler. + * + * The callable signature MUST match the ErrorHandlerInterface + * + * @param string|callable|ErrorHandler $handler + * @see ErrorHandlerInterface + * + * 1. Instance of \Psr\Http\Message\ServerRequestInterface + * 2. Instance of \Throwable + * 3. Boolean $displayErrorDetails + * 4. Boolean $logErrors + * 5. Boolean $logErrorDetails + * + * The callable MUST return an instance of + * \Psr\Http\Message\ResponseInterface. + * + */ + public function setDefaultErrorHandler($handler): self + { + $this->defaultErrorHandler = $handler; + return $this; + } + + /** + * Set callable to handle scenarios where an error + * occurs when processing the current request. + * + * The callable signature MUST match the ErrorHandlerInterface + * + * Pass true to $handleSubclasses to make the handler handle all subclasses of + * the type as well. Pass an array of classes to make the same function handle multiple exceptions. + * + * @param string|string[] $typeOrTypes Exception/Throwable name. + * ie: RuntimeException::class or an array of classes + * ie: [HttpNotFoundException::class, HttpMethodNotAllowedException::class] + * @param string|callable|ErrorHandlerInterface $handler + * + * @see ErrorHandlerInterface + * + * 1. Instance of \Psr\Http\Message\ServerRequestInterface + * 2. Instance of \Throwable + * 3. Boolean $displayErrorDetails + * 4. Boolean $logErrors + * 5. Boolean $logErrorDetails + * + * The callable MUST return an instance of + * \Psr\Http\Message\ResponseInterface. + * + */ + public function setErrorHandler($typeOrTypes, $handler, bool $handleSubclasses = false): self + { + if (is_array($typeOrTypes)) { + foreach ($typeOrTypes as $type) { + $this->addErrorHandler($type, $handler, $handleSubclasses); + } + } else { + $this->addErrorHandler($typeOrTypes, $handler, $handleSubclasses); + } + + return $this; + } + + /** + * Used internally to avoid code repetition when passing multiple exceptions to setErrorHandler(). + * @param string|callable|ErrorHandlerInterface $handler + */ + private function addErrorHandler(string $type, $handler, bool $handleSubclasses): void + { + if ($handleSubclasses) { + $this->subClassHandlers[$type] = $handler; + } else { + $this->handlers[$type] = $handler; + } + } +} diff --git a/api/vendor/slim/slim/Slim/Middleware/MethodOverrideMiddleware.php b/api/vendor/slim/slim/Slim/Middleware/MethodOverrideMiddleware.php new file mode 100644 index 0000000..61b1dcb --- /dev/null +++ b/api/vendor/slim/slim/Slim/Middleware/MethodOverrideMiddleware.php @@ -0,0 +1,44 @@ +getHeaderLine('X-Http-Method-Override'); + + if ($methodHeader) { + $request = $request->withMethod($methodHeader); + } elseif (strtoupper($request->getMethod()) === 'POST') { + $body = $request->getParsedBody(); + + if (is_array($body) && !empty($body['_METHOD']) && is_string($body['_METHOD'])) { + $request = $request->withMethod($body['_METHOD']); + } + + if ($request->getBody()->eof()) { + $request->getBody()->rewind(); + } + } + + return $handler->handle($request); + } +} diff --git a/api/vendor/slim/slim/Slim/Middleware/OutputBufferingMiddleware.php b/api/vendor/slim/slim/Slim/Middleware/OutputBufferingMiddleware.php new file mode 100644 index 0000000..8bfbbf6 --- /dev/null +++ b/api/vendor/slim/slim/Slim/Middleware/OutputBufferingMiddleware.php @@ -0,0 +1,75 @@ +streamFactory = $streamFactory; + $this->style = $style; + + if (!in_array($style, [static::APPEND, static::PREPEND], true)) { + throw new InvalidArgumentException("Invalid style `{$style}`. Must be `append` or `prepend`"); + } + } + + /** + * @throws Throwable + */ + public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface + { + try { + ob_start(); + $response = $handler->handle($request); + $output = ob_get_clean(); + } catch (Throwable $e) { + ob_end_clean(); + throw $e; + } + + if (!empty($output)) { + if ($this->style === static::PREPEND) { + $body = $this->streamFactory->createStream(); + $body->write($output . $response->getBody()); + $response = $response->withBody($body); + } elseif ($this->style === static::APPEND && $response->getBody()->isWritable()) { + $response->getBody()->write($output); + } + } + + return $response; + } +} diff --git a/api/vendor/slim/slim/Slim/Middleware/RoutingMiddleware.php b/api/vendor/slim/slim/Slim/Middleware/RoutingMiddleware.php new file mode 100644 index 0000000..a3d3085 --- /dev/null +++ b/api/vendor/slim/slim/Slim/Middleware/RoutingMiddleware.php @@ -0,0 +1,98 @@ +routeResolver = $routeResolver; + $this->routeParser = $routeParser; + } + + /** + * @throws HttpNotFoundException + * @throws HttpMethodNotAllowedException + * @throws RuntimeException + */ + public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface + { + $request = $this->performRouting($request); + return $handler->handle($request); + } + + /** + * Perform routing + * + * @param ServerRequestInterface $request PSR7 Server Request + * + * @throws HttpNotFoundException + * @throws HttpMethodNotAllowedException + * @throws RuntimeException + */ + public function performRouting(ServerRequestInterface $request): ServerRequestInterface + { + $request = $request->withAttribute(RouteContext::ROUTE_PARSER, $this->routeParser); + + $routingResults = $this->resolveRoutingResultsFromRequest($request); + $routeStatus = $routingResults->getRouteStatus(); + + $request = $request->withAttribute(RouteContext::ROUTING_RESULTS, $routingResults); + + switch ($routeStatus) { + case RoutingResults::FOUND: + $routeArguments = $routingResults->getRouteArguments(); + $routeIdentifier = $routingResults->getRouteIdentifier() ?? ''; + $route = $this->routeResolver + ->resolveRoute($routeIdentifier) + ->prepare($routeArguments); + return $request->withAttribute(RouteContext::ROUTE, $route); + + case RoutingResults::NOT_FOUND: + throw new HttpNotFoundException($request); + + case RoutingResults::METHOD_NOT_ALLOWED: + $exception = new HttpMethodNotAllowedException($request); + $exception->setAllowedMethods($routingResults->getAllowedMethods()); + throw $exception; + + default: + throw new RuntimeException('An unexpected error occurred while performing routing.'); + } + } + + /** + * Resolves the route from the given request + */ + protected function resolveRoutingResultsFromRequest(ServerRequestInterface $request): RoutingResults + { + return $this->routeResolver->computeRoutingResults( + $request->getUri()->getPath(), + $request->getMethod() + ); + } +} diff --git a/api/vendor/slim/slim/Slim/MiddlewareDispatcher.php b/api/vendor/slim/slim/Slim/MiddlewareDispatcher.php new file mode 100644 index 0000000..def9323 --- /dev/null +++ b/api/vendor/slim/slim/Slim/MiddlewareDispatcher.php @@ -0,0 +1,289 @@ +seedMiddlewareStack($kernel); + $this->callableResolver = $callableResolver; + $this->container = $container; + } + + /** + * {@inheritdoc} + */ + public function seedMiddlewareStack(RequestHandlerInterface $kernel): void + { + $this->tip = $kernel; + } + + /** + * Invoke the middleware stack + */ + public function handle(ServerRequestInterface $request): ResponseInterface + { + return $this->tip->handle($request); + } + + /** + * Add a new middleware to the stack + * + * Middleware are organized as a stack. That means middleware + * that have been added before will be executed after the newly + * added one (last in, first out). + * + * @param MiddlewareInterface|string|callable $middleware + */ + public function add($middleware): MiddlewareDispatcherInterface + { + if ($middleware instanceof MiddlewareInterface) { + return $this->addMiddleware($middleware); + } + + if (is_string($middleware)) { + return $this->addDeferred($middleware); + } + + if (is_callable($middleware)) { + return $this->addCallable($middleware); + } + + /** @phpstan-ignore-next-line */ + throw new RuntimeException( + 'A middleware must be an object/class name referencing an implementation of ' . + 'MiddlewareInterface or a callable with a matching signature.' + ); + } + + /** + * Add a new middleware to the stack + * + * Middleware are organized as a stack. That means middleware + * that have been added before will be executed after the newly + * added one (last in, first out). + */ + public function addMiddleware(MiddlewareInterface $middleware): MiddlewareDispatcherInterface + { + $next = $this->tip; + $this->tip = new class ($middleware, $next) implements RequestHandlerInterface { + private MiddlewareInterface $middleware; + + private RequestHandlerInterface $next; + + public function __construct(MiddlewareInterface $middleware, RequestHandlerInterface $next) + { + $this->middleware = $middleware; + $this->next = $next; + } + + public function handle(ServerRequestInterface $request): ResponseInterface + { + return $this->middleware->process($request, $this->next); + } + }; + + return $this; + } + + /** + * Add a new middleware by class name + * + * Middleware are organized as a stack. That means middleware + * that have been added before will be executed after the newly + * added one (last in, first out). + * @return MiddlewareDispatcher + */ + public function addDeferred(string $middleware): self + { + $next = $this->tip; + $this->tip = new class ( + $middleware, + $next, + $this->container, + $this->callableResolver + ) implements RequestHandlerInterface { + private string $middleware; + + private RequestHandlerInterface $next; + + private ?ContainerInterface $container; + + private ?CallableResolverInterface $callableResolver; + + public function __construct( + string $middleware, + RequestHandlerInterface $next, + ?ContainerInterface $container = null, + ?CallableResolverInterface $callableResolver = null + ) { + $this->middleware = $middleware; + $this->next = $next; + $this->container = $container; + $this->callableResolver = $callableResolver; + } + + public function handle(ServerRequestInterface $request): ResponseInterface + { + if ($this->callableResolver instanceof AdvancedCallableResolverInterface) { + $callable = $this->callableResolver->resolveMiddleware($this->middleware); + /** @var ResponseInterface */ + return $callable($request, $this->next); + } + + $callable = null; + + if ($this->callableResolver instanceof CallableResolverInterface) { + try { + $callable = $this->callableResolver->resolve($this->middleware); + } catch (RuntimeException $e) { + // Do Nothing + } + } + + if (!$callable) { + $resolved = $this->middleware; + $instance = null; + $method = null; + + /** @psalm-suppress ArgumentTypeCoercion */ + // Check for Slim callable as `class:method` + if (preg_match(CallableResolver::$callablePattern, $resolved, $matches)) { + $resolved = $matches[1]; + $method = $matches[2]; + } + + if ($this->container && $this->container->has($resolved)) { + $instance = $this->container->get($resolved); + if ($instance instanceof MiddlewareInterface) { + return $instance->process($request, $this->next); + } + } elseif (!function_exists($resolved)) { + if (!class_exists($resolved)) { + throw new RuntimeException(sprintf('Middleware %s does not exist', $resolved)); + } + $instance = new $resolved($this->container); + } + + if ($instance && $instance instanceof MiddlewareInterface) { + return $instance->process($request, $this->next); + } + + $callable = $instance ?? $resolved; + if ($instance && $method) { + $callable = [$instance, $method]; + } + + if ($this->container && $callable instanceof Closure) { + $callable = $callable->bindTo($this->container); + } + } + + if (!is_callable($callable)) { + throw new RuntimeException( + sprintf( + 'Middleware %s is not resolvable', + $this->middleware + ) + ); + } + + /** @var ResponseInterface */ + return $callable($request, $this->next); + } + }; + + return $this; + } + + /** + * Add a (non-standard) callable middleware to the stack + * + * Middleware are organized as a stack. That means middleware + * that have been added before will be executed after the newly + * added one (last in, first out). + * @return MiddlewareDispatcher + */ + public function addCallable(callable $middleware): self + { + $next = $this->tip; + + if ($this->container && $middleware instanceof Closure) { + /** @var Closure $middleware */ + $middleware = $middleware->bindTo($this->container); + } + + $this->tip = new class ($middleware, $next) implements RequestHandlerInterface { + /** + * @var callable + */ + private $middleware; + + /** + * @var RequestHandlerInterface + */ + private $next; + + public function __construct(callable $middleware, RequestHandlerInterface $next) + { + $this->middleware = $middleware; + $this->next = $next; + } + + public function handle(ServerRequestInterface $request): ResponseInterface + { + /** @var ResponseInterface */ + return ($this->middleware)($request, $this->next); + } + }; + + return $this; + } +} diff --git a/api/vendor/slim/slim/Slim/ResponseEmitter.php b/api/vendor/slim/slim/Slim/ResponseEmitter.php new file mode 100644 index 0000000..fac36e9 --- /dev/null +++ b/api/vendor/slim/slim/Slim/ResponseEmitter.php @@ -0,0 +1,136 @@ +responseChunkSize = $responseChunkSize; + } + + /** + * Send the response the client + */ + public function emit(ResponseInterface $response): void + { + $isEmpty = $this->isResponseEmpty($response); + if (headers_sent() === false) { + $this->emitHeaders($response); + + // Set the status _after_ the headers, because of PHP's "helpful" behavior with location headers. + // See https://github.com/slimphp/Slim/issues/1730 + + $this->emitStatusLine($response); + } + + if (!$isEmpty) { + $this->emitBody($response); + } + } + + /** + * Emit Response Headers + */ + private function emitHeaders(ResponseInterface $response): void + { + foreach ($response->getHeaders() as $name => $values) { + $first = strtolower($name) !== 'set-cookie'; + foreach ($values as $value) { + $header = sprintf('%s: %s', $name, $value); + header($header, $first); + $first = false; + } + } + } + + /** + * Emit Status Line + */ + private function emitStatusLine(ResponseInterface $response): void + { + $statusLine = sprintf( + 'HTTP/%s %s %s', + $response->getProtocolVersion(), + $response->getStatusCode(), + $response->getReasonPhrase() + ); + header($statusLine, true, $response->getStatusCode()); + } + + /** + * Emit Body + */ + private function emitBody(ResponseInterface $response): void + { + $body = $response->getBody(); + if ($body->isSeekable()) { + $body->rewind(); + } + + $amountToRead = (int) $response->getHeaderLine('Content-Length'); + if (!$amountToRead) { + $amountToRead = $body->getSize(); + } + + if ($amountToRead) { + while ($amountToRead > 0 && !$body->eof()) { + $length = min($this->responseChunkSize, $amountToRead); + $data = $body->read($length); + echo $data; + + $amountToRead -= strlen($data); + + if (connection_status() !== CONNECTION_NORMAL) { + break; + } + } + } else { + while (!$body->eof()) { + echo $body->read($this->responseChunkSize); + if (connection_status() !== CONNECTION_NORMAL) { + break; + } + } + } + } + + /** + * Asserts response body is empty or status code is 204, 205 or 304 + */ + public function isResponseEmpty(ResponseInterface $response): bool + { + if (in_array($response->getStatusCode(), [204, 205, 304], true)) { + return true; + } + $stream = $response->getBody(); + $seekable = $stream->isSeekable(); + if ($seekable) { + $stream->rewind(); + } + return $seekable ? $stream->read(1) === '' : $stream->eof(); + } +} diff --git a/api/vendor/slim/slim/Slim/Routing/Dispatcher.php b/api/vendor/slim/slim/Slim/Routing/Dispatcher.php new file mode 100644 index 0000000..e33eac3 --- /dev/null +++ b/api/vendor/slim/slim/Slim/Routing/Dispatcher.php @@ -0,0 +1,78 @@ +routeCollector = $routeCollector; + } + + protected function createDispatcher(): FastRouteDispatcher + { + if ($this->dispatcher) { + return $this->dispatcher; + } + + $routeDefinitionCallback = function (FastRouteCollector $r): void { + $basePath = $this->routeCollector->getBasePath(); + + foreach ($this->routeCollector->getRoutes() as $route) { + $r->addRoute($route->getMethods(), $basePath . $route->getPattern(), $route->getIdentifier()); + } + }; + + $cacheFile = $this->routeCollector->getCacheFile(); + if ($cacheFile) { + /** @var FastRouteDispatcher $dispatcher */ + $dispatcher = \FastRoute\cachedDispatcher($routeDefinitionCallback, [ + 'dataGenerator' => GroupCountBased::class, + 'dispatcher' => FastRouteDispatcher::class, + 'routeParser' => new Std(), + 'cacheFile' => $cacheFile, + ]); + } else { + /** @var FastRouteDispatcher $dispatcher */ + $dispatcher = \FastRoute\simpleDispatcher($routeDefinitionCallback, [ + 'dataGenerator' => GroupCountBased::class, + 'dispatcher' => FastRouteDispatcher::class, + 'routeParser' => new Std(), + ]); + } + + $this->dispatcher = $dispatcher; + return $this->dispatcher; + } + + /** + * {@inheritdoc} + */ + public function dispatch(string $method, string $uri): RoutingResults + { + $dispatcher = $this->createDispatcher(); + $results = $dispatcher->dispatch($method, $uri); + return new RoutingResults($this, $method, $uri, $results[0], $results[1], $results[2]); + } + + /** + * {@inheritdoc} + */ + public function getAllowedMethods(string $uri): array + { + $dispatcher = $this->createDispatcher(); + return $dispatcher->getAllowedMethods($uri); + } +} diff --git a/api/vendor/slim/slim/Slim/Routing/FastRouteDispatcher.php b/api/vendor/slim/slim/Slim/Routing/FastRouteDispatcher.php new file mode 100644 index 0000000..797746b --- /dev/null +++ b/api/vendor/slim/slim/Slim/Routing/FastRouteDispatcher.php @@ -0,0 +1,109 @@ +} + */ + public function dispatch($httpMethod, $uri): array + { + $routingResults = $this->routingResults($httpMethod, $uri); + if ($routingResults[0] === self::FOUND) { + return $routingResults; + } + + // For HEAD requests, attempt fallback to GET + if ($httpMethod === 'HEAD') { + $routingResults = $this->routingResults('GET', $uri); + if ($routingResults[0] === self::FOUND) { + return $routingResults; + } + } + + // If nothing else matches, try fallback routes + $routingResults = $this->routingResults('*', $uri); + if ($routingResults[0] === self::FOUND) { + return $routingResults; + } + + if (!empty($this->getAllowedMethods($uri))) { + return [self::METHOD_NOT_ALLOWED, null, []]; + } + + return [self::NOT_FOUND, null, []]; + } + + /** + * @param string $httpMethod + * @param string $uri + * + * @return array{int, string|null, array} + */ + private function routingResults(string $httpMethod, string $uri): array + { + if (isset($this->staticRouteMap[$httpMethod][$uri])) { + /** @var string $routeIdentifier */ + $routeIdentifier = $this->staticRouteMap[$httpMethod][$uri]; + return [self::FOUND, $routeIdentifier, []]; + } + + if (isset($this->variableRouteData[$httpMethod])) { + /** @var array{0: int, 1?: string, 2?: array} $result */ + $result = $this->dispatchVariableRoute($this->variableRouteData[$httpMethod], $uri); + if ($result[0] === self::FOUND) { + /** @var array{int, string, array} $result */ + return [self::FOUND, $result[1], $result[2]]; + } + } + + return [self::NOT_FOUND, null, []]; + } + + /** + * @param string $uri + * + * @return string[] + */ + public function getAllowedMethods(string $uri): array + { + if (isset($this->allowedMethods[$uri])) { + return $this->allowedMethods[$uri]; + } + + $allowedMethods = []; + foreach ($this->staticRouteMap as $method => $uriMap) { + if (isset($uriMap[$uri])) { + $allowedMethods[$method] = true; + } + } + + foreach ($this->variableRouteData as $method => $routeData) { + $result = $this->dispatchVariableRoute($routeData, $uri); + if ($result[0] === self::FOUND) { + $allowedMethods[$method] = true; + } + } + + return $this->allowedMethods[$uri] = array_keys($allowedMethods); + } +} diff --git a/api/vendor/slim/slim/Slim/Routing/Route.php b/api/vendor/slim/slim/Slim/Routing/Route.php new file mode 100644 index 0000000..b5caa09 --- /dev/null +++ b/api/vendor/slim/slim/Slim/Routing/Route.php @@ -0,0 +1,364 @@ + + */ + protected array $arguments = []; + + /** + * Route arguments parameters + * + * @var array + */ + protected array $savedArguments = []; + + /** + * Container + * @var TContainerInterface $container + */ + protected ?ContainerInterface $container = null; + + /** @var MiddlewareDispatcher $middlewareDispatcher */ + protected MiddlewareDispatcher $middlewareDispatcher; + + /** + * Route callable + * + * @var callable|array{class-string, string}|string + */ + protected $callable; + + protected CallableResolverInterface $callableResolver; + + protected ResponseFactoryInterface $responseFactory; + + /** + * Route pattern + */ + protected string $pattern; + + protected bool $groupMiddlewareAppended = false; + + /** + * @param string[] $methods The route HTTP methods + * @param string $pattern The route pattern + * @param callable|array{class-string, string}|string $callable The route callable + * @param ResponseFactoryInterface $responseFactory + * @param CallableResolverInterface $callableResolver + * @param TContainerInterface $container + * @param InvocationStrategyInterface|null $invocationStrategy + * @param RouteGroupInterface[] $groups The parent route groups + * @param int $identifier The route identifier + */ + public function __construct( + array $methods, + string $pattern, + $callable, + ResponseFactoryInterface $responseFactory, + CallableResolverInterface $callableResolver, + ?ContainerInterface $container = null, + ?InvocationStrategyInterface $invocationStrategy = null, + array $groups = [], + int $identifier = 0 + ) { + $this->methods = $methods; + $this->pattern = $pattern; + $this->callable = $callable; + $this->responseFactory = $responseFactory; + $this->callableResolver = $callableResolver; + $this->container = $container; + $this->invocationStrategy = $invocationStrategy ?? new RequestResponse(); + $this->groups = $groups; + $this->identifier = 'route' . $identifier; + $this->middlewareDispatcher = new MiddlewareDispatcher($this, $callableResolver, $container); + } + + public function getCallableResolver(): CallableResolverInterface + { + return $this->callableResolver; + } + + /** + * {@inheritdoc} + */ + public function getInvocationStrategy(): InvocationStrategyInterface + { + return $this->invocationStrategy; + } + + /** + * {@inheritdoc} + */ + public function setInvocationStrategy(InvocationStrategyInterface $invocationStrategy): RouteInterface + { + $this->invocationStrategy = $invocationStrategy; + return $this; + } + + /** + * {@inheritdoc} + */ + public function getMethods(): array + { + return $this->methods; + } + + /** + * {@inheritdoc} + */ + public function getPattern(): string + { + return $this->pattern; + } + + /** + * {@inheritdoc} + */ + public function setPattern(string $pattern): RouteInterface + { + $this->pattern = $pattern; + return $this; + } + + /** + * {@inheritdoc} + */ + public function getCallable() + { + return $this->callable; + } + + /** + * {@inheritdoc} + */ + public function setCallable($callable): RouteInterface + { + $this->callable = $callable; + return $this; + } + + /** + * {@inheritdoc} + */ + public function getName(): ?string + { + return $this->name; + } + + /** + * {@inheritdoc} + */ + public function setName(string $name): RouteInterface + { + $this->name = $name; + return $this; + } + + /** + * {@inheritdoc} + */ + public function getIdentifier(): string + { + return $this->identifier; + } + + /** + * {@inheritdoc} + */ + public function getArgument(string $name, ?string $default = null): ?string + { + if (array_key_exists($name, $this->arguments)) { + return $this->arguments[$name]; + } + return $default; + } + + /** + * {@inheritdoc} + */ + public function getArguments(): array + { + return $this->arguments; + } + + /** + * {@inheritdoc} + */ + public function setArguments(array $arguments, bool $includeInSavedArguments = true): RouteInterface + { + if ($includeInSavedArguments) { + $this->savedArguments = $arguments; + } + + $this->arguments = $arguments; + return $this; + } + + /** + * @return RouteGroupInterface[] + */ + public function getGroups(): array + { + return $this->groups; + } + + /** + * {@inheritdoc} + */ + public function add($middleware): RouteInterface + { + $this->middlewareDispatcher->add($middleware); + return $this; + } + + /** + * {@inheritdoc} + */ + public function addMiddleware(MiddlewareInterface $middleware): RouteInterface + { + $this->middlewareDispatcher->addMiddleware($middleware); + return $this; + } + + /** + * {@inheritdoc} + */ + public function prepare(array $arguments): RouteInterface + { + $this->arguments = array_replace($this->savedArguments, $arguments); + return $this; + } + + /** + * {@inheritdoc} + */ + public function setArgument(string $name, string $value, bool $includeInSavedArguments = true): RouteInterface + { + if ($includeInSavedArguments) { + $this->savedArguments[$name] = $value; + } + + $this->arguments[$name] = $value; + return $this; + } + + /** + * {@inheritdoc} + */ + public function run(ServerRequestInterface $request): ResponseInterface + { + if (!$this->groupMiddlewareAppended) { + $this->appendGroupMiddlewareToRoute(); + } + + return $this->middlewareDispatcher->handle($request); + } + + /** + * @return void + */ + protected function appendGroupMiddlewareToRoute(): void + { + $inner = $this->middlewareDispatcher; + $this->middlewareDispatcher = new MiddlewareDispatcher($inner, $this->callableResolver, $this->container); + + foreach (array_reverse($this->groups) as $group) { + $group->appendMiddlewareToDispatcher($this->middlewareDispatcher); + } + + $this->groupMiddlewareAppended = true; + } + + /** + * {@inheritdoc} + */ + public function handle(ServerRequestInterface $request): ResponseInterface + { + if ($this->callableResolver instanceof AdvancedCallableResolverInterface) { + $callable = $this->callableResolver->resolveRoute($this->callable); + } else { + $callable = $this->callableResolver->resolve($this->callable); + } + $strategy = $this->invocationStrategy; + + $strategyImplements = class_implements($strategy); + + if ( + is_array($callable) + && $callable[0] instanceof RequestHandlerInterface + && !in_array(RequestHandlerInvocationStrategyInterface::class, $strategyImplements) + ) { + $strategy = new RequestHandler(); + } + + $response = $this->responseFactory->createResponse(); + return $strategy($callable, $request, $response, $this->arguments); + } +} diff --git a/api/vendor/slim/slim/Slim/Routing/RouteCollector.php b/api/vendor/slim/slim/Slim/Routing/RouteCollector.php new file mode 100644 index 0000000..07d85cf --- /dev/null +++ b/api/vendor/slim/slim/Slim/Routing/RouteCollector.php @@ -0,0 +1,302 @@ +responseFactory = $responseFactory; + $this->callableResolver = $callableResolver; + $this->container = $container; + $this->defaultInvocationStrategy = $defaultInvocationStrategy ?? new RequestResponse(); + $this->routeParser = $routeParser ?? new RouteParser($this); + + if ($cacheFile) { + $this->setCacheFile($cacheFile); + } + } + + public function getRouteParser(): RouteParserInterface + { + return $this->routeParser; + } + + /** + * Get default route invocation strategy + */ + public function getDefaultInvocationStrategy(): InvocationStrategyInterface + { + return $this->defaultInvocationStrategy; + } + + public function setDefaultInvocationStrategy(InvocationStrategyInterface $strategy): RouteCollectorInterface + { + $this->defaultInvocationStrategy = $strategy; + return $this; + } + + /** + * {@inheritdoc} + */ + public function getCacheFile(): ?string + { + return $this->cacheFile; + } + + /** + * {@inheritdoc} + */ + public function setCacheFile(string $cacheFile): RouteCollectorInterface + { + if (file_exists($cacheFile) && !is_readable($cacheFile)) { + throw new RuntimeException( + sprintf('Route collector cache file `%s` is not readable', $cacheFile) + ); + } + + if (!file_exists($cacheFile) && !is_writable(dirname($cacheFile))) { + throw new RuntimeException( + sprintf('Route collector cache file directory `%s` is not writable', dirname($cacheFile)) + ); + } + + $this->cacheFile = $cacheFile; + return $this; + } + + /** + * {@inheritdoc} + */ + public function getBasePath(): string + { + return $this->basePath; + } + + /** + * Set the base path used in urlFor() + */ + public function setBasePath(string $basePath): RouteCollectorInterface + { + $this->basePath = $basePath; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getRoutes(): array + { + return $this->routes; + } + + /** + * {@inheritdoc} + */ + public function removeNamedRoute(string $name): RouteCollectorInterface + { + $route = $this->getNamedRoute($name); + + /** @psalm-suppress PossiblyNullArrayOffset */ + unset($this->routesByName[$route->getName()], $this->routes[$route->getIdentifier()]); + return $this; + } + + /** + * {@inheritdoc} + */ + public function getNamedRoute(string $name): RouteInterface + { + if (isset($this->routesByName[$name])) { + $route = $this->routesByName[$name]; + if ($route->getName() === $name) { + return $route; + } + + unset($this->routesByName[$name]); + } + + foreach ($this->routes as $route) { + if ($name === $route->getName()) { + $this->routesByName[$name] = $route; + return $route; + } + } + + throw new RuntimeException('Named route does not exist for name: ' . $name); + } + + /** + * {@inheritdoc} + */ + public function lookupRoute(string $identifier): RouteInterface + { + if (!isset($this->routes[$identifier])) { + throw new RuntimeException('Route not found, looks like your route cache is stale.'); + } + return $this->routes[$identifier]; + } + + /** + * {@inheritdoc} + */ + public function group(string $pattern, $callable): RouteGroupInterface + { + $routeGroup = $this->createGroup($pattern, $callable); + $this->routeGroups[] = $routeGroup; + + $routeGroup->collectRoutes(); + array_pop($this->routeGroups); + + return $routeGroup; + } + + /** + * @param string|callable $callable + */ + protected function createGroup(string $pattern, $callable): RouteGroupInterface + { + $routeCollectorProxy = $this->createProxy($pattern); + return new RouteGroup($pattern, $callable, $this->callableResolver, $routeCollectorProxy); + } + + /** + * @return RouteCollectorProxyInterface + */ + protected function createProxy(string $pattern): RouteCollectorProxyInterface + { + /** @var RouteCollectorProxy */ + return new RouteCollectorProxy( + $this->responseFactory, + $this->callableResolver, + $this->container, + $this, + $pattern + ); + } + + /** + * {@inheritdoc} + */ + public function map(array $methods, string $pattern, $handler): RouteInterface + { + $route = $this->createRoute($methods, $pattern, $handler); + $this->routes[$route->getIdentifier()] = $route; + + $routeName = $route->getName(); + if ($routeName !== null && !isset($this->routesByName[$routeName])) { + $this->routesByName[$routeName] = $route; + } + + $this->routeCounter++; + + return $route; + } + + /** + * @param string[] $methods + * @param callable|array{class-string, string}|string $callable + */ + protected function createRoute(array $methods, string $pattern, $callable): RouteInterface + { + return new Route( + $methods, + $pattern, + $callable, + $this->responseFactory, + $this->callableResolver, + $this->container, + $this->defaultInvocationStrategy, + $this->routeGroups, + $this->routeCounter + ); + } +} diff --git a/api/vendor/slim/slim/Slim/Routing/RouteCollectorProxy.php b/api/vendor/slim/slim/Slim/Routing/RouteCollectorProxy.php new file mode 100644 index 0000000..a946d14 --- /dev/null +++ b/api/vendor/slim/slim/Slim/Routing/RouteCollectorProxy.php @@ -0,0 +1,196 @@ + + */ +class RouteCollectorProxy implements RouteCollectorProxyInterface +{ + protected ResponseFactoryInterface $responseFactory; + + protected CallableResolverInterface $callableResolver; + + /** @var TContainerInterface */ + protected ?ContainerInterface $container = null; + + protected RouteCollectorInterface $routeCollector; + + protected string $groupPattern; + + /** + * @param TContainerInterface $container + */ + public function __construct( + ResponseFactoryInterface $responseFactory, + CallableResolverInterface $callableResolver, + ?ContainerInterface $container = null, + ?RouteCollectorInterface $routeCollector = null, + string $groupPattern = '' + ) { + $this->responseFactory = $responseFactory; + $this->callableResolver = $callableResolver; + $this->container = $container; + $this->routeCollector = $routeCollector ?? new RouteCollector($responseFactory, $callableResolver, $container); + $this->groupPattern = $groupPattern; + } + + /** + * {@inheritdoc} + */ + public function getResponseFactory(): ResponseFactoryInterface + { + return $this->responseFactory; + } + + /** + * {@inheritdoc} + */ + public function getCallableResolver(): CallableResolverInterface + { + return $this->callableResolver; + } + + /** + * {@inheritdoc} + * @return TContainerInterface + */ + public function getContainer(): ?ContainerInterface + { + return $this->container; + } + + /** + * {@inheritdoc} + */ + public function getRouteCollector(): RouteCollectorInterface + { + return $this->routeCollector; + } + + /** + * {@inheritdoc} + */ + public function getBasePath(): string + { + return $this->routeCollector->getBasePath(); + } + + /** + * {@inheritdoc} + */ + public function setBasePath(string $basePath): RouteCollectorProxyInterface + { + $this->routeCollector->setBasePath($basePath); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function get(string $pattern, $callable): RouteInterface + { + return $this->map(['GET'], $pattern, $callable); + } + + /** + * {@inheritdoc} + */ + public function post(string $pattern, $callable): RouteInterface + { + return $this->map(['POST'], $pattern, $callable); + } + + /** + * {@inheritdoc} + */ + public function put(string $pattern, $callable): RouteInterface + { + return $this->map(['PUT'], $pattern, $callable); + } + + /** + * {@inheritdoc} + */ + public function patch(string $pattern, $callable): RouteInterface + { + return $this->map(['PATCH'], $pattern, $callable); + } + + /** + * {@inheritdoc} + */ + public function delete(string $pattern, $callable): RouteInterface + { + return $this->map(['DELETE'], $pattern, $callable); + } + + /** + * {@inheritdoc} + */ + public function options(string $pattern, $callable): RouteInterface + { + return $this->map(['OPTIONS'], $pattern, $callable); + } + + /** + * {@inheritdoc} + */ + public function any(string $pattern, $callable): RouteInterface + { + return $this->map(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'], $pattern, $callable); + } + + /** + * {@inheritdoc} + */ + public function map(array $methods, string $pattern, $callable): RouteInterface + { + $pattern = $this->groupPattern . $pattern; + + return $this->routeCollector->map($methods, $pattern, $callable); + } + + /** + * {@inheritdoc} + */ + public function group(string $pattern, $callable): RouteGroupInterface + { + $pattern = $this->groupPattern . $pattern; + + return $this->routeCollector->group($pattern, $callable); + } + + /** + * {@inheritdoc} + */ + public function redirect(string $from, $to, int $status = 302): RouteInterface + { + $responseFactory = $this->responseFactory; + + $handler = function () use ($to, $status, $responseFactory) { + $response = $responseFactory->createResponse($status); + return $response->withHeader('Location', (string) $to); + }; + + return $this->get($from, $handler); + } +} diff --git a/api/vendor/slim/slim/Slim/Routing/RouteContext.php b/api/vendor/slim/slim/Slim/Routing/RouteContext.php new file mode 100644 index 0000000..853b0df --- /dev/null +++ b/api/vendor/slim/slim/Slim/Routing/RouteContext.php @@ -0,0 +1,89 @@ +getAttribute(self::ROUTE); + $routeParser = $serverRequest->getAttribute(self::ROUTE_PARSER); + $routingResults = $serverRequest->getAttribute(self::ROUTING_RESULTS); + $basePath = $serverRequest->getAttribute(self::BASE_PATH); + + if ($routeParser === null || $routingResults === null) { + throw new RuntimeException('Cannot create RouteContext before routing has been completed'); + } + + /** @var RouteInterface|null $route */ + /** @var RouteParserInterface $routeParser */ + /** @var RoutingResults $routingResults */ + /** @var string|null $basePath */ + return new self($route, $routeParser, $routingResults, $basePath); + } + + private ?RouteInterface $route; + + private RouteParserInterface $routeParser; + + private RoutingResults $routingResults; + + private ?string $basePath; + + private function __construct( + ?RouteInterface $route, + RouteParserInterface $routeParser, + RoutingResults $routingResults, + ?string $basePath = null + ) { + $this->route = $route; + $this->routeParser = $routeParser; + $this->routingResults = $routingResults; + $this->basePath = $basePath; + } + + public function getRoute(): ?RouteInterface + { + return $this->route; + } + + public function getRouteParser(): RouteParserInterface + { + return $this->routeParser; + } + + public function getRoutingResults(): RoutingResults + { + return $this->routingResults; + } + + public function getBasePath(): string + { + if ($this->basePath === null) { + throw new RuntimeException('No base path defined.'); + } + return $this->basePath; + } +} diff --git a/api/vendor/slim/slim/Slim/Routing/RouteGroup.php b/api/vendor/slim/slim/Slim/Routing/RouteGroup.php new file mode 100644 index 0000000..60d3df3 --- /dev/null +++ b/api/vendor/slim/slim/Slim/Routing/RouteGroup.php @@ -0,0 +1,109 @@ + + */ + protected RouteCollectorProxyInterface $routeCollectorProxy; + + /** + * @var MiddlewareInterface[]|string[]|callable[] + */ + protected array $middleware = []; + + protected string $pattern; + + /** + * @param callable|string $callable + * @param RouteCollectorProxyInterface<\Psr\Container\ContainerInterface|null> $routeCollectorProxy + */ + public function __construct( + string $pattern, + $callable, + CallableResolverInterface $callableResolver, + RouteCollectorProxyInterface $routeCollectorProxy + ) { + $this->pattern = $pattern; + $this->callable = $callable; + $this->callableResolver = $callableResolver; + $this->routeCollectorProxy = $routeCollectorProxy; + } + + /** + * {@inheritdoc} + */ + public function collectRoutes(): RouteGroupInterface + { + if ($this->callableResolver instanceof AdvancedCallableResolverInterface) { + $callable = $this->callableResolver->resolveRoute($this->callable); + } else { + $callable = $this->callableResolver->resolve($this->callable); + } + $callable($this->routeCollectorProxy); + return $this; + } + + /** + * {@inheritdoc} + */ + public function add($middleware): RouteGroupInterface + { + $this->middleware[] = $middleware; + return $this; + } + + /** + * {@inheritdoc} + */ + public function addMiddleware(MiddlewareInterface $middleware): RouteGroupInterface + { + $this->middleware[] = $middleware; + return $this; + } + + /** + * {@inheritdoc} + * @param MiddlewareDispatcher<\Psr\Container\ContainerInterface|null> $dispatcher + */ + public function appendMiddlewareToDispatcher(MiddlewareDispatcher $dispatcher): RouteGroupInterface + { + foreach ($this->middleware as $middleware) { + $dispatcher->add($middleware); + } + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getPattern(): string + { + return $this->pattern; + } +} diff --git a/api/vendor/slim/slim/Slim/Routing/RouteParser.php b/api/vendor/slim/slim/Slim/Routing/RouteParser.php new file mode 100644 index 0000000..afb533c --- /dev/null +++ b/api/vendor/slim/slim/Slim/Routing/RouteParser.php @@ -0,0 +1,127 @@ +routeCollector = $routeCollector; + $this->routeParser = new Std(); + } + + /** + * {@inheritdoc} + */ + public function relativeUrlFor(string $routeName, array $data = [], array $queryParams = []): string + { + $route = $this->routeCollector->getNamedRoute($routeName); + $pattern = $route->getPattern(); + + $segments = []; + $segmentName = ''; + + /* + * $routes is an associative array of expressions representing a route as multiple segments + * There is an expression for each optional parameter plus one without the optional parameters + * The most specific is last, hence why we reverse the array before iterating over it + */ + $expressions = array_reverse($this->routeParser->parse($pattern)); + foreach ($expressions as $expression) { + foreach ($expression as $segment) { + /* + * Each $segment is either a string or an array of strings + * containing optional parameters of an expression + */ + if (is_string($segment)) { + $segments[] = $segment; + continue; + } + + /** @var string[] $segment */ + /* + * If we don't have a data element for this segment in the provided $data + * we cancel testing to move onto the next expression with a less specific item + */ + if (!array_key_exists($segment[0], $data)) { + $segments = []; + $segmentName = $segment[0]; + break; + } + + $segments[] = $data[$segment[0]]; + } + + /* + * If we get to this logic block we have found all the parameters + * for the provided $data which means we don't need to continue testing + * less specific expressions + */ + if (!empty($segments)) { + break; + } + } + + if (empty($segments)) { + throw new InvalidArgumentException('Missing data for URL segment: ' . $segmentName); + } + + $url = implode('', $segments); + if ($queryParams) { + $url .= '?' . http_build_query($queryParams); + } + + return $url; + } + + /** + * {@inheritdoc} + */ + public function urlFor(string $routeName, array $data = [], array $queryParams = []): string + { + $basePath = $this->routeCollector->getBasePath(); + $url = $this->relativeUrlFor($routeName, $data, $queryParams); + + if ($basePath) { + $url = $basePath . $url; + } + + return $url; + } + + /** + * {@inheritdoc} + */ + public function fullUrlFor(UriInterface $uri, string $routeName, array $data = [], array $queryParams = []): string + { + $path = $this->urlFor($routeName, $data, $queryParams); + $scheme = $uri->getScheme(); + $authority = $uri->getAuthority(); + $protocol = ($scheme ? $scheme . ':' : '') . ($authority ? '//' . $authority : ''); + return $protocol . $path; + } +} diff --git a/api/vendor/slim/slim/Slim/Routing/RouteResolver.php b/api/vendor/slim/slim/Slim/Routing/RouteResolver.php new file mode 100644 index 0000000..d4f4eaf --- /dev/null +++ b/api/vendor/slim/slim/Slim/Routing/RouteResolver.php @@ -0,0 +1,56 @@ +routeCollector = $routeCollector; + $this->dispatcher = $dispatcher ?? new Dispatcher($routeCollector); + } + + /** + * @param string $uri Should be $request->getUri()->getPath() + */ + public function computeRoutingResults(string $uri, string $method): RoutingResults + { + $uri = rawurldecode($uri); + if ($uri === '' || $uri[0] !== '/') { + $uri = '/' . $uri; + } + return $this->dispatcher->dispatch($method, $uri); + } + + /** + * @throws RuntimeException + */ + public function resolveRoute(string $identifier): RouteInterface + { + return $this->routeCollector->lookupRoute($identifier); + } +} diff --git a/api/vendor/slim/slim/Slim/Routing/RouteRunner.php b/api/vendor/slim/slim/Slim/Routing/RouteRunner.php new file mode 100644 index 0000000..3fb5413 --- /dev/null +++ b/api/vendor/slim/slim/Slim/Routing/RouteRunner.php @@ -0,0 +1,76 @@ + + */ + private ?RouteCollectorProxyInterface $routeCollectorProxy; + + /** + * @param RouteCollectorProxyInterface<\Psr\Container\ContainerInterface|null> $routeCollectorProxy + */ + public function __construct( + RouteResolverInterface $routeResolver, + RouteParserInterface $routeParser, + ?RouteCollectorProxyInterface $routeCollectorProxy = null + ) { + $this->routeResolver = $routeResolver; + $this->routeParser = $routeParser; + $this->routeCollectorProxy = $routeCollectorProxy; + } + + /** + * This request handler is instantiated automatically in App::__construct() + * It is at the very tip of the middleware queue meaning it will be executed + * last and it detects whether or not routing has been performed in the user + * defined middleware stack. In the event that the user did not perform routing + * it is done here + * + * @throws HttpNotFoundException + * @throws HttpMethodNotAllowedException + */ + public function handle(ServerRequestInterface $request): ResponseInterface + { + // If routing hasn't been done, then do it now so we can dispatch + if ($request->getAttribute(RouteContext::ROUTING_RESULTS) === null) { + $routingMiddleware = new RoutingMiddleware($this->routeResolver, $this->routeParser); + $request = $routingMiddleware->performRouting($request); + } + + if ($this->routeCollectorProxy !== null) { + $request = $request->withAttribute( + RouteContext::BASE_PATH, + $this->routeCollectorProxy->getBasePath() + ); + } + + /** @var Route<\Psr\Container\ContainerInterface|null> $route */ + $route = $request->getAttribute(RouteContext::ROUTE); + return $route->run($request); + } +} diff --git a/api/vendor/slim/slim/Slim/Routing/RoutingResults.php b/api/vendor/slim/slim/Slim/Routing/RoutingResults.php new file mode 100644 index 0000000..4fd8973 --- /dev/null +++ b/api/vendor/slim/slim/Slim/Routing/RoutingResults.php @@ -0,0 +1,113 @@ + + */ + protected array $routeArguments; + + /** + * @param array $routeArguments + */ + public function __construct( + DispatcherInterface $dispatcher, + string $method, + string $uri, + int $routeStatus, + ?string $routeIdentifier = null, + array $routeArguments = [] + ) { + $this->dispatcher = $dispatcher; + $this->method = $method; + $this->uri = $uri; + $this->routeStatus = $routeStatus; + $this->routeIdentifier = $routeIdentifier; + $this->routeArguments = $routeArguments; + } + + public function getDispatcher(): DispatcherInterface + { + return $this->dispatcher; + } + + public function getMethod(): string + { + return $this->method; + } + + public function getUri(): string + { + return $this->uri; + } + + public function getRouteStatus(): int + { + return $this->routeStatus; + } + + public function getRouteIdentifier(): ?string + { + return $this->routeIdentifier; + } + + /** + * @return array + */ + public function getRouteArguments(bool $urlDecode = true): array + { + if (!$urlDecode) { + return $this->routeArguments; + } + + $routeArguments = []; + foreach ($this->routeArguments as $key => $value) { + $routeArguments[$key] = rawurldecode($value); + } + + return $routeArguments; + } + + /** + * @return string[] + */ + public function getAllowedMethods(): array + { + return $this->dispatcher->getAllowedMethods($this->uri); + } +} diff --git a/api/vendor/slim/slim/composer.json b/api/vendor/slim/slim/composer.json new file mode 100644 index 0000000..6ff4d8b --- /dev/null +++ b/api/vendor/slim/slim/composer.json @@ -0,0 +1,105 @@ +{ + "name": "slim/slim", + "type": "library", + "description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs", + "keywords": ["framework","micro","api","router"], + "homepage": "https://www.slimframework.com", + "license": "MIT", + "authors": [ + { + "name": "Josh Lockhart", + "email": "hello@joshlockhart.com", + "homepage": "https://joshlockhart.com" + }, + { + "name": "Andrew Smith", + "email": "a.smith@silentworks.co.uk", + "homepage": "https://silentworks.co.uk" + }, + { + "name": "Rob Allen", + "email": "rob@akrabat.com", + "homepage": "https://akrabat.com" + }, + { + "name": "Pierre Berube", + "email": "pierre@lgse.com", + "homepage": "https://www.lgse.com" + }, + { + "name": "Gabriel Manricks", + "email": "gmanricks@me.com", + "homepage": "http://gabrielmanricks.com" + } + ], + "support": { + "docs": "https://www.slimframework.com/docs/v4/", + "forum": "https://discourse.slimframework.com/", + "irc": "irc://irc.freenode.net:6667/slimphp", + "issues": "https://github.com/slimphp/Slim/issues", + "rss": "https://www.slimframework.com/blog/feed.rss", + "slack": "https://slimphp.slack.com/", + "source": "https://github.com/slimphp/Slim", + "wiki": "https://github.com/slimphp/Slim/wiki" + }, + "require": { + "php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", + "ext-json": "*", + "nikic/fast-route": "^1.3", + "psr/container": "^1.0 || ^2.0", + "psr/http-factory": "^1.1", + "psr/http-message": "^1.1 || ^2.0", + "psr/http-server-handler": "^1.0", + "psr/http-server-middleware": "^1.0", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "require-dev": { + "ext-simplexml": "*", + "adriansuter/php-autoload-override": "^1.4 || ^2", + "guzzlehttp/psr7": "^2.6", + "httpsoft/http-message": "^1.1", + "httpsoft/http-server-request": "^1.1", + "laminas/laminas-diactoros": "^2.17 || ^3", + "nyholm/psr7": "^1.8", + "nyholm/psr7-server": "^1.1", + "phpspec/prophecy": "^1.19", + "phpspec/prophecy-phpunit": "^2.1", + "phpstan/phpstan": "^1 || ^2", + "phpunit/phpunit": "^9.6", + "slim/http": "^1.3", + "slim/psr7": "^1.6", + "squizlabs/php_codesniffer": "^3.10", + "vimeo/psalm": "^5 || ^6" + }, + "autoload": { + "psr-4": { + "Slim\\": "Slim" + } + }, + "autoload-dev": { + "psr-4": { + "Slim\\Tests\\": "tests" + } + }, + "scripts": { + "test": [ + "@phpunit", + "@phpcs", + "@phpstan", + "@psalm" + ], + "phpunit": "phpunit", + "phpcs": "phpcs", + "phpstan": "phpstan --memory-limit=-1", + "psalm": "psalm --no-cache" + }, + "suggest": { + "ext-simplexml": "Needed to support XML format in BodyParsingMiddleware", + "ext-xml": "Needed to support XML format in BodyParsingMiddleware", + "slim/psr7": "Slim PSR-7 implementation. See https://www.slimframework.com/docs/v4/start/installation.html for more information.", + "php-di/php-di": "PHP-DI is the recommended container library to be used with Slim" + }, + "config": { + "sort-packages": true + } +} diff --git a/api/vendor/slim/slim/psalm.xml b/api/vendor/slim/slim/psalm.xml new file mode 100644 index 0000000..af258ff --- /dev/null +++ b/api/vendor/slim/slim/psalm.xml @@ -0,0 +1,17 @@ + + + + + + + + + diff --git a/api/vendor/symfony/polyfill-ctype/Ctype.php b/api/vendor/symfony/polyfill-ctype/Ctype.php new file mode 100644 index 0000000..ba75a2c --- /dev/null +++ b/api/vendor/symfony/polyfill-ctype/Ctype.php @@ -0,0 +1,232 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Ctype; + +/** + * Ctype implementation through regex. + * + * @internal + * + * @author Gert de Pagter + */ +final class Ctype +{ + /** + * Returns TRUE if every character in text is either a letter or a digit, FALSE otherwise. + * + * @see https://php.net/ctype-alnum + * + * @param mixed $text + * + * @return bool + */ + public static function ctype_alnum($text) + { + $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); + + return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z0-9]/', $text); + } + + /** + * Returns TRUE if every character in text is a letter, FALSE otherwise. + * + * @see https://php.net/ctype-alpha + * + * @param mixed $text + * + * @return bool + */ + public static function ctype_alpha($text) + { + $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); + + return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z]/', $text); + } + + /** + * Returns TRUE if every character in text is a control character from the current locale, FALSE otherwise. + * + * @see https://php.net/ctype-cntrl + * + * @param mixed $text + * + * @return bool + */ + public static function ctype_cntrl($text) + { + $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); + + return \is_string($text) && '' !== $text && !preg_match('/[^\x00-\x1f\x7f]/', $text); + } + + /** + * Returns TRUE if every character in the string text is a decimal digit, FALSE otherwise. + * + * @see https://php.net/ctype-digit + * + * @param mixed $text + * + * @return bool + */ + public static function ctype_digit($text) + { + $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); + + return \is_string($text) && '' !== $text && !preg_match('/[^0-9]/', $text); + } + + /** + * Returns TRUE if every character in text is printable and actually creates visible output (no white space), FALSE otherwise. + * + * @see https://php.net/ctype-graph + * + * @param mixed $text + * + * @return bool + */ + public static function ctype_graph($text) + { + $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); + + return \is_string($text) && '' !== $text && !preg_match('/[^!-~]/', $text); + } + + /** + * Returns TRUE if every character in text is a lowercase letter. + * + * @see https://php.net/ctype-lower + * + * @param mixed $text + * + * @return bool + */ + public static function ctype_lower($text) + { + $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); + + return \is_string($text) && '' !== $text && !preg_match('/[^a-z]/', $text); + } + + /** + * Returns TRUE if every character in text will actually create output (including blanks). Returns FALSE if text contains control characters or characters that do not have any output or control function at all. + * + * @see https://php.net/ctype-print + * + * @param mixed $text + * + * @return bool + */ + public static function ctype_print($text) + { + $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); + + return \is_string($text) && '' !== $text && !preg_match('/[^ -~]/', $text); + } + + /** + * Returns TRUE if every character in text is printable, but neither letter, digit or blank, FALSE otherwise. + * + * @see https://php.net/ctype-punct + * + * @param mixed $text + * + * @return bool + */ + public static function ctype_punct($text) + { + $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); + + return \is_string($text) && '' !== $text && !preg_match('/[^!-\/\:-@\[-`\{-~]/', $text); + } + + /** + * Returns TRUE if every character in text creates some sort of white space, FALSE otherwise. Besides the blank character this also includes tab, vertical tab, line feed, carriage return and form feed characters. + * + * @see https://php.net/ctype-space + * + * @param mixed $text + * + * @return bool + */ + public static function ctype_space($text) + { + $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); + + return \is_string($text) && '' !== $text && !preg_match('/[^\s]/', $text); + } + + /** + * Returns TRUE if every character in text is an uppercase letter. + * + * @see https://php.net/ctype-upper + * + * @param mixed $text + * + * @return bool + */ + public static function ctype_upper($text) + { + $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); + + return \is_string($text) && '' !== $text && !preg_match('/[^A-Z]/', $text); + } + + /** + * Returns TRUE if every character in text is a hexadecimal 'digit', that is a decimal digit or a character from [A-Fa-f] , FALSE otherwise. + * + * @see https://php.net/ctype-xdigit + * + * @param mixed $text + * + * @return bool + */ + public static function ctype_xdigit($text) + { + $text = self::convert_int_to_char_for_ctype($text, __FUNCTION__); + + return \is_string($text) && '' !== $text && !preg_match('/[^A-Fa-f0-9]/', $text); + } + + /** + * Converts integers to their char versions according to normal ctype behaviour, if needed. + * + * If an integer between -128 and 255 inclusive is provided, + * it is interpreted as the ASCII value of a single character + * (negative values have 256 added in order to allow characters in the Extended ASCII range). + * Any other integer is interpreted as a string containing the decimal digits of the integer. + * + * @param mixed $int + * @param string $function + * + * @return mixed + */ + private static function convert_int_to_char_for_ctype($int, $function) + { + if (!\is_int($int)) { + return $int; + } + + if ($int < -128 || $int > 255) { + return (string) $int; + } + + if (\PHP_VERSION_ID >= 80100) { + @trigger_error($function.'(): Argument of type int will be interpreted as string in the future', \E_USER_DEPRECATED); + } + + if ($int < 0) { + $int += 256; + } + + return \chr($int); + } +} diff --git a/api/vendor/symfony/polyfill-ctype/LICENSE b/api/vendor/symfony/polyfill-ctype/LICENSE new file mode 100644 index 0000000..7536cae --- /dev/null +++ b/api/vendor/symfony/polyfill-ctype/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2018-present Fabien Potencier + +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. diff --git a/api/vendor/symfony/polyfill-ctype/README.md b/api/vendor/symfony/polyfill-ctype/README.md new file mode 100644 index 0000000..b144d03 --- /dev/null +++ b/api/vendor/symfony/polyfill-ctype/README.md @@ -0,0 +1,12 @@ +Symfony Polyfill / Ctype +======================== + +This component provides `ctype_*` functions to users who run php versions without the ctype extension. + +More information can be found in the +[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md). + +License +======= + +This library is released under the [MIT license](LICENSE). diff --git a/api/vendor/symfony/polyfill-ctype/bootstrap.php b/api/vendor/symfony/polyfill-ctype/bootstrap.php new file mode 100644 index 0000000..d54524b --- /dev/null +++ b/api/vendor/symfony/polyfill-ctype/bootstrap.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Ctype as p; + +if (\PHP_VERSION_ID >= 80000) { + return require __DIR__.'/bootstrap80.php'; +} + +if (!function_exists('ctype_alnum')) { + function ctype_alnum($text) { return p\Ctype::ctype_alnum($text); } +} +if (!function_exists('ctype_alpha')) { + function ctype_alpha($text) { return p\Ctype::ctype_alpha($text); } +} +if (!function_exists('ctype_cntrl')) { + function ctype_cntrl($text) { return p\Ctype::ctype_cntrl($text); } +} +if (!function_exists('ctype_digit')) { + function ctype_digit($text) { return p\Ctype::ctype_digit($text); } +} +if (!function_exists('ctype_graph')) { + function ctype_graph($text) { return p\Ctype::ctype_graph($text); } +} +if (!function_exists('ctype_lower')) { + function ctype_lower($text) { return p\Ctype::ctype_lower($text); } +} +if (!function_exists('ctype_print')) { + function ctype_print($text) { return p\Ctype::ctype_print($text); } +} +if (!function_exists('ctype_punct')) { + function ctype_punct($text) { return p\Ctype::ctype_punct($text); } +} +if (!function_exists('ctype_space')) { + function ctype_space($text) { return p\Ctype::ctype_space($text); } +} +if (!function_exists('ctype_upper')) { + function ctype_upper($text) { return p\Ctype::ctype_upper($text); } +} +if (!function_exists('ctype_xdigit')) { + function ctype_xdigit($text) { return p\Ctype::ctype_xdigit($text); } +} diff --git a/api/vendor/symfony/polyfill-ctype/bootstrap80.php b/api/vendor/symfony/polyfill-ctype/bootstrap80.php new file mode 100644 index 0000000..ab2f861 --- /dev/null +++ b/api/vendor/symfony/polyfill-ctype/bootstrap80.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Ctype as p; + +if (!function_exists('ctype_alnum')) { + function ctype_alnum(mixed $text): bool { return p\Ctype::ctype_alnum($text); } +} +if (!function_exists('ctype_alpha')) { + function ctype_alpha(mixed $text): bool { return p\Ctype::ctype_alpha($text); } +} +if (!function_exists('ctype_cntrl')) { + function ctype_cntrl(mixed $text): bool { return p\Ctype::ctype_cntrl($text); } +} +if (!function_exists('ctype_digit')) { + function ctype_digit(mixed $text): bool { return p\Ctype::ctype_digit($text); } +} +if (!function_exists('ctype_graph')) { + function ctype_graph(mixed $text): bool { return p\Ctype::ctype_graph($text); } +} +if (!function_exists('ctype_lower')) { + function ctype_lower(mixed $text): bool { return p\Ctype::ctype_lower($text); } +} +if (!function_exists('ctype_print')) { + function ctype_print(mixed $text): bool { return p\Ctype::ctype_print($text); } +} +if (!function_exists('ctype_punct')) { + function ctype_punct(mixed $text): bool { return p\Ctype::ctype_punct($text); } +} +if (!function_exists('ctype_space')) { + function ctype_space(mixed $text): bool { return p\Ctype::ctype_space($text); } +} +if (!function_exists('ctype_upper')) { + function ctype_upper(mixed $text): bool { return p\Ctype::ctype_upper($text); } +} +if (!function_exists('ctype_xdigit')) { + function ctype_xdigit(mixed $text): bool { return p\Ctype::ctype_xdigit($text); } +} diff --git a/api/vendor/symfony/polyfill-ctype/composer.json b/api/vendor/symfony/polyfill-ctype/composer.json new file mode 100644 index 0000000..131ca7a --- /dev/null +++ b/api/vendor/symfony/polyfill-ctype/composer.json @@ -0,0 +1,38 @@ +{ + "name": "symfony/polyfill-ctype", + "type": "library", + "description": "Symfony polyfill for ctype functions", + "keywords": ["polyfill", "compatibility", "portable", "ctype"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-ctype": "*" + }, + "autoload": { + "psr-4": { "Symfony\\Polyfill\\Ctype\\": "" }, + "files": [ "bootstrap.php" ] + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "minimum-stability": "dev", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + } +} diff --git a/api/vendor/symfony/polyfill-mbstring/LICENSE b/api/vendor/symfony/polyfill-mbstring/LICENSE new file mode 100644 index 0000000..6e3afce --- /dev/null +++ b/api/vendor/symfony/polyfill-mbstring/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2015-present Fabien Potencier + +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. diff --git a/api/vendor/symfony/polyfill-mbstring/Mbstring.php b/api/vendor/symfony/polyfill-mbstring/Mbstring.php new file mode 100644 index 0000000..31e36a3 --- /dev/null +++ b/api/vendor/symfony/polyfill-mbstring/Mbstring.php @@ -0,0 +1,1045 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Mbstring; + +/** + * Partial mbstring implementation in PHP, iconv based, UTF-8 centric. + * + * Implemented: + * - mb_chr - Returns a specific character from its Unicode code point + * - mb_convert_encoding - Convert character encoding + * - mb_convert_variables - Convert character code in variable(s) + * - mb_decode_mimeheader - Decode string in MIME header field + * - mb_encode_mimeheader - Encode string for MIME header XXX NATIVE IMPLEMENTATION IS REALLY BUGGED + * - mb_decode_numericentity - Decode HTML numeric string reference to character + * - mb_encode_numericentity - Encode character to HTML numeric string reference + * - mb_convert_case - Perform case folding on a string + * - mb_detect_encoding - Detect character encoding + * - mb_get_info - Get internal settings of mbstring + * - mb_http_input - Detect HTTP input character encoding + * - mb_http_output - Set/Get HTTP output character encoding + * - mb_internal_encoding - Set/Get internal character encoding + * - mb_list_encodings - Returns an array of all supported encodings + * - mb_ord - Returns the Unicode code point of a character + * - mb_output_handler - Callback function converts character encoding in output buffer + * - mb_scrub - Replaces ill-formed byte sequences with substitute characters + * - mb_strlen - Get string length + * - mb_strpos - Find position of first occurrence of string in a string + * - mb_strrpos - Find position of last occurrence of a string in a string + * - mb_str_split - Convert a string to an array + * - mb_strtolower - Make a string lowercase + * - mb_strtoupper - Make a string uppercase + * - mb_substitute_character - Set/Get substitution character + * - mb_substr - Get part of string + * - mb_stripos - Finds position of first occurrence of a string within another, case insensitive + * - mb_stristr - Finds first occurrence of a string within another, case insensitive + * - mb_strrchr - Finds the last occurrence of a character in a string within another + * - mb_strrichr - Finds the last occurrence of a character in a string within another, case insensitive + * - mb_strripos - Finds position of last occurrence of a string within another, case insensitive + * - mb_strstr - Finds first occurrence of a string within another + * - mb_strwidth - Return width of string + * - mb_substr_count - Count the number of substring occurrences + * - mb_ucfirst - Make a string's first character uppercase + * - mb_lcfirst - Make a string's first character lowercase + * - mb_trim - Strip whitespace (or other characters) from the beginning and end of a string + * - mb_ltrim - Strip whitespace (or other characters) from the beginning of a string + * - mb_rtrim - Strip whitespace (or other characters) from the end of a string + * + * Not implemented: + * - mb_convert_kana - Convert "kana" one from another ("zen-kaku", "han-kaku" and more) + * - mb_ereg_* - Regular expression with multibyte support + * - mb_parse_str - Parse GET/POST/COOKIE data and set global variable + * - mb_preferred_mime_name - Get MIME charset string + * - mb_regex_encoding - Returns current encoding for multibyte regex as string + * - mb_regex_set_options - Set/Get the default options for mbregex functions + * - mb_send_mail - Send encoded mail + * - mb_split - Split multibyte string using regular expression + * - mb_strcut - Get part of string + * - mb_strimwidth - Get truncated string with specified width + * + * @author Nicolas Grekas + * + * @internal + */ +final class Mbstring +{ + public const MB_CASE_FOLD = \PHP_INT_MAX; + + private const SIMPLE_CASE_FOLD = [ + ['µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"], + ['μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "\xE1\xB9\xA1", 'ι'], + ]; + + private static $encodingList = ['ASCII', 'UTF-8']; + private static $language = 'neutral'; + private static $internalEncoding = 'UTF-8'; + + public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null) + { + if (\is_array($s)) { + $r = []; + foreach ($s as $str) { + $r[] = self::mb_convert_encoding($str, $toEncoding, $fromEncoding); + } + + return $r; + } + + if (\is_array($fromEncoding) || (null !== $fromEncoding && false !== strpos($fromEncoding, ','))) { + $fromEncoding = self::mb_detect_encoding($s, $fromEncoding); + } else { + $fromEncoding = self::getEncoding($fromEncoding); + } + + $toEncoding = self::getEncoding($toEncoding); + + if ('BASE64' === $fromEncoding) { + $s = base64_decode($s); + $fromEncoding = $toEncoding; + } + + if ('BASE64' === $toEncoding) { + return base64_encode($s); + } + + if ('HTML-ENTITIES' === $toEncoding || 'HTML' === $toEncoding) { + if ('HTML-ENTITIES' === $fromEncoding || 'HTML' === $fromEncoding) { + $fromEncoding = 'Windows-1252'; + } + if ('UTF-8' !== $fromEncoding) { + $s = iconv($fromEncoding, 'UTF-8//IGNORE', $s); + } + + return preg_replace_callback('/[\x80-\xFF]+/', [__CLASS__, 'html_encoding_callback'], $s); + } + + if ('HTML-ENTITIES' === $fromEncoding) { + $s = html_entity_decode($s, \ENT_COMPAT, 'UTF-8'); + $fromEncoding = 'UTF-8'; + } + + return iconv($fromEncoding, $toEncoding.'//IGNORE', $s); + } + + public static function mb_convert_variables($toEncoding, $fromEncoding, &...$vars) + { + $ok = true; + array_walk_recursive($vars, function (&$v) use (&$ok, $toEncoding, $fromEncoding) { + if (false === $v = self::mb_convert_encoding($v, $toEncoding, $fromEncoding)) { + $ok = false; + } + }); + + return $ok ? $fromEncoding : false; + } + + public static function mb_decode_mimeheader($s) + { + return iconv_mime_decode($s, 2, self::$internalEncoding); + } + + public static function mb_encode_mimeheader($s, $charset = null, $transferEncoding = null, $linefeed = null, $indent = null) + { + trigger_error('mb_encode_mimeheader() is bugged. Please use iconv_mime_encode() instead', \E_USER_WARNING); + } + + public static function mb_decode_numericentity($s, $convmap, $encoding = null) + { + if (null !== $s && !\is_scalar($s) && !(\is_object($s) && method_exists($s, '__toString'))) { + trigger_error('mb_decode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', \E_USER_WARNING); + + return null; + } + + if (!\is_array($convmap) || (80000 > \PHP_VERSION_ID && !$convmap)) { + return false; + } + + if (null !== $encoding && !\is_scalar($encoding)) { + trigger_error('mb_decode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', \E_USER_WARNING); + + return ''; // Instead of null (cf. mb_encode_numericentity). + } + + $s = (string) $s; + if ('' === $s) { + return ''; + } + + $encoding = self::getEncoding($encoding); + + if ('UTF-8' === $encoding) { + $encoding = null; + if (!preg_match('//u', $s)) { + $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s); + } + } else { + $s = iconv($encoding, 'UTF-8//IGNORE', $s); + } + + $cnt = floor(\count($convmap) / 4) * 4; + + for ($i = 0; $i < $cnt; $i += 4) { + // collector_decode_htmlnumericentity ignores $convmap[$i + 3] + $convmap[$i] += $convmap[$i + 2]; + $convmap[$i + 1] += $convmap[$i + 2]; + } + + $s = preg_replace_callback('/&#(?:0*([0-9]+)|x0*([0-9a-fA-F]+))(?!&);?/', function (array $m) use ($cnt, $convmap) { + $c = isset($m[2]) ? (int) hexdec($m[2]) : $m[1]; + for ($i = 0; $i < $cnt; $i += 4) { + if ($c >= $convmap[$i] && $c <= $convmap[$i + 1]) { + return self::mb_chr($c - $convmap[$i + 2]); + } + } + + return $m[0]; + }, $s); + + if (null === $encoding) { + return $s; + } + + return iconv('UTF-8', $encoding.'//IGNORE', $s); + } + + public static function mb_encode_numericentity($s, $convmap, $encoding = null, $is_hex = false) + { + if (null !== $s && !\is_scalar($s) && !(\is_object($s) && method_exists($s, '__toString'))) { + trigger_error('mb_encode_numericentity() expects parameter 1 to be string, '.\gettype($s).' given', \E_USER_WARNING); + + return null; + } + + if (!\is_array($convmap) || (80000 > \PHP_VERSION_ID && !$convmap)) { + return false; + } + + if (null !== $encoding && !\is_scalar($encoding)) { + trigger_error('mb_encode_numericentity() expects parameter 3 to be string, '.\gettype($s).' given', \E_USER_WARNING); + + return null; // Instead of '' (cf. mb_decode_numericentity). + } + + if (null !== $is_hex && !\is_scalar($is_hex)) { + trigger_error('mb_encode_numericentity() expects parameter 4 to be boolean, '.\gettype($s).' given', \E_USER_WARNING); + + return null; + } + + $s = (string) $s; + if ('' === $s) { + return ''; + } + + $encoding = self::getEncoding($encoding); + + if ('UTF-8' === $encoding) { + $encoding = null; + if (!preg_match('//u', $s)) { + $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s); + } + } else { + $s = iconv($encoding, 'UTF-8//IGNORE', $s); + } + + static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4]; + + $cnt = floor(\count($convmap) / 4) * 4; + $i = 0; + $len = \strlen($s); + $result = ''; + + while ($i < $len) { + $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"]; + $uchr = substr($s, $i, $ulen); + $i += $ulen; + $c = self::mb_ord($uchr); + + for ($j = 0; $j < $cnt; $j += 4) { + if ($c >= $convmap[$j] && $c <= $convmap[$j + 1]) { + $cOffset = ($c + $convmap[$j + 2]) & $convmap[$j + 3]; + $result .= $is_hex ? sprintf('&#x%X;', $cOffset) : '&#'.$cOffset.';'; + continue 2; + } + } + $result .= $uchr; + } + + if (null === $encoding) { + return $result; + } + + return iconv('UTF-8', $encoding.'//IGNORE', $result); + } + + public static function mb_convert_case($s, $mode, $encoding = null) + { + $s = (string) $s; + if ('' === $s) { + return ''; + } + + $encoding = self::getEncoding($encoding); + + if ('UTF-8' === $encoding) { + $encoding = null; + if (!preg_match('//u', $s)) { + $s = @iconv('UTF-8', 'UTF-8//IGNORE', $s); + } + } else { + $s = iconv($encoding, 'UTF-8//IGNORE', $s); + } + + if (\MB_CASE_TITLE == $mode) { + static $titleRegexp = null; + if (null === $titleRegexp) { + $titleRegexp = self::getData('titleCaseRegexp'); + } + $s = preg_replace_callback($titleRegexp, [__CLASS__, 'title_case'], $s); + } else { + if (\MB_CASE_UPPER == $mode) { + static $upper = null; + if (null === $upper) { + $upper = self::getData('upperCase'); + } + $map = $upper; + } else { + if (self::MB_CASE_FOLD === $mode) { + static $caseFolding = null; + if (null === $caseFolding) { + $caseFolding = self::getData('caseFolding'); + } + $s = strtr($s, $caseFolding); + } + + static $lower = null; + if (null === $lower) { + $lower = self::getData('lowerCase'); + } + $map = $lower; + } + + static $ulenMask = ["\xC0" => 2, "\xD0" => 2, "\xE0" => 3, "\xF0" => 4]; + + $i = 0; + $len = \strlen($s); + + while ($i < $len) { + $ulen = $s[$i] < "\x80" ? 1 : $ulenMask[$s[$i] & "\xF0"]; + $uchr = substr($s, $i, $ulen); + $i += $ulen; + + if (isset($map[$uchr])) { + $uchr = $map[$uchr]; + $nlen = \strlen($uchr); + + if ($nlen == $ulen) { + $nlen = $i; + do { + $s[--$nlen] = $uchr[--$ulen]; + } while ($ulen); + } else { + $s = substr_replace($s, $uchr, $i - $ulen, $ulen); + $len += $nlen - $ulen; + $i += $nlen - $ulen; + } + } + } + } + + if (null === $encoding) { + return $s; + } + + return iconv('UTF-8', $encoding.'//IGNORE', $s); + } + + public static function mb_internal_encoding($encoding = null) + { + if (null === $encoding) { + return self::$internalEncoding; + } + + $normalizedEncoding = self::getEncoding($encoding); + + if ('UTF-8' === $normalizedEncoding || false !== @iconv($normalizedEncoding, $normalizedEncoding, ' ')) { + self::$internalEncoding = $normalizedEncoding; + + return true; + } + + if (80000 > \PHP_VERSION_ID) { + return false; + } + + throw new \ValueError(sprintf('Argument #1 ($encoding) must be a valid encoding, "%s" given', $encoding)); + } + + public static function mb_language($lang = null) + { + if (null === $lang) { + return self::$language; + } + + switch ($normalizedLang = strtolower($lang)) { + case 'uni': + case 'neutral': + self::$language = $normalizedLang; + + return true; + } + + if (80000 > \PHP_VERSION_ID) { + return false; + } + + throw new \ValueError(sprintf('Argument #1 ($language) must be a valid language, "%s" given', $lang)); + } + + public static function mb_list_encodings() + { + return ['UTF-8']; + } + + public static function mb_encoding_aliases($encoding) + { + switch (strtoupper($encoding)) { + case 'UTF8': + case 'UTF-8': + return ['utf8']; + } + + return false; + } + + public static function mb_check_encoding($var = null, $encoding = null) + { + if (null === $encoding) { + if (null === $var) { + return false; + } + $encoding = self::$internalEncoding; + } + + if (!\is_array($var)) { + return self::mb_detect_encoding($var, [$encoding]) || false !== @iconv($encoding, $encoding, $var); + } + + foreach ($var as $key => $value) { + if (!self::mb_check_encoding($key, $encoding)) { + return false; + } + if (!self::mb_check_encoding($value, $encoding)) { + return false; + } + } + + return true; + } + + public static function mb_detect_encoding($str, $encodingList = null, $strict = false) + { + if (null === $encodingList) { + $encodingList = self::$encodingList; + } else { + if (!\is_array($encodingList)) { + $encodingList = array_map('trim', explode(',', $encodingList)); + } + $encodingList = array_map('strtoupper', $encodingList); + } + + foreach ($encodingList as $enc) { + switch ($enc) { + case 'ASCII': + if (!preg_match('/[\x80-\xFF]/', $str)) { + return $enc; + } + break; + + case 'UTF8': + case 'UTF-8': + if (preg_match('//u', $str)) { + return 'UTF-8'; + } + break; + + default: + if (0 === strncmp($enc, 'ISO-8859-', 9)) { + return $enc; + } + } + } + + return false; + } + + public static function mb_detect_order($encodingList = null) + { + if (null === $encodingList) { + return self::$encodingList; + } + + if (!\is_array($encodingList)) { + $encodingList = array_map('trim', explode(',', $encodingList)); + } + $encodingList = array_map('strtoupper', $encodingList); + + foreach ($encodingList as $enc) { + switch ($enc) { + default: + if (strncmp($enc, 'ISO-8859-', 9)) { + return false; + } + // no break + case 'ASCII': + case 'UTF8': + case 'UTF-8': + } + } + + self::$encodingList = $encodingList; + + return true; + } + + public static function mb_strlen($s, $encoding = null) + { + $encoding = self::getEncoding($encoding); + if ('CP850' === $encoding || 'ASCII' === $encoding) { + return \strlen($s); + } + + return @iconv_strlen($s, $encoding); + } + + public static function mb_strpos($haystack, $needle, $offset = 0, $encoding = null) + { + $encoding = self::getEncoding($encoding); + if ('CP850' === $encoding || 'ASCII' === $encoding) { + return strpos($haystack, $needle, $offset); + } + + $needle = (string) $needle; + if ('' === $needle) { + if (80000 > \PHP_VERSION_ID) { + trigger_error(__METHOD__.': Empty delimiter', \E_USER_WARNING); + + return false; + } + + return 0; + } + + return iconv_strpos($haystack, $needle, $offset, $encoding); + } + + public static function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null) + { + $encoding = self::getEncoding($encoding); + if ('CP850' === $encoding || 'ASCII' === $encoding) { + return strrpos($haystack, $needle, $offset); + } + + if ($offset != (int) $offset) { + $offset = 0; + } elseif ($offset = (int) $offset) { + if ($offset < 0) { + if (0 > $offset += self::mb_strlen($needle)) { + $haystack = self::mb_substr($haystack, 0, $offset, $encoding); + } + $offset = 0; + } else { + $haystack = self::mb_substr($haystack, $offset, 2147483647, $encoding); + } + } + + $pos = '' !== $needle || 80000 > \PHP_VERSION_ID + ? iconv_strrpos($haystack, $needle, $encoding) + : self::mb_strlen($haystack, $encoding); + + return false !== $pos ? $offset + $pos : false; + } + + public static function mb_str_split($string, $split_length = 1, $encoding = null) + { + if (null !== $string && !\is_scalar($string) && !(\is_object($string) && method_exists($string, '__toString'))) { + trigger_error('mb_str_split() expects parameter 1 to be string, '.\gettype($string).' given', \E_USER_WARNING); + + return null; + } + + if (1 > $split_length = (int) $split_length) { + if (80000 > \PHP_VERSION_ID) { + trigger_error('The length of each segment must be greater than zero', \E_USER_WARNING); + + return false; + } + + throw new \ValueError('Argument #2 ($length) must be greater than 0'); + } + + if (null === $encoding) { + $encoding = mb_internal_encoding(); + } + + if ('UTF-8' === $encoding = self::getEncoding($encoding)) { + $rx = '/('; + while (65535 < $split_length) { + $rx .= '.{65535}'; + $split_length -= 65535; + } + $rx .= '.{'.$split_length.'})/us'; + + return preg_split($rx, $string, -1, \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY); + } + + $result = []; + $length = mb_strlen($string, $encoding); + + for ($i = 0; $i < $length; $i += $split_length) { + $result[] = mb_substr($string, $i, $split_length, $encoding); + } + + return $result; + } + + public static function mb_strtolower($s, $encoding = null) + { + return self::mb_convert_case($s, \MB_CASE_LOWER, $encoding); + } + + public static function mb_strtoupper($s, $encoding = null) + { + return self::mb_convert_case($s, \MB_CASE_UPPER, $encoding); + } + + public static function mb_substitute_character($c = null) + { + if (null === $c) { + return 'none'; + } + if (0 === strcasecmp($c, 'none')) { + return true; + } + if (80000 > \PHP_VERSION_ID) { + return false; + } + if (\is_int($c) || 'long' === $c || 'entity' === $c) { + return false; + } + + throw new \ValueError('Argument #1 ($substitute_character) must be "none", "long", "entity" or a valid codepoint'); + } + + public static function mb_substr($s, $start, $length = null, $encoding = null) + { + $encoding = self::getEncoding($encoding); + if ('CP850' === $encoding || 'ASCII' === $encoding) { + return (string) substr($s, $start, null === $length ? 2147483647 : $length); + } + + if ($start < 0) { + $start = iconv_strlen($s, $encoding) + $start; + if ($start < 0) { + $start = 0; + } + } + + if (null === $length) { + $length = 2147483647; + } elseif ($length < 0) { + $length = iconv_strlen($s, $encoding) + $length - $start; + if ($length < 0) { + return ''; + } + } + + return (string) iconv_substr($s, $start, $length, $encoding); + } + + public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) + { + [$haystack, $needle] = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], [ + self::mb_convert_case($haystack, \MB_CASE_LOWER, $encoding), + self::mb_convert_case($needle, \MB_CASE_LOWER, $encoding), + ]); + + return self::mb_strpos($haystack, $needle, $offset, $encoding); + } + + public static function mb_stristr($haystack, $needle, $part = false, $encoding = null) + { + $pos = self::mb_stripos($haystack, $needle, 0, $encoding); + + return self::getSubpart($pos, $part, $haystack, $encoding); + } + + public static function mb_strrchr($haystack, $needle, $part = false, $encoding = null) + { + $encoding = self::getEncoding($encoding); + if ('CP850' === $encoding || 'ASCII' === $encoding) { + $pos = strrpos($haystack, $needle); + } else { + $needle = self::mb_substr($needle, 0, 1, $encoding); + $pos = iconv_strrpos($haystack, $needle, $encoding); + } + + return self::getSubpart($pos, $part, $haystack, $encoding); + } + + public static function mb_strrichr($haystack, $needle, $part = false, $encoding = null) + { + $needle = self::mb_substr($needle, 0, 1, $encoding); + $pos = self::mb_strripos($haystack, $needle, $encoding); + + return self::getSubpart($pos, $part, $haystack, $encoding); + } + + public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null) + { + $haystack = self::mb_convert_case($haystack, \MB_CASE_LOWER, $encoding); + $needle = self::mb_convert_case($needle, \MB_CASE_LOWER, $encoding); + + $haystack = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], $haystack); + $needle = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], $needle); + + return self::mb_strrpos($haystack, $needle, $offset, $encoding); + } + + public static function mb_strstr($haystack, $needle, $part = false, $encoding = null) + { + $pos = strpos($haystack, $needle); + if (false === $pos) { + return false; + } + if ($part) { + return substr($haystack, 0, $pos); + } + + return substr($haystack, $pos); + } + + public static function mb_get_info($type = 'all') + { + $info = [ + 'internal_encoding' => self::$internalEncoding, + 'http_output' => 'pass', + 'http_output_conv_mimetypes' => '^(text/|application/xhtml\+xml)', + 'func_overload' => 0, + 'func_overload_list' => 'no overload', + 'mail_charset' => 'UTF-8', + 'mail_header_encoding' => 'BASE64', + 'mail_body_encoding' => 'BASE64', + 'illegal_chars' => 0, + 'encoding_translation' => 'Off', + 'language' => self::$language, + 'detect_order' => self::$encodingList, + 'substitute_character' => 'none', + 'strict_detection' => 'Off', + ]; + + if ('all' === $type) { + return $info; + } + if (isset($info[$type])) { + return $info[$type]; + } + + return false; + } + + public static function mb_http_input($type = '') + { + return false; + } + + public static function mb_http_output($encoding = null) + { + return null !== $encoding ? 'pass' === $encoding : 'pass'; + } + + public static function mb_strwidth($s, $encoding = null) + { + $encoding = self::getEncoding($encoding); + + if ('UTF-8' !== $encoding) { + $s = iconv($encoding, 'UTF-8//IGNORE', $s); + } + + $s = preg_replace('/[\x{1100}-\x{115F}\x{2329}\x{232A}\x{2E80}-\x{303E}\x{3040}-\x{A4CF}\x{AC00}-\x{D7A3}\x{F900}-\x{FAFF}\x{FE10}-\x{FE19}\x{FE30}-\x{FE6F}\x{FF00}-\x{FF60}\x{FFE0}-\x{FFE6}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}]/u', '', $s, -1, $wide); + + return ($wide << 1) + iconv_strlen($s, 'UTF-8'); + } + + public static function mb_substr_count($haystack, $needle, $encoding = null) + { + return substr_count($haystack, $needle); + } + + public static function mb_output_handler($contents, $status) + { + return $contents; + } + + public static function mb_chr($code, $encoding = null) + { + if (0x80 > $code %= 0x200000) { + $s = \chr($code); + } elseif (0x800 > $code) { + $s = \chr(0xC0 | $code >> 6).\chr(0x80 | $code & 0x3F); + } elseif (0x10000 > $code) { + $s = \chr(0xE0 | $code >> 12).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F); + } else { + $s = \chr(0xF0 | $code >> 18).\chr(0x80 | $code >> 12 & 0x3F).\chr(0x80 | $code >> 6 & 0x3F).\chr(0x80 | $code & 0x3F); + } + + if ('UTF-8' !== $encoding = self::getEncoding($encoding)) { + $s = mb_convert_encoding($s, $encoding, 'UTF-8'); + } + + return $s; + } + + public static function mb_ord($s, $encoding = null) + { + if ('UTF-8' !== $encoding = self::getEncoding($encoding)) { + $s = mb_convert_encoding($s, 'UTF-8', $encoding); + } + + if (1 === \strlen($s)) { + return \ord($s); + } + + $code = ($s = unpack('C*', substr($s, 0, 4))) ? $s[1] : 0; + if (0xF0 <= $code) { + return (($code - 0xF0) << 18) + (($s[2] - 0x80) << 12) + (($s[3] - 0x80) << 6) + $s[4] - 0x80; + } + if (0xE0 <= $code) { + return (($code - 0xE0) << 12) + (($s[2] - 0x80) << 6) + $s[3] - 0x80; + } + if (0xC0 <= $code) { + return (($code - 0xC0) << 6) + $s[2] - 0x80; + } + + return $code; + } + + public static function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \STR_PAD_RIGHT, ?string $encoding = null): string + { + if (!\in_array($pad_type, [\STR_PAD_RIGHT, \STR_PAD_LEFT, \STR_PAD_BOTH], true)) { + throw new \ValueError('mb_str_pad(): Argument #4 ($pad_type) must be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH'); + } + + if (null === $encoding) { + $encoding = self::mb_internal_encoding(); + } else { + self::assertEncoding($encoding, 'mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given'); + } + + if (self::mb_strlen($pad_string, $encoding) <= 0) { + throw new \ValueError('mb_str_pad(): Argument #3 ($pad_string) must be a non-empty string'); + } + + $paddingRequired = $length - self::mb_strlen($string, $encoding); + + if ($paddingRequired < 1) { + return $string; + } + + switch ($pad_type) { + case \STR_PAD_LEFT: + return self::mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding).$string; + case \STR_PAD_RIGHT: + return $string.self::mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding); + default: + $leftPaddingLength = floor($paddingRequired / 2); + $rightPaddingLength = $paddingRequired - $leftPaddingLength; + + return self::mb_substr(str_repeat($pad_string, $leftPaddingLength), 0, $leftPaddingLength, $encoding).$string.self::mb_substr(str_repeat($pad_string, $rightPaddingLength), 0, $rightPaddingLength, $encoding); + } + } + + public static function mb_ucfirst(string $string, ?string $encoding = null): string + { + if (null === $encoding) { + $encoding = self::mb_internal_encoding(); + } else { + self::assertEncoding($encoding, 'mb_ucfirst(): Argument #2 ($encoding) must be a valid encoding, "%s" given'); + } + + $firstChar = mb_substr($string, 0, 1, $encoding); + $firstChar = mb_convert_case($firstChar, \MB_CASE_TITLE, $encoding); + + return $firstChar.mb_substr($string, 1, null, $encoding); + } + + public static function mb_lcfirst(string $string, ?string $encoding = null): string + { + if (null === $encoding) { + $encoding = self::mb_internal_encoding(); + } else { + self::assertEncoding($encoding, 'mb_lcfirst(): Argument #2 ($encoding) must be a valid encoding, "%s" given'); + } + + $firstChar = mb_substr($string, 0, 1, $encoding); + $firstChar = mb_convert_case($firstChar, \MB_CASE_LOWER, $encoding); + + return $firstChar.mb_substr($string, 1, null, $encoding); + } + + private static function getSubpart($pos, $part, $haystack, $encoding) + { + if (false === $pos) { + return false; + } + if ($part) { + return self::mb_substr($haystack, 0, $pos, $encoding); + } + + return self::mb_substr($haystack, $pos, null, $encoding); + } + + private static function html_encoding_callback(array $m) + { + $i = 1; + $entities = ''; + $m = unpack('C*', htmlentities($m[0], \ENT_COMPAT, 'UTF-8')); + + while (isset($m[$i])) { + if (0x80 > $m[$i]) { + $entities .= \chr($m[$i++]); + continue; + } + if (0xF0 <= $m[$i]) { + $c = (($m[$i++] - 0xF0) << 18) + (($m[$i++] - 0x80) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80; + } elseif (0xE0 <= $m[$i]) { + $c = (($m[$i++] - 0xE0) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80; + } else { + $c = (($m[$i++] - 0xC0) << 6) + $m[$i++] - 0x80; + } + + $entities .= '&#'.$c.';'; + } + + return $entities; + } + + private static function title_case(array $s) + { + return self::mb_convert_case($s[1], \MB_CASE_UPPER, 'UTF-8').self::mb_convert_case($s[2], \MB_CASE_LOWER, 'UTF-8'); + } + + private static function getData($file) + { + if (file_exists($file = __DIR__.'/Resources/unidata/'.$file.'.php')) { + return require $file; + } + + return false; + } + + private static function getEncoding($encoding) + { + if (null === $encoding) { + return self::$internalEncoding; + } + + if ('UTF-8' === $encoding) { + return 'UTF-8'; + } + + $encoding = strtoupper($encoding); + + if ('8BIT' === $encoding || 'BINARY' === $encoding) { + return 'CP850'; + } + + if ('UTF8' === $encoding) { + return 'UTF-8'; + } + + return $encoding; + } + + public static function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string + { + return self::mb_internal_trim('{^[%s]+|[%1$s]+$}Du', $string, $characters, $encoding, __FUNCTION__); + } + + public static function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string + { + return self::mb_internal_trim('{^[%s]+}Du', $string, $characters, $encoding, __FUNCTION__); + } + + public static function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string + { + return self::mb_internal_trim('{[%s]+$}Du', $string, $characters, $encoding, __FUNCTION__); + } + + private static function mb_internal_trim(string $regex, string $string, ?string $characters, ?string $encoding, string $function): string + { + if (null === $encoding) { + $encoding = self::mb_internal_encoding(); + } else { + self::assertEncoding($encoding, $function.'(): Argument #3 ($encoding) must be a valid encoding, "%s" given'); + } + + if ('' === $characters) { + return null === $encoding ? $string : self::mb_convert_encoding($string, $encoding); + } + + if ('UTF-8' === $encoding) { + $encoding = null; + if (!preg_match('//u', $string)) { + $string = @iconv('UTF-8', 'UTF-8//IGNORE', $string); + } + if (null !== $characters && !preg_match('//u', $characters)) { + $characters = @iconv('UTF-8', 'UTF-8//IGNORE', $characters); + } + } else { + $string = iconv($encoding, 'UTF-8//IGNORE', $string); + + if (null !== $characters) { + $characters = iconv($encoding, 'UTF-8//IGNORE', $characters); + } + } + + if (null === $characters) { + $characters = "\\0 \f\n\r\t\v\u{00A0}\u{1680}\u{2000}\u{2001}\u{2002}\u{2003}\u{2004}\u{2005}\u{2006}\u{2007}\u{2008}\u{2009}\u{200A}\u{2028}\u{2029}\u{202F}\u{205F}\u{3000}\u{0085}\u{180E}"; + } else { + $characters = preg_quote($characters); + } + + $string = preg_replace(sprintf($regex, $characters), '', $string); + + if (null === $encoding) { + return $string; + } + + return iconv('UTF-8', $encoding.'//IGNORE', $string); + } + + private static function assertEncoding(string $encoding, string $errorFormat): void + { + try { + $validEncoding = @self::mb_check_encoding('', $encoding); + } catch (\ValueError $e) { + throw new \ValueError(sprintf($errorFormat, $encoding)); + } + + // BC for PHP 7.3 and lower + if (!$validEncoding) { + throw new \ValueError(sprintf($errorFormat, $encoding)); + } + } +} diff --git a/api/vendor/symfony/polyfill-mbstring/README.md b/api/vendor/symfony/polyfill-mbstring/README.md new file mode 100644 index 0000000..478b40d --- /dev/null +++ b/api/vendor/symfony/polyfill-mbstring/README.md @@ -0,0 +1,13 @@ +Symfony Polyfill / Mbstring +=========================== + +This component provides a partial, native PHP implementation for the +[Mbstring](https://php.net/mbstring) extension. + +More information can be found in the +[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md). + +License +======= + +This library is released under the [MIT license](LICENSE). diff --git a/api/vendor/symfony/polyfill-mbstring/Resources/unidata/caseFolding.php b/api/vendor/symfony/polyfill-mbstring/Resources/unidata/caseFolding.php new file mode 100644 index 0000000..512bba0 --- /dev/null +++ b/api/vendor/symfony/polyfill-mbstring/Resources/unidata/caseFolding.php @@ -0,0 +1,119 @@ + 'i̇', + 'µ' => 'μ', + 'ſ' => 's', + 'ͅ' => 'ι', + 'ς' => 'σ', + 'ϐ' => 'β', + 'ϑ' => 'θ', + 'ϕ' => 'φ', + 'ϖ' => 'π', + 'ϰ' => 'κ', + 'ϱ' => 'ρ', + 'ϵ' => 'ε', + 'ẛ' => 'ṡ', + 'ι' => 'ι', + 'ß' => 'ss', + 'ʼn' => 'ʼn', + 'ǰ' => 'ǰ', + 'ΐ' => 'ΐ', + 'ΰ' => 'ΰ', + 'և' => 'եւ', + 'ẖ' => 'ẖ', + 'ẗ' => 'ẗ', + 'ẘ' => 'ẘ', + 'ẙ' => 'ẙ', + 'ẚ' => 'aʾ', + 'ẞ' => 'ss', + 'ὐ' => 'ὐ', + 'ὒ' => 'ὒ', + 'ὔ' => 'ὔ', + 'ὖ' => 'ὖ', + 'ᾀ' => 'ἀι', + 'ᾁ' => 'ἁι', + 'ᾂ' => 'ἂι', + 'ᾃ' => 'ἃι', + 'ᾄ' => 'ἄι', + 'ᾅ' => 'ἅι', + 'ᾆ' => 'ἆι', + 'ᾇ' => 'ἇι', + 'ᾈ' => 'ἀι', + 'ᾉ' => 'ἁι', + 'ᾊ' => 'ἂι', + 'ᾋ' => 'ἃι', + 'ᾌ' => 'ἄι', + 'ᾍ' => 'ἅι', + 'ᾎ' => 'ἆι', + 'ᾏ' => 'ἇι', + 'ᾐ' => 'ἠι', + 'ᾑ' => 'ἡι', + 'ᾒ' => 'ἢι', + 'ᾓ' => 'ἣι', + 'ᾔ' => 'ἤι', + 'ᾕ' => 'ἥι', + 'ᾖ' => 'ἦι', + 'ᾗ' => 'ἧι', + 'ᾘ' => 'ἠι', + 'ᾙ' => 'ἡι', + 'ᾚ' => 'ἢι', + 'ᾛ' => 'ἣι', + 'ᾜ' => 'ἤι', + 'ᾝ' => 'ἥι', + 'ᾞ' => 'ἦι', + 'ᾟ' => 'ἧι', + 'ᾠ' => 'ὠι', + 'ᾡ' => 'ὡι', + 'ᾢ' => 'ὢι', + 'ᾣ' => 'ὣι', + 'ᾤ' => 'ὤι', + 'ᾥ' => 'ὥι', + 'ᾦ' => 'ὦι', + 'ᾧ' => 'ὧι', + 'ᾨ' => 'ὠι', + 'ᾩ' => 'ὡι', + 'ᾪ' => 'ὢι', + 'ᾫ' => 'ὣι', + 'ᾬ' => 'ὤι', + 'ᾭ' => 'ὥι', + 'ᾮ' => 'ὦι', + 'ᾯ' => 'ὧι', + 'ᾲ' => 'ὰι', + 'ᾳ' => 'αι', + 'ᾴ' => 'άι', + 'ᾶ' => 'ᾶ', + 'ᾷ' => 'ᾶι', + 'ᾼ' => 'αι', + 'ῂ' => 'ὴι', + 'ῃ' => 'ηι', + 'ῄ' => 'ήι', + 'ῆ' => 'ῆ', + 'ῇ' => 'ῆι', + 'ῌ' => 'ηι', + 'ῒ' => 'ῒ', + 'ῖ' => 'ῖ', + 'ῗ' => 'ῗ', + 'ῢ' => 'ῢ', + 'ῤ' => 'ῤ', + 'ῦ' => 'ῦ', + 'ῧ' => 'ῧ', + 'ῲ' => 'ὼι', + 'ῳ' => 'ωι', + 'ῴ' => 'ώι', + 'ῶ' => 'ῶ', + 'ῷ' => 'ῶι', + 'ῼ' => 'ωι', + 'ff' => 'ff', + 'fi' => 'fi', + 'fl' => 'fl', + 'ffi' => 'ffi', + 'ffl' => 'ffl', + 'ſt' => 'st', + 'st' => 'st', + 'ﬓ' => 'մն', + 'ﬔ' => 'մե', + 'ﬕ' => 'մի', + 'ﬖ' => 'վն', + 'ﬗ' => 'մխ', +]; diff --git a/api/vendor/symfony/polyfill-mbstring/Resources/unidata/lowerCase.php b/api/vendor/symfony/polyfill-mbstring/Resources/unidata/lowerCase.php new file mode 100644 index 0000000..fac60b0 --- /dev/null +++ b/api/vendor/symfony/polyfill-mbstring/Resources/unidata/lowerCase.php @@ -0,0 +1,1397 @@ + 'a', + 'B' => 'b', + 'C' => 'c', + 'D' => 'd', + 'E' => 'e', + 'F' => 'f', + 'G' => 'g', + 'H' => 'h', + 'I' => 'i', + 'J' => 'j', + 'K' => 'k', + 'L' => 'l', + 'M' => 'm', + 'N' => 'n', + 'O' => 'o', + 'P' => 'p', + 'Q' => 'q', + 'R' => 'r', + 'S' => 's', + 'T' => 't', + 'U' => 'u', + 'V' => 'v', + 'W' => 'w', + 'X' => 'x', + 'Y' => 'y', + 'Z' => 'z', + 'À' => 'à', + 'Á' => 'á', + 'Â' => 'â', + 'Ã' => 'ã', + 'Ä' => 'ä', + 'Å' => 'å', + 'Æ' => 'æ', + 'Ç' => 'ç', + 'È' => 'è', + 'É' => 'é', + 'Ê' => 'ê', + 'Ë' => 'ë', + 'Ì' => 'ì', + 'Í' => 'í', + 'Î' => 'î', + 'Ï' => 'ï', + 'Ð' => 'ð', + 'Ñ' => 'ñ', + 'Ò' => 'ò', + 'Ó' => 'ó', + 'Ô' => 'ô', + 'Õ' => 'õ', + 'Ö' => 'ö', + 'Ø' => 'ø', + 'Ù' => 'ù', + 'Ú' => 'ú', + 'Û' => 'û', + 'Ü' => 'ü', + 'Ý' => 'ý', + 'Þ' => 'þ', + 'Ā' => 'ā', + 'Ă' => 'ă', + 'Ą' => 'ą', + 'Ć' => 'ć', + 'Ĉ' => 'ĉ', + 'Ċ' => 'ċ', + 'Č' => 'č', + 'Ď' => 'ď', + 'Đ' => 'đ', + 'Ē' => 'ē', + 'Ĕ' => 'ĕ', + 'Ė' => 'ė', + 'Ę' => 'ę', + 'Ě' => 'ě', + 'Ĝ' => 'ĝ', + 'Ğ' => 'ğ', + 'Ġ' => 'ġ', + 'Ģ' => 'ģ', + 'Ĥ' => 'ĥ', + 'Ħ' => 'ħ', + 'Ĩ' => 'ĩ', + 'Ī' => 'ī', + 'Ĭ' => 'ĭ', + 'Į' => 'į', + 'İ' => 'i̇', + 'IJ' => 'ij', + 'Ĵ' => 'ĵ', + 'Ķ' => 'ķ', + 'Ĺ' => 'ĺ', + 'Ļ' => 'ļ', + 'Ľ' => 'ľ', + 'Ŀ' => 'ŀ', + 'Ł' => 'ł', + 'Ń' => 'ń', + 'Ņ' => 'ņ', + 'Ň' => 'ň', + 'Ŋ' => 'ŋ', + 'Ō' => 'ō', + 'Ŏ' => 'ŏ', + 'Ő' => 'ő', + 'Œ' => 'œ', + 'Ŕ' => 'ŕ', + 'Ŗ' => 'ŗ', + 'Ř' => 'ř', + 'Ś' => 'ś', + 'Ŝ' => 'ŝ', + 'Ş' => 'ş', + 'Š' => 'š', + 'Ţ' => 'ţ', + 'Ť' => 'ť', + 'Ŧ' => 'ŧ', + 'Ũ' => 'ũ', + 'Ū' => 'ū', + 'Ŭ' => 'ŭ', + 'Ů' => 'ů', + 'Ű' => 'ű', + 'Ų' => 'ų', + 'Ŵ' => 'ŵ', + 'Ŷ' => 'ŷ', + 'Ÿ' => 'ÿ', + 'Ź' => 'ź', + 'Ż' => 'ż', + 'Ž' => 'ž', + 'Ɓ' => 'ɓ', + 'Ƃ' => 'ƃ', + 'Ƅ' => 'ƅ', + 'Ɔ' => 'ɔ', + 'Ƈ' => 'ƈ', + 'Ɖ' => 'ɖ', + 'Ɗ' => 'ɗ', + 'Ƌ' => 'ƌ', + 'Ǝ' => 'ǝ', + 'Ə' => 'ə', + 'Ɛ' => 'ɛ', + 'Ƒ' => 'ƒ', + 'Ɠ' => 'ɠ', + 'Ɣ' => 'ɣ', + 'Ɩ' => 'ɩ', + 'Ɨ' => 'ɨ', + 'Ƙ' => 'ƙ', + 'Ɯ' => 'ɯ', + 'Ɲ' => 'ɲ', + 'Ɵ' => 'ɵ', + 'Ơ' => 'ơ', + 'Ƣ' => 'ƣ', + 'Ƥ' => 'ƥ', + 'Ʀ' => 'ʀ', + 'Ƨ' => 'ƨ', + 'Ʃ' => 'ʃ', + 'Ƭ' => 'ƭ', + 'Ʈ' => 'ʈ', + 'Ư' => 'ư', + 'Ʊ' => 'ʊ', + 'Ʋ' => 'ʋ', + 'Ƴ' => 'ƴ', + 'Ƶ' => 'ƶ', + 'Ʒ' => 'ʒ', + 'Ƹ' => 'ƹ', + 'Ƽ' => 'ƽ', + 'DŽ' => 'dž', + 'Dž' => 'dž', + 'LJ' => 'lj', + 'Lj' => 'lj', + 'NJ' => 'nj', + 'Nj' => 'nj', + 'Ǎ' => 'ǎ', + 'Ǐ' => 'ǐ', + 'Ǒ' => 'ǒ', + 'Ǔ' => 'ǔ', + 'Ǖ' => 'ǖ', + 'Ǘ' => 'ǘ', + 'Ǚ' => 'ǚ', + 'Ǜ' => 'ǜ', + 'Ǟ' => 'ǟ', + 'Ǡ' => 'ǡ', + 'Ǣ' => 'ǣ', + 'Ǥ' => 'ǥ', + 'Ǧ' => 'ǧ', + 'Ǩ' => 'ǩ', + 'Ǫ' => 'ǫ', + 'Ǭ' => 'ǭ', + 'Ǯ' => 'ǯ', + 'DZ' => 'dz', + 'Dz' => 'dz', + 'Ǵ' => 'ǵ', + 'Ƕ' => 'ƕ', + 'Ƿ' => 'ƿ', + 'Ǹ' => 'ǹ', + 'Ǻ' => 'ǻ', + 'Ǽ' => 'ǽ', + 'Ǿ' => 'ǿ', + 'Ȁ' => 'ȁ', + 'Ȃ' => 'ȃ', + 'Ȅ' => 'ȅ', + 'Ȇ' => 'ȇ', + 'Ȉ' => 'ȉ', + 'Ȋ' => 'ȋ', + 'Ȍ' => 'ȍ', + 'Ȏ' => 'ȏ', + 'Ȑ' => 'ȑ', + 'Ȓ' => 'ȓ', + 'Ȕ' => 'ȕ', + 'Ȗ' => 'ȗ', + 'Ș' => 'ș', + 'Ț' => 'ț', + 'Ȝ' => 'ȝ', + 'Ȟ' => 'ȟ', + 'Ƞ' => 'ƞ', + 'Ȣ' => 'ȣ', + 'Ȥ' => 'ȥ', + 'Ȧ' => 'ȧ', + 'Ȩ' => 'ȩ', + 'Ȫ' => 'ȫ', + 'Ȭ' => 'ȭ', + 'Ȯ' => 'ȯ', + 'Ȱ' => 'ȱ', + 'Ȳ' => 'ȳ', + 'Ⱥ' => 'ⱥ', + 'Ȼ' => 'ȼ', + 'Ƚ' => 'ƚ', + 'Ⱦ' => 'ⱦ', + 'Ɂ' => 'ɂ', + 'Ƀ' => 'ƀ', + 'Ʉ' => 'ʉ', + 'Ʌ' => 'ʌ', + 'Ɇ' => 'ɇ', + 'Ɉ' => 'ɉ', + 'Ɋ' => 'ɋ', + 'Ɍ' => 'ɍ', + 'Ɏ' => 'ɏ', + 'Ͱ' => 'ͱ', + 'Ͳ' => 'ͳ', + 'Ͷ' => 'ͷ', + 'Ϳ' => 'ϳ', + 'Ά' => 'ά', + 'Έ' => 'έ', + 'Ή' => 'ή', + 'Ί' => 'ί', + 'Ό' => 'ό', + 'Ύ' => 'ύ', + 'Ώ' => 'ώ', + 'Α' => 'α', + 'Β' => 'β', + 'Γ' => 'γ', + 'Δ' => 'δ', + 'Ε' => 'ε', + 'Ζ' => 'ζ', + 'Η' => 'η', + 'Θ' => 'θ', + 'Ι' => 'ι', + 'Κ' => 'κ', + 'Λ' => 'λ', + 'Μ' => 'μ', + 'Ν' => 'ν', + 'Ξ' => 'ξ', + 'Ο' => 'ο', + 'Π' => 'π', + 'Ρ' => 'ρ', + 'Σ' => 'σ', + 'Τ' => 'τ', + 'Υ' => 'υ', + 'Φ' => 'φ', + 'Χ' => 'χ', + 'Ψ' => 'ψ', + 'Ω' => 'ω', + 'Ϊ' => 'ϊ', + 'Ϋ' => 'ϋ', + 'Ϗ' => 'ϗ', + 'Ϙ' => 'ϙ', + 'Ϛ' => 'ϛ', + 'Ϝ' => 'ϝ', + 'Ϟ' => 'ϟ', + 'Ϡ' => 'ϡ', + 'Ϣ' => 'ϣ', + 'Ϥ' => 'ϥ', + 'Ϧ' => 'ϧ', + 'Ϩ' => 'ϩ', + 'Ϫ' => 'ϫ', + 'Ϭ' => 'ϭ', + 'Ϯ' => 'ϯ', + 'ϴ' => 'θ', + 'Ϸ' => 'ϸ', + 'Ϲ' => 'ϲ', + 'Ϻ' => 'ϻ', + 'Ͻ' => 'ͻ', + 'Ͼ' => 'ͼ', + 'Ͽ' => 'ͽ', + 'Ѐ' => 'ѐ', + 'Ё' => 'ё', + 'Ђ' => 'ђ', + 'Ѓ' => 'ѓ', + 'Є' => 'є', + 'Ѕ' => 'ѕ', + 'І' => 'і', + 'Ї' => 'ї', + 'Ј' => 'ј', + 'Љ' => 'љ', + 'Њ' => 'њ', + 'Ћ' => 'ћ', + 'Ќ' => 'ќ', + 'Ѝ' => 'ѝ', + 'Ў' => 'ў', + 'Џ' => 'џ', + 'А' => 'а', + 'Б' => 'б', + 'В' => 'в', + 'Г' => 'г', + 'Д' => 'д', + 'Е' => 'е', + 'Ж' => 'ж', + 'З' => 'з', + 'И' => 'и', + 'Й' => 'й', + 'К' => 'к', + 'Л' => 'л', + 'М' => 'м', + 'Н' => 'н', + 'О' => 'о', + 'П' => 'п', + 'Р' => 'р', + 'С' => 'с', + 'Т' => 'т', + 'У' => 'у', + 'Ф' => 'ф', + 'Х' => 'х', + 'Ц' => 'ц', + 'Ч' => 'ч', + 'Ш' => 'ш', + 'Щ' => 'щ', + 'Ъ' => 'ъ', + 'Ы' => 'ы', + 'Ь' => 'ь', + 'Э' => 'э', + 'Ю' => 'ю', + 'Я' => 'я', + 'Ѡ' => 'ѡ', + 'Ѣ' => 'ѣ', + 'Ѥ' => 'ѥ', + 'Ѧ' => 'ѧ', + 'Ѩ' => 'ѩ', + 'Ѫ' => 'ѫ', + 'Ѭ' => 'ѭ', + 'Ѯ' => 'ѯ', + 'Ѱ' => 'ѱ', + 'Ѳ' => 'ѳ', + 'Ѵ' => 'ѵ', + 'Ѷ' => 'ѷ', + 'Ѹ' => 'ѹ', + 'Ѻ' => 'ѻ', + 'Ѽ' => 'ѽ', + 'Ѿ' => 'ѿ', + 'Ҁ' => 'ҁ', + 'Ҋ' => 'ҋ', + 'Ҍ' => 'ҍ', + 'Ҏ' => 'ҏ', + 'Ґ' => 'ґ', + 'Ғ' => 'ғ', + 'Ҕ' => 'ҕ', + 'Җ' => 'җ', + 'Ҙ' => 'ҙ', + 'Қ' => 'қ', + 'Ҝ' => 'ҝ', + 'Ҟ' => 'ҟ', + 'Ҡ' => 'ҡ', + 'Ң' => 'ң', + 'Ҥ' => 'ҥ', + 'Ҧ' => 'ҧ', + 'Ҩ' => 'ҩ', + 'Ҫ' => 'ҫ', + 'Ҭ' => 'ҭ', + 'Ү' => 'ү', + 'Ұ' => 'ұ', + 'Ҳ' => 'ҳ', + 'Ҵ' => 'ҵ', + 'Ҷ' => 'ҷ', + 'Ҹ' => 'ҹ', + 'Һ' => 'һ', + 'Ҽ' => 'ҽ', + 'Ҿ' => 'ҿ', + 'Ӏ' => 'ӏ', + 'Ӂ' => 'ӂ', + 'Ӄ' => 'ӄ', + 'Ӆ' => 'ӆ', + 'Ӈ' => 'ӈ', + 'Ӊ' => 'ӊ', + 'Ӌ' => 'ӌ', + 'Ӎ' => 'ӎ', + 'Ӑ' => 'ӑ', + 'Ӓ' => 'ӓ', + 'Ӕ' => 'ӕ', + 'Ӗ' => 'ӗ', + 'Ә' => 'ә', + 'Ӛ' => 'ӛ', + 'Ӝ' => 'ӝ', + 'Ӟ' => 'ӟ', + 'Ӡ' => 'ӡ', + 'Ӣ' => 'ӣ', + 'Ӥ' => 'ӥ', + 'Ӧ' => 'ӧ', + 'Ө' => 'ө', + 'Ӫ' => 'ӫ', + 'Ӭ' => 'ӭ', + 'Ӯ' => 'ӯ', + 'Ӱ' => 'ӱ', + 'Ӳ' => 'ӳ', + 'Ӵ' => 'ӵ', + 'Ӷ' => 'ӷ', + 'Ӹ' => 'ӹ', + 'Ӻ' => 'ӻ', + 'Ӽ' => 'ӽ', + 'Ӿ' => 'ӿ', + 'Ԁ' => 'ԁ', + 'Ԃ' => 'ԃ', + 'Ԅ' => 'ԅ', + 'Ԇ' => 'ԇ', + 'Ԉ' => 'ԉ', + 'Ԋ' => 'ԋ', + 'Ԍ' => 'ԍ', + 'Ԏ' => 'ԏ', + 'Ԑ' => 'ԑ', + 'Ԓ' => 'ԓ', + 'Ԕ' => 'ԕ', + 'Ԗ' => 'ԗ', + 'Ԙ' => 'ԙ', + 'Ԛ' => 'ԛ', + 'Ԝ' => 'ԝ', + 'Ԟ' => 'ԟ', + 'Ԡ' => 'ԡ', + 'Ԣ' => 'ԣ', + 'Ԥ' => 'ԥ', + 'Ԧ' => 'ԧ', + 'Ԩ' => 'ԩ', + 'Ԫ' => 'ԫ', + 'Ԭ' => 'ԭ', + 'Ԯ' => 'ԯ', + 'Ա' => 'ա', + 'Բ' => 'բ', + 'Գ' => 'գ', + 'Դ' => 'դ', + 'Ե' => 'ե', + 'Զ' => 'զ', + 'Է' => 'է', + 'Ը' => 'ը', + 'Թ' => 'թ', + 'Ժ' => 'ժ', + 'Ի' => 'ի', + 'Լ' => 'լ', + 'Խ' => 'խ', + 'Ծ' => 'ծ', + 'Կ' => 'կ', + 'Հ' => 'հ', + 'Ձ' => 'ձ', + 'Ղ' => 'ղ', + 'Ճ' => 'ճ', + 'Մ' => 'մ', + 'Յ' => 'յ', + 'Ն' => 'ն', + 'Շ' => 'շ', + 'Ո' => 'ո', + 'Չ' => 'չ', + 'Պ' => 'պ', + 'Ջ' => 'ջ', + 'Ռ' => 'ռ', + 'Ս' => 'ս', + 'Վ' => 'վ', + 'Տ' => 'տ', + 'Ր' => 'ր', + 'Ց' => 'ց', + 'Ւ' => 'ւ', + 'Փ' => 'փ', + 'Ք' => 'ք', + 'Օ' => 'օ', + 'Ֆ' => 'ֆ', + 'Ⴀ' => 'ⴀ', + 'Ⴁ' => 'ⴁ', + 'Ⴂ' => 'ⴂ', + 'Ⴃ' => 'ⴃ', + 'Ⴄ' => 'ⴄ', + 'Ⴅ' => 'ⴅ', + 'Ⴆ' => 'ⴆ', + 'Ⴇ' => 'ⴇ', + 'Ⴈ' => 'ⴈ', + 'Ⴉ' => 'ⴉ', + 'Ⴊ' => 'ⴊ', + 'Ⴋ' => 'ⴋ', + 'Ⴌ' => 'ⴌ', + 'Ⴍ' => 'ⴍ', + 'Ⴎ' => 'ⴎ', + 'Ⴏ' => 'ⴏ', + 'Ⴐ' => 'ⴐ', + 'Ⴑ' => 'ⴑ', + 'Ⴒ' => 'ⴒ', + 'Ⴓ' => 'ⴓ', + 'Ⴔ' => 'ⴔ', + 'Ⴕ' => 'ⴕ', + 'Ⴖ' => 'ⴖ', + 'Ⴗ' => 'ⴗ', + 'Ⴘ' => 'ⴘ', + 'Ⴙ' => 'ⴙ', + 'Ⴚ' => 'ⴚ', + 'Ⴛ' => 'ⴛ', + 'Ⴜ' => 'ⴜ', + 'Ⴝ' => 'ⴝ', + 'Ⴞ' => 'ⴞ', + 'Ⴟ' => 'ⴟ', + 'Ⴠ' => 'ⴠ', + 'Ⴡ' => 'ⴡ', + 'Ⴢ' => 'ⴢ', + 'Ⴣ' => 'ⴣ', + 'Ⴤ' => 'ⴤ', + 'Ⴥ' => 'ⴥ', + 'Ⴧ' => 'ⴧ', + 'Ⴭ' => 'ⴭ', + 'Ꭰ' => 'ꭰ', + 'Ꭱ' => 'ꭱ', + 'Ꭲ' => 'ꭲ', + 'Ꭳ' => 'ꭳ', + 'Ꭴ' => 'ꭴ', + 'Ꭵ' => 'ꭵ', + 'Ꭶ' => 'ꭶ', + 'Ꭷ' => 'ꭷ', + 'Ꭸ' => 'ꭸ', + 'Ꭹ' => 'ꭹ', + 'Ꭺ' => 'ꭺ', + 'Ꭻ' => 'ꭻ', + 'Ꭼ' => 'ꭼ', + 'Ꭽ' => 'ꭽ', + 'Ꭾ' => 'ꭾ', + 'Ꭿ' => 'ꭿ', + 'Ꮀ' => 'ꮀ', + 'Ꮁ' => 'ꮁ', + 'Ꮂ' => 'ꮂ', + 'Ꮃ' => 'ꮃ', + 'Ꮄ' => 'ꮄ', + 'Ꮅ' => 'ꮅ', + 'Ꮆ' => 'ꮆ', + 'Ꮇ' => 'ꮇ', + 'Ꮈ' => 'ꮈ', + 'Ꮉ' => 'ꮉ', + 'Ꮊ' => 'ꮊ', + 'Ꮋ' => 'ꮋ', + 'Ꮌ' => 'ꮌ', + 'Ꮍ' => 'ꮍ', + 'Ꮎ' => 'ꮎ', + 'Ꮏ' => 'ꮏ', + 'Ꮐ' => 'ꮐ', + 'Ꮑ' => 'ꮑ', + 'Ꮒ' => 'ꮒ', + 'Ꮓ' => 'ꮓ', + 'Ꮔ' => 'ꮔ', + 'Ꮕ' => 'ꮕ', + 'Ꮖ' => 'ꮖ', + 'Ꮗ' => 'ꮗ', + 'Ꮘ' => 'ꮘ', + 'Ꮙ' => 'ꮙ', + 'Ꮚ' => 'ꮚ', + 'Ꮛ' => 'ꮛ', + 'Ꮜ' => 'ꮜ', + 'Ꮝ' => 'ꮝ', + 'Ꮞ' => 'ꮞ', + 'Ꮟ' => 'ꮟ', + 'Ꮠ' => 'ꮠ', + 'Ꮡ' => 'ꮡ', + 'Ꮢ' => 'ꮢ', + 'Ꮣ' => 'ꮣ', + 'Ꮤ' => 'ꮤ', + 'Ꮥ' => 'ꮥ', + 'Ꮦ' => 'ꮦ', + 'Ꮧ' => 'ꮧ', + 'Ꮨ' => 'ꮨ', + 'Ꮩ' => 'ꮩ', + 'Ꮪ' => 'ꮪ', + 'Ꮫ' => 'ꮫ', + 'Ꮬ' => 'ꮬ', + 'Ꮭ' => 'ꮭ', + 'Ꮮ' => 'ꮮ', + 'Ꮯ' => 'ꮯ', + 'Ꮰ' => 'ꮰ', + 'Ꮱ' => 'ꮱ', + 'Ꮲ' => 'ꮲ', + 'Ꮳ' => 'ꮳ', + 'Ꮴ' => 'ꮴ', + 'Ꮵ' => 'ꮵ', + 'Ꮶ' => 'ꮶ', + 'Ꮷ' => 'ꮷ', + 'Ꮸ' => 'ꮸ', + 'Ꮹ' => 'ꮹ', + 'Ꮺ' => 'ꮺ', + 'Ꮻ' => 'ꮻ', + 'Ꮼ' => 'ꮼ', + 'Ꮽ' => 'ꮽ', + 'Ꮾ' => 'ꮾ', + 'Ꮿ' => 'ꮿ', + 'Ᏸ' => 'ᏸ', + 'Ᏹ' => 'ᏹ', + 'Ᏺ' => 'ᏺ', + 'Ᏻ' => 'ᏻ', + 'Ᏼ' => 'ᏼ', + 'Ᏽ' => 'ᏽ', + 'Ა' => 'ა', + 'Ბ' => 'ბ', + 'Გ' => 'გ', + 'Დ' => 'დ', + 'Ე' => 'ე', + 'Ვ' => 'ვ', + 'Ზ' => 'ზ', + 'Თ' => 'თ', + 'Ი' => 'ი', + 'Კ' => 'კ', + 'Ლ' => 'ლ', + 'Მ' => 'მ', + 'Ნ' => 'ნ', + 'Ო' => 'ო', + 'Პ' => 'პ', + 'Ჟ' => 'ჟ', + 'Რ' => 'რ', + 'Ს' => 'ს', + 'Ტ' => 'ტ', + 'Უ' => 'უ', + 'Ფ' => 'ფ', + 'Ქ' => 'ქ', + 'Ღ' => 'ღ', + 'Ყ' => 'ყ', + 'Შ' => 'შ', + 'Ჩ' => 'ჩ', + 'Ც' => 'ც', + 'Ძ' => 'ძ', + 'Წ' => 'წ', + 'Ჭ' => 'ჭ', + 'Ხ' => 'ხ', + 'Ჯ' => 'ჯ', + 'Ჰ' => 'ჰ', + 'Ჱ' => 'ჱ', + 'Ჲ' => 'ჲ', + 'Ჳ' => 'ჳ', + 'Ჴ' => 'ჴ', + 'Ჵ' => 'ჵ', + 'Ჶ' => 'ჶ', + 'Ჷ' => 'ჷ', + 'Ჸ' => 'ჸ', + 'Ჹ' => 'ჹ', + 'Ჺ' => 'ჺ', + 'Ჽ' => 'ჽ', + 'Ჾ' => 'ჾ', + 'Ჿ' => 'ჿ', + 'Ḁ' => 'ḁ', + 'Ḃ' => 'ḃ', + 'Ḅ' => 'ḅ', + 'Ḇ' => 'ḇ', + 'Ḉ' => 'ḉ', + 'Ḋ' => 'ḋ', + 'Ḍ' => 'ḍ', + 'Ḏ' => 'ḏ', + 'Ḑ' => 'ḑ', + 'Ḓ' => 'ḓ', + 'Ḕ' => 'ḕ', + 'Ḗ' => 'ḗ', + 'Ḙ' => 'ḙ', + 'Ḛ' => 'ḛ', + 'Ḝ' => 'ḝ', + 'Ḟ' => 'ḟ', + 'Ḡ' => 'ḡ', + 'Ḣ' => 'ḣ', + 'Ḥ' => 'ḥ', + 'Ḧ' => 'ḧ', + 'Ḩ' => 'ḩ', + 'Ḫ' => 'ḫ', + 'Ḭ' => 'ḭ', + 'Ḯ' => 'ḯ', + 'Ḱ' => 'ḱ', + 'Ḳ' => 'ḳ', + 'Ḵ' => 'ḵ', + 'Ḷ' => 'ḷ', + 'Ḹ' => 'ḹ', + 'Ḻ' => 'ḻ', + 'Ḽ' => 'ḽ', + 'Ḿ' => 'ḿ', + 'Ṁ' => 'ṁ', + 'Ṃ' => 'ṃ', + 'Ṅ' => 'ṅ', + 'Ṇ' => 'ṇ', + 'Ṉ' => 'ṉ', + 'Ṋ' => 'ṋ', + 'Ṍ' => 'ṍ', + 'Ṏ' => 'ṏ', + 'Ṑ' => 'ṑ', + 'Ṓ' => 'ṓ', + 'Ṕ' => 'ṕ', + 'Ṗ' => 'ṗ', + 'Ṙ' => 'ṙ', + 'Ṛ' => 'ṛ', + 'Ṝ' => 'ṝ', + 'Ṟ' => 'ṟ', + 'Ṡ' => 'ṡ', + 'Ṣ' => 'ṣ', + 'Ṥ' => 'ṥ', + 'Ṧ' => 'ṧ', + 'Ṩ' => 'ṩ', + 'Ṫ' => 'ṫ', + 'Ṭ' => 'ṭ', + 'Ṯ' => 'ṯ', + 'Ṱ' => 'ṱ', + 'Ṳ' => 'ṳ', + 'Ṵ' => 'ṵ', + 'Ṷ' => 'ṷ', + 'Ṹ' => 'ṹ', + 'Ṻ' => 'ṻ', + 'Ṽ' => 'ṽ', + 'Ṿ' => 'ṿ', + 'Ẁ' => 'ẁ', + 'Ẃ' => 'ẃ', + 'Ẅ' => 'ẅ', + 'Ẇ' => 'ẇ', + 'Ẉ' => 'ẉ', + 'Ẋ' => 'ẋ', + 'Ẍ' => 'ẍ', + 'Ẏ' => 'ẏ', + 'Ẑ' => 'ẑ', + 'Ẓ' => 'ẓ', + 'Ẕ' => 'ẕ', + 'ẞ' => 'ß', + 'Ạ' => 'ạ', + 'Ả' => 'ả', + 'Ấ' => 'ấ', + 'Ầ' => 'ầ', + 'Ẩ' => 'ẩ', + 'Ẫ' => 'ẫ', + 'Ậ' => 'ậ', + 'Ắ' => 'ắ', + 'Ằ' => 'ằ', + 'Ẳ' => 'ẳ', + 'Ẵ' => 'ẵ', + 'Ặ' => 'ặ', + 'Ẹ' => 'ẹ', + 'Ẻ' => 'ẻ', + 'Ẽ' => 'ẽ', + 'Ế' => 'ế', + 'Ề' => 'ề', + 'Ể' => 'ể', + 'Ễ' => 'ễ', + 'Ệ' => 'ệ', + 'Ỉ' => 'ỉ', + 'Ị' => 'ị', + 'Ọ' => 'ọ', + 'Ỏ' => 'ỏ', + 'Ố' => 'ố', + 'Ồ' => 'ồ', + 'Ổ' => 'ổ', + 'Ỗ' => 'ỗ', + 'Ộ' => 'ộ', + 'Ớ' => 'ớ', + 'Ờ' => 'ờ', + 'Ở' => 'ở', + 'Ỡ' => 'ỡ', + 'Ợ' => 'ợ', + 'Ụ' => 'ụ', + 'Ủ' => 'ủ', + 'Ứ' => 'ứ', + 'Ừ' => 'ừ', + 'Ử' => 'ử', + 'Ữ' => 'ữ', + 'Ự' => 'ự', + 'Ỳ' => 'ỳ', + 'Ỵ' => 'ỵ', + 'Ỷ' => 'ỷ', + 'Ỹ' => 'ỹ', + 'Ỻ' => 'ỻ', + 'Ỽ' => 'ỽ', + 'Ỿ' => 'ỿ', + 'Ἀ' => 'ἀ', + 'Ἁ' => 'ἁ', + 'Ἂ' => 'ἂ', + 'Ἃ' => 'ἃ', + 'Ἄ' => 'ἄ', + 'Ἅ' => 'ἅ', + 'Ἆ' => 'ἆ', + 'Ἇ' => 'ἇ', + 'Ἐ' => 'ἐ', + 'Ἑ' => 'ἑ', + 'Ἒ' => 'ἒ', + 'Ἓ' => 'ἓ', + 'Ἔ' => 'ἔ', + 'Ἕ' => 'ἕ', + 'Ἠ' => 'ἠ', + 'Ἡ' => 'ἡ', + 'Ἢ' => 'ἢ', + 'Ἣ' => 'ἣ', + 'Ἤ' => 'ἤ', + 'Ἥ' => 'ἥ', + 'Ἦ' => 'ἦ', + 'Ἧ' => 'ἧ', + 'Ἰ' => 'ἰ', + 'Ἱ' => 'ἱ', + 'Ἲ' => 'ἲ', + 'Ἳ' => 'ἳ', + 'Ἴ' => 'ἴ', + 'Ἵ' => 'ἵ', + 'Ἶ' => 'ἶ', + 'Ἷ' => 'ἷ', + 'Ὀ' => 'ὀ', + 'Ὁ' => 'ὁ', + 'Ὂ' => 'ὂ', + 'Ὃ' => 'ὃ', + 'Ὄ' => 'ὄ', + 'Ὅ' => 'ὅ', + 'Ὑ' => 'ὑ', + 'Ὓ' => 'ὓ', + 'Ὕ' => 'ὕ', + 'Ὗ' => 'ὗ', + 'Ὠ' => 'ὠ', + 'Ὡ' => 'ὡ', + 'Ὢ' => 'ὢ', + 'Ὣ' => 'ὣ', + 'Ὤ' => 'ὤ', + 'Ὥ' => 'ὥ', + 'Ὦ' => 'ὦ', + 'Ὧ' => 'ὧ', + 'ᾈ' => 'ᾀ', + 'ᾉ' => 'ᾁ', + 'ᾊ' => 'ᾂ', + 'ᾋ' => 'ᾃ', + 'ᾌ' => 'ᾄ', + 'ᾍ' => 'ᾅ', + 'ᾎ' => 'ᾆ', + 'ᾏ' => 'ᾇ', + 'ᾘ' => 'ᾐ', + 'ᾙ' => 'ᾑ', + 'ᾚ' => 'ᾒ', + 'ᾛ' => 'ᾓ', + 'ᾜ' => 'ᾔ', + 'ᾝ' => 'ᾕ', + 'ᾞ' => 'ᾖ', + 'ᾟ' => 'ᾗ', + 'ᾨ' => 'ᾠ', + 'ᾩ' => 'ᾡ', + 'ᾪ' => 'ᾢ', + 'ᾫ' => 'ᾣ', + 'ᾬ' => 'ᾤ', + 'ᾭ' => 'ᾥ', + 'ᾮ' => 'ᾦ', + 'ᾯ' => 'ᾧ', + 'Ᾰ' => 'ᾰ', + 'Ᾱ' => 'ᾱ', + 'Ὰ' => 'ὰ', + 'Ά' => 'ά', + 'ᾼ' => 'ᾳ', + 'Ὲ' => 'ὲ', + 'Έ' => 'έ', + 'Ὴ' => 'ὴ', + 'Ή' => 'ή', + 'ῌ' => 'ῃ', + 'Ῐ' => 'ῐ', + 'Ῑ' => 'ῑ', + 'Ὶ' => 'ὶ', + 'Ί' => 'ί', + 'Ῠ' => 'ῠ', + 'Ῡ' => 'ῡ', + 'Ὺ' => 'ὺ', + 'Ύ' => 'ύ', + 'Ῥ' => 'ῥ', + 'Ὸ' => 'ὸ', + 'Ό' => 'ό', + 'Ὼ' => 'ὼ', + 'Ώ' => 'ώ', + 'ῼ' => 'ῳ', + 'Ω' => 'ω', + 'K' => 'k', + 'Å' => 'å', + 'Ⅎ' => 'ⅎ', + 'Ⅰ' => 'ⅰ', + 'Ⅱ' => 'ⅱ', + 'Ⅲ' => 'ⅲ', + 'Ⅳ' => 'ⅳ', + 'Ⅴ' => 'ⅴ', + 'Ⅵ' => 'ⅵ', + 'Ⅶ' => 'ⅶ', + 'Ⅷ' => 'ⅷ', + 'Ⅸ' => 'ⅸ', + 'Ⅹ' => 'ⅹ', + 'Ⅺ' => 'ⅺ', + 'Ⅻ' => 'ⅻ', + 'Ⅼ' => 'ⅼ', + 'Ⅽ' => 'ⅽ', + 'Ⅾ' => 'ⅾ', + 'Ⅿ' => 'ⅿ', + 'Ↄ' => 'ↄ', + 'Ⓐ' => 'ⓐ', + 'Ⓑ' => 'ⓑ', + 'Ⓒ' => 'ⓒ', + 'Ⓓ' => 'ⓓ', + 'Ⓔ' => 'ⓔ', + 'Ⓕ' => 'ⓕ', + 'Ⓖ' => 'ⓖ', + 'Ⓗ' => 'ⓗ', + 'Ⓘ' => 'ⓘ', + 'Ⓙ' => 'ⓙ', + 'Ⓚ' => 'ⓚ', + 'Ⓛ' => 'ⓛ', + 'Ⓜ' => 'ⓜ', + 'Ⓝ' => 'ⓝ', + 'Ⓞ' => 'ⓞ', + 'Ⓟ' => 'ⓟ', + 'Ⓠ' => 'ⓠ', + 'Ⓡ' => 'ⓡ', + 'Ⓢ' => 'ⓢ', + 'Ⓣ' => 'ⓣ', + 'Ⓤ' => 'ⓤ', + 'Ⓥ' => 'ⓥ', + 'Ⓦ' => 'ⓦ', + 'Ⓧ' => 'ⓧ', + 'Ⓨ' => 'ⓨ', + 'Ⓩ' => 'ⓩ', + 'Ⰰ' => 'ⰰ', + 'Ⰱ' => 'ⰱ', + 'Ⰲ' => 'ⰲ', + 'Ⰳ' => 'ⰳ', + 'Ⰴ' => 'ⰴ', + 'Ⰵ' => 'ⰵ', + 'Ⰶ' => 'ⰶ', + 'Ⰷ' => 'ⰷ', + 'Ⰸ' => 'ⰸ', + 'Ⰹ' => 'ⰹ', + 'Ⰺ' => 'ⰺ', + 'Ⰻ' => 'ⰻ', + 'Ⰼ' => 'ⰼ', + 'Ⰽ' => 'ⰽ', + 'Ⰾ' => 'ⰾ', + 'Ⰿ' => 'ⰿ', + 'Ⱀ' => 'ⱀ', + 'Ⱁ' => 'ⱁ', + 'Ⱂ' => 'ⱂ', + 'Ⱃ' => 'ⱃ', + 'Ⱄ' => 'ⱄ', + 'Ⱅ' => 'ⱅ', + 'Ⱆ' => 'ⱆ', + 'Ⱇ' => 'ⱇ', + 'Ⱈ' => 'ⱈ', + 'Ⱉ' => 'ⱉ', + 'Ⱊ' => 'ⱊ', + 'Ⱋ' => 'ⱋ', + 'Ⱌ' => 'ⱌ', + 'Ⱍ' => 'ⱍ', + 'Ⱎ' => 'ⱎ', + 'Ⱏ' => 'ⱏ', + 'Ⱐ' => 'ⱐ', + 'Ⱑ' => 'ⱑ', + 'Ⱒ' => 'ⱒ', + 'Ⱓ' => 'ⱓ', + 'Ⱔ' => 'ⱔ', + 'Ⱕ' => 'ⱕ', + 'Ⱖ' => 'ⱖ', + 'Ⱗ' => 'ⱗ', + 'Ⱘ' => 'ⱘ', + 'Ⱙ' => 'ⱙ', + 'Ⱚ' => 'ⱚ', + 'Ⱛ' => 'ⱛ', + 'Ⱜ' => 'ⱜ', + 'Ⱝ' => 'ⱝ', + 'Ⱞ' => 'ⱞ', + 'Ⱡ' => 'ⱡ', + 'Ɫ' => 'ɫ', + 'Ᵽ' => 'ᵽ', + 'Ɽ' => 'ɽ', + 'Ⱨ' => 'ⱨ', + 'Ⱪ' => 'ⱪ', + 'Ⱬ' => 'ⱬ', + 'Ɑ' => 'ɑ', + 'Ɱ' => 'ɱ', + 'Ɐ' => 'ɐ', + 'Ɒ' => 'ɒ', + 'Ⱳ' => 'ⱳ', + 'Ⱶ' => 'ⱶ', + 'Ȿ' => 'ȿ', + 'Ɀ' => 'ɀ', + 'Ⲁ' => 'ⲁ', + 'Ⲃ' => 'ⲃ', + 'Ⲅ' => 'ⲅ', + 'Ⲇ' => 'ⲇ', + 'Ⲉ' => 'ⲉ', + 'Ⲋ' => 'ⲋ', + 'Ⲍ' => 'ⲍ', + 'Ⲏ' => 'ⲏ', + 'Ⲑ' => 'ⲑ', + 'Ⲓ' => 'ⲓ', + 'Ⲕ' => 'ⲕ', + 'Ⲗ' => 'ⲗ', + 'Ⲙ' => 'ⲙ', + 'Ⲛ' => 'ⲛ', + 'Ⲝ' => 'ⲝ', + 'Ⲟ' => 'ⲟ', + 'Ⲡ' => 'ⲡ', + 'Ⲣ' => 'ⲣ', + 'Ⲥ' => 'ⲥ', + 'Ⲧ' => 'ⲧ', + 'Ⲩ' => 'ⲩ', + 'Ⲫ' => 'ⲫ', + 'Ⲭ' => 'ⲭ', + 'Ⲯ' => 'ⲯ', + 'Ⲱ' => 'ⲱ', + 'Ⲳ' => 'ⲳ', + 'Ⲵ' => 'ⲵ', + 'Ⲷ' => 'ⲷ', + 'Ⲹ' => 'ⲹ', + 'Ⲻ' => 'ⲻ', + 'Ⲽ' => 'ⲽ', + 'Ⲿ' => 'ⲿ', + 'Ⳁ' => 'ⳁ', + 'Ⳃ' => 'ⳃ', + 'Ⳅ' => 'ⳅ', + 'Ⳇ' => 'ⳇ', + 'Ⳉ' => 'ⳉ', + 'Ⳋ' => 'ⳋ', + 'Ⳍ' => 'ⳍ', + 'Ⳏ' => 'ⳏ', + 'Ⳑ' => 'ⳑ', + 'Ⳓ' => 'ⳓ', + 'Ⳕ' => 'ⳕ', + 'Ⳗ' => 'ⳗ', + 'Ⳙ' => 'ⳙ', + 'Ⳛ' => 'ⳛ', + 'Ⳝ' => 'ⳝ', + 'Ⳟ' => 'ⳟ', + 'Ⳡ' => 'ⳡ', + 'Ⳣ' => 'ⳣ', + 'Ⳬ' => 'ⳬ', + 'Ⳮ' => 'ⳮ', + 'Ⳳ' => 'ⳳ', + 'Ꙁ' => 'ꙁ', + 'Ꙃ' => 'ꙃ', + 'Ꙅ' => 'ꙅ', + 'Ꙇ' => 'ꙇ', + 'Ꙉ' => 'ꙉ', + 'Ꙋ' => 'ꙋ', + 'Ꙍ' => 'ꙍ', + 'Ꙏ' => 'ꙏ', + 'Ꙑ' => 'ꙑ', + 'Ꙓ' => 'ꙓ', + 'Ꙕ' => 'ꙕ', + 'Ꙗ' => 'ꙗ', + 'Ꙙ' => 'ꙙ', + 'Ꙛ' => 'ꙛ', + 'Ꙝ' => 'ꙝ', + 'Ꙟ' => 'ꙟ', + 'Ꙡ' => 'ꙡ', + 'Ꙣ' => 'ꙣ', + 'Ꙥ' => 'ꙥ', + 'Ꙧ' => 'ꙧ', + 'Ꙩ' => 'ꙩ', + 'Ꙫ' => 'ꙫ', + 'Ꙭ' => 'ꙭ', + 'Ꚁ' => 'ꚁ', + 'Ꚃ' => 'ꚃ', + 'Ꚅ' => 'ꚅ', + 'Ꚇ' => 'ꚇ', + 'Ꚉ' => 'ꚉ', + 'Ꚋ' => 'ꚋ', + 'Ꚍ' => 'ꚍ', + 'Ꚏ' => 'ꚏ', + 'Ꚑ' => 'ꚑ', + 'Ꚓ' => 'ꚓ', + 'Ꚕ' => 'ꚕ', + 'Ꚗ' => 'ꚗ', + 'Ꚙ' => 'ꚙ', + 'Ꚛ' => 'ꚛ', + 'Ꜣ' => 'ꜣ', + 'Ꜥ' => 'ꜥ', + 'Ꜧ' => 'ꜧ', + 'Ꜩ' => 'ꜩ', + 'Ꜫ' => 'ꜫ', + 'Ꜭ' => 'ꜭ', + 'Ꜯ' => 'ꜯ', + 'Ꜳ' => 'ꜳ', + 'Ꜵ' => 'ꜵ', + 'Ꜷ' => 'ꜷ', + 'Ꜹ' => 'ꜹ', + 'Ꜻ' => 'ꜻ', + 'Ꜽ' => 'ꜽ', + 'Ꜿ' => 'ꜿ', + 'Ꝁ' => 'ꝁ', + 'Ꝃ' => 'ꝃ', + 'Ꝅ' => 'ꝅ', + 'Ꝇ' => 'ꝇ', + 'Ꝉ' => 'ꝉ', + 'Ꝋ' => 'ꝋ', + 'Ꝍ' => 'ꝍ', + 'Ꝏ' => 'ꝏ', + 'Ꝑ' => 'ꝑ', + 'Ꝓ' => 'ꝓ', + 'Ꝕ' => 'ꝕ', + 'Ꝗ' => 'ꝗ', + 'Ꝙ' => 'ꝙ', + 'Ꝛ' => 'ꝛ', + 'Ꝝ' => 'ꝝ', + 'Ꝟ' => 'ꝟ', + 'Ꝡ' => 'ꝡ', + 'Ꝣ' => 'ꝣ', + 'Ꝥ' => 'ꝥ', + 'Ꝧ' => 'ꝧ', + 'Ꝩ' => 'ꝩ', + 'Ꝫ' => 'ꝫ', + 'Ꝭ' => 'ꝭ', + 'Ꝯ' => 'ꝯ', + 'Ꝺ' => 'ꝺ', + 'Ꝼ' => 'ꝼ', + 'Ᵹ' => 'ᵹ', + 'Ꝿ' => 'ꝿ', + 'Ꞁ' => 'ꞁ', + 'Ꞃ' => 'ꞃ', + 'Ꞅ' => 'ꞅ', + 'Ꞇ' => 'ꞇ', + 'Ꞌ' => 'ꞌ', + 'Ɥ' => 'ɥ', + 'Ꞑ' => 'ꞑ', + 'Ꞓ' => 'ꞓ', + 'Ꞗ' => 'ꞗ', + 'Ꞙ' => 'ꞙ', + 'Ꞛ' => 'ꞛ', + 'Ꞝ' => 'ꞝ', + 'Ꞟ' => 'ꞟ', + 'Ꞡ' => 'ꞡ', + 'Ꞣ' => 'ꞣ', + 'Ꞥ' => 'ꞥ', + 'Ꞧ' => 'ꞧ', + 'Ꞩ' => 'ꞩ', + 'Ɦ' => 'ɦ', + 'Ɜ' => 'ɜ', + 'Ɡ' => 'ɡ', + 'Ɬ' => 'ɬ', + 'Ɪ' => 'ɪ', + 'Ʞ' => 'ʞ', + 'Ʇ' => 'ʇ', + 'Ʝ' => 'ʝ', + 'Ꭓ' => 'ꭓ', + 'Ꞵ' => 'ꞵ', + 'Ꞷ' => 'ꞷ', + 'Ꞹ' => 'ꞹ', + 'Ꞻ' => 'ꞻ', + 'Ꞽ' => 'ꞽ', + 'Ꞿ' => 'ꞿ', + 'Ꟃ' => 'ꟃ', + 'Ꞔ' => 'ꞔ', + 'Ʂ' => 'ʂ', + 'Ᶎ' => 'ᶎ', + 'Ꟈ' => 'ꟈ', + 'Ꟊ' => 'ꟊ', + 'Ꟶ' => 'ꟶ', + 'A' => 'a', + 'B' => 'b', + 'C' => 'c', + 'D' => 'd', + 'E' => 'e', + 'F' => 'f', + 'G' => 'g', + 'H' => 'h', + 'I' => 'i', + 'J' => 'j', + 'K' => 'k', + 'L' => 'l', + 'M' => 'm', + 'N' => 'n', + 'O' => 'o', + 'P' => 'p', + 'Q' => 'q', + 'R' => 'r', + 'S' => 's', + 'T' => 't', + 'U' => 'u', + 'V' => 'v', + 'W' => 'w', + 'X' => 'x', + 'Y' => 'y', + 'Z' => 'z', + '𐐀' => '𐐨', + '𐐁' => '𐐩', + '𐐂' => '𐐪', + '𐐃' => '𐐫', + '𐐄' => '𐐬', + '𐐅' => '𐐭', + '𐐆' => '𐐮', + '𐐇' => '𐐯', + '𐐈' => '𐐰', + '𐐉' => '𐐱', + '𐐊' => '𐐲', + '𐐋' => '𐐳', + '𐐌' => '𐐴', + '𐐍' => '𐐵', + '𐐎' => '𐐶', + '𐐏' => '𐐷', + '𐐐' => '𐐸', + '𐐑' => '𐐹', + '𐐒' => '𐐺', + '𐐓' => '𐐻', + '𐐔' => '𐐼', + '𐐕' => '𐐽', + '𐐖' => '𐐾', + '𐐗' => '𐐿', + '𐐘' => '𐑀', + '𐐙' => '𐑁', + '𐐚' => '𐑂', + '𐐛' => '𐑃', + '𐐜' => '𐑄', + '𐐝' => '𐑅', + '𐐞' => '𐑆', + '𐐟' => '𐑇', + '𐐠' => '𐑈', + '𐐡' => '𐑉', + '𐐢' => '𐑊', + '𐐣' => '𐑋', + '𐐤' => '𐑌', + '𐐥' => '𐑍', + '𐐦' => '𐑎', + '𐐧' => '𐑏', + '𐒰' => '𐓘', + '𐒱' => '𐓙', + '𐒲' => '𐓚', + '𐒳' => '𐓛', + '𐒴' => '𐓜', + '𐒵' => '𐓝', + '𐒶' => '𐓞', + '𐒷' => '𐓟', + '𐒸' => '𐓠', + '𐒹' => '𐓡', + '𐒺' => '𐓢', + '𐒻' => '𐓣', + '𐒼' => '𐓤', + '𐒽' => '𐓥', + '𐒾' => '𐓦', + '𐒿' => '𐓧', + '𐓀' => '𐓨', + '𐓁' => '𐓩', + '𐓂' => '𐓪', + '𐓃' => '𐓫', + '𐓄' => '𐓬', + '𐓅' => '𐓭', + '𐓆' => '𐓮', + '𐓇' => '𐓯', + '𐓈' => '𐓰', + '𐓉' => '𐓱', + '𐓊' => '𐓲', + '𐓋' => '𐓳', + '𐓌' => '𐓴', + '𐓍' => '𐓵', + '𐓎' => '𐓶', + '𐓏' => '𐓷', + '𐓐' => '𐓸', + '𐓑' => '𐓹', + '𐓒' => '𐓺', + '𐓓' => '𐓻', + '𐲀' => '𐳀', + '𐲁' => '𐳁', + '𐲂' => '𐳂', + '𐲃' => '𐳃', + '𐲄' => '𐳄', + '𐲅' => '𐳅', + '𐲆' => '𐳆', + '𐲇' => '𐳇', + '𐲈' => '𐳈', + '𐲉' => '𐳉', + '𐲊' => '𐳊', + '𐲋' => '𐳋', + '𐲌' => '𐳌', + '𐲍' => '𐳍', + '𐲎' => '𐳎', + '𐲏' => '𐳏', + '𐲐' => '𐳐', + '𐲑' => '𐳑', + '𐲒' => '𐳒', + '𐲓' => '𐳓', + '𐲔' => '𐳔', + '𐲕' => '𐳕', + '𐲖' => '𐳖', + '𐲗' => '𐳗', + '𐲘' => '𐳘', + '𐲙' => '𐳙', + '𐲚' => '𐳚', + '𐲛' => '𐳛', + '𐲜' => '𐳜', + '𐲝' => '𐳝', + '𐲞' => '𐳞', + '𐲟' => '𐳟', + '𐲠' => '𐳠', + '𐲡' => '𐳡', + '𐲢' => '𐳢', + '𐲣' => '𐳣', + '𐲤' => '𐳤', + '𐲥' => '𐳥', + '𐲦' => '𐳦', + '𐲧' => '𐳧', + '𐲨' => '𐳨', + '𐲩' => '𐳩', + '𐲪' => '𐳪', + '𐲫' => '𐳫', + '𐲬' => '𐳬', + '𐲭' => '𐳭', + '𐲮' => '𐳮', + '𐲯' => '𐳯', + '𐲰' => '𐳰', + '𐲱' => '𐳱', + '𐲲' => '𐳲', + '𑢠' => '𑣀', + '𑢡' => '𑣁', + '𑢢' => '𑣂', + '𑢣' => '𑣃', + '𑢤' => '𑣄', + '𑢥' => '𑣅', + '𑢦' => '𑣆', + '𑢧' => '𑣇', + '𑢨' => '𑣈', + '𑢩' => '𑣉', + '𑢪' => '𑣊', + '𑢫' => '𑣋', + '𑢬' => '𑣌', + '𑢭' => '𑣍', + '𑢮' => '𑣎', + '𑢯' => '𑣏', + '𑢰' => '𑣐', + '𑢱' => '𑣑', + '𑢲' => '𑣒', + '𑢳' => '𑣓', + '𑢴' => '𑣔', + '𑢵' => '𑣕', + '𑢶' => '𑣖', + '𑢷' => '𑣗', + '𑢸' => '𑣘', + '𑢹' => '𑣙', + '𑢺' => '𑣚', + '𑢻' => '𑣛', + '𑢼' => '𑣜', + '𑢽' => '𑣝', + '𑢾' => '𑣞', + '𑢿' => '𑣟', + '𖹀' => '𖹠', + '𖹁' => '𖹡', + '𖹂' => '𖹢', + '𖹃' => '𖹣', + '𖹄' => '𖹤', + '𖹅' => '𖹥', + '𖹆' => '𖹦', + '𖹇' => '𖹧', + '𖹈' => '𖹨', + '𖹉' => '𖹩', + '𖹊' => '𖹪', + '𖹋' => '𖹫', + '𖹌' => '𖹬', + '𖹍' => '𖹭', + '𖹎' => '𖹮', + '𖹏' => '𖹯', + '𖹐' => '𖹰', + '𖹑' => '𖹱', + '𖹒' => '𖹲', + '𖹓' => '𖹳', + '𖹔' => '𖹴', + '𖹕' => '𖹵', + '𖹖' => '𖹶', + '𖹗' => '𖹷', + '𖹘' => '𖹸', + '𖹙' => '𖹹', + '𖹚' => '𖹺', + '𖹛' => '𖹻', + '𖹜' => '𖹼', + '𖹝' => '𖹽', + '𖹞' => '𖹾', + '𖹟' => '𖹿', + '𞤀' => '𞤢', + '𞤁' => '𞤣', + '𞤂' => '𞤤', + '𞤃' => '𞤥', + '𞤄' => '𞤦', + '𞤅' => '𞤧', + '𞤆' => '𞤨', + '𞤇' => '𞤩', + '𞤈' => '𞤪', + '𞤉' => '𞤫', + '𞤊' => '𞤬', + '𞤋' => '𞤭', + '𞤌' => '𞤮', + '𞤍' => '𞤯', + '𞤎' => '𞤰', + '𞤏' => '𞤱', + '𞤐' => '𞤲', + '𞤑' => '𞤳', + '𞤒' => '𞤴', + '𞤓' => '𞤵', + '𞤔' => '𞤶', + '𞤕' => '𞤷', + '𞤖' => '𞤸', + '𞤗' => '𞤹', + '𞤘' => '𞤺', + '𞤙' => '𞤻', + '𞤚' => '𞤼', + '𞤛' => '𞤽', + '𞤜' => '𞤾', + '𞤝' => '𞤿', + '𞤞' => '𞥀', + '𞤟' => '𞥁', + '𞤠' => '𞥂', + '𞤡' => '𞥃', +); diff --git a/api/vendor/symfony/polyfill-mbstring/Resources/unidata/titleCaseRegexp.php b/api/vendor/symfony/polyfill-mbstring/Resources/unidata/titleCaseRegexp.php new file mode 100644 index 0000000..2a8f6e7 --- /dev/null +++ b/api/vendor/symfony/polyfill-mbstring/Resources/unidata/titleCaseRegexp.php @@ -0,0 +1,5 @@ + 'A', + 'b' => 'B', + 'c' => 'C', + 'd' => 'D', + 'e' => 'E', + 'f' => 'F', + 'g' => 'G', + 'h' => 'H', + 'i' => 'I', + 'j' => 'J', + 'k' => 'K', + 'l' => 'L', + 'm' => 'M', + 'n' => 'N', + 'o' => 'O', + 'p' => 'P', + 'q' => 'Q', + 'r' => 'R', + 's' => 'S', + 't' => 'T', + 'u' => 'U', + 'v' => 'V', + 'w' => 'W', + 'x' => 'X', + 'y' => 'Y', + 'z' => 'Z', + 'µ' => 'Μ', + 'à' => 'À', + 'á' => 'Á', + 'â' => 'Â', + 'ã' => 'Ã', + 'ä' => 'Ä', + 'å' => 'Å', + 'æ' => 'Æ', + 'ç' => 'Ç', + 'è' => 'È', + 'é' => 'É', + 'ê' => 'Ê', + 'ë' => 'Ë', + 'ì' => 'Ì', + 'í' => 'Í', + 'î' => 'Î', + 'ï' => 'Ï', + 'ð' => 'Ð', + 'ñ' => 'Ñ', + 'ò' => 'Ò', + 'ó' => 'Ó', + 'ô' => 'Ô', + 'õ' => 'Õ', + 'ö' => 'Ö', + 'ø' => 'Ø', + 'ù' => 'Ù', + 'ú' => 'Ú', + 'û' => 'Û', + 'ü' => 'Ü', + 'ý' => 'Ý', + 'þ' => 'Þ', + 'ÿ' => 'Ÿ', + 'ā' => 'Ā', + 'ă' => 'Ă', + 'ą' => 'Ą', + 'ć' => 'Ć', + 'ĉ' => 'Ĉ', + 'ċ' => 'Ċ', + 'č' => 'Č', + 'ď' => 'Ď', + 'đ' => 'Đ', + 'ē' => 'Ē', + 'ĕ' => 'Ĕ', + 'ė' => 'Ė', + 'ę' => 'Ę', + 'ě' => 'Ě', + 'ĝ' => 'Ĝ', + 'ğ' => 'Ğ', + 'ġ' => 'Ġ', + 'ģ' => 'Ģ', + 'ĥ' => 'Ĥ', + 'ħ' => 'Ħ', + 'ĩ' => 'Ĩ', + 'ī' => 'Ī', + 'ĭ' => 'Ĭ', + 'į' => 'Į', + 'ı' => 'I', + 'ij' => 'IJ', + 'ĵ' => 'Ĵ', + 'ķ' => 'Ķ', + 'ĺ' => 'Ĺ', + 'ļ' => 'Ļ', + 'ľ' => 'Ľ', + 'ŀ' => 'Ŀ', + 'ł' => 'Ł', + 'ń' => 'Ń', + 'ņ' => 'Ņ', + 'ň' => 'Ň', + 'ŋ' => 'Ŋ', + 'ō' => 'Ō', + 'ŏ' => 'Ŏ', + 'ő' => 'Ő', + 'œ' => 'Œ', + 'ŕ' => 'Ŕ', + 'ŗ' => 'Ŗ', + 'ř' => 'Ř', + 'ś' => 'Ś', + 'ŝ' => 'Ŝ', + 'ş' => 'Ş', + 'š' => 'Š', + 'ţ' => 'Ţ', + 'ť' => 'Ť', + 'ŧ' => 'Ŧ', + 'ũ' => 'Ũ', + 'ū' => 'Ū', + 'ŭ' => 'Ŭ', + 'ů' => 'Ů', + 'ű' => 'Ű', + 'ų' => 'Ų', + 'ŵ' => 'Ŵ', + 'ŷ' => 'Ŷ', + 'ź' => 'Ź', + 'ż' => 'Ż', + 'ž' => 'Ž', + 'ſ' => 'S', + 'ƀ' => 'Ƀ', + 'ƃ' => 'Ƃ', + 'ƅ' => 'Ƅ', + 'ƈ' => 'Ƈ', + 'ƌ' => 'Ƌ', + 'ƒ' => 'Ƒ', + 'ƕ' => 'Ƕ', + 'ƙ' => 'Ƙ', + 'ƚ' => 'Ƚ', + 'ƞ' => 'Ƞ', + 'ơ' => 'Ơ', + 'ƣ' => 'Ƣ', + 'ƥ' => 'Ƥ', + 'ƨ' => 'Ƨ', + 'ƭ' => 'Ƭ', + 'ư' => 'Ư', + 'ƴ' => 'Ƴ', + 'ƶ' => 'Ƶ', + 'ƹ' => 'Ƹ', + 'ƽ' => 'Ƽ', + 'ƿ' => 'Ƿ', + 'Dž' => 'DŽ', + 'dž' => 'DŽ', + 'Lj' => 'LJ', + 'lj' => 'LJ', + 'Nj' => 'NJ', + 'nj' => 'NJ', + 'ǎ' => 'Ǎ', + 'ǐ' => 'Ǐ', + 'ǒ' => 'Ǒ', + 'ǔ' => 'Ǔ', + 'ǖ' => 'Ǖ', + 'ǘ' => 'Ǘ', + 'ǚ' => 'Ǚ', + 'ǜ' => 'Ǜ', + 'ǝ' => 'Ǝ', + 'ǟ' => 'Ǟ', + 'ǡ' => 'Ǡ', + 'ǣ' => 'Ǣ', + 'ǥ' => 'Ǥ', + 'ǧ' => 'Ǧ', + 'ǩ' => 'Ǩ', + 'ǫ' => 'Ǫ', + 'ǭ' => 'Ǭ', + 'ǯ' => 'Ǯ', + 'Dz' => 'DZ', + 'dz' => 'DZ', + 'ǵ' => 'Ǵ', + 'ǹ' => 'Ǹ', + 'ǻ' => 'Ǻ', + 'ǽ' => 'Ǽ', + 'ǿ' => 'Ǿ', + 'ȁ' => 'Ȁ', + 'ȃ' => 'Ȃ', + 'ȅ' => 'Ȅ', + 'ȇ' => 'Ȇ', + 'ȉ' => 'Ȉ', + 'ȋ' => 'Ȋ', + 'ȍ' => 'Ȍ', + 'ȏ' => 'Ȏ', + 'ȑ' => 'Ȑ', + 'ȓ' => 'Ȓ', + 'ȕ' => 'Ȕ', + 'ȗ' => 'Ȗ', + 'ș' => 'Ș', + 'ț' => 'Ț', + 'ȝ' => 'Ȝ', + 'ȟ' => 'Ȟ', + 'ȣ' => 'Ȣ', + 'ȥ' => 'Ȥ', + 'ȧ' => 'Ȧ', + 'ȩ' => 'Ȩ', + 'ȫ' => 'Ȫ', + 'ȭ' => 'Ȭ', + 'ȯ' => 'Ȯ', + 'ȱ' => 'Ȱ', + 'ȳ' => 'Ȳ', + 'ȼ' => 'Ȼ', + 'ȿ' => 'Ȿ', + 'ɀ' => 'Ɀ', + 'ɂ' => 'Ɂ', + 'ɇ' => 'Ɇ', + 'ɉ' => 'Ɉ', + 'ɋ' => 'Ɋ', + 'ɍ' => 'Ɍ', + 'ɏ' => 'Ɏ', + 'ɐ' => 'Ɐ', + 'ɑ' => 'Ɑ', + 'ɒ' => 'Ɒ', + 'ɓ' => 'Ɓ', + 'ɔ' => 'Ɔ', + 'ɖ' => 'Ɖ', + 'ɗ' => 'Ɗ', + 'ə' => 'Ə', + 'ɛ' => 'Ɛ', + 'ɜ' => 'Ɜ', + 'ɠ' => 'Ɠ', + 'ɡ' => 'Ɡ', + 'ɣ' => 'Ɣ', + 'ɥ' => 'Ɥ', + 'ɦ' => 'Ɦ', + 'ɨ' => 'Ɨ', + 'ɩ' => 'Ɩ', + 'ɪ' => 'Ɪ', + 'ɫ' => 'Ɫ', + 'ɬ' => 'Ɬ', + 'ɯ' => 'Ɯ', + 'ɱ' => 'Ɱ', + 'ɲ' => 'Ɲ', + 'ɵ' => 'Ɵ', + 'ɽ' => 'Ɽ', + 'ʀ' => 'Ʀ', + 'ʂ' => 'Ʂ', + 'ʃ' => 'Ʃ', + 'ʇ' => 'Ʇ', + 'ʈ' => 'Ʈ', + 'ʉ' => 'Ʉ', + 'ʊ' => 'Ʊ', + 'ʋ' => 'Ʋ', + 'ʌ' => 'Ʌ', + 'ʒ' => 'Ʒ', + 'ʝ' => 'Ʝ', + 'ʞ' => 'Ʞ', + 'ͅ' => 'Ι', + 'ͱ' => 'Ͱ', + 'ͳ' => 'Ͳ', + 'ͷ' => 'Ͷ', + 'ͻ' => 'Ͻ', + 'ͼ' => 'Ͼ', + 'ͽ' => 'Ͽ', + 'ά' => 'Ά', + 'έ' => 'Έ', + 'ή' => 'Ή', + 'ί' => 'Ί', + 'α' => 'Α', + 'β' => 'Β', + 'γ' => 'Γ', + 'δ' => 'Δ', + 'ε' => 'Ε', + 'ζ' => 'Ζ', + 'η' => 'Η', + 'θ' => 'Θ', + 'ι' => 'Ι', + 'κ' => 'Κ', + 'λ' => 'Λ', + 'μ' => 'Μ', + 'ν' => 'Ν', + 'ξ' => 'Ξ', + 'ο' => 'Ο', + 'π' => 'Π', + 'ρ' => 'Ρ', + 'ς' => 'Σ', + 'σ' => 'Σ', + 'τ' => 'Τ', + 'υ' => 'Υ', + 'φ' => 'Φ', + 'χ' => 'Χ', + 'ψ' => 'Ψ', + 'ω' => 'Ω', + 'ϊ' => 'Ϊ', + 'ϋ' => 'Ϋ', + 'ό' => 'Ό', + 'ύ' => 'Ύ', + 'ώ' => 'Ώ', + 'ϐ' => 'Β', + 'ϑ' => 'Θ', + 'ϕ' => 'Φ', + 'ϖ' => 'Π', + 'ϗ' => 'Ϗ', + 'ϙ' => 'Ϙ', + 'ϛ' => 'Ϛ', + 'ϝ' => 'Ϝ', + 'ϟ' => 'Ϟ', + 'ϡ' => 'Ϡ', + 'ϣ' => 'Ϣ', + 'ϥ' => 'Ϥ', + 'ϧ' => 'Ϧ', + 'ϩ' => 'Ϩ', + 'ϫ' => 'Ϫ', + 'ϭ' => 'Ϭ', + 'ϯ' => 'Ϯ', + 'ϰ' => 'Κ', + 'ϱ' => 'Ρ', + 'ϲ' => 'Ϲ', + 'ϳ' => 'Ϳ', + 'ϵ' => 'Ε', + 'ϸ' => 'Ϸ', + 'ϻ' => 'Ϻ', + 'а' => 'А', + 'б' => 'Б', + 'в' => 'В', + 'г' => 'Г', + 'д' => 'Д', + 'е' => 'Е', + 'ж' => 'Ж', + 'з' => 'З', + 'и' => 'И', + 'й' => 'Й', + 'к' => 'К', + 'л' => 'Л', + 'м' => 'М', + 'н' => 'Н', + 'о' => 'О', + 'п' => 'П', + 'р' => 'Р', + 'с' => 'С', + 'т' => 'Т', + 'у' => 'У', + 'ф' => 'Ф', + 'х' => 'Х', + 'ц' => 'Ц', + 'ч' => 'Ч', + 'ш' => 'Ш', + 'щ' => 'Щ', + 'ъ' => 'Ъ', + 'ы' => 'Ы', + 'ь' => 'Ь', + 'э' => 'Э', + 'ю' => 'Ю', + 'я' => 'Я', + 'ѐ' => 'Ѐ', + 'ё' => 'Ё', + 'ђ' => 'Ђ', + 'ѓ' => 'Ѓ', + 'є' => 'Є', + 'ѕ' => 'Ѕ', + 'і' => 'І', + 'ї' => 'Ї', + 'ј' => 'Ј', + 'љ' => 'Љ', + 'њ' => 'Њ', + 'ћ' => 'Ћ', + 'ќ' => 'Ќ', + 'ѝ' => 'Ѝ', + 'ў' => 'Ў', + 'џ' => 'Џ', + 'ѡ' => 'Ѡ', + 'ѣ' => 'Ѣ', + 'ѥ' => 'Ѥ', + 'ѧ' => 'Ѧ', + 'ѩ' => 'Ѩ', + 'ѫ' => 'Ѫ', + 'ѭ' => 'Ѭ', + 'ѯ' => 'Ѯ', + 'ѱ' => 'Ѱ', + 'ѳ' => 'Ѳ', + 'ѵ' => 'Ѵ', + 'ѷ' => 'Ѷ', + 'ѹ' => 'Ѹ', + 'ѻ' => 'Ѻ', + 'ѽ' => 'Ѽ', + 'ѿ' => 'Ѿ', + 'ҁ' => 'Ҁ', + 'ҋ' => 'Ҋ', + 'ҍ' => 'Ҍ', + 'ҏ' => 'Ҏ', + 'ґ' => 'Ґ', + 'ғ' => 'Ғ', + 'ҕ' => 'Ҕ', + 'җ' => 'Җ', + 'ҙ' => 'Ҙ', + 'қ' => 'Қ', + 'ҝ' => 'Ҝ', + 'ҟ' => 'Ҟ', + 'ҡ' => 'Ҡ', + 'ң' => 'Ң', + 'ҥ' => 'Ҥ', + 'ҧ' => 'Ҧ', + 'ҩ' => 'Ҩ', + 'ҫ' => 'Ҫ', + 'ҭ' => 'Ҭ', + 'ү' => 'Ү', + 'ұ' => 'Ұ', + 'ҳ' => 'Ҳ', + 'ҵ' => 'Ҵ', + 'ҷ' => 'Ҷ', + 'ҹ' => 'Ҹ', + 'һ' => 'Һ', + 'ҽ' => 'Ҽ', + 'ҿ' => 'Ҿ', + 'ӂ' => 'Ӂ', + 'ӄ' => 'Ӄ', + 'ӆ' => 'Ӆ', + 'ӈ' => 'Ӈ', + 'ӊ' => 'Ӊ', + 'ӌ' => 'Ӌ', + 'ӎ' => 'Ӎ', + 'ӏ' => 'Ӏ', + 'ӑ' => 'Ӑ', + 'ӓ' => 'Ӓ', + 'ӕ' => 'Ӕ', + 'ӗ' => 'Ӗ', + 'ә' => 'Ә', + 'ӛ' => 'Ӛ', + 'ӝ' => 'Ӝ', + 'ӟ' => 'Ӟ', + 'ӡ' => 'Ӡ', + 'ӣ' => 'Ӣ', + 'ӥ' => 'Ӥ', + 'ӧ' => 'Ӧ', + 'ө' => 'Ө', + 'ӫ' => 'Ӫ', + 'ӭ' => 'Ӭ', + 'ӯ' => 'Ӯ', + 'ӱ' => 'Ӱ', + 'ӳ' => 'Ӳ', + 'ӵ' => 'Ӵ', + 'ӷ' => 'Ӷ', + 'ӹ' => 'Ӹ', + 'ӻ' => 'Ӻ', + 'ӽ' => 'Ӽ', + 'ӿ' => 'Ӿ', + 'ԁ' => 'Ԁ', + 'ԃ' => 'Ԃ', + 'ԅ' => 'Ԅ', + 'ԇ' => 'Ԇ', + 'ԉ' => 'Ԉ', + 'ԋ' => 'Ԋ', + 'ԍ' => 'Ԍ', + 'ԏ' => 'Ԏ', + 'ԑ' => 'Ԑ', + 'ԓ' => 'Ԓ', + 'ԕ' => 'Ԕ', + 'ԗ' => 'Ԗ', + 'ԙ' => 'Ԙ', + 'ԛ' => 'Ԛ', + 'ԝ' => 'Ԝ', + 'ԟ' => 'Ԟ', + 'ԡ' => 'Ԡ', + 'ԣ' => 'Ԣ', + 'ԥ' => 'Ԥ', + 'ԧ' => 'Ԧ', + 'ԩ' => 'Ԩ', + 'ԫ' => 'Ԫ', + 'ԭ' => 'Ԭ', + 'ԯ' => 'Ԯ', + 'ա' => 'Ա', + 'բ' => 'Բ', + 'գ' => 'Գ', + 'դ' => 'Դ', + 'ե' => 'Ե', + 'զ' => 'Զ', + 'է' => 'Է', + 'ը' => 'Ը', + 'թ' => 'Թ', + 'ժ' => 'Ժ', + 'ի' => 'Ի', + 'լ' => 'Լ', + 'խ' => 'Խ', + 'ծ' => 'Ծ', + 'կ' => 'Կ', + 'հ' => 'Հ', + 'ձ' => 'Ձ', + 'ղ' => 'Ղ', + 'ճ' => 'Ճ', + 'մ' => 'Մ', + 'յ' => 'Յ', + 'ն' => 'Ն', + 'շ' => 'Շ', + 'ո' => 'Ո', + 'չ' => 'Չ', + 'պ' => 'Պ', + 'ջ' => 'Ջ', + 'ռ' => 'Ռ', + 'ս' => 'Ս', + 'վ' => 'Վ', + 'տ' => 'Տ', + 'ր' => 'Ր', + 'ց' => 'Ց', + 'ւ' => 'Ւ', + 'փ' => 'Փ', + 'ք' => 'Ք', + 'օ' => 'Օ', + 'ֆ' => 'Ֆ', + 'ა' => 'Ა', + 'ბ' => 'Ბ', + 'გ' => 'Გ', + 'დ' => 'Დ', + 'ე' => 'Ე', + 'ვ' => 'Ვ', + 'ზ' => 'Ზ', + 'თ' => 'Თ', + 'ი' => 'Ი', + 'კ' => 'Კ', + 'ლ' => 'Ლ', + 'მ' => 'Მ', + 'ნ' => 'Ნ', + 'ო' => 'Ო', + 'პ' => 'Პ', + 'ჟ' => 'Ჟ', + 'რ' => 'Რ', + 'ს' => 'Ს', + 'ტ' => 'Ტ', + 'უ' => 'Უ', + 'ფ' => 'Ფ', + 'ქ' => 'Ქ', + 'ღ' => 'Ღ', + 'ყ' => 'Ყ', + 'შ' => 'Შ', + 'ჩ' => 'Ჩ', + 'ც' => 'Ც', + 'ძ' => 'Ძ', + 'წ' => 'Წ', + 'ჭ' => 'Ჭ', + 'ხ' => 'Ხ', + 'ჯ' => 'Ჯ', + 'ჰ' => 'Ჰ', + 'ჱ' => 'Ჱ', + 'ჲ' => 'Ჲ', + 'ჳ' => 'Ჳ', + 'ჴ' => 'Ჴ', + 'ჵ' => 'Ჵ', + 'ჶ' => 'Ჶ', + 'ჷ' => 'Ჷ', + 'ჸ' => 'Ჸ', + 'ჹ' => 'Ჹ', + 'ჺ' => 'Ჺ', + 'ჽ' => 'Ჽ', + 'ჾ' => 'Ჾ', + 'ჿ' => 'Ჿ', + 'ᏸ' => 'Ᏸ', + 'ᏹ' => 'Ᏹ', + 'ᏺ' => 'Ᏺ', + 'ᏻ' => 'Ᏻ', + 'ᏼ' => 'Ᏼ', + 'ᏽ' => 'Ᏽ', + 'ᲀ' => 'В', + 'ᲁ' => 'Д', + 'ᲂ' => 'О', + 'ᲃ' => 'С', + 'ᲄ' => 'Т', + 'ᲅ' => 'Т', + 'ᲆ' => 'Ъ', + 'ᲇ' => 'Ѣ', + 'ᲈ' => 'Ꙋ', + 'ᵹ' => 'Ᵹ', + 'ᵽ' => 'Ᵽ', + 'ᶎ' => 'Ᶎ', + 'ḁ' => 'Ḁ', + 'ḃ' => 'Ḃ', + 'ḅ' => 'Ḅ', + 'ḇ' => 'Ḇ', + 'ḉ' => 'Ḉ', + 'ḋ' => 'Ḋ', + 'ḍ' => 'Ḍ', + 'ḏ' => 'Ḏ', + 'ḑ' => 'Ḑ', + 'ḓ' => 'Ḓ', + 'ḕ' => 'Ḕ', + 'ḗ' => 'Ḗ', + 'ḙ' => 'Ḙ', + 'ḛ' => 'Ḛ', + 'ḝ' => 'Ḝ', + 'ḟ' => 'Ḟ', + 'ḡ' => 'Ḡ', + 'ḣ' => 'Ḣ', + 'ḥ' => 'Ḥ', + 'ḧ' => 'Ḧ', + 'ḩ' => 'Ḩ', + 'ḫ' => 'Ḫ', + 'ḭ' => 'Ḭ', + 'ḯ' => 'Ḯ', + 'ḱ' => 'Ḱ', + 'ḳ' => 'Ḳ', + 'ḵ' => 'Ḵ', + 'ḷ' => 'Ḷ', + 'ḹ' => 'Ḹ', + 'ḻ' => 'Ḻ', + 'ḽ' => 'Ḽ', + 'ḿ' => 'Ḿ', + 'ṁ' => 'Ṁ', + 'ṃ' => 'Ṃ', + 'ṅ' => 'Ṅ', + 'ṇ' => 'Ṇ', + 'ṉ' => 'Ṉ', + 'ṋ' => 'Ṋ', + 'ṍ' => 'Ṍ', + 'ṏ' => 'Ṏ', + 'ṑ' => 'Ṑ', + 'ṓ' => 'Ṓ', + 'ṕ' => 'Ṕ', + 'ṗ' => 'Ṗ', + 'ṙ' => 'Ṙ', + 'ṛ' => 'Ṛ', + 'ṝ' => 'Ṝ', + 'ṟ' => 'Ṟ', + 'ṡ' => 'Ṡ', + 'ṣ' => 'Ṣ', + 'ṥ' => 'Ṥ', + 'ṧ' => 'Ṧ', + 'ṩ' => 'Ṩ', + 'ṫ' => 'Ṫ', + 'ṭ' => 'Ṭ', + 'ṯ' => 'Ṯ', + 'ṱ' => 'Ṱ', + 'ṳ' => 'Ṳ', + 'ṵ' => 'Ṵ', + 'ṷ' => 'Ṷ', + 'ṹ' => 'Ṹ', + 'ṻ' => 'Ṻ', + 'ṽ' => 'Ṽ', + 'ṿ' => 'Ṿ', + 'ẁ' => 'Ẁ', + 'ẃ' => 'Ẃ', + 'ẅ' => 'Ẅ', + 'ẇ' => 'Ẇ', + 'ẉ' => 'Ẉ', + 'ẋ' => 'Ẋ', + 'ẍ' => 'Ẍ', + 'ẏ' => 'Ẏ', + 'ẑ' => 'Ẑ', + 'ẓ' => 'Ẓ', + 'ẕ' => 'Ẕ', + 'ẛ' => 'Ṡ', + 'ạ' => 'Ạ', + 'ả' => 'Ả', + 'ấ' => 'Ấ', + 'ầ' => 'Ầ', + 'ẩ' => 'Ẩ', + 'ẫ' => 'Ẫ', + 'ậ' => 'Ậ', + 'ắ' => 'Ắ', + 'ằ' => 'Ằ', + 'ẳ' => 'Ẳ', + 'ẵ' => 'Ẵ', + 'ặ' => 'Ặ', + 'ẹ' => 'Ẹ', + 'ẻ' => 'Ẻ', + 'ẽ' => 'Ẽ', + 'ế' => 'Ế', + 'ề' => 'Ề', + 'ể' => 'Ể', + 'ễ' => 'Ễ', + 'ệ' => 'Ệ', + 'ỉ' => 'Ỉ', + 'ị' => 'Ị', + 'ọ' => 'Ọ', + 'ỏ' => 'Ỏ', + 'ố' => 'Ố', + 'ồ' => 'Ồ', + 'ổ' => 'Ổ', + 'ỗ' => 'Ỗ', + 'ộ' => 'Ộ', + 'ớ' => 'Ớ', + 'ờ' => 'Ờ', + 'ở' => 'Ở', + 'ỡ' => 'Ỡ', + 'ợ' => 'Ợ', + 'ụ' => 'Ụ', + 'ủ' => 'Ủ', + 'ứ' => 'Ứ', + 'ừ' => 'Ừ', + 'ử' => 'Ử', + 'ữ' => 'Ữ', + 'ự' => 'Ự', + 'ỳ' => 'Ỳ', + 'ỵ' => 'Ỵ', + 'ỷ' => 'Ỷ', + 'ỹ' => 'Ỹ', + 'ỻ' => 'Ỻ', + 'ỽ' => 'Ỽ', + 'ỿ' => 'Ỿ', + 'ἀ' => 'Ἀ', + 'ἁ' => 'Ἁ', + 'ἂ' => 'Ἂ', + 'ἃ' => 'Ἃ', + 'ἄ' => 'Ἄ', + 'ἅ' => 'Ἅ', + 'ἆ' => 'Ἆ', + 'ἇ' => 'Ἇ', + 'ἐ' => 'Ἐ', + 'ἑ' => 'Ἑ', + 'ἒ' => 'Ἒ', + 'ἓ' => 'Ἓ', + 'ἔ' => 'Ἔ', + 'ἕ' => 'Ἕ', + 'ἠ' => 'Ἠ', + 'ἡ' => 'Ἡ', + 'ἢ' => 'Ἢ', + 'ἣ' => 'Ἣ', + 'ἤ' => 'Ἤ', + 'ἥ' => 'Ἥ', + 'ἦ' => 'Ἦ', + 'ἧ' => 'Ἧ', + 'ἰ' => 'Ἰ', + 'ἱ' => 'Ἱ', + 'ἲ' => 'Ἲ', + 'ἳ' => 'Ἳ', + 'ἴ' => 'Ἴ', + 'ἵ' => 'Ἵ', + 'ἶ' => 'Ἶ', + 'ἷ' => 'Ἷ', + 'ὀ' => 'Ὀ', + 'ὁ' => 'Ὁ', + 'ὂ' => 'Ὂ', + 'ὃ' => 'Ὃ', + 'ὄ' => 'Ὄ', + 'ὅ' => 'Ὅ', + 'ὑ' => 'Ὑ', + 'ὓ' => 'Ὓ', + 'ὕ' => 'Ὕ', + 'ὗ' => 'Ὗ', + 'ὠ' => 'Ὠ', + 'ὡ' => 'Ὡ', + 'ὢ' => 'Ὢ', + 'ὣ' => 'Ὣ', + 'ὤ' => 'Ὤ', + 'ὥ' => 'Ὥ', + 'ὦ' => 'Ὦ', + 'ὧ' => 'Ὧ', + 'ὰ' => 'Ὰ', + 'ά' => 'Ά', + 'ὲ' => 'Ὲ', + 'έ' => 'Έ', + 'ὴ' => 'Ὴ', + 'ή' => 'Ή', + 'ὶ' => 'Ὶ', + 'ί' => 'Ί', + 'ὸ' => 'Ὸ', + 'ό' => 'Ό', + 'ὺ' => 'Ὺ', + 'ύ' => 'Ύ', + 'ὼ' => 'Ὼ', + 'ώ' => 'Ώ', + 'ᾀ' => 'ἈΙ', + 'ᾁ' => 'ἉΙ', + 'ᾂ' => 'ἊΙ', + 'ᾃ' => 'ἋΙ', + 'ᾄ' => 'ἌΙ', + 'ᾅ' => 'ἍΙ', + 'ᾆ' => 'ἎΙ', + 'ᾇ' => 'ἏΙ', + 'ᾐ' => 'ἨΙ', + 'ᾑ' => 'ἩΙ', + 'ᾒ' => 'ἪΙ', + 'ᾓ' => 'ἫΙ', + 'ᾔ' => 'ἬΙ', + 'ᾕ' => 'ἭΙ', + 'ᾖ' => 'ἮΙ', + 'ᾗ' => 'ἯΙ', + 'ᾠ' => 'ὨΙ', + 'ᾡ' => 'ὩΙ', + 'ᾢ' => 'ὪΙ', + 'ᾣ' => 'ὫΙ', + 'ᾤ' => 'ὬΙ', + 'ᾥ' => 'ὭΙ', + 'ᾦ' => 'ὮΙ', + 'ᾧ' => 'ὯΙ', + 'ᾰ' => 'Ᾰ', + 'ᾱ' => 'Ᾱ', + 'ᾳ' => 'ΑΙ', + 'ι' => 'Ι', + 'ῃ' => 'ΗΙ', + 'ῐ' => 'Ῐ', + 'ῑ' => 'Ῑ', + 'ῠ' => 'Ῠ', + 'ῡ' => 'Ῡ', + 'ῥ' => 'Ῥ', + 'ῳ' => 'ΩΙ', + 'ⅎ' => 'Ⅎ', + 'ⅰ' => 'Ⅰ', + 'ⅱ' => 'Ⅱ', + 'ⅲ' => 'Ⅲ', + 'ⅳ' => 'Ⅳ', + 'ⅴ' => 'Ⅴ', + 'ⅵ' => 'Ⅵ', + 'ⅶ' => 'Ⅶ', + 'ⅷ' => 'Ⅷ', + 'ⅸ' => 'Ⅸ', + 'ⅹ' => 'Ⅹ', + 'ⅺ' => 'Ⅺ', + 'ⅻ' => 'Ⅻ', + 'ⅼ' => 'Ⅼ', + 'ⅽ' => 'Ⅽ', + 'ⅾ' => 'Ⅾ', + 'ⅿ' => 'Ⅿ', + 'ↄ' => 'Ↄ', + 'ⓐ' => 'Ⓐ', + 'ⓑ' => 'Ⓑ', + 'ⓒ' => 'Ⓒ', + 'ⓓ' => 'Ⓓ', + 'ⓔ' => 'Ⓔ', + 'ⓕ' => 'Ⓕ', + 'ⓖ' => 'Ⓖ', + 'ⓗ' => 'Ⓗ', + 'ⓘ' => 'Ⓘ', + 'ⓙ' => 'Ⓙ', + 'ⓚ' => 'Ⓚ', + 'ⓛ' => 'Ⓛ', + 'ⓜ' => 'Ⓜ', + 'ⓝ' => 'Ⓝ', + 'ⓞ' => 'Ⓞ', + 'ⓟ' => 'Ⓟ', + 'ⓠ' => 'Ⓠ', + 'ⓡ' => 'Ⓡ', + 'ⓢ' => 'Ⓢ', + 'ⓣ' => 'Ⓣ', + 'ⓤ' => 'Ⓤ', + 'ⓥ' => 'Ⓥ', + 'ⓦ' => 'Ⓦ', + 'ⓧ' => 'Ⓧ', + 'ⓨ' => 'Ⓨ', + 'ⓩ' => 'Ⓩ', + 'ⰰ' => 'Ⰰ', + 'ⰱ' => 'Ⰱ', + 'ⰲ' => 'Ⰲ', + 'ⰳ' => 'Ⰳ', + 'ⰴ' => 'Ⰴ', + 'ⰵ' => 'Ⰵ', + 'ⰶ' => 'Ⰶ', + 'ⰷ' => 'Ⰷ', + 'ⰸ' => 'Ⰸ', + 'ⰹ' => 'Ⰹ', + 'ⰺ' => 'Ⰺ', + 'ⰻ' => 'Ⰻ', + 'ⰼ' => 'Ⰼ', + 'ⰽ' => 'Ⰽ', + 'ⰾ' => 'Ⰾ', + 'ⰿ' => 'Ⰿ', + 'ⱀ' => 'Ⱀ', + 'ⱁ' => 'Ⱁ', + 'ⱂ' => 'Ⱂ', + 'ⱃ' => 'Ⱃ', + 'ⱄ' => 'Ⱄ', + 'ⱅ' => 'Ⱅ', + 'ⱆ' => 'Ⱆ', + 'ⱇ' => 'Ⱇ', + 'ⱈ' => 'Ⱈ', + 'ⱉ' => 'Ⱉ', + 'ⱊ' => 'Ⱊ', + 'ⱋ' => 'Ⱋ', + 'ⱌ' => 'Ⱌ', + 'ⱍ' => 'Ⱍ', + 'ⱎ' => 'Ⱎ', + 'ⱏ' => 'Ⱏ', + 'ⱐ' => 'Ⱐ', + 'ⱑ' => 'Ⱑ', + 'ⱒ' => 'Ⱒ', + 'ⱓ' => 'Ⱓ', + 'ⱔ' => 'Ⱔ', + 'ⱕ' => 'Ⱕ', + 'ⱖ' => 'Ⱖ', + 'ⱗ' => 'Ⱗ', + 'ⱘ' => 'Ⱘ', + 'ⱙ' => 'Ⱙ', + 'ⱚ' => 'Ⱚ', + 'ⱛ' => 'Ⱛ', + 'ⱜ' => 'Ⱜ', + 'ⱝ' => 'Ⱝ', + 'ⱞ' => 'Ⱞ', + 'ⱡ' => 'Ⱡ', + 'ⱥ' => 'Ⱥ', + 'ⱦ' => 'Ⱦ', + 'ⱨ' => 'Ⱨ', + 'ⱪ' => 'Ⱪ', + 'ⱬ' => 'Ⱬ', + 'ⱳ' => 'Ⱳ', + 'ⱶ' => 'Ⱶ', + 'ⲁ' => 'Ⲁ', + 'ⲃ' => 'Ⲃ', + 'ⲅ' => 'Ⲅ', + 'ⲇ' => 'Ⲇ', + 'ⲉ' => 'Ⲉ', + 'ⲋ' => 'Ⲋ', + 'ⲍ' => 'Ⲍ', + 'ⲏ' => 'Ⲏ', + 'ⲑ' => 'Ⲑ', + 'ⲓ' => 'Ⲓ', + 'ⲕ' => 'Ⲕ', + 'ⲗ' => 'Ⲗ', + 'ⲙ' => 'Ⲙ', + 'ⲛ' => 'Ⲛ', + 'ⲝ' => 'Ⲝ', + 'ⲟ' => 'Ⲟ', + 'ⲡ' => 'Ⲡ', + 'ⲣ' => 'Ⲣ', + 'ⲥ' => 'Ⲥ', + 'ⲧ' => 'Ⲧ', + 'ⲩ' => 'Ⲩ', + 'ⲫ' => 'Ⲫ', + 'ⲭ' => 'Ⲭ', + 'ⲯ' => 'Ⲯ', + 'ⲱ' => 'Ⲱ', + 'ⲳ' => 'Ⲳ', + 'ⲵ' => 'Ⲵ', + 'ⲷ' => 'Ⲷ', + 'ⲹ' => 'Ⲹ', + 'ⲻ' => 'Ⲻ', + 'ⲽ' => 'Ⲽ', + 'ⲿ' => 'Ⲿ', + 'ⳁ' => 'Ⳁ', + 'ⳃ' => 'Ⳃ', + 'ⳅ' => 'Ⳅ', + 'ⳇ' => 'Ⳇ', + 'ⳉ' => 'Ⳉ', + 'ⳋ' => 'Ⳋ', + 'ⳍ' => 'Ⳍ', + 'ⳏ' => 'Ⳏ', + 'ⳑ' => 'Ⳑ', + 'ⳓ' => 'Ⳓ', + 'ⳕ' => 'Ⳕ', + 'ⳗ' => 'Ⳗ', + 'ⳙ' => 'Ⳙ', + 'ⳛ' => 'Ⳛ', + 'ⳝ' => 'Ⳝ', + 'ⳟ' => 'Ⳟ', + 'ⳡ' => 'Ⳡ', + 'ⳣ' => 'Ⳣ', + 'ⳬ' => 'Ⳬ', + 'ⳮ' => 'Ⳮ', + 'ⳳ' => 'Ⳳ', + 'ⴀ' => 'Ⴀ', + 'ⴁ' => 'Ⴁ', + 'ⴂ' => 'Ⴂ', + 'ⴃ' => 'Ⴃ', + 'ⴄ' => 'Ⴄ', + 'ⴅ' => 'Ⴅ', + 'ⴆ' => 'Ⴆ', + 'ⴇ' => 'Ⴇ', + 'ⴈ' => 'Ⴈ', + 'ⴉ' => 'Ⴉ', + 'ⴊ' => 'Ⴊ', + 'ⴋ' => 'Ⴋ', + 'ⴌ' => 'Ⴌ', + 'ⴍ' => 'Ⴍ', + 'ⴎ' => 'Ⴎ', + 'ⴏ' => 'Ⴏ', + 'ⴐ' => 'Ⴐ', + 'ⴑ' => 'Ⴑ', + 'ⴒ' => 'Ⴒ', + 'ⴓ' => 'Ⴓ', + 'ⴔ' => 'Ⴔ', + 'ⴕ' => 'Ⴕ', + 'ⴖ' => 'Ⴖ', + 'ⴗ' => 'Ⴗ', + 'ⴘ' => 'Ⴘ', + 'ⴙ' => 'Ⴙ', + 'ⴚ' => 'Ⴚ', + 'ⴛ' => 'Ⴛ', + 'ⴜ' => 'Ⴜ', + 'ⴝ' => 'Ⴝ', + 'ⴞ' => 'Ⴞ', + 'ⴟ' => 'Ⴟ', + 'ⴠ' => 'Ⴠ', + 'ⴡ' => 'Ⴡ', + 'ⴢ' => 'Ⴢ', + 'ⴣ' => 'Ⴣ', + 'ⴤ' => 'Ⴤ', + 'ⴥ' => 'Ⴥ', + 'ⴧ' => 'Ⴧ', + 'ⴭ' => 'Ⴭ', + 'ꙁ' => 'Ꙁ', + 'ꙃ' => 'Ꙃ', + 'ꙅ' => 'Ꙅ', + 'ꙇ' => 'Ꙇ', + 'ꙉ' => 'Ꙉ', + 'ꙋ' => 'Ꙋ', + 'ꙍ' => 'Ꙍ', + 'ꙏ' => 'Ꙏ', + 'ꙑ' => 'Ꙑ', + 'ꙓ' => 'Ꙓ', + 'ꙕ' => 'Ꙕ', + 'ꙗ' => 'Ꙗ', + 'ꙙ' => 'Ꙙ', + 'ꙛ' => 'Ꙛ', + 'ꙝ' => 'Ꙝ', + 'ꙟ' => 'Ꙟ', + 'ꙡ' => 'Ꙡ', + 'ꙣ' => 'Ꙣ', + 'ꙥ' => 'Ꙥ', + 'ꙧ' => 'Ꙧ', + 'ꙩ' => 'Ꙩ', + 'ꙫ' => 'Ꙫ', + 'ꙭ' => 'Ꙭ', + 'ꚁ' => 'Ꚁ', + 'ꚃ' => 'Ꚃ', + 'ꚅ' => 'Ꚅ', + 'ꚇ' => 'Ꚇ', + 'ꚉ' => 'Ꚉ', + 'ꚋ' => 'Ꚋ', + 'ꚍ' => 'Ꚍ', + 'ꚏ' => 'Ꚏ', + 'ꚑ' => 'Ꚑ', + 'ꚓ' => 'Ꚓ', + 'ꚕ' => 'Ꚕ', + 'ꚗ' => 'Ꚗ', + 'ꚙ' => 'Ꚙ', + 'ꚛ' => 'Ꚛ', + 'ꜣ' => 'Ꜣ', + 'ꜥ' => 'Ꜥ', + 'ꜧ' => 'Ꜧ', + 'ꜩ' => 'Ꜩ', + 'ꜫ' => 'Ꜫ', + 'ꜭ' => 'Ꜭ', + 'ꜯ' => 'Ꜯ', + 'ꜳ' => 'Ꜳ', + 'ꜵ' => 'Ꜵ', + 'ꜷ' => 'Ꜷ', + 'ꜹ' => 'Ꜹ', + 'ꜻ' => 'Ꜻ', + 'ꜽ' => 'Ꜽ', + 'ꜿ' => 'Ꜿ', + 'ꝁ' => 'Ꝁ', + 'ꝃ' => 'Ꝃ', + 'ꝅ' => 'Ꝅ', + 'ꝇ' => 'Ꝇ', + 'ꝉ' => 'Ꝉ', + 'ꝋ' => 'Ꝋ', + 'ꝍ' => 'Ꝍ', + 'ꝏ' => 'Ꝏ', + 'ꝑ' => 'Ꝑ', + 'ꝓ' => 'Ꝓ', + 'ꝕ' => 'Ꝕ', + 'ꝗ' => 'Ꝗ', + 'ꝙ' => 'Ꝙ', + 'ꝛ' => 'Ꝛ', + 'ꝝ' => 'Ꝝ', + 'ꝟ' => 'Ꝟ', + 'ꝡ' => 'Ꝡ', + 'ꝣ' => 'Ꝣ', + 'ꝥ' => 'Ꝥ', + 'ꝧ' => 'Ꝧ', + 'ꝩ' => 'Ꝩ', + 'ꝫ' => 'Ꝫ', + 'ꝭ' => 'Ꝭ', + 'ꝯ' => 'Ꝯ', + 'ꝺ' => 'Ꝺ', + 'ꝼ' => 'Ꝼ', + 'ꝿ' => 'Ꝿ', + 'ꞁ' => 'Ꞁ', + 'ꞃ' => 'Ꞃ', + 'ꞅ' => 'Ꞅ', + 'ꞇ' => 'Ꞇ', + 'ꞌ' => 'Ꞌ', + 'ꞑ' => 'Ꞑ', + 'ꞓ' => 'Ꞓ', + 'ꞔ' => 'Ꞔ', + 'ꞗ' => 'Ꞗ', + 'ꞙ' => 'Ꞙ', + 'ꞛ' => 'Ꞛ', + 'ꞝ' => 'Ꞝ', + 'ꞟ' => 'Ꞟ', + 'ꞡ' => 'Ꞡ', + 'ꞣ' => 'Ꞣ', + 'ꞥ' => 'Ꞥ', + 'ꞧ' => 'Ꞧ', + 'ꞩ' => 'Ꞩ', + 'ꞵ' => 'Ꞵ', + 'ꞷ' => 'Ꞷ', + 'ꞹ' => 'Ꞹ', + 'ꞻ' => 'Ꞻ', + 'ꞽ' => 'Ꞽ', + 'ꞿ' => 'Ꞿ', + 'ꟃ' => 'Ꟃ', + 'ꟈ' => 'Ꟈ', + 'ꟊ' => 'Ꟊ', + 'ꟶ' => 'Ꟶ', + 'ꭓ' => 'Ꭓ', + 'ꭰ' => 'Ꭰ', + 'ꭱ' => 'Ꭱ', + 'ꭲ' => 'Ꭲ', + 'ꭳ' => 'Ꭳ', + 'ꭴ' => 'Ꭴ', + 'ꭵ' => 'Ꭵ', + 'ꭶ' => 'Ꭶ', + 'ꭷ' => 'Ꭷ', + 'ꭸ' => 'Ꭸ', + 'ꭹ' => 'Ꭹ', + 'ꭺ' => 'Ꭺ', + 'ꭻ' => 'Ꭻ', + 'ꭼ' => 'Ꭼ', + 'ꭽ' => 'Ꭽ', + 'ꭾ' => 'Ꭾ', + 'ꭿ' => 'Ꭿ', + 'ꮀ' => 'Ꮀ', + 'ꮁ' => 'Ꮁ', + 'ꮂ' => 'Ꮂ', + 'ꮃ' => 'Ꮃ', + 'ꮄ' => 'Ꮄ', + 'ꮅ' => 'Ꮅ', + 'ꮆ' => 'Ꮆ', + 'ꮇ' => 'Ꮇ', + 'ꮈ' => 'Ꮈ', + 'ꮉ' => 'Ꮉ', + 'ꮊ' => 'Ꮊ', + 'ꮋ' => 'Ꮋ', + 'ꮌ' => 'Ꮌ', + 'ꮍ' => 'Ꮍ', + 'ꮎ' => 'Ꮎ', + 'ꮏ' => 'Ꮏ', + 'ꮐ' => 'Ꮐ', + 'ꮑ' => 'Ꮑ', + 'ꮒ' => 'Ꮒ', + 'ꮓ' => 'Ꮓ', + 'ꮔ' => 'Ꮔ', + 'ꮕ' => 'Ꮕ', + 'ꮖ' => 'Ꮖ', + 'ꮗ' => 'Ꮗ', + 'ꮘ' => 'Ꮘ', + 'ꮙ' => 'Ꮙ', + 'ꮚ' => 'Ꮚ', + 'ꮛ' => 'Ꮛ', + 'ꮜ' => 'Ꮜ', + 'ꮝ' => 'Ꮝ', + 'ꮞ' => 'Ꮞ', + 'ꮟ' => 'Ꮟ', + 'ꮠ' => 'Ꮠ', + 'ꮡ' => 'Ꮡ', + 'ꮢ' => 'Ꮢ', + 'ꮣ' => 'Ꮣ', + 'ꮤ' => 'Ꮤ', + 'ꮥ' => 'Ꮥ', + 'ꮦ' => 'Ꮦ', + 'ꮧ' => 'Ꮧ', + 'ꮨ' => 'Ꮨ', + 'ꮩ' => 'Ꮩ', + 'ꮪ' => 'Ꮪ', + 'ꮫ' => 'Ꮫ', + 'ꮬ' => 'Ꮬ', + 'ꮭ' => 'Ꮭ', + 'ꮮ' => 'Ꮮ', + 'ꮯ' => 'Ꮯ', + 'ꮰ' => 'Ꮰ', + 'ꮱ' => 'Ꮱ', + 'ꮲ' => 'Ꮲ', + 'ꮳ' => 'Ꮳ', + 'ꮴ' => 'Ꮴ', + 'ꮵ' => 'Ꮵ', + 'ꮶ' => 'Ꮶ', + 'ꮷ' => 'Ꮷ', + 'ꮸ' => 'Ꮸ', + 'ꮹ' => 'Ꮹ', + 'ꮺ' => 'Ꮺ', + 'ꮻ' => 'Ꮻ', + 'ꮼ' => 'Ꮼ', + 'ꮽ' => 'Ꮽ', + 'ꮾ' => 'Ꮾ', + 'ꮿ' => 'Ꮿ', + 'a' => 'A', + 'b' => 'B', + 'c' => 'C', + 'd' => 'D', + 'e' => 'E', + 'f' => 'F', + 'g' => 'G', + 'h' => 'H', + 'i' => 'I', + 'j' => 'J', + 'k' => 'K', + 'l' => 'L', + 'm' => 'M', + 'n' => 'N', + 'o' => 'O', + 'p' => 'P', + 'q' => 'Q', + 'r' => 'R', + 's' => 'S', + 't' => 'T', + 'u' => 'U', + 'v' => 'V', + 'w' => 'W', + 'x' => 'X', + 'y' => 'Y', + 'z' => 'Z', + '𐐨' => '𐐀', + '𐐩' => '𐐁', + '𐐪' => '𐐂', + '𐐫' => '𐐃', + '𐐬' => '𐐄', + '𐐭' => '𐐅', + '𐐮' => '𐐆', + '𐐯' => '𐐇', + '𐐰' => '𐐈', + '𐐱' => '𐐉', + '𐐲' => '𐐊', + '𐐳' => '𐐋', + '𐐴' => '𐐌', + '𐐵' => '𐐍', + '𐐶' => '𐐎', + '𐐷' => '𐐏', + '𐐸' => '𐐐', + '𐐹' => '𐐑', + '𐐺' => '𐐒', + '𐐻' => '𐐓', + '𐐼' => '𐐔', + '𐐽' => '𐐕', + '𐐾' => '𐐖', + '𐐿' => '𐐗', + '𐑀' => '𐐘', + '𐑁' => '𐐙', + '𐑂' => '𐐚', + '𐑃' => '𐐛', + '𐑄' => '𐐜', + '𐑅' => '𐐝', + '𐑆' => '𐐞', + '𐑇' => '𐐟', + '𐑈' => '𐐠', + '𐑉' => '𐐡', + '𐑊' => '𐐢', + '𐑋' => '𐐣', + '𐑌' => '𐐤', + '𐑍' => '𐐥', + '𐑎' => '𐐦', + '𐑏' => '𐐧', + '𐓘' => '𐒰', + '𐓙' => '𐒱', + '𐓚' => '𐒲', + '𐓛' => '𐒳', + '𐓜' => '𐒴', + '𐓝' => '𐒵', + '𐓞' => '𐒶', + '𐓟' => '𐒷', + '𐓠' => '𐒸', + '𐓡' => '𐒹', + '𐓢' => '𐒺', + '𐓣' => '𐒻', + '𐓤' => '𐒼', + '𐓥' => '𐒽', + '𐓦' => '𐒾', + '𐓧' => '𐒿', + '𐓨' => '𐓀', + '𐓩' => '𐓁', + '𐓪' => '𐓂', + '𐓫' => '𐓃', + '𐓬' => '𐓄', + '𐓭' => '𐓅', + '𐓮' => '𐓆', + '𐓯' => '𐓇', + '𐓰' => '𐓈', + '𐓱' => '𐓉', + '𐓲' => '𐓊', + '𐓳' => '𐓋', + '𐓴' => '𐓌', + '𐓵' => '𐓍', + '𐓶' => '𐓎', + '𐓷' => '𐓏', + '𐓸' => '𐓐', + '𐓹' => '𐓑', + '𐓺' => '𐓒', + '𐓻' => '𐓓', + '𐳀' => '𐲀', + '𐳁' => '𐲁', + '𐳂' => '𐲂', + '𐳃' => '𐲃', + '𐳄' => '𐲄', + '𐳅' => '𐲅', + '𐳆' => '𐲆', + '𐳇' => '𐲇', + '𐳈' => '𐲈', + '𐳉' => '𐲉', + '𐳊' => '𐲊', + '𐳋' => '𐲋', + '𐳌' => '𐲌', + '𐳍' => '𐲍', + '𐳎' => '𐲎', + '𐳏' => '𐲏', + '𐳐' => '𐲐', + '𐳑' => '𐲑', + '𐳒' => '𐲒', + '𐳓' => '𐲓', + '𐳔' => '𐲔', + '𐳕' => '𐲕', + '𐳖' => '𐲖', + '𐳗' => '𐲗', + '𐳘' => '𐲘', + '𐳙' => '𐲙', + '𐳚' => '𐲚', + '𐳛' => '𐲛', + '𐳜' => '𐲜', + '𐳝' => '𐲝', + '𐳞' => '𐲞', + '𐳟' => '𐲟', + '𐳠' => '𐲠', + '𐳡' => '𐲡', + '𐳢' => '𐲢', + '𐳣' => '𐲣', + '𐳤' => '𐲤', + '𐳥' => '𐲥', + '𐳦' => '𐲦', + '𐳧' => '𐲧', + '𐳨' => '𐲨', + '𐳩' => '𐲩', + '𐳪' => '𐲪', + '𐳫' => '𐲫', + '𐳬' => '𐲬', + '𐳭' => '𐲭', + '𐳮' => '𐲮', + '𐳯' => '𐲯', + '𐳰' => '𐲰', + '𐳱' => '𐲱', + '𐳲' => '𐲲', + '𑣀' => '𑢠', + '𑣁' => '𑢡', + '𑣂' => '𑢢', + '𑣃' => '𑢣', + '𑣄' => '𑢤', + '𑣅' => '𑢥', + '𑣆' => '𑢦', + '𑣇' => '𑢧', + '𑣈' => '𑢨', + '𑣉' => '𑢩', + '𑣊' => '𑢪', + '𑣋' => '𑢫', + '𑣌' => '𑢬', + '𑣍' => '𑢭', + '𑣎' => '𑢮', + '𑣏' => '𑢯', + '𑣐' => '𑢰', + '𑣑' => '𑢱', + '𑣒' => '𑢲', + '𑣓' => '𑢳', + '𑣔' => '𑢴', + '𑣕' => '𑢵', + '𑣖' => '𑢶', + '𑣗' => '𑢷', + '𑣘' => '𑢸', + '𑣙' => '𑢹', + '𑣚' => '𑢺', + '𑣛' => '𑢻', + '𑣜' => '𑢼', + '𑣝' => '𑢽', + '𑣞' => '𑢾', + '𑣟' => '𑢿', + '𖹠' => '𖹀', + '𖹡' => '𖹁', + '𖹢' => '𖹂', + '𖹣' => '𖹃', + '𖹤' => '𖹄', + '𖹥' => '𖹅', + '𖹦' => '𖹆', + '𖹧' => '𖹇', + '𖹨' => '𖹈', + '𖹩' => '𖹉', + '𖹪' => '𖹊', + '𖹫' => '𖹋', + '𖹬' => '𖹌', + '𖹭' => '𖹍', + '𖹮' => '𖹎', + '𖹯' => '𖹏', + '𖹰' => '𖹐', + '𖹱' => '𖹑', + '𖹲' => '𖹒', + '𖹳' => '𖹓', + '𖹴' => '𖹔', + '𖹵' => '𖹕', + '𖹶' => '𖹖', + '𖹷' => '𖹗', + '𖹸' => '𖹘', + '𖹹' => '𖹙', + '𖹺' => '𖹚', + '𖹻' => '𖹛', + '𖹼' => '𖹜', + '𖹽' => '𖹝', + '𖹾' => '𖹞', + '𖹿' => '𖹟', + '𞤢' => '𞤀', + '𞤣' => '𞤁', + '𞤤' => '𞤂', + '𞤥' => '𞤃', + '𞤦' => '𞤄', + '𞤧' => '𞤅', + '𞤨' => '𞤆', + '𞤩' => '𞤇', + '𞤪' => '𞤈', + '𞤫' => '𞤉', + '𞤬' => '𞤊', + '𞤭' => '𞤋', + '𞤮' => '𞤌', + '𞤯' => '𞤍', + '𞤰' => '𞤎', + '𞤱' => '𞤏', + '𞤲' => '𞤐', + '𞤳' => '𞤑', + '𞤴' => '𞤒', + '𞤵' => '𞤓', + '𞤶' => '𞤔', + '𞤷' => '𞤕', + '𞤸' => '𞤖', + '𞤹' => '𞤗', + '𞤺' => '𞤘', + '𞤻' => '𞤙', + '𞤼' => '𞤚', + '𞤽' => '𞤛', + '𞤾' => '𞤜', + '𞤿' => '𞤝', + '𞥀' => '𞤞', + '𞥁' => '𞤟', + '𞥂' => '𞤠', + '𞥃' => '𞤡', + 'ß' => 'SS', + 'ff' => 'FF', + 'fi' => 'FI', + 'fl' => 'FL', + 'ffi' => 'FFI', + 'ffl' => 'FFL', + 'ſt' => 'ST', + 'st' => 'ST', + 'և' => 'ԵՒ', + 'ﬓ' => 'ՄՆ', + 'ﬔ' => 'ՄԵ', + 'ﬕ' => 'ՄԻ', + 'ﬖ' => 'ՎՆ', + 'ﬗ' => 'ՄԽ', + 'ʼn' => 'ʼN', + 'ΐ' => 'Ϊ́', + 'ΰ' => 'Ϋ́', + 'ǰ' => 'J̌', + 'ẖ' => 'H̱', + 'ẗ' => 'T̈', + 'ẘ' => 'W̊', + 'ẙ' => 'Y̊', + 'ẚ' => 'Aʾ', + 'ὐ' => 'Υ̓', + 'ὒ' => 'Υ̓̀', + 'ὔ' => 'Υ̓́', + 'ὖ' => 'Υ̓͂', + 'ᾶ' => 'Α͂', + 'ῆ' => 'Η͂', + 'ῒ' => 'Ϊ̀', + 'ΐ' => 'Ϊ́', + 'ῖ' => 'Ι͂', + 'ῗ' => 'Ϊ͂', + 'ῢ' => 'Ϋ̀', + 'ΰ' => 'Ϋ́', + 'ῤ' => 'Ρ̓', + 'ῦ' => 'Υ͂', + 'ῧ' => 'Ϋ͂', + 'ῶ' => 'Ω͂', + 'ᾈ' => 'ἈΙ', + 'ᾉ' => 'ἉΙ', + 'ᾊ' => 'ἊΙ', + 'ᾋ' => 'ἋΙ', + 'ᾌ' => 'ἌΙ', + 'ᾍ' => 'ἍΙ', + 'ᾎ' => 'ἎΙ', + 'ᾏ' => 'ἏΙ', + 'ᾘ' => 'ἨΙ', + 'ᾙ' => 'ἩΙ', + 'ᾚ' => 'ἪΙ', + 'ᾛ' => 'ἫΙ', + 'ᾜ' => 'ἬΙ', + 'ᾝ' => 'ἭΙ', + 'ᾞ' => 'ἮΙ', + 'ᾟ' => 'ἯΙ', + 'ᾨ' => 'ὨΙ', + 'ᾩ' => 'ὩΙ', + 'ᾪ' => 'ὪΙ', + 'ᾫ' => 'ὫΙ', + 'ᾬ' => 'ὬΙ', + 'ᾭ' => 'ὭΙ', + 'ᾮ' => 'ὮΙ', + 'ᾯ' => 'ὯΙ', + 'ᾼ' => 'ΑΙ', + 'ῌ' => 'ΗΙ', + 'ῼ' => 'ΩΙ', + 'ᾲ' => 'ᾺΙ', + 'ᾴ' => 'ΆΙ', + 'ῂ' => 'ῊΙ', + 'ῄ' => 'ΉΙ', + 'ῲ' => 'ῺΙ', + 'ῴ' => 'ΏΙ', + 'ᾷ' => 'Α͂Ι', + 'ῇ' => 'Η͂Ι', + 'ῷ' => 'Ω͂Ι', +); diff --git a/api/vendor/symfony/polyfill-mbstring/bootstrap.php b/api/vendor/symfony/polyfill-mbstring/bootstrap.php new file mode 100644 index 0000000..ff51ae0 --- /dev/null +++ b/api/vendor/symfony/polyfill-mbstring/bootstrap.php @@ -0,0 +1,172 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Mbstring as p; + +if (\PHP_VERSION_ID >= 80000) { + return require __DIR__.'/bootstrap80.php'; +} + +if (!function_exists('mb_convert_encoding')) { + function mb_convert_encoding($string, $to_encoding, $from_encoding = null) { return p\Mbstring::mb_convert_encoding($string, $to_encoding, $from_encoding); } +} +if (!function_exists('mb_decode_mimeheader')) { + function mb_decode_mimeheader($string) { return p\Mbstring::mb_decode_mimeheader($string); } +} +if (!function_exists('mb_encode_mimeheader')) { + function mb_encode_mimeheader($string, $charset = null, $transfer_encoding = null, $newline = "\r\n", $indent = 0) { return p\Mbstring::mb_encode_mimeheader($string, $charset, $transfer_encoding, $newline, $indent); } +} +if (!function_exists('mb_decode_numericentity')) { + function mb_decode_numericentity($string, $map, $encoding = null) { return p\Mbstring::mb_decode_numericentity($string, $map, $encoding); } +} +if (!function_exists('mb_encode_numericentity')) { + function mb_encode_numericentity($string, $map, $encoding = null, $hex = false) { return p\Mbstring::mb_encode_numericentity($string, $map, $encoding, $hex); } +} +if (!function_exists('mb_convert_case')) { + function mb_convert_case($string, $mode, $encoding = null) { return p\Mbstring::mb_convert_case($string, $mode, $encoding); } +} +if (!function_exists('mb_internal_encoding')) { + function mb_internal_encoding($encoding = null) { return p\Mbstring::mb_internal_encoding($encoding); } +} +if (!function_exists('mb_language')) { + function mb_language($language = null) { return p\Mbstring::mb_language($language); } +} +if (!function_exists('mb_list_encodings')) { + function mb_list_encodings() { return p\Mbstring::mb_list_encodings(); } +} +if (!function_exists('mb_encoding_aliases')) { + function mb_encoding_aliases($encoding) { return p\Mbstring::mb_encoding_aliases($encoding); } +} +if (!function_exists('mb_check_encoding')) { + function mb_check_encoding($value = null, $encoding = null) { return p\Mbstring::mb_check_encoding($value, $encoding); } +} +if (!function_exists('mb_detect_encoding')) { + function mb_detect_encoding($string, $encodings = null, $strict = false) { return p\Mbstring::mb_detect_encoding($string, $encodings, $strict); } +} +if (!function_exists('mb_detect_order')) { + function mb_detect_order($encoding = null) { return p\Mbstring::mb_detect_order($encoding); } +} +if (!function_exists('mb_parse_str')) { + function mb_parse_str($string, &$result = []) { parse_str($string, $result); return (bool) $result; } +} +if (!function_exists('mb_strlen')) { + function mb_strlen($string, $encoding = null) { return p\Mbstring::mb_strlen($string, $encoding); } +} +if (!function_exists('mb_strpos')) { + function mb_strpos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strpos($haystack, $needle, $offset, $encoding); } +} +if (!function_exists('mb_strtolower')) { + function mb_strtolower($string, $encoding = null) { return p\Mbstring::mb_strtolower($string, $encoding); } +} +if (!function_exists('mb_strtoupper')) { + function mb_strtoupper($string, $encoding = null) { return p\Mbstring::mb_strtoupper($string, $encoding); } +} +if (!function_exists('mb_substitute_character')) { + function mb_substitute_character($substitute_character = null) { return p\Mbstring::mb_substitute_character($substitute_character); } +} +if (!function_exists('mb_substr')) { + function mb_substr($string, $start, $length = 2147483647, $encoding = null) { return p\Mbstring::mb_substr($string, $start, $length, $encoding); } +} +if (!function_exists('mb_stripos')) { + function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_stripos($haystack, $needle, $offset, $encoding); } +} +if (!function_exists('mb_stristr')) { + function mb_stristr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_stristr($haystack, $needle, $before_needle, $encoding); } +} +if (!function_exists('mb_strrchr')) { + function mb_strrchr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strrchr($haystack, $needle, $before_needle, $encoding); } +} +if (!function_exists('mb_strrichr')) { + function mb_strrichr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strrichr($haystack, $needle, $before_needle, $encoding); } +} +if (!function_exists('mb_strripos')) { + function mb_strripos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strripos($haystack, $needle, $offset, $encoding); } +} +if (!function_exists('mb_strrpos')) { + function mb_strrpos($haystack, $needle, $offset = 0, $encoding = null) { return p\Mbstring::mb_strrpos($haystack, $needle, $offset, $encoding); } +} +if (!function_exists('mb_strstr')) { + function mb_strstr($haystack, $needle, $before_needle = false, $encoding = null) { return p\Mbstring::mb_strstr($haystack, $needle, $before_needle, $encoding); } +} +if (!function_exists('mb_get_info')) { + function mb_get_info($type = 'all') { return p\Mbstring::mb_get_info($type); } +} +if (!function_exists('mb_http_output')) { + function mb_http_output($encoding = null) { return p\Mbstring::mb_http_output($encoding); } +} +if (!function_exists('mb_strwidth')) { + function mb_strwidth($string, $encoding = null) { return p\Mbstring::mb_strwidth($string, $encoding); } +} +if (!function_exists('mb_substr_count')) { + function mb_substr_count($haystack, $needle, $encoding = null) { return p\Mbstring::mb_substr_count($haystack, $needle, $encoding); } +} +if (!function_exists('mb_output_handler')) { + function mb_output_handler($string, $status) { return p\Mbstring::mb_output_handler($string, $status); } +} +if (!function_exists('mb_http_input')) { + function mb_http_input($type = null) { return p\Mbstring::mb_http_input($type); } +} + +if (!function_exists('mb_convert_variables')) { + function mb_convert_variables($to_encoding, $from_encoding, &...$vars) { return p\Mbstring::mb_convert_variables($to_encoding, $from_encoding, ...$vars); } +} + +if (!function_exists('mb_ord')) { + function mb_ord($string, $encoding = null) { return p\Mbstring::mb_ord($string, $encoding); } +} +if (!function_exists('mb_chr')) { + function mb_chr($codepoint, $encoding = null) { return p\Mbstring::mb_chr($codepoint, $encoding); } +} +if (!function_exists('mb_scrub')) { + function mb_scrub($string, $encoding = null) { $encoding = null === $encoding ? mb_internal_encoding() : $encoding; return mb_convert_encoding($string, $encoding, $encoding); } +} +if (!function_exists('mb_str_split')) { + function mb_str_split($string, $length = 1, $encoding = null) { return p\Mbstring::mb_str_split($string, $length, $encoding); } +} + +if (!function_exists('mb_str_pad')) { + function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Mbstring::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); } +} + +if (!function_exists('mb_ucfirst')) { + function mb_ucfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_ucfirst($string, $encoding); } +} + +if (!function_exists('mb_lcfirst')) { + function mb_lcfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_lcfirst($string, $encoding); } +} + +if (!function_exists('mb_trim')) { + function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_trim($string, $characters, $encoding); } +} + +if (!function_exists('mb_ltrim')) { + function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_ltrim($string, $characters, $encoding); } +} + +if (!function_exists('mb_rtrim')) { + function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_rtrim($string, $characters, $encoding); } +} + + +if (extension_loaded('mbstring')) { + return; +} + +if (!defined('MB_CASE_UPPER')) { + define('MB_CASE_UPPER', 0); +} +if (!defined('MB_CASE_LOWER')) { + define('MB_CASE_LOWER', 1); +} +if (!defined('MB_CASE_TITLE')) { + define('MB_CASE_TITLE', 2); +} diff --git a/api/vendor/symfony/polyfill-mbstring/bootstrap80.php b/api/vendor/symfony/polyfill-mbstring/bootstrap80.php new file mode 100644 index 0000000..5236e6d --- /dev/null +++ b/api/vendor/symfony/polyfill-mbstring/bootstrap80.php @@ -0,0 +1,167 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Mbstring as p; + +if (!function_exists('mb_convert_encoding')) { + function mb_convert_encoding(array|string|null $string, ?string $to_encoding, array|string|null $from_encoding = null): array|string|false { return p\Mbstring::mb_convert_encoding($string ?? '', (string) $to_encoding, $from_encoding); } +} +if (!function_exists('mb_decode_mimeheader')) { + function mb_decode_mimeheader(?string $string): string { return p\Mbstring::mb_decode_mimeheader((string) $string); } +} +if (!function_exists('mb_encode_mimeheader')) { + function mb_encode_mimeheader(?string $string, ?string $charset = null, ?string $transfer_encoding = null, ?string $newline = "\r\n", ?int $indent = 0): string { return p\Mbstring::mb_encode_mimeheader((string) $string, $charset, $transfer_encoding, (string) $newline, (int) $indent); } +} +if (!function_exists('mb_decode_numericentity')) { + function mb_decode_numericentity(?string $string, array $map, ?string $encoding = null): string { return p\Mbstring::mb_decode_numericentity((string) $string, $map, $encoding); } +} +if (!function_exists('mb_encode_numericentity')) { + function mb_encode_numericentity(?string $string, array $map, ?string $encoding = null, ?bool $hex = false): string { return p\Mbstring::mb_encode_numericentity((string) $string, $map, $encoding, (bool) $hex); } +} +if (!function_exists('mb_convert_case')) { + function mb_convert_case(?string $string, ?int $mode, ?string $encoding = null): string { return p\Mbstring::mb_convert_case((string) $string, (int) $mode, $encoding); } +} +if (!function_exists('mb_internal_encoding')) { + function mb_internal_encoding(?string $encoding = null): string|bool { return p\Mbstring::mb_internal_encoding($encoding); } +} +if (!function_exists('mb_language')) { + function mb_language(?string $language = null): string|bool { return p\Mbstring::mb_language($language); } +} +if (!function_exists('mb_list_encodings')) { + function mb_list_encodings(): array { return p\Mbstring::mb_list_encodings(); } +} +if (!function_exists('mb_encoding_aliases')) { + function mb_encoding_aliases(?string $encoding): array { return p\Mbstring::mb_encoding_aliases((string) $encoding); } +} +if (!function_exists('mb_check_encoding')) { + function mb_check_encoding(array|string|null $value = null, ?string $encoding = null): bool { return p\Mbstring::mb_check_encoding($value, $encoding); } +} +if (!function_exists('mb_detect_encoding')) { + function mb_detect_encoding(?string $string, array|string|null $encodings = null, ?bool $strict = false): string|false { return p\Mbstring::mb_detect_encoding((string) $string, $encodings, (bool) $strict); } +} +if (!function_exists('mb_detect_order')) { + function mb_detect_order(array|string|null $encoding = null): array|bool { return p\Mbstring::mb_detect_order($encoding); } +} +if (!function_exists('mb_parse_str')) { + function mb_parse_str(?string $string, &$result = []): bool { parse_str((string) $string, $result); return (bool) $result; } +} +if (!function_exists('mb_strlen')) { + function mb_strlen(?string $string, ?string $encoding = null): int { return p\Mbstring::mb_strlen((string) $string, $encoding); } +} +if (!function_exists('mb_strpos')) { + function mb_strpos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strpos((string) $haystack, (string) $needle, (int) $offset, $encoding); } +} +if (!function_exists('mb_strtolower')) { + function mb_strtolower(?string $string, ?string $encoding = null): string { return p\Mbstring::mb_strtolower((string) $string, $encoding); } +} +if (!function_exists('mb_strtoupper')) { + function mb_strtoupper(?string $string, ?string $encoding = null): string { return p\Mbstring::mb_strtoupper((string) $string, $encoding); } +} +if (!function_exists('mb_substitute_character')) { + function mb_substitute_character(string|int|null $substitute_character = null): string|int|bool { return p\Mbstring::mb_substitute_character($substitute_character); } +} +if (!function_exists('mb_substr')) { + function mb_substr(?string $string, ?int $start, ?int $length = null, ?string $encoding = null): string { return p\Mbstring::mb_substr((string) $string, (int) $start, $length, $encoding); } +} +if (!function_exists('mb_stripos')) { + function mb_stripos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_stripos((string) $haystack, (string) $needle, (int) $offset, $encoding); } +} +if (!function_exists('mb_stristr')) { + function mb_stristr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_stristr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); } +} +if (!function_exists('mb_strrchr')) { + function mb_strrchr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strrchr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); } +} +if (!function_exists('mb_strrichr')) { + function mb_strrichr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strrichr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); } +} +if (!function_exists('mb_strripos')) { + function mb_strripos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strripos((string) $haystack, (string) $needle, (int) $offset, $encoding); } +} +if (!function_exists('mb_strrpos')) { + function mb_strrpos(?string $haystack, ?string $needle, ?int $offset = 0, ?string $encoding = null): int|false { return p\Mbstring::mb_strrpos((string) $haystack, (string) $needle, (int) $offset, $encoding); } +} +if (!function_exists('mb_strstr')) { + function mb_strstr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strstr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); } +} +if (!function_exists('mb_get_info')) { + function mb_get_info(?string $type = 'all'): array|string|int|false|null { return p\Mbstring::mb_get_info((string) $type); } +} +if (!function_exists('mb_http_output')) { + function mb_http_output(?string $encoding = null): string|bool { return p\Mbstring::mb_http_output($encoding); } +} +if (!function_exists('mb_strwidth')) { + function mb_strwidth(?string $string, ?string $encoding = null): int { return p\Mbstring::mb_strwidth((string) $string, $encoding); } +} +if (!function_exists('mb_substr_count')) { + function mb_substr_count(?string $haystack, ?string $needle, ?string $encoding = null): int { return p\Mbstring::mb_substr_count((string) $haystack, (string) $needle, $encoding); } +} +if (!function_exists('mb_output_handler')) { + function mb_output_handler(?string $string, ?int $status): string { return p\Mbstring::mb_output_handler((string) $string, (int) $status); } +} +if (!function_exists('mb_http_input')) { + function mb_http_input(?string $type = null): array|string|false { return p\Mbstring::mb_http_input($type); } +} + +if (!function_exists('mb_convert_variables')) { + function mb_convert_variables(?string $to_encoding, array|string|null $from_encoding, mixed &$var, mixed &...$vars): string|false { return p\Mbstring::mb_convert_variables((string) $to_encoding, $from_encoding ?? '', $var, ...$vars); } +} + +if (!function_exists('mb_ord')) { + function mb_ord(?string $string, ?string $encoding = null): int|false { return p\Mbstring::mb_ord((string) $string, $encoding); } +} +if (!function_exists('mb_chr')) { + function mb_chr(?int $codepoint, ?string $encoding = null): string|false { return p\Mbstring::mb_chr((int) $codepoint, $encoding); } +} +if (!function_exists('mb_scrub')) { + function mb_scrub(?string $string, ?string $encoding = null): string { $encoding ??= mb_internal_encoding(); return mb_convert_encoding((string) $string, $encoding, $encoding); } +} +if (!function_exists('mb_str_split')) { + function mb_str_split(?string $string, ?int $length = 1, ?string $encoding = null): array { return p\Mbstring::mb_str_split((string) $string, (int) $length, $encoding); } +} + +if (!function_exists('mb_str_pad')) { + function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Mbstring::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); } +} + +if (!function_exists('mb_ucfirst')) { + function mb_ucfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_ucfirst($string, $encoding); } +} + +if (!function_exists('mb_lcfirst')) { + function mb_lcfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_lcfirst($string, $encoding); } +} + +if (!function_exists('mb_trim')) { + function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_trim($string, $characters, $encoding); } +} + +if (!function_exists('mb_ltrim')) { + function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_ltrim($string, $characters, $encoding); } +} + +if (!function_exists('mb_rtrim')) { + function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_rtrim($string, $characters, $encoding); } +} + +if (extension_loaded('mbstring')) { + return; +} + +if (!defined('MB_CASE_UPPER')) { + define('MB_CASE_UPPER', 0); +} +if (!defined('MB_CASE_LOWER')) { + define('MB_CASE_LOWER', 1); +} +if (!defined('MB_CASE_TITLE')) { + define('MB_CASE_TITLE', 2); +} diff --git a/api/vendor/symfony/polyfill-mbstring/composer.json b/api/vendor/symfony/polyfill-mbstring/composer.json new file mode 100644 index 0000000..daa07f8 --- /dev/null +++ b/api/vendor/symfony/polyfill-mbstring/composer.json @@ -0,0 +1,39 @@ +{ + "name": "symfony/polyfill-mbstring", + "type": "library", + "description": "Symfony polyfill for the Mbstring extension", + "keywords": ["polyfill", "shim", "compatibility", "portable", "mbstring"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.2", + "ext-iconv": "*" + }, + "provide": { + "ext-mbstring": "*" + }, + "autoload": { + "psr-4": { "Symfony\\Polyfill\\Mbstring\\": "" }, + "files": [ "bootstrap.php" ] + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "minimum-stability": "dev", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + } +} diff --git a/api/vendor/symfony/polyfill-php80/LICENSE b/api/vendor/symfony/polyfill-php80/LICENSE new file mode 100644 index 0000000..0ed3a24 --- /dev/null +++ b/api/vendor/symfony/polyfill-php80/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2020-present Fabien Potencier + +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. diff --git a/api/vendor/symfony/polyfill-php80/Php80.php b/api/vendor/symfony/polyfill-php80/Php80.php new file mode 100644 index 0000000..362dd1a --- /dev/null +++ b/api/vendor/symfony/polyfill-php80/Php80.php @@ -0,0 +1,115 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Php80; + +/** + * @author Ion Bazan + * @author Nico Oelgart + * @author Nicolas Grekas + * + * @internal + */ +final class Php80 +{ + public static function fdiv(float $dividend, float $divisor): float + { + return @($dividend / $divisor); + } + + public static function get_debug_type($value): string + { + switch (true) { + case null === $value: return 'null'; + case \is_bool($value): return 'bool'; + case \is_string($value): return 'string'; + case \is_array($value): return 'array'; + case \is_int($value): return 'int'; + case \is_float($value): return 'float'; + case \is_object($value): break; + case $value instanceof \__PHP_Incomplete_Class: return '__PHP_Incomplete_Class'; + default: + if (null === $type = @get_resource_type($value)) { + return 'unknown'; + } + + if ('Unknown' === $type) { + $type = 'closed'; + } + + return "resource ($type)"; + } + + $class = \get_class($value); + + if (false === strpos($class, '@')) { + return $class; + } + + return (get_parent_class($class) ?: key(class_implements($class)) ?: 'class').'@anonymous'; + } + + public static function get_resource_id($res): int + { + if (!\is_resource($res) && null === @get_resource_type($res)) { + throw new \TypeError(sprintf('Argument 1 passed to get_resource_id() must be of the type resource, %s given', get_debug_type($res))); + } + + return (int) $res; + } + + public static function preg_last_error_msg(): string + { + switch (preg_last_error()) { + case \PREG_INTERNAL_ERROR: + return 'Internal error'; + case \PREG_BAD_UTF8_ERROR: + return 'Malformed UTF-8 characters, possibly incorrectly encoded'; + case \PREG_BAD_UTF8_OFFSET_ERROR: + return 'The offset did not correspond to the beginning of a valid UTF-8 code point'; + case \PREG_BACKTRACK_LIMIT_ERROR: + return 'Backtrack limit exhausted'; + case \PREG_RECURSION_LIMIT_ERROR: + return 'Recursion limit exhausted'; + case \PREG_JIT_STACKLIMIT_ERROR: + return 'JIT stack limit exhausted'; + case \PREG_NO_ERROR: + return 'No error'; + default: + return 'Unknown error'; + } + } + + public static function str_contains(string $haystack, string $needle): bool + { + return '' === $needle || false !== strpos($haystack, $needle); + } + + public static function str_starts_with(string $haystack, string $needle): bool + { + return 0 === strncmp($haystack, $needle, \strlen($needle)); + } + + public static function str_ends_with(string $haystack, string $needle): bool + { + if ('' === $needle || $needle === $haystack) { + return true; + } + + if ('' === $haystack) { + return false; + } + + $needleLength = \strlen($needle); + + return $needleLength <= \strlen($haystack) && 0 === substr_compare($haystack, $needle, -$needleLength); + } +} diff --git a/api/vendor/symfony/polyfill-php80/PhpToken.php b/api/vendor/symfony/polyfill-php80/PhpToken.php new file mode 100644 index 0000000..cd78c4c --- /dev/null +++ b/api/vendor/symfony/polyfill-php80/PhpToken.php @@ -0,0 +1,106 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Php80; + +/** + * @author Fedonyuk Anton + * + * @internal + */ +class PhpToken implements \Stringable +{ + /** + * @var int + */ + public $id; + + /** + * @var string + */ + public $text; + + /** + * @var -1|positive-int + */ + public $line; + + /** + * @var int + */ + public $pos; + + /** + * @param -1|positive-int $line + */ + public function __construct(int $id, string $text, int $line = -1, int $position = -1) + { + $this->id = $id; + $this->text = $text; + $this->line = $line; + $this->pos = $position; + } + + public function getTokenName(): ?string + { + if ('UNKNOWN' === $name = token_name($this->id)) { + $name = \strlen($this->text) > 1 || \ord($this->text) < 32 ? null : $this->text; + } + + return $name; + } + + /** + * @param int|string|array $kind + */ + public function is($kind): bool + { + foreach ((array) $kind as $value) { + if (\in_array($value, [$this->id, $this->text], true)) { + return true; + } + } + + return false; + } + + public function isIgnorable(): bool + { + return \in_array($this->id, [\T_WHITESPACE, \T_COMMENT, \T_DOC_COMMENT, \T_OPEN_TAG], true); + } + + public function __toString(): string + { + return (string) $this->text; + } + + /** + * @return list + */ + public static function tokenize(string $code, int $flags = 0): array + { + $line = 1; + $position = 0; + $tokens = token_get_all($code, $flags); + foreach ($tokens as $index => $token) { + if (\is_string($token)) { + $id = \ord($token); + $text = $token; + } else { + [$id, $text, $line] = $token; + } + $tokens[$index] = new static($id, $text, $line, $position); + $position += \strlen($text); + } + + return $tokens; + } +} diff --git a/api/vendor/symfony/polyfill-php80/README.md b/api/vendor/symfony/polyfill-php80/README.md new file mode 100644 index 0000000..3816c55 --- /dev/null +++ b/api/vendor/symfony/polyfill-php80/README.md @@ -0,0 +1,25 @@ +Symfony Polyfill / Php80 +======================== + +This component provides features added to PHP 8.0 core: + +- [`Stringable`](https://php.net/stringable) interface +- [`fdiv`](https://php.net/fdiv) +- [`ValueError`](https://php.net/valueerror) class +- [`UnhandledMatchError`](https://php.net/unhandledmatcherror) class +- `FILTER_VALIDATE_BOOL` constant +- [`get_debug_type`](https://php.net/get_debug_type) +- [`PhpToken`](https://php.net/phptoken) class +- [`preg_last_error_msg`](https://php.net/preg_last_error_msg) +- [`str_contains`](https://php.net/str_contains) +- [`str_starts_with`](https://php.net/str_starts_with) +- [`str_ends_with`](https://php.net/str_ends_with) +- [`get_resource_id`](https://php.net/get_resource_id) + +More information can be found in the +[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md). + +License +======= + +This library is released under the [MIT license](LICENSE). diff --git a/api/vendor/symfony/polyfill-php80/Resources/stubs/Attribute.php b/api/vendor/symfony/polyfill-php80/Resources/stubs/Attribute.php new file mode 100644 index 0000000..2b95542 --- /dev/null +++ b/api/vendor/symfony/polyfill-php80/Resources/stubs/Attribute.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#[Attribute(Attribute::TARGET_CLASS)] +final class Attribute +{ + public const TARGET_CLASS = 1; + public const TARGET_FUNCTION = 2; + public const TARGET_METHOD = 4; + public const TARGET_PROPERTY = 8; + public const TARGET_CLASS_CONSTANT = 16; + public const TARGET_PARAMETER = 32; + public const TARGET_ALL = 63; + public const IS_REPEATABLE = 64; + + /** @var int */ + public $flags; + + public function __construct(int $flags = self::TARGET_ALL) + { + $this->flags = $flags; + } +} diff --git a/api/vendor/symfony/polyfill-php80/Resources/stubs/PhpToken.php b/api/vendor/symfony/polyfill-php80/Resources/stubs/PhpToken.php new file mode 100644 index 0000000..bd1212f --- /dev/null +++ b/api/vendor/symfony/polyfill-php80/Resources/stubs/PhpToken.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +if (\PHP_VERSION_ID < 80000 && extension_loaded('tokenizer')) { + class PhpToken extends Symfony\Polyfill\Php80\PhpToken + { + } +} diff --git a/api/vendor/symfony/polyfill-php80/Resources/stubs/Stringable.php b/api/vendor/symfony/polyfill-php80/Resources/stubs/Stringable.php new file mode 100644 index 0000000..7c62d75 --- /dev/null +++ b/api/vendor/symfony/polyfill-php80/Resources/stubs/Stringable.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +if (\PHP_VERSION_ID < 80000) { + interface Stringable + { + /** + * @return string + */ + public function __toString(); + } +} diff --git a/api/vendor/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php b/api/vendor/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php new file mode 100644 index 0000000..01c6c6c --- /dev/null +++ b/api/vendor/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +if (\PHP_VERSION_ID < 80000) { + class UnhandledMatchError extends Error + { + } +} diff --git a/api/vendor/symfony/polyfill-php80/Resources/stubs/ValueError.php b/api/vendor/symfony/polyfill-php80/Resources/stubs/ValueError.php new file mode 100644 index 0000000..783dbc2 --- /dev/null +++ b/api/vendor/symfony/polyfill-php80/Resources/stubs/ValueError.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +if (\PHP_VERSION_ID < 80000) { + class ValueError extends Error + { + } +} diff --git a/api/vendor/symfony/polyfill-php80/bootstrap.php b/api/vendor/symfony/polyfill-php80/bootstrap.php new file mode 100644 index 0000000..e5f7dbc --- /dev/null +++ b/api/vendor/symfony/polyfill-php80/bootstrap.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Php80 as p; + +if (\PHP_VERSION_ID >= 80000) { + return; +} + +if (!defined('FILTER_VALIDATE_BOOL') && defined('FILTER_VALIDATE_BOOLEAN')) { + define('FILTER_VALIDATE_BOOL', \FILTER_VALIDATE_BOOLEAN); +} + +if (!function_exists('fdiv')) { + function fdiv(float $num1, float $num2): float { return p\Php80::fdiv($num1, $num2); } +} +if (!function_exists('preg_last_error_msg')) { + function preg_last_error_msg(): string { return p\Php80::preg_last_error_msg(); } +} +if (!function_exists('str_contains')) { + function str_contains(?string $haystack, ?string $needle): bool { return p\Php80::str_contains($haystack ?? '', $needle ?? ''); } +} +if (!function_exists('str_starts_with')) { + function str_starts_with(?string $haystack, ?string $needle): bool { return p\Php80::str_starts_with($haystack ?? '', $needle ?? ''); } +} +if (!function_exists('str_ends_with')) { + function str_ends_with(?string $haystack, ?string $needle): bool { return p\Php80::str_ends_with($haystack ?? '', $needle ?? ''); } +} +if (!function_exists('get_debug_type')) { + function get_debug_type($value): string { return p\Php80::get_debug_type($value); } +} +if (!function_exists('get_resource_id')) { + function get_resource_id($resource): int { return p\Php80::get_resource_id($resource); } +} diff --git a/api/vendor/symfony/polyfill-php80/composer.json b/api/vendor/symfony/polyfill-php80/composer.json new file mode 100644 index 0000000..a503b03 --- /dev/null +++ b/api/vendor/symfony/polyfill-php80/composer.json @@ -0,0 +1,37 @@ +{ + "name": "symfony/polyfill-php80", + "type": "library", + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "keywords": ["polyfill", "shim", "compatibility", "portable"], + "homepage": "https://symfony.com", + "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" + } + ], + "require": { + "php": ">=7.2" + }, + "autoload": { + "psr-4": { "Symfony\\Polyfill\\Php80\\": "" }, + "files": [ "bootstrap.php" ], + "classmap": [ "Resources/stubs" ] + }, + "minimum-stability": "dev", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + } +} diff --git a/api/vendor/vlucas/phpdotenv/LICENSE b/api/vendor/vlucas/phpdotenv/LICENSE new file mode 100644 index 0000000..922c552 --- /dev/null +++ b/api/vendor/vlucas/phpdotenv/LICENSE @@ -0,0 +1,30 @@ +BSD 3-Clause License + +Copyright (c) 2014, Graham Campbell. +Copyright (c) 2013, Vance Lucas. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/api/vendor/vlucas/phpdotenv/composer.json b/api/vendor/vlucas/phpdotenv/composer.json new file mode 100644 index 0000000..3636317 --- /dev/null +++ b/api/vendor/vlucas/phpdotenv/composer.json @@ -0,0 +1,60 @@ +{ + "name": "vlucas/phpdotenv", + "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", + "keywords": ["env", "dotenv", "environment"], + "license": "BSD-3-Clause", + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Vance Lucas", + "email": "vance@vancelucas.com", + "homepage": "https://github.com/vlucas" + } + ], + "require": { + "php": "^7.2.5 || ^8.0", + "ext-pcre": "*", + "graham-campbell/result-type": "^1.1.3", + "phpoption/phpoption": "^1.9.3", + "symfony/polyfill-ctype": "^1.24", + "symfony/polyfill-mbstring": "^1.24", + "symfony/polyfill-php80": "^1.24" + }, + "require-dev": { + "ext-filter": "*", + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit":"^8.5.34 || ^9.6.13 || ^10.4.2" + }, + "autoload": { + "psr-4": { + "Dotenv\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Dotenv\\Tests\\": "tests/Dotenv/" + } + }, + "suggest": { + "ext-filter": "Required to use the boolean validator." + }, + "config": { + "allow-plugins": { + "bamarni/composer-bin-plugin": true + }, + "preferred-install": "dist" + }, + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "5.6-dev" + } + } +} diff --git a/api/vendor/vlucas/phpdotenv/src/Dotenv.php b/api/vendor/vlucas/phpdotenv/src/Dotenv.php new file mode 100644 index 0000000..34ca850 --- /dev/null +++ b/api/vendor/vlucas/phpdotenv/src/Dotenv.php @@ -0,0 +1,267 @@ +store = $store; + $this->parser = $parser; + $this->loader = $loader; + $this->repository = $repository; + } + + /** + * Create a new dotenv instance. + * + * @param \Dotenv\Repository\RepositoryInterface $repository + * @param string|string[] $paths + * @param string|string[]|null $names + * @param bool $shortCircuit + * @param string|null $fileEncoding + * + * @return \Dotenv\Dotenv + */ + public static function create(RepositoryInterface $repository, $paths, $names = null, bool $shortCircuit = true, ?string $fileEncoding = null) + { + $builder = $names === null ? StoreBuilder::createWithDefaultName() : StoreBuilder::createWithNoNames(); + + foreach ((array) $paths as $path) { + $builder = $builder->addPath($path); + } + + foreach ((array) $names as $name) { + $builder = $builder->addName($name); + } + + if ($shortCircuit) { + $builder = $builder->shortCircuit(); + } + + return new self($builder->fileEncoding($fileEncoding)->make(), new Parser(), new Loader(), $repository); + } + + /** + * Create a new mutable dotenv instance with default repository. + * + * @param string|string[] $paths + * @param string|string[]|null $names + * @param bool $shortCircuit + * @param string|null $fileEncoding + * + * @return \Dotenv\Dotenv + */ + public static function createMutable($paths, $names = null, bool $shortCircuit = true, ?string $fileEncoding = null) + { + $repository = RepositoryBuilder::createWithDefaultAdapters()->make(); + + return self::create($repository, $paths, $names, $shortCircuit, $fileEncoding); + } + + /** + * Create a new mutable dotenv instance with default repository with the putenv adapter. + * + * @param string|string[] $paths + * @param string|string[]|null $names + * @param bool $shortCircuit + * @param string|null $fileEncoding + * + * @return \Dotenv\Dotenv + */ + public static function createUnsafeMutable($paths, $names = null, bool $shortCircuit = true, ?string $fileEncoding = null) + { + $repository = RepositoryBuilder::createWithDefaultAdapters() + ->addAdapter(PutenvAdapter::class) + ->make(); + + return self::create($repository, $paths, $names, $shortCircuit, $fileEncoding); + } + + /** + * Create a new immutable dotenv instance with default repository. + * + * @param string|string[] $paths + * @param string|string[]|null $names + * @param bool $shortCircuit + * @param string|null $fileEncoding + * + * @return \Dotenv\Dotenv + */ + public static function createImmutable($paths, $names = null, bool $shortCircuit = true, ?string $fileEncoding = null) + { + $repository = RepositoryBuilder::createWithDefaultAdapters()->immutable()->make(); + + return self::create($repository, $paths, $names, $shortCircuit, $fileEncoding); + } + + /** + * Create a new immutable dotenv instance with default repository with the putenv adapter. + * + * @param string|string[] $paths + * @param string|string[]|null $names + * @param bool $shortCircuit + * @param string|null $fileEncoding + * + * @return \Dotenv\Dotenv + */ + public static function createUnsafeImmutable($paths, $names = null, bool $shortCircuit = true, ?string $fileEncoding = null) + { + $repository = RepositoryBuilder::createWithDefaultAdapters() + ->addAdapter(PutenvAdapter::class) + ->immutable() + ->make(); + + return self::create($repository, $paths, $names, $shortCircuit, $fileEncoding); + } + + /** + * Create a new dotenv instance with an array backed repository. + * + * @param string|string[] $paths + * @param string|string[]|null $names + * @param bool $shortCircuit + * @param string|null $fileEncoding + * + * @return \Dotenv\Dotenv + */ + public static function createArrayBacked($paths, $names = null, bool $shortCircuit = true, ?string $fileEncoding = null) + { + $repository = RepositoryBuilder::createWithNoAdapters()->addAdapter(ArrayAdapter::class)->make(); + + return self::create($repository, $paths, $names, $shortCircuit, $fileEncoding); + } + + /** + * Parse the given content and resolve nested variables. + * + * This method behaves just like load(), only without mutating your actual + * environment. We do this by using an array backed repository. + * + * @param string $content + * + * @throws \Dotenv\Exception\InvalidFileException + * + * @return array + */ + public static function parse(string $content) + { + $repository = RepositoryBuilder::createWithNoAdapters()->addAdapter(ArrayAdapter::class)->make(); + + $phpdotenv = new self(new StringStore($content), new Parser(), new Loader(), $repository); + + return $phpdotenv->load(); + } + + /** + * Read and load environment file(s). + * + * @throws \Dotenv\Exception\InvalidPathException|\Dotenv\Exception\InvalidEncodingException|\Dotenv\Exception\InvalidFileException + * + * @return array + */ + public function load() + { + $entries = $this->parser->parse($this->store->read()); + + return $this->loader->load($this->repository, $entries); + } + + /** + * Read and load environment file(s), silently failing if no files can be read. + * + * @throws \Dotenv\Exception\InvalidEncodingException|\Dotenv\Exception\InvalidFileException + * + * @return array + */ + public function safeLoad() + { + try { + return $this->load(); + } catch (InvalidPathException $e) { + // suppressing exception + return []; + } + } + + /** + * Required ensures that the specified variables exist, and returns a new validator object. + * + * @param string|string[] $variables + * + * @return \Dotenv\Validator + */ + public function required($variables) + { + return (new Validator($this->repository, (array) $variables))->required(); + } + + /** + * Returns a new validator object that won't check if the specified variables exist. + * + * @param string|string[] $variables + * + * @return \Dotenv\Validator + */ + public function ifPresent($variables) + { + return new Validator($this->repository, (array) $variables); + } +} diff --git a/api/vendor/vlucas/phpdotenv/src/Exception/ExceptionInterface.php b/api/vendor/vlucas/phpdotenv/src/Exception/ExceptionInterface.php new file mode 100644 index 0000000..1e80f53 --- /dev/null +++ b/api/vendor/vlucas/phpdotenv/src/Exception/ExceptionInterface.php @@ -0,0 +1,12 @@ + + */ + public function load(RepositoryInterface $repository, array $entries) + { + /** @var array */ + return \array_reduce($entries, static function (array $vars, Entry $entry) use ($repository) { + $name = $entry->getName(); + + $value = $entry->getValue()->map(static function (Value $value) use ($repository) { + return Resolver::resolve($repository, $value); + }); + + if ($value->isDefined()) { + $inner = $value->get(); + if ($repository->set($name, $inner)) { + return \array_merge($vars, [$name => $inner]); + } + } else { + if ($repository->clear($name)) { + return \array_merge($vars, [$name => null]); + } + } + + return $vars; + }, []); + } +} diff --git a/api/vendor/vlucas/phpdotenv/src/Loader/LoaderInterface.php b/api/vendor/vlucas/phpdotenv/src/Loader/LoaderInterface.php new file mode 100644 index 0000000..f40d6ad --- /dev/null +++ b/api/vendor/vlucas/phpdotenv/src/Loader/LoaderInterface.php @@ -0,0 +1,20 @@ + + */ + public function load(RepositoryInterface $repository, array $entries); +} diff --git a/api/vendor/vlucas/phpdotenv/src/Loader/Resolver.php b/api/vendor/vlucas/phpdotenv/src/Loader/Resolver.php new file mode 100644 index 0000000..ab5adf8 --- /dev/null +++ b/api/vendor/vlucas/phpdotenv/src/Loader/Resolver.php @@ -0,0 +1,65 @@ +getVars(), static function (string $s, int $i) use ($repository) { + return Str::substr($s, 0, $i).self::resolveVariable($repository, Str::substr($s, $i)); + }, $value->getChars()); + } + + /** + * Resolve a single nested variable. + * + * @param \Dotenv\Repository\RepositoryInterface $repository + * @param string $str + * + * @return string + */ + private static function resolveVariable(RepositoryInterface $repository, string $str) + { + return Regex::replaceCallback( + '/\A\${([a-zA-Z0-9_.]+)}/', + static function (array $matches) use ($repository) { + /** @var string */ + return Option::fromValue($repository->get($matches[1]))->getOrElse($matches[0]); + }, + $str, + 1 + )->success()->getOrElse($str); + } +} diff --git a/api/vendor/vlucas/phpdotenv/src/Parser/Entry.php b/api/vendor/vlucas/phpdotenv/src/Parser/Entry.php new file mode 100644 index 0000000..716f422 --- /dev/null +++ b/api/vendor/vlucas/phpdotenv/src/Parser/Entry.php @@ -0,0 +1,59 @@ +name = $name; + $this->value = $value; + } + + /** + * Get the entry name. + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * Get the entry value. + * + * @return \PhpOption\Option<\Dotenv\Parser\Value> + */ + public function getValue() + { + /** @var \PhpOption\Option<\Dotenv\Parser\Value> */ + return Option::fromValue($this->value); + } +} diff --git a/api/vendor/vlucas/phpdotenv/src/Parser/EntryParser.php b/api/vendor/vlucas/phpdotenv/src/Parser/EntryParser.php new file mode 100644 index 0000000..85e5fa3 --- /dev/null +++ b/api/vendor/vlucas/phpdotenv/src/Parser/EntryParser.php @@ -0,0 +1,300 @@ + + */ + public static function parse(string $entry) + { + return self::splitStringIntoParts($entry)->flatMap(static function (array $parts) { + [$name, $value] = $parts; + + return self::parseName($name)->flatMap(static function (string $name) use ($value) { + /** @var Result */ + $parsedValue = $value === null ? Success::create(null) : self::parseValue($value); + + return $parsedValue->map(static function (?Value $value) use ($name) { + return new Entry($name, $value); + }); + }); + }); + } + + /** + * Split the compound string into parts. + * + * @param string $line + * + * @return \GrahamCampbell\ResultType\Result + */ + private static function splitStringIntoParts(string $line) + { + /** @var array{string, string|null} */ + $result = Str::pos($line, '=')->map(static function () use ($line) { + return \array_map('trim', \explode('=', $line, 2)); + })->getOrElse([$line, null]); + + if ($result[0] === '') { + /** @var \GrahamCampbell\ResultType\Result */ + return Error::create(self::getErrorMessage('an unexpected equals', $line)); + } + + /** @var \GrahamCampbell\ResultType\Result */ + return Success::create($result); + } + + /** + * Parse the given variable name. + * + * That is, strip the optional quotes and leading "export" from the + * variable name. We wrap the answer in a result type. + * + * @param string $name + * + * @return \GrahamCampbell\ResultType\Result + */ + private static function parseName(string $name) + { + if (Str::len($name) > 8 && Str::substr($name, 0, 6) === 'export' && \ctype_space(Str::substr($name, 6, 1))) { + $name = \ltrim(Str::substr($name, 6)); + } + + if (self::isQuotedName($name)) { + $name = Str::substr($name, 1, -1); + } + + if (!self::isValidName($name)) { + /** @var \GrahamCampbell\ResultType\Result */ + return Error::create(self::getErrorMessage('an invalid name', $name)); + } + + /** @var \GrahamCampbell\ResultType\Result */ + return Success::create($name); + } + + /** + * Is the given variable name quoted? + * + * @param string $name + * + * @return bool + */ + private static function isQuotedName(string $name) + { + if (Str::len($name) < 3) { + return false; + } + + $first = Str::substr($name, 0, 1); + $last = Str::substr($name, -1, 1); + + return ($first === '"' && $last === '"') || ($first === '\'' && $last === '\''); + } + + /** + * Is the given variable name valid? + * + * @param string $name + * + * @return bool + */ + private static function isValidName(string $name) + { + return Regex::matches('~(*UTF8)\A[\p{Ll}\p{Lu}\p{M}\p{N}_.]+\z~', $name)->success()->getOrElse(false); + } + + /** + * Parse the given variable value. + * + * This has the effect of stripping quotes and comments, dealing with + * special characters, and locating nested variables, but not resolving + * them. Formally, we run a finite state automaton with an output tape: a + * transducer. We wrap the answer in a result type. + * + * @param string $value + * + * @return \GrahamCampbell\ResultType\Result<\Dotenv\Parser\Value, string> + */ + private static function parseValue(string $value) + { + if (\trim($value) === '') { + /** @var \GrahamCampbell\ResultType\Result<\Dotenv\Parser\Value, string> */ + return Success::create(Value::blank()); + } + + return \array_reduce(\iterator_to_array(Lexer::lex($value)), static function (Result $data, string $token) { + return $data->flatMap(static function (array $data) use ($token) { + return self::processToken($data[1], $token)->map(static function (array $val) use ($data) { + return [$data[0]->append($val[0], $val[1]), $val[2]]; + }); + }); + }, Success::create([Value::blank(), self::INITIAL_STATE]))->flatMap(static function (array $result) { + /** @psalm-suppress DocblockTypeContradiction */ + if (in_array($result[1], self::REJECT_STATES, true)) { + /** @var \GrahamCampbell\ResultType\Result<\Dotenv\Parser\Value, string> */ + return Error::create('a missing closing quote'); + } + + /** @var \GrahamCampbell\ResultType\Result<\Dotenv\Parser\Value, string> */ + return Success::create($result[0]); + })->mapError(static function (string $err) use ($value) { + return self::getErrorMessage($err, $value); + }); + } + + /** + * Process the given token. + * + * @param int $state + * @param string $token + * + * @return \GrahamCampbell\ResultType\Result + */ + private static function processToken(int $state, string $token) + { + switch ($state) { + case self::INITIAL_STATE: + if ($token === '\'') { + /** @var \GrahamCampbell\ResultType\Result */ + return Success::create(['', false, self::SINGLE_QUOTED_STATE]); + } elseif ($token === '"') { + /** @var \GrahamCampbell\ResultType\Result */ + return Success::create(['', false, self::DOUBLE_QUOTED_STATE]); + } elseif ($token === '#') { + /** @var \GrahamCampbell\ResultType\Result */ + return Success::create(['', false, self::COMMENT_STATE]); + } elseif ($token === '$') { + /** @var \GrahamCampbell\ResultType\Result */ + return Success::create([$token, true, self::UNQUOTED_STATE]); + } else { + /** @var \GrahamCampbell\ResultType\Result */ + return Success::create([$token, false, self::UNQUOTED_STATE]); + } + case self::UNQUOTED_STATE: + if ($token === '#') { + /** @var \GrahamCampbell\ResultType\Result */ + return Success::create(['', false, self::COMMENT_STATE]); + } elseif (\ctype_space($token)) { + /** @var \GrahamCampbell\ResultType\Result */ + return Success::create(['', false, self::WHITESPACE_STATE]); + } elseif ($token === '$') { + /** @var \GrahamCampbell\ResultType\Result */ + return Success::create([$token, true, self::UNQUOTED_STATE]); + } else { + /** @var \GrahamCampbell\ResultType\Result */ + return Success::create([$token, false, self::UNQUOTED_STATE]); + } + case self::SINGLE_QUOTED_STATE: + if ($token === '\'') { + /** @var \GrahamCampbell\ResultType\Result */ + return Success::create(['', false, self::WHITESPACE_STATE]); + } else { + /** @var \GrahamCampbell\ResultType\Result */ + return Success::create([$token, false, self::SINGLE_QUOTED_STATE]); + } + case self::DOUBLE_QUOTED_STATE: + if ($token === '"') { + /** @var \GrahamCampbell\ResultType\Result */ + return Success::create(['', false, self::WHITESPACE_STATE]); + } elseif ($token === '\\') { + /** @var \GrahamCampbell\ResultType\Result */ + return Success::create(['', false, self::ESCAPE_SEQUENCE_STATE]); + } elseif ($token === '$') { + /** @var \GrahamCampbell\ResultType\Result */ + return Success::create([$token, true, self::DOUBLE_QUOTED_STATE]); + } else { + /** @var \GrahamCampbell\ResultType\Result */ + return Success::create([$token, false, self::DOUBLE_QUOTED_STATE]); + } + case self::ESCAPE_SEQUENCE_STATE: + if ($token === '"' || $token === '\\') { + /** @var \GrahamCampbell\ResultType\Result */ + return Success::create([$token, false, self::DOUBLE_QUOTED_STATE]); + } elseif ($token === '$') { + /** @var \GrahamCampbell\ResultType\Result */ + return Success::create([$token, false, self::DOUBLE_QUOTED_STATE]); + } else { + $first = Str::substr($token, 0, 1); + if (\in_array($first, ['f', 'n', 'r', 't', 'v'], true)) { + /** @var \GrahamCampbell\ResultType\Result */ + return Success::create([\stripcslashes('\\'.$first).Str::substr($token, 1), false, self::DOUBLE_QUOTED_STATE]); + } else { + /** @var \GrahamCampbell\ResultType\Result */ + return Error::create('an unexpected escape sequence'); + } + } + case self::WHITESPACE_STATE: + if ($token === '#') { + /** @var \GrahamCampbell\ResultType\Result */ + return Success::create(['', false, self::COMMENT_STATE]); + } elseif (!\ctype_space($token)) { + /** @var \GrahamCampbell\ResultType\Result */ + return Error::create('unexpected whitespace'); + } else { + /** @var \GrahamCampbell\ResultType\Result */ + return Success::create(['', false, self::WHITESPACE_STATE]); + } + case self::COMMENT_STATE: + /** @var \GrahamCampbell\ResultType\Result */ + return Success::create(['', false, self::COMMENT_STATE]); + default: + throw new \Error('Parser entered invalid state.'); + } + } + + /** + * Generate a friendly error message. + * + * @param string $cause + * @param string $subject + * + * @return string + */ + private static function getErrorMessage(string $cause, string $subject) + { + return \sprintf( + 'Encountered %s at [%s].', + $cause, + \strtok($subject, "\n") + ); + } +} diff --git a/api/vendor/vlucas/phpdotenv/src/Parser/Lexer.php b/api/vendor/vlucas/phpdotenv/src/Parser/Lexer.php new file mode 100644 index 0000000..981af24 --- /dev/null +++ b/api/vendor/vlucas/phpdotenv/src/Parser/Lexer.php @@ -0,0 +1,58 @@ + + */ + public static function lex(string $content) + { + static $regex; + + if ($regex === null) { + $regex = '(('.\implode(')|(', self::PATTERNS).'))A'; + } + + $offset = 0; + + while (isset($content[$offset])) { + if (!\preg_match($regex, $content, $matches, 0, $offset)) { + throw new \Error(\sprintf('Lexer encountered unexpected character [%s].', $content[$offset])); + } + + $offset += \strlen($matches[0]); + + yield $matches[0]; + } + } +} diff --git a/api/vendor/vlucas/phpdotenv/src/Parser/Lines.php b/api/vendor/vlucas/phpdotenv/src/Parser/Lines.php new file mode 100644 index 0000000..b3af160 --- /dev/null +++ b/api/vendor/vlucas/phpdotenv/src/Parser/Lines.php @@ -0,0 +1,127 @@ +map(static function () use ($line) { + return self::looksLikeMultilineStop($line, true) === false; + })->getOrElse(false); + } + + /** + * Determine if the given line can be the start of a multiline variable. + * + * @param string $line + * @param bool $started + * + * @return bool + */ + private static function looksLikeMultilineStop(string $line, bool $started) + { + if ($line === '"') { + return true; + } + + return Regex::occurrences('/(?=([^\\\\]"))/', \str_replace('\\\\', '', $line))->map(static function (int $count) use ($started) { + return $started ? $count > 1 : $count >= 1; + })->success()->getOrElse(false); + } + + /** + * Determine if the line in the file is a comment or whitespace. + * + * @param string $line + * + * @return bool + */ + private static function isCommentOrWhitespace(string $line) + { + $line = \trim($line); + + return $line === '' || (isset($line[0]) && $line[0] === '#'); + } +} diff --git a/api/vendor/vlucas/phpdotenv/src/Parser/Parser.php b/api/vendor/vlucas/phpdotenv/src/Parser/Parser.php new file mode 100644 index 0000000..bca8ec5 --- /dev/null +++ b/api/vendor/vlucas/phpdotenv/src/Parser/Parser.php @@ -0,0 +1,53 @@ +mapError(static function () { + return 'Could not split into separate lines.'; + })->flatMap(static function (array $lines) { + return self::process(Lines::process($lines)); + })->mapError(static function (string $error) { + throw new InvalidFileException(\sprintf('Failed to parse dotenv file. %s', $error)); + })->success()->get(); + } + + /** + * Convert the raw entries into proper entries. + * + * @param string[] $entries + * + * @return \GrahamCampbell\ResultType\Result<\Dotenv\Parser\Entry[], string> + */ + private static function process(array $entries) + { + /** @var \GrahamCampbell\ResultType\Result<\Dotenv\Parser\Entry[], string> */ + return \array_reduce($entries, static function (Result $result, string $raw) { + return $result->flatMap(static function (array $entries) use ($raw) { + return EntryParser::parse($raw)->map(static function (Entry $entry) use ($entries) { + /** @var \Dotenv\Parser\Entry[] */ + return \array_merge($entries, [$entry]); + }); + }); + }, Success::create([])); + } +} diff --git a/api/vendor/vlucas/phpdotenv/src/Parser/ParserInterface.php b/api/vendor/vlucas/phpdotenv/src/Parser/ParserInterface.php new file mode 100644 index 0000000..17cc42a --- /dev/null +++ b/api/vendor/vlucas/phpdotenv/src/Parser/ParserInterface.php @@ -0,0 +1,19 @@ +chars = $chars; + $this->vars = $vars; + } + + /** + * Create an empty value instance. + * + * @return \Dotenv\Parser\Value + */ + public static function blank() + { + return new self('', []); + } + + /** + * Create a new value instance, appending the characters. + * + * @param string $chars + * @param bool $var + * + * @return \Dotenv\Parser\Value + */ + public function append(string $chars, bool $var) + { + return new self( + $this->chars.$chars, + $var ? \array_merge($this->vars, [Str::len($this->chars)]) : $this->vars + ); + } + + /** + * Get the string representation of the parsed value. + * + * @return string + */ + public function getChars() + { + return $this->chars; + } + + /** + * Get the locations of the variables in the value. + * + * @return int[] + */ + public function getVars() + { + $vars = $this->vars; + + \rsort($vars); + + return $vars; + } +} diff --git a/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/AdapterInterface.php b/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/AdapterInterface.php new file mode 100644 index 0000000..5604398 --- /dev/null +++ b/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/AdapterInterface.php @@ -0,0 +1,15 @@ + + */ + public static function create(); +} diff --git a/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/ApacheAdapter.php b/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/ApacheAdapter.php new file mode 100644 index 0000000..af0aae1 --- /dev/null +++ b/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/ApacheAdapter.php @@ -0,0 +1,89 @@ + + */ + public static function create() + { + if (self::isSupported()) { + /** @var \PhpOption\Option */ + return Some::create(new self()); + } + + return None::create(); + } + + /** + * Determines if the adapter is supported. + * + * This happens if PHP is running as an Apache module. + * + * @return bool + */ + private static function isSupported() + { + return \function_exists('apache_getenv') && \function_exists('apache_setenv'); + } + + /** + * Read an environment variable, if it exists. + * + * @param non-empty-string $name + * + * @return \PhpOption\Option + */ + public function read(string $name) + { + /** @var \PhpOption\Option */ + return Option::fromValue(apache_getenv($name))->filter(static function ($value) { + return \is_string($value) && $value !== ''; + }); + } + + /** + * Write to an environment variable, if possible. + * + * @param non-empty-string $name + * @param string $value + * + * @return bool + */ + public function write(string $name, string $value) + { + return apache_setenv($name, $value); + } + + /** + * Delete an environment variable, if possible. + * + * @param non-empty-string $name + * + * @return bool + */ + public function delete(string $name) + { + return apache_setenv($name, ''); + } +} diff --git a/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/ArrayAdapter.php b/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/ArrayAdapter.php new file mode 100644 index 0000000..7c3740d --- /dev/null +++ b/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/ArrayAdapter.php @@ -0,0 +1,80 @@ + + */ + private $variables; + + /** + * Create a new array adapter instance. + * + * @return void + */ + private function __construct() + { + $this->variables = []; + } + + /** + * Create a new instance of the adapter, if it is available. + * + * @return \PhpOption\Option<\Dotenv\Repository\Adapter\AdapterInterface> + */ + public static function create() + { + /** @var \PhpOption\Option */ + return Some::create(new self()); + } + + /** + * Read an environment variable, if it exists. + * + * @param non-empty-string $name + * + * @return \PhpOption\Option + */ + public function read(string $name) + { + return Option::fromArraysValue($this->variables, $name); + } + + /** + * Write to an environment variable, if possible. + * + * @param non-empty-string $name + * @param string $value + * + * @return bool + */ + public function write(string $name, string $value) + { + $this->variables[$name] = $value; + + return true; + } + + /** + * Delete an environment variable, if possible. + * + * @param non-empty-string $name + * + * @return bool + */ + public function delete(string $name) + { + unset($this->variables[$name]); + + return true; + } +} diff --git a/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/EnvConstAdapter.php b/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/EnvConstAdapter.php new file mode 100644 index 0000000..9eb1947 --- /dev/null +++ b/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/EnvConstAdapter.php @@ -0,0 +1,89 @@ + + */ + public static function create() + { + /** @var \PhpOption\Option */ + return Some::create(new self()); + } + + /** + * Read an environment variable, if it exists. + * + * @param non-empty-string $name + * + * @return \PhpOption\Option + */ + public function read(string $name) + { + /** @var \PhpOption\Option */ + return Option::fromArraysValue($_ENV, $name) + ->filter(static function ($value) { + return \is_scalar($value); + }) + ->map(static function ($value) { + if ($value === false) { + return 'false'; + } + + if ($value === true) { + return 'true'; + } + + /** @psalm-suppress PossiblyInvalidCast */ + return (string) $value; + }); + } + + /** + * Write to an environment variable, if possible. + * + * @param non-empty-string $name + * @param string $value + * + * @return bool + */ + public function write(string $name, string $value) + { + $_ENV[$name] = $value; + + return true; + } + + /** + * Delete an environment variable, if possible. + * + * @param non-empty-string $name + * + * @return bool + */ + public function delete(string $name) + { + unset($_ENV[$name]); + + return true; + } +} diff --git a/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/GuardedWriter.php b/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/GuardedWriter.php new file mode 100644 index 0000000..fed8b9b --- /dev/null +++ b/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/GuardedWriter.php @@ -0,0 +1,85 @@ +writer = $writer; + $this->allowList = $allowList; + } + + /** + * Write to an environment variable, if possible. + * + * @param non-empty-string $name + * @param string $value + * + * @return bool + */ + public function write(string $name, string $value) + { + // Don't set non-allowed variables + if (!$this->isAllowed($name)) { + return false; + } + + // Set the value on the inner writer + return $this->writer->write($name, $value); + } + + /** + * Delete an environment variable, if possible. + * + * @param non-empty-string $name + * + * @return bool + */ + public function delete(string $name) + { + // Don't clear non-allowed variables + if (!$this->isAllowed($name)) { + return false; + } + + // Set the value on the inner writer + return $this->writer->delete($name); + } + + /** + * Determine if the given variable is allowed. + * + * @param non-empty-string $name + * + * @return bool + */ + private function isAllowed(string $name) + { + return \in_array($name, $this->allowList, true); + } +} diff --git a/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/ImmutableWriter.php b/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/ImmutableWriter.php new file mode 100644 index 0000000..3b279b8 --- /dev/null +++ b/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/ImmutableWriter.php @@ -0,0 +1,110 @@ + + */ + private $loaded; + + /** + * Create a new immutable writer instance. + * + * @param \Dotenv\Repository\Adapter\WriterInterface $writer + * @param \Dotenv\Repository\Adapter\ReaderInterface $reader + * + * @return void + */ + public function __construct(WriterInterface $writer, ReaderInterface $reader) + { + $this->writer = $writer; + $this->reader = $reader; + $this->loaded = []; + } + + /** + * Write to an environment variable, if possible. + * + * @param non-empty-string $name + * @param string $value + * + * @return bool + */ + public function write(string $name, string $value) + { + // Don't overwrite existing environment variables + // Ruby's dotenv does this with `ENV[key] ||= value` + if ($this->isExternallyDefined($name)) { + return false; + } + + // Set the value on the inner writer + if (!$this->writer->write($name, $value)) { + return false; + } + + // Record that we have loaded the variable + $this->loaded[$name] = ''; + + return true; + } + + /** + * Delete an environment variable, if possible. + * + * @param non-empty-string $name + * + * @return bool + */ + public function delete(string $name) + { + // Don't clear existing environment variables + if ($this->isExternallyDefined($name)) { + return false; + } + + // Clear the value on the inner writer + if (!$this->writer->delete($name)) { + return false; + } + + // Leave the variable as fair game + unset($this->loaded[$name]); + + return true; + } + + /** + * Determine if the given variable is externally defined. + * + * That is, is it an "existing" variable. + * + * @param non-empty-string $name + * + * @return bool + */ + private function isExternallyDefined(string $name) + { + return $this->reader->read($name)->isDefined() && !isset($this->loaded[$name]); + } +} diff --git a/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/MultiReader.php b/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/MultiReader.php new file mode 100644 index 0000000..0cfda6f --- /dev/null +++ b/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/MultiReader.php @@ -0,0 +1,48 @@ +readers = $readers; + } + + /** + * Read an environment variable, if it exists. + * + * @param non-empty-string $name + * + * @return \PhpOption\Option + */ + public function read(string $name) + { + foreach ($this->readers as $reader) { + $result = $reader->read($name); + if ($result->isDefined()) { + return $result; + } + } + + return None::create(); + } +} diff --git a/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/MultiWriter.php b/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/MultiWriter.php new file mode 100644 index 0000000..15a9d8f --- /dev/null +++ b/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/MultiWriter.php @@ -0,0 +1,64 @@ +writers = $writers; + } + + /** + * Write to an environment variable, if possible. + * + * @param non-empty-string $name + * @param string $value + * + * @return bool + */ + public function write(string $name, string $value) + { + foreach ($this->writers as $writers) { + if (!$writers->write($name, $value)) { + return false; + } + } + + return true; + } + + /** + * Delete an environment variable, if possible. + * + * @param non-empty-string $name + * + * @return bool + */ + public function delete(string $name) + { + foreach ($this->writers as $writers) { + if (!$writers->delete($name)) { + return false; + } + } + + return true; + } +} diff --git a/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/PutenvAdapter.php b/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/PutenvAdapter.php new file mode 100644 index 0000000..6d017cd --- /dev/null +++ b/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/PutenvAdapter.php @@ -0,0 +1,91 @@ + + */ + public static function create() + { + if (self::isSupported()) { + /** @var \PhpOption\Option */ + return Some::create(new self()); + } + + return None::create(); + } + + /** + * Determines if the adapter is supported. + * + * @return bool + */ + private static function isSupported() + { + return \function_exists('getenv') && \function_exists('putenv'); + } + + /** + * Read an environment variable, if it exists. + * + * @param non-empty-string $name + * + * @return \PhpOption\Option + */ + public function read(string $name) + { + /** @var \PhpOption\Option */ + return Option::fromValue(\getenv($name), false)->filter(static function ($value) { + return \is_string($value); + }); + } + + /** + * Write to an environment variable, if possible. + * + * @param non-empty-string $name + * @param string $value + * + * @return bool + */ + public function write(string $name, string $value) + { + \putenv("$name=$value"); + + return true; + } + + /** + * Delete an environment variable, if possible. + * + * @param non-empty-string $name + * + * @return bool + */ + public function delete(string $name) + { + \putenv($name); + + return true; + } +} diff --git a/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/ReaderInterface.php b/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/ReaderInterface.php new file mode 100644 index 0000000..306a63f --- /dev/null +++ b/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/ReaderInterface.php @@ -0,0 +1,17 @@ + + */ + public function read(string $name); +} diff --git a/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/ReplacingWriter.php b/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/ReplacingWriter.php new file mode 100644 index 0000000..4c92a4f --- /dev/null +++ b/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/ReplacingWriter.php @@ -0,0 +1,104 @@ + + */ + private $seen; + + /** + * Create a new replacement writer instance. + * + * @param \Dotenv\Repository\Adapter\WriterInterface $writer + * @param \Dotenv\Repository\Adapter\ReaderInterface $reader + * + * @return void + */ + public function __construct(WriterInterface $writer, ReaderInterface $reader) + { + $this->writer = $writer; + $this->reader = $reader; + $this->seen = []; + } + + /** + * Write to an environment variable, if possible. + * + * @param non-empty-string $name + * @param string $value + * + * @return bool + */ + public function write(string $name, string $value) + { + if ($this->exists($name)) { + return $this->writer->write($name, $value); + } + + // succeed if nothing to do + return true; + } + + /** + * Delete an environment variable, if possible. + * + * @param non-empty-string $name + * + * @return bool + */ + public function delete(string $name) + { + if ($this->exists($name)) { + return $this->writer->delete($name); + } + + // succeed if nothing to do + return true; + } + + /** + * Does the given environment variable exist. + * + * Returns true if it currently exists, or existed at any point in the past + * that we are aware of. + * + * @param non-empty-string $name + * + * @return bool + */ + private function exists(string $name) + { + if (isset($this->seen[$name])) { + return true; + } + + if ($this->reader->read($name)->isDefined()) { + $this->seen[$name] = ''; + + return true; + } + + return false; + } +} diff --git a/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/ServerConstAdapter.php b/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/ServerConstAdapter.php new file mode 100644 index 0000000..f93b6e5 --- /dev/null +++ b/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/ServerConstAdapter.php @@ -0,0 +1,89 @@ + + */ + public static function create() + { + /** @var \PhpOption\Option */ + return Some::create(new self()); + } + + /** + * Read an environment variable, if it exists. + * + * @param non-empty-string $name + * + * @return \PhpOption\Option + */ + public function read(string $name) + { + /** @var \PhpOption\Option */ + return Option::fromArraysValue($_SERVER, $name) + ->filter(static function ($value) { + return \is_scalar($value); + }) + ->map(static function ($value) { + if ($value === false) { + return 'false'; + } + + if ($value === true) { + return 'true'; + } + + /** @psalm-suppress PossiblyInvalidCast */ + return (string) $value; + }); + } + + /** + * Write to an environment variable, if possible. + * + * @param non-empty-string $name + * @param string $value + * + * @return bool + */ + public function write(string $name, string $value) + { + $_SERVER[$name] = $value; + + return true; + } + + /** + * Delete an environment variable, if possible. + * + * @param non-empty-string $name + * + * @return bool + */ + public function delete(string $name) + { + unset($_SERVER[$name]); + + return true; + } +} diff --git a/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/WriterInterface.php b/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/WriterInterface.php new file mode 100644 index 0000000..4cb3d61 --- /dev/null +++ b/api/vendor/vlucas/phpdotenv/src/Repository/Adapter/WriterInterface.php @@ -0,0 +1,27 @@ +reader = $reader; + $this->writer = $writer; + } + + /** + * Determine if the given environment variable is defined. + * + * @param string $name + * + * @return bool + */ + public function has(string $name) + { + return '' !== $name && $this->reader->read($name)->isDefined(); + } + + /** + * Get an environment variable. + * + * @param string $name + * + * @throws \InvalidArgumentException + * + * @return string|null + */ + public function get(string $name) + { + if ('' === $name) { + throw new InvalidArgumentException('Expected name to be a non-empty string.'); + } + + return $this->reader->read($name)->getOrElse(null); + } + + /** + * Set an environment variable. + * + * @param string $name + * @param string $value + * + * @throws \InvalidArgumentException + * + * @return bool + */ + public function set(string $name, string $value) + { + if ('' === $name) { + throw new InvalidArgumentException('Expected name to be a non-empty string.'); + } + + return $this->writer->write($name, $value); + } + + /** + * Clear an environment variable. + * + * @param string $name + * + * @throws \InvalidArgumentException + * + * @return bool + */ + public function clear(string $name) + { + if ('' === $name) { + throw new InvalidArgumentException('Expected name to be a non-empty string.'); + } + + return $this->writer->delete($name); + } +} diff --git a/api/vendor/vlucas/phpdotenv/src/Repository/RepositoryBuilder.php b/api/vendor/vlucas/phpdotenv/src/Repository/RepositoryBuilder.php new file mode 100644 index 0000000..7607924 --- /dev/null +++ b/api/vendor/vlucas/phpdotenv/src/Repository/RepositoryBuilder.php @@ -0,0 +1,272 @@ +readers = $readers; + $this->writers = $writers; + $this->immutable = $immutable; + $this->allowList = $allowList; + } + + /** + * Create a new repository builder instance with no adapters added. + * + * @return \Dotenv\Repository\RepositoryBuilder + */ + public static function createWithNoAdapters() + { + return new self(); + } + + /** + * Create a new repository builder instance with the default adapters added. + * + * @return \Dotenv\Repository\RepositoryBuilder + */ + public static function createWithDefaultAdapters() + { + $adapters = \iterator_to_array(self::defaultAdapters()); + + return new self($adapters, $adapters); + } + + /** + * Return the array of default adapters. + * + * @return \Generator<\Dotenv\Repository\Adapter\AdapterInterface> + */ + private static function defaultAdapters() + { + foreach (self::DEFAULT_ADAPTERS as $adapter) { + $instance = $adapter::create(); + if ($instance->isDefined()) { + yield $instance->get(); + } + } + } + + /** + * Determine if the given name if of an adapterclass. + * + * @param string $name + * + * @return bool + */ + private static function isAnAdapterClass(string $name) + { + if (!\class_exists($name)) { + return false; + } + + return (new ReflectionClass($name))->implementsInterface(AdapterInterface::class); + } + + /** + * Creates a repository builder with the given reader added. + * + * Accepts either a reader instance, or a class-string for an adapter. If + * the adapter is not supported, then we silently skip adding it. + * + * @param \Dotenv\Repository\Adapter\ReaderInterface|string $reader + * + * @throws \InvalidArgumentException + * + * @return \Dotenv\Repository\RepositoryBuilder + */ + public function addReader($reader) + { + if (!(\is_string($reader) && self::isAnAdapterClass($reader)) && !($reader instanceof ReaderInterface)) { + throw new InvalidArgumentException( + \sprintf( + 'Expected either an instance of %s or a class-string implementing %s', + ReaderInterface::class, + AdapterInterface::class + ) + ); + } + + $optional = Some::create($reader)->flatMap(static function ($reader) { + return \is_string($reader) ? $reader::create() : Some::create($reader); + }); + + $readers = \array_merge($this->readers, \iterator_to_array($optional)); + + return new self($readers, $this->writers, $this->immutable, $this->allowList); + } + + /** + * Creates a repository builder with the given writer added. + * + * Accepts either a writer instance, or a class-string for an adapter. If + * the adapter is not supported, then we silently skip adding it. + * + * @param \Dotenv\Repository\Adapter\WriterInterface|string $writer + * + * @throws \InvalidArgumentException + * + * @return \Dotenv\Repository\RepositoryBuilder + */ + public function addWriter($writer) + { + if (!(\is_string($writer) && self::isAnAdapterClass($writer)) && !($writer instanceof WriterInterface)) { + throw new InvalidArgumentException( + \sprintf( + 'Expected either an instance of %s or a class-string implementing %s', + WriterInterface::class, + AdapterInterface::class + ) + ); + } + + $optional = Some::create($writer)->flatMap(static function ($writer) { + return \is_string($writer) ? $writer::create() : Some::create($writer); + }); + + $writers = \array_merge($this->writers, \iterator_to_array($optional)); + + return new self($this->readers, $writers, $this->immutable, $this->allowList); + } + + /** + * Creates a repository builder with the given adapter added. + * + * Accepts either an adapter instance, or a class-string for an adapter. If + * the adapter is not supported, then we silently skip adding it. We will + * add the adapter as both a reader and a writer. + * + * @param \Dotenv\Repository\Adapter\WriterInterface|string $adapter + * + * @throws \InvalidArgumentException + * + * @return \Dotenv\Repository\RepositoryBuilder + */ + public function addAdapter($adapter) + { + if (!(\is_string($adapter) && self::isAnAdapterClass($adapter)) && !($adapter instanceof AdapterInterface)) { + throw new InvalidArgumentException( + \sprintf( + 'Expected either an instance of %s or a class-string implementing %s', + WriterInterface::class, + AdapterInterface::class + ) + ); + } + + $optional = Some::create($adapter)->flatMap(static function ($adapter) { + return \is_string($adapter) ? $adapter::create() : Some::create($adapter); + }); + + $readers = \array_merge($this->readers, \iterator_to_array($optional)); + $writers = \array_merge($this->writers, \iterator_to_array($optional)); + + return new self($readers, $writers, $this->immutable, $this->allowList); + } + + /** + * Creates a repository builder with mutability enabled. + * + * @return \Dotenv\Repository\RepositoryBuilder + */ + public function immutable() + { + return new self($this->readers, $this->writers, true, $this->allowList); + } + + /** + * Creates a repository builder with the given allow list. + * + * @param string[]|null $allowList + * + * @return \Dotenv\Repository\RepositoryBuilder + */ + public function allowList(?array $allowList = null) + { + return new self($this->readers, $this->writers, $this->immutable, $allowList); + } + + /** + * Creates a new repository instance. + * + * @return \Dotenv\Repository\RepositoryInterface + */ + public function make() + { + $reader = new MultiReader($this->readers); + $writer = new MultiWriter($this->writers); + + if ($this->immutable) { + $writer = new ImmutableWriter($writer, $reader); + } + + if ($this->allowList !== null) { + $writer = new GuardedWriter($writer, $this->allowList); + } + + return new AdapterRepository($reader, $writer); + } +} diff --git a/api/vendor/vlucas/phpdotenv/src/Repository/RepositoryInterface.php b/api/vendor/vlucas/phpdotenv/src/Repository/RepositoryInterface.php new file mode 100644 index 0000000..d9b18a4 --- /dev/null +++ b/api/vendor/vlucas/phpdotenv/src/Repository/RepositoryInterface.php @@ -0,0 +1,51 @@ + + */ + public static function read(array $filePaths, bool $shortCircuit = true, ?string $fileEncoding = null) + { + $output = []; + + foreach ($filePaths as $filePath) { + $content = self::readFromFile($filePath, $fileEncoding); + if ($content->isDefined()) { + $output[$filePath] = $content->get(); + if ($shortCircuit) { + break; + } + } + } + + return $output; + } + + /** + * Read the given file. + * + * @param string $path + * @param string|null $encoding + * + * @throws \Dotenv\Exception\InvalidEncodingException + * + * @return \PhpOption\Option + */ + private static function readFromFile(string $path, ?string $encoding = null) + { + /** @var Option */ + $content = Option::fromValue(@\file_get_contents($path), false); + + return $content->flatMap(static function (string $content) use ($encoding) { + return Str::utf8($content, $encoding)->mapError(static function (string $error) { + throw new InvalidEncodingException($error); + })->success(); + }); + } +} diff --git a/api/vendor/vlucas/phpdotenv/src/Store/FileStore.php b/api/vendor/vlucas/phpdotenv/src/Store/FileStore.php new file mode 100644 index 0000000..e7a4d3f --- /dev/null +++ b/api/vendor/vlucas/phpdotenv/src/Store/FileStore.php @@ -0,0 +1,72 @@ +filePaths = $filePaths; + $this->shortCircuit = $shortCircuit; + $this->fileEncoding = $fileEncoding; + } + + /** + * Read the content of the environment file(s). + * + * @throws \Dotenv\Exception\InvalidEncodingException|\Dotenv\Exception\InvalidPathException + * + * @return string + */ + public function read() + { + if ($this->filePaths === []) { + throw new InvalidPathException('At least one environment file path must be provided.'); + } + + $contents = Reader::read($this->filePaths, $this->shortCircuit, $this->fileEncoding); + + if (\count($contents) > 0) { + return \implode("\n", $contents); + } + + throw new InvalidPathException( + \sprintf('Unable to read any of the environment file(s) at [%s].', \implode(', ', $this->filePaths)) + ); + } +} diff --git a/api/vendor/vlucas/phpdotenv/src/Store/StoreBuilder.php b/api/vendor/vlucas/phpdotenv/src/Store/StoreBuilder.php new file mode 100644 index 0000000..2ce0851 --- /dev/null +++ b/api/vendor/vlucas/phpdotenv/src/Store/StoreBuilder.php @@ -0,0 +1,141 @@ +paths = $paths; + $this->names = $names; + $this->shortCircuit = $shortCircuit; + $this->fileEncoding = $fileEncoding; + } + + /** + * Create a new store builder instance with no names. + * + * @return \Dotenv\Store\StoreBuilder + */ + public static function createWithNoNames() + { + return new self(); + } + + /** + * Create a new store builder instance with the default name. + * + * @return \Dotenv\Store\StoreBuilder + */ + public static function createWithDefaultName() + { + return new self([], [self::DEFAULT_NAME]); + } + + /** + * Creates a store builder with the given path added. + * + * @param string $path + * + * @return \Dotenv\Store\StoreBuilder + */ + public function addPath(string $path) + { + return new self(\array_merge($this->paths, [$path]), $this->names, $this->shortCircuit, $this->fileEncoding); + } + + /** + * Creates a store builder with the given name added. + * + * @param string $name + * + * @return \Dotenv\Store\StoreBuilder + */ + public function addName(string $name) + { + return new self($this->paths, \array_merge($this->names, [$name]), $this->shortCircuit, $this->fileEncoding); + } + + /** + * Creates a store builder with short circuit mode enabled. + * + * @return \Dotenv\Store\StoreBuilder + */ + public function shortCircuit() + { + return new self($this->paths, $this->names, true, $this->fileEncoding); + } + + /** + * Creates a store builder with the specified file encoding. + * + * @param string|null $fileEncoding + * + * @return \Dotenv\Store\StoreBuilder + */ + public function fileEncoding(?string $fileEncoding = null) + { + return new self($this->paths, $this->names, $this->shortCircuit, $fileEncoding); + } + + /** + * Creates a new store instance. + * + * @return \Dotenv\Store\StoreInterface + */ + public function make() + { + return new FileStore( + Paths::filePaths($this->paths, $this->names), + $this->shortCircuit, + $this->fileEncoding + ); + } +} diff --git a/api/vendor/vlucas/phpdotenv/src/Store/StoreInterface.php b/api/vendor/vlucas/phpdotenv/src/Store/StoreInterface.php new file mode 100644 index 0000000..6f5b986 --- /dev/null +++ b/api/vendor/vlucas/phpdotenv/src/Store/StoreInterface.php @@ -0,0 +1,17 @@ +content = $content; + } + + /** + * Read the content of the environment file(s). + * + * @return string + */ + public function read() + { + return $this->content; + } +} diff --git a/api/vendor/vlucas/phpdotenv/src/Util/Regex.php b/api/vendor/vlucas/phpdotenv/src/Util/Regex.php new file mode 100644 index 0000000..599f09c --- /dev/null +++ b/api/vendor/vlucas/phpdotenv/src/Util/Regex.php @@ -0,0 +1,112 @@ + + */ + public static function matches(string $pattern, string $subject) + { + return self::pregAndWrap(static function (string $subject) use ($pattern) { + return @\preg_match($pattern, $subject) === 1; + }, $subject); + } + + /** + * Perform a preg match all, wrapping up the result. + * + * @param string $pattern + * @param string $subject + * + * @return \GrahamCampbell\ResultType\Result + */ + public static function occurrences(string $pattern, string $subject) + { + return self::pregAndWrap(static function (string $subject) use ($pattern) { + return (int) @\preg_match_all($pattern, $subject); + }, $subject); + } + + /** + * Perform a preg replace callback, wrapping up the result. + * + * @param string $pattern + * @param callable(string[]): string $callback + * @param string $subject + * @param int|null $limit + * + * @return \GrahamCampbell\ResultType\Result + */ + public static function replaceCallback(string $pattern, callable $callback, string $subject, ?int $limit = null) + { + return self::pregAndWrap(static function (string $subject) use ($pattern, $callback, $limit) { + return (string) @\preg_replace_callback($pattern, $callback, $subject, $limit ?? -1); + }, $subject); + } + + /** + * Perform a preg split, wrapping up the result. + * + * @param string $pattern + * @param string $subject + * + * @return \GrahamCampbell\ResultType\Result + */ + public static function split(string $pattern, string $subject) + { + return self::pregAndWrap(static function (string $subject) use ($pattern) { + /** @var string[] */ + return (array) @\preg_split($pattern, $subject); + }, $subject); + } + + /** + * Perform a preg operation, wrapping up the result. + * + * @template V + * + * @param callable(string): V $operation + * @param string $subject + * + * @return \GrahamCampbell\ResultType\Result + */ + private static function pregAndWrap(callable $operation, string $subject) + { + $result = $operation($subject); + + if (\preg_last_error() !== \PREG_NO_ERROR) { + /** @var \GrahamCampbell\ResultType\Result */ + return Error::create(\preg_last_error_msg()); + } + + /** @var \GrahamCampbell\ResultType\Result */ + return Success::create($result); + } +} diff --git a/api/vendor/vlucas/phpdotenv/src/Util/Str.php b/api/vendor/vlucas/phpdotenv/src/Util/Str.php new file mode 100644 index 0000000..b113d78 --- /dev/null +++ b/api/vendor/vlucas/phpdotenv/src/Util/Str.php @@ -0,0 +1,108 @@ + + */ + public static function utf8(string $input, ?string $encoding = null) + { + if ($encoding !== null && !\in_array($encoding, \mb_list_encodings(), true)) { + /** @var \GrahamCampbell\ResultType\Result */ + return Error::create( + \sprintf('Illegal character encoding [%s] specified.', $encoding) + ); + } + + $converted = $encoding === null ? + @\mb_convert_encoding($input, 'UTF-8') : + @\mb_convert_encoding($input, 'UTF-8', $encoding); + + if (!is_string($converted)) { + /** @var \GrahamCampbell\ResultType\Result */ + return Error::create( + \sprintf('Conversion from encoding [%s] failed.', $encoding ?? 'NULL') + ); + } + + /** + * this is for support UTF-8 with BOM encoding + * @see https://en.wikipedia.org/wiki/Byte_order_mark + * @see https://github.com/vlucas/phpdotenv/issues/500 + */ + if (\substr($converted, 0, 3) == "\xEF\xBB\xBF") { + $converted = \substr($converted, 3); + } + + /** @var \GrahamCampbell\ResultType\Result */ + return Success::create($converted); + } + + /** + * Search for a given substring of the input. + * + * @param string $haystack + * @param string $needle + * + * @return \PhpOption\Option + */ + public static function pos(string $haystack, string $needle) + { + /** @var \PhpOption\Option */ + return Option::fromValue(\mb_strpos($haystack, $needle, 0, 'UTF-8'), false); + } + + /** + * Grab the specified substring of the input. + * + * @param string $input + * @param int $start + * @param int|null $length + * + * @return string + */ + public static function substr(string $input, int $start, ?int $length = null) + { + return \mb_substr($input, $start, $length, 'UTF-8'); + } + + /** + * Compute the length of the given string. + * + * @param string $input + * + * @return int + */ + public static function len(string $input) + { + return \mb_strlen($input, 'UTF-8'); + } +} diff --git a/api/vendor/vlucas/phpdotenv/src/Validator.php b/api/vendor/vlucas/phpdotenv/src/Validator.php new file mode 100644 index 0000000..d5580c7 --- /dev/null +++ b/api/vendor/vlucas/phpdotenv/src/Validator.php @@ -0,0 +1,207 @@ +repository = $repository; + $this->variables = $variables; + } + + /** + * Assert that each variable is present. + * + * @throws \Dotenv\Exception\ValidationException + * + * @return \Dotenv\Validator + */ + public function required() + { + return $this->assert( + static function (?string $value) { + return $value !== null; + }, + 'is missing' + ); + } + + /** + * Assert that each variable is not empty. + * + * @throws \Dotenv\Exception\ValidationException + * + * @return \Dotenv\Validator + */ + public function notEmpty() + { + return $this->assertNullable( + static function (string $value) { + return Str::len(\trim($value)) > 0; + }, + 'is empty' + ); + } + + /** + * Assert that each specified variable is an integer. + * + * @throws \Dotenv\Exception\ValidationException + * + * @return \Dotenv\Validator + */ + public function isInteger() + { + return $this->assertNullable( + static function (string $value) { + return \ctype_digit($value); + }, + 'is not an integer' + ); + } + + /** + * Assert that each specified variable is a boolean. + * + * @throws \Dotenv\Exception\ValidationException + * + * @return \Dotenv\Validator + */ + public function isBoolean() + { + return $this->assertNullable( + static function (string $value) { + if ($value === '') { + return false; + } + + return \filter_var($value, \FILTER_VALIDATE_BOOLEAN, \FILTER_NULL_ON_FAILURE) !== null; + }, + 'is not a boolean' + ); + } + + /** + * Assert that each variable is amongst the given choices. + * + * @param string[] $choices + * + * @throws \Dotenv\Exception\ValidationException + * + * @return \Dotenv\Validator + */ + public function allowedValues(array $choices) + { + return $this->assertNullable( + static function (string $value) use ($choices) { + return \in_array($value, $choices, true); + }, + \sprintf('is not one of [%s]', \implode(', ', $choices)) + ); + } + + /** + * Assert that each variable matches the given regular expression. + * + * @param string $regex + * + * @throws \Dotenv\Exception\ValidationException + * + * @return \Dotenv\Validator + */ + public function allowedRegexValues(string $regex) + { + return $this->assertNullable( + static function (string $value) use ($regex) { + return Regex::matches($regex, $value)->success()->getOrElse(false); + }, + \sprintf('does not match "%s"', $regex) + ); + } + + /** + * Assert that the callback returns true for each variable. + * + * @param callable(?string):bool $callback + * @param string $message + * + * @throws \Dotenv\Exception\ValidationException + * + * @return \Dotenv\Validator + */ + public function assert(callable $callback, string $message) + { + $failing = []; + + foreach ($this->variables as $variable) { + if ($callback($this->repository->get($variable)) === false) { + $failing[] = \sprintf('%s %s', $variable, $message); + } + } + + if (\count($failing) > 0) { + throw new ValidationException(\sprintf( + 'One or more environment variables failed assertions: %s.', + \implode(', ', $failing) + )); + } + + return $this; + } + + /** + * Assert that the callback returns true for each variable. + * + * Skip checking null variable values. + * + * @param callable(string):bool $callback + * @param string $message + * + * @throws \Dotenv\Exception\ValidationException + * + * @return \Dotenv\Validator + */ + public function assertNullable(callable $callback, string $message) + { + return $this->assert( + static function (?string $value) use ($callback) { + if ($value === null) { + return true; + } + + return $callback($value); + }, + $message + ); + } +} diff --git a/api/vendor/zounar/php-proxy/.gitignore b/api/vendor/zounar/php-proxy/.gitignore new file mode 100644 index 0000000..daef67c --- /dev/null +++ b/api/vendor/zounar/php-proxy/.gitignore @@ -0,0 +1,4 @@ +.idea/ +.vscode/ + +vendor/ diff --git a/api/vendor/zounar/php-proxy/LICENSE b/api/vendor/zounar/php-proxy/LICENSE new file mode 100644 index 0000000..68a49da --- /dev/null +++ b/api/vendor/zounar/php-proxy/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +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 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. + +For more information, please refer to diff --git a/api/vendor/zounar/php-proxy/Proxy.php b/api/vendor/zounar/php-proxy/Proxy.php new file mode 100644 index 0000000..5691aea --- /dev/null +++ b/api/vendor/zounar/php-proxy/Proxy.php @@ -0,0 +1,470 @@ + + * @license http://unlicense.org + * @package Zounar\PHPProxy + * + * Credits to: + * https://github.com/cowboy/php-simple-proxy/ + * https://gist.github.com/iovar + * + * Usage: + * To call this script two headers must be sent + * HTTP_PROXY_AUTH Access key for the proxy (should be changed) + * HTTP_PROXY_TARGET_URL URL to be called by this script + * + * Debug: + * To debug, send HTTP_PROXY_DEBUG header with any non-zero value + * + * Compatibility: + * PHP >=5.6 + * libcurl + * gzip + * PHP safe_mode disabled + */ +class Proxy +{ + /** + * Your private auth key. It is recommended to change it. + * If you installed the package via composer, call `Proxy::$AUTH_KEY = '';` before running the proxy. + * If you copied this file, change the value here in place. + * @var string + */ + public static $AUTH_KEY = 'Bj5pnZEX6DkcG6Nz6AjDUT1bvcGRVhRaXDuKDX9CjsEs2'; + + /** + * Set this to false to disable authorization. Useful for debugging, not recommended in production. + * @var bool + */ + public static $ENABLE_AUTH = true; + + /** + * If true, PHP safe mode compatibility will not be checked + * (you may not need it if no POST files are sent over proxy) + * @var bool + */ + public static $IGNORE_SAFE_MODE = false; + + /** + * Enable debug mode (you can do it by sending Proxy-Debug header as well). + * This value overrides any value specified in Proxy-Debug header. + * @var bool + */ + public static $DEBUG = false; + + /** + * When set to false the fetched header is not included in the result + * @var bool + */ + public static $CURLOPT_HEADER = true; + + /** + * When set to false the fetched result is echoed immediately instead of waiting for the fetch to complete first + * @var bool + */ + public static $CURLOPT_RETURNTRANSFER = true; + + /** + * Target URL is set via Proxy-Target-URL header. For debugging purposes you might set it directly here. + * This value overrides any value specified in Proxy-Target-URL header. + * @var string + */ + public static $TARGET_URL = ''; + + /** + * Name of remote debug header + * @var string + */ + public static $HEADER_HTTP_PROXY_DEBUG = 'HTTP_PROXY_DEBUG'; + + /** + * Name of the proxy auth key header + * @var string + */ + public static $HEADER_HTTP_PROXY_AUTH = 'HTTP_PROXY_AUTH'; + + /** + * Name of the target url header + * @var string + */ + public static $HEADER_HTTP_PROXY_TARGET_URL = 'HTTP_PROXY_TARGET_URL'; + + /** + * Line break for debug purposes + * @var string + */ + protected static $HR = PHP_EOL . PHP_EOL . '----------------------------------------------' . PHP_EOL . PHP_EOL; + + /** + * @return string[] + */ + protected static function getSkippedHeaders() + { + return [ + static::$HEADER_HTTP_PROXY_TARGET_URL, + static::$HEADER_HTTP_PROXY_AUTH, + static::$HEADER_HTTP_PROXY_DEBUG, + 'HTTP_HOST', + 'HTTP_ACCEPT_ENCODING' + ]; + } + + /** + * Return variable or default value if not set + * @param mixed $variable + * @param mixed|null $default + * @return mixed + * @noinspection PhpParameterByRefIsNotUsedAsReferenceInspection + */ + protected static function ri(&$variable, $default = null) + { + if (isset($variable)) { + return $variable; + } else { + return $default; + } + } + + /** + * @param string $message + */ + protected static function exitWithError($message) + { + http_response_code(500); + echo 'PROXY ERROR: ' . $message; + exit(500); + } + + /** + * @return bool + */ + public static function isInstalledWithComposer() + { + $autoloaderPath = join(DIRECTORY_SEPARATOR, [dirname(dirname(__DIR__)), 'autoload.php']); + return is_readable($autoloaderPath); + } + + /** + * @return void + */ + public static function registerErrorHandlers() + { + set_error_handler(function ($code, $message, $file, $line) { + Proxy::exitWithError("($code) $message in $file at line $line"); + }, E_ALL); + + set_exception_handler(function (Exception $ex) { + Proxy::exitWithError("{$ex->getMessage()} in {$ex->getFile()} at line {$ex->getLine()}"); + }); + } + + /** + * @return void + */ + public static function checkCompatibility() + { + if (!static::$IGNORE_SAFE_MODE && function_exists('ini_get') && ini_get('safe_mode')) { + throw new RuntimeException('Safe mode is enabled, this may cause problems with uploading files'); + } + + if (!function_exists('curl_init')) { + throw new RuntimeException('libcurl is not installed on this server'); + } + + if (!function_exists('gzdecode')) { + throw new RuntimeException('gzip is not installed on this server'); + } + } + + /** + * @return bool + */ + protected static function hasCURLFileSupport() + { + return class_exists('CURLFile'); + } + + /** + * @param string $headerString + * @return string[] + */ + protected static function splitResponseHeaders($headerString) + { + $results = []; + $headerLines = preg_split('/[\r\n]+/', $headerString); + foreach ($headerLines as $headerLine) { + if (empty($headerLine)) { + continue; + } + + // Header contains HTTP version specification and path + if (strpos($headerLine, 'HTTP/') === 0) { + // Reset the output array as there may by multiple response headers + $results = []; + continue; + } + + $results[] = "$headerLine"; + } + + return $results; + } + + /** + * Returns true if response code matches 2xx or 3xx + * @param int $responseCode + * @return bool + */ + public static function isResponseCodeOk($responseCode) + { + return preg_match('/^[23]\d\d$/', $responseCode) === 1; + } + + /** + * @return string + */ + protected static function getTargetUrl() + { + if (!empty(static::$TARGET_URL)) { + $targetURL = static::$TARGET_URL; + } else { + $targetURL = static::ri($_SERVER[static::$HEADER_HTTP_PROXY_TARGET_URL]); + } + + if (empty($targetURL)) { + throw new RuntimeException(static::$HEADER_HTTP_PROXY_TARGET_URL . ' header is empty'); + } + + if (filter_var($targetURL, FILTER_VALIDATE_URL) === false) { + throw new RuntimeException(static::$HEADER_HTTP_PROXY_TARGET_URL . ' "' . $targetURL . '" is invalid'); + } + + return $targetURL; + } + + /** + * @return bool + */ + protected static function isDebug() + { + return static::$DEBUG || !empty($_SERVER[static::$HEADER_HTTP_PROXY_DEBUG]); + } + + /** + * @return bool + */ + protected static function isAuthenticated() + { + return !static::$ENABLE_AUTH || static::ri($_SERVER[static::$HEADER_HTTP_PROXY_AUTH]) === static::$AUTH_KEY; + } + + /** + * @param string[] $skippedHeaders + * @return string[] + */ + protected static function getIncomingRequestHeaders($skippedHeaders = []) + { + $results = []; + foreach ($_SERVER as $key => $value) { + if (in_array($key, $skippedHeaders)) { + continue; + } + + $loweredKey = strtolower($key); + if (strpos($loweredKey, 'http_') === 0) { + // Remove prefix + $key = substr($loweredKey, strlen('http_')); + // Replace underscores with dashes + $key = str_replace('_', '-', $key); + // Capital each word + $key = ucwords($key, '-'); + + $results[] = "$key: $value"; + } + } + + return $results; + } + + /** + * @param string $targetURL + * @return false|resource + */ + protected static function createRequest($targetURL) + { + $request = curl_init($targetURL); + + // Set input data + $requestMethod = strtoupper(static::ri($_SERVER['REQUEST_METHOD'])); + if ($requestMethod === "PUT" || $requestMethod === "PATCH") { + curl_setopt($request, CURLOPT_POSTFIELDS, file_get_contents('php://input')); + } elseif ($requestMethod === "POST") { + $data = array(); + + if (!empty($_FILES)) { + if (!static::hasCURLFileSupport()) { + curl_setopt($request, CURLOPT_SAFE_UPLOAD, false); + } + + foreach ($_FILES as $fileName => $file) { + $filePath = realpath($file['tmp_name']); + + if (static::hasCURLFileSupport()) { + $data[$fileName] = new CURLFile($filePath, $file['type'], $file['name']); + } else { + $data[$fileName] = '@' . $filePath; + } + } + } + + curl_setopt($request, CURLOPT_POSTFIELDS, $data + $_POST); + } + + $headers = static::getIncomingRequestHeaders(static::getSkippedHeaders()); + + curl_setopt_array($request, [ + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_HEADER => static::$CURLOPT_HEADER, + CURLOPT_RETURNTRANSFER => static::$CURLOPT_RETURNTRANSFER, + CURLINFO_HEADER_OUT => true, + CURLOPT_HTTPHEADER => $headers + ]); + + return $request; + } + + /** + * @return int HTTP response code (200, 404, 500, etc.) + */ + public static function run() + { + if (!static::isAuthenticated()) { + throw new RuntimeException(static::$HEADER_HTTP_PROXY_AUTH . ' header is invalid'); + } + + $debug = static::isDebug(); + $targetURL = static::getTargetUrl(); + + $request = static::createRequest($targetURL); + + // Get response + $response = curl_exec($request); + + $headerSize = curl_getinfo($request, CURLINFO_HEADER_SIZE); + $responseHeader = substr($response, 0, $headerSize); + $responseBody = substr($response, $headerSize); + $responseInfo = curl_getinfo($request); + $responseCode = static::ri($responseInfo['http_code'], 500); + $redirectCount = static::ri($responseInfo['redirect_count'], 0); + $requestHeaders = preg_split('/[\r\n]+/', static::ri($responseInfo['request_header'], '')); + if ($responseCode === 0) { + $responseCode = 404; + } + + $finalRequestURL = curl_getinfo($request, CURLINFO_EFFECTIVE_URL); + if ($redirectCount > 0 && !empty($finalRequestURL)) { + $finalRequestURLParts = parse_url($finalRequestURL); + $effectiveURL = static::ri($finalRequestURLParts['scheme'], 'http') . '://' . + static::ri($finalRequestURLParts['host']) . static::ri($finalRequestURLParts['path'], ''); + } + + curl_close($request); + + //---------------------------------- + + // Split header text into an array. + $responseHeaders = static::splitResponseHeaders($responseHeader); + // Pass headers to output + foreach ($responseHeaders as $header) { + $headerParts = preg_split('/:\s+/', $header, 2); + if (count($headerParts) !== 2) { + throw new RuntimeException("Can not parse header \"$header\""); + } + + $headerName = $headerParts[0]; + $loweredHeaderName = strtolower($headerName); + + $headerValue = $headerParts[1]; + $loweredHeaderValue = strtolower($headerValue); + + // Pass following headers to response + if (in_array($loweredHeaderName, + ['content-type', 'content-language', 'content-security', 'server'])) { + header("$headerName: $headerValue"); + } elseif (strpos($loweredHeaderName, 'x-') === 0) { + header("$headerName: $headerValue"); + } // Replace cookie domain and path + elseif ($loweredHeaderName === 'set-cookie') { + $newValue = preg_replace('/((?>domain)\s*=\s*)[^;\s]+/', '\1.' . $_SERVER['HTTP_HOST'], $headerValue); + $newValue = preg_replace('/\s*;?\s*path\s*=\s*[^;\s]+/', '', $newValue); + header("$headerName: $newValue", false); + } // Decode response body if gzip encoding is used + elseif ($loweredHeaderName === 'content-encoding' && $loweredHeaderValue === 'gzip') { + $responseBody = gzdecode($responseBody); + } + } + + http_response_code($responseCode); + + //---------------------------------- + + if ($debug) { + echo 'Headers sent to proxy' . PHP_EOL . PHP_EOL; + echo implode(PHP_EOL, static::getIncomingRequestHeaders()); + echo static::$HR; + + if (!empty($_GET)) { + echo '$_GET sent to proxy' . PHP_EOL . PHP_EOL; + print_r($_GET); + echo static::$HR; + } + + if (!empty($_POST)) { + echo '$_POST sent to proxy' . PHP_EOL . PHP_EOL; + print_r($_POST); + echo static::$HR; + } + + echo 'Headers sent to target' . PHP_EOL . PHP_EOL; + echo implode(PHP_EOL, $requestHeaders); + echo static::$HR; + + if (isset($effectiveURL) && $effectiveURL !== $targetURL) { + echo "Request was redirected from \"$targetURL\" to \"$effectiveURL\""; + echo static::$HR; + } + + echo 'Headers received from target' . PHP_EOL . PHP_EOL; + echo $responseHeader; + echo static::$HR; + + echo 'Headers sent from proxy to client' . PHP_EOL . PHP_EOL; + echo implode(PHP_EOL, headers_list()); + echo static::$HR; + + echo 'Body sent from proxy to client' . PHP_EOL . PHP_EOL; + } + + echo $responseBody; + return $responseCode; + } +} + +if (!Proxy::isInstalledWithComposer()) { + Proxy::checkCompatibility(); + Proxy::registerErrorHandlers(); + $responseCode = Proxy::run(); + + if (Proxy::isResponseCodeOk($responseCode)) { + exit(0); + } else { + exit($responseCode); + } +} diff --git a/api/vendor/zounar/php-proxy/README.md b/api/vendor/zounar/php-proxy/README.md new file mode 100644 index 0000000..590646c --- /dev/null +++ b/api/vendor/zounar/php-proxy/README.md @@ -0,0 +1,118 @@ +# Simple PHP Proxy + +This proxy script allows you to forward all HTTP/HTTPS requests to another server. Works for all common request types +including GET, POST requests with files, PATCH and PUT requests. It has minimal set of requirements +(PHP >=5.6, libcurl, gzip) which are available even on the smallest free hostings and has its own simple authorization +and cookie support. + +## How to use +* Copy the [Proxy.php](Proxy.php) script to publicly-accessible folder of a PHP web server (the script is standalone and has no PHP dependencies) +* Make a cURL request targeting this script +* Add **Proxy-Auth** header with auth key [found here](https://github.com/zounar/php-proxy/blob/master/Proxy.php#L40) +* Add **Proxy-Target-URL** header with URL to be requested by the proxy +* (Optional) Add **Proxy-Debug** header for debug mode + +In order to protect using proxy by unauthorized users, consider changing `Proxy-Auth` token in [proxy source file](https://github.com/zounar/php-proxy/blob/master/Proxy.php#L40) and in all your requests. + +## How to use (via composer) +This might be useful when you want to redirect requests coming into your app. + +* Run `composer require zounar/php-proxy` +* Add `Proxy::run();` line to where you want to execute it (usually into a controller action) + * In this example, the script is in `AppController` - `actionProxy`: + ``` + use Zounar\PHPProxy\Proxy; + + class AppController extends Controller { + + public function actionProxy() { + Proxy::$AUTH_KEY = ''; + // Do your custom logic before running proxy + $responseCode = Proxy::run(); + // Do your custom logic after running proxy + // You can utilize HTTP response code returned from the run() method + } + } + ``` +* Make a cURL request to your web + * In the example, it would be `http://your-web.com/app/proxy` +* Add **Proxy-Auth** header with auth key [found here](https://github.com/zounar/php-proxy/blob/master/Proxy.php#L40) +* Add **Proxy-Target-URL** header with URL to be requested by the proxy +* (Optional) Add **Proxy-Debug** header for debug mode + +In order to protect using proxy by unauthorized users, consider changing `Proxy-Auth` token by calling +`Proxy::$AUTH_KEY = '';` before `Proxy::run()`. Then change the token in all your requests. + +## Usage example +Following example shows how to execute GET request to https://www.github.com. Proxy script is at http://www.foo.bar/Proxy.php. All proxy settings are kept default, the response is automatically echoed. + +```php +$request = curl_init('http://www.foo.bar/Proxy.php'); + +curl_setopt($request, CURLOPT_HTTPHEADER, array( + 'Proxy-Auth: Bj5pnZEX6DkcG6Nz6AjDUT1bvcGRVhRaXDuKDX9CjsEs2', + 'Proxy-Target-URL: https://www.github.com' +)); + +curl_exec($request); +``` + +## Debugging +In order to show some debug info from the proxy, add `Proxy-Debug: 1` header into the request. This will show debug info in plain-text containing request headers, response headers and response body. + +```php +$request = curl_init('http://www.foo.bar/Proxy.php'); + +curl_setopt($request, CURLOPT_HTTPHEADER, array( + 'Proxy-Auth: Bj5pnZEX6DkcG6Nz6AjDUT1bvcGRVhRaXDuKDX9CjsEs2', + 'Proxy-Target-URL: https://www.github.com', + 'Proxy-Debug: 1' +)); + +curl_exec($request); +``` + +## Specifying User-Agent +Some sites may return different content for different user agents. In such case add `User-Agent` header to cURL request, it will be automatically passed to the request for target site. In this case it's Firefox 70 for Ubuntu. + +```php +$request = curl_init('http://www.foo.bar/Proxy.php'); + +curl_setopt($request, CURLOPT_HTTPHEADER, array( + 'User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:70.0) Gecko/20100101 Firefox/70.0', + 'Proxy-Auth: Bj5pnZEX6DkcG6Nz6AjDUT1bvcGRVhRaXDuKDX9CjsEs2', + 'Proxy-Target-URL: https://www.github.com' +)); + +curl_exec($request); +``` + +## Error 301 Moved permanently +It might occur that there's a redirection when calling the proxy (not the target site), eg. during `http -> https` redirection. You can either modify/fix the proxy URL (which is recommended), or add `CURLOPT_FOLLOWLOCATION` option before `curl_exec`. + +```php +$request = curl_init('http://www.foo.bar/Proxy.php'); + +curl_setopt($request, CURLOPT_FOLLOWLOCATION, true ); +curl_setopt($request, CURLOPT_HTTPHEADER, array( + 'Proxy-Auth: Bj5pnZEX6DkcG6Nz6AjDUT1bvcGRVhRaXDuKDX9CjsEs2', + 'Proxy-Target-URL: https://www.github.com' +)); + +curl_exec($request); +``` + +## Save response into variable +The default cURL behavior is to echo the response of `curl_exec`. In order to save response into variable, all you have to do is to add `CURLOPT_RETURNTRANSFER` cURL option. + +```php +$request = curl_init('http://www.foo.bar/Proxy.php'); + +curl_setopt($request, CURLOPT_RETURNTRANSFER, true); +curl_setopt($request, CURLOPT_HTTPHEADER, array( + 'Proxy-Auth: Bj5pnZEX6DkcG6Nz6AjDUT1bvcGRVhRaXDuKDX9CjsEs2', + 'Proxy-Target-URL: https://www.github.com' +)); + +$response = curl_exec($request); +``` diff --git a/api/vendor/zounar/php-proxy/composer.json b/api/vendor/zounar/php-proxy/composer.json new file mode 100644 index 0000000..55ac2c9 --- /dev/null +++ b/api/vendor/zounar/php-proxy/composer.json @@ -0,0 +1,39 @@ +{ + "name": "zounar/php-proxy", + "description": "Forward your HTTP/HTTPS requests to another server.", + "type": "library", + "keywords": [ + "php-proxy", + "proxy-script", + "php", + "proxy", + "http", + "http-proxy", + "curl", + "curlphp" + ], + "homepage": "https://github.com/zounar/php-proxy", + "readme": "README.md", + "require": { + "php": ">=5.6.0", + "ext-curl": "*", + "ext-zlib": "*" + }, + "license": "unlicense", + "authors": [ + { + "name": "Robin Zounar", + "homepage": "https://zounar.me" + } + ], + "support": { + "issues": "https://github.com/zounar/php-proxy/issues", + "source": "https://github.com/zounar/php-proxy", + "docs": "https://github.com/zounar/php-proxy/blob/master/README.md" + }, + "autoload": { + "psr-4": { + "Zounar\\PHPProxy\\": "./" + } + } +} diff --git a/api/vendor/zounar/php-proxy/composer.lock b/api/vendor/zounar/php-proxy/composer.lock new file mode 100644 index 0000000..087c63a --- /dev/null +++ b/api/vendor/zounar/php-proxy/composer.lock @@ -0,0 +1,22 @@ +{ + "_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": "a101b9e5b9b0bff50de607452cc30901", + "packages": [], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=5.6.0", + "ext-curl": "*", + "ext-zlib": "*" + }, + "platform-dev": [], + "plugin-api-version": "2.0.0" +} diff --git a/api/vendor/zounar/php-proxy/docker-compose.yml b/api/vendor/zounar/php-proxy/docker-compose.yml new file mode 100644 index 0000000..5a49602 --- /dev/null +++ b/api/vendor/zounar/php-proxy/docker-compose.yml @@ -0,0 +1,11 @@ +version: "2" +services: + proxy: +# image: webdevops/php-nginx:8.0 +# image: webdevops/php-nginx:7.4 + image: webdevops/php-nginx:5.6 + ports: + - 80:80 + - 443:443 + volumes: + - ./:/app diff --git a/app/package-lock.json b/app/package-lock.json new file mode 100644 index 0000000..e2970f9 --- /dev/null +++ b/app/package-lock.json @@ -0,0 +1,9390 @@ +{ + "name": "nuxt-app", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "nuxt-app", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-svg-core": "^6.7.2", + "@fortawesome/free-solid-svg-icons": "^6.7.2", + "@fortawesome/vue-fontawesome": "^3.0.8", + "nuxt": "^3.17.6", + "vue": "^3.5.17", + "vue-router": "^4.5.1" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz", + "integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.3.tgz", + "integrity": "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==", + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.3", + "@babel/parser": "^7.28.3", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.3", + "@babel/types": "^7.28.2", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", + "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.3", + "@babel/types": "^7.28.2", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.3.tgz", + "integrity": "sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.28.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz", + "integrity": "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", + "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.3.tgz", + "integrity": "sha512-PTNtvUQihsAsDHMOP5pfobP8C6CM4JWXmP8DrEIt46c3r2bf87Ua1zoqevsMo9g+tWDwgWrFP5EIxuBx5RudAw==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.3.tgz", + "integrity": "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", + "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", + "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.0.tgz", + "integrity": "sha512-4AEiDEBPIZvLQaWlc9liCavE0xRM0dNca41WtBeM3jgFptfUOSG9z0uteLhq6+3rq+WB6jIvUwKDTpXEHPJ2Vg==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.3.tgz", + "integrity": "sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.3", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.2", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz", + "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@cloudflare/kv-asset-handler": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.4.0.tgz", + "integrity": "sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA==", + "license": "MIT OR Apache-2.0", + "dependencies": { + "mime": "^3.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@cloudflare/kv-asset-handler/node_modules/mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@emnapi/core": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.5.0.tgz", + "integrity": "sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.1.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz", + "integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", + "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz", + "integrity": "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.9.tgz", + "integrity": "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz", + "integrity": "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.9.tgz", + "integrity": "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz", + "integrity": "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz", + "integrity": "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz", + "integrity": "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz", + "integrity": "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz", + "integrity": "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz", + "integrity": "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz", + "integrity": "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz", + "integrity": "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz", + "integrity": "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz", + "integrity": "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz", + "integrity": "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz", + "integrity": "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz", + "integrity": "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz", + "integrity": "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz", + "integrity": "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz", + "integrity": "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz", + "integrity": "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz", + "integrity": "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz", + "integrity": "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz", + "integrity": "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz", + "integrity": "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz", + "integrity": "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@fortawesome/fontawesome-common-types": { + "version": "6.7.2", + "resolved": "https://npm.fontawesome.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.7.2.tgz", + "integrity": "sha512-Zs+YeHUC5fkt7Mg1l6XTniei3k4bwG/yo3iFUtZWd/pMx9g3fdvkSK9E0FOC+++phXOka78uJcYb8JaFkW52Xg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/fontawesome-svg-core": { + "version": "6.7.2", + "resolved": "https://npm.fontawesome.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.7.2.tgz", + "integrity": "sha512-yxtOBWDrdi5DD5o1pmVdq3WMCvnobT0LU6R8RyyVXPvFRd2o79/0NCuQoCjNTeZz9EzA9xS3JxNWfv54RIHFEA==", + "license": "MIT", + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.7.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-solid-svg-icons": { + "version": "6.7.2", + "resolved": "https://npm.fontawesome.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.7.2.tgz", + "integrity": "sha512-GsBrnOzU8uj0LECDfD5zomZJIjrPhIlWU82AHwa2s40FKH+kcxQaBvBo3Z4TxyZHIyX8XTDxsyA33/Vx9eFuQA==", + "license": "(CC-BY-4.0 AND MIT)", + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.7.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/vue-fontawesome": { + "version": "3.1.1", + "resolved": "https://npm.fontawesome.com/@fortawesome/vue-fontawesome/-/vue-fontawesome-3.1.1.tgz", + "integrity": "sha512-U5azn4mcUVpjHe4JO0Wbe7Ih8e3VbN83EH7OTBtA5/QGw9qcPGffqcmwsLyZYgEkpVkYbq/6dX1Iyl5KUGMp6Q==", + "license": "MIT", + "peerDependencies": { + "@fortawesome/fontawesome-svg-core": "~1 || ~6 || ~7", + "vue": ">= 3.0.0 < 4" + } + }, + "node_modules/@ioredis/commands": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.3.1.tgz", + "integrity": "sha512-bYtU8avhGIcje3IhvF9aSjsa5URMZBHnwKtOvXsT4sfYy9gppW11gLPT/9oNqlJZD47yPKveQFTAFWpHjKvUoQ==", + "license": "MIT" + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.30", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz", + "integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@kwsites/file-exists": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", + "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", + "license": "MIT", + "dependencies": { + "debug": "^4.1.1" + } + }, + "node_modules/@kwsites/promise-deferred": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", + "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==", + "license": "MIT" + }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-2.0.0.tgz", + "integrity": "sha512-llMXd39jtP0HpQLVI37Bf1m2ADlEb35GYSh1SDSLsBhR+5iCxiNGlT31yqbNtVHygHAtMy6dWFERpU2JgufhPg==", + "license": "BSD-3-Clause", + "dependencies": { + "consola": "^3.2.3", + "detect-libc": "^2.0.0", + "https-proxy-agent": "^7.0.5", + "node-fetch": "^2.6.7", + "nopt": "^8.0.0", + "semver": "^7.5.3", + "tar": "^7.4.0" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/detect-libc": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.0.3.tgz", + "integrity": "sha512-rZxtMsLwjdXkMUGC3WwsPwLNVqVqnTJT6MNIB6e+5fhMcSCPP0AOsNWuMQ5mdCq6HNjs/ZeWAEchpqeprqBD2Q==", + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.5", + "@emnapi/runtime": "^1.4.5", + "@tybys/wasm-util": "^0.10.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nuxt/cli": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@nuxt/cli/-/cli-3.28.0.tgz", + "integrity": "sha512-WQ751WxWLBIeH3TDFt/LWQ2znyAKxpR5+gpv80oerwnVQs4GKajAfR6dIgExXZkjaPUHEFv2lVD9vM+frbprzw==", + "license": "MIT", + "dependencies": { + "c12": "^3.2.0", + "citty": "^0.1.6", + "clipboardy": "^4.0.0", + "confbox": "^0.2.2", + "consola": "^3.4.2", + "defu": "^6.1.4", + "exsolve": "^1.0.7", + "fuse.js": "^7.1.0", + "get-port-please": "^3.2.0", + "giget": "^2.0.0", + "h3": "^1.15.4", + "httpxy": "^0.1.7", + "jiti": "^2.5.1", + "listhen": "^1.9.0", + "nypm": "^0.6.1", + "ofetch": "^1.4.1", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "perfect-debounce": "^1.0.0", + "pkg-types": "^2.2.0", + "scule": "^1.3.0", + "semver": "^7.7.2", + "std-env": "^3.9.0", + "tinyexec": "^1.0.1", + "ufo": "^1.6.1", + "youch": "^4.1.0-beta.11" + }, + "bin": { + "nuxi": "bin/nuxi.mjs", + "nuxi-ng": "bin/nuxi.mjs", + "nuxt": "bin/nuxi.mjs", + "nuxt-cli": "bin/nuxi.mjs" + }, + "engines": { + "node": "^16.10.0 || >=18.0.0" + } + }, + "node_modules/@nuxt/cli/node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "license": "MIT" + }, + "node_modules/@nuxt/devalue": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@nuxt/devalue/-/devalue-2.0.2.tgz", + "integrity": "sha512-GBzP8zOc7CGWyFQS6dv1lQz8VVpz5C2yRszbXufwG/9zhStTIH50EtD87NmWbTMwXDvZLNg8GIpb1UFdH93JCA==", + "license": "MIT" + }, + "node_modules/@nuxt/devtools": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/@nuxt/devtools/-/devtools-2.6.3.tgz", + "integrity": "sha512-n+8we7pr0tNl6w+KfbFDXZsYpWIYL4vG/daIdRF66lQ6fLyQy/CcxDAx8+JNu3Ew96RjuBtWRSbCCv454L5p0Q==", + "license": "MIT", + "dependencies": { + "@nuxt/devtools-kit": "2.6.3", + "@nuxt/devtools-wizard": "2.6.3", + "@nuxt/kit": "^3.18.1", + "@vue/devtools-core": "^7.7.7", + "@vue/devtools-kit": "^7.7.7", + "birpc": "^2.5.0", + "consola": "^3.4.2", + "destr": "^2.0.5", + "error-stack-parser-es": "^1.0.5", + "execa": "^8.0.1", + "fast-npm-meta": "^0.4.6", + "get-port-please": "^3.2.0", + "hookable": "^5.5.3", + "image-meta": "^0.2.1", + "is-installed-globally": "^1.0.0", + "launch-editor": "^2.11.1", + "local-pkg": "^1.1.2", + "magicast": "^0.3.5", + "nypm": "^0.6.1", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "perfect-debounce": "^1.0.0", + "pkg-types": "^2.3.0", + "semver": "^7.7.2", + "simple-git": "^3.28.0", + "sirv": "^3.0.1", + "structured-clone-es": "^1.0.0", + "tinyglobby": "^0.2.14", + "vite-plugin-inspect": "^11.3.2", + "vite-plugin-vue-tracer": "^1.0.0", + "which": "^5.0.0", + "ws": "^8.18.3" + }, + "bin": { + "devtools": "cli.mjs" + }, + "peerDependencies": { + "vite": ">=6.0" + } + }, + "node_modules/@nuxt/devtools-kit": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/@nuxt/devtools-kit/-/devtools-kit-2.6.3.tgz", + "integrity": "sha512-cDmai3Ws6AbJlYy1p4CCwc718cfbqtAjXe6oEc6q03zoJnvX1PsvKUfmU+yuowfqTSR6DZRmH4SjCBWuMjgaKQ==", + "license": "MIT", + "dependencies": { + "@nuxt/kit": "^3.18.1", + "execa": "^8.0.1" + }, + "peerDependencies": { + "vite": ">=6.0" + } + }, + "node_modules/@nuxt/devtools-wizard": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/@nuxt/devtools-wizard/-/devtools-wizard-2.6.3.tgz", + "integrity": "sha512-FWXPkuJ1RUp+9nWP5Vvk29cJPNtm4OO38bgr9G8vGbqcRznzgaSODH/92c8sm2dKR7AF+9MAYLL+BexOWOkljQ==", + "license": "MIT", + "dependencies": { + "consola": "^3.4.2", + "diff": "^8.0.2", + "execa": "^8.0.1", + "magicast": "^0.3.5", + "pathe": "^2.0.3", + "pkg-types": "^2.3.0", + "prompts": "^2.4.2", + "semver": "^7.7.2" + }, + "bin": { + "devtools-wizard": "cli.mjs" + } + }, + "node_modules/@nuxt/devtools/node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "license": "MIT" + }, + "node_modules/@nuxt/kit": { + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-3.19.0.tgz", + "integrity": "sha512-kecjqWORKdy7xnsOf/X4NtsFMbn+hNiiYhsA+INYVbgoyhCdx1rpEURCJdQITzHehXy5QWINTqmjNGp//PO4CQ==", + "license": "MIT", + "dependencies": { + "c12": "^3.2.0", + "consola": "^3.4.2", + "defu": "^6.1.4", + "destr": "^2.0.5", + "errx": "^0.1.0", + "exsolve": "^1.0.7", + "ignore": "^7.0.5", + "jiti": "^2.5.1", + "klona": "^2.0.6", + "knitwork": "^1.2.0", + "mlly": "^1.8.0", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "pkg-types": "^2.3.0", + "rc9": "^2.1.2", + "scule": "^1.3.0", + "semver": "^7.7.2", + "std-env": "^3.9.0", + "tinyglobby": "^0.2.14", + "ufo": "^1.6.1", + "unctx": "^2.4.1", + "unimport": "^5.2.0", + "untyped": "^2.0.0" + }, + "engines": { + "node": ">=18.12.0" + } + }, + "node_modules/@nuxt/schema": { + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/@nuxt/schema/-/schema-3.19.0.tgz", + "integrity": "sha512-V3vgqXFruyOe7s8nBt+6OD+yQ18tqq5aLF7KPNJ5OaBvdWy24S5s4SbhUfgCNJmVmmsXsbxgHi9amz5uRFiaIw==", + "license": "MIT", + "dependencies": { + "@vue/shared": "^3.5.20", + "consola": "^3.4.2", + "defu": "^6.1.4", + "pathe": "^2.0.3", + "std-env": "^3.9.0", + "ufo": "1.6.1" + }, + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/@nuxt/telemetry": { + "version": "2.6.6", + "resolved": "https://registry.npmjs.org/@nuxt/telemetry/-/telemetry-2.6.6.tgz", + "integrity": "sha512-Zh4HJLjzvm3Cq9w6sfzIFyH9ozK5ePYVfCUzzUQNiZojFsI2k1QkSBrVI9BGc6ArKXj/O6rkI6w7qQ+ouL8Cag==", + "license": "MIT", + "dependencies": { + "@nuxt/kit": "^3.15.4", + "citty": "^0.1.6", + "consola": "^3.4.2", + "destr": "^2.0.3", + "dotenv": "^16.4.7", + "git-url-parse": "^16.0.1", + "is-docker": "^3.0.0", + "ofetch": "^1.4.1", + "package-manager-detector": "^1.1.0", + "pathe": "^2.0.3", + "rc9": "^2.1.2", + "std-env": "^3.8.1" + }, + "bin": { + "nuxt-telemetry": "bin/nuxt-telemetry.mjs" + }, + "engines": { + "node": ">=18.12.0" + } + }, + "node_modules/@nuxt/vite-builder": { + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/@nuxt/vite-builder/-/vite-builder-3.19.0.tgz", + "integrity": "sha512-a7Zn4+smxMhZqXlDLE2fhHZfYBeOVYtjeg1s/yK/1T5LWOqHu9NGtNhJT7notYM491Mrp5eY9UaaiHlmTnI0dA==", + "license": "MIT", + "dependencies": { + "@nuxt/kit": "3.19.0", + "@rollup/plugin-replace": "^6.0.2", + "@vitejs/plugin-vue": "^6.0.1", + "@vitejs/plugin-vue-jsx": "^5.1.1", + "autoprefixer": "^10.4.21", + "consola": "^3.4.2", + "cssnano": "^7.1.1", + "defu": "^6.1.4", + "esbuild": "^0.25.9", + "escape-string-regexp": "^5.0.0", + "exsolve": "^1.0.7", + "externality": "^1.0.2", + "get-port-please": "^3.2.0", + "h3": "^1.15.4", + "jiti": "^2.5.1", + "knitwork": "^1.2.0", + "magic-string": "^0.30.18", + "mlly": "^1.8.0", + "mocked-exports": "^0.1.1", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "perfect-debounce": "^2.0.0", + "pkg-types": "^2.3.0", + "postcss": "^8.5.6", + "rollup-plugin-visualizer": "^6.0.3", + "std-env": "^3.9.0", + "ufo": "^1.6.1", + "unenv": "^2.0.0-rc.19", + "vite": "^7.1.4", + "vite-node": "^3.2.4", + "vite-plugin-checker": "^0.10.3", + "vue-bundle-renderer": "^2.1.2" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vue": "^3.3.4" + } + }, + "node_modules/@oxc-minify/binding-android-arm64": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-android-arm64/-/binding-android-arm64-0.86.0.tgz", + "integrity": "sha512-jOgbDgp6A1ax9sxHPRHBxUpxIzp2VTgbZ/6HPKIVUJ7IQqKVsELKFXIOEbCDlb1rUhZZtGf53MFypXf72kR5eQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-minify/binding-darwin-arm64": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-darwin-arm64/-/binding-darwin-arm64-0.86.0.tgz", + "integrity": "sha512-LQkjIHhIzxVYnxfC2QV7MMe4hgqIbwK07j+zzEsNWWfdmWABw11Aa6FP0uIvERmoxstzsDT77F8c/+xhxswKiw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-minify/binding-darwin-x64": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-darwin-x64/-/binding-darwin-x64-0.86.0.tgz", + "integrity": "sha512-AuLkeXIvJ535qOhFzZfHBkcEZA59SN1vKUblW2oN+6ClZfIMru0I2wr0cCHA9QDxIVDkI7swDu29qcn2AqKdrg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-minify/binding-freebsd-x64": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-freebsd-x64/-/binding-freebsd-x64-0.86.0.tgz", + "integrity": "sha512-UcXLcM8+iHW1EL+peHHV1HDBFUVdoxFMJC7HBc2U83q9oiF/K73TnAEgW/xteR+IvbV/9HD+cQsH+DX6oBXoQg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-minify/binding-linux-arm-gnueabihf": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.86.0.tgz", + "integrity": "sha512-UtSplQY10Idp//cLS5i2rFaunS71padZFavHLHygNAxJBt+37DPKDl/4kddpV6Kv2Mr6bhw2KpXGAVs0C3dIOw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-minify/binding-linux-arm-musleabihf": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.86.0.tgz", + "integrity": "sha512-P5efCOl9QiwqqJHrw1Q+4ssexvOz+MAmgTmBorbdEM3WJdIHR1CWGDj4GqcvKBlwpBqt4XilOuoN0QD8dfl85A==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-minify/binding-linux-arm64-gnu": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.86.0.tgz", + "integrity": "sha512-hwHahfs//g9iZLQmKldjQPmnpzq76eyHvfkmdnXXmPtwTHnwXL1hPlNbTIqakUirAsroBeQwXqzHm3I040R+mg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-minify/binding-linux-arm64-musl": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.86.0.tgz", + "integrity": "sha512-S2dL24nxWqDCwrq48xlZBvhSIBcEWOu3aDOiaccP4q73PiTLrf6rm1M11J7vQNSRiH6ao9UKr7ZMsepCZcOyfA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-minify/binding-linux-riscv64-gnu": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.86.0.tgz", + "integrity": "sha512-itZ24A1a5NOw0ibbt6EYOHdBojfV4vbiC209d06Dwv5WLXtntHCjc8P4yfrCsC22uDmMPNkVa+UL+OM4mkUrwg==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-minify/binding-linux-s390x-gnu": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.86.0.tgz", + "integrity": "sha512-/nJAwS/uit19qXNpaOybf7GYJI7modbXYVZ8q1pIFdxs6HkhZLxS1ZvcIzY3W75+37u+uKeZ4MbygawAN8kQpQ==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-minify/binding-linux-x64-gnu": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.86.0.tgz", + "integrity": "sha512-3qnWZB2cOj5Em/uEJqJ1qP/8lxtoi/Rf1U8fmdLzPW5zIaiTRUr/LklB4aJ+Vc/GU5g3HX5nFPQG3ZnEV3Ktzg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-minify/binding-linux-x64-musl": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-x64-musl/-/binding-linux-x64-musl-0.86.0.tgz", + "integrity": "sha512-+ZqYG8IQSRq9dR2djrnyzGHlmwGRKdueVjHYbEOwngb/4h/+FxAOaNUbsoUsCthAfXTrZHVXiQMTKJ32r7j2Bg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-minify/binding-wasm32-wasi": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-wasm32-wasi/-/binding-wasm32-wasi-0.86.0.tgz", + "integrity": "sha512-ixeSZW7jzd3g9fh8MoR9AzGLQxMCo//Q2mVpO2S/4NmcPtMaJEog85KzHULgUvbs70RqxTHEUqtVgpnc/5lMWA==", + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^1.0.3" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-minify/binding-win32-arm64-msvc": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.86.0.tgz", + "integrity": "sha512-cN309CnFVG8jeSRd+lQGnoMpZAVmz4bzH4fgqJM0NsMXVnFPGFceG/XiToLoBA1FigGQvkV0PJ7MQKWxBHPoUA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-minify/binding-win32-x64-msvc": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-minify/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.86.0.tgz", + "integrity": "sha512-YAqCKtZ9KKhSW73d/Oa9Uut0myYnCEUL2D0buMjJ4p0PuK1PQsMCJsmX4ku0PgK31snanZneRwtEjjNFYNdX2A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-parser/binding-android-arm64": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm64/-/binding-android-arm64-0.86.0.tgz", + "integrity": "sha512-BfNFEWpRo4gqLHKvRuQmhbPGeJqB1Ka/hsPhKf1imAojwUcf/Dr/yRkZBuEi2yc1LWBjApKYJEqpsBUmtqSY1Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@oxc-parser/binding-darwin-arm64": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-arm64/-/binding-darwin-arm64-0.86.0.tgz", + "integrity": "sha512-gRSnEHcyNEfLdNj6v8XKcuHUaZnRpH2lOZFztuGEi23ENydPOQVEtiZYexuHOTeaLGgzw+93TgB4n/YkjYodug==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@oxc-parser/binding-darwin-x64": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-x64/-/binding-darwin-x64-0.86.0.tgz", + "integrity": "sha512-6mdymm8i+VpLTJP19D3PSFumMmAyfhhhIRWcRHsc0bL7CSZjCWbvRb00ActKrGKWtsol/A/KKgqglJwpvjlzOA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@oxc-parser/binding-freebsd-x64": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-freebsd-x64/-/binding-freebsd-x64-0.86.0.tgz", + "integrity": "sha512-mc2xYRPxhzFg4NX1iqfIWP+8ORtXiNpAkaomNDepegQFlIFUmrESa3IJrKJ/4vg77Tbti7omHbraOqwdTk849g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm-gnueabihf": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.86.0.tgz", + "integrity": "sha512-LZzapjFhwGQMKefcFsn3lJc/mTY37fBlm0jjEvETgNCyd5pH4gDwOcrp/wZHAz2qw5uLWOHaa69I6ci5lBjJgA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm-musleabihf": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.86.0.tgz", + "integrity": "sha512-/rhJMpng7/Qgn8hE4sigxTRb04+zdO0K1kfAMZ3nONphk5r2Yk2RjyEpLLz17adysCyQw/KndaMHNv8GR8VMNg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm64-gnu": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.86.0.tgz", + "integrity": "sha512-IXEZnk6O0zJg5gDn1Zvt5Qx62Z3E+ewrKwPgMfExqnNCLq+Ix2g7hQypevm/S6qxVgyz5HbiW+a/5ziMFXTCJQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@oxc-parser/binding-linux-arm64-musl": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.86.0.tgz", + "integrity": "sha512-QG7DUVZ/AtBaUGMhgToB4glOdq0MGAEYU1MJQpNB5HqiEcOpteF9Pd+oPfscj2zrGPd47KNyljtJRBKJr6Ut0w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@oxc-parser/binding-linux-riscv64-gnu": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.86.0.tgz", + "integrity": "sha512-smz+J6riX2du2lp0IKeZSaOBIhhoE2N/L1IQdOLCpzB0ikjCDBoyNKdDM7te8ZDq3KDnRmJChmhQGd8P1/LGBQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@oxc-parser/binding-linux-s390x-gnu": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.86.0.tgz", + "integrity": "sha512-vas1BOMWVdicuimmi5Y+xPj3csaYQquVA45Im9a/DtVsypVeh8RWYXBMO1qJNM5Fg5HD0QvYNqxvftx3c+f5pg==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@oxc-parser/binding-linux-x64-gnu": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.86.0.tgz", + "integrity": "sha512-3Fsi+JA3NwdZdrpC6AieOP48cuBrq0q59JgnR0mfoWfr9wHrbn2lt8EEubrj6EXpBUmu1Zii7S9NNRC6fl/d+w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@oxc-parser/binding-linux-x64-musl": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-musl/-/binding-linux-x64-musl-0.86.0.tgz", + "integrity": "sha512-89/d43EW76wJagz8u5zcKW8itB2rnS/uN7un5APb8Ebme8TePBwDyxo64J6oY5rcJYkfJ6lEszSF/ovicsNVPw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@oxc-parser/binding-wasm32-wasi": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-wasm32-wasi/-/binding-wasm32-wasi-0.86.0.tgz", + "integrity": "sha512-gRrGmE2L27stNMeiAucy/ffHF9VjYr84MizuJzSYnnKmd5WXf3HelNdd0UYSJnpb7APBuyFSN2Oato+Qb6yAFw==", + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^1.0.3" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-parser/binding-win32-arm64-msvc": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.86.0.tgz", + "integrity": "sha512-parTnpNviJYR3JIFLseDGip1KkYbhWLeuZG9OMek62gr6Omflddoytvb17s+qODoZqFAVjvuOmVipDdjTl9q3Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@oxc-parser/binding-win32-x64-msvc": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.86.0.tgz", + "integrity": "sha512-FTso24eQh3vPTe/SOTf0/RXfjJ13tsk5fw728fm+z5y6Rb+mmEBfyVT6XxyGhEwtdfnRSZawheX74/9caI1etw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.86.0.tgz", + "integrity": "sha512-bJ57vWNQnOnUe5ZxUkrWpLyExxqb0BoyQ+IRmI/V1uxHbBNBzFGMIjKIf5ECFsgS0KgUUl8TM3a4xpeAtAnvIA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@oxc-transform/binding-android-arm64": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-android-arm64/-/binding-android-arm64-0.86.0.tgz", + "integrity": "sha512-025JJoCWi04alNef6WvLnGCbx2MH9Ld2xvr0168bpOcpBjxt8sOZawu0MPrZQhnNWWiX8rrwrhuUDasWCWHxFw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-transform/binding-darwin-arm64": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-darwin-arm64/-/binding-darwin-arm64-0.86.0.tgz", + "integrity": "sha512-dJls3eCO1Y2dc4zAdA+fiRbQwlvFFDmfRHRpGOllwS1FtvKQ7dMkRFKsHODEdxWakxISLvyabUmkGOhcJ47Dog==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-transform/binding-darwin-x64": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-darwin-x64/-/binding-darwin-x64-0.86.0.tgz", + "integrity": "sha512-udMZFZn6FEy36tVMs/yrczEqWyCJc+l/lqIMS4xYWsm/6qVafUWDSAZJLgcPilng16IdMnHINkc8NSz7Pp1EVw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-transform/binding-freebsd-x64": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-freebsd-x64/-/binding-freebsd-x64-0.86.0.tgz", + "integrity": "sha512-41J5qSlypbE0HCOd+4poFD96+ZKoR8sfDn5qdaU0Hc5bT5Drwat/wv06s9Y5Lu86uXYTwPPj6kbbxHHsiV2irw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-transform/binding-linux-arm-gnueabihf": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.86.0.tgz", + "integrity": "sha512-mrI+nKgwRsr4FYjb0pECrNTVnNvHAflukS3SFqFHI8n+3LJgrCYDcnbrFD/4VWKp2EUrkIZ//RhwgGsTiSXbng==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-transform/binding-linux-arm-musleabihf": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.86.0.tgz", + "integrity": "sha512-FXWyvpxiEXBewA3L6HGFtEribqFjGOiounD8ke/4C1F5134+rH5rNrgK6vY116P4MtWKfZolMRdvlzaD3TaX0A==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-transform/binding-linux-arm64-gnu": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.86.0.tgz", + "integrity": "sha512-gktU/9WLAc0d2hAq8yRi3K92xwkWoDt1gJmokMOfb1FU4fyDbzbt13jdZEd6KVn2xLaiQeaFTTfFTghFsJUM3A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-transform/binding-linux-arm64-musl": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.86.0.tgz", + "integrity": "sha512-2w5e5qiTBYQ0xc1aSY1GNyAOP9BQFEjN43FI3OhrRWZXHOj3inqcVSlptO/hHGK3Q2bG26kWLfSNFOEylTX39A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-transform/binding-linux-riscv64-gnu": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.86.0.tgz", + "integrity": "sha512-PfnTYm+vQ9X5VNXqs0Z3S67Xp2FoZj5RteYKUNwL+j/sxGi05eps+EWLVrcGsuN9x2GHFpTiqBz3lzERCn2USg==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-transform/binding-linux-s390x-gnu": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.86.0.tgz", + "integrity": "sha512-uHgGN0rFfqDcdkLUITshqrpV34PRKAiRwsw6Jgkg7CRcRGIU8rOJc568EU0jfhTZ1zO5MJKt/S8D6cgIFJwe0A==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-transform/binding-linux-x64-gnu": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.86.0.tgz", + "integrity": "sha512-MtrvfU2RkSD+oTnzG4Xle3jK8FXJPQa1MhYQm0ivcAMf0tUQDojTaqBtM/9E0iFr/4l1xZODJOHCGjLktdpykg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-transform/binding-linux-x64-musl": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-x64-musl/-/binding-linux-x64-musl-0.86.0.tgz", + "integrity": "sha512-wTTTIPcnoS04SRJ7HuOL/VxIu1QzUtv2n6Mx0wPIEQobj2qPGum0qYGnFEMU0Njltp+8FAUg5EfX6u3udRQBbQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-transform/binding-wasm32-wasi": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-wasm32-wasi/-/binding-wasm32-wasi-0.86.0.tgz", + "integrity": "sha512-g+0bf+ZA2DvBHQ+0u8TvEY8ERo86Brqvdghfv06Wph2qGTlhzSmrE0c0Zurr7yhtqI5yZjMaBr2HbqwW1kHFng==", + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^1.0.3" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-transform/binding-win32-arm64-msvc": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.86.0.tgz", + "integrity": "sha512-dgBeU4qBEag0rhW3OT9YHgj4cvW51KZzrxhDQ1gAVX2fqgl+CeJnu0a9q+DMhefHrO3c8Yxwbt7NxUDmWGkEtg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oxc-transform/binding-win32-x64-msvc": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/@oxc-transform/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.86.0.tgz", + "integrity": "sha512-M1eCl8xz7MmEatuqWdr+VdvNCUJ+d4ECF+HND39PqRCVkaH+Vl1rcyP5pLILb2CB/wTb2DMvZmb9RCt5+8S5TQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@parcel/watcher": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", + "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.1", + "@parcel/watcher-darwin-arm64": "2.5.1", + "@parcel/watcher-darwin-x64": "2.5.1", + "@parcel/watcher-freebsd-x64": "2.5.1", + "@parcel/watcher-linux-arm-glibc": "2.5.1", + "@parcel/watcher-linux-arm-musl": "2.5.1", + "@parcel/watcher-linux-arm64-glibc": "2.5.1", + "@parcel/watcher-linux-arm64-musl": "2.5.1", + "@parcel/watcher-linux-x64-glibc": "2.5.1", + "@parcel/watcher-linux-x64-musl": "2.5.1", + "@parcel/watcher-win32-arm64": "2.5.1", + "@parcel/watcher-win32-ia32": "2.5.1", + "@parcel/watcher-win32-x64": "2.5.1" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", + "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", + "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", + "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", + "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", + "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", + "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", + "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", + "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", + "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", + "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-wasm": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-wasm/-/watcher-wasm-2.5.1.tgz", + "integrity": "sha512-RJxlQQLkaMMIuWRozy+z2vEqbaQlCuaCgVZIUCzQLYggY22LZbP5Y1+ia+FD724Ids9e+XIyOLXLrLgQSHIthw==", + "bundleDependencies": [ + "napi-wasm" + ], + "license": "MIT", + "dependencies": { + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "napi-wasm": "^1.1.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-wasm/node_modules/napi-wasm": { + "version": "1.1.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", + "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", + "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", + "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "license": "MIT" + }, + "node_modules/@poppinss/colors": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@poppinss/colors/-/colors-4.1.5.tgz", + "integrity": "sha512-FvdDqtcRCtz6hThExcFOgW0cWX+xwSMWcRuQe5ZEb2m7cVQOAVZOIMt+/v9RxGiD9/OY16qJBXK4CVKWAPalBw==", + "license": "MIT", + "dependencies": { + "kleur": "^4.1.5" + } + }, + "node_modules/@poppinss/colors/node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@poppinss/dumper": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/@poppinss/dumper/-/dumper-0.6.4.tgz", + "integrity": "sha512-iG0TIdqv8xJ3Lt9O8DrPRxw1MRLjNpoqiSGU03P/wNLP/s0ra0udPJ1J2Tx5M0J3H/cVyEgpbn8xUKRY9j59kQ==", + "license": "MIT", + "dependencies": { + "@poppinss/colors": "^4.1.5", + "@sindresorhus/is": "^7.0.2", + "supports-color": "^10.0.0" + } + }, + "node_modules/@poppinss/exception": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@poppinss/exception/-/exception-1.2.2.tgz", + "integrity": "sha512-m7bpKCD4QMlFCjA/nKTs23fuvoVFoA83brRKmObCUNmi/9tVu8Ve3w4YQAnJu4q3Tjf5fr685HYIC/IA2zHRSg==", + "license": "MIT" + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.29", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.29.tgz", + "integrity": "sha512-NIJgOsMjbxAXvoGq/X0gD7VPMQ8j9g0BiDaNjVNVjvl+iKXxL3Jre0v31RmBYeLEmkbj2s02v8vFTbUXi5XS2Q==", + "license": "MIT" + }, + "node_modules/@rollup/plugin-alias": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-alias/-/plugin-alias-5.1.1.tgz", + "integrity": "sha512-PR9zDb+rOzkRb2VD+EuKB7UC41vU5DIwZ5qqCpk0KJudcWAyi8rvYOhS7+L5aZCspw1stTViLgN5v6FF1p5cgQ==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-commonjs": { + "version": "28.0.6", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.6.tgz", + "integrity": "sha512-XSQB1K7FUU5QP+3lOQmVCE3I0FcbbNvmNT4VJSj93iUjayaARrTQeoRdiYQoftAJBLrR9t2agwAd3ekaTgHNlw==", + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "commondir": "^1.0.1", + "estree-walker": "^2.0.2", + "fdir": "^6.2.0", + "is-reference": "1.2.1", + "magic-string": "^0.30.3", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=16.0.0 || 14 >= 14.17" + }, + "peerDependencies": { + "rollup": "^2.68.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-commonjs/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/@rollup/plugin-inject": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@rollup/plugin-inject/-/plugin-inject-5.0.5.tgz", + "integrity": "sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg==", + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-inject/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/@rollup/plugin-json": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.1.0.tgz", + "integrity": "sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==", + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.1.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.1.tgz", + "integrity": "sha512-tk5YCxJWIG81umIvNkSod2qK5KyQW19qcBF/B78n1bjtOON6gzKoVeSzAE8yHCZEDmqkHKkxplExA8KzdJLJpA==", + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-module": "^1.0.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.78.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-replace": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-6.0.2.tgz", + "integrity": "sha512-7QaYCf8bqF04dOy7w/eHmJeNExxTYwvKAmlSAH/EaWWUzbT0h5sbF6bktFoX/0F/0qwng5/dWFMyf3gzaM8DsQ==", + "license": "MIT", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "magic-string": "^0.30.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-terser": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", + "integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==", + "license": "MIT", + "dependencies": { + "serialize-javascript": "^6.0.1", + "smob": "^1.0.0", + "terser": "^5.17.4" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.2.0.tgz", + "integrity": "sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.50.0.tgz", + "integrity": "sha512-lVgpeQyy4fWN5QYebtW4buT/4kn4p4IJ+kDNB4uYNT5b8c8DLJDg6titg20NIg7E8RWwdWZORW6vUFfrLyG3KQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.50.0.tgz", + "integrity": "sha512-2O73dR4Dc9bp+wSYhviP6sDziurB5/HCym7xILKifWdE9UsOe2FtNcM+I4xZjKrfLJnq5UR8k9riB87gauiQtw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.50.0.tgz", + "integrity": "sha512-vwSXQN8T4sKf1RHr1F0s98Pf8UPz7pS6P3LG9NSmuw0TVh7EmaE+5Ny7hJOZ0M2yuTctEsHHRTMi2wuHkdS6Hg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.50.0.tgz", + "integrity": "sha512-cQp/WG8HE7BCGyFVuzUg0FNmupxC+EPZEwWu2FCGGw5WDT1o2/YlENbm5e9SMvfDFR6FRhVCBePLqj0o8MN7Vw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.50.0.tgz", + "integrity": "sha512-UR1uTJFU/p801DvvBbtDD7z9mQL8J80xB0bR7DqW7UGQHRm/OaKzp4is7sQSdbt2pjjSS72eAtRh43hNduTnnQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.50.0.tgz", + "integrity": "sha512-G/DKyS6PK0dD0+VEzH/6n/hWDNPDZSMBmqsElWnCRGrYOb2jC0VSupp7UAHHQ4+QILwkxSMaYIbQ72dktp8pKA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.50.0.tgz", + "integrity": "sha512-u72Mzc6jyJwKjJbZZcIYmd9bumJu7KNmHYdue43vT1rXPm2rITwmPWF0mmPzLm9/vJWxIRbao/jrQmxTO0Sm9w==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.50.0.tgz", + "integrity": "sha512-S4UefYdV0tnynDJV1mdkNawp0E5Qm2MtSs330IyHgaccOFrwqsvgigUD29uT+B/70PDY1eQ3t40+xf6wIvXJyg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.50.0.tgz", + "integrity": "sha512-1EhkSvUQXJsIhk4msxP5nNAUWoB4MFDHhtc4gAYvnqoHlaL9V3F37pNHabndawsfy/Tp7BPiy/aSa6XBYbaD1g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.50.0.tgz", + "integrity": "sha512-EtBDIZuDtVg75xIPIK1l5vCXNNCIRM0OBPUG+tbApDuJAy9mKago6QxX+tfMzbCI6tXEhMuZuN1+CU8iDW+0UQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.50.0.tgz", + "integrity": "sha512-BGYSwJdMP0hT5CCmljuSNx7+k+0upweM2M4YGfFBjnFSZMHOLYR0gEEj/dxyYJ6Zc6AiSeaBY8dWOa11GF/ppQ==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.50.0.tgz", + "integrity": "sha512-I1gSMzkVe1KzAxKAroCJL30hA4DqSi+wGc5gviD0y3IL/VkvcnAqwBf4RHXHyvH66YVHxpKO8ojrgc4SrWAnLg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.50.0.tgz", + "integrity": "sha512-bSbWlY3jZo7molh4tc5dKfeSxkqnf48UsLqYbUhnkdnfgZjgufLS/NTA8PcP/dnvct5CCdNkABJ56CbclMRYCA==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.50.0.tgz", + "integrity": "sha512-LSXSGumSURzEQLT2e4sFqFOv3LWZsEF8FK7AAv9zHZNDdMnUPYH3t8ZlaeYYZyTXnsob3htwTKeWtBIkPV27iQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.50.0.tgz", + "integrity": "sha512-CxRKyakfDrsLXiCyucVfVWVoaPA4oFSpPpDwlMcDFQvrv3XY6KEzMtMZrA+e/goC8xxp2WSOxHQubP8fPmmjOQ==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.50.0.tgz", + "integrity": "sha512-8PrJJA7/VU8ToHVEPu14FzuSAqVKyo5gg/J8xUerMbyNkWkO9j2ExBho/68RnJsMGNJq4zH114iAttgm7BZVkA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.50.0.tgz", + "integrity": "sha512-SkE6YQp+CzpyOrbw7Oc4MgXFvTw2UIBElvAvLCo230pyxOLmYwRPwZ/L5lBe/VW/qT1ZgND9wJfOsdy0XptRvw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.50.0.tgz", + "integrity": "sha512-PZkNLPfvXeIOgJWA804zjSFH7fARBBCpCXxgkGDRjjAhRLOR8o0IGS01ykh5GYfod4c2yiiREuDM8iZ+pVsT+Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.50.0.tgz", + "integrity": "sha512-q7cIIdFvWQoaCbLDUyUc8YfR3Jh2xx3unO8Dn6/TTogKjfwrax9SyfmGGK6cQhKtjePI7jRfd7iRYcxYs93esg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.50.0.tgz", + "integrity": "sha512-XzNOVg/YnDOmFdDKcxxK410PrcbcqZkBmz+0FicpW5jtjKQxcW1BZJEQOF0NJa6JO7CZhett8GEtRN/wYLYJuw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.50.0.tgz", + "integrity": "sha512-xMmiWRR8sp72Zqwjgtf3QbZfF1wdh8X2ABu3EaozvZcyHJeU0r+XAnXdKgs4cCAp6ORoYoCygipYP1mjmbjrsg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@sindresorhus/is": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-7.0.2.tgz", + "integrity": "sha512-d9xRovfKNz1SKieM0qJdO+PQonjnnIfSNWfHYnBSJ9hkjm0ZPw6HlxscDXYstp3z+7V2GOFHc+J0CYrYTjqCJw==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@speed-highlight/core": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@speed-highlight/core/-/core-1.2.7.tgz", + "integrity": "sha512-0dxmVj4gxg3Jg879kvFS/msl4s9F3T9UXC1InxgOf7t5NvcPD97u/WTA5vL/IxWHMn7qSxBozqrnnE2wvl1m8g==", + "license": "CC0-1.0" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.0.tgz", + "integrity": "sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "license": "MIT" + }, + "node_modules/@types/parse-path": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/parse-path/-/parse-path-7.0.3.tgz", + "integrity": "sha512-LriObC2+KYZD3FzCrgWGv/qufdUy4eXrxcLgQMfYXgPbLIecKIsVBaQgUPmxSSLcjmYbDTQbMgr6qr6l/eb7Bg==", + "license": "MIT" + }, + "node_modules/@types/resolve": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", + "license": "MIT" + }, + "node_modules/@unhead/vue": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@unhead/vue/-/vue-2.0.14.tgz", + "integrity": "sha512-Ym9f+Kd2Afqek2FtUHvYvK+j2uZ2vbZ6Rr9NCnNGGBMdmafAuiZpT117YGyh0ARcueL6Znia0U8ySqPsnHOZIg==", + "license": "MIT", + "dependencies": { + "hookable": "^5.5.3", + "unhead": "2.0.14" + }, + "funding": { + "url": "https://github.com/sponsors/harlan-zw" + }, + "peerDependencies": { + "vue": ">=3.5.18" + } + }, + "node_modules/@vercel/nft": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/@vercel/nft/-/nft-0.30.1.tgz", + "integrity": "sha512-2mgJZv4AYBFkD/nJ4QmiX5Ymxi+AisPLPcS/KPXVqniyQNqKXX+wjieAbDXQP3HcogfEbpHoRMs49Cd4pfkk8g==", + "license": "MIT", + "dependencies": { + "@mapbox/node-pre-gyp": "^2.0.0", + "@rollup/pluginutils": "^5.1.3", + "acorn": "^8.6.0", + "acorn-import-attributes": "^1.9.5", + "async-sema": "^3.1.1", + "bindings": "^1.4.0", + "estree-walker": "2.0.2", + "glob": "^10.4.5", + "graceful-fs": "^4.2.9", + "node-gyp-build": "^4.2.2", + "picomatch": "^4.0.2", + "resolve-from": "^5.0.0" + }, + "bin": { + "nft": "out/cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@vercel/nft/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/@vitejs/plugin-vue": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.1.tgz", + "integrity": "sha512-+MaE752hU0wfPFJEUAIxqw18+20euHHdxVtMvbFcOEpjEyfqXH/5DCoTHiVJ0J29EhTJdoTkjEv5YBKU9dnoTw==", + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "1.0.0-beta.29" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@vitejs/plugin-vue-jsx": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue-jsx/-/plugin-vue-jsx-5.1.1.tgz", + "integrity": "sha512-uQkfxzlF8SGHJJVH966lFTdjM/lGcwJGzwAHpVqAPDD/QcsqoUGa+q31ox1BrUfi+FLP2ChVp7uLXE3DkHyDdQ==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.3", + "@babel/plugin-syntax-typescript": "^7.27.1", + "@babel/plugin-transform-typescript": "^7.28.0", + "@rolldown/pluginutils": "^1.0.0-beta.34", + "@vue/babel-plugin-jsx": "^1.5.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0", + "vue": "^3.0.0" + } + }, + "node_modules/@vitejs/plugin-vue-jsx/node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.34", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.34.tgz", + "integrity": "sha512-LyAREkZHP5pMom7c24meKmJCdhf2hEyvam2q0unr3or9ydwDL+DJ8chTF6Av/RFPb3rH8UFBdMzO5MxTZW97oA==", + "license": "MIT" + }, + "node_modules/@volar/language-core": { + "version": "2.4.23", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.23.tgz", + "integrity": "sha512-hEEd5ET/oSmBC6pi1j6NaNYRWoAiDhINbT8rmwtINugR39loROSlufGdYMF9TaKGfz+ViGs1Idi3mAhnuPcoGQ==", + "license": "MIT", + "dependencies": { + "@volar/source-map": "2.4.23" + } + }, + "node_modules/@volar/source-map": { + "version": "2.4.23", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.23.tgz", + "integrity": "sha512-Z1Uc8IB57Lm6k7q6KIDu/p+JWtf3xsXJqAX/5r18hYOTpJyBn0KXUR8oTJ4WFYOcDzWC9n3IflGgHowx6U6z9Q==", + "license": "MIT" + }, + "node_modules/@vue-macros/common": { + "version": "3.0.0-beta.16", + "resolved": "https://registry.npmjs.org/@vue-macros/common/-/common-3.0.0-beta.16.tgz", + "integrity": "sha512-8O2gWxWFiaoNkk7PGi0+p7NPGe/f8xJ3/INUufvje/RZOs7sJvlI1jnR4lydtRFa/mU0ylMXUXXjSK0fHDEYTA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-sfc": "^3.5.17", + "ast-kit": "^2.1.1", + "local-pkg": "^1.1.1", + "magic-string-ast": "^1.0.0", + "unplugin-utils": "^0.2.4" + }, + "engines": { + "node": ">=20.18.0" + }, + "funding": { + "url": "https://github.com/sponsors/vue-macros" + }, + "peerDependencies": { + "vue": "^2.7.0 || ^3.2.25" + }, + "peerDependenciesMeta": { + "vue": { + "optional": true + } + } + }, + "node_modules/@vue/babel-helper-vue-transform-on": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.5.0.tgz", + "integrity": "sha512-0dAYkerNhhHutHZ34JtTl2czVQHUNWv6xEbkdF5W+Yrv5pCWsqjeORdOgbtW2I9gWlt+wBmVn+ttqN9ZxR5tzA==", + "license": "MIT" + }, + "node_modules/@vue/babel-plugin-jsx": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.5.0.tgz", + "integrity": "sha512-mneBhw1oOqCd2247O0Yw/mRwC9jIGACAJUlawkmMBiNmL4dGA2eMzuNZVNqOUfYTa6vqmND4CtOPzmEEEqLKFw==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.0", + "@babel/types": "^7.28.2", + "@vue/babel-helper-vue-transform-on": "1.5.0", + "@vue/babel-plugin-resolve-type": "1.5.0", + "@vue/shared": "^3.5.18" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + } + } + }, + "node_modules/@vue/babel-plugin-resolve-type": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@vue/babel-plugin-resolve-type/-/babel-plugin-resolve-type-1.5.0.tgz", + "integrity": "sha512-Wm/60o+53JwJODm4Knz47dxJnLDJ9FnKnGZJbUUf8nQRAtt6P+undLUAVU3Ha33LxOJe6IPoifRQ6F/0RrU31w==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/parser": "^7.28.0", + "@vue/compiler-sfc": "^3.5.18" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.21.tgz", + "integrity": "sha512-8i+LZ0vf6ZgII5Z9XmUvrCyEzocvWT+TeR2VBUVlzIH6Tyv57E20mPZ1bCS+tbejgUgmjrEh7q/0F0bibskAmw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.3", + "@vue/shared": "3.5.21", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-core/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.21.tgz", + "integrity": "sha512-jNtbu/u97wiyEBJlJ9kmdw7tAr5Vy0Aj5CgQmo+6pxWNQhXZDPsRr1UWPN4v3Zf82s2H3kF51IbzZ4jMWAgPlQ==", + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.21", + "@vue/shared": "3.5.21" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.21.tgz", + "integrity": "sha512-SXlyk6I5eUGBd2v8Ie7tF6ADHE9kCR6mBEuPyH1nUZ0h6Xx6nZI29i12sJKQmzbDyr2tUHMhhTt51Z6blbkTTQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.3", + "@vue/compiler-core": "3.5.21", + "@vue/compiler-dom": "3.5.21", + "@vue/compiler-ssr": "3.5.21", + "@vue/shared": "3.5.21", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.18", + "postcss": "^8.5.6", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-sfc/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.21.tgz", + "integrity": "sha512-vKQ5olH5edFZdf5ZrlEgSO1j1DMA4u23TVK5XR1uMhvwnYvVdDF0nHXJUblL/GvzlShQbjhZZ2uvYmDlAbgo9w==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.21", + "@vue/shared": "3.5.21" + } + }, + "node_modules/@vue/compiler-vue2": { + "version": "2.7.16", + "resolved": "https://registry.npmjs.org/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz", + "integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==", + "license": "MIT", + "dependencies": { + "de-indent": "^1.0.2", + "he": "^1.2.0" + } + }, + "node_modules/@vue/devtools-api": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", + "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", + "license": "MIT" + }, + "node_modules/@vue/devtools-core": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@vue/devtools-core/-/devtools-core-7.7.7.tgz", + "integrity": "sha512-9z9TLbfC+AjAi1PQyWX+OErjIaJmdFlbDHcD+cAMYKY6Bh5VlsAtCeGyRMrXwIlMEQPukvnWt3gZBLwTAIMKzQ==", + "license": "MIT", + "dependencies": { + "@vue/devtools-kit": "^7.7.7", + "@vue/devtools-shared": "^7.7.7", + "mitt": "^3.0.1", + "nanoid": "^5.1.0", + "pathe": "^2.0.3", + "vite-hot-client": "^2.0.4" + }, + "peerDependencies": { + "vue": "^3.0.0" + } + }, + "node_modules/@vue/devtools-kit": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.7.tgz", + "integrity": "sha512-wgoZtxcTta65cnZ1Q6MbAfePVFxfM+gq0saaeytoph7nEa7yMXoi6sCPy4ufO111B9msnw0VOWjPEFCXuAKRHA==", + "license": "MIT", + "dependencies": { + "@vue/devtools-shared": "^7.7.7", + "birpc": "^2.3.0", + "hookable": "^5.5.3", + "mitt": "^3.0.1", + "perfect-debounce": "^1.0.0", + "speakingurl": "^14.0.1", + "superjson": "^2.2.2" + } + }, + "node_modules/@vue/devtools-kit/node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "license": "MIT" + }, + "node_modules/@vue/devtools-shared": { + "version": "7.7.7", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.7.tgz", + "integrity": "sha512-+udSj47aRl5aKb0memBvcUG9koarqnxNM5yjuREvqwK6T3ap4mn3Zqqc17QrBFTqSMjr3HK1cvStEZpMDpfdyw==", + "license": "MIT", + "dependencies": { + "rfdc": "^1.4.1" + } + }, + "node_modules/@vue/language-core": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.0.6.tgz", + "integrity": "sha512-e2RRzYWm+qGm8apUHW1wA5RQxzNhkqbbKdbKhiDUcmMrNAZGyM8aTiL3UrTqkaFI5s7wJRGGrp4u3jgusuBp2A==", + "license": "MIT", + "dependencies": { + "@volar/language-core": "2.4.23", + "@vue/compiler-dom": "^3.5.0", + "@vue/compiler-vue2": "^2.7.16", + "@vue/shared": "^3.5.0", + "alien-signals": "^2.0.5", + "muggle-string": "^0.4.1", + "path-browserify": "^1.0.1", + "picomatch": "^4.0.2" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.21.tgz", + "integrity": "sha512-3ah7sa+Cwr9iiYEERt9JfZKPw4A2UlbY8RbbnH2mGCE8NwHkhmlZt2VsH0oDA3P08X3jJd29ohBDtX+TbD9AsA==", + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.21" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.21.tgz", + "integrity": "sha512-+DplQlRS4MXfIf9gfD1BOJpk5RSyGgGXD/R+cumhe8jdjUcq/qlxDawQlSI8hCKupBlvM+3eS1se5xW+SuNAwA==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.21", + "@vue/shared": "3.5.21" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.21.tgz", + "integrity": "sha512-3M2DZsOFwM5qI15wrMmNF5RJe1+ARijt2HM3TbzBbPSuBHOQpoidE+Pa+XEaVN+czbHf81ETRoG1ltztP2em8w==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.21", + "@vue/runtime-core": "3.5.21", + "@vue/shared": "3.5.21", + "csstype": "^3.1.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.21.tgz", + "integrity": "sha512-qr8AqgD3DJPJcGvLcJKQo2tAc8OnXRcfxhOJCPF+fcfn5bBGz7VCcO7t+qETOPxpWK1mgysXvVT/j+xWaHeMWA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.21", + "@vue/shared": "3.5.21" + }, + "peerDependencies": { + "vue": "3.5.21" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.21.tgz", + "integrity": "sha512-+2k1EQpnYuVuu3N7atWyG3/xoFWIVJZq4Mz8XNOdScFI0etES75fbny/oU4lKWk/577P1zmg0ioYvpGEDZ3DLw==", + "license": "MIT" + }, + "node_modules/abbrev": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-3.0.1.tgz", + "integrity": "sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==", + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "license": "MIT", + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/alien-signals": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-2.0.7.tgz", + "integrity": "sha512-wE7y3jmYeb0+h6mr5BOovuqhFv22O/MV9j5p0ndJsa7z1zJNPGQ4ph5pQk/kTTCWRC3xsA4SmtwmkzQO+7NCNg==", + "license": "MIT" + }, + "node_modules/ansi-regex": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.0.tgz", + "integrity": "sha512-TKY5pyBkHyADOPYlRT9Lx6F544mPl0vS5Ew7BJ45hA08Q+t3GjbueLliBWN3sMICk6+y7HdyxSzC4bWS8baBdg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ansis": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.1.0.tgz", + "integrity": "sha512-BGcItUBWSMRgOCe+SVZJ+S7yTRG0eGt9cXAHev72yuGcY23hnLA7Bky5L/xLyPINoSN95geovfBkqoTlNZYa7w==", + "license": "ISC", + "engines": { + "node": ">=14" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/archiver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.1.tgz", + "integrity": "sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==", + "license": "MIT", + "dependencies": { + "archiver-utils": "^5.0.2", + "async": "^3.2.4", + "buffer-crc32": "^1.0.0", + "readable-stream": "^4.0.0", + "readdir-glob": "^1.1.2", + "tar-stream": "^3.0.0", + "zip-stream": "^6.0.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/archiver-utils": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-5.0.2.tgz", + "integrity": "sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==", + "license": "MIT", + "dependencies": { + "glob": "^10.0.0", + "graceful-fs": "^4.2.0", + "is-stream": "^2.0.1", + "lazystream": "^1.0.0", + "lodash": "^4.17.15", + "normalize-path": "^3.0.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/archiver-utils/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ast-kit": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ast-kit/-/ast-kit-2.1.2.tgz", + "integrity": "sha512-cl76xfBQM6pztbrFWRnxbrDm9EOqDr1BF6+qQnnDZG2Co2LjyUktkN9GTJfBAfdae+DbT2nJf2nCGAdDDN7W2g==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.0", + "pathe": "^2.0.3" + }, + "engines": { + "node": ">=20.18.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/ast-walker-scope": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/ast-walker-scope/-/ast-walker-scope-0.8.2.tgz", + "integrity": "sha512-3pYeLyDZ6nJew9QeBhS4Nly02269Dkdk32+zdbbKmL6n4ZuaGorwwA+xx12xgOciA8BF1w9x+dlH7oUkFTW91w==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.3", + "ast-kit": "^2.1.2" + }, + "engines": { + "node": ">=20.18.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "license": "MIT" + }, + "node_modules/async-sema": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/async-sema/-/async-sema-3.1.1.tgz", + "integrity": "sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==", + "license": "MIT" + }, + "node_modules/autoprefixer": { + "version": "10.4.21", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", + "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.24.4", + "caniuse-lite": "^1.0.30001702", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/b4a": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz", + "integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==", + "license": "Apache-2.0" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/bare-events": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.6.1.tgz", + "integrity": "sha512-AuTJkq9XmE6Vk0FJVNq5QxETrSA/vKHarWVBG5l/JbdCL1prJemiyJqUS0jrlXO0MftuPq4m3YVYhoNc5+aE/g==", + "license": "Apache-2.0", + "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" + } + ], + "license": "MIT" + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "license": "MIT", + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/birpc": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.5.0.tgz", + "integrity": "sha512-VSWO/W6nNQdyP520F1mhf+Lc2f8pjGQOtoHHm7Ze8Go1kX7akpVIrtTa0fn+HB0QJEDVacl6aO08YE0PgXfdnQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "license": "ISC" + }, + "node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.25.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.4.tgz", + "integrity": "sha512-4jYpcjabC606xJ3kw2QwGEZKX0Aw7sgQdZCvIK9dhVSPh76BKo+C+btT1RRofH7B+8iNpEbgGNVWiLki5q93yg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001737", + "electron-to-chromium": "^1.5.211", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-crc32": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", + "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/c12": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/c12/-/c12-3.2.0.tgz", + "integrity": "sha512-ixkEtbYafL56E6HiFuonMm1ZjoKtIo7TH68/uiEq4DAwv9NcUX2nJ95F8TrbMeNjqIkZpruo3ojXQJ+MGG5gcQ==", + "license": "MIT", + "dependencies": { + "chokidar": "^4.0.3", + "confbox": "^0.2.2", + "defu": "^6.1.4", + "dotenv": "^17.2.1", + "exsolve": "^1.0.7", + "giget": "^2.0.0", + "jiti": "^2.5.1", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "perfect-debounce": "^1.0.0", + "pkg-types": "^2.2.0", + "rc9": "^2.1.2" + }, + "peerDependencies": { + "magicast": "^0.3.5" + }, + "peerDependenciesMeta": { + "magicast": { + "optional": true + } + } + }, + "node_modules/c12/node_modules/dotenv": { + "version": "17.2.2", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.2.tgz", + "integrity": "sha512-Sf2LSQP+bOlhKWWyhFsn0UsfdK/kCWRv1iuA2gXAwt3dyNabr6QSj00I2V10pidqz69soatm9ZwZvpQMTIOd5Q==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/c12/node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "license": "MIT" + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001739", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001739.tgz", + "integrity": "sha512-y+j60d6ulelrNSwpPyrHdl+9mJnQzHBr08xm48Qno0nSk4h3Qojh+ziv2qE6rXf4k3tadF4o1J/1tAbVm1NtnA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/citty": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz", + "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==", + "license": "MIT", + "dependencies": { + "consola": "^3.2.3" + } + }, + "node_modules/clipboardy": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-4.0.0.tgz", + "integrity": "sha512-5mOlNS0mhX0707P2I0aZ2V/cmHUEO/fL7VFLqszkhUsxt7RwnmrInf/eEQKlf5GzvYeHIjT+Ov1HRfNmymlG0w==", + "license": "MIT", + "dependencies": { + "execa": "^8.0.1", + "is-wsl": "^3.1.0", + "is64bit": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/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==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/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==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/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==", + "license": "MIT" + }, + "node_modules/cliui/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==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/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==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/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==", + "license": "MIT", + "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/cluster-key-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", + "license": "MIT" + }, + "node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "license": "MIT" + }, + "node_modules/compatx": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/compatx/-/compatx-0.2.0.tgz", + "integrity": "sha512-6gLRNt4ygsi5NyMVhceOCFv14CIdDFN7fQjX1U4+47qVE/+kjPoXMK65KWK+dWxmFzMTuKazoQ9sch6pM0p5oA==", + "license": "MIT" + }, + "node_modules/compress-commons": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz", + "integrity": "sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==", + "license": "MIT", + "dependencies": { + "crc-32": "^1.2.0", + "crc32-stream": "^6.0.0", + "is-stream": "^2.0.1", + "normalize-path": "^3.0.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/compress-commons/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/confbox": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", + "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", + "license": "MIT" + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" + }, + "node_modules/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/cookie-es": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-2.0.0.tgz", + "integrity": "sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg==", + "license": "MIT" + }, + "node_modules/copy-anything": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz", + "integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==", + "license": "MIT", + "dependencies": { + "is-what": "^4.1.8" + }, + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "license": "Apache-2.0", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/crc32-stream": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-6.0.0.tgz", + "integrity": "sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==", + "license": "MIT", + "dependencies": { + "crc-32": "^1.2.0", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/croner": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/croner/-/croner-9.1.0.tgz", + "integrity": "sha512-p9nwwR4qyT5W996vBZhdvBCnMhicY5ytZkR4D1Xj0wuTDEiMnjwR57Q3RXYY/s0EpX6Ay3vgIcfaR+ewGHsi+g==", + "license": "MIT", + "engines": { + "node": ">=18.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cross-spawn/node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crossws": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/crossws/-/crossws-0.3.5.tgz", + "integrity": "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==", + "license": "MIT", + "dependencies": { + "uncrypto": "^0.1.3" + } + }, + "node_modules/css-declaration-sorter": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.2.0.tgz", + "integrity": "sha512-h70rUM+3PNFuaBDTLe8wF/cdWu+dOZmb7pJt8Z2sedYbAcQVQV/tEchueg3GWxwqS0cxtbxmaHEdkNACqcvsow==", + "license": "ISC", + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, + "node_modules/css-select": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.1.0.tgz", + "integrity": "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.12.2", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css-what": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-7.1.1.tgz", + "integrity": "sha512-fm4D8ti0dQmFPeF8DXSAA//btEmqCOgAc/9Oa3C1LW94h5usNrJEfrON7b4FkPZgnDEn6OUs5NdxiJZmAtGOpQ==", + "license": "MIT", + "dependencies": { + "cssnano-preset-default": "^7.0.9", + "lilconfig": "^3.1.3" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/cssnano" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/cssnano-preset-default": { + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-7.0.9.tgz", + "integrity": "sha512-tCD6AAFgYBOVpMBX41KjbvRh9c2uUjLXRyV7KHSIrwHiq5Z9o0TFfUCoM3TwVrRsRteN3sVXGNvjVNxYzkpTsA==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.25.1", + "css-declaration-sorter": "^7.2.0", + "cssnano-utils": "^5.0.1", + "postcss-calc": "^10.1.1", + "postcss-colormin": "^7.0.4", + "postcss-convert-values": "^7.0.7", + "postcss-discard-comments": "^7.0.4", + "postcss-discard-duplicates": "^7.0.2", + "postcss-discard-empty": "^7.0.1", + "postcss-discard-overridden": "^7.0.1", + "postcss-merge-longhand": "^7.0.5", + "postcss-merge-rules": "^7.0.6", + "postcss-minify-font-values": "^7.0.1", + "postcss-minify-gradients": "^7.0.1", + "postcss-minify-params": "^7.0.4", + "postcss-minify-selectors": "^7.0.5", + "postcss-normalize-charset": "^7.0.1", + "postcss-normalize-display-values": "^7.0.1", + "postcss-normalize-positions": "^7.0.1", + "postcss-normalize-repeat-style": "^7.0.1", + "postcss-normalize-string": "^7.0.1", + "postcss-normalize-timing-functions": "^7.0.1", + "postcss-normalize-unicode": "^7.0.4", + "postcss-normalize-url": "^7.0.1", + "postcss-normalize-whitespace": "^7.0.1", + "postcss-ordered-values": "^7.0.2", + "postcss-reduce-initial": "^7.0.4", + "postcss-reduce-transforms": "^7.0.1", + "postcss-svgo": "^7.1.0", + "postcss-unique-selectors": "^7.0.4" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/cssnano-utils": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-5.0.1.tgz", + "integrity": "sha512-ZIP71eQgG9JwjVZsTPSqhc6GHgEr53uJ7tK5///VfyWj6Xp2DBmixWHqJgPno+PqATzn48pL42ww9x5SSGmhZg==", + "license": "MIT", + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "license": "MIT", + "dependencies": { + "css-tree": "~2.2.0" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "license": "CC0-1.0" + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" + }, + "node_modules/db0": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/db0/-/db0-0.3.2.tgz", + "integrity": "sha512-xzWNQ6jk/+NtdfLyXEipbX55dmDSeteLFt/ayF+wZUU5bzKgmrDOxmInUTbyVRp46YwnJdkDA1KhB7WIXFofJw==", + "license": "MIT", + "peerDependencies": { + "@electric-sql/pglite": "*", + "@libsql/client": "*", + "better-sqlite3": "*", + "drizzle-orm": "*", + "mysql2": "*", + "sqlite3": "*" + }, + "peerDependenciesMeta": { + "@electric-sql/pglite": { + "optional": true + }, + "@libsql/client": { + "optional": true + }, + "better-sqlite3": { + "optional": true + }, + "drizzle-orm": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "sqlite3": { + "optional": true + } + } + }, + "node_modules/de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-browser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", + "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", + "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "license": "MIT" + }, + "node_modules/denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "license": "Apache-2.0", + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/devalue": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.3.2.tgz", + "integrity": "sha512-UDsjUbpQn9kvm68slnrs+mfxwFkIflOhkanmyabZ8zOYk8SMEIbJ3TK+88g70hSIeytu4y18f0z/hYHMTrXIWw==", + "license": "MIT" + }, + "node_modules/diff": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.2.tgz", + "integrity": "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-prop": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-9.0.0.tgz", + "integrity": "sha512-1gxPBJpI/pcjQhKgIU91II6Wkay+dLcN3M6rf2uwP8hRur3HtQXjVrdAK3sjC0piaEuxzMwjXChcETiJl47lAQ==", + "license": "MIT", + "dependencies": { + "type-fest": "^4.18.2" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "license": "MIT" + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.213", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.213.tgz", + "integrity": "sha512-xr9eRzSLNa4neDO0xVFrkXu3vyIzG4Ay08dApecw42Z1NbmCt+keEpXdvlYGVe0wtvY5dhW0Ay0lY0IOfsCg0Q==", + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.18.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", + "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-stack-parser-es": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/error-stack-parser-es/-/error-stack-parser-es-1.0.5.tgz", + "integrity": "sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/errx": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/errx/-/errx-0.1.0.tgz", + "integrity": "sha512-fZmsRiDNv07K6s2KkKFTiD2aIvECa7++PKyD5NC32tpRw46qZA3sOz+aM+/V9V0GDHxVTKLziveV4JhzBHDp9Q==", + "license": "MIT" + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz", + "integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.9", + "@esbuild/android-arm": "0.25.9", + "@esbuild/android-arm64": "0.25.9", + "@esbuild/android-x64": "0.25.9", + "@esbuild/darwin-arm64": "0.25.9", + "@esbuild/darwin-x64": "0.25.9", + "@esbuild/freebsd-arm64": "0.25.9", + "@esbuild/freebsd-x64": "0.25.9", + "@esbuild/linux-arm": "0.25.9", + "@esbuild/linux-arm64": "0.25.9", + "@esbuild/linux-ia32": "0.25.9", + "@esbuild/linux-loong64": "0.25.9", + "@esbuild/linux-mips64el": "0.25.9", + "@esbuild/linux-ppc64": "0.25.9", + "@esbuild/linux-riscv64": "0.25.9", + "@esbuild/linux-s390x": "0.25.9", + "@esbuild/linux-x64": "0.25.9", + "@esbuild/netbsd-arm64": "0.25.9", + "@esbuild/netbsd-x64": "0.25.9", + "@esbuild/openbsd-arm64": "0.25.9", + "@esbuild/openbsd-x64": "0.25.9", + "@esbuild/openharmony-arm64": "0.25.9", + "@esbuild/sunos-x64": "0.25.9", + "@esbuild/win32-arm64": "0.25.9", + "@esbuild/win32-ia32": "0.25.9", + "@esbuild/win32-x64": "0.25.9" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exsolve": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.7.tgz", + "integrity": "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==", + "license": "MIT" + }, + "node_modules/externality": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/externality/-/externality-1.0.2.tgz", + "integrity": "sha512-LyExtJWKxtgVzmgtEHyQtLFpw1KFhQphF9nTG8TpAIVkiI/xQ3FJh75tRFLYl4hkn7BNIIdLJInuDAavX35pMw==", + "license": "MIT", + "dependencies": { + "enhanced-resolve": "^5.14.1", + "mlly": "^1.3.0", + "pathe": "^1.1.1", + "ufo": "^1.1.2" + } + }, + "node_modules/externality/node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "license": "MIT" + }, + "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==", + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-npm-meta": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/fast-npm-meta/-/fast-npm-meta-0.4.6.tgz", + "integrity": "sha512-zbBBOAOlzxfrU4WSnbCHk/nR6Vf32lSEPxDEvNOR08Z5DSZ/A6qJu0rqrHVcexBTd1hc2gim998xnqF/R1PuEw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "license": "MIT" + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/fuse.js": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.1.0.tgz", + "integrity": "sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=10" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "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==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-port-please": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/get-port-please/-/get-port-please-3.2.0.tgz", + "integrity": "sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A==", + "license": "MIT" + }, + "node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/giget": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/giget/-/giget-2.0.0.tgz", + "integrity": "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==", + "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.0", + "defu": "^6.1.4", + "node-fetch-native": "^1.6.6", + "nypm": "^0.6.0", + "pathe": "^2.0.3" + }, + "bin": { + "giget": "dist/cli.mjs" + } + }, + "node_modules/git-up": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/git-up/-/git-up-8.1.1.tgz", + "integrity": "sha512-FDenSF3fVqBYSaJoYy1KSc2wosx0gCvKP+c+PRBht7cAaiCeQlBtfBDX9vgnNOHmdePlSFITVcn4pFfcgNvx3g==", + "license": "MIT", + "dependencies": { + "is-ssh": "^1.4.0", + "parse-url": "^9.2.0" + } + }, + "node_modules/git-url-parse": { + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-16.1.0.tgz", + "integrity": "sha512-cPLz4HuK86wClEW7iDdeAKcCVlWXmrLpb2L+G9goW0Z1dtpNS6BXXSOckUTlJT/LDQViE1QZKstNORzHsLnobw==", + "license": "MIT", + "dependencies": { + "git-up": "^8.1.0" + } + }, + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/global-directory": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz", + "integrity": "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==", + "license": "MIT", + "dependencies": { + "ini": "4.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.1.0.tgz", + "integrity": "sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==", + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.3", + "ignore": "^7.0.3", + "path-type": "^6.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "license": "ISC" + }, + "node_modules/gzip-size": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-7.0.0.tgz", + "integrity": "sha512-O1Ld7Dr+nqPnmGpdhzLmMTQ4vAsD+rHwMm1NLUmoUFFymBOMKxCCrtDxqdBRYXdeEPEi3SyoR4TizJLQrnKBNA==", + "license": "MIT", + "dependencies": { + "duplexer": "^0.1.2" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/h3": { + "version": "1.15.4", + "resolved": "https://registry.npmjs.org/h3/-/h3-1.15.4.tgz", + "integrity": "sha512-z5cFQWDffyOe4vQ9xIqNfCZdV4p//vy6fBnr8Q1AWnVZ0teurKMG66rLj++TKwKPUP3u7iMUvrvKaEUiQw2QWQ==", + "license": "MIT", + "dependencies": { + "cookie-es": "^1.2.2", + "crossws": "^0.3.5", + "defu": "^6.1.4", + "destr": "^2.0.5", + "iron-webcrypto": "^1.2.1", + "node-mock-http": "^1.0.2", + "radix3": "^1.1.2", + "ufo": "^1.6.1", + "uncrypto": "^0.1.3" + } + }, + "node_modules/h3/node_modules/cookie-es": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-1.2.2.tgz", + "integrity": "sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==", + "license": "MIT" + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/hookable": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", + "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", + "license": "MIT" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-shutdown": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/http-shutdown/-/http-shutdown-1.2.2.tgz", + "integrity": "sha512-S9wWkJ/VSY9/k4qcjG318bqJNruzE4HySUhFYknwmu6LBP97KLLfwNf+n4V1BHurvFNkSKLFnK/RsuUnRTf9Vw==", + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/httpxy": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/httpxy/-/httpxy-0.1.7.tgz", + "integrity": "sha512-pXNx8gnANKAndgga5ahefxc++tJvNL87CXoRwxn1cJE2ZkWEojF3tNfQIEhZX/vfpt+wzeAzpUI4qkediX1MLQ==", + "license": "MIT" + }, + "node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=16.17.0" + } + }, + "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" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/image-meta": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/image-meta/-/image-meta-0.2.1.tgz", + "integrity": "sha512-K6acvFaelNxx8wc2VjbIzXKDVB0Khs0QT35U6NkGfTdCmjLNcO2945m7RFNR9/RPVFm48hq7QPzK8uGH18HCGw==", + "license": "MIT" + }, + "node_modules/impound": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/impound/-/impound-1.0.0.tgz", + "integrity": "sha512-8lAJ+1Arw2sMaZ9HE2ZmL5zOcMnt18s6+7Xqgq2aUVy4P1nlzAyPtzCDxsk51KVFwHEEdc6OWvUyqwHwhRYaug==", + "license": "MIT", + "dependencies": { + "exsolve": "^1.0.5", + "mocked-exports": "^0.1.1", + "pathe": "^2.0.3", + "unplugin": "^2.3.2", + "unplugin-utils": "^0.2.4" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ini": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", + "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/ioredis": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.7.0.tgz", + "integrity": "sha512-NUcA93i1lukyXU+riqEyPtSEkyFq8tX90uL659J+qpCZ3rEdViB/APC58oAhIh3+bJln2hzdlZbBZsGNrlsR8g==", + "license": "MIT", + "dependencies": { + "@ioredis/commands": "^1.3.0", + "cluster-key-slot": "^1.1.0", + "debug": "^4.3.4", + "denque": "^2.1.0", + "lodash.defaults": "^4.2.0", + "lodash.isarguments": "^3.1.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0", + "standard-as-callback": "^2.1.0" + }, + "engines": { + "node": ">=12.22.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ioredis" + } + }, + "node_modules/iron-webcrypto": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/iron-webcrypto/-/iron-webcrypto-1.2.1.tgz", + "integrity": "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/brc-dd" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-installed-globally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-1.0.0.tgz", + "integrity": "sha512-K55T22lfpQ63N4KEN57jZUAaAYqYHEe8veb/TycJRk9DdSCLLcovXz/mL6mOnhQaZsQGwPhuFopdQIlqGSEjiQ==", + "license": "MIT", + "dependencies": { + "global-directory": "^4.0.1", + "is-path-inside": "^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "license": "MIT" + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz", + "integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-reference": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/is-ssh": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.4.1.tgz", + "integrity": "sha512-JNeu1wQsHjyHgn9NcWTaXq6zWSR6hqE0++zhfZlkFBbScNkyvxCdeV8sRkSBaeLKxmbpR21brail63ACNxJ0Tg==", + "license": "MIT", + "dependencies": { + "protocols": "^2.0.1" + } + }, + "node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-what": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz", + "integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==", + "license": "MIT", + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/is-wsl": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is64bit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is64bit/-/is64bit-2.0.0.tgz", + "integrity": "sha512-jv+8jaWCl0g2lSBkNSVXdzfBA0npK1HGC2KtWM9FumFRoGS94g3NbCCLVnCYHLjp4GrW2KZeeSTMo5ddtznmGw==", + "license": "MIT", + "dependencies": { + "system-architecture": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "license": "ISC", + "engines": { + "node": ">=16" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jiti": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz", + "integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/knitwork": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/knitwork/-/knitwork-1.2.0.tgz", + "integrity": "sha512-xYSH7AvuQ6nXkq42x0v5S8/Iry+cfulBz/DJQzhIyESdLD7425jXsPy4vn5cCXU+HhRN2kVw51Vd1K6/By4BQg==", + "license": "MIT" + }, + "node_modules/launch-editor": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.11.1.tgz", + "integrity": "sha512-SEET7oNfgSaB6Ym0jufAdCeo3meJVeCaaDyzRygy0xsp2BFKCprcfHljTq4QkzTLUxEKkFK6OK4811YM2oSrRg==", + "license": "MIT", + "dependencies": { + "picocolors": "^1.1.1", + "shell-quote": "^1.8.3" + } + }, + "node_modules/lazystream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz", + "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==", + "license": "MIT", + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, + "node_modules/lazystream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/lazystream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/lazystream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/listhen": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/listhen/-/listhen-1.9.0.tgz", + "integrity": "sha512-I8oW2+QL5KJo8zXNWX046M134WchxsXC7SawLPvRQpogCbkyQIaFxPE89A2HiwR7vAK2Dm2ERBAmyjTYGYEpBg==", + "license": "MIT", + "dependencies": { + "@parcel/watcher": "^2.4.1", + "@parcel/watcher-wasm": "^2.4.1", + "citty": "^0.1.6", + "clipboardy": "^4.0.0", + "consola": "^3.2.3", + "crossws": ">=0.2.0 <0.4.0", + "defu": "^6.1.4", + "get-port-please": "^3.1.2", + "h3": "^1.12.0", + "http-shutdown": "^1.2.2", + "jiti": "^2.1.2", + "mlly": "^1.7.1", + "node-forge": "^1.3.1", + "pathe": "^1.1.2", + "std-env": "^3.7.0", + "ufo": "^1.5.4", + "untun": "^0.1.3", + "uqr": "^0.1.2" + }, + "bin": { + "listen": "bin/listhen.mjs", + "listhen": "bin/listhen.mjs" + } + }, + "node_modules/listhen/node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "license": "MIT" + }, + "node_modules/local-pkg": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.1.2.tgz", + "integrity": "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==", + "license": "MIT", + "dependencies": { + "mlly": "^1.7.4", + "pkg-types": "^2.3.0", + "quansync": "^0.2.11" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", + "license": "MIT" + }, + "node_modules/lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==", + "license": "MIT" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "license": "MIT" + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/magic-regexp": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/magic-regexp/-/magic-regexp-0.10.0.tgz", + "integrity": "sha512-Uly1Bu4lO1hwHUW0CQeSWuRtzCMNO00CmXtS8N6fyvB3B979GOEEeAkiTUDsmbYLAbvpUS/Kt5c4ibosAzVyVg==", + "license": "MIT", + "dependencies": { + "estree-walker": "^3.0.3", + "magic-string": "^0.30.12", + "mlly": "^1.7.2", + "regexp-tree": "^0.1.27", + "type-level-regexp": "~0.1.17", + "ufo": "^1.5.4", + "unplugin": "^2.0.0" + } + }, + "node_modules/magic-string": { + "version": "0.30.18", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.18.tgz", + "integrity": "sha512-yi8swmWbO17qHhwIBNeeZxTceJMeBvWJaId6dyvTSOwTipqeHhMhOrz6513r1sOKnpvQ7zkhlG8tPrpilwTxHQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/magic-string-ast": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/magic-string-ast/-/magic-string-ast-1.0.2.tgz", + "integrity": "sha512-8ngQgLhcT0t3YBdn9CGkZqCYlvwW9pm7aWJwd7AxseVWf1RU8ZHCQvG1mt3N5vvUme+pXTcHB8G/7fE666U8Vw==", + "license": "MIT", + "dependencies": { + "magic-string": "^0.30.17" + }, + "engines": { + "node": ">=20.18.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/magicast": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz", + "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.25.4", + "@babel/types": "^7.25.4", + "source-map-js": "^1.2.0" + } + }, + "node_modules/mdn-data": { + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz", + "integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==", + "license": "CC0-1.0" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/mime": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/mime/-/mime-4.0.7.tgz", + "integrity": "sha512-2OfDPL+e03E0LrXaGYOtTFIYhiuzep94NSsuhrNULq+stylcJedcHdzHtz0atMUuGwJfFYs0YL5xeC/Ca2x0eQ==", + "funding": [ + "https://github.com/sponsors/broofa" + ], + "license": "MIT", + "bin": { + "mime": "bin/cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minizlib": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz", + "integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==", + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "license": "MIT" + }, + "node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "license": "MIT", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mlly": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz", + "integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==", + "license": "MIT", + "dependencies": { + "acorn": "^8.15.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.1" + } + }, + "node_modules/mlly/node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "license": "MIT" + }, + "node_modules/mlly/node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "license": "MIT", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, + "node_modules/mocked-exports": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/mocked-exports/-/mocked-exports-0.1.1.tgz", + "integrity": "sha512-aF7yRQr/Q0O2/4pIXm6PZ5G+jAd7QS4Yu8m+WEeEHGnbo+7mE36CbLSDQiXYV8bVL3NfmdeqPJct0tUlnjVSnA==", + "license": "MIT" + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/muggle-string": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.5.tgz", + "integrity": "sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^18 || >=20" + } + }, + "node_modules/nanotar": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/nanotar/-/nanotar-0.2.0.tgz", + "integrity": "sha512-9ca1h0Xjvo9bEkE4UOxgAzLV0jHKe6LMaxo37ND2DAhhAtd0j8pR1Wxz+/goMrZO8AEZTWCmyaOsFI/W5AdpCQ==", + "license": "MIT" + }, + "node_modules/nitropack": { + "version": "2.12.5", + "resolved": "https://registry.npmjs.org/nitropack/-/nitropack-2.12.5.tgz", + "integrity": "sha512-KDTFhATOzqWHXFZkNlAH9J989Wibpl6s38eaYZj/Km2GbcUBLdcDxL4x7vd9pHWhD1Yk1u5oLh8+MsqJeQ7GMA==", + "license": "MIT", + "dependencies": { + "@cloudflare/kv-asset-handler": "^0.4.0", + "@rollup/plugin-alias": "^5.1.1", + "@rollup/plugin-commonjs": "^28.0.6", + "@rollup/plugin-inject": "^5.0.5", + "@rollup/plugin-json": "^6.1.0", + "@rollup/plugin-node-resolve": "^16.0.1", + "@rollup/plugin-replace": "^6.0.2", + "@rollup/plugin-terser": "^0.4.4", + "@vercel/nft": "^0.30.1", + "archiver": "^7.0.1", + "c12": "^3.2.0", + "chokidar": "^4.0.3", + "citty": "^0.1.6", + "compatx": "^0.2.0", + "confbox": "^0.2.2", + "consola": "^3.4.2", + "cookie-es": "^2.0.0", + "croner": "^9.1.0", + "crossws": "^0.3.5", + "db0": "^0.3.2", + "defu": "^6.1.4", + "destr": "^2.0.5", + "dot-prop": "^9.0.0", + "esbuild": "^0.25.9", + "escape-string-regexp": "^5.0.0", + "etag": "^1.8.1", + "exsolve": "^1.0.7", + "globby": "^14.1.0", + "gzip-size": "^7.0.0", + "h3": "^1.15.4", + "hookable": "^5.5.3", + "httpxy": "^0.1.7", + "ioredis": "^5.7.0", + "jiti": "^2.5.1", + "klona": "^2.0.6", + "knitwork": "^1.2.0", + "listhen": "^1.9.0", + "magic-string": "^0.30.18", + "magicast": "^0.3.5", + "mime": "^4.0.7", + "mlly": "^1.8.0", + "node-fetch-native": "^1.6.7", + "node-mock-http": "^1.0.2", + "ofetch": "^1.4.1", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "perfect-debounce": "^2.0.0", + "pkg-types": "^2.3.0", + "pretty-bytes": "^7.0.1", + "radix3": "^1.1.2", + "rollup": "^4.50.0", + "rollup-plugin-visualizer": "^6.0.3", + "scule": "^1.3.0", + "semver": "^7.7.2", + "serve-placeholder": "^2.0.2", + "serve-static": "^2.2.0", + "source-map": "^0.7.6", + "std-env": "^3.9.0", + "ufo": "^1.6.1", + "ultrahtml": "^1.6.0", + "uncrypto": "^0.1.3", + "unctx": "^2.4.1", + "unenv": "2.0.0-rc.20", + "unimport": "^5.2.0", + "unplugin-utils": "^0.3.0", + "unstorage": "^1.17.0", + "untyped": "^2.0.0", + "unwasm": "^0.3.11", + "youch": "4.1.0-beta.8", + "youch-core": "^0.3.3" + }, + "bin": { + "nitro": "dist/cli/index.mjs", + "nitropack": "dist/cli/index.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "xml2js": "^0.6.2" + }, + "peerDependenciesMeta": { + "xml2js": { + "optional": true + } + } + }, + "node_modules/nitropack/node_modules/unplugin-utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unplugin-utils/-/unplugin-utils-0.3.0.tgz", + "integrity": "sha512-JLoggz+PvLVMJo+jZt97hdIIIZ2yTzGgft9e9q8iMrC4ewufl62ekeW7mixBghonn2gVb/ICjyvlmOCUBnJLQg==", + "license": "MIT", + "dependencies": { + "pathe": "^2.0.3", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/nitropack/node_modules/youch": { + "version": "4.1.0-beta.8", + "resolved": "https://registry.npmjs.org/youch/-/youch-4.1.0-beta.8.tgz", + "integrity": "sha512-rY2A2lSF7zC+l7HH9Mq+83D1dLlsPnEvy8jTouzaptDZM6geqZ3aJe/b7ULCwRURPtWV3vbDjA2DDMdoBol0HQ==", + "license": "MIT", + "dependencies": { + "@poppinss/colors": "^4.1.4", + "@poppinss/dumper": "^0.6.3", + "@speed-highlight/core": "^1.2.7", + "cookie": "^1.0.2", + "youch-core": "^0.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "license": "MIT" + }, + "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==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch-native": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", + "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", + "license": "MIT" + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "license": "(BSD-3-Clause OR GPL-2.0)", + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-gyp-build": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "license": "MIT", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/node-mock-http": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/node-mock-http/-/node-mock-http-1.0.2.tgz", + "integrity": "sha512-zWaamgDUdo9SSLw47we78+zYw/bDr5gH8pH7oRRs8V3KmBtu8GLgGIbV2p/gRPd3LWpEOpjQj7X1FOU3VFMJ8g==", + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "license": "MIT" + }, + "node_modules/nopt": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-8.1.0.tgz", + "integrity": "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==", + "license": "ISC", + "dependencies": { + "abbrev": "^3.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/nuxt": { + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/nuxt/-/nuxt-3.19.0.tgz", + "integrity": "sha512-gDXI7sL6dtdgHVh+D90UpI0El5LzQhKvwhIB6ppm8Zh3khG5WsFj3GZkPF0JVkN2BG9oAFgU14qsVajkOEXG3g==", + "license": "MIT", + "dependencies": { + "@nuxt/cli": "^3.28.0", + "@nuxt/devalue": "^2.0.2", + "@nuxt/devtools": "^2.6.3", + "@nuxt/kit": "3.19.0", + "@nuxt/schema": "3.19.0", + "@nuxt/telemetry": "^2.6.6", + "@nuxt/vite-builder": "3.19.0", + "@unhead/vue": "^2.0.14", + "@vue/shared": "^3.5.20", + "c12": "^3.2.0", + "chokidar": "^4.0.3", + "compatx": "^0.2.0", + "consola": "^3.4.2", + "cookie-es": "^2.0.0", + "defu": "^6.1.4", + "destr": "^2.0.5", + "devalue": "^5.3.2", + "errx": "^0.1.0", + "esbuild": "^0.25.9", + "escape-string-regexp": "^5.0.0", + "estree-walker": "^3.0.3", + "exsolve": "^1.0.7", + "h3": "^1.15.4", + "hookable": "^5.5.3", + "ignore": "^7.0.5", + "impound": "^1.0.0", + "jiti": "^2.5.1", + "klona": "^2.0.6", + "knitwork": "^1.2.0", + "magic-string": "^0.30.18", + "mlly": "^1.8.0", + "mocked-exports": "^0.1.1", + "nanotar": "^0.2.0", + "nitropack": "^2.12.4", + "nypm": "^0.6.1", + "ofetch": "^1.4.1", + "ohash": "^2.0.11", + "on-change": "^5.0.1", + "oxc-minify": "^0.86.0", + "oxc-parser": "^0.86.0", + "oxc-transform": "^0.86.0", + "oxc-walker": "^0.4.0", + "pathe": "^2.0.3", + "perfect-debounce": "^2.0.0", + "pkg-types": "^2.3.0", + "radix3": "^1.1.2", + "scule": "^1.3.0", + "semver": "^7.7.2", + "std-env": "^3.9.0", + "strip-literal": "^3.0.0", + "tinyglobby": "0.2.14", + "ufo": "^1.6.1", + "ultrahtml": "^1.6.0", + "uncrypto": "^0.1.3", + "unctx": "^2.4.1", + "unimport": "^5.2.0", + "unplugin": "^2.3.10", + "unplugin-vue-router": "^0.15.0", + "unstorage": "^1.17.0", + "untyped": "^2.0.0", + "vue": "^3.5.20", + "vue-bundle-renderer": "^2.1.2", + "vue-devtools-stub": "^0.1.0", + "vue-router": "^4.5.1" + }, + "bin": { + "nuxi": "bin/nuxt.mjs", + "nuxt": "bin/nuxt.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@parcel/watcher": "^2.1.0", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "peerDependenciesMeta": { + "@parcel/watcher": { + "optional": true + }, + "@types/node": { + "optional": true + } + } + }, + "node_modules/nypm": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.1.tgz", + "integrity": "sha512-hlacBiRiv1k9hZFiphPUkfSQ/ZfQzZDzC+8z0wL3lvDAOUu/2NnChkKuMoMjNur/9OpKuz2QsIeiPVN0xM5Q0w==", + "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "consola": "^3.4.2", + "pathe": "^2.0.3", + "pkg-types": "^2.2.0", + "tinyexec": "^1.0.1" + }, + "bin": { + "nypm": "dist/cli.mjs" + }, + "engines": { + "node": "^14.16.0 || >=16.10.0" + } + }, + "node_modules/ofetch": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/ofetch/-/ofetch-1.4.1.tgz", + "integrity": "sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw==", + "license": "MIT", + "dependencies": { + "destr": "^2.0.3", + "node-fetch-native": "^1.6.4", + "ufo": "^1.5.4" + } + }, + "node_modules/ohash": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", + "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", + "license": "MIT" + }, + "node_modules/on-change": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/on-change/-/on-change-5.0.1.tgz", + "integrity": "sha512-n7THCP7RkyReRSLkJb8kUWoNsxUIBxTkIp3JKno+sEz6o/9AJ3w3P9fzQkITEkMwyTKJjZciF3v/pVoouxZZMg==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sindresorhus/on-change?sponsor=1" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "license": "MIT", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "license": "MIT", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open/node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open/node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/oxc-minify": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/oxc-minify/-/oxc-minify-0.86.0.tgz", + "integrity": "sha512-pjtM94KElw/RxF3R1ls1ADcBUyZcrCgn0qeL4nD8cOotfzeVFa0xXwQQeCkk+5GPiOqdRApNFuJvK//lQgpqJw==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxc-minify/binding-android-arm64": "0.86.0", + "@oxc-minify/binding-darwin-arm64": "0.86.0", + "@oxc-minify/binding-darwin-x64": "0.86.0", + "@oxc-minify/binding-freebsd-x64": "0.86.0", + "@oxc-minify/binding-linux-arm-gnueabihf": "0.86.0", + "@oxc-minify/binding-linux-arm-musleabihf": "0.86.0", + "@oxc-minify/binding-linux-arm64-gnu": "0.86.0", + "@oxc-minify/binding-linux-arm64-musl": "0.86.0", + "@oxc-minify/binding-linux-riscv64-gnu": "0.86.0", + "@oxc-minify/binding-linux-s390x-gnu": "0.86.0", + "@oxc-minify/binding-linux-x64-gnu": "0.86.0", + "@oxc-minify/binding-linux-x64-musl": "0.86.0", + "@oxc-minify/binding-wasm32-wasi": "0.86.0", + "@oxc-minify/binding-win32-arm64-msvc": "0.86.0", + "@oxc-minify/binding-win32-x64-msvc": "0.86.0" + } + }, + "node_modules/oxc-parser": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/oxc-parser/-/oxc-parser-0.86.0.tgz", + "integrity": "sha512-v9+uomgqyLSxlq3qlaMqJJtXg2+rUsa368p/zkmgi5OMGmcZAtZt5GIeSVFF84iNET+08Hdx/rUtd/FyIdfNFQ==", + "license": "MIT", + "dependencies": { + "@oxc-project/types": "^0.86.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxc-parser/binding-android-arm64": "0.86.0", + "@oxc-parser/binding-darwin-arm64": "0.86.0", + "@oxc-parser/binding-darwin-x64": "0.86.0", + "@oxc-parser/binding-freebsd-x64": "0.86.0", + "@oxc-parser/binding-linux-arm-gnueabihf": "0.86.0", + "@oxc-parser/binding-linux-arm-musleabihf": "0.86.0", + "@oxc-parser/binding-linux-arm64-gnu": "0.86.0", + "@oxc-parser/binding-linux-arm64-musl": "0.86.0", + "@oxc-parser/binding-linux-riscv64-gnu": "0.86.0", + "@oxc-parser/binding-linux-s390x-gnu": "0.86.0", + "@oxc-parser/binding-linux-x64-gnu": "0.86.0", + "@oxc-parser/binding-linux-x64-musl": "0.86.0", + "@oxc-parser/binding-wasm32-wasi": "0.86.0", + "@oxc-parser/binding-win32-arm64-msvc": "0.86.0", + "@oxc-parser/binding-win32-x64-msvc": "0.86.0" + } + }, + "node_modules/oxc-transform": { + "version": "0.86.0", + "resolved": "https://registry.npmjs.org/oxc-transform/-/oxc-transform-0.86.0.tgz", + "integrity": "sha512-Ghgm/zzjPXROMpljLy4HYBcko/25sixWi2yJQJ6rDu/ltgFB1nEQ4JYCYV5F+ENt0McsJkcgmX5I4dRfDViyDA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxc-transform/binding-android-arm64": "0.86.0", + "@oxc-transform/binding-darwin-arm64": "0.86.0", + "@oxc-transform/binding-darwin-x64": "0.86.0", + "@oxc-transform/binding-freebsd-x64": "0.86.0", + "@oxc-transform/binding-linux-arm-gnueabihf": "0.86.0", + "@oxc-transform/binding-linux-arm-musleabihf": "0.86.0", + "@oxc-transform/binding-linux-arm64-gnu": "0.86.0", + "@oxc-transform/binding-linux-arm64-musl": "0.86.0", + "@oxc-transform/binding-linux-riscv64-gnu": "0.86.0", + "@oxc-transform/binding-linux-s390x-gnu": "0.86.0", + "@oxc-transform/binding-linux-x64-gnu": "0.86.0", + "@oxc-transform/binding-linux-x64-musl": "0.86.0", + "@oxc-transform/binding-wasm32-wasi": "0.86.0", + "@oxc-transform/binding-win32-arm64-msvc": "0.86.0", + "@oxc-transform/binding-win32-x64-msvc": "0.86.0" + } + }, + "node_modules/oxc-walker": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/oxc-walker/-/oxc-walker-0.4.0.tgz", + "integrity": "sha512-x5TJAZQD3kRnRBGZ+8uryMZUwkTYddwzBftkqyJIcmpBOXmoK/fwriRKATjZroR2d+aS7+2w1B0oz189bBTwfw==", + "license": "MIT", + "dependencies": { + "estree-walker": "^3.0.3", + "magic-regexp": "^0.10.0" + }, + "peerDependencies": { + "oxc-parser": ">=0.72.0" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "license": "BlueOak-1.0.0" + }, + "node_modules/package-manager-detector": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.3.0.tgz", + "integrity": "sha512-ZsEbbZORsyHuO00lY1kV3/t72yp6Ysay6Pd17ZAlNGuGwmWDLCJxFpRs0IzfXfj1o4icJOkUEioexFHzyPurSQ==", + "license": "MIT" + }, + "node_modules/parse-path": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-7.1.0.tgz", + "integrity": "sha512-EuCycjZtfPcjWk7KTksnJ5xPMvWGA/6i4zrLYhRG0hGvC3GPU/jGUj3Cy+ZR0v30duV3e23R95T1lE2+lsndSw==", + "license": "MIT", + "dependencies": { + "protocols": "^2.0.0" + } + }, + "node_modules/parse-url": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-9.2.0.tgz", + "integrity": "sha512-bCgsFI+GeGWPAvAiUv63ZorMeif3/U0zaXABGJbOWt5OH2KCaPHF6S+0ok4aqM9RuIPGyZdx9tR9l13PsW4AYQ==", + "license": "MIT", + "dependencies": { + "@types/parse-path": "^7.0.0", + "parse-path": "^7.0.0" + }, + "engines": { + "node": ">=14.13.0" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "license": "MIT" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/path-type": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz", + "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "license": "MIT" + }, + "node_modules/perfect-debounce": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.0.0.tgz", + "integrity": "sha512-fkEH/OBiKrqqI/yIgjR92lMfs2K8105zt/VT6+7eTjNwisrsh47CeIED9z58zI7DfKdH3uHAn25ziRZn3kgAow==", + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-types": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", + "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "license": "MIT", + "dependencies": { + "confbox": "^0.2.2", + "exsolve": "^1.0.7", + "pathe": "^2.0.3" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-calc": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-10.1.1.tgz", + "integrity": "sha512-NYEsLHh8DgG/PRH2+G9BTuUdtf9ViS+vdoQ0YA5OQdGsfN4ztiwtDWNtBl9EKeqNMFnIu8IKZ0cLxEQ5r5KVMw==", + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^7.0.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^18.12 || ^20.9 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.38" + } + }, + "node_modules/postcss-colormin": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-7.0.4.tgz", + "integrity": "sha512-ziQuVzQZBROpKpfeDwmrG+Vvlr0YWmY/ZAk99XD+mGEBuEojoFekL41NCsdhyNUtZI7DPOoIWIR7vQQK9xwluw==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.25.1", + "caniuse-api": "^3.0.0", + "colord": "^2.9.3", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/postcss-convert-values": { + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-7.0.7.tgz", + "integrity": "sha512-HR9DZLN04Xbe6xugRH6lS4ZQH2zm/bFh/ZyRkpedZozhvh+awAfbA0P36InO4fZfDhvYfNJeNvlTf1sjwGbw/A==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.25.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/postcss-discard-comments": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-7.0.4.tgz", + "integrity": "sha512-6tCUoql/ipWwKtVP/xYiFf1U9QgJ0PUvxN7pTcsQ8Ns3Fnwq1pU5D5s1MhT/XySeLq6GXNvn37U46Ded0TckWg==", + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^7.1.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/postcss-discard-duplicates": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-7.0.2.tgz", + "integrity": "sha512-eTonaQvPZ/3i1ASDHOKkYwAybiM45zFIc7KXils4mQmHLqIswXD9XNOKEVxtTFnsmwYzF66u4LMgSr0abDlh5w==", + "license": "MIT", + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/postcss-discard-empty": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-7.0.1.tgz", + "integrity": "sha512-cFrJKZvcg/uxB6Ijr4l6qmn3pXQBna9zyrPC+sK0zjbkDUZew+6xDltSF7OeB7rAtzaaMVYSdbod+sZOCWnMOg==", + "license": "MIT", + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/postcss-discard-overridden": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-7.0.1.tgz", + "integrity": "sha512-7c3MMjjSZ/qYrx3uc1940GSOzN1Iqjtlqe8uoSg+qdVPYyRb0TILSqqmtlSFuE4mTDECwsm397Ya7iXGzfF7lg==", + "license": "MIT", + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/postcss-merge-longhand": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-7.0.5.tgz", + "integrity": "sha512-Kpu5v4Ys6QI59FxmxtNB/iHUVDn9Y9sYw66D6+SZoIk4QTz1prC4aYkhIESu+ieG1iylod1f8MILMs1Em3mmIw==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "stylehacks": "^7.0.5" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/postcss-merge-rules": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-7.0.6.tgz", + "integrity": "sha512-2jIPT4Tzs8K87tvgCpSukRQ2jjd+hH6Bb8rEEOUDmmhOeTcqDg5fEFK8uKIu+Pvc3//sm3Uu6FRqfyv7YF7+BQ==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.25.1", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^5.0.1", + "postcss-selector-parser": "^7.1.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/postcss-minify-font-values": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-7.0.1.tgz", + "integrity": "sha512-2m1uiuJeTplll+tq4ENOQSzB8LRnSUChBv7oSyFLsJRtUgAAJGP6LLz0/8lkinTgxrmJSPOEhgY1bMXOQ4ZXhQ==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/postcss-minify-gradients": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-7.0.1.tgz", + "integrity": "sha512-X9JjaysZJwlqNkJbUDgOclyG3jZEpAMOfof6PUZjPnPrePnPG62pS17CjdM32uT1Uq1jFvNSff9l7kNbmMSL2A==", + "license": "MIT", + "dependencies": { + "colord": "^2.9.3", + "cssnano-utils": "^5.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/postcss-minify-params": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-7.0.4.tgz", + "integrity": "sha512-3OqqUddfH8c2e7M35W6zIwv7jssM/3miF9cbCSb1iJiWvtguQjlxZGIHK9JRmc8XAKmE2PFGtHSM7g/VcW97sw==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.25.1", + "cssnano-utils": "^5.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/postcss-minify-selectors": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-7.0.5.tgz", + "integrity": "sha512-x2/IvofHcdIrAm9Q+p06ZD1h6FPcQ32WtCRVodJLDR+WMn8EVHI1kvLxZuGKz/9EY5nAmI6lIQIrpo4tBy5+ug==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "postcss-selector-parser": "^7.1.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/postcss-normalize-charset": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-7.0.1.tgz", + "integrity": "sha512-sn413ofhSQHlZFae//m9FTOfkmiZ+YQXsbosqOWRiVQncU2BA3daX3n0VF3cG6rGLSFVc5Di/yns0dFfh8NFgQ==", + "license": "MIT", + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/postcss-normalize-display-values": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-7.0.1.tgz", + "integrity": "sha512-E5nnB26XjSYz/mGITm6JgiDpAbVuAkzXwLzRZtts19jHDUBFxZ0BkXAehy0uimrOjYJbocby4FVswA/5noOxrQ==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/postcss-normalize-positions": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-7.0.1.tgz", + "integrity": "sha512-pB/SzrIP2l50ZIYu+yQZyMNmnAcwyYb9R1fVWPRxm4zcUFCY2ign7rcntGFuMXDdd9L2pPNUgoODDk91PzRZuQ==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/postcss-normalize-repeat-style": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-7.0.1.tgz", + "integrity": "sha512-NsSQJ8zj8TIDiF0ig44Byo3Jk9e4gNt9x2VIlJudnQQ5DhWAHJPF4Tr1ITwyHio2BUi/I6Iv0HRO7beHYOloYQ==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/postcss-normalize-string": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-7.0.1.tgz", + "integrity": "sha512-QByrI7hAhsoze992kpbMlJSbZ8FuCEc1OT9EFbZ6HldXNpsdpZr+YXC5di3UEv0+jeZlHbZcoCADgb7a+lPmmQ==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/postcss-normalize-timing-functions": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-7.0.1.tgz", + "integrity": "sha512-bHifyuuSNdKKsnNJ0s8fmfLMlvsQwYVxIoUBnowIVl2ZAdrkYQNGVB4RxjfpvkMjipqvbz0u7feBZybkl/6NJg==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/postcss-normalize-unicode": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-7.0.4.tgz", + "integrity": "sha512-LvIURTi1sQoZqj8mEIE8R15yvM+OhbR1avynMtI9bUzj5gGKR/gfZFd8O7VMj0QgJaIFzxDwxGl/ASMYAkqO8g==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.25.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/postcss-normalize-url": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-7.0.1.tgz", + "integrity": "sha512-sUcD2cWtyK1AOL/82Fwy1aIVm/wwj5SdZkgZ3QiUzSzQQofrbq15jWJ3BA7Z+yVRwamCjJgZJN0I9IS7c6tgeQ==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/postcss-normalize-whitespace": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-7.0.1.tgz", + "integrity": "sha512-vsbgFHMFQrJBJKrUFJNZ2pgBeBkC2IvvoHjz1to0/0Xk7sII24T0qFOiJzG6Fu3zJoq/0yI4rKWi7WhApW+EFA==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/postcss-ordered-values": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-7.0.2.tgz", + "integrity": "sha512-AMJjt1ECBffF7CEON/Y0rekRLS6KsePU6PRP08UqYW4UGFRnTXNrByUzYK1h8AC7UWTZdQ9O3Oq9kFIhm0SFEw==", + "license": "MIT", + "dependencies": { + "cssnano-utils": "^5.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/postcss-reduce-initial": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-7.0.4.tgz", + "integrity": "sha512-rdIC9IlMBn7zJo6puim58Xd++0HdbvHeHaPgXsimMfG1ijC5A9ULvNLSE0rUKVJOvNMcwewW4Ga21ngyJjY/+Q==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.25.1", + "caniuse-api": "^3.0.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/postcss-reduce-transforms": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-7.0.1.tgz", + "integrity": "sha512-MhyEbfrm+Mlp/36hvZ9mT9DaO7dbncU0CvWI8V93LRkY6IYlu38OPg3FObnuKTUxJ4qA8HpurdQOo5CyqqO76g==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/postcss-selector-parser": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-svgo": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-7.1.0.tgz", + "integrity": "sha512-KnAlfmhtoLz6IuU3Sij2ycusNs4jPW+QoFE5kuuUOK8awR6tMxZQrs5Ey3BUz7nFCzT3eqyFgqkyrHiaU2xx3w==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.2.0", + "svgo": "^4.0.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >= 18" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/postcss-unique-selectors": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-7.0.4.tgz", + "integrity": "sha512-pmlZjsmEAG7cHd7uK3ZiNSW6otSZ13RHuZ/4cDN/bVglS5EpF2r2oxY99SuOHa8m7AWoBCelTS3JPpzsIs8skQ==", + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^7.1.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "license": "MIT" + }, + "node_modules/postcss/node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/pretty-bytes": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-7.0.1.tgz", + "integrity": "sha512-285/jRCYIbMGDciDdrw0KPNC4LKEEwz/bwErcYNxSJOi4CpGUuLpb9gQpg3XJP0XYj9ldSRluXxih4lX2YN8Xw==", + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/protocols": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/protocols/-/protocols-2.0.2.tgz", + "integrity": "sha512-hHVTzba3wboROl0/aWRRG9dMytgH6ow//STBZh43l/wQgmMhYhOFi0EHWAPtoCz9IAUymsyP0TSBHkhgMEGNnQ==", + "license": "MIT" + }, + "node_modules/quansync": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz", + "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/antfu" + }, + { + "type": "individual", + "url": "https://github.com/sponsors/sxzz" + } + ], + "license": "MIT" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/radix3": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/radix3/-/radix3-1.1.2.tgz", + "integrity": "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==", + "license": "MIT" + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/rc9": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz", + "integrity": "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==", + "license": "MIT", + "dependencies": { + "defu": "^6.1.4", + "destr": "^2.0.3" + } + }, + "node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/readdir-glob": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz", + "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==", + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.1.0" + } + }, + "node_modules/readdir-glob/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", + "license": "MIT", + "dependencies": { + "redis-errors": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regexp-tree": { + "version": "0.1.27", + "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz", + "integrity": "sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==", + "license": "MIT", + "bin": { + "regexp-tree": "bin/regexp-tree" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "license": "MIT" + }, + "node_modules/rollup": { + "version": "4.50.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.0.tgz", + "integrity": "sha512-/Zl4D8zPifNmyGzJS+3kVoyXeDeT/GrsJM94sACNg9RtUE0hrHa1bNPtRSrfHTMH5HjRzce6K7rlTh3Khiw+pw==", + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.50.0", + "@rollup/rollup-android-arm64": "4.50.0", + "@rollup/rollup-darwin-arm64": "4.50.0", + "@rollup/rollup-darwin-x64": "4.50.0", + "@rollup/rollup-freebsd-arm64": "4.50.0", + "@rollup/rollup-freebsd-x64": "4.50.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.50.0", + "@rollup/rollup-linux-arm-musleabihf": "4.50.0", + "@rollup/rollup-linux-arm64-gnu": "4.50.0", + "@rollup/rollup-linux-arm64-musl": "4.50.0", + "@rollup/rollup-linux-loongarch64-gnu": "4.50.0", + "@rollup/rollup-linux-ppc64-gnu": "4.50.0", + "@rollup/rollup-linux-riscv64-gnu": "4.50.0", + "@rollup/rollup-linux-riscv64-musl": "4.50.0", + "@rollup/rollup-linux-s390x-gnu": "4.50.0", + "@rollup/rollup-linux-x64-gnu": "4.50.0", + "@rollup/rollup-linux-x64-musl": "4.50.0", + "@rollup/rollup-openharmony-arm64": "4.50.0", + "@rollup/rollup-win32-arm64-msvc": "4.50.0", + "@rollup/rollup-win32-ia32-msvc": "4.50.0", + "@rollup/rollup-win32-x64-msvc": "4.50.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup-plugin-visualizer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/rollup-plugin-visualizer/-/rollup-plugin-visualizer-6.0.3.tgz", + "integrity": "sha512-ZU41GwrkDcCpVoffviuM9Clwjy5fcUxlz0oMoTXTYsK+tcIFzbdacnrr2n8TXcHxbGKKXtOdjxM2HUS4HjkwIw==", + "license": "MIT", + "dependencies": { + "open": "^8.0.0", + "picomatch": "^4.0.2", + "source-map": "^0.7.4", + "yargs": "^17.5.1" + }, + "bin": { + "rollup-plugin-visualizer": "dist/bin/cli.js" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "rolldown": "1.x || ^1.0.0-beta", + "rollup": "2.x || 3.x || 4.x" + }, + "peerDependenciesMeta": { + "rolldown": { + "optional": true + }, + "rollup": { + "optional": true + } + } + }, + "node_modules/run-applescript": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", + "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/sax": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", + "license": "ISC" + }, + "node_modules/scule": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/scule/-/scule-1.3.0.tgz", + "integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", + "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.5", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "mime-types": "^3.0.1", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-placeholder": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/serve-placeholder/-/serve-placeholder-2.0.2.tgz", + "integrity": "sha512-/TMG8SboeiQbZJWRlfTCqMs2DD3SZgWp0kDQePz9yUuCnDfDh/92gf7/PxGhzXTKBIPASIHxFcZndoNbp6QOLQ==", + "license": "MIT", + "dependencies": { + "defu": "^6.1.4" + } + }, + "node_modules/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/simple-git": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.28.0.tgz", + "integrity": "sha512-Rs/vQRwsn1ILH1oBUy8NucJlXmnnLeLCfcvbSehkPzbv3wwoFWIdtfd6Ndo6ZPhlPsCZ60CPI4rxurnwAa+a2w==", + "license": "MIT", + "dependencies": { + "@kwsites/file-exists": "^1.1.1", + "@kwsites/promise-deferred": "^1.1.1", + "debug": "^4.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/steveukx/git-js?sponsor=1" + } + }, + "node_modules/sirv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.1.tgz", + "integrity": "sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==", + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "license": "MIT" + }, + "node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/smob": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz", + "integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==", + "license": "MIT" + }, + "node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/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==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/speakingurl": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", + "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/standard-as-callback": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", + "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==", + "license": "MIT" + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/std-env": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz", + "integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==", + "license": "MIT" + }, + "node_modules/streamx": { + "version": "2.22.1", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.22.1.tgz", + "integrity": "sha512-znKXEBxfatz2GBNK02kRnCXjV+AA4kjZIUxeWSr3UGirZMJfTE9uiwKHobnbgxWyL/JWro8tTq+vOqAK1/qbSA==", + "license": "MIT", + "dependencies": { + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" + }, + "optionalDependencies": { + "bare-events": "^2.2.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "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==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/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==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/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==", + "license": "MIT" + }, + "node_modules/string-width-cjs/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==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/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==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-literal": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.0.0.tgz", + "integrity": "sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==", + "license": "MIT", + "dependencies": { + "js-tokens": "^9.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/strip-literal/node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "license": "MIT" + }, + "node_modules/structured-clone-es": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/structured-clone-es/-/structured-clone-es-1.0.0.tgz", + "integrity": "sha512-FL8EeKFFyNQv5cMnXI31CIMCsFarSVI2bF0U0ImeNE3g/F1IvJQyqzOXxPBRXiwQfyBTlbNe88jh1jFW0O/jiQ==", + "license": "ISC" + }, + "node_modules/stylehacks": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-7.0.6.tgz", + "integrity": "sha512-iitguKivmsueOmTO0wmxURXBP8uqOO+zikLGZ7Mm9e/94R4w5T999Js2taS/KBOnQ/wdC3jN3vNSrkGDrlnqQg==", + "license": "MIT", + "dependencies": { + "browserslist": "^4.25.1", + "postcss-selector-parser": "^7.1.0" + }, + "engines": { + "node": "^18.12.0 || ^20.9.0 || >=22.0" + }, + "peerDependencies": { + "postcss": "^8.4.32" + } + }, + "node_modules/superjson": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.2.tgz", + "integrity": "sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==", + "license": "MIT", + "dependencies": { + "copy-anything": "^3.0.2" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/supports-color": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.0.tgz", + "integrity": "sha512-5eG9FQjEjDbAlI5+kdpdyPIBMRH4GfTVDGREVupaZHmVoppknhM29b/S9BkQz7cathp85BVgRi/As3Siln7e0Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svgo": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.0.tgz", + "integrity": "sha512-VvrHQ+9uniE+Mvx3+C9IEe/lWasXCU0nXMY2kZeLrHNICuRiC8uMPyM14UEaMOFA5mhyQqEkB02VoQ16n3DLaw==", + "license": "MIT", + "dependencies": { + "commander": "^11.1.0", + "css-select": "^5.1.0", + "css-tree": "^3.0.1", + "css-what": "^6.1.0", + "csso": "^5.0.5", + "picocolors": "^1.1.1", + "sax": "^1.4.1" + }, + "bin": { + "svgo": "bin/svgo.js" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" + } + }, + "node_modules/system-architecture": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/system-architecture/-/system-architecture-0.1.0.tgz", + "integrity": "sha512-ulAk51I9UVUyJgxlv9M6lFot2WP3e7t8Kz9+IS6D4rVba1tR9kON+Ey69f+1R4Q8cd45Lod6a4IcJIxnzGc/zA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tapable": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.3.tgz", + "integrity": "sha512-ZL6DDuAlRlLGghwcfmSn9sK3Hr6ArtyudlSAiCqQ6IfE+b+HHbydbYDIG15IfS5do+7XQQBdBiubF/cV2dnDzg==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tar": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz", + "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==", + "license": "ISC", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.0.1", + "mkdirp": "^3.0.1", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/terser": { + "version": "5.44.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.44.0.tgz", + "integrity": "sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==", + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/text-decoder": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", + "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" + } + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz", + "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==", + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD", + "optional": true + }, + "node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-level-regexp": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/type-level-regexp/-/type-level-regexp-0.1.17.tgz", + "integrity": "sha512-wTk4DH3cxwk196uGLK/E9pE45aLfeKJacKmcEgEOA/q5dnPGNxXt0cfYdFxb57L+sEpf1oJH4Dnx/pnRcku9jg==", + "license": "MIT" + }, + "node_modules/ufo": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz", + "integrity": "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==", + "license": "MIT" + }, + "node_modules/ultrahtml": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ultrahtml/-/ultrahtml-1.6.0.tgz", + "integrity": "sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw==", + "license": "MIT" + }, + "node_modules/uncrypto": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/uncrypto/-/uncrypto-0.1.3.tgz", + "integrity": "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==", + "license": "MIT" + }, + "node_modules/unctx": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/unctx/-/unctx-2.4.1.tgz", + "integrity": "sha512-AbaYw0Nm4mK4qjhns67C+kgxR2YWiwlDBPzxrN8h8C6VtAdCgditAY5Dezu3IJy4XVqAnbrXt9oQJvsn3fyozg==", + "license": "MIT", + "dependencies": { + "acorn": "^8.14.0", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.17", + "unplugin": "^2.1.0" + } + }, + "node_modules/unenv": { + "version": "2.0.0-rc.20", + "resolved": "https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.20.tgz", + "integrity": "sha512-8tn4tAl9vD5nWoggAAPz28vf0FY8+pQAayhU94qD+ZkIbVKCBAH/E1MWEEmhb9Whn5EgouYVfBJB20RsTLRDdg==", + "license": "MIT", + "dependencies": { + "defu": "^6.1.4", + "exsolve": "^1.0.7", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "ufo": "^1.6.1" + } + }, + "node_modules/unhead": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/unhead/-/unhead-2.0.14.tgz", + "integrity": "sha512-dRP6OCqtShhMVZQe1F4wdt/WsYl2MskxKK+cvfSo0lQnrPJ4oAUQEkxRg7pPP+vJENabhlir31HwAyHUv7wfMg==", + "license": "MIT", + "dependencies": { + "hookable": "^5.5.3" + }, + "funding": { + "url": "https://github.com/sponsors/harlan-zw" + } + }, + "node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unimport": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/unimport/-/unimport-5.2.0.tgz", + "integrity": "sha512-bTuAMMOOqIAyjV4i4UH7P07pO+EsVxmhOzQ2YJ290J6mkLUdozNhb5I/YoOEheeNADC03ent3Qj07X0fWfUpmw==", + "license": "MIT", + "dependencies": { + "acorn": "^8.15.0", + "escape-string-regexp": "^5.0.0", + "estree-walker": "^3.0.3", + "local-pkg": "^1.1.1", + "magic-string": "^0.30.17", + "mlly": "^1.7.4", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "pkg-types": "^2.2.0", + "scule": "^1.3.0", + "strip-literal": "^3.0.0", + "tinyglobby": "^0.2.14", + "unplugin": "^2.3.5", + "unplugin-utils": "^0.2.4" + }, + "engines": { + "node": ">=18.12.0" + } + }, + "node_modules/unplugin": { + "version": "2.3.10", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.10.tgz", + "integrity": "sha512-6NCPkv1ClwH+/BGE9QeoTIl09nuiAt0gS28nn1PvYXsGKRwM2TCbFA2QiilmehPDTXIe684k4rZI1yl3A1PCUw==", + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "acorn": "^8.15.0", + "picomatch": "^4.0.3", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": ">=18.12.0" + } + }, + "node_modules/unplugin-utils": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/unplugin-utils/-/unplugin-utils-0.2.5.tgz", + "integrity": "sha512-gwXJnPRewT4rT7sBi/IvxKTjsms7jX7QIDLOClApuZwR49SXbrB1z2NLUZ+vDHyqCj/n58OzRRqaW+B8OZi8vg==", + "license": "MIT", + "dependencies": { + "pathe": "^2.0.3", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=18.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/unplugin-vue-router": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/unplugin-vue-router/-/unplugin-vue-router-0.15.0.tgz", + "integrity": "sha512-PyGehCjd9Ny9h+Uer4McbBjjib3lHihcyUEILa7pHKl6+rh8N7sFyw4ZkV+N30Oq2zmIUG7iKs3qpL0r+gXAaQ==", + "license": "MIT", + "dependencies": { + "@vue-macros/common": "3.0.0-beta.16", + "@vue/language-core": "^3.0.1", + "ast-walker-scope": "^0.8.1", + "chokidar": "^4.0.3", + "json5": "^2.2.3", + "local-pkg": "^1.1.1", + "magic-string": "^0.30.17", + "mlly": "^1.7.4", + "muggle-string": "^0.4.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "scule": "^1.3.0", + "tinyglobby": "^0.2.14", + "unplugin": "^2.3.5", + "unplugin-utils": "^0.2.4", + "yaml": "^2.8.0" + }, + "peerDependencies": { + "@vue/compiler-sfc": "^3.5.17", + "vue-router": "^4.5.1" + }, + "peerDependenciesMeta": { + "vue-router": { + "optional": true + } + } + }, + "node_modules/unstorage": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.17.0.tgz", + "integrity": "sha512-l9Z7lBiwtNp8ZmcoZ/dmPkFXFdtEdZtTZafCSnEIj3YvtkXeGAtL2rN8MQFy/0cs4eOLpuRJMp9ivdug7TCvww==", + "license": "MIT", + "dependencies": { + "anymatch": "^3.1.3", + "chokidar": "^4.0.3", + "destr": "^2.0.5", + "h3": "^1.15.4", + "lru-cache": "^10.4.3", + "node-fetch-native": "^1.6.7", + "ofetch": "^1.4.1", + "ufo": "^1.6.1" + }, + "peerDependencies": { + "@azure/app-configuration": "^1.8.0", + "@azure/cosmos": "^4.2.0", + "@azure/data-tables": "^13.3.0", + "@azure/identity": "^4.6.0", + "@azure/keyvault-secrets": "^4.9.0", + "@azure/storage-blob": "^12.26.0", + "@capacitor/preferences": "^6.0.3 || ^7.0.0", + "@deno/kv": ">=0.9.0", + "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", + "@planetscale/database": "^1.19.0", + "@upstash/redis": "^1.34.3", + "@vercel/blob": ">=0.27.1", + "@vercel/functions": "^2.2.12", + "@vercel/kv": "^1.0.1", + "aws4fetch": "^1.0.20", + "db0": ">=0.2.1", + "idb-keyval": "^6.2.1", + "ioredis": "^5.4.2", + "uploadthing": "^7.4.4" + }, + "peerDependenciesMeta": { + "@azure/app-configuration": { + "optional": true + }, + "@azure/cosmos": { + "optional": true + }, + "@azure/data-tables": { + "optional": true + }, + "@azure/identity": { + "optional": true + }, + "@azure/keyvault-secrets": { + "optional": true + }, + "@azure/storage-blob": { + "optional": true + }, + "@capacitor/preferences": { + "optional": true + }, + "@deno/kv": { + "optional": true + }, + "@netlify/blobs": { + "optional": true + }, + "@planetscale/database": { + "optional": true + }, + "@upstash/redis": { + "optional": true + }, + "@vercel/blob": { + "optional": true + }, + "@vercel/functions": { + "optional": true + }, + "@vercel/kv": { + "optional": true + }, + "aws4fetch": { + "optional": true + }, + "db0": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "ioredis": { + "optional": true + }, + "uploadthing": { + "optional": true + } + } + }, + "node_modules/unstorage/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/untun": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/untun/-/untun-0.1.3.tgz", + "integrity": "sha512-4luGP9LMYszMRZwsvyUd9MrxgEGZdZuZgpVQHEEX0lCYFESasVRvZd0EYpCkOIbJKHMuv0LskpXc/8Un+MJzEQ==", + "license": "MIT", + "dependencies": { + "citty": "^0.1.5", + "consola": "^3.2.3", + "pathe": "^1.1.1" + }, + "bin": { + "untun": "bin/untun.mjs" + } + }, + "node_modules/untun/node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "license": "MIT" + }, + "node_modules/untyped": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/untyped/-/untyped-2.0.0.tgz", + "integrity": "sha512-nwNCjxJTjNuLCgFr42fEak5OcLuB3ecca+9ksPFNvtfYSLpjf+iJqSIaSnIile6ZPbKYxI5k2AfXqeopGudK/g==", + "license": "MIT", + "dependencies": { + "citty": "^0.1.6", + "defu": "^6.1.4", + "jiti": "^2.4.2", + "knitwork": "^1.2.0", + "scule": "^1.3.0" + }, + "bin": { + "untyped": "dist/cli.mjs" + } + }, + "node_modules/unwasm": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/unwasm/-/unwasm-0.3.11.tgz", + "integrity": "sha512-Vhp5gb1tusSQw5of/g3Q697srYgMXvwMgXMjcG4ZNga02fDX9coxJ9fAb0Ci38hM2Hv/U1FXRPGgjP2BYqhNoQ==", + "license": "MIT", + "dependencies": { + "knitwork": "^1.2.0", + "magic-string": "^0.30.17", + "mlly": "^1.7.4", + "pathe": "^2.0.3", + "pkg-types": "^2.2.0", + "unplugin": "^2.3.6" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uqr": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/uqr/-/uqr-0.1.2.tgz", + "integrity": "sha512-MJu7ypHq6QasgF5YRTjqscSzQp/W11zoUk6kvmlH+fmWEs63Y0Eib13hYFwAzagRJcVY8WVnlV+eBDUGMJ5IbA==", + "license": "MIT" + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/vite": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.4.tgz", + "integrity": "sha512-X5QFK4SGynAeeIt+A7ZWnApdUyHYm+pzv/8/A57LqSGcI88U6R6ipOs3uCesdc6yl7nl+zNO0t8LmqAdXcQihw==", + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.14" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-dev-rpc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/vite-dev-rpc/-/vite-dev-rpc-1.1.0.tgz", + "integrity": "sha512-pKXZlgoXGoE8sEKiKJSng4hI1sQ4wi5YT24FCrwrLt6opmkjlqPPVmiPWWJn8M8byMxRGzp1CrFuqQs4M/Z39A==", + "license": "MIT", + "dependencies": { + "birpc": "^2.4.0", + "vite-hot-client": "^2.1.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vite": "^2.9.0 || ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.1 || ^7.0.0-0" + } + }, + "node_modules/vite-hot-client": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/vite-hot-client/-/vite-hot-client-2.1.0.tgz", + "integrity": "sha512-7SpgZmU7R+dDnSmvXE1mfDtnHLHQSisdySVR7lO8ceAXvM0otZeuQQ6C8LrS5d/aYyP/QZ0hI0L+dIPrm4YlFQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vite": "^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0" + } + }, + "node_modules/vite-node": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", + "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.4.1", + "es-module-lexer": "^1.7.0", + "pathe": "^2.0.3", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vite-plugin-checker": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/vite-plugin-checker/-/vite-plugin-checker-0.10.3.tgz", + "integrity": "sha512-f4sekUcDPF+T+GdbbE8idb1i2YplBAoH+SfRS0e/WRBWb2rYb1Jf5Pimll0Rj+3JgIYWwG2K5LtBPCXxoibkLg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "chokidar": "^4.0.3", + "npm-run-path": "^6.0.0", + "picocolors": "^1.1.1", + "picomatch": "^4.0.3", + "strip-ansi": "^7.1.0", + "tiny-invariant": "^1.3.3", + "tinyglobby": "^0.2.14", + "vscode-uri": "^3.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "peerDependencies": { + "@biomejs/biome": ">=1.7", + "eslint": ">=7", + "meow": "^13.2.0", + "optionator": "^0.9.4", + "stylelint": ">=16", + "typescript": "*", + "vite": ">=2.0.0", + "vls": "*", + "vti": "*", + "vue-tsc": "~2.2.10 || ^3.0.0" + }, + "peerDependenciesMeta": { + "@biomejs/biome": { + "optional": true + }, + "eslint": { + "optional": true + }, + "meow": { + "optional": true + }, + "optionator": { + "optional": true + }, + "stylelint": { + "optional": true + }, + "typescript": { + "optional": true + }, + "vls": { + "optional": true + }, + "vti": { + "optional": true + }, + "vue-tsc": { + "optional": true + } + } + }, + "node_modules/vite-plugin-checker/node_modules/npm-run-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", + "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/vite-plugin-checker/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/vite-plugin-inspect": { + "version": "11.3.3", + "resolved": "https://registry.npmjs.org/vite-plugin-inspect/-/vite-plugin-inspect-11.3.3.tgz", + "integrity": "sha512-u2eV5La99oHoYPHE6UvbwgEqKKOQGz86wMg40CCosP6q8BkB6e5xPneZfYagK4ojPJSj5anHCrnvC20DpwVdRA==", + "license": "MIT", + "dependencies": { + "ansis": "^4.1.0", + "debug": "^4.4.1", + "error-stack-parser-es": "^1.0.5", + "ohash": "^2.0.11", + "open": "^10.2.0", + "perfect-debounce": "^2.0.0", + "sirv": "^3.0.1", + "unplugin-utils": "^0.3.0", + "vite-dev-rpc": "^1.1.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vite": "^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "@nuxt/kit": { + "optional": true + } + } + }, + "node_modules/vite-plugin-inspect/node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/vite-plugin-inspect/node_modules/open": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", + "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", + "license": "MIT", + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "wsl-utils": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/vite-plugin-inspect/node_modules/unplugin-utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unplugin-utils/-/unplugin-utils-0.3.0.tgz", + "integrity": "sha512-JLoggz+PvLVMJo+jZt97hdIIIZ2yTzGgft9e9q8iMrC4ewufl62ekeW7mixBghonn2gVb/ICjyvlmOCUBnJLQg==", + "license": "MIT", + "dependencies": { + "pathe": "^2.0.3", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/vite-plugin-vue-tracer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/vite-plugin-vue-tracer/-/vite-plugin-vue-tracer-1.0.0.tgz", + "integrity": "sha512-a+UB9IwGx5uwS4uG/a9kM6fCMnxONDkOTbgCUbhFpiGhqfxrrC1+9BibV7sWwUnwj1Dg6MnRxG0trLgUZslDXA==", + "license": "MIT", + "dependencies": { + "estree-walker": "^3.0.3", + "exsolve": "^1.0.7", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "source-map-js": "^1.2.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "vite": "^6.0.0 || ^7.0.0", + "vue": "^3.5.0" + } + }, + "node_modules/vscode-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", + "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", + "license": "MIT" + }, + "node_modules/vue": { + "version": "3.5.21", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.21.tgz", + "integrity": "sha512-xxf9rum9KtOdwdRkiApWL+9hZEMWE90FHh8yS1+KJAiWYh+iGWV1FquPjoO9VUHQ+VIhsCXNNyZ5Sf4++RVZBA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.21", + "@vue/compiler-sfc": "3.5.21", + "@vue/runtime-dom": "3.5.21", + "@vue/server-renderer": "3.5.21", + "@vue/shared": "3.5.21" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vue-bundle-renderer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/vue-bundle-renderer/-/vue-bundle-renderer-2.1.2.tgz", + "integrity": "sha512-M4WRBO/O/7G9phGaGH9AOwOnYtY9ZpPoDVpBpRzR2jO5rFL9mgIlQIgums2ljCTC2HL1jDXFQc//CzWcAQHgAw==", + "license": "MIT", + "dependencies": { + "ufo": "^1.6.1" + } + }, + "node_modules/vue-devtools-stub": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/vue-devtools-stub/-/vue-devtools-stub-0.1.0.tgz", + "integrity": "sha512-RutnB7X8c5hjq39NceArgXg28WZtZpGc3+J16ljMiYnFhKvd8hITxSWQSQ5bvldxMDU6gG5mkxl1MTQLXckVSQ==", + "license": "MIT" + }, + "node_modules/vue-router": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.5.1.tgz", + "integrity": "sha512-ogAF3P97NPm8fJsE4by9dwSYtDwXIY1nFY9T6DyQnGHd1E2Da94w9JIolpe42LJGIl0DwOHBi8TcRPlPGwbTtw==", + "license": "MIT", + "dependencies": { + "@vue/devtools-api": "^6.6.4" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "vue": "^3.2.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==", + "license": "BSD-2-Clause" + }, + "node_modules/webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "license": "MIT" + }, + "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==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", + "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "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==", + "license": "MIT", + "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-cjs/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==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/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==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/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==", + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/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==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/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==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "license": "MIT", + "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/wsl-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", + "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC" + }, + "node_modules/yaml": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", + "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "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==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/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==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/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==", + "license": "MIT" + }, + "node_modules/yargs/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==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/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==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/youch": { + "version": "4.1.0-beta.11", + "resolved": "https://registry.npmjs.org/youch/-/youch-4.1.0-beta.11.tgz", + "integrity": "sha512-sQi6PERyO/mT8w564ojOVeAlYTtVQmC2GaktQAf+IdI75/GKIggosBuvyVXvEV+FATAT6RbLdIjFoiIId4ozoQ==", + "license": "MIT", + "dependencies": { + "@poppinss/colors": "^4.1.5", + "@poppinss/dumper": "^0.6.4", + "@speed-highlight/core": "^1.2.7", + "cookie": "^1.0.2", + "youch-core": "^0.3.3" + } + }, + "node_modules/youch-core": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/youch-core/-/youch-core-0.3.3.tgz", + "integrity": "sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==", + "license": "MIT", + "dependencies": { + "@poppinss/exception": "^1.2.2", + "error-stack-parser-es": "^1.0.5" + } + }, + "node_modules/zip-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-6.0.1.tgz", + "integrity": "sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==", + "license": "MIT", + "dependencies": { + "archiver-utils": "^5.0.0", + "compress-commons": "^6.0.2", + "readable-stream": "^4.0.0" + }, + "engines": { + "node": ">= 14" + } + } + } +} diff --git a/app/pages/index.vue b/app/pages/index.vue index 61eed19..b84a817 100644 --- a/app/pages/index.vue +++ b/app/pages/index.vue @@ -2,16 +2,18 @@
-
- - - \ No newline at end of file diff --git a/index.php b/index.php index 7d5f21c..ee7f6e5 100644 --- a/index.php +++ b/index.php @@ -26,7 +26,7 @@ $container = $config[$host] ?? null; $lxd = new LxdService(); // === Helper URLs === -$redirectBase = parseUrl("$host/app?auth=ok&redirect=" . urlencode(getFullUrl())); +$redirectBase = parseUrl("$host/app"); $waitingPage = parseUrl("$host/app/waiting?name=$container&redirect=" . urlencode(getFullUrl())); // === If container is missing or invalid === if (!$container || !$lxd->containerExists($container)) { @@ -69,7 +69,8 @@ function proxy(string $name, string $targetUrl): void { $_SERVER['HTTP_PROXY_TARGET_URL'] = $targetUrl; $responseCode = Proxy::run(); - writeLog($name, $targetUrl); + touch($_ENV['STATEDIR']."/".$name); + } function getFullUrl(): string {