diff --git a/.env b/.env
new file mode 100644
index 0000000..a6679f2
--- /dev/null
+++ b/.env
@@ -0,0 +1,5 @@
+UTOPIA_DATA_API_ENV=development
+UTOPIA_DATA_API_SECRET=proxy-secret-key
+UTOPIA_DATA_API_SECRET_CONNECTION=mariadb://root:password@mariadb:3306/appwrite?pool_size=256
+UTOPIA_DATA_API_LOGGING_PROVIDER=
+UTOPIA_DATA_API_LOGGING_CONFIG=
\ No newline at end of file
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
new file mode 100644
index 0000000..3253e2c
--- /dev/null
+++ b/.github/workflows/codeql-analysis.yml
@@ -0,0 +1,16 @@
+name: "CodeQL"
+
+on: [pull_request]
+jobs:
+ lint:
+ name: CodeQL
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Check out the repo
+ uses: actions/checkout@v2
+
+ - name: Run CodeQL
+ run: |
+ docker run --rm -v $PWD:/app composer sh -c \
+ "composer install --profile --ignore-platform-reqs && composer check"
\ No newline at end of file
diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml
new file mode 100644
index 0000000..28f4c6a
--- /dev/null
+++ b/.github/workflows/linter.yml
@@ -0,0 +1,16 @@
+name: "Linter"
+
+on: [pull_request]
+jobs:
+ lint:
+ name: Linter
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Check out the repo
+ uses: actions/checkout@v2
+
+ - name: Run Linter
+ run: |
+ docker run --rm -v $PWD:/app composer sh -c \
+ "composer install --profile --ignore-platform-reqs && composer lint"
\ No newline at end of file
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000..8cc9deb
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,41 @@
+name: "Release"
+
+on:
+ release:
+ types: [published]
+
+env:
+ IMAGE_NAME: utopia-php/database-proxy
+ TAG: ${{ github.event.release.tag_name }}
+ USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
+ PASSWORD: ${{ secrets.DOCKERHUB_PASSWORD }}
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Check out the repo
+ uses: actions/checkout@v2
+
+ - name: Set up QEMU
+ uses: docker/setup-qemu-action@v2
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v2
+
+ - name: Login to DockerHub
+ uses: docker/login-action@v2
+ with:
+ registry: ${{ env.REGISTRY }}
+ username: ${{ env.USERNAME }}
+ password: ${{ env.PASSWORD }}
+
+ - name: Build and push
+ uses: docker/build-push-action@v4
+ with:
+ build-args: |
+ UTOPIA_DATA_API_VERSION=${{ env.TAG }}
+ platforms: linux/amd64,linux/arm64,linux/arm/v6,linux/arm/v7
+ context: .
+ push: true
+ tags: ${{ env.IMAGE_NAME }}:latest,${{ env.IMAGE_NAME }}:${{ env.TAG }}
\ No newline at end of file
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
new file mode 100644
index 0000000..ff9b7e2
--- /dev/null
+++ b/.github/workflows/tests.yml
@@ -0,0 +1,33 @@
+name: "Tests"
+
+on: [pull_request]
+jobs:
+ tests:
+ name: Tests
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Check out the repo
+ uses: actions/checkout@v2
+
+ - name: Start Test Stack
+ run: |
+ export COMPOSE_INTERACTIVE_NO_CLI
+ export DOCKER_BUILDKIT=1
+ export COMPOSE_DOCKER_CLI_BUILD=1
+ export BUILDKIT_PROGRESS=plain
+ docker pull composer:2.0
+ docker compose build
+ docker compose up -d
+ sleep 60
+
+ - name: Doctor
+ run: |
+ docker compose logs
+ docker ps
+ docker network ls
+
+ - name: Run Tests
+ run: |
+ docker run --rm -v $PWD:/app --network data-api_database -w /app phpswoole/swoole:4.8.12-php8.1-alpine sh -c \
+ "composer install --profile --ignore-platform-reqs && composer test"
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..03766f7
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+/vendor/
+/.idea/
+.phpunit.cache
\ No newline at end of file
diff --git a/.phpunit.result.cache b/.phpunit.result.cache
new file mode 100644
index 0000000..fd470f7
--- /dev/null
+++ b/.phpunit.result.cache
@@ -0,0 +1 @@
+{"version":1,"defects":{"Tests\\ProxyTest::testSecret":8,"Tests\\ProxyTest::testDefaultDatabase":7,"Tests\\ProxyTest::testNamespace":7,"Tests\\ProxyTest::testTimeout":7,"Tests\\ProxyTest::testAuth":7,"Tests\\ProxyTest::testMock":8,"Tests\\ProxyTest::testPing":7,"Tests\\ProxyTest::testExists":7},"times":{"Tests\\ProxyTest::testSecret":0.005,"Tests\\ProxyTest::testDefaultDatabase":0.009,"Tests\\ProxyTest::testNamespace":0.018,"Tests\\ProxyTest::testTimeout":0.005,"Tests\\ProxyTest::testAuth":0.056,"Tests\\ProxyTest::testMock":0.043,"Tests\\ProxyTest::testPing":0.003,"Tests\\ProxyTest::testExists":0.022}}
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..340c444
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,89 @@
+# Install PHP libraries
+FROM composer:2.0 as composer
+
+WORKDIR /usr/local/src/
+
+COPY composer.lock /usr/local/src/
+COPY composer.json /usr/local/src/
+
+RUN composer install --ignore-platform-reqs --optimize-autoloader \
+ --no-plugins --no-scripts --prefer-dist
+
+# Prepare generic compiler
+FROM php:8.1.25-cli-alpine3.16 as compile
+
+ENV PHP_SWOOLE_VERSION="v5.1.0" \
+ PHP_MONGODB_VERSION="1.16.1"
+
+RUN \
+ apk add --no-cache --virtual .deps \
+ make \
+ automake \
+ autoconf \
+ gcc \
+ g++ \
+ git \
+ openssl-dev
+
+RUN docker-php-ext-install sockets
+
+# Compile Swoole
+FROM compile AS swoole
+
+RUN \
+ git clone --depth 1 --branch $PHP_SWOOLE_VERSION https://github.com/swoole/swoole-src.git && \
+ cd swoole-src && \
+ phpize && \
+ ./configure --enable-sockets --enable-http2 --enable-openssl && \
+ make && make install && \
+ cd ..
+
+# Mongodb Extension
+FROM compile as mongodb
+RUN \
+ git clone --depth 1 --branch $PHP_MONGODB_VERSION https://github.com/mongodb/mongo-php-driver.git && \
+ cd mongo-php-driver && \
+ git submodule update --init && \
+ phpize && \
+ ./configure && \
+ make && make install
+
+# Proxy
+FROM php:8.1.25-cli-alpine3.16 as final
+
+ARG UTOPIA_DATA_API_VERSION
+ENV UTOPIA_DATA_API_VERSION=$UTOPIA_DATA_API_VERSION
+
+LABEL maintainer="team@appwrite.io"
+
+RUN \
+ apk update \
+ && apk add --no-cache --virtual .deps \
+ make \
+ automake \
+ autoconf \
+ gcc \
+ g++ \
+ curl-dev \
+ && apk add --no-cache \
+ libstdc++ \
+ postgresql-dev \
+ && docker-php-ext-install sockets pdo_mysql pdo_pgsql \
+ && apk del .deps \
+ && rm -rf /var/cache/apk/*
+
+WORKDIR /usr/local/
+
+# Source code
+COPY ./app /usr/local/app
+
+# Extensions and libraries
+COPY --from=composer /usr/local/src/vendor /usr/local/vendor
+COPY --from=swoole /usr/local/lib/php/extensions/no-debug-non-zts-20210902/swoole.so /usr/local/lib/php/extensions/no-debug-non-zts-20210902/
+COPY --from=mongodb /usr/local/lib/php/extensions/no-debug-non-zts-20210902/mongodb.so /usr/local/lib/php/extensions/no-debug-non-zts-20210902/
+
+RUN echo extension=swoole.so >> /usr/local/etc/php/conf.d/swoole.ini
+
+EXPOSE 80
+
+CMD [ "php", "app/http.php" ]
\ No newline at end of file
diff --git a/README.md b/README.md
index 7146af6..cb4873e 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,4 @@
-# Utopia PHP Database Proxy
\ No newline at end of file
+# Utopia PHP Data API
+
+Build:
+docker build -t data-api .
\ No newline at end of file
diff --git a/app/http.php b/app/http.php
new file mode 100644
index 0000000..10e7468
--- /dev/null
+++ b/app/http.php
@@ -0,0 +1,329 @@
+set('logger', function () {
+ $providerName = Http::getEnv('UTOPIA_DATA_API_LOGGING_PROVIDER', '');
+ $providerConfig = Http::getEnv('UTOPIA_DATA_API_LOGGING_CONFIG', '');
+ $logger = null;
+
+ if (!empty($providerName) && !empty($providerConfig) && Logger::hasProvider($providerName)) {
+ $adapter = match ($providerName) {
+ 'sentry' => new Sentry($providerConfig),
+ 'raygun' => new Raygun($providerConfig),
+ 'logowl' => new LogOwl($providerConfig),
+ 'appsignal' => new AppSignal($providerConfig),
+ default => throw new Exception('Provider "' . $providerName . '" not supported.')
+ };
+
+ $logger = new Logger($adapter);
+ }
+
+ return $logger;
+});
+
+$registry->set('pool', function () {
+ $dsnString = Http::getEnv('UTOPIA_DATA_API_SECRET_CONNECTION', '') ?? '';
+
+ $dsn = new DSN($dsnString);
+ $dsnHost = $dsn->getHost();
+ $dsnPort = $dsn->getPort();
+ $dsnUser = $dsn->getUser();
+ $dsnPass = $dsn->getPassword();
+ $dsnScheme = $dsn->getScheme();
+ $dsnDatabase = $dsn->getPath() ?? '';
+ $poolSize = \intval($dsn->getParam('pool_size', '255'));
+
+ $pool = new Pool('adapter-pool', $poolSize, function () use ($dsnScheme, $dsnHost, $dsnPort, $dsnUser, $dsnPass, $dsnDatabase) {
+ switch ($dsnScheme) {
+ case 'mariadb':
+ $pdo = new PDO("mysql:host={$dsnHost};port={$dsnPort};dbname={$dsnDatabase};charset=utf8mb4", $dsnUser, $dsnPass, array(
+ PDO::ATTR_TIMEOUT => 15, // Seconds
+ PDO::ATTR_PERSISTENT => false,
+ PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
+ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, // PDO will throw a PDOException
+ PDO::ATTR_EMULATE_PREPARES => true,
+ PDO::ATTR_STRINGIFY_FETCHES => true
+ ));
+ $adapter = new MariaDB($pdo);
+ $adapter->setDatabase($dsnDatabase);
+
+ return $adapter;
+ };
+ });
+
+ return $pool;
+});
+
+$http = new Server("0.0.0.0", Http::getEnv('UTOPIA_DATA_API_PORT', '80'), [
+ 'open_http2_protocol' => true,
+ 'http_compression' => true,
+ 'http_compression_level' => 6,
+ 'package_max_length' => PAYLOAD_SIZE,
+ 'buffer_output_size' => PAYLOAD_SIZE,
+]);
+
+Http::onStart()
+ ->action(function () {
+ Console::success("HTTP server started.");
+ });
+
+Http::setResource('registry', fn () => $registry);
+Http::setResource('logger', fn (Registry $registry) => $registry->get('logger'), ['registry']);
+Http::setResource('pool', fn (Registry $registry) => $registry->get('pool'), ['registry']);
+Http::setResource('log', fn () => new Log());
+Http::setResource('authorization', fn () => new Authorization());
+
+Http::setResource('adapterConnection', function (Pool $pool) {
+ $connection = $pool->pop();
+ return $connection;
+}, ['pool']);
+
+Http::setResource('adapter', function (Request $request, Connection $adapterConnection, Authorization $authorization) {
+ $namespace = $request->getHeader('x-utopia-namespace', '');
+ $timeoutsString = $request->getHeader('x-utopia-timeouts', '[]');
+ $database = $request->getHeader('x-utopia-database', '');
+ $roles = $request->getHeader('x-utopia-auth-roles', '');
+ $status = $request->getHeader('x-utopia-auth-status', '');
+ $statusDefault = $request->getHeader('x-utopia-auth-status-default', '');
+ $shareTables = $request->getHeader('x-utopia-share-tables', '');
+ $tenant = $request->getHeader('x-utopia-tenant', '');
+
+ $timeouts = \json_decode($timeoutsString, true);
+
+ /**
+ * @var Adapter $resource
+ */
+ $resource = $adapterConnection->getResource();
+ $resource->setAuthorization($authorization);
+ $resource->setNamespace($namespace);
+
+ $resource->clearTransformations();
+
+ foreach ($timeouts as $event => $timeout) {
+ $resource->setTimeout(\intval($timeout), $event);
+ }
+
+ if (!empty($database)) {
+ $resource->setDatabase($database);
+ } else {
+ $resource->setDatabase('');
+ }
+
+ if (!empty($shareTables)) {
+ if ($shareTables === 'false') {
+ $resource->setShareTables(false);
+ } else {
+ $resource->setShareTables(true);
+ }
+ }
+
+ if (!empty($tenant)) {
+ $resource->setTenant(\intval($tenant));
+ }
+
+ $authorization->cleanRoles();
+ $authorization->addRole('any');
+ foreach (\explode(',', $roles) as $role) {
+ $authorization->addRole($role);
+ }
+
+ if (!empty($statusDefault) && $statusDefault === 'false') {
+ $authorization->setDefaultStatus(false);
+ } else {
+ $authorization->setDefaultStatus(true);
+ }
+
+ if (!empty($status)) {
+ if ($status === 'false') {
+ $authorization->disable();
+ } else {
+ $authorization->enable();
+ }
+ }
+
+ return $resource;
+}, ['request', 'adapterConnection', 'authorization']);
+
+Http::init()
+ ->groups(['api'])
+ ->inject('request')
+ ->action(function (Request $request) {
+ $secret = Http::getEnv('UTOPIA_DATA_API_SECRET', '');
+ $header = $request->getHeader('x-utopia-secret', '');
+
+ if ($header !== $secret) {
+ throw new Exception('Incorrect secret in x-utopia-secret header.', 401);
+ }
+ });
+
+Http::init()
+ ->groups(['mock'])
+ ->action(function () {
+ if (!Http::isDevelopment()) {
+ throw new Exception('Mock endpoints are not implemented on production.', 404);
+ }
+ });
+
+Http::get('/mock/error')
+ ->groups(['api', 'mock'])
+ ->action(function () {
+ throw new Exception('Mock error', 500);
+ });
+
+Http::post('/v1/queries')
+ ->groups(['api'])
+ ->param('query', '', new Text(1024, 1), 'Method name to run with query')
+ ->param('params', '', new Text(0, 0), 'Base64 of serialized parameters to pass into a method call', true)
+ ->inject('adapter')
+ ->inject('request')
+ ->inject('response')
+ ->action(function (string $query, string $params, Adapter $adapter, Request $request, Response $response) {
+
+ if(empty($params)) {
+ $typedParams = [];
+ } else {
+ $typedParams = \unserialize(\base64_decode($params));
+ }
+
+ /**
+ * @var callable $method
+ */
+ $method = [$adapter, $query];
+ $output = call_user_func_array($method, $typedParams);
+
+ $response->json([
+ 'output' => $output
+ ]);
+ });
+
+Http::shutdown()
+ ->inject('utopia')
+ ->inject('context')
+ ->action(function (Http $app, string $context) {
+ $connection = $app->getResource('adapterConnection', $context);
+
+ if (isset($connection)) {
+ $connection->reclaim();
+ }
+ });
+
+Http::error()
+ ->inject('route')
+ ->inject('error')
+ ->inject('logger')
+ ->inject('response')
+ ->inject('log')
+ ->action(function (?Route $route, Throwable $error, ?Logger $logger, Response $response, Log $log) {
+ Console::error('[Error] Type: ' . get_class($error));
+ Console::error('[Error] Type: ' . get_class($error));
+ Console::error('[Error] Message: ' . $error->getMessage());
+ Console::error('[Error] File: ' . $error->getFile());
+ Console::error('[Error] Line: ' . $error->getLine());
+
+ if ($logger && ($error->getCode() === 500 || $error->getCode() === 0)) {
+ $version = (string) Http::getEnv('UTOPIA_DATA_API_VERSION', '');
+ if (empty($version)) {
+ $version = 'UNKNOWN';
+ }
+
+ $log->setNamespace("database-proxy");
+ $log->setServer(\gethostname() !== false ? \gethostname() : null);
+ $log->setVersion($version);
+ $log->setType(Log::TYPE_ERROR);
+ $log->setMessage($error->getMessage());
+
+ if ($route) {
+ $log->addTag('method', $route->getMethod());
+ $log->addTag('url', $route->getPath());
+ }
+
+ $log->addTag('code', \strval($error->getCode()));
+ $log->addTag('verboseType', get_class($error));
+
+ $log->addExtra('file', $error->getFile());
+ $log->addExtra('line', $error->getLine());
+ $log->addExtra('trace', $error->getTraceAsString());
+ $log->addExtra('detailedTrace', $error->getTrace());
+
+ $log->setAction('httpError');
+
+ $log->setEnvironment(Http::isProduction() ? Log::ENVIRONMENT_PRODUCTION : Log::ENVIRONMENT_STAGING);
+
+ $responseCode = $logger->addLog($log);
+ Console::info('Log pushed with status code: ' . $responseCode);
+ }
+
+ switch ($error->getCode()) {
+ case 400: // Error allowed publicly
+ case 401: // Error allowed publicly
+ case 402: // Error allowed publicly
+ case 403: // Error allowed publicly
+ case 404: // Error allowed publicly
+ case 406: // Error allowed publicly
+ case 408: // Error allowed publicly
+ case 409: // Error allowed publicly
+ case 412: // Error allowed publicly
+ case 425: // Error allowed publicly
+ case 429: // Error allowed publicly
+ case 501: // Error allowed publicly
+ case 503: // Error allowed publicly
+ $code = $error->getCode();
+ break;
+ default:
+ $code = 500; // All other errors get the generic 500 server error status code
+ }
+
+ $output = [
+ 'type' => \get_class($error),
+ 'message' => $error->getMessage(),
+ 'code' => $error->getCode(),
+ 'file' => $error->getFile(),
+ 'line' => $error->getLine(),
+ 'trace' => $error->getTrace(),
+ 'version' => Http::getEnv('UTOPIA_DATA_API_VERSION', 'UNKNOWN')
+ ];
+
+ $response
+ ->addHeader('Cache-Control', 'no-cache, no-store, must-revalidate')
+ ->addHeader('Expires', '0')
+ ->addHeader('Pragma', 'no-cache')
+ ->setStatusCode(\intval($code));
+
+ $response->json($output);
+ });
+
+$app = new Http($http, 'UTC');
+$app->start();
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..805e372
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,48 @@
+{
+ "name": "utopia/database-proxy",
+ "description": "HTTP proxy to manage Utopia Database connections.",
+ "type": "project",
+ "license": "MIT",
+ "autoload": {
+ "psr-4": {
+ "Utopia\\DatabaseProxy\\": "app"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Tests\\": "tests"
+ }
+ },
+ "scripts": {
+ "lint": "./vendor/bin/pint --test",
+ "format": "./vendor/bin/pint",
+ "check": "./vendor/bin/phpstan analyse --level 8 -c phpstan.neon app tests",
+ "test": "./vendor/bin/phpunit --configuration phpunit.xml --testdox"
+ },
+ "require": {
+ "php": ">=8.1.0",
+ "ext-curl": "*",
+ "ext-json": "*",
+ "ext-swoole": "*",
+ "utopia-php/framework": "0.34.*",
+ "utopia-php/database": "dev-feat-framework-v2",
+ "utopia-php/cache": "0.9.*",
+ "utopia-php/cli": "0.16.*",
+ "utopia-php/registry": "0.6.*",
+ "utopia-php/dsn": "0.1.*",
+ "utopia-php/logger": "0.3.*",
+ "utopia-php/pools": "0.4.*"
+ },
+ "require-dev": {
+ "swoole/ide-helper": "5.1.*",
+ "phpunit/phpunit": "10.4.*",
+ "laravel/pint": "1.13.*",
+ "phpstan/phpstan": "1.10.*",
+ "utopia-php/fetch": "0.1.*"
+ },
+ "config": {
+ "platform": {
+ "php": "8.1"
+ }
+ }
+}
\ No newline at end of file
diff --git a/composer.lock b/composer.lock
new file mode 100644
index 0000000..e32cc8f
--- /dev/null
+++ b/composer.lock
@@ -0,0 +1,2518 @@
+{
+ "_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": "ad445a0c21278f56603b165891018278",
+ "packages": [
+ {
+ "name": "jean85/pretty-package-versions",
+ "version": "2.0.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/Jean85/pretty-package-versions.git",
+ "reference": "ae547e455a3d8babd07b96966b17d7fd21d9c6af"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/ae547e455a3d8babd07b96966b17d7fd21d9c6af",
+ "reference": "ae547e455a3d8babd07b96966b17d7fd21d9c6af",
+ "shasum": ""
+ },
+ "require": {
+ "composer-runtime-api": "^2.0.0",
+ "php": "^7.1|^8.0"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^2.17",
+ "jean85/composer-provided-replaced-stub-package": "^1.0",
+ "phpstan/phpstan": "^0.12.66",
+ "phpunit/phpunit": "^7.5|^8.5|^9.4",
+ "vimeo/psalm": "^4.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Jean85\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Alessandro Lai",
+ "email": "alessandro.lai85@gmail.com"
+ }
+ ],
+ "description": "A library to get pretty versions strings of installed dependencies",
+ "keywords": [
+ "composer",
+ "package",
+ "release",
+ "versions"
+ ],
+ "support": {
+ "issues": "https://github.com/Jean85/pretty-package-versions/issues",
+ "source": "https://github.com/Jean85/pretty-package-versions/tree/2.0.5"
+ },
+ "time": "2021-10-08T21:21:46+00:00"
+ },
+ {
+ "name": "mongodb/mongodb",
+ "version": "1.10.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/mongodb/mongo-php-library.git",
+ "reference": "b0bbd657f84219212487d01a8ffe93a789e1e488"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/mongodb/mongo-php-library/zipball/b0bbd657f84219212487d01a8ffe93a789e1e488",
+ "reference": "b0bbd657f84219212487d01a8ffe93a789e1e488",
+ "shasum": ""
+ },
+ "require": {
+ "ext-hash": "*",
+ "ext-json": "*",
+ "ext-mongodb": "^1.11.0",
+ "jean85/pretty-package-versions": "^1.2 || ^2.0.1",
+ "php": "^7.1 || ^8.0",
+ "symfony/polyfill-php80": "^1.19"
+ },
+ "require-dev": {
+ "doctrine/coding-standard": "^9.0",
+ "squizlabs/php_codesniffer": "^3.6",
+ "symfony/phpunit-bridge": "^5.2"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.10.x-dev"
+ }
+ },
+ "autoload": {
+ "files": [
+ "src/functions.php"
+ ],
+ "psr-4": {
+ "MongoDB\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "Andreas Braun",
+ "email": "andreas.braun@mongodb.com"
+ },
+ {
+ "name": "Jeremy Mikola",
+ "email": "jmikola@gmail.com"
+ }
+ ],
+ "description": "MongoDB driver library",
+ "homepage": "https://jira.mongodb.org/browse/PHPLIB",
+ "keywords": [
+ "database",
+ "driver",
+ "mongodb",
+ "persistence"
+ ],
+ "support": {
+ "issues": "https://github.com/mongodb/mongo-php-library/issues",
+ "source": "https://github.com/mongodb/mongo-php-library/tree/1.10.0"
+ },
+ "time": "2021-10-20T22:22:37+00:00"
+ },
+ {
+ "name": "symfony/polyfill-php80",
+ "version": "v1.29.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-php80.git",
+ "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
+ "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.1"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "name": "symfony/polyfill",
+ "url": "https://github.com/symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Php80\\": ""
+ },
+ "classmap": [
+ "Resources/stubs"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Ion Bazan",
+ "email": "ion.bazan@gmail.com"
+ },
+ {
+ "name": "Nicolas Grekas",
+ "email": "p@tchwork.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-php80/tree/v1.29.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-01-29T20:11:03+00:00"
+ },
+ {
+ "name": "utopia-php/cache",
+ "version": "0.9.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/utopia-php/cache.git",
+ "reference": "4fc7b4789b5f0ce74835c1ecfec4f3afe6f0e34e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/utopia-php/cache/zipball/4fc7b4789b5f0ce74835c1ecfec4f3afe6f0e34e",
+ "reference": "4fc7b4789b5f0ce74835c1ecfec4f3afe6f0e34e",
+ "shasum": ""
+ },
+ "require": {
+ "ext-json": "*",
+ "ext-memcached": "*",
+ "ext-redis": "*",
+ "php": ">=8.0"
+ },
+ "require-dev": {
+ "laravel/pint": "1.2.*",
+ "phpstan/phpstan": "1.9.x-dev",
+ "phpunit/phpunit": "^9.3",
+ "vimeo/psalm": "4.13.1"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Utopia\\Cache\\": "src/Cache"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "A simple cache library to manage application cache storing, loading and purging",
+ "keywords": [
+ "cache",
+ "framework",
+ "php",
+ "upf",
+ "utopia"
+ ],
+ "support": {
+ "issues": "https://github.com/utopia-php/cache/issues",
+ "source": "https://github.com/utopia-php/cache/tree/0.9.0"
+ },
+ "time": "2024-01-07T18:11:23+00:00"
+ },
+ {
+ "name": "utopia-php/cli",
+ "version": "0.16.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/utopia-php/cli.git",
+ "reference": "5b936638c90c86d1bae83d0dbe81fe14d12ff8ff"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/utopia-php/cli/zipball/5b936638c90c86d1bae83d0dbe81fe14d12ff8ff",
+ "reference": "5b936638c90c86d1bae83d0dbe81fe14d12ff8ff",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.4",
+ "utopia-php/framework": "0.*.*"
+ },
+ "require-dev": {
+ "laravel/pint": "1.2.*",
+ "phpunit/phpunit": "^9.3",
+ "squizlabs/php_codesniffer": "^3.6",
+ "vimeo/psalm": "4.0.1"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Utopia\\CLI\\": "src/CLI"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "A simple CLI library to manage command line applications",
+ "keywords": [
+ "cli",
+ "command line",
+ "framework",
+ "php",
+ "upf",
+ "utopia"
+ ],
+ "support": {
+ "issues": "https://github.com/utopia-php/cli/issues",
+ "source": "https://github.com/utopia-php/cli/tree/0.16.0"
+ },
+ "time": "2023-08-05T13:13:08+00:00"
+ },
+ {
+ "name": "utopia-php/database",
+ "version": "dev-feat-framework-v2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/utopia-php/database.git",
+ "reference": "79fd5790227e039832372f2c6c9c284f6f1284bb"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/utopia-php/database/zipball/79fd5790227e039832372f2c6c9c284f6f1284bb",
+ "reference": "79fd5790227e039832372f2c6c9c284f6f1284bb",
+ "shasum": ""
+ },
+ "require": {
+ "ext-mbstring": "*",
+ "ext-pdo": "*",
+ "php": ">=8.0",
+ "utopia-php/cache": "0.9.*",
+ "utopia-php/framework": "0.34.*",
+ "utopia-php/mongo": "0.3.*"
+ },
+ "require-dev": {
+ "fakerphp/faker": "^1.14",
+ "laravel/pint": "1.13.*",
+ "pcov/clobber": "^2.0",
+ "phpstan/phpstan": "1.10.*",
+ "phpunit/phpunit": "^9.4",
+ "rregeer/phpunit-coverage-check": "^0.3.1",
+ "swoole/ide-helper": "4.8.0",
+ "utopia-php/cli": "0.17.*"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Utopia\\Database\\": "src/Database"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "A simple library to manage application persistence using multiple database adapters",
+ "keywords": [
+ "database",
+ "framework",
+ "php",
+ "upf",
+ "utopia"
+ ],
+ "support": {
+ "issues": "https://github.com/utopia-php/database/issues",
+ "source": "https://github.com/utopia-php/database/tree/feat-framework-v2"
+ },
+ "time": "2024-02-27T10:05:08+00:00"
+ },
+ {
+ "name": "utopia-php/dsn",
+ "version": "0.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/utopia-php/dsn.git",
+ "reference": "17a5935eab1b89fb4b95600db50a1b6d5faa6cea"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/utopia-php/dsn/zipball/17a5935eab1b89fb4b95600db50a1b6d5faa6cea",
+ "reference": "17a5935eab1b89fb4b95600db50a1b6d5faa6cea",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0"
+ },
+ "require-dev": {
+ "laravel/pint": "1.2.*",
+ "phpunit/phpunit": "^9.3",
+ "squizlabs/php_codesniffer": "^3.6",
+ "vimeo/psalm": "4.0.1"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Utopia\\DSN\\": "src/DSN"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "A simple library for parsing and managing Data Source Names ( DSNs )",
+ "keywords": [
+ "dsn",
+ "framework",
+ "php",
+ "upf",
+ "utopia"
+ ],
+ "support": {
+ "issues": "https://github.com/utopia-php/dsn/issues",
+ "source": "https://github.com/utopia-php/dsn/tree/0.1.0"
+ },
+ "time": "2022-10-26T10:06:20+00:00"
+ },
+ {
+ "name": "utopia-php/framework",
+ "version": "0.34.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/utopia-php/http.git",
+ "reference": "fd126c02b78cc80678c9638f7b335dfb4a841b78"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/utopia-php/http/zipball/fd126c02b78cc80678c9638f7b335dfb4a841b78",
+ "reference": "fd126c02b78cc80678c9638f7b335dfb4a841b78",
+ "shasum": ""
+ },
+ "require": {
+ "ext-swoole": "*",
+ "php": ">=8.0"
+ },
+ "require-dev": {
+ "laravel/pint": "^1.2",
+ "phpbench/phpbench": "^1.2",
+ "phpstan/phpstan": "^1.10",
+ "phpunit/phpunit": "^9.5.25",
+ "swoole/ide-helper": "4.8.3"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Utopia\\Http\\": "src/Http"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "A simple, light and advanced PHP HTTP framework",
+ "keywords": [
+ "framework",
+ "http",
+ "php",
+ "upf"
+ ],
+ "support": {
+ "issues": "https://github.com/utopia-php/http/issues",
+ "source": "https://github.com/utopia-php/http/tree/0.34.2"
+ },
+ "time": "2024-02-20T11:36:56+00:00"
+ },
+ {
+ "name": "utopia-php/logger",
+ "version": "0.3.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/utopia-php/logger.git",
+ "reference": "ba763c10688fe2ed715ad2bed3f13d18dfec6253"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/utopia-php/logger/zipball/ba763c10688fe2ed715ad2bed3f13d18dfec6253",
+ "reference": "ba763c10688fe2ed715ad2bed3f13d18dfec6253",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "1.9.x-dev",
+ "phpunit/phpunit": "^9.3",
+ "vimeo/psalm": "4.0.1"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Utopia\\Logger\\": "src/Logger"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "Utopia Logger library is simple and lite library for logging information, such as errors or warnings. This library is aiming to be as simple and easy to learn and use.",
+ "keywords": [
+ "appsignal",
+ "errors",
+ "framework",
+ "logger",
+ "logging",
+ "logs",
+ "php",
+ "raygun",
+ "sentry",
+ "upf",
+ "utopia",
+ "warnings"
+ ],
+ "support": {
+ "issues": "https://github.com/utopia-php/logger/issues",
+ "source": "https://github.com/utopia-php/logger/tree/0.3.2"
+ },
+ "time": "2023-11-22T14:45:43+00:00"
+ },
+ {
+ "name": "utopia-php/mongo",
+ "version": "0.3.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/utopia-php/mongo.git",
+ "reference": "52326a9a43e2d27ff0c15c48ba746dacbe9a7aee"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/utopia-php/mongo/zipball/52326a9a43e2d27ff0c15c48ba746dacbe9a7aee",
+ "reference": "52326a9a43e2d27ff0c15c48ba746dacbe9a7aee",
+ "shasum": ""
+ },
+ "require": {
+ "ext-mongodb": "*",
+ "mongodb/mongodb": "1.10.0",
+ "php": ">=8.0"
+ },
+ "require-dev": {
+ "fakerphp/faker": "^1.14",
+ "laravel/pint": "1.2.*",
+ "phpstan/phpstan": "1.8.*",
+ "phpunit/phpunit": "^9.4",
+ "swoole/ide-helper": "4.8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Utopia\\Mongo\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Eldad Fux",
+ "email": "eldad@appwrite.io"
+ },
+ {
+ "name": "Wess",
+ "email": "wess@appwrite.io"
+ }
+ ],
+ "description": "A simple library to manage Mongo database",
+ "keywords": [
+ "database",
+ "mongo",
+ "php",
+ "upf",
+ "utopia"
+ ],
+ "support": {
+ "issues": "https://github.com/utopia-php/mongo/issues",
+ "source": "https://github.com/utopia-php/mongo/tree/0.3.1"
+ },
+ "time": "2023-09-01T17:25:28+00:00"
+ },
+ {
+ "name": "utopia-php/pools",
+ "version": "0.4.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/utopia-php/pools.git",
+ "reference": "d2870ab74b31b7f4027799f082e85122154f8bed"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/utopia-php/pools/zipball/d2870ab74b31b7f4027799f082e85122154f8bed",
+ "reference": "d2870ab74b31b7f4027799f082e85122154f8bed",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0"
+ },
+ "require-dev": {
+ "laravel/pint": "1.2.*",
+ "phpstan/phpstan": "1.8.*",
+ "phpunit/phpunit": "^9.3"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Utopia\\Pools\\": "src/Pools"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Team Appwrite",
+ "email": "team@appwrite.io"
+ }
+ ],
+ "description": "A simple library to manage connection pools",
+ "keywords": [
+ "framework",
+ "php",
+ "pools",
+ "utopia"
+ ],
+ "support": {
+ "issues": "https://github.com/utopia-php/pools/issues",
+ "source": "https://github.com/utopia-php/pools/tree/0.4.2"
+ },
+ "time": "2022-11-22T07:55:45+00:00"
+ },
+ {
+ "name": "utopia-php/registry",
+ "version": "0.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/utopia-php/registry.git",
+ "reference": "9c183312e48c926135085f34ac2e73dadb83e0c8"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/utopia-php/registry/zipball/9c183312e48c926135085f34ac2e73dadb83e0c8",
+ "reference": "9c183312e48c926135085f34ac2e73dadb83e0c8",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.4"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^9.3",
+ "vimeo/psalm": "4.0.1"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Utopia\\Registry\\": "src/Registry"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Eldad Fux",
+ "email": "eldad@appwrite.io"
+ }
+ ],
+ "description": "A simple dependency management library for PHP",
+ "keywords": [
+ "dependency management",
+ "di",
+ "framework",
+ "php",
+ "upf",
+ "utopia"
+ ],
+ "support": {
+ "issues": "https://github.com/utopia-php/registry/issues",
+ "source": "https://github.com/utopia-php/registry/tree/0.6.0"
+ },
+ "time": "2022-07-17T15:26:57+00:00"
+ }
+ ],
+ "packages-dev": [
+ {
+ "name": "laravel/pint",
+ "version": "v1.13.11",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/laravel/pint.git",
+ "reference": "60a163c3e7e3346a1dec96d3e6f02e6465452552"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/laravel/pint/zipball/60a163c3e7e3346a1dec96d3e6f02e6465452552",
+ "reference": "60a163c3e7e3346a1dec96d3e6f02e6465452552",
+ "shasum": ""
+ },
+ "require": {
+ "ext-json": "*",
+ "ext-mbstring": "*",
+ "ext-tokenizer": "*",
+ "ext-xml": "*",
+ "php": "^8.1.0"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^3.49.0",
+ "illuminate/view": "^10.43.0",
+ "larastan/larastan": "^2.8.1",
+ "laravel-zero/framework": "^10.3.0",
+ "mockery/mockery": "^1.6.7",
+ "nunomaduro/termwind": "^1.15.1",
+ "pestphp/pest": "^2.33.6"
+ },
+ "bin": [
+ "builds/pint"
+ ],
+ "type": "project",
+ "autoload": {
+ "psr-4": {
+ "App\\": "app/",
+ "Database\\Seeders\\": "database/seeders/",
+ "Database\\Factories\\": "database/factories/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Nuno Maduro",
+ "email": "enunomaduro@gmail.com"
+ }
+ ],
+ "description": "An opinionated code formatter for PHP.",
+ "homepage": "https://laravel.com",
+ "keywords": [
+ "format",
+ "formatter",
+ "lint",
+ "linter",
+ "php"
+ ],
+ "support": {
+ "issues": "https://github.com/laravel/pint/issues",
+ "source": "https://github.com/laravel/pint"
+ },
+ "time": "2024-02-13T17:20:13+00:00"
+ },
+ {
+ "name": "myclabs/deep-copy",
+ "version": "1.11.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/myclabs/DeepCopy.git",
+ "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
+ "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.1 || ^8.0"
+ },
+ "conflict": {
+ "doctrine/collections": "<1.6.8",
+ "doctrine/common": "<2.13.3 || >=3,<3.2.2"
+ },
+ "require-dev": {
+ "doctrine/collections": "^1.6.8",
+ "doctrine/common": "^2.13.3 || ^3.2.2",
+ "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/DeepCopy/deep_copy.php"
+ ],
+ "psr-4": {
+ "DeepCopy\\": "src/DeepCopy/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "Create deep copies (clones) of your objects",
+ "keywords": [
+ "clone",
+ "copy",
+ "duplicate",
+ "object",
+ "object graph"
+ ],
+ "support": {
+ "issues": "https://github.com/myclabs/DeepCopy/issues",
+ "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1"
+ },
+ "funding": [
+ {
+ "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-03-08T13:26:56+00:00"
+ },
+ {
+ "name": "nikic/php-parser",
+ "version": "v5.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/nikic/PHP-Parser.git",
+ "reference": "2218c2252c874a4624ab2f613d86ac32d227bc69"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/2218c2252c874a4624ab2f613d86ac32d227bc69",
+ "reference": "2218c2252c874a4624ab2f613d86ac32d227bc69",
+ "shasum": ""
+ },
+ "require": {
+ "ext-ctype": "*",
+ "ext-json": "*",
+ "ext-tokenizer": "*",
+ "php": ">=7.4"
+ },
+ "require-dev": {
+ "ircmaxell/php-yacc": "^0.0.7",
+ "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0"
+ },
+ "bin": [
+ "bin/php-parse"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "5.0-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "PhpParser\\": "lib/PhpParser"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Nikita Popov"
+ }
+ ],
+ "description": "A PHP parser written in PHP",
+ "keywords": [
+ "parser",
+ "php"
+ ],
+ "support": {
+ "issues": "https://github.com/nikic/PHP-Parser/issues",
+ "source": "https://github.com/nikic/PHP-Parser/tree/v5.0.1"
+ },
+ "time": "2024-02-21T19:24:10+00:00"
+ },
+ {
+ "name": "phar-io/manifest",
+ "version": "2.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phar-io/manifest.git",
+ "reference": "97803eca37d319dfa7826cc2437fc020857acb53"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53",
+ "reference": "97803eca37d319dfa7826cc2437fc020857acb53",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-phar": "*",
+ "ext-xmlwriter": "*",
+ "phar-io/version": "^3.0.1",
+ "php": "^7.2 || ^8.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Heuer",
+ "email": "sebastian@phpeople.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
+ "support": {
+ "issues": "https://github.com/phar-io/manifest/issues",
+ "source": "https://github.com/phar-io/manifest/tree/2.0.3"
+ },
+ "time": "2021-07-20T11:28:43+00:00"
+ },
+ {
+ "name": "phar-io/version",
+ "version": "3.2.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phar-io/version.git",
+ "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
+ "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2 || ^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Heuer",
+ "email": "sebastian@phpeople.de",
+ "role": "Developer"
+ },
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "Library for handling version information and constraints",
+ "support": {
+ "issues": "https://github.com/phar-io/version/issues",
+ "source": "https://github.com/phar-io/version/tree/3.2.1"
+ },
+ "time": "2022-02-21T01:04:05+00:00"
+ },
+ {
+ "name": "phpstan/phpstan",
+ "version": "1.10.59",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpstan/phpstan.git",
+ "reference": "e607609388d3a6d418a50a49f7940e8086798281"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e607609388d3a6d418a50a49f7940e8086798281",
+ "reference": "e607609388d3a6d418a50a49f7940e8086798281",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2|^8.0"
+ },
+ "conflict": {
+ "phpstan/phpstan-shim": "*"
+ },
+ "bin": [
+ "phpstan",
+ "phpstan.phar"
+ ],
+ "type": "library",
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "PHPStan - PHP Static Analysis Tool",
+ "keywords": [
+ "dev",
+ "static analysis"
+ ],
+ "support": {
+ "docs": "https://phpstan.org/user-guide/getting-started",
+ "forum": "https://github.com/phpstan/phpstan/discussions",
+ "issues": "https://github.com/phpstan/phpstan/issues",
+ "security": "https://github.com/phpstan/phpstan/security/policy",
+ "source": "https://github.com/phpstan/phpstan-src"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/ondrejmirtes",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/phpstan",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-02-20T13:59:13+00:00"
+ },
+ {
+ "name": "phpunit/php-code-coverage",
+ "version": "10.1.11",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
+ "reference": "78c3b7625965c2513ee96569a4dbb62601784145"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/78c3b7625965c2513ee96569a4dbb62601784145",
+ "reference": "78c3b7625965c2513ee96569a4dbb62601784145",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-libxml": "*",
+ "ext-xmlwriter": "*",
+ "nikic/php-parser": "^4.18 || ^5.0",
+ "php": ">=8.1",
+ "phpunit/php-file-iterator": "^4.0",
+ "phpunit/php-text-template": "^3.0",
+ "sebastian/code-unit-reverse-lookup": "^3.0",
+ "sebastian/complexity": "^3.0",
+ "sebastian/environment": "^6.0",
+ "sebastian/lines-of-code": "^2.0",
+ "sebastian/version": "^4.0",
+ "theseer/tokenizer": "^1.2.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.1"
+ },
+ "suggest": {
+ "ext-pcov": "PHP extension that provides line coverage",
+ "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "10.1-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
+ "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
+ "keywords": [
+ "coverage",
+ "testing",
+ "xunit"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
+ "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.11"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-12-21T15:38:30+00:00"
+ },
+ {
+ "name": "phpunit/php-file-iterator",
+ "version": "4.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-file-iterator.git",
+ "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/a95037b6d9e608ba092da1b23931e537cadc3c3c",
+ "reference": "a95037b6d9e608ba092da1b23931e537cadc3c3c",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "4.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "FilterIterator implementation that filters files based on a list of suffixes.",
+ "homepage": "https://github.com/sebastianbergmann/php-file-iterator/",
+ "keywords": [
+ "filesystem",
+ "iterator"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
+ "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/4.1.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-08-31T06:24:48+00:00"
+ },
+ {
+ "name": "phpunit/php-invoker",
+ "version": "4.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-invoker.git",
+ "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7",
+ "reference": "f5e568ba02fa5ba0ddd0f618391d5a9ea50b06d7",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "ext-pcntl": "*",
+ "phpunit/phpunit": "^10.0"
+ },
+ "suggest": {
+ "ext-pcntl": "*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "4.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Invoke callables with a timeout",
+ "homepage": "https://github.com/sebastianbergmann/php-invoker/",
+ "keywords": [
+ "process"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-invoker/issues",
+ "source": "https://github.com/sebastianbergmann/php-invoker/tree/4.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-02-03T06:56:09+00:00"
+ },
+ {
+ "name": "phpunit/php-text-template",
+ "version": "3.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-text-template.git",
+ "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/0c7b06ff49e3d5072f057eb1fa59258bf287a748",
+ "reference": "0c7b06ff49e3d5072f057eb1fa59258bf287a748",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "3.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Simple template engine.",
+ "homepage": "https://github.com/sebastianbergmann/php-text-template/",
+ "keywords": [
+ "template"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-text-template/issues",
+ "security": "https://github.com/sebastianbergmann/php-text-template/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-text-template/tree/3.0.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-08-31T14:07:24+00:00"
+ },
+ {
+ "name": "phpunit/php-timer",
+ "version": "6.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-timer.git",
+ "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/e2a2d67966e740530f4a3343fe2e030ffdc1161d",
+ "reference": "e2a2d67966e740530f4a3343fe2e030ffdc1161d",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "6.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Utility class for timing",
+ "homepage": "https://github.com/sebastianbergmann/php-timer/",
+ "keywords": [
+ "timer"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/php-timer/issues",
+ "source": "https://github.com/sebastianbergmann/php-timer/tree/6.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-02-03T06:57:52+00:00"
+ },
+ {
+ "name": "phpunit/phpunit",
+ "version": "10.4.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/phpunit.git",
+ "reference": "cacd8b9dd224efa8eb28beb69004126c7ca1a1a1"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/cacd8b9dd224efa8eb28beb69004126c7ca1a1a1",
+ "reference": "cacd8b9dd224efa8eb28beb69004126c7ca1a1a1",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-json": "*",
+ "ext-libxml": "*",
+ "ext-mbstring": "*",
+ "ext-xml": "*",
+ "ext-xmlwriter": "*",
+ "myclabs/deep-copy": "^1.10.1",
+ "phar-io/manifest": "^2.0.3",
+ "phar-io/version": "^3.0.2",
+ "php": ">=8.1",
+ "phpunit/php-code-coverage": "^10.1.5",
+ "phpunit/php-file-iterator": "^4.0",
+ "phpunit/php-invoker": "^4.0",
+ "phpunit/php-text-template": "^3.0",
+ "phpunit/php-timer": "^6.0",
+ "sebastian/cli-parser": "^2.0",
+ "sebastian/code-unit": "^2.0",
+ "sebastian/comparator": "^5.0",
+ "sebastian/diff": "^5.0",
+ "sebastian/environment": "^6.0",
+ "sebastian/exporter": "^5.1",
+ "sebastian/global-state": "^6.0.1",
+ "sebastian/object-enumerator": "^5.0",
+ "sebastian/recursion-context": "^5.0",
+ "sebastian/type": "^4.0",
+ "sebastian/version": "^4.0"
+ },
+ "suggest": {
+ "ext-soap": "To be able to generate mocks based on WSDL files"
+ },
+ "bin": [
+ "phpunit"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "10.4-dev"
+ }
+ },
+ "autoload": {
+ "files": [
+ "src/Framework/Assert/Functions.php"
+ ],
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "The PHP Unit Testing framework.",
+ "homepage": "https://phpunit.de/",
+ "keywords": [
+ "phpunit",
+ "testing",
+ "xunit"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/phpunit/issues",
+ "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/10.4.2"
+ },
+ "funding": [
+ {
+ "url": "https://phpunit.de/sponsors.html",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-10-26T07:21:45+00:00"
+ },
+ {
+ "name": "sebastian/cli-parser",
+ "version": "2.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/cli-parser.git",
+ "reference": "efdc130dbbbb8ef0b545a994fd811725c5282cae"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/efdc130dbbbb8ef0b545a994fd811725c5282cae",
+ "reference": "efdc130dbbbb8ef0b545a994fd811725c5282cae",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "2.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library for parsing CLI options",
+ "homepage": "https://github.com/sebastianbergmann/cli-parser",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/cli-parser/issues",
+ "source": "https://github.com/sebastianbergmann/cli-parser/tree/2.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-02-03T06:58:15+00:00"
+ },
+ {
+ "name": "sebastian/code-unit",
+ "version": "2.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/code-unit.git",
+ "reference": "a81fee9eef0b7a76af11d121767abc44c104e503"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/a81fee9eef0b7a76af11d121767abc44c104e503",
+ "reference": "a81fee9eef0b7a76af11d121767abc44c104e503",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "2.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Collection of value objects that represent the PHP code units",
+ "homepage": "https://github.com/sebastianbergmann/code-unit",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/code-unit/issues",
+ "source": "https://github.com/sebastianbergmann/code-unit/tree/2.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-02-03T06:58:43+00:00"
+ },
+ {
+ "name": "sebastian/code-unit-reverse-lookup",
+ "version": "3.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
+ "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/5e3a687f7d8ae33fb362c5c0743794bbb2420a1d",
+ "reference": "5e3a687f7d8ae33fb362c5c0743794bbb2420a1d",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "3.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Looks up which function or method a line of code belongs to",
+ "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues",
+ "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/3.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-02-03T06:59:15+00:00"
+ },
+ {
+ "name": "sebastian/comparator",
+ "version": "5.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/comparator.git",
+ "reference": "2db5010a484d53ebf536087a70b4a5423c102372"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2db5010a484d53ebf536087a70b4a5423c102372",
+ "reference": "2db5010a484d53ebf536087a70b4a5423c102372",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-mbstring": "*",
+ "php": ">=8.1",
+ "sebastian/diff": "^5.0",
+ "sebastian/exporter": "^5.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.3"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "5.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Volker Dusch",
+ "email": "github@wallbash.com"
+ },
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@2bepublished.at"
+ }
+ ],
+ "description": "Provides the functionality to compare PHP values for equality",
+ "homepage": "https://github.com/sebastianbergmann/comparator",
+ "keywords": [
+ "comparator",
+ "compare",
+ "equality"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/comparator/issues",
+ "security": "https://github.com/sebastianbergmann/comparator/security/policy",
+ "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-08-14T13:18:12+00:00"
+ },
+ {
+ "name": "sebastian/complexity",
+ "version": "3.2.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/complexity.git",
+ "reference": "68ff824baeae169ec9f2137158ee529584553799"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68ff824baeae169ec9f2137158ee529584553799",
+ "reference": "68ff824baeae169ec9f2137158ee529584553799",
+ "shasum": ""
+ },
+ "require": {
+ "nikic/php-parser": "^4.18 || ^5.0",
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "3.2-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library for calculating the complexity of PHP code units",
+ "homepage": "https://github.com/sebastianbergmann/complexity",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/complexity/issues",
+ "security": "https://github.com/sebastianbergmann/complexity/security/policy",
+ "source": "https://github.com/sebastianbergmann/complexity/tree/3.2.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-12-21T08:37:17+00:00"
+ },
+ {
+ "name": "sebastian/diff",
+ "version": "5.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/diff.git",
+ "reference": "fbf413a49e54f6b9b17e12d900ac7f6101591b7f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/fbf413a49e54f6b9b17e12d900ac7f6101591b7f",
+ "reference": "fbf413a49e54f6b9b17e12d900ac7f6101591b7f",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0",
+ "symfony/process": "^4.2 || ^5"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "5.1-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Kore Nordmann",
+ "email": "mail@kore-nordmann.de"
+ }
+ ],
+ "description": "Diff implementation",
+ "homepage": "https://github.com/sebastianbergmann/diff",
+ "keywords": [
+ "diff",
+ "udiff",
+ "unidiff",
+ "unified diff"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/diff/issues",
+ "security": "https://github.com/sebastianbergmann/diff/security/policy",
+ "source": "https://github.com/sebastianbergmann/diff/tree/5.1.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-12-22T10:55:06+00:00"
+ },
+ {
+ "name": "sebastian/environment",
+ "version": "6.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/environment.git",
+ "reference": "43c751b41d74f96cbbd4e07b7aec9675651e2951"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/43c751b41d74f96cbbd4e07b7aec9675651e2951",
+ "reference": "43c751b41d74f96cbbd4e07b7aec9675651e2951",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0"
+ },
+ "suggest": {
+ "ext-posix": "*"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "6.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Provides functionality to handle HHVM/PHP environments",
+ "homepage": "https://github.com/sebastianbergmann/environment",
+ "keywords": [
+ "Xdebug",
+ "environment",
+ "hhvm"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/environment/issues",
+ "security": "https://github.com/sebastianbergmann/environment/security/policy",
+ "source": "https://github.com/sebastianbergmann/environment/tree/6.0.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-04-11T05:39:26+00:00"
+ },
+ {
+ "name": "sebastian/exporter",
+ "version": "5.1.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/exporter.git",
+ "reference": "64f51654862e0f5e318db7e9dcc2292c63cdbddc"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/64f51654862e0f5e318db7e9dcc2292c63cdbddc",
+ "reference": "64f51654862e0f5e318db7e9dcc2292c63cdbddc",
+ "shasum": ""
+ },
+ "require": {
+ "ext-mbstring": "*",
+ "php": ">=8.1",
+ "sebastian/recursion-context": "^5.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "5.1-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Volker Dusch",
+ "email": "github@wallbash.com"
+ },
+ {
+ "name": "Adam Harvey",
+ "email": "aharvey@php.net"
+ },
+ {
+ "name": "Bernhard Schussek",
+ "email": "bschussek@gmail.com"
+ }
+ ],
+ "description": "Provides the functionality to export PHP variables for visualization",
+ "homepage": "https://www.github.com/sebastianbergmann/exporter",
+ "keywords": [
+ "export",
+ "exporter"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/exporter/issues",
+ "security": "https://github.com/sebastianbergmann/exporter/security/policy",
+ "source": "https://github.com/sebastianbergmann/exporter/tree/5.1.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-09-24T13:22:09+00:00"
+ },
+ {
+ "name": "sebastian/global-state",
+ "version": "6.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/global-state.git",
+ "reference": "7ea9ead78f6d380d2a667864c132c2f7b83055e4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/7ea9ead78f6d380d2a667864c132c2f7b83055e4",
+ "reference": "7ea9ead78f6d380d2a667864c132c2f7b83055e4",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1",
+ "sebastian/object-reflector": "^3.0",
+ "sebastian/recursion-context": "^5.0"
+ },
+ "require-dev": {
+ "ext-dom": "*",
+ "phpunit/phpunit": "^10.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "6.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Snapshotting of global state",
+ "homepage": "http://www.github.com/sebastianbergmann/global-state",
+ "keywords": [
+ "global state"
+ ],
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/global-state/issues",
+ "security": "https://github.com/sebastianbergmann/global-state/security/policy",
+ "source": "https://github.com/sebastianbergmann/global-state/tree/6.0.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-07-19T07:19:23+00:00"
+ },
+ {
+ "name": "sebastian/lines-of-code",
+ "version": "2.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/lines-of-code.git",
+ "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/856e7f6a75a84e339195d48c556f23be2ebf75d0",
+ "reference": "856e7f6a75a84e339195d48c556f23be2ebf75d0",
+ "shasum": ""
+ },
+ "require": {
+ "nikic/php-parser": "^4.18 || ^5.0",
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "2.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library for counting the lines of code in PHP source code",
+ "homepage": "https://github.com/sebastianbergmann/lines-of-code",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
+ "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy",
+ "source": "https://github.com/sebastianbergmann/lines-of-code/tree/2.0.2"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-12-21T08:38:20+00:00"
+ },
+ {
+ "name": "sebastian/object-enumerator",
+ "version": "5.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/object-enumerator.git",
+ "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/202d0e344a580d7f7d04b3fafce6933e59dae906",
+ "reference": "202d0e344a580d7f7d04b3fafce6933e59dae906",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1",
+ "sebastian/object-reflector": "^3.0",
+ "sebastian/recursion-context": "^5.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "5.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Traverses array structures and object graphs to enumerate all referenced objects",
+ "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/object-enumerator/issues",
+ "source": "https://github.com/sebastianbergmann/object-enumerator/tree/5.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-02-03T07:08:32+00:00"
+ },
+ {
+ "name": "sebastian/object-reflector",
+ "version": "3.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/object-reflector.git",
+ "reference": "24ed13d98130f0e7122df55d06c5c4942a577957"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/24ed13d98130f0e7122df55d06c5c4942a577957",
+ "reference": "24ed13d98130f0e7122df55d06c5c4942a577957",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "3.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ }
+ ],
+ "description": "Allows reflection of object attributes, including inherited and non-public ones",
+ "homepage": "https://github.com/sebastianbergmann/object-reflector/",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/object-reflector/issues",
+ "source": "https://github.com/sebastianbergmann/object-reflector/tree/3.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-02-03T07:06:18+00:00"
+ },
+ {
+ "name": "sebastian/recursion-context",
+ "version": "5.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/recursion-context.git",
+ "reference": "05909fb5bc7df4c52992396d0116aed689f93712"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/05909fb5bc7df4c52992396d0116aed689f93712",
+ "reference": "05909fb5bc7df4c52992396d0116aed689f93712",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "5.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de"
+ },
+ {
+ "name": "Jeff Welch",
+ "email": "whatthejeff@gmail.com"
+ },
+ {
+ "name": "Adam Harvey",
+ "email": "aharvey@php.net"
+ }
+ ],
+ "description": "Provides functionality to recursively process PHP variables",
+ "homepage": "https://github.com/sebastianbergmann/recursion-context",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/recursion-context/issues",
+ "source": "https://github.com/sebastianbergmann/recursion-context/tree/5.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-02-03T07:05:40+00:00"
+ },
+ {
+ "name": "sebastian/type",
+ "version": "4.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/type.git",
+ "reference": "462699a16464c3944eefc02ebdd77882bd3925bf"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/462699a16464c3944eefc02ebdd77882bd3925bf",
+ "reference": "462699a16464c3944eefc02ebdd77882bd3925bf",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^10.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "4.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Collection of value objects that represent the types of the PHP type system",
+ "homepage": "https://github.com/sebastianbergmann/type",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/type/issues",
+ "source": "https://github.com/sebastianbergmann/type/tree/4.0.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-02-03T07:10:45+00:00"
+ },
+ {
+ "name": "sebastian/version",
+ "version": "4.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/version.git",
+ "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c51fa83a5d8f43f1402e3f32a005e6262244ef17",
+ "reference": "c51fa83a5d8f43f1402e3f32a005e6262244ef17",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-main": "4.0-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library that helps with managing the version number of Git-hosted PHP projects",
+ "homepage": "https://github.com/sebastianbergmann/version",
+ "support": {
+ "issues": "https://github.com/sebastianbergmann/version/issues",
+ "source": "https://github.com/sebastianbergmann/version/tree/4.0.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/sebastianbergmann",
+ "type": "github"
+ }
+ ],
+ "time": "2023-02-07T11:34:05+00:00"
+ },
+ {
+ "name": "swoole/ide-helper",
+ "version": "5.1.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/swoole/ide-helper.git",
+ "reference": "33ec7af9111b76d06a70dd31191cc74793551112"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/swoole/ide-helper/zipball/33ec7af9111b76d06a70dd31191cc74793551112",
+ "reference": "33ec7af9111b76d06a70dd31191cc74793551112",
+ "shasum": ""
+ },
+ "type": "library",
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "Team Swoole",
+ "email": "team@swoole.com"
+ }
+ ],
+ "description": "IDE help files for Swoole.",
+ "support": {
+ "issues": "https://github.com/swoole/ide-helper/issues",
+ "source": "https://github.com/swoole/ide-helper/tree/5.1.2"
+ },
+ "time": "2024-02-01T22:28:11+00:00"
+ },
+ {
+ "name": "theseer/tokenizer",
+ "version": "1.2.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/theseer/tokenizer.git",
+ "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b2ad5003ca10d4ee50a12da31de12a5774ba6b96",
+ "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-tokenizer": "*",
+ "ext-xmlwriter": "*",
+ "php": "^7.2 || ^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Arne Blankerts",
+ "email": "arne@blankerts.de",
+ "role": "Developer"
+ }
+ ],
+ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
+ "support": {
+ "issues": "https://github.com/theseer/tokenizer/issues",
+ "source": "https://github.com/theseer/tokenizer/tree/1.2.2"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/theseer",
+ "type": "github"
+ }
+ ],
+ "time": "2023-11-20T00:12:19+00:00"
+ },
+ {
+ "name": "utopia-php/fetch",
+ "version": "0.1.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/utopia-php/fetch.git",
+ "reference": "2fa214b9262acd1a3583515a364da4f35929d5c5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/utopia-php/fetch/zipball/2fa214b9262acd1a3583515a364da4f35929d5c5",
+ "reference": "2fa214b9262acd1a3583515a364da4f35929d5c5",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0"
+ },
+ "require-dev": {
+ "laravel/pint": "^1.5.0",
+ "phpstan/phpstan": "^1.10",
+ "phpunit/phpunit": "^9.5"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Utopia\\Fetch\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "A simple library that provides an interface for making HTTP Requests.",
+ "support": {
+ "issues": "https://github.com/utopia-php/fetch/issues",
+ "source": "https://github.com/utopia-php/fetch/tree/0.1.0"
+ },
+ "time": "2023-10-10T11:58:32+00:00"
+ }
+ ],
+ "aliases": [],
+ "minimum-stability": "stable",
+ "stability-flags": {
+ "utopia-php/database": 20
+ },
+ "prefer-stable": false,
+ "prefer-lowest": false,
+ "platform": {
+ "php": ">=8.1.0",
+ "ext-curl": "*",
+ "ext-json": "*",
+ "ext-swoole": "*"
+ },
+ "platform-dev": [],
+ "platform-overrides": {
+ "php": "8.1"
+ },
+ "plugin-api-version": "2.3.0"
+}
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..4ca9e60
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,44 @@
+version: '3.1'
+
+services:
+ data-api:
+ container_name: data-api
+ image: proxy-dev
+ build:
+ context: .
+ networks:
+ - database
+ volumes:
+ - ./app:/usr/local/app
+ ports:
+ - 8088:80
+ environment:
+ - UTOPIA_DATA_API_ENV
+ - UTOPIA_DATA_API_SECRET
+ - UTOPIA_DATA_API_SECRET_CONNECTION
+ - UTOPIA_DATA_API_LOGGING_PROVIDER
+ - UTOPIA_DATA_API_LOGGING_CONFIG
+
+ adminer:
+ image: adminer
+ container_name: appwrite-adminer
+ restart: always
+ ports:
+ - 9506:8080
+ networks:
+ - database
+
+ mariadb:
+ image: mariadb:10.7
+ container_name: utopia-mariadb
+ command: 'mysqld --max_connections=500'
+ networks:
+ - database
+ ports:
+ - 8100:3306
+ environment:
+ - MYSQL_ROOT_PASSWORD=password
+ - MARIADB_DATABASE=appwrite
+
+networks:
+ database:
\ No newline at end of file
diff --git a/phpstan.neon b/phpstan.neon
new file mode 100644
index 0000000..69758b9
--- /dev/null
+++ b/phpstan.neon
@@ -0,0 +1,3 @@
+parameters:
+ scanDirectories:
+ - vendor/swoole/ide-helper
\ No newline at end of file
diff --git a/phpunit.xml b/phpunit.xml
new file mode 100644
index 0000000..3b34652
--- /dev/null
+++ b/phpunit.xml
@@ -0,0 +1,17 @@
+
+
+
+
+ ./tests/
+
+
+
diff --git a/pint.json b/pint.json
new file mode 100644
index 0000000..70add70
--- /dev/null
+++ b/pint.json
@@ -0,0 +1,6 @@
+{
+ "preset": "psr12",
+ "exclude": [
+ "tests/resources"
+ ]
+}
\ No newline at end of file
diff --git a/psalm.xml b/psalm.xml
new file mode 100644
index 0000000..b5d5891
--- /dev/null
+++ b/psalm.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/ProxyTest.php b/tests/ProxyTest.php
new file mode 100644
index 0000000..95bbde1
--- /dev/null
+++ b/tests/ProxyTest.php
@@ -0,0 +1,275 @@
+testUniqueId = \uniqid();
+ $this->namespace .= '-' . $this->testUniqueId;
+ $this->database .= '-' . $this->testUniqueId;
+
+ $this->call('POST', '/queries', [ 'query' => 'create', 'params' => [ $this->database ] ]);
+ }
+
+ /**
+ * @param array $roles
+ */
+ private function call(string $method, string $endpoint, mixed $body = [], array $roles = [], bool $skipAuth = false): Response
+ {
+ if(isset($body['params'])) {
+ $body['params'] = \base64_encode(\serialize($body['params']));
+ }
+
+ $timeouts = \json_encode(['*' => $this->timeout]);
+ if($timeouts == false) {
+ $timeouts = '';
+ }
+
+ return Client::fetch($this->endpoint . $endpoint, [
+ 'x-utopia-secret' => $this->secret,
+ 'x-utopia-namespace' => $this->namespace,
+ 'x-utopia-database' => $this->database,
+ 'x-utopia-auth-roles' => \implode(',', $roles),
+ 'x-utopia-auth-status' => $skipAuth ? 'false' : 'true',
+ 'x-utopia-auth-status-default' => $this->defaultAuthStatus ? 'true' : 'false',
+ 'x-utopia-timeouts' => $timeouts,
+ 'content-type' => 'application/json'
+ ], $method, $body);
+ }
+
+ public function testSecret(): void
+ {
+ $correctSecret = $this->secret;
+ $this->secret = 'wrong-secret';
+ $response = $this->call('POST', '/queries', [ 'query' => 'ping' ]);
+ self::assertEquals(401, $response->getStatusCode());
+ $this->secret = $correctSecret;
+ }
+
+ public function testTimeout(): void
+ {
+ $correctTimeout = $this->timeout;
+
+ $this->timeout = 600000;
+ $response = $this->call('POST', '/queries', [ 'query' => 'ping' ]);
+ self::assertEquals(200, $response->getStatusCode());
+
+ $this->timeout = -1;
+ $response = $this->call('POST', '/queries', [ 'query' => 'ping' ]);
+ self::assertEquals(500, $response->getStatusCode());
+
+ $this->timeout = $correctTimeout;
+ }
+
+ public function testMock(): void
+ {
+ $correctEndpoint = $this->endpoint;
+ $this->endpoint = 'http://data-api/mock';
+ $response = $this->call('GET', '/error');
+ self::assertEquals(500, $response->getStatusCode());
+ $this->endpoint = $correctEndpoint;
+ }
+
+ public function testPing(): void
+ {
+ $response = $this->call('POST', '/queries', [ 'query' => 'ping' ]);
+ self::assertEquals(200, $response->getStatusCode());
+ $body = \json_decode($response->getBody(), true);
+ self::assertTrue($body['output']);
+ }
+
+ public function testDatabase(): void
+ {
+ $response = $this->call('POST', '/queries', [ 'query' => 'exists', 'params' => [ $this->database ] ]);
+ self::assertEquals(200, $response->getStatusCode());
+ $body = \json_decode($response->getBody(), true);
+ self::assertTrue($body['output']);
+
+ $response = $this->call('POST', '/queries', [ 'query' => 'exists', 'params' => [ $this->database . '-wrong' ] ]);
+ self::assertEquals(200, $response->getStatusCode());
+ $body = \json_decode($response->getBody(), true);
+ self::assertFalse($body['output']);
+
+ $response = $this->call('POST', '/queries', [ 'query' => 'create', 'params' => [ $this->database . '-wrong' ] ]);
+ self::assertEquals(200, $response->getStatusCode());
+ $body = \json_decode($response->getBody(), true);
+ self::assertTrue($body['output']);
+
+ $response = $this->call('POST', '/queries', [ 'query' => 'exists', 'params' => [ $this->database . '-wrong' ] ]);
+ self::assertEquals(200, $response->getStatusCode());
+ $body = \json_decode($response->getBody(), true);
+ self::assertTrue($body['output']);
+
+ $correctDatabase = $this->database;
+ $this->database .= '-wrong';
+ $response = $this->call('POST', '/queries', [ 'query' => 'createCollection', 'params' => [ 'default-db-test' ] ]);
+ $this->database = $correctDatabase;
+ self::assertEquals(200, $response->getStatusCode());
+ $body = \json_decode($response->getBody(), true);
+ self::assertTrue($body['output']);
+
+ $response = $this->call('POST', '/queries', [ 'query' => 'exists', 'params' => [ $this->database . '-wrong', 'default-db-test' ] ]);
+ self::assertEquals(200, $response->getStatusCode());
+ $body = \json_decode($response->getBody(), true);
+ self::assertTrue($body['output']);
+
+ $response = $this->call('POST', '/queries', [ 'query' => 'exists', 'params' => [ $this->database, 'default-db-test' ] ]);
+ self::assertEquals(200, $response->getStatusCode());
+ $body = \json_decode($response->getBody(), true);
+ self::assertFalse($body['output']);
+ }
+
+ public function testNamespace(): void
+ {
+ $correctNamespace = $this->namespace;
+ $this->namespace .= '-wrong';
+
+ $response = $this->call('POST', '/queries', [ 'query' => 'exists', 'params' => [ $this->database, 'cars' ] ]);
+ self::assertEquals(200, $response->getStatusCode());
+ $body = \json_decode($response->getBody(), true);
+ self::assertFalse($body['output']);
+
+ $response = $this->call('POST', '/queries', [ 'query' => 'createCollection', 'params' => [ 'cars' ] ]);
+ self::assertEquals(200, $response->getStatusCode());
+ $body = \json_decode($response->getBody(), true);
+ self::assertTrue($body['output']);
+
+ $response = $this->call('POST', '/queries', [ 'query' => 'exists', 'params' => [ $this->database, 'cars' ] ]);
+ self::assertEquals(200, $response->getStatusCode());
+ $body = \json_decode($response->getBody(), true);
+ self::assertTrue($body['output']);
+
+ $this->namespace = $correctNamespace;
+
+ $response = $this->call('POST', '/queries', [ 'query' => 'exists', 'params' => [ $this->database, 'cars' ] ]);
+ self::assertEquals(200, $response->getStatusCode());
+ $body = \json_decode($response->getBody(), true);
+ self::assertFalse($body['output']);
+ }
+
+ public function testAuth(): void
+ {
+ $response = $this->call('POST', '/queries', [ 'query' => 'createCollection', 'params' => [ 'passwords', [
+ new Document([
+ '$id' => 'password',
+ 'type' => Database::VAR_STRING,
+ 'size' => 512,
+ 'required' => true
+ ])
+ ] ] ]);
+ self::assertEquals(200, $response->getStatusCode());
+ $body = \json_decode($response->getBody(), true);
+ self::assertTrue($body['output']);
+
+ $response = $this->call('POST', '/queries', [ 'query' => 'exists', 'params' => [ $this->database, 'passwords' ] ]);
+ self::assertEquals(200, $response->getStatusCode());
+ $body = \json_decode($response->getBody(), true);
+ self::assertTrue($body['output']);
+
+ $docAny = ID::unique();
+ $response = $this->call('POST', '/queries', [ 'query' => 'createDocument', 'params' => [
+ 'passwords', new Document([
+ '$id' => $docAny,
+ '$permissions' => [
+ Permission::read(Role::any())
+ ],
+ 'password' => 'any-password'
+ ])
+ ] ]);
+ self::assertEquals(200, $response->getStatusCode());
+
+ $docsGuests = ID::unique();
+ $response = $this->call('POST', '/queries', [ 'query' => 'createDocument', 'params' => [
+ 'passwords', new Document([
+ '$id' => $docsGuests,
+ '$permissions' => [
+ Permission::read(Role::guests())
+ ],
+ 'password' => 'guests-password'
+ ])
+ ]]);
+ self::assertEquals(200, $response->getStatusCode());
+
+ $docUsers = ID::unique();
+ $response = $this->call('POST', '/queries', [ 'query' => 'createDocument', 'params' => [
+ 'passwords', new Document([
+ '$id' => $docUsers,
+ '$permissions' => [
+ Permission::read(Role::users())
+ ],
+ 'password' => 'users-password'
+ ])
+ ]]);
+ self::assertEquals(200, $response->getStatusCode());
+
+ $docTeam = ID::unique();
+ $response = $this->call('POST', '/queries', [ 'query' => 'createDocument', 'params' => [
+ 'passwords', new Document([
+ '$id' => $docTeam,
+ '$permissions' => [
+ Permission::read(Role::team('admin'))
+ ],
+ 'password' => 'team-password'
+ ])
+ ]]);
+ self::assertEquals(200, $response->getStatusCode());
+
+ $response = $this->call('POST', '/queries', [ 'query' => 'find', 'params' => ['passwords'] ], [ ], true);
+ self::assertEquals(200, $response->getStatusCode());
+ $body = \json_decode($response->getBody(), true);
+ self::assertCount(4, $body['output']);
+
+
+ $response = $this->call('POST', '/queries', [ 'query' => 'find', 'params' => ['passwords'] ], [], false);
+ self::assertEquals(200, $response->getStatusCode());
+ $body = \json_decode($response->getBody(), true);
+ self::assertCount(1, $body['output']);
+
+ $response = $this->call('POST', '/queries', [ 'query' => 'find', 'params' => ['passwords'] ], [
+ 'users'
+ ], false);
+ self::assertEquals(200, $response->getStatusCode());
+ $body = \json_decode($response->getBody(), true);
+ self::assertCount(2, $body['output']);
+
+ $response = $this->call('POST', '/queries', [ 'query' => 'find', 'params' => ['passwords'] ], [
+ 'guests'
+ ], false);
+ self::assertEquals(200, $response->getStatusCode());
+ $body = \json_decode($response->getBody(), true);
+ self::assertCount(2, $body['output']);
+
+ $response = $this->call('POST', '/queries', [ 'query' => 'find', 'params' => ['passwords'] ], [
+ 'users',
+ 'guests',
+ 'team:admin'
+ ], false);
+
+ self::assertEquals(200, $response->getStatusCode());
+ $body = \json_decode($response->getBody(), true);
+ self::assertCount(4, $body['output']);
+ }
+
+ // TODO: Tests for x-utopia-share-tables
+ // TODO: Tests for x-utopia-tenant
+}