diff --git a/app/cli.php b/app/cli.php index ce978c6d9d..f080217365 100644 --- a/app/cli.php +++ b/app/cli.php @@ -25,7 +25,7 @@ use Utopia\Queue\Publisher; use Utopia\Registry\Registry; use Utopia\System\System; -// overwriting runtimes to be architectur agnostic for CLI +// Overwriting runtimes to be architecture agnostic for CLI Config::setParam('runtimes', (new Runtimes('v4'))->getAll(supported: false)); // require controllers after overwriting runtimes @@ -43,8 +43,7 @@ CLI::setResource('cache', function ($pools) { $adapters[] = $pools ->get($value) ->pop() - ->getResource() - ; + ->getResource(); } return new Cache(new Sharding($adapters)); @@ -187,7 +186,7 @@ CLI::setResource('getLogsDB', function (Group $pools, Cache $cache) { $database ->setSharedTables(true) ->setNamespace('logsV1') - ->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS) + ->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_TASK) ->setMaxQueryValues(APP_DATABASE_QUERY_MAX_VALUES); // set tenant diff --git a/app/config/collections/platform.php b/app/config/collections/platform.php index 8a46bfd3ec..8725f4b4ce 100644 --- a/app/config/collections/platform.php +++ b/app/config/collections/platform.php @@ -1066,7 +1066,29 @@ return [ 'default' => null, 'array' => false, 'filters' => [], - ] + ], + [ + '$id' => ID::custom('owner'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 16, + 'signed' => true, + 'required' => false, + 'default' => '', // "Appwrite" or empty string + 'array' => false, + 'filters' => [], + ], + [ + '$id' => ID::custom('region'), + 'type' => Database::VAR_STRING, + 'format' => '', + 'size' => 16, + 'signed' => true, + 'required' => true, + 'default' => null, + 'array' => false, + 'filters' => [], + ], ], 'indexes' => [ [ @@ -1111,6 +1133,20 @@ return [ 'lengths' => [], 'orders' => [Database::ORDER_ASC], ], + [ + '$id' => ID::custom('_key_owner'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['owner'], + 'lengths' => [16], + 'orders' => [Database::ORDER_ASC], + ], + [ + '$id' => ID::custom('_key_region'), + 'type' => Database::INDEX_KEY, + 'attributes' => ['region'], + 'lengths' => [16], + 'orders' => [Database::ORDER_ASC], + ], ], ], diff --git a/app/config/collections/projects.php b/app/config/collections/projects.php index e77751c124..4461fcada6 100644 --- a/app/config/collections/projects.php +++ b/app/config/collections/projects.php @@ -1665,6 +1665,17 @@ return [ 'array' => false, 'filters' => ['encrypt'] ], + [ + '$id' => ID::custom('secret'), + 'type' => Database::VAR_BOOLEAN, + 'format' => '', + 'size' => 0, + 'signed' => true, + 'required' => false, + 'default' => false, + 'array' => false, + 'filters' => [], + ], [ '$id' => ID::custom('search'), 'type' => Database::VAR_STRING, diff --git a/app/config/console.php b/app/config/console.php index 5c15a7930f..e37c9b7836 100644 --- a/app/config/console.php +++ b/app/config/console.php @@ -27,6 +27,7 @@ $console = [ 'hostname' => 'localhost', ], // Current host is added on app init ], + 'region' => 'fra', 'legalName' => '', 'legalCountry' => '', 'legalState' => '', diff --git a/app/config/platforms.php b/app/config/platforms.php index 92e325bd44..86f0a756c9 100644 --- a/app/config/platforms.php +++ b/app/config/platforms.php @@ -11,7 +11,7 @@ return [ [ 'key' => 'web', 'name' => 'Web', - 'version' => '16.1.0', + 'version' => '17.0.1', 'url' => 'https://github.com/appwrite/sdk-for-web', 'package' => 'https://www.npmjs.com/package/appwrite', 'enabled' => true, @@ -59,7 +59,7 @@ return [ [ 'key' => 'flutter', 'name' => 'Flutter', - 'version' => '13.1.1', + 'version' => '15.0.0', 'url' => 'https://github.com/appwrite/sdk-for-flutter', 'package' => 'https://pub.dev/packages/appwrite', 'enabled' => true, @@ -77,7 +77,7 @@ return [ [ 'key' => 'apple', 'name' => 'Apple', - 'version' => '7.1.0', + 'version' => '9.0.0', 'url' => 'https://github.com/appwrite/sdk-for-apple', 'package' => 'https://github.com/appwrite/sdk-for-apple', 'enabled' => true, @@ -134,7 +134,7 @@ return [ [ 'key' => 'react-native', 'name' => 'React Native', - 'version' => '0.6.0', + 'version' => '0.7.1', 'url' => 'https://github.com/appwrite/sdk-for-react-native', 'package' => 'https://npmjs.com/package/react-native-appwrite', 'enabled' => true, @@ -217,7 +217,7 @@ return [ [ 'key' => 'cli', 'name' => 'Command Line', - 'version' => '6.2.0', + 'version' => '6.2.2', 'url' => 'https://github.com/appwrite/sdk-for-cli', 'package' => 'https://www.npmjs.com/package/appwrite-cli', 'enabled' => true, @@ -245,7 +245,7 @@ return [ [ 'key' => 'nodejs', 'name' => 'Node.js', - 'version' => '14.2.0', + 'version' => '15.0.1', 'url' => 'https://github.com/appwrite/sdk-for-node', 'package' => 'https://www.npmjs.com/package/node-appwrite', 'enabled' => true, @@ -299,7 +299,7 @@ return [ [ 'key' => 'python', 'name' => 'Python', - 'version' => '6.2.0', + 'version' => '9.0.2', 'url' => 'https://github.com/appwrite/sdk-for-python', 'package' => 'https://pypi.org/project/appwrite/', 'enabled' => true, @@ -371,7 +371,7 @@ return [ [ 'key' => 'dart', 'name' => 'Dart', - 'version' => '12.2.0', + 'version' => '14.0.0', 'url' => 'https://github.com/appwrite/sdk-for-dart', 'package' => 'https://pub.dev/packages/dart_appwrite', 'enabled' => true, @@ -411,7 +411,7 @@ return [ [ 'key' => 'swift', 'name' => 'Swift', - 'version' => '6.2.0', + 'version' => '8.0.0', 'url' => 'https://github.com/appwrite/sdk-for-swift', 'package' => 'https://github.com/appwrite/sdk-for-swift', 'enabled' => true, diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php index 583468f6c1..064dd52b9d 100644 --- a/app/controllers/api/functions.php +++ b/app/controllers/api/functions.php @@ -387,6 +387,8 @@ App::post('/v1/functions') 'resourceInternalId' => $function->getInternalId(), 'status' => 'verified', 'certificateId' => '', + 'owner' => 'Appwrite', + 'region' => $project->getAttribute('region') ])) ); @@ -2503,10 +2505,11 @@ App::post('/v1/functions/:functionId/variables') ->param('functionId', '', new UID(), 'Function unique ID.', false) ->param('key', null, new Text(Database::LENGTH_KEY), 'Variable key. Max length: ' . Database::LENGTH_KEY . ' chars.', false) ->param('value', null, new Text(8192, 0), 'Variable value. Max length: 8192 chars.', false) + ->param('secret', false, new Boolean(), 'Is secret? Secret variables can only be updated or deleted, they cannot be read.', true) ->inject('response') ->inject('dbForProject') ->inject('dbForPlatform') - ->action(function (string $functionId, string $key, string $value, Response $response, Database $dbForProject, Database $dbForPlatform) { + ->action(function (string $functionId, string $key, string $value, bool $secret, Response $response, Database $dbForProject, Database $dbForPlatform) { $function = $dbForProject->getDocument('functions', $functionId); if ($function->isEmpty()) { @@ -2527,6 +2530,7 @@ App::post('/v1/functions/:functionId/variables') 'resourceType' => 'function', 'key' => $key, 'value' => $value, + 'secret' => $secret, 'search' => implode(' ', [$variableId, $function->getId(), $key, 'function']), ]); diff --git a/app/controllers/api/project.php b/app/controllers/api/project.php index b267e8e51e..a3c1933d8c 100644 --- a/app/controllers/api/project.php +++ b/app/controllers/api/project.php @@ -17,6 +17,7 @@ use Utopia\Database\Query; use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Datetime as DateTimeValidator; use Utopia\Database\Validator\UID; +use Utopia\Validator\Boolean; use Utopia\Validator\Text; use Utopia\Validator\WhiteList; @@ -399,11 +400,12 @@ App::post('/v1/project/variables') )) ->param('key', null, new Text(Database::LENGTH_KEY), 'Variable key. Max length: ' . Database::LENGTH_KEY . ' chars.', false) ->param('value', null, new Text(8192, 0), 'Variable value. Max length: 8192 chars.', false) + ->param('secret', false, new Boolean(), 'Is secret? Secret variables can only be updated or deleted, they cannot be read.', true) ->inject('project') ->inject('response') ->inject('dbForProject') ->inject('dbForPlatform') - ->action(function (string $key, string $value, Document $project, Response $response, Database $dbForProject, Database $dbForPlatform) { + ->action(function (string $key, string $value, bool $secret, Document $project, Response $response, Database $dbForProject, Database $dbForPlatform) { $variableId = ID::unique(); $variable = new Document([ @@ -418,6 +420,7 @@ App::post('/v1/project/variables') 'resourceType' => 'project', 'key' => $key, 'value' => $value, + 'secret' => $secret, 'search' => implode(' ', [$variableId, $key, 'project']), ]); diff --git a/app/controllers/api/proxy.php b/app/controllers/api/proxy.php index 2567c23be6..393caad93d 100644 --- a/app/controllers/api/proxy.php +++ b/app/controllers/api/proxy.php @@ -130,6 +130,8 @@ App::post('/v1/proxy/rules') 'resourceId' => $resourceId, 'resourceInternalId' => $resourceInternalId, 'certificateId' => '', + 'owner' => '', + 'region' => $project->getAttribute('region') ]); $status = 'created'; diff --git a/app/controllers/general.php b/app/controllers/general.php index d93766a5e7..a374aa3c39 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -582,6 +582,12 @@ App::init() ]); } + $owner = ''; + $functionsDomain = System::getEnv('_APP_DOMAIN_FUNCTIONS', ''); + if (!empty($functionsDomain) && \str_ends_with($domain->get(), $functionsDomain)) { + $owner = 'Appwrite'; + } + if ($domainDocument->isEmpty()) { $domainDocument = new Document([ // TODO: @christyjacob remove once we migrate the rules in 1.7.x @@ -589,8 +595,10 @@ App::init() 'domain' => $domain->get(), 'resourceType' => 'api', 'status' => 'verifying', - 'projectId' => 'console', - 'projectInternalId' => 'console' + 'projectId' => $console->getId(), + 'projectInternalId' => $console->getInternalId(), + 'owner' => $owner, + 'region' => $console->getAttribute('region') ]); $domainDocument = $dbForPlatform->createDocument('rules', $domainDocument); diff --git a/app/init.php b/app/init.php index 9a499412db..6eb2baafd8 100644 --- a/app/init.php +++ b/app/init.php @@ -134,7 +134,9 @@ const APP_DATABASE_ATTRIBUTE_URL = 'url'; const APP_DATABASE_ATTRIBUTE_INT_RANGE = 'intRange'; const APP_DATABASE_ATTRIBUTE_FLOAT_RANGE = 'floatRange'; const APP_DATABASE_ATTRIBUTE_STRING_MAX_LENGTH = 1_073_741_824; // 2^32 bits / 4 bits per char -const APP_DATABASE_TIMEOUT_MILLISECONDS = 15_000; +const APP_DATABASE_TIMEOUT_MILLISECONDS_API = 15 * 1000; // 15 seconds +const APP_DATABASE_TIMEOUT_MILLISECONDS_WORKER = 300 * 1000; // 5 minutes +const APP_DATABASE_TIMEOUT_MILLISECONDS_TASK = 300 * 1000; // 5 minutes const APP_DATABASE_QUERY_MAX_VALUES = 500; const APP_STORAGE_UPLOADS = '/storage/uploads'; const APP_STORAGE_FUNCTIONS = '/storage/functions'; @@ -1434,7 +1436,7 @@ App::setResource('dbForProject', function (Group $pools, Database $dbForPlatform $database ->setMetadata('host', \gethostname()) ->setMetadata('project', $project->getId()) - ->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS) + ->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_API) ->setMaxQueryValues(APP_DATABASE_QUERY_MAX_VALUES); $sharedTables = \explode(',', System::getEnv('_APP_DATABASE_SHARED_TABLES', '')); @@ -1466,7 +1468,7 @@ App::setResource('dbForPlatform', function (Group $pools, Cache $cache) { ->setNamespace('_console') ->setMetadata('host', \gethostname()) ->setMetadata('project', 'console') - ->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS) + ->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_API) ->setMaxQueryValues(APP_DATABASE_QUERY_MAX_VALUES); return $database; @@ -1491,7 +1493,7 @@ App::setResource('getProjectDB', function (Group $pools, Database $dbForPlatform $database ->setMetadata('host', \gethostname()) ->setMetadata('project', $project->getId()) - ->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS) + ->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_API) ->setMaxQueryValues(APP_DATABASE_QUERY_MAX_VALUES); $sharedTables = \explode(',', System::getEnv('_APP_DATABASE_SHARED_TABLES', '')); @@ -1549,7 +1551,7 @@ App::setResource('getLogsDB', function (Group $pools, Cache $cache) { $database ->setSharedTables(true) ->setNamespace('logsV1') - ->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS) + ->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_API) ->setMaxQueryValues(APP_DATABASE_QUERY_MAX_VALUES); // set tenant diff --git a/app/worker.php b/app/worker.php index f3e0541c9a..eeefe80000 100644 --- a/app/worker.php +++ b/app/worker.php @@ -112,6 +112,8 @@ Server::setResource('dbForProject', function (Cache $cache, Registry $register, ->setNamespace('_' . $project->getInternalId()); } + $database->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_WORKER); + return $database; }, ['cache', 'register', 'message', 'project', 'dbForPlatform']); @@ -173,6 +175,8 @@ Server::setResource('getProjectDB', function (Group $pools, Database $dbForPlatf ->setNamespace('_' . $project->getInternalId()); } + $database->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_WORKER); + return $database; }; }, ['pools', 'dbForPlatform', 'cache']); @@ -198,7 +202,7 @@ Server::setResource('getLogsDB', function (Group $pools, Cache $cache) { $database ->setSharedTables(true) ->setNamespace('logsV1') - ->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS) + ->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_WORKER) ->setMaxQueryValues(APP_DATABASE_QUERY_MAX_VALUES); // set tenant diff --git a/composer.json b/composer.json index c9b057b061..53c2a6d482 100644 --- a/composer.json +++ b/composer.json @@ -45,13 +45,13 @@ "ext-sockets": "*", "appwrite/php-runtimes": "0.16.*", "appwrite/php-clamav": "2.0.*", - "utopia-php/abuse": "0.51.*", + "utopia-php/abuse": "0.52.*", "utopia-php/analytics": "0.10.*", - "utopia-php/audit": "0.54.0", + "utopia-php/audit": "0.55.*", "utopia-php/cache": "0.12.*", "utopia-php/cli": "0.15.*", "utopia-php/config": "0.2.*", - "utopia-php/database": "0.60.*", + "utopia-php/database": "0.61.*", "utopia-php/domains": "0.5.*", "utopia-php/dsn": "0.2.1", "utopia-php/framework": "0.33.*", @@ -62,10 +62,10 @@ "utopia-php/messaging": "0.16.*", "utopia-php/migration": "0.6.*", "utopia-php/orchestration": "0.9.*", - "utopia-php/platform": "0.7.3", + "utopia-php/platform": "0.7.*", "utopia-php/pools": "0.5.*", "utopia-php/preloader": "0.2.*", - "utopia-php/queue": "0.8.*", + "utopia-php/queue": "0.9.*", "utopia-php/registry": "0.5.*", "utopia-php/storage": "0.18.*", "utopia-php/swoole": "0.8.*", diff --git a/composer.lock b/composer.lock index e89d6b53b5..23937694f8 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "58ad2e1375ec47d944b96864d4aae63f", + "content-hash": "44c6436ced36b0b026139edba252052e", "packages": [ { "name": "adhocore/jwt", @@ -709,16 +709,16 @@ }, { "name": "google/protobuf", - "version": "v4.30.0", + "version": "v4.30.1", "source": { "type": "git", "url": "https://github.com/protocolbuffers/protobuf-php.git", - "reference": "e1d66682f6836aa87820400f0aa07d9eb566feb6" + "reference": "f29ba8a30dfd940efb3a8a75dc44446539101f24" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/e1d66682f6836aa87820400f0aa07d9eb566feb6", - "reference": "e1d66682f6836aa87820400f0aa07d9eb566feb6", + "url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/f29ba8a30dfd940efb3a8a75dc44446539101f24", + "reference": "f29ba8a30dfd940efb3a8a75dc44446539101f24", "shasum": "" }, "require": { @@ -747,9 +747,9 @@ "proto" ], "support": { - "source": "https://github.com/protocolbuffers/protobuf-php/tree/v4.30.0" + "source": "https://github.com/protocolbuffers/protobuf-php/tree/v4.30.1" }, - "time": "2025-03-04T22:54:49+00:00" + "time": "2025-03-13T21:08:17+00:00" }, { "name": "jean85/pretty-package-versions", @@ -3364,16 +3364,16 @@ }, { "name": "utopia-php/abuse", - "version": "0.51.0", + "version": "0.52.0", "source": { "type": "git", "url": "https://github.com/utopia-php/abuse.git", - "reference": "661687b03277f1d202a0e8cf9da6e58c97da2b5e" + "reference": "a0d6421e7e5baa3ac02755496dca9fdeaa814b93" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/abuse/zipball/661687b03277f1d202a0e8cf9da6e58c97da2b5e", - "reference": "661687b03277f1d202a0e8cf9da6e58c97da2b5e", + "url": "https://api.github.com/repos/utopia-php/abuse/zipball/a0d6421e7e5baa3ac02755496dca9fdeaa814b93", + "reference": "a0d6421e7e5baa3ac02755496dca9fdeaa814b93", "shasum": "" }, "require": { @@ -3381,7 +3381,7 @@ "ext-pdo": "*", "ext-redis": "*", "php": ">=8.0", - "utopia-php/database": "0.60.*" + "utopia-php/database": "0.*.*" }, "require-dev": { "laravel/pint": "1.*", @@ -3409,9 +3409,9 @@ ], "support": { "issues": "https://github.com/utopia-php/abuse/issues", - "source": "https://github.com/utopia-php/abuse/tree/0.51.0" + "source": "https://github.com/utopia-php/abuse/tree/0.52.0" }, - "time": "2025-02-17T11:10:18+00:00" + "time": "2025-03-06T03:48:29+00:00" }, { "name": "utopia-php/analytics", @@ -3461,21 +3461,21 @@ }, { "name": "utopia-php/audit", - "version": "0.54.0", + "version": "0.55.0", "source": { "type": "git", "url": "https://github.com/utopia-php/audit.git", - "reference": "1b0cb8ac6bfbd7703e3f9a753c6ba59ff1c39975" + "reference": "9f8cfe5fa5d5011b8dbf93b710236dfa91dc5518" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/audit/zipball/1b0cb8ac6bfbd7703e3f9a753c6ba59ff1c39975", - "reference": "1b0cb8ac6bfbd7703e3f9a753c6ba59ff1c39975", + "url": "https://api.github.com/repos/utopia-php/audit/zipball/9f8cfe5fa5d5011b8dbf93b710236dfa91dc5518", + "reference": "9f8cfe5fa5d5011b8dbf93b710236dfa91dc5518", "shasum": "" }, "require": { "php": ">=8.0", - "utopia-php/database": "0.60.*" + "utopia-php/database": "0.*.*" }, "require-dev": { "laravel/pint": "1.*", @@ -3502,9 +3502,9 @@ ], "support": { "issues": "https://github.com/utopia-php/audit/issues", - "source": "https://github.com/utopia-php/audit/tree/0.54.0" + "source": "https://github.com/utopia-php/audit/tree/0.55.0" }, - "time": "2025-02-25T07:21:07+00:00" + "time": "2025-03-06T03:47:47+00:00" }, { "name": "utopia-php/cache", @@ -3705,16 +3705,16 @@ }, { "name": "utopia-php/database", - "version": "0.60.6", + "version": "0.61.1", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "f3c9aa964b39c6205069f038a26e709a15541406" + "reference": "2e0165bd14a570ec151f400ed381108e81d15b94" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/f3c9aa964b39c6205069f038a26e709a15541406", - "reference": "f3c9aa964b39c6205069f038a26e709a15541406", + "url": "https://api.github.com/repos/utopia-php/database/zipball/2e0165bd14a570ec151f400ed381108e81d15b94", + "reference": "2e0165bd14a570ec151f400ed381108e81d15b94", "shasum": "" }, "require": { @@ -3755,9 +3755,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.60.6" + "source": "https://github.com/utopia-php/database/tree/0.61.1" }, - "time": "2025-03-05T01:23:14+00:00" + "time": "2025-03-14T01:19:38+00:00" }, { "name": "utopia-php/domains", @@ -4159,16 +4159,16 @@ }, { "name": "utopia-php/migration", - "version": "0.6.20", + "version": "0.6.22", "source": { "type": "git", "url": "https://github.com/utopia-php/migration.git", - "reference": "8c9ba52196f50aaef4aa1903f0d8fe0c8d9997ba" + "reference": "a0269746bd318ff0993f5aa008675b971689d5b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/migration/zipball/8c9ba52196f50aaef4aa1903f0d8fe0c8d9997ba", - "reference": "8c9ba52196f50aaef4aa1903f0d8fe0c8d9997ba", + "url": "https://api.github.com/repos/utopia-php/migration/zipball/a0269746bd318ff0993f5aa008675b971689d5b5", + "reference": "a0269746bd318ff0993f5aa008675b971689d5b5", "shasum": "" }, "require": { @@ -4176,7 +4176,7 @@ "ext-curl": "*", "ext-openssl": "*", "php": ">=8.1", - "utopia-php/database": "0.60.*", + "utopia-php/database": "0.61.*", "utopia-php/dsn": "0.2.*", "utopia-php/framework": "0.33.*", "utopia-php/storage": "0.18.*" @@ -4209,9 +4209,9 @@ ], "support": { "issues": "https://github.com/utopia-php/migration/issues", - "source": "https://github.com/utopia-php/migration/tree/0.6.20" + "source": "https://github.com/utopia-php/migration/tree/0.6.22" }, - "time": "2025-02-17T11:02:15+00:00" + "time": "2025-03-13T07:35:55+00:00" }, { "name": "utopia-php/mongo", @@ -4325,16 +4325,16 @@ }, { "name": "utopia-php/platform", - "version": "0.7.3", + "version": "0.7.4", "source": { "type": "git", "url": "https://github.com/utopia-php/platform.git", - "reference": "463c2d817c893d7dbb678c2eac7a8291f2710e25" + "reference": "a5b93d8177702ec458c3af9137663133c012b71b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/platform/zipball/463c2d817c893d7dbb678c2eac7a8291f2710e25", - "reference": "463c2d817c893d7dbb678c2eac7a8291f2710e25", + "url": "https://api.github.com/repos/utopia-php/platform/zipball/a5b93d8177702ec458c3af9137663133c012b71b", + "reference": "a5b93d8177702ec458c3af9137663133c012b71b", "shasum": "" }, "require": { @@ -4343,7 +4343,7 @@ "php": ">=8.0", "utopia-php/cli": "0.15.*", "utopia-php/framework": "0.33.*", - "utopia-php/queue": "0.8.*" + "utopia-php/queue": "0.9.*" }, "require-dev": { "laravel/pint": "1.2.*", @@ -4369,9 +4369,9 @@ ], "support": { "issues": "https://github.com/utopia-php/platform/issues", - "source": "https://github.com/utopia-php/platform/tree/0.7.3" + "source": "https://github.com/utopia-php/platform/tree/0.7.4" }, - "time": "2025-02-04T15:09:00+00:00" + "time": "2025-03-13T13:00:12+00:00" }, { "name": "utopia-php/pools", @@ -4479,16 +4479,16 @@ }, { "name": "utopia-php/queue", - "version": "0.8.6", + "version": "0.9.0", "source": { "type": "git", "url": "https://github.com/utopia-php/queue.git", - "reference": "b713b997285c29d120bbcbe3d6e93762d850f87c" + "reference": "077075f1d57afa430f76c35ed3bf4616e0eee8e7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/queue/zipball/b713b997285c29d120bbcbe3d6e93762d850f87c", - "reference": "b713b997285c29d120bbcbe3d6e93762d850f87c", + "url": "https://api.github.com/repos/utopia-php/queue/zipball/077075f1d57afa430f76c35ed3bf4616e0eee8e7", + "reference": "077075f1d57afa430f76c35ed3bf4616e0eee8e7", "shasum": "" }, "require": { @@ -4538,9 +4538,9 @@ ], "support": { "issues": "https://github.com/utopia-php/queue/issues", - "source": "https://github.com/utopia-php/queue/tree/0.8.6" + "source": "https://github.com/utopia-php/queue/tree/0.9.0" }, - "time": "2025-02-10T03:35:00+00:00" + "time": "2025-03-13T12:22:41+00:00" }, { "name": "utopia-php/registry", @@ -4810,16 +4810,16 @@ }, { "name": "utopia-php/vcs", - "version": "0.9.3", + "version": "0.9.4", "source": { "type": "git", "url": "https://github.com/utopia-php/vcs.git", - "reference": "865a00c67e81a20938b883f9aa802303790dd3b5" + "reference": "1a8d280b176acc99ea8d9e7364b8767cbb206b4a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/vcs/zipball/865a00c67e81a20938b883f9aa802303790dd3b5", - "reference": "865a00c67e81a20938b883f9aa802303790dd3b5", + "url": "https://api.github.com/repos/utopia-php/vcs/zipball/1a8d280b176acc99ea8d9e7364b8767cbb206b4a", + "reference": "1a8d280b176acc99ea8d9e7364b8767cbb206b4a", "shasum": "" }, "require": { @@ -4854,9 +4854,9 @@ ], "support": { "issues": "https://github.com/utopia-php/vcs/issues", - "source": "https://github.com/utopia-php/vcs/tree/0.9.3" + "source": "https://github.com/utopia-php/vcs/tree/0.9.4" }, - "time": "2025-02-26T16:33:35+00:00" + "time": "2025-03-13T10:09:45+00:00" }, { "name": "utopia-php/websocket", @@ -5043,16 +5043,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "0.40.2", + "version": "0.40.7", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "56f09482d9e2f223911277ab887f197402708049" + "reference": "9e89b0bc4d8e6c81817d27096629f34a149fa873" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/56f09482d9e2f223911277ab887f197402708049", - "reference": "56f09482d9e2f223911277ab887f197402708049", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/9e89b0bc4d8e6c81817d27096629f34a149fa873", + "reference": "9e89b0bc4d8e6c81817d27096629f34a149fa873", "shasum": "" }, "require": { @@ -5088,9 +5088,9 @@ "description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms", "support": { "issues": "https://github.com/appwrite/sdk-generator/issues", - "source": "https://github.com/appwrite/sdk-generator/tree/0.40.2" + "source": "https://github.com/appwrite/sdk-generator/tree/0.40.7" }, - "time": "2025-03-06T16:31:03+00:00" + "time": "2025-03-12T08:43:55+00:00" }, { "name": "doctrine/annotations", @@ -5317,16 +5317,16 @@ }, { "name": "laravel/pint", - "version": "v1.21.0", + "version": "v1.21.1", "source": { "type": "git", "url": "https://github.com/laravel/pint.git", - "reference": "531fa0871fbde719c51b12afa3a443b8f4e4b425" + "reference": "c44bffbb2334e90fba560933c45948fa4a3f3e86" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/pint/zipball/531fa0871fbde719c51b12afa3a443b8f4e4b425", - "reference": "531fa0871fbde719c51b12afa3a443b8f4e4b425", + "url": "https://api.github.com/repos/laravel/pint/zipball/c44bffbb2334e90fba560933c45948fa4a3f3e86", + "reference": "c44bffbb2334e90fba560933c45948fa4a3f3e86", "shasum": "" }, "require": { @@ -5337,9 +5337,9 @@ "php": "^8.2.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^3.68.5", - "illuminate/view": "^11.42.0", - "larastan/larastan": "^3.0.4", + "friendsofphp/php-cs-fixer": "^3.70.2", + "illuminate/view": "^11.44.1", + "larastan/larastan": "^3.1.0", "laravel-zero/framework": "^11.36.1", "mockery/mockery": "^1.6.12", "nunomaduro/termwind": "^2.3", @@ -5379,7 +5379,7 @@ "issues": "https://github.com/laravel/pint/issues", "source": "https://github.com/laravel/pint" }, - "time": "2025-02-18T03:18:57+00:00" + "time": "2025-03-11T03:22:21+00:00" }, { "name": "matthiasmullie/minify", @@ -5794,16 +5794,16 @@ }, { "name": "phpbench/phpbench", - "version": "1.4.0", + "version": "1.4.1", "source": { "type": "git", "url": "https://github.com/phpbench/phpbench.git", - "reference": "4248817222514421cba466bfa7adc7d8932345d4" + "reference": "78cd98a9aa34e0f8f80ca01972a8b88d2c30194b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpbench/phpbench/zipball/4248817222514421cba466bfa7adc7d8932345d4", - "reference": "4248817222514421cba466bfa7adc7d8932345d4", + "url": "https://api.github.com/repos/phpbench/phpbench/zipball/78cd98a9aa34e0f8f80ca01972a8b88d2c30194b", + "reference": "78cd98a9aa34e0f8f80ca01972a8b88d2c30194b", "shasum": "" }, "require": { @@ -5880,7 +5880,7 @@ ], "support": { "issues": "https://github.com/phpbench/phpbench/issues", - "source": "https://github.com/phpbench/phpbench/tree/1.4.0" + "source": "https://github.com/phpbench/phpbench/tree/1.4.1" }, "funding": [ { @@ -5888,7 +5888,7 @@ "type": "github" } ], - "time": "2025-01-26T19:54:45+00:00" + "time": "2025-03-12T08:01:40+00:00" }, { "name": "phpunit/php-code-coverage", diff --git a/docs/sdks/dart/CHANGELOG.md b/docs/sdks/dart/CHANGELOG.md index a46f1dcf0f..c41413b9ec 100644 --- a/docs/sdks/dart/CHANGELOG.md +++ b/docs/sdks/dart/CHANGELOG.md @@ -1,3 +1,15 @@ +## 14.0.0 + +* Breaking changes: + * Changed the typing of `AppwriteException`'s response parameter from a `dynamic` object to an optional string (`?String`). + +## 13.0.0 + +* Fixed realtime pong response. +* Fixed issues with `chunkedUpload` method. +* Fixed type mismatch bug where `List` was incorrectly causing runtime type errors. +* Updated return type of `updateMfaChallenge()` from raw data to properly typed `models.Session` object. + ## 12.0.0 * Support for Appwrite 1.6 diff --git a/docs/sdks/flutter/CHANGELOG.md b/docs/sdks/flutter/CHANGELOG.md index abb8967f84..110b6d08c3 100644 --- a/docs/sdks/flutter/CHANGELOG.md +++ b/docs/sdks/flutter/CHANGELOG.md @@ -1,3 +1,13 @@ +## 15.0.0 + +* Breaking changes: + * Changed the typing of `AppwriteException`'s response parameter from a `dynamic` object to an optional string (`?String`). + +## 14.0.0 + +* Fixed realtime pong response. +* Fixed issues with `chunkedUpload` method. + ## 13.0.0 * Fixed realtime reconnection issues diff --git a/src/Appwrite/Platform/Workers/Deletes.php b/src/Appwrite/Platform/Workers/Deletes.php index 52dc3d73c9..dd219765c2 100644 --- a/src/Appwrite/Platform/Workers/Deletes.php +++ b/src/Appwrite/Platform/Workers/Deletes.php @@ -387,6 +387,7 @@ class Deletes extends Action $query = [ Query::lessThan('accessedAt', $datetime), + Query::orderDesc('accessedAt') ]; $this->deleteByGroup( @@ -420,6 +421,7 @@ class Deletes extends Action // Delete Usage stats from projectDB $this->deleteByGroup('stats', [ Query::lessThan('time', $hourlyUsageRetentionDatetime), + Query::orderDesc('time'), Query::equal('period', ['1h']), ], $dbForProject); @@ -430,6 +432,7 @@ class Deletes extends Action // Delete Usage stats from logsDB $this->deleteByGroup('stats', [ Query::lessThan('time', $hourlyUsageRetentionDatetime), + Query::orderDesc('time'), Query::equal('period', ['1h']), ], $dbForLogs); } @@ -688,9 +691,11 @@ class Deletes extends Action private function deleteExecutionLogs(Document $project, callable $getProjectDB, string $datetime): void { $dbForProject = $getProjectDB($project); + // Delete Executions $this->deleteByGroup('executions', [ - Query::lessThan('$createdAt', $datetime) + Query::lessThan('$createdAt', $datetime), + Query::orderDesc('$createdAt'), ], $dbForProject); } @@ -708,7 +713,8 @@ class Deletes extends Action // Delete Sessions $this->deleteByGroup('sessions', [ - Query::lessThan('$createdAt', $expired) + Query::lessThan('$createdAt', $expired), + Query::orderDesc('$createdAt'), ], $dbForProject); } @@ -722,7 +728,8 @@ class Deletes extends Action { // Delete Dead Realtime Logs $this->deleteByGroup('realtime', [ - Query::lessThan('timestamp', $datetime) + Query::lessThan('timestamp', $datetime), + Query::orderDesc('timestamp'), ], $dbForPlatform); } diff --git a/src/Appwrite/Utopia/Response/Model/Variable.php b/src/Appwrite/Utopia/Response/Model/Variable.php index 88fcd14ca1..22f76e44d4 100644 --- a/src/Appwrite/Utopia/Response/Model/Variable.php +++ b/src/Appwrite/Utopia/Response/Model/Variable.php @@ -4,6 +4,7 @@ namespace Appwrite\Utopia\Response\Model; use Appwrite\Utopia\Response; use Appwrite\Utopia\Response\Model; +use Utopia\Database\Document; class Variable extends Model { @@ -41,6 +42,12 @@ class Variable extends Model 'default' => '', 'example' => 'myPa$$word1', ]) + ->addRule('secret', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Variable secret flag. Secret variables can only be updated or deleted, but never read.', + 'default' => false, + 'example' => false, + ]) ->addRule('resourceType', [ 'type' => self::TYPE_STRING, 'description' => 'Service to which the variable belongs. Possible values are "project", "function"', @@ -56,6 +63,21 @@ class Variable extends Model ; } + /** + * Filter + * + * @param Document $document + * @return Document + */ + public function filter(Document $document): Document + { + $secret = $document->getAttribute('secret'); + if ($secret === true) { + $document->setAttribute('value', null); + } + return $document; + } + /** * Get Name * diff --git a/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php b/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php index 3a02cbcba2..0708d40aab 100644 --- a/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php +++ b/tests/e2e/Services/Functions/FunctionsConsoleClientTest.php @@ -118,6 +118,22 @@ class FunctionsConsoleClientTest extends Scope $variableId = $variable['body']['$id']; + // test for secret variable + $variable = $this->createVariable( + $data['functionId'], + [ + 'key' => 'APP_TEST_1', + 'value' => 'TESTINGVALUE_1', + 'secret' => true + ] + ); + + $this->assertEquals(201, $variable['headers']['status-code']); + $this->assertEquals('APP_TEST_1', $variable['body']['key']); + $this->assertEmpty($variable['body']['value']); + + $secretVariableId = $variable['body']['$id']; + /** * Test for FAILURE */ @@ -157,7 +173,8 @@ class FunctionsConsoleClientTest extends Scope return array_merge( $data, [ - 'variableId' => $variableId + 'variableId' => $variableId, + 'secretVariableId' => $secretVariableId ] ); } @@ -177,10 +194,12 @@ class FunctionsConsoleClientTest extends Scope ], $this->getHeaders())); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(1, sizeof($response['body']['variables'])); - $this->assertEquals(1, $response['body']['total']); + $this->assertEquals(2, sizeof($response['body']['variables'])); + $this->assertEquals(2, $response['body']['total']); $this->assertEquals("APP_TEST", $response['body']['variables'][0]['key']); $this->assertEquals("TESTINGVALUE", $response['body']['variables'][0]['value']); + $this->assertEquals("APP_TEST_1", $response['body']['variables'][1]['key']); + $this->assertEmpty($response['body']['variables'][1]['value']); /** * Test for FAILURE @@ -207,6 +226,15 @@ class FunctionsConsoleClientTest extends Scope $this->assertEquals("APP_TEST", $response['body']['key']); $this->assertEquals("TESTINGVALUE", $response['body']['value']); + $response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/variables/' . $data['secretVariableId'], array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals("APP_TEST_1", $response['body']['key']); + $this->assertEmpty($response['body']['value']); + /** * Test for FAILURE */ @@ -251,6 +279,27 @@ class FunctionsConsoleClientTest extends Scope $this->assertEquals("APP_TEST_UPDATE", $variable['body']['key']); $this->assertEquals("TESTINGVALUEUPDATED", $variable['body']['value']); + $response = $this->client->call(Client::METHOD_PUT, '/functions/' . $data['functionId'] . '/variables/' . $data['secretVariableId'], array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'key' => 'APP_TEST_UPDATE_1', + 'value' => 'TESTINGVALUEUPDATED_1' + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals("APP_TEST_UPDATE_1", $response['body']['key']); + $this->assertEmpty($response['body']['value']); + + $variable = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/variables/' . $data['secretVariableId'], array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(200, $variable['headers']['status-code']); + $this->assertEquals("APP_TEST_UPDATE_1", $variable['body']['key']); + $this->assertEmpty($variable['body']['value']); + $response = $this->client->call(Client::METHOD_PUT, '/functions/' . $data['functionId'] . '/variables/' . $data['variableId'], array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -332,6 +381,13 @@ class FunctionsConsoleClientTest extends Scope $this->assertEquals(204, $response['headers']['status-code']); + $response = $this->client->call(Client::METHOD_DELETE, '/functions/' . $data['functionId'] . '/variables/' . $data['secretVariableId'], array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(204, $response['headers']['status-code']); + $response = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/variables', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], diff --git a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php index a6498b8a4e..34c1142619 100644 --- a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php +++ b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php @@ -3929,6 +3929,23 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(201, $variable['headers']['status-code']); $variableId = $variable['body']['$id']; + // test for secret variable + $variable = $this->client->call(Client::METHOD_POST, '/project/variables', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $data['projectId'], + 'x-appwrite-mode' => 'admin', + ], $this->getHeaders()), [ + 'key' => 'APP_TEST_1', + 'value' => 'TESTINGVALUE_1', + 'secret' => true + ]); + + $this->assertEquals(201, $variable['headers']['status-code']); + $this->assertEquals('APP_TEST_1', $variable['body']['key']); + $this->assertEmpty($variable['body']['value']); + + $secretVariableId = $variable['body']['$id']; + /** * Test for FAILURE */ @@ -3972,6 +3989,7 @@ class ProjectsConsoleClientTest extends Scope $data, [ 'variableId' => $variableId, + 'secretVariableId' => $secretVariableId ] ); } @@ -3992,10 +4010,12 @@ class ProjectsConsoleClientTest extends Scope ], $this->getHeaders())); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertCount(1, $response['body']['variables']); - $this->assertEquals(1, $response['body']['total']); + $this->assertCount(2, $response['body']['variables']); + $this->assertEquals(2, $response['body']['total']); $this->assertEquals("APP_TEST", $response['body']['variables'][0]['key']); $this->assertEquals("TESTINGVALUE", $response['body']['variables'][0]['value']); + $this->assertEquals("APP_TEST_1", $response['body']['variables'][1]['key']); + $this->assertEmpty($response['body']['variables'][1]['value']); return $data; } @@ -4018,6 +4038,16 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals("APP_TEST", $response['body']['key']); $this->assertEquals("TESTINGVALUE", $response['body']['value']); + $response = $this->client->call(Client::METHOD_GET, '/project/variables/' . $data['secretVariableId'], array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $data['projectId'], + 'x-appwrite-mode' => 'admin', + ], $this->getHeaders())); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals("APP_TEST_1", $response['body']['key']); + $this->assertEmpty($response['body']['value']); + /** * Test for FAILURE */ @@ -4065,6 +4095,29 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals("APP_TEST_UPDATE", $variable['body']['key']); $this->assertEquals("TESTINGVALUEUPDATED", $variable['body']['value']); + $response = $this->client->call(Client::METHOD_PUT, '/project/variables/' . $data['secretVariableId'], array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $data['projectId'], + 'x-appwrite-mode' => 'admin', + ], $this->getHeaders()), [ + 'key' => 'APP_TEST_UPDATE_1', + 'value' => 'TESTINGVALUEUPDATED_1' + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals("APP_TEST_UPDATE_1", $response['body']['key']); + $this->assertEmpty($response['body']['value']); + + $variable = $this->client->call(Client::METHOD_GET, '/project/variables/' . $data['secretVariableId'], array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $data['projectId'], + 'x-appwrite-mode' => 'admin', + ], $this->getHeaders())); + + $this->assertEquals(200, $variable['headers']['status-code']); + $this->assertEquals("APP_TEST_UPDATE_1", $variable['body']['key']); + $this->assertEmpty($variable['body']['value']); + $response = $this->client->call(Client::METHOD_GET, '/project/variables', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $data['projectId'], @@ -4072,8 +4125,9 @@ class ProjectsConsoleClientTest extends Scope ], $this->getHeaders())); $this->assertEquals(200, $response['headers']['status-code']); - $this->assertCount(1, $response['body']['variables']); + $this->assertCount(2, $response['body']['variables']); $this->assertEquals("APP_TEST_UPDATE", $response['body']['variables'][0]['key']); + $this->assertEquals("APP_TEST_UPDATE_1", $response['body']['variables'][1]['key']); /** * Test for FAILURE @@ -4152,6 +4206,14 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals(204, $response['headers']['status-code']); + $this->assertEquals(204, $response['headers']['status-code']); + + $response = $this->client->call(Client::METHOD_DELETE, '/project/variables/' . $data['secretVariableId'], array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $data['projectId'], + 'x-appwrite-mode' => 'admin', + ], $this->getHeaders())); + $response = $this->client->call(Client::METHOD_GET, '/project/variables', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $data['projectId'],