From 6684364b981beb78b765d18e133d304c35d3dbcb Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Thu, 8 May 2025 07:25:29 +0000 Subject: [PATCH 01/19] chore: improve route not found error message --- app/config/errors.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/config/errors.php b/app/config/errors.php index 4b2e58b08b..eb5a6cbbbb 100644 --- a/app/config/errors.php +++ b/app/config/errors.php @@ -81,7 +81,7 @@ return [ ], Exception::GENERAL_ROUTE_NOT_FOUND => [ 'name' => Exception::GENERAL_ROUTE_NOT_FOUND, - 'description' => 'The requested route was not found. Please refer to the API docs and try again.', + 'description' => 'Route not found. Please ensure the endpoint is configured correctly and that the API route is valid for this SDK version. Refer to the API docs for more details.', 'code' => 404, ], Exception::GENERAL_CURSOR_NOT_FOUND => [ From b0e95171f803c5444c4255670dda6a73d213c9f1 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Sat, 10 May 2025 14:29:11 +0000 Subject: [PATCH 02/19] chore: update react native and generate sdk --- app/config/platforms.php | 2 +- app/config/specs/open-api3-1.6.x-client.json | 20 ---------- app/config/specs/open-api3-1.6.x-console.json | 20 ---------- app/config/specs/open-api3-1.6.x-server.json | 20 ---------- app/config/specs/open-api3-latest-client.json | 20 ---------- .../specs/open-api3-latest-console.json | 20 ---------- app/config/specs/open-api3-latest-server.json | 20 ---------- app/config/specs/swagger2-1.6.x-client.json | 20 ---------- app/config/specs/swagger2-1.6.x-console.json | 20 ---------- app/config/specs/swagger2-1.6.x-server.json | 20 ---------- app/config/specs/swagger2-latest-client.json | 20 ---------- app/config/specs/swagger2-latest-console.json | 20 ---------- app/config/specs/swagger2-latest-server.json | 20 ---------- app/controllers/api/databases.php | 38 +++++++++---------- composer.lock | 12 +++--- docs/sdks/react-native/CHANGELOG.md | 7 +++- 16 files changed, 32 insertions(+), 267 deletions(-) diff --git a/app/config/platforms.php b/app/config/platforms.php index 98afd1a9b4..aff6aaf7c0 100644 --- a/app/config/platforms.php +++ b/app/config/platforms.php @@ -134,7 +134,7 @@ return [ [ 'key' => 'react-native', 'name' => 'React Native', - 'version' => '0.7.3', + 'version' => '0.7.4', 'url' => 'https://github.com/appwrite/sdk-for-react-native', 'package' => 'https://npmjs.com/package/react-native-appwrite', 'enabled' => true, diff --git a/app/config/specs/open-api3-1.6.x-client.json b/app/config/specs/open-api3-1.6.x-client.json index 3cb424e53b..e84c511f78 100644 --- a/app/config/specs/open-api3-1.6.x-client.json +++ b/app/config/specs/open-api3-1.6.x-client.json @@ -4485,26 +4485,6 @@ } ], "description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." - }, - { - "name": "createDocuments", - "parameters": [ - "databaseId", - "collectionId", - "documents" - ], - "required": [ - "databaseId", - "collectionId", - "documents" - ], - "responses": [ - { - "code": 201, - "model": "#\/components\/schemas\/documentList" - } - ], - "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.\n" } ], "auth": { diff --git a/app/config/specs/open-api3-1.6.x-console.json b/app/config/specs/open-api3-1.6.x-console.json index ede32a8dbc..16ac0ee040 100644 --- a/app/config/specs/open-api3-1.6.x-console.json +++ b/app/config/specs/open-api3-1.6.x-console.json @@ -7976,26 +7976,6 @@ } ], "description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." - }, - { - "name": "createDocuments", - "parameters": [ - "databaseId", - "collectionId", - "documents" - ], - "required": [ - "databaseId", - "collectionId", - "documents" - ], - "responses": [ - { - "code": 201, - "model": "#\/components\/schemas\/documentList" - } - ], - "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.\n" } ], "auth": { diff --git a/app/config/specs/open-api3-1.6.x-server.json b/app/config/specs/open-api3-1.6.x-server.json index 584caa2956..e3d2255c8d 100644 --- a/app/config/specs/open-api3-1.6.x-server.json +++ b/app/config/specs/open-api3-1.6.x-server.json @@ -7525,26 +7525,6 @@ } ], "description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." - }, - { - "name": "createDocuments", - "parameters": [ - "databaseId", - "collectionId", - "documents" - ], - "required": [ - "databaseId", - "collectionId", - "documents" - ], - "responses": [ - { - "code": 201, - "model": "#\/components\/schemas\/documentList" - } - ], - "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.\n" } ], "auth": { diff --git a/app/config/specs/open-api3-latest-client.json b/app/config/specs/open-api3-latest-client.json index 3cb424e53b..e84c511f78 100644 --- a/app/config/specs/open-api3-latest-client.json +++ b/app/config/specs/open-api3-latest-client.json @@ -4485,26 +4485,6 @@ } ], "description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." - }, - { - "name": "createDocuments", - "parameters": [ - "databaseId", - "collectionId", - "documents" - ], - "required": [ - "databaseId", - "collectionId", - "documents" - ], - "responses": [ - { - "code": 201, - "model": "#\/components\/schemas\/documentList" - } - ], - "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.\n" } ], "auth": { diff --git a/app/config/specs/open-api3-latest-console.json b/app/config/specs/open-api3-latest-console.json index ede32a8dbc..16ac0ee040 100644 --- a/app/config/specs/open-api3-latest-console.json +++ b/app/config/specs/open-api3-latest-console.json @@ -7976,26 +7976,6 @@ } ], "description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." - }, - { - "name": "createDocuments", - "parameters": [ - "databaseId", - "collectionId", - "documents" - ], - "required": [ - "databaseId", - "collectionId", - "documents" - ], - "responses": [ - { - "code": 201, - "model": "#\/components\/schemas\/documentList" - } - ], - "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.\n" } ], "auth": { diff --git a/app/config/specs/open-api3-latest-server.json b/app/config/specs/open-api3-latest-server.json index 584caa2956..e3d2255c8d 100644 --- a/app/config/specs/open-api3-latest-server.json +++ b/app/config/specs/open-api3-latest-server.json @@ -7525,26 +7525,6 @@ } ], "description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." - }, - { - "name": "createDocuments", - "parameters": [ - "databaseId", - "collectionId", - "documents" - ], - "required": [ - "databaseId", - "collectionId", - "documents" - ], - "responses": [ - { - "code": 201, - "model": "#\/components\/schemas\/documentList" - } - ], - "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.\n" } ], "auth": { diff --git a/app/config/specs/swagger2-1.6.x-client.json b/app/config/specs/swagger2-1.6.x-client.json index e3b2663cab..6033eb40ea 100644 --- a/app/config/specs/swagger2-1.6.x-client.json +++ b/app/config/specs/swagger2-1.6.x-client.json @@ -4625,26 +4625,6 @@ } ], "description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." - }, - { - "name": "createDocuments", - "parameters": [ - "databaseId", - "collectionId", - "documents" - ], - "required": [ - "databaseId", - "collectionId", - "documents" - ], - "responses": [ - { - "code": 201, - "model": "#\/definitions\/documentList" - } - ], - "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.\n" } ], "auth": { diff --git a/app/config/specs/swagger2-1.6.x-console.json b/app/config/specs/swagger2-1.6.x-console.json index 808ce06f85..5b61ba75d6 100644 --- a/app/config/specs/swagger2-1.6.x-console.json +++ b/app/config/specs/swagger2-1.6.x-console.json @@ -8107,26 +8107,6 @@ } ], "description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." - }, - { - "name": "createDocuments", - "parameters": [ - "databaseId", - "collectionId", - "documents" - ], - "required": [ - "databaseId", - "collectionId", - "documents" - ], - "responses": [ - { - "code": 201, - "model": "#\/definitions\/documentList" - } - ], - "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.\n" } ], "auth": { diff --git a/app/config/specs/swagger2-1.6.x-server.json b/app/config/specs/swagger2-1.6.x-server.json index f3da5cf4f8..697f28c1e4 100644 --- a/app/config/specs/swagger2-1.6.x-server.json +++ b/app/config/specs/swagger2-1.6.x-server.json @@ -7644,26 +7644,6 @@ } ], "description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." - }, - { - "name": "createDocuments", - "parameters": [ - "databaseId", - "collectionId", - "documents" - ], - "required": [ - "databaseId", - "collectionId", - "documents" - ], - "responses": [ - { - "code": 201, - "model": "#\/definitions\/documentList" - } - ], - "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.\n" } ], "auth": { diff --git a/app/config/specs/swagger2-latest-client.json b/app/config/specs/swagger2-latest-client.json index e3b2663cab..6033eb40ea 100644 --- a/app/config/specs/swagger2-latest-client.json +++ b/app/config/specs/swagger2-latest-client.json @@ -4625,26 +4625,6 @@ } ], "description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." - }, - { - "name": "createDocuments", - "parameters": [ - "databaseId", - "collectionId", - "documents" - ], - "required": [ - "databaseId", - "collectionId", - "documents" - ], - "responses": [ - { - "code": 201, - "model": "#\/definitions\/documentList" - } - ], - "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.\n" } ], "auth": { diff --git a/app/config/specs/swagger2-latest-console.json b/app/config/specs/swagger2-latest-console.json index 808ce06f85..5b61ba75d6 100644 --- a/app/config/specs/swagger2-latest-console.json +++ b/app/config/specs/swagger2-latest-console.json @@ -8107,26 +8107,6 @@ } ], "description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." - }, - { - "name": "createDocuments", - "parameters": [ - "databaseId", - "collectionId", - "documents" - ], - "required": [ - "databaseId", - "collectionId", - "documents" - ], - "responses": [ - { - "code": 201, - "model": "#\/definitions\/documentList" - } - ], - "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.\n" } ], "auth": { diff --git a/app/config/specs/swagger2-latest-server.json b/app/config/specs/swagger2-latest-server.json index f3da5cf4f8..697f28c1e4 100644 --- a/app/config/specs/swagger2-latest-server.json +++ b/app/config/specs/swagger2-latest-server.json @@ -7644,26 +7644,6 @@ } ], "description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." - }, - { - "name": "createDocuments", - "parameters": [ - "databaseId", - "collectionId", - "documents" - ], - "required": [ - "databaseId", - "collectionId", - "documents" - ], - "responses": [ - { - "code": 201, - "model": "#\/definitions\/documentList" - } - ], - "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console.\n" } ], "auth": { diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index 0bdb42ec1c..edc9d55ddb 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -3204,25 +3204,25 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/documents') new Parameter('permissions', optional: true), ] ), - new Method( - namespace: 'databases', - group: 'documents', - name: 'createDocuments', - description: '/docs/references/databases/create-documents.md', - auth: [AuthType::KEY], - responses: [ - new SDKResponse( - code: Response::STATUS_CODE_CREATED, - model: Response::MODEL_DOCUMENT_LIST, - ) - ], - contentType: ContentType::JSON, - parameters: [ - new Parameter('databaseId', optional: false), - new Parameter('collectionId', optional: false), - new Parameter('documents', optional: false), - ] - ) + // new Method( + // namespace: 'databases', + // group: 'documents', + // name: 'createDocuments', + // description: '/docs/references/databases/create-documents.md', + // auth: [AuthType::KEY], + // responses: [ + // new SDKResponse( + // code: Response::STATUS_CODE_CREATED, + // model: Response::MODEL_DOCUMENT_LIST, + // ) + // ], + // contentType: ContentType::JSON, + // parameters: [ + // new Parameter('databaseId', optional: false), + // new Parameter('collectionId', optional: false), + // new Parameter('documents', optional: false), + // ] + // ) ] ) ->param('databaseId', '', new UID(), 'Database ID.') diff --git a/composer.lock b/composer.lock index b56b7b387d..cf15b7657e 100644 --- a/composer.lock +++ b/composer.lock @@ -4769,16 +4769,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "0.40.15", + "version": "0.40.16", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "65c708b931b29b3e01c5cc7504a734ce2cc3dc95" + "reference": "f1f506da74033f0cb5a11e3dffcfd1ee8daf237d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/65c708b931b29b3e01c5cc7504a734ce2cc3dc95", - "reference": "65c708b931b29b3e01c5cc7504a734ce2cc3dc95", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/f1f506da74033f0cb5a11e3dffcfd1ee8daf237d", + "reference": "f1f506da74033f0cb5a11e3dffcfd1ee8daf237d", "shasum": "" }, "require": { @@ -4814,9 +4814,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.15" + "source": "https://github.com/appwrite/sdk-generator/tree/0.40.16" }, - "time": "2025-04-25T08:50:44+00:00" + "time": "2025-05-09T12:06:09+00:00" }, { "name": "doctrine/annotations", diff --git a/docs/sdks/react-native/CHANGELOG.md b/docs/sdks/react-native/CHANGELOG.md index 21fbe5456c..f720e11ac6 100644 --- a/docs/sdks/react-native/CHANGELOG.md +++ b/docs/sdks/react-native/CHANGELOG.md @@ -1 +1,6 @@ -# Change log \ No newline at end of file +# Change log + +## 0.7.4 + +* Upgrade dependencies to resolve PlatformConstants error with Expo 53 +* Update doc examples to use new multi-region endpoint \ No newline at end of file From a970512e3cf92adabb33b7bcd23dfbae470a5a71 Mon Sep 17 00:00:00 2001 From: arnab Date: Tue, 13 May 2025 10:35:04 +0530 Subject: [PATCH 03/19] added length param, response model, e2e test --- app/controllers/api/databases.php | 13 ++++---- src/Appwrite/Utopia/Response/Model/Index.php | 7 ++++ .../e2e/Services/Databases/DatabasesBase.php | 33 ++++++++++++++++++- 3 files changed, 45 insertions(+), 8 deletions(-) diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index 0bdb42ec1c..1b7108329f 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -2812,12 +2812,13 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') ->param('key', null, new Key(), 'Index Key.') ->param('type', null, new WhiteList([Database::INDEX_KEY, Database::INDEX_FULLTEXT, Database::INDEX_UNIQUE]), 'Index type.') ->param('attributes', null, new ArrayList(new Key(true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of attributes to index. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' attributes are allowed, each 32 characters long.') + ->param('lengths', [], new ArrayList(new Integer(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Length of index. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE, optional:true) ->param('orders', [], new ArrayList(new WhiteList(['ASC', 'DESC'], false, Database::VAR_STRING), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of index orders. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' orders are allowed.', true) ->inject('response') ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->action(function (string $databaseId, string $collectionId, string $key, string $type, array $attributes, array $orders, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) { + ->action(function (string $databaseId, string $collectionId, string $key, string $type, array $attributes, array $lengths, array $orders, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) { $db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); @@ -2877,9 +2878,6 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') 'size' => 0 ]; - // lengths hidden by default - $lengths = []; - foreach ($attributes as $i => $attribute) { // find attribute metadata in collection document $attributeIndex = \array_search($attribute, array_column($oldAttributes, 'key')); @@ -2901,10 +2899,11 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') throw new Exception(Exception::ATTRIBUTE_NOT_AVAILABLE, 'Attribute not available: ' . $oldAttributes[$attributeIndex]['key']); } - $lengths[$i] = null; - + $lengths[$i] = array_key_exists($i, $lengths) ? $lengths[$i] : null; if ($attributeArray === true) { - $lengths[$i] = Database::ARRAY_INDEX_LENGTH; + if ($lengths[$i] === null) { + $lengths[$i] = Database::ARRAY_INDEX_LENGTH; + } $orders[$i] = null; } } diff --git a/src/Appwrite/Utopia/Response/Model/Index.php b/src/Appwrite/Utopia/Response/Model/Index.php index 2d795ad439..fcd978b5be 100644 --- a/src/Appwrite/Utopia/Response/Model/Index.php +++ b/src/Appwrite/Utopia/Response/Model/Index.php @@ -41,6 +41,13 @@ class Index extends Model 'example' => [], 'array' => true, ]) + ->addRule('lengths', [ + 'type' => self::TYPE_INTEGER, + 'description' => 'Index attributes length.', + 'default' => [], + 'example' => [], + 'array' => true, + ]) ->addRule('orders', [ 'type' => self::TYPE_STRING, 'description' => 'Index orders.', diff --git a/tests/e2e/Services/Databases/DatabasesBase.php b/tests/e2e/Services/Databases/DatabasesBase.php index 1f19c514d1..3ae88cca57 100644 --- a/tests/e2e/Services/Databases/DatabasesBase.php +++ b/tests/e2e/Services/Databases/DatabasesBase.php @@ -1422,9 +1422,40 @@ trait DatabasesBase return $data; } + /** - * @depends testCreateIndexes + * @depends testCreateAttributes */ + public function testGetIndexByKeyWithLengths(array $data): void + { + $databaseId = $data['databaseId']; + $collectionId = $data['moviesId']; + + $create = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$collectionId}/indexes", [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ], [ + 'key' => 'lengthTestIndex', + 'type' => 'key', + 'attributes' => ['title','description'], + 'lengths' => [128,200] + ]); + + $this->assertEquals(202, $create['headers']['status-code']); + + $index = $this->client->call(Client::METHOD_GET, "/databases/{$databaseId}/collections/{$collectionId}/indexes/lengthTestIndex", [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]); + $this->assertEquals(200, $index['headers']['status-code']); + $this->assertEquals('lengthTestIndex', $index['body']['key']); + $this->assertEquals([128,200], $index['body']['lengths']); + } + /** + * @depends testCreateIndexes + */ public function testListIndexes(array $data): void { $databaseId = $data['databaseId']; From cd806e80d76780d8fcf611cb2fbe3340772f25aa Mon Sep 17 00:00:00 2001 From: arnab Date: Tue, 13 May 2025 15:39:13 +0530 Subject: [PATCH 04/19] updated tests and validations --- app/controllers/api/databases.php | 19 +++++- .../e2e/Services/Databases/DatabasesBase.php | 68 +++++++++++++++++-- 2 files changed, 80 insertions(+), 7 deletions(-) diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index 1b7108329f..3f25f65faf 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -2812,13 +2812,13 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') ->param('key', null, new Key(), 'Index Key.') ->param('type', null, new WhiteList([Database::INDEX_KEY, Database::INDEX_FULLTEXT, Database::INDEX_UNIQUE]), 'Index type.') ->param('attributes', null, new ArrayList(new Key(true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of attributes to index. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' attributes are allowed, each 32 characters long.') - ->param('lengths', [], new ArrayList(new Integer(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Length of index. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE, optional:true) ->param('orders', [], new ArrayList(new WhiteList(['ASC', 'DESC'], false, Database::VAR_STRING), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of index orders. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' orders are allowed.', true) + ->param('lengths', [], new ArrayList(new Nullable(new Integer()), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Length of index. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE, optional:true) ->inject('response') ->inject('dbForProject') ->inject('queueForDatabase') ->inject('queueForEvents') - ->action(function (string $databaseId, string $collectionId, string $key, string $type, array $attributes, array $lengths, array $orders, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) { + ->action(function (string $databaseId, string $collectionId, string $key, string $type, array $attributes, array $orders, array $lengths, Response $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) { $db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId)); @@ -2832,6 +2832,10 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') throw new Exception(Exception::COLLECTION_NOT_FOUND); } + if (count($lengths) > count($attributes)) { + throw new Exception(Exception::INDEX_LENGTHS_INVALID); + } + $count = $dbForProject->count('indexes', [ Query::equal('collectionInternalId', [$collection->getInternalId()]), Query::equal('databaseInternalId', [$db->getInternalId()]) @@ -2878,6 +2882,11 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') 'size' => 0 ]; + $totalIndexLength = array_sum($lengths); + if ($totalIndexLength > 768) { + throw new Exception(Exception::INDEX_LIMIT_EXCEEDED, 'Index total length crossing 768'); + } + foreach ($attributes as $i => $attribute) { // find attribute metadata in collection document $attributeIndex = \array_search($attribute, array_column($oldAttributes, 'key')); @@ -2899,7 +2908,11 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') throw new Exception(Exception::ATTRIBUTE_NOT_AVAILABLE, 'Attribute not available: ' . $oldAttributes[$attributeIndex]['key']); } - $lengths[$i] = array_key_exists($i, $lengths) ? $lengths[$i] : null; + if ($lengths[$i] < 0) { + throw new Exception(Exception::INDEX_INVALID, 'Negative index provided for ' . $oldAttributes[$attributeIndex]['key']); + } + + $lengths[$i] ??= null; if ($attributeArray === true) { if ($lengths[$i] === null) { $lengths[$i] = Database::ARRAY_INDEX_LENGTH; diff --git a/tests/e2e/Services/Databases/DatabasesBase.php b/tests/e2e/Services/Databases/DatabasesBase.php index 3ae88cca57..025394362e 100644 --- a/tests/e2e/Services/Databases/DatabasesBase.php +++ b/tests/e2e/Services/Databases/DatabasesBase.php @@ -1424,13 +1424,14 @@ trait DatabasesBase /** - * @depends testCreateAttributes - */ + * @depends testCreateAttributes + */ public function testGetIndexByKeyWithLengths(array $data): void { $databaseId = $data['databaseId']; $collectionId = $data['moviesId']; + // Test case for valid lengths $create = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$collectionId}/indexes", [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -1441,9 +1442,9 @@ trait DatabasesBase 'attributes' => ['title','description'], 'lengths' => [128,200] ]); - $this->assertEquals(202, $create['headers']['status-code']); + // Fetch index and check correct lengths $index = $this->client->call(Client::METHOD_GET, "/databases/{$databaseId}/collections/{$collectionId}/indexes/lengthTestIndex", [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -1451,7 +1452,66 @@ trait DatabasesBase ]); $this->assertEquals(200, $index['headers']['status-code']); $this->assertEquals('lengthTestIndex', $index['body']['key']); - $this->assertEquals([128,200], $index['body']['lengths']); + $this->assertEquals([128, 200], $index['body']['lengths']); + + // Test case for lengths array overriding + $create = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$collectionId}/indexes", [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ], [ + 'key' => 'lengthOverrideTestIndex', + 'type' => 'key', + 'attributes' => ['title', 'description'], + 'lengths' => [null, 255] + ]); + $this->assertEquals(202, $create['headers']['status-code']); + $index = $this->client->call(Client::METHOD_GET, "/databases/{$databaseId}/collections/{$collectionId}/indexes/lengthOverrideTestIndex", [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]); + $this->assertEquals([null, 255], $index['body']['lengths']); + + // Test case for count of lengths greater than attributes (should throw 400) + $create = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$collectionId}/indexes", [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ], [ + 'key' => 'lengthCountExceededIndex', + 'type' => 'key', + 'attributes' => ['title'], + 'lengths' => [128, 128] + ]); + $this->assertEquals(400, $create['headers']['status-code']); + + // Test case for lengths exceeding total of 768 + $create = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$collectionId}/indexes", [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ], [ + 'key' => 'lengthTooLargeIndex', + 'type' => 'key', + 'attributes' => ['title','description','tagline','actors'], + 'lengths' => [256,256,256,20] + ]); + + $this->assertEquals(400, $create['headers']['status-code']); + + // Test case for negative length values + $create = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$collectionId}/indexes", [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ], [ + 'key' => 'negativeLengthIndex', + 'type' => 'key', + 'attributes' => ['title'], + 'lengths' => [-1] + ]); + $this->assertEquals(400, $create['headers']['status-code']); } /** * @depends testCreateIndexes From 40642b2aad0b76160a64aa362741bbf20acc3482 Mon Sep 17 00:00:00 2001 From: Fabian Gruber <1951610+basert@users.noreply.github.com> Date: Tue, 13 May 2025 13:03:09 +0200 Subject: [PATCH 05/19] fix(schedules): enqueue delay telemetry in wrong format (#9749) --- src/Appwrite/Platform/Tasks/ScheduleBase.php | 6 ++---- src/Appwrite/Platform/Tasks/ScheduleExecutions.php | 4 ++-- src/Appwrite/Platform/Tasks/ScheduleFunctions.php | 11 ++++++----- src/Appwrite/Platform/Tasks/ScheduleMessages.php | 4 ++-- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/Appwrite/Platform/Tasks/ScheduleBase.php b/src/Appwrite/Platform/Tasks/ScheduleBase.php index 093c2740ba..d9de41ea64 100644 --- a/src/Appwrite/Platform/Tasks/ScheduleBase.php +++ b/src/Appwrite/Platform/Tasks/ScheduleBase.php @@ -202,10 +202,8 @@ abstract class ScheduleBase extends Action Console::success("{$total} resources were loaded in " . $duration . " seconds"); } - protected function recordEnqueueDelay(string $expectedExecutionSchedule): void + protected function recordEnqueueDelay(\DateTime $expectedExecutionSchedule): void { - $now = strtotime('now'); - $scheduledAt = strtotime($expectedExecutionSchedule); - $this->enqueueDelayTelemetry->record($now - $scheduledAt, ['resourceType' => static::getSupportedResource()]); + $this->enqueueDelayTelemetry->record(time() - $expectedExecutionSchedule->getTimestamp(), ['resourceType' => static::getSupportedResource()]); } } diff --git a/src/Appwrite/Platform/Tasks/ScheduleExecutions.php b/src/Appwrite/Platform/Tasks/ScheduleExecutions.php index 79e983f0c3..89d1609a33 100644 --- a/src/Appwrite/Platform/Tasks/ScheduleExecutions.php +++ b/src/Appwrite/Platform/Tasks/ScheduleExecutions.php @@ -59,7 +59,7 @@ class ScheduleExecutions extends ScheduleBase $this->updateProjectAccess($schedule['project'], $dbForPlatform); - \go(function () use ($queueForFunctions, $schedule, $delay, $data) { + \go(function () use ($queueForFunctions, $schedule, $scheduledAt, $delay, $data) { Co::sleep($delay); $queueForFunctions->setType('schedule') @@ -75,7 +75,7 @@ class ScheduleExecutions extends ScheduleBase ->setUserId($data['userId'] ?? '') ->trigger(); - $this->recordEnqueueDelay($schedule['schedule']); + $this->recordEnqueueDelay($scheduledAt); }); $dbForPlatform->deleteDocument( diff --git a/src/Appwrite/Platform/Tasks/ScheduleFunctions.php b/src/Appwrite/Platform/Tasks/ScheduleFunctions.php index abcfe132e3..689ba831b8 100644 --- a/src/Appwrite/Platform/Tasks/ScheduleFunctions.php +++ b/src/Appwrite/Platform/Tasks/ScheduleFunctions.php @@ -66,17 +66,18 @@ class ScheduleFunctions extends ScheduleBase $delayedExecutions[$delay] = []; } - $delayedExecutions[$delay][] = $key; + $delayedExecutions[$delay][] = ['key' => $key, 'nextDate' => $nextDate]; } - foreach ($delayedExecutions as $delay => $scheduleKeys) { - \go(function () use ($delay, $scheduleKeys, $pools, $dbForPlatform) { + foreach ($delayedExecutions as $delay => $schedules) { + \go(function () use ($delay, $schedules, $pools, $dbForPlatform) { \sleep($delay); // in seconds $queue = $pools->get('publisher')->pop(); $connection = $queue->getResource(); - foreach ($scheduleKeys as $scheduleKey) { + foreach ($schedules as $delayConfig) { + $scheduleKey = $delayConfig['key']; // Ensure schedule was not deleted if (!\array_key_exists($scheduleKey, $this->schedules)) { return; @@ -96,7 +97,7 @@ class ScheduleFunctions extends ScheduleBase ->setProject($schedule['project']) ->trigger(); - $this->recordEnqueueDelay($schedule['schedule']); + $this->recordEnqueueDelay($delayConfig['nextDate']); } $queue->reclaim(); diff --git a/src/Appwrite/Platform/Tasks/ScheduleMessages.php b/src/Appwrite/Platform/Tasks/ScheduleMessages.php index 9b962c99ee..a15df6ed5b 100644 --- a/src/Appwrite/Platform/Tasks/ScheduleMessages.php +++ b/src/Appwrite/Platform/Tasks/ScheduleMessages.php @@ -40,7 +40,7 @@ class ScheduleMessages extends ScheduleBase continue; } - \go(function () use ($schedule, $pools, $dbForPlatform) { + \go(function () use ($schedule, $scheduledAt, $pools, $dbForPlatform) { $queue = $pools->get('publisher')->pop(); $connection = $queue->getResource(); $queueForMessaging = new Messaging($connection); @@ -59,7 +59,7 @@ class ScheduleMessages extends ScheduleBase ); $queue->reclaim(); - $this->recordEnqueueDelay($schedule['schedule']); + $this->recordEnqueueDelay($scheduledAt); unset($this->schedules[$schedule['$internalId']]); }); } From 4853e0803ce19b7f2bcdf7b27ebae8febf2c5460 Mon Sep 17 00:00:00 2001 From: Fabian Gruber <1951610+basert@users.noreply.github.com> Date: Tue, 13 May 2025 14:05:13 +0200 Subject: [PATCH 06/19] fix(schedules): better error handling (#9751) --- src/Appwrite/Platform/Tasks/ScheduleBase.php | 13 +++++++++---- src/Appwrite/Platform/Tasks/ScheduleFunctions.php | 8 +++++++- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/Appwrite/Platform/Tasks/ScheduleBase.php b/src/Appwrite/Platform/Tasks/ScheduleBase.php index d9de41ea64..afd7d9d22a 100644 --- a/src/Appwrite/Platform/Tasks/ScheduleBase.php +++ b/src/Appwrite/Platform/Tasks/ScheduleBase.php @@ -91,13 +91,18 @@ abstract class ScheduleBase extends Action }); while (true) { - $this->enqueueResources($pools, $dbForPlatform, $getProjectDB); - $this->scheduleTelemetryCount->record(count($this->schedules), ['resourceType' => static::getSupportedResource()]); - sleep(static::ENQUEUE_TIMER); + try { + go(fn () => $this->enqueueResources($pools, $dbForPlatform, $getProjectDB)); + $this->scheduleTelemetryCount->record(count($this->schedules), ['resourceType' => static::getSupportedResource()]); + sleep(static::ENQUEUE_TIMER); + } catch (\Throwable $th) { + Console::error('Failed to enqueue resources: ' . $th->getMessage()); + } + } } - private function collectSchedules(Group $pools, Database $dbForPlatform, callable $getProjectDB, ?string &$lastSyncUpdate): void + private function collectSchedules(Group $pools, Database $dbForPlatform, callable $getProjectDB, string &$lastSyncUpdate): void { // If we haven't synced yet, load all active schedules $initialLoad = $lastSyncUpdate === "0"; diff --git a/src/Appwrite/Platform/Tasks/ScheduleFunctions.php b/src/Appwrite/Platform/Tasks/ScheduleFunctions.php index 689ba831b8..6788748f3d 100644 --- a/src/Appwrite/Platform/Tasks/ScheduleFunctions.php +++ b/src/Appwrite/Platform/Tasks/ScheduleFunctions.php @@ -46,7 +46,13 @@ class ScheduleFunctions extends ScheduleBase $delayedExecutions = []; // Group executions with same delay to share one coroutine foreach ($this->schedules as $key => $schedule) { - $cron = new CronExpression($schedule['schedule']); + try { + $cron = new CronExpression($schedule['schedule']); + } catch (\InvalidArgumentException) { + // ignore invalid cron expressions + continue; + } + $nextDate = $cron->getNextRunDate(); $next = DateTime::format($nextDate); From 41d7114e97282169147fb767e9d77633173c6665 Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Tue, 13 May 2025 17:37:15 +0530 Subject: [PATCH 07/19] updated composer and index api --- app/controllers/api/databases.php | 13 --------- composer.json | 2 +- composer.lock | 44 +++++++++++++++---------------- 3 files changed, 23 insertions(+), 36 deletions(-) diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index 3f25f65faf..a56e0a05df 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -2832,10 +2832,6 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') throw new Exception(Exception::COLLECTION_NOT_FOUND); } - if (count($lengths) > count($attributes)) { - throw new Exception(Exception::INDEX_LENGTHS_INVALID); - } - $count = $dbForProject->count('indexes', [ Query::equal('collectionInternalId', [$collection->getInternalId()]), Query::equal('databaseInternalId', [$db->getInternalId()]) @@ -2882,11 +2878,6 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') 'size' => 0 ]; - $totalIndexLength = array_sum($lengths); - if ($totalIndexLength > 768) { - throw new Exception(Exception::INDEX_LIMIT_EXCEEDED, 'Index total length crossing 768'); - } - foreach ($attributes as $i => $attribute) { // find attribute metadata in collection document $attributeIndex = \array_search($attribute, array_column($oldAttributes, 'key')); @@ -2908,10 +2899,6 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') throw new Exception(Exception::ATTRIBUTE_NOT_AVAILABLE, 'Attribute not available: ' . $oldAttributes[$attributeIndex]['key']); } - if ($lengths[$i] < 0) { - throw new Exception(Exception::INDEX_INVALID, 'Negative index provided for ' . $oldAttributes[$attributeIndex]['key']); - } - $lengths[$i] ??= null; if ($attributeArray === true) { if ($lengths[$i] === null) { diff --git a/composer.json b/composer.json index 9e45f71c61..9b2cf7a1ab 100644 --- a/composer.json +++ b/composer.json @@ -51,7 +51,7 @@ "utopia-php/cache": "0.13.*", "utopia-php/cli": "0.15.*", "utopia-php/config": "0.2.*", - "utopia-php/database": "0.68.*", + "utopia-php/database": "0.69.*", "utopia-php/domains": "0.5.*", "utopia-php/dsn": "0.2.1", "utopia-php/framework": "0.33.*", diff --git a/composer.lock b/composer.lock index cf15b7657e..e6bcd919e2 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": "a5c4c6b723423bc6cb3a7344ab071b43", + "content-hash": "1eeb5a0f3560aefd8f71bd0955e30360", "packages": [ { "name": "adhocore/jwt", @@ -1109,16 +1109,16 @@ }, { "name": "open-telemetry/api", - "version": "1.2.3", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/opentelemetry-php/api.git", - "reference": "199d7ddda88f5f5619fa73463f1a5a7149ccd1f1" + "reference": "4e3bb38e069876fb73c2ce85c89583bf2b28cd86" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/opentelemetry-php/api/zipball/199d7ddda88f5f5619fa73463f1a5a7149ccd1f1", - "reference": "199d7ddda88f5f5619fa73463f1a5a7149ccd1f1", + "url": "https://api.github.com/repos/opentelemetry-php/api/zipball/4e3bb38e069876fb73c2ce85c89583bf2b28cd86", + "reference": "4e3bb38e069876fb73c2ce85c89583bf2b28cd86", "shasum": "" }, "require": { @@ -1175,7 +1175,7 @@ "issues": "https://github.com/open-telemetry/opentelemetry-php/issues", "source": "https://github.com/open-telemetry/opentelemetry-php" }, - "time": "2025-03-05T21:42:54+00:00" + "time": "2025-05-07T12:32:21+00:00" }, { "name": "open-telemetry/context", @@ -1238,16 +1238,16 @@ }, { "name": "open-telemetry/exporter-otlp", - "version": "1.2.1", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/opentelemetry-php/exporter-otlp.git", - "reference": "b7580440b7481a98da97aceabeb46e1b276c8747" + "reference": "19adf03d2b0f91f9e9b1c7f93db6c755c737cf6c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/opentelemetry-php/exporter-otlp/zipball/b7580440b7481a98da97aceabeb46e1b276c8747", - "reference": "b7580440b7481a98da97aceabeb46e1b276c8747", + "url": "https://api.github.com/repos/opentelemetry-php/exporter-otlp/zipball/19adf03d2b0f91f9e9b1c7f93db6c755c737cf6c", + "reference": "19adf03d2b0f91f9e9b1c7f93db6c755c737cf6c", "shasum": "" }, "require": { @@ -1298,7 +1298,7 @@ "issues": "https://github.com/open-telemetry/opentelemetry-php/issues", "source": "https://github.com/open-telemetry/opentelemetry-php" }, - "time": "2025-03-06T23:21:56+00:00" + "time": "2025-05-12T00:36:35+00:00" }, { "name": "open-telemetry/gen-otlp-protobuf", @@ -1365,16 +1365,16 @@ }, { "name": "open-telemetry/sdk", - "version": "1.3.0", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/opentelemetry-php/sdk.git", - "reference": "05d9ceb6773b5bddcf485af6d4a6f543bbeb980b" + "reference": "939d3a28395c249a763676458140dad44b3a8011" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/opentelemetry-php/sdk/zipball/05d9ceb6773b5bddcf485af6d4a6f543bbeb980b", - "reference": "05d9ceb6773b5bddcf485af6d4a6f543bbeb980b", + "url": "https://api.github.com/repos/opentelemetry-php/sdk/zipball/939d3a28395c249a763676458140dad44b3a8011", + "reference": "939d3a28395c249a763676458140dad44b3a8011", "shasum": "" }, "require": { @@ -1451,7 +1451,7 @@ "issues": "https://github.com/open-telemetry/opentelemetry-php/issues", "source": "https://github.com/open-telemetry/opentelemetry-php" }, - "time": "2025-05-01T23:20:43+00:00" + "time": "2025-05-07T12:32:21+00:00" }, { "name": "open-telemetry/sem-conv", @@ -3499,16 +3499,16 @@ }, { "name": "utopia-php/database", - "version": "0.68.1", + "version": "0.69.1", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "72b2e2c0b875028f7d9dd755f6d4524b693c6507" + "reference": "cc6538e05e25d930244ab938c966d32db0922e83" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/72b2e2c0b875028f7d9dd755f6d4524b693c6507", - "reference": "72b2e2c0b875028f7d9dd755f6d4524b693c6507", + "url": "https://api.github.com/repos/utopia-php/database/zipball/cc6538e05e25d930244ab938c966d32db0922e83", + "reference": "cc6538e05e25d930244ab938c966d32db0922e83", "shasum": "" }, "require": { @@ -3549,9 +3549,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.68.1" + "source": "https://github.com/utopia-php/database/tree/0.69.1" }, - "time": "2025-05-09T10:08:53+00:00" + "time": "2025-05-13T12:00:31+00:00" }, { "name": "utopia-php/domains", From f8fdecaa2dbb16a6727f67732f72e2b85dcc37ab Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Tue, 13 May 2025 17:40:04 +0530 Subject: [PATCH 08/19] made the code a bit simpler --- app/controllers/api/databases.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index a56e0a05df..b98c5f0215 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -2901,9 +2901,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') $lengths[$i] ??= null; if ($attributeArray === true) { - if ($lengths[$i] === null) { - $lengths[$i] = Database::ARRAY_INDEX_LENGTH; - } + $lengths[$i] ??= Database::ARRAY_INDEX_LENGTH; $orders[$i] = null; } } From 9055645d06e246b8449cd94527b27d211f6f9fc8 Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Tue, 13 May 2025 18:21:34 +0530 Subject: [PATCH 09/19] updated test for the array attribute index overriding --- tests/e2e/Services/Databases/DatabasesBase.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/e2e/Services/Databases/DatabasesBase.php b/tests/e2e/Services/Databases/DatabasesBase.php index 025394362e..2b60dee856 100644 --- a/tests/e2e/Services/Databases/DatabasesBase.php +++ b/tests/e2e/Services/Databases/DatabasesBase.php @@ -1455,6 +1455,7 @@ trait DatabasesBase $this->assertEquals([128, 200], $index['body']['lengths']); // Test case for lengths array overriding + // set a length for an array attribute, it should get overriden with Database::ARRAY_INDEX_LENGTH $create = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$collectionId}/indexes", [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -1462,16 +1463,17 @@ trait DatabasesBase ], [ 'key' => 'lengthOverrideTestIndex', 'type' => 'key', - 'attributes' => ['title', 'description'], - 'lengths' => [null, 255] + 'attributes' => ['actors'], + 'lengths' => [120] ]); $this->assertEquals(202, $create['headers']['status-code']); + $index = $this->client->call(Client::METHOD_GET, "/databases/{$databaseId}/collections/{$collectionId}/indexes/lengthOverrideTestIndex", [ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'] ]); - $this->assertEquals([null, 255], $index['body']['lengths']); + $this->assertEquals([Database::ARRAY_INDEX_LENGTH], $index['body']['lengths']); // Test case for count of lengths greater than attributes (should throw 400) $create = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$collectionId}/indexes", [ From 4208c52c7f828f5118130a2a6c6e5f925b58dc62 Mon Sep 17 00:00:00 2001 From: ArnabChatterjee20k Date: Tue, 13 May 2025 18:21:58 +0530 Subject: [PATCH 10/19] reverted overriding index size for index attribute --- app/controllers/api/databases.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index b98c5f0215..cac713948a 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -2901,7 +2901,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes') $lengths[$i] ??= null; if ($attributeArray === true) { - $lengths[$i] ??= Database::ARRAY_INDEX_LENGTH; + $lengths[$i] = Database::ARRAY_INDEX_LENGTH; $orders[$i] = null; } } From c0b7c47615300142e67cc75711e95bcfefdc78c5 Mon Sep 17 00:00:00 2001 From: Fabian Gruber <1951610+basert@users.noreply.github.com> Date: Wed, 14 May 2025 10:40:56 +0200 Subject: [PATCH 11/19] fix(schedules): disable coroutine until we have proper pool support (#9759) --- src/Appwrite/Platform/Tasks/ScheduleBase.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Appwrite/Platform/Tasks/ScheduleBase.php b/src/Appwrite/Platform/Tasks/ScheduleBase.php index afd7d9d22a..8f7eab4d87 100644 --- a/src/Appwrite/Platform/Tasks/ScheduleBase.php +++ b/src/Appwrite/Platform/Tasks/ScheduleBase.php @@ -2,7 +2,6 @@ namespace Appwrite\Platform\Tasks; -use Swoole\Runtime; use Swoole\Timer; use Utopia\CLI\Console; use Utopia\Database\Database; @@ -66,8 +65,6 @@ abstract class ScheduleBase extends Action */ public function action(Group $pools, Database $dbForPlatform, callable $getProjectDB, Telemetry $telemetry): void { - Runtime::enableCoroutine(); - Console::title(\ucfirst(static::getSupportedResource()) . ' scheduler V1'); Console::success(APP_NAME . ' ' . \ucfirst(static::getSupportedResource()) . ' scheduler v1 has started'); From f62979cfa8e4fc05e221a5e72977b7e48848ce04 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Wed, 14 May 2025 15:41:21 +0530 Subject: [PATCH 12/19] feat: inforu adapter (#9620) * chore: update utopia messaging library * chore: init inforu adapter * chore: use dev message * chore: update composer * chore: fix ordering * chore: use user for senderId --- composer.json | 2 +- composer.lock | 14 +++++++------- src/Appwrite/Platform/Workers/Messaging.php | 9 +++++++++ 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/composer.json b/composer.json index 9b2cf7a1ab..8b8bb811af 100644 --- a/composer.json +++ b/composer.json @@ -59,7 +59,7 @@ "utopia-php/image": "0.8.*", "utopia-php/locale": "0.4.*", "utopia-php/logger": "0.6.*", - "utopia-php/messaging": "0.16.*", + "utopia-php/messaging": "0.17.*", "utopia-php/migration": "0.9.*", "utopia-php/orchestration": "0.9.*", "utopia-php/platform": "0.7.*", diff --git a/composer.lock b/composer.lock index e6bcd919e2..5e86bfafd2 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": "1eeb5a0f3560aefd8f71bd0955e30360", + "content-hash": "2c14e20244a06f508dd67cda717aefeb", "packages": [ { "name": "adhocore/jwt", @@ -3902,16 +3902,16 @@ }, { "name": "utopia-php/messaging", - "version": "0.16.0", + "version": "0.17.0", "source": { "type": "git", "url": "https://github.com/utopia-php/messaging.git", - "reference": "5f3083697102b1821d6624938186761b1e09c54e" + "reference": "c51915d0e030db3a3add37f1561751d18b2d9a85" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/messaging/zipball/5f3083697102b1821d6624938186761b1e09c54e", - "reference": "5f3083697102b1821d6624938186761b1e09c54e", + "url": "https://api.github.com/repos/utopia-php/messaging/zipball/c51915d0e030db3a3add37f1561751d18b2d9a85", + "reference": "c51915d0e030db3a3add37f1561751d18b2d9a85", "shasum": "" }, "require": { @@ -3947,9 +3947,9 @@ ], "support": { "issues": "https://github.com/utopia-php/messaging/issues", - "source": "https://github.com/utopia-php/messaging/tree/0.16.0" + "source": "https://github.com/utopia-php/messaging/tree/0.17.0" }, - "time": "2025-02-18T08:27:00+00:00" + "time": "2025-05-12T16:14:08+00:00" }, { "name": "utopia-php/migration", diff --git a/src/Appwrite/Platform/Workers/Messaging.php b/src/Appwrite/Platform/Workers/Messaging.php index cf2b8bfc84..c9eca2a1e0 100644 --- a/src/Appwrite/Platform/Workers/Messaging.php +++ b/src/Appwrite/Platform/Workers/Messaging.php @@ -24,6 +24,7 @@ use Utopia\Messaging\Adapter\Push\FCM; use Utopia\Messaging\Adapter\SMS as SMSAdapter; use Utopia\Messaging\Adapter\SMS\Fast2SMS; use Utopia\Messaging\Adapter\SMS\GEOSMS; +use Utopia\Messaging\Adapter\SMS\Inforu; use Utopia\Messaging\Adapter\SMS\Mock; use Utopia\Messaging\Adapter\SMS\Msg91; use Utopia\Messaging\Adapter\SMS\Telesign; @@ -455,6 +456,10 @@ class Messaging extends Action $credentials['messageId'] ?? '', $credentials['useDLT'] ?? true ), + 'inforu' => new Inforu( + $credentials['senderId'] ?? '', + $credentials['apiKey'] ?? '', + ), default => null }; } @@ -780,6 +785,10 @@ class Messaging extends Action 'messageId' => $dsn->getParam('messageId'), 'useDLT' => $dsn->getParam('useDLT'), ], + 'inforu' => [ + 'senderId' => $user, + 'apiKey' => $password, + ], default => null }, 'options' => match ($host) { From e08133976b63e434728e4b39c8f1feeea62cc24d Mon Sep 17 00:00:00 2001 From: Shimon Newman Date: Wed, 14 May 2025 15:57:41 +0300 Subject: [PATCH 13/19] fix metrics name in databases usage api (#9760) --- app/controllers/api/databases.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/databases.php b/app/controllers/api/databases.php index cac713948a..2e847ae11c 100644 --- a/app/controllers/api/databases.php +++ b/app/controllers/api/databases.php @@ -4739,8 +4739,8 @@ App::get('/v1/databases/:databaseId/usage') str_replace('{databaseInternalId}', $database->getInternalId(), METRIC_DATABASE_ID_COLLECTIONS), str_replace('{databaseInternalId}', $database->getInternalId(), METRIC_DATABASE_ID_DOCUMENTS), str_replace('{databaseInternalId}', $database->getInternalId(), METRIC_DATABASE_ID_STORAGE), - str_replace('{databaseInternalId}', $database->getInternalId(), METRIC_DATABASES_OPERATIONS_READS), - str_replace('{databaseInternalId}', $database->getInternalId(), METRIC_DATABASES_OPERATIONS_WRITES) + str_replace('{databaseInternalId}', $database->getInternalId(), METRIC_DATABASE_ID_OPERATIONS_READS), + str_replace('{databaseInternalId}', $database->getInternalId(), METRIC_DATABASE_ID_OPERATIONS_WRITES) ]; Authorization::skip(function () use ($dbForProject, $days, $metrics, &$stats) { From 651cec65da231ae8eacaa832b70ed8f4e5a6d962 Mon Sep 17 00:00:00 2001 From: Fabian Gruber <1951610+basert@users.noreply.github.com> Date: Thu, 15 May 2025 10:21:38 +0200 Subject: [PATCH 14/19] feat: telemetry for storage devices (#9761) --- app/init/resources.php | 24 ++++++++++++------------ app/worker.php | 29 +++++++++++++++++------------ composer.lock | 41 +++++++++++++++++++++-------------------- 3 files changed, 50 insertions(+), 44 deletions(-) diff --git a/app/init/resources.php b/app/init/resources.php index c719a47344..6bd40c6593 100644 --- a/app/init/resources.php +++ b/app/init/resources.php @@ -507,21 +507,21 @@ App::setResource('timelimit', function (\Redis $redis) { }; }, ['redis']); -App::setResource('deviceForLocal', function () { - return new Local(); -}); +App::setResource('deviceForLocal', function (Telemetry $telemetry) { + return new Device\Telemetry($telemetry, new Local()); +}, ['telemetry']); -App::setResource('deviceForFiles', function ($project) { - return getDevice(APP_STORAGE_UPLOADS . '/app-' . $project->getId()); -}, ['project']); +App::setResource('deviceForFiles', function ($project, Telemetry $telemetry) { + return new Device\Telemetry($telemetry, getDevice(APP_STORAGE_UPLOADS . '/app-' . $project->getId())); +}, ['project', 'telemetry']); -App::setResource('deviceForFunctions', function ($project) { - return getDevice(APP_STORAGE_FUNCTIONS . '/app-' . $project->getId()); -}, ['project']); +App::setResource('deviceForFunctions', function ($project, Telemetry $telemetry) { + return new Device\Telemetry($telemetry, getDevice(APP_STORAGE_FUNCTIONS . '/app-' . $project->getId())); +}, ['project', 'telemetry']); -App::setResource('deviceForBuilds', function ($project) { - return getDevice(APP_STORAGE_BUILDS . '/app-' . $project->getId()); -}, ['project']); +App::setResource('deviceForBuilds', function ($project, Telemetry $telemetry) { + return new Device\Telemetry($telemetry, getDevice(APP_STORAGE_BUILDS . '/app-' . $project->getId())); +}, ['project', 'telemetry']); function getDevice(string $root, string $connection = ''): Device { diff --git a/app/worker.php b/app/worker.php index 232e0b3684..29ebc836cd 100644 --- a/app/worker.php +++ b/app/worker.php @@ -37,7 +37,10 @@ use Utopia\Queue\Message; use Utopia\Queue\Publisher; use Utopia\Queue\Server; use Utopia\Registry\Registry; +use Utopia\Storage\Device; use Utopia\System\System; +use Utopia\Telemetry\Adapter as Telemetry; +use Utopia\Telemetry\Adapter\None as NoTelemetry; Authorization::disable(); Runtime::enableCoroutine(SWOOLE_HOOK_ALL); @@ -334,21 +337,23 @@ Server::setResource('pools', function (Registry $register) { return $register->get('pools'); }, ['register']); -Server::setResource('deviceForFunctions', function (Document $project) { - return getDevice(APP_STORAGE_FUNCTIONS . '/app-' . $project->getId()); -}, ['project']); +Server::setResource('telemetry', fn () => new NoTelemetry()); -Server::setResource('deviceForFiles', function (Document $project) { - return getDevice(APP_STORAGE_UPLOADS . '/app-' . $project->getId()); -}, ['project']); +Server::setResource('deviceForFunctions', function (Document $project, Telemetry $telemetry) { + return new Device\Telemetry($telemetry, getDevice(APP_STORAGE_FUNCTIONS . '/app-' . $project->getId())); +}, ['project', 'telemetry']); -Server::setResource('deviceForBuilds', function (Document $project) { - return getDevice(APP_STORAGE_BUILDS . '/app-' . $project->getId()); -}, ['project']); +Server::setResource('deviceForFiles', function (Document $project, Telemetry $telemetry) { + return new Device\Telemetry($telemetry, getDevice(APP_STORAGE_UPLOADS . '/app-' . $project->getId())); +}, ['project', 'telemetry']); -Server::setResource('deviceForCache', function (Document $project) { - return getDevice(APP_STORAGE_CACHE . '/app-' . $project->getId()); -}, ['project']); +Server::setResource('deviceForBuilds', function (Document $project, Telemetry $telemetry) { + return new Device\Telemetry($telemetry, getDevice(APP_STORAGE_BUILDS . '/app-' . $project->getId())); +}, ['project', 'telemetry']); + +Server::setResource('deviceForCache', function (Document $project, Telemetry $telemetry) { + return new Device\Telemetry($telemetry, getDevice(APP_STORAGE_CACHE . '/app-' . $project->getId())); +}, ['project', 'telemetry']); Server::setResource( 'isResourceBlocked', diff --git a/composer.lock b/composer.lock index 5e86bfafd2..828915d158 100644 --- a/composer.lock +++ b/composer.lock @@ -709,16 +709,16 @@ }, { "name": "google/protobuf", - "version": "v4.30.2", + "version": "v4.31.0", "source": { "type": "git", "url": "https://github.com/protocolbuffers/protobuf-php.git", - "reference": "a4c4d8565b40b9f76debc9dfeb221412eacb8ced" + "reference": "d59e31ce4bf0e4b48728e90c4d880839edb5be07" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/a4c4d8565b40b9f76debc9dfeb221412eacb8ced", - "reference": "a4c4d8565b40b9f76debc9dfeb221412eacb8ced", + "url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/d59e31ce4bf0e4b48728e90c4d880839edb5be07", + "reference": "d59e31ce4bf0e4b48728e90c4d880839edb5be07", "shasum": "" }, "require": { @@ -747,9 +747,9 @@ "proto" ], "support": { - "source": "https://github.com/protocolbuffers/protobuf-php/tree/v4.30.2" + "source": "https://github.com/protocolbuffers/protobuf-php/tree/v4.31.0" }, - "time": "2025-03-26T18:01:50+00:00" + "time": "2025-05-14T16:17:23+00:00" }, { "name": "league/csv", @@ -3499,16 +3499,16 @@ }, { "name": "utopia-php/database", - "version": "0.69.1", + "version": "0.69.2", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "cc6538e05e25d930244ab938c966d32db0922e83" + "reference": "60591ab073bb80bb9843338754b679bb8169e4ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/cc6538e05e25d930244ab938c966d32db0922e83", - "reference": "cc6538e05e25d930244ab938c966d32db0922e83", + "url": "https://api.github.com/repos/utopia-php/database/zipball/60591ab073bb80bb9843338754b679bb8169e4ed", + "reference": "60591ab073bb80bb9843338754b679bb8169e4ed", "shasum": "" }, "require": { @@ -3549,9 +3549,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.69.1" + "source": "https://github.com/utopia-php/database/tree/0.69.2" }, - "time": "2025-05-13T12:00:31+00:00" + "time": "2025-05-14T07:51:44+00:00" }, { "name": "utopia-php/domains", @@ -4331,16 +4331,16 @@ }, { "name": "utopia-php/storage", - "version": "0.18.10", + "version": "0.18.12", "source": { "type": "git", "url": "https://github.com/utopia-php/storage.git", - "reference": "76f31158f4251abb207f7a9b16f7cb0bfdb3b39e" + "reference": "9a2556c39b5f4d9f8e79111fd34ec889b7bb1e97" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/storage/zipball/76f31158f4251abb207f7a9b16f7cb0bfdb3b39e", - "reference": "76f31158f4251abb207f7a9b16f7cb0bfdb3b39e", + "url": "https://api.github.com/repos/utopia-php/storage/zipball/9a2556c39b5f4d9f8e79111fd34ec889b7bb1e97", + "reference": "9a2556c39b5f4d9f8e79111fd34ec889b7bb1e97", "shasum": "" }, "require": { @@ -4353,9 +4353,10 @@ "ext-xz": "*", "ext-zlib": "*", "ext-zstd": "*", - "php": ">=8.0", + "php": ">=8.1", "utopia-php/framework": "0.*.*", - "utopia-php/system": "0.*.*" + "utopia-php/system": "0.*.*", + "utopia-php/telemetry": "0.1.*" }, "require-dev": { "laravel/pint": "1.2.*", @@ -4382,9 +4383,9 @@ ], "support": { "issues": "https://github.com/utopia-php/storage/issues", - "source": "https://github.com/utopia-php/storage/tree/0.18.10" + "source": "https://github.com/utopia-php/storage/tree/0.18.12" }, - "time": "2025-03-03T10:47:54+00:00" + "time": "2025-05-15T07:55:58+00:00" }, { "name": "utopia-php/swoole", From ad3adbda21569b30c63beadc888098cb56852624 Mon Sep 17 00:00:00 2001 From: Darshan Date: Thu, 15 May 2025 14:08:54 +0530 Subject: [PATCH 15/19] fix: owner downgrade. --- app/controllers/api/teams.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index dd64fe0768..9c383803f2 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -1089,7 +1089,10 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId') // Quick check: fetch up to 2 owners to determine if only one exists $ownersCount = $dbForProject->count( collection: 'memberships', - queries: [Query::contains('roles', ['owner'])], + queries: [ + Query::contains('roles', ['owner']), + Query::equal('teamInternalId', [$team->getInternalId()]) + ], max: 2 ); From 15992da36943518c82d8f90864c8321cb98733a0 Mon Sep 17 00:00:00 2001 From: Darshan Date: Thu, 15 May 2025 15:01:23 +0530 Subject: [PATCH 16/19] update: tests. --- tests/e2e/Services/Teams/TeamsConsoleClientTest.php | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/tests/e2e/Services/Teams/TeamsConsoleClientTest.php b/tests/e2e/Services/Teams/TeamsConsoleClientTest.php index 4b5ade7cbf..06358765f6 100644 --- a/tests/e2e/Services/Teams/TeamsConsoleClientTest.php +++ b/tests/e2e/Services/Teams/TeamsConsoleClientTest.php @@ -86,7 +86,7 @@ class TeamsConsoleClientTest extends Scope $session = $data['session'] ?? ''; /** - * Test for SUCCESS + * Test for FAILURE */ $roles = ['developer']; $response = $this->client->call(Client::METHOD_PATCH, '/teams/' . $teamUid . '/memberships/' . $membershipUid, array_merge([ @@ -97,12 +97,8 @@ class TeamsConsoleClientTest extends Scope 'roles' => $roles ]); - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertNotEmpty($response['body']['$id']); - $this->assertNotEmpty($response['body']['userId']); - $this->assertNotEmpty($response['body']['teamId']); - $this->assertCount(count($roles), $response['body']['roles']); - $this->assertEquals($roles[0], $response['body']['roles'][0]); + $this->assertEquals(400, $response['headers']['status-code']); + $this->assertEquals('There must be at least one owner in the organization.', $response['body']['message']); /** * Test for unknown team From d28831632e88ee593d84d26829a1ad6a5b900a6a Mon Sep 17 00:00:00 2001 From: Fabian Gruber <1951610+basert@users.noreply.github.com> Date: Thu, 15 May 2025 14:45:24 +0200 Subject: [PATCH 17/19] Swap default image quality to -1, keeping source image quality. (#9766) --- app/controllers/api/avatars.php | 6 +++--- app/controllers/api/storage.php | 2 +- composer.lock | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/controllers/api/avatars.php b/app/controllers/api/avatars.php index 24fa36725f..05a9af81f8 100644 --- a/app/controllers/api/avatars.php +++ b/app/controllers/api/avatars.php @@ -187,7 +187,7 @@ App::get('/v1/avatars/credit-cards/:code') ->param('code', '', new WhiteList(\array_keys(Config::getParam('avatar-credit-cards'))), 'Credit Card Code. Possible values: ' . \implode(', ', \array_keys(Config::getParam('avatar-credit-cards'))) . '.') ->param('width', 100, new Range(0, 2000), 'Image width. Pass an integer between 0 to 2000. Defaults to 100.', true) ->param('height', 100, new Range(0, 2000), 'Image height. Pass an integer between 0 to 2000. Defaults to 100.', true) - ->param('quality', 100, new Range(0, 100), 'Image quality. Pass an integer between 0 to 100. Defaults to 100.', true) + ->param('quality', -1, new Range(-1, 100), 'Image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.', true) ->inject('response') ->action(fn (string $code, int $width, int $height, int $quality, Response $response) => $avatarCallback('credit-cards', $code, $width, $height, $quality, $response)); @@ -215,7 +215,7 @@ App::get('/v1/avatars/browsers/:code') ->param('code', '', new WhiteList(\array_keys(Config::getParam('avatar-browsers'))), 'Browser Code.') ->param('width', 100, new Range(0, 2000), 'Image width. Pass an integer between 0 to 2000. Defaults to 100.', true) ->param('height', 100, new Range(0, 2000), 'Image height. Pass an integer between 0 to 2000. Defaults to 100.', true) - ->param('quality', 100, new Range(0, 100), 'Image quality. Pass an integer between 0 to 100. Defaults to 100.', true) + ->param('quality', -1, new Range(-1, 100), 'Image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.', true) ->inject('response') ->action(fn (string $code, int $width, int $height, int $quality, Response $response) => $avatarCallback('browsers', $code, $width, $height, $quality, $response)); @@ -243,7 +243,7 @@ App::get('/v1/avatars/flags/:code') ->param('code', '', new WhiteList(\array_keys(Config::getParam('avatar-flags'))), 'Country Code. ISO Alpha-2 country code format.') ->param('width', 100, new Range(0, 2000), 'Image width. Pass an integer between 0 to 2000. Defaults to 100.', true) ->param('height', 100, new Range(0, 2000), 'Image height. Pass an integer between 0 to 2000. Defaults to 100.', true) - ->param('quality', 100, new Range(0, 100), 'Image quality. Pass an integer between 0 to 100. Defaults to 100.', true) + ->param('quality', -1, new Range(-1, 100), 'Image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.', true) ->inject('response') ->action(fn (string $code, int $width, int $height, int $quality, Response $response) => $avatarCallback('flags', $code, $width, $height, $quality, $response)); diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index d7e7c494f7..78c4c5fec9 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -943,7 +943,7 @@ App::get('/v1/storage/buckets/:bucketId/files/:fileId/preview') ->param('width', 0, new Range(0, 4000), 'Resize preview image width, Pass an integer between 0 to 4000.', true) ->param('height', 0, new Range(0, 4000), 'Resize preview image height, Pass an integer between 0 to 4000.', true) ->param('gravity', Image::GRAVITY_CENTER, new WhiteList(Image::getGravityTypes()), 'Image crop gravity. Can be one of ' . implode(",", Image::getGravityTypes()), true) - ->param('quality', 100, new Range(0, 100), 'Preview image quality. Pass an integer between 0 to 100. Defaults to 100.', true) + ->param('quality', -1, new Range(-1, 100), 'Preview image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.', true) ->param('borderWidth', 0, new Range(0, 100), 'Preview image border in pixels. Pass an integer between 0 to 100. Defaults to 0.', true) ->param('borderColor', '', new HexColor(), 'Preview image border color. Use a valid HEX color, no # is needed for prefix.', true) ->param('borderRadius', 0, new Range(0, 4000), 'Preview image border radius in pixels. Pass an integer between 0 to 4000.', true) diff --git a/composer.lock b/composer.lock index 828915d158..e108e45171 100644 --- a/composer.lock +++ b/composer.lock @@ -3748,16 +3748,16 @@ }, { "name": "utopia-php/image", - "version": "0.8.2", + "version": "0.8.3", "source": { "type": "git", "url": "https://github.com/utopia-php/image.git", - "reference": "6c736965177f9a9e71311e22b80cfa88511768e9" + "reference": "8820b0e53b3636b7bdf815e92394d333fef06f26" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/image/zipball/6c736965177f9a9e71311e22b80cfa88511768e9", - "reference": "6c736965177f9a9e71311e22b80cfa88511768e9", + "url": "https://api.github.com/repos/utopia-php/image/zipball/8820b0e53b3636b7bdf815e92394d333fef06f26", + "reference": "8820b0e53b3636b7bdf815e92394d333fef06f26", "shasum": "" }, "require": { @@ -3791,9 +3791,9 @@ ], "support": { "issues": "https://github.com/utopia-php/image/issues", - "source": "https://github.com/utopia-php/image/tree/0.8.2" + "source": "https://github.com/utopia-php/image/tree/0.8.3" }, - "time": "2025-04-08T11:31:45+00:00" + "time": "2025-05-15T10:39:28+00:00" }, { "name": "utopia-php/locale", From 8a555fd294307a746f4256e889fedc99b0c72444 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Thu, 15 May 2025 16:21:36 +0200 Subject: [PATCH 18/19] Add react native --- app/config/frameworks.php | 17 +++++++++++++++++ app/config/templates/site.php | 15 ++++++++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/app/config/frameworks.php b/app/config/frameworks.php index ae9830314d..f4d8ec7ffa 100644 --- a/app/config/frameworks.php +++ b/app/config/frameworks.php @@ -260,6 +260,23 @@ return [ ], ], ], + 'react-native' => [ + 'key' => 'react-native', + 'name' => 'React Native', + 'screenshotSleep' => 3000, + 'buildRuntime' => 'node-22', + 'runtimes' => getVersions($templateRuntimes['NODE']['versions'], 'node'), + 'adapters' => [ + 'static' => [ + 'key' => 'static', + 'buildCommand' => 'npm run build', + 'installCommand' => 'npm install', + 'outputDirectory' => './dist', + 'startCommand' => 'bash helpers/server.sh', + 'fallbackFile' => 'index.html' + ] + ] + ], 'vite' => [ 'key' => 'vite', 'name' => 'Vite', diff --git a/app/config/templates/site.php b/app/config/templates/site.php index 7f8951d0f9..ab6d5c4d4d 100644 --- a/app/config/templates/site.php +++ b/app/config/templates/site.php @@ -106,6 +106,16 @@ const TEMPLATE_FRAMEWORKS = [ 'outputDirectory' => './dist', 'fallbackFile' => 'index.html', ], + 'REACT_NATIVE' => [ + 'key' => 'react-native', + 'name' => 'React Native', + 'installCommand' => 'npm install', + 'buildCommand' => 'npm run build', + 'buildRuntime' => 'node-22', + 'adapter' => 'static', + 'outputDirectory' => './dist', + 'fallbackFile' => '+not-found.html', + ], 'ANGULAR' => [ 'key' => 'angular', 'name' => 'Angular', @@ -866,9 +876,8 @@ return [ 'screenshotDark' => $url . '/images/sites/templates/starter-for-react-native-dark.png', 'screenshotLight' => $url . '/images/sites/templates/starter-for-react-native-light.png', 'frameworks' => [ - getFramework('REACT', [ + getFramework('REACT_NATIVE', [ 'providerRootDirectory' => './', - 'fallbackFile' => '+not-found.html', ]), ], 'vcsProvider' => 'github', @@ -1332,7 +1341,7 @@ return [ 'screenshotDark' => $url . '/images/sites/templates/playground-for-react-native-dark.png', 'screenshotLight' => $url . '/images/sites/templates/playground-for-react-native-light.png', 'frameworks' => [ - getFramework('REACT', [ + getFramework('REACT_NATIVE', [ 'providerRootDirectory' => './react-native/starter', ]), ], From 2db7ec3290ffdaee3e3e62999e7d43d0e7f5db6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Thu, 15 May 2025 18:10:11 +0200 Subject: [PATCH 19/19] Post-merge fixes --- app/config/specs/open-api3-latest-client.json | 44 ++++-------- .../specs/open-api3-latest-console.json | 64 ++++++++--------- app/config/specs/open-api3-latest-server.json | 64 ++++++++--------- app/config/specs/swagger2-latest-client.json | 44 ++++-------- app/config/specs/swagger2-latest-console.json | 65 ++++++++--------- app/config/specs/swagger2-latest-server.json | 65 ++++++++--------- composer.lock | 71 ++++++++++--------- 7 files changed, 190 insertions(+), 227 deletions(-) diff --git a/app/config/specs/open-api3-latest-client.json b/app/config/specs/open-api3-latest-client.json index 80aa4cf420..f33dffd348 100644 --- a/app/config/specs/open-api3-latest-client.json +++ b/app/config/specs/open-api3-latest-client.json @@ -3381,13 +3381,13 @@ }, { "name": "quality", - "description": "Image quality. Pass an integer between 0 to 100. Defaults to 100.", + "description": "Image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.", "required": false, "schema": { "type": "integer", "format": "int32", - "x-example": 0, - "default": 100 + "x-example": -1, + "default": -1 }, "in": "query" } @@ -3513,13 +3513,13 @@ }, { "name": "quality", - "description": "Image quality. Pass an integer between 0 to 100. Defaults to 100.", + "description": "Image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.", "required": false, "schema": { "type": "integer", "format": "int32", - "x-example": 0, - "default": 100 + "x-example": -1, + "default": -1 }, "in": "query" } @@ -4059,13 +4059,13 @@ }, { "name": "quality", - "description": "Image quality. Pass an integer between 0 to 100. Defaults to 100.", + "description": "Image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.", "required": false, "schema": { "type": "integer", "format": "int32", - "x-example": 0, - "default": 100 + "x-example": -1, + "default": -1 }, "in": "query" } @@ -4485,26 +4485,6 @@ } ], "description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." - }, - { - "name": "createDocuments", - "parameters": [ - "databaseId", - "collectionId", - "documents" - ], - "required": [ - "databaseId", - "collectionId", - "documents" - ], - "responses": [ - { - "code": 201, - "model": "#\/components\/schemas\/documentList" - } - ], - "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." } ], "auth": { @@ -6410,13 +6390,13 @@ }, { "name": "quality", - "description": "Preview image quality. Pass an integer between 0 to 100. Defaults to 100.", + "description": "Preview image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.", "required": false, "schema": { "type": "integer", "format": "int32", - "x-example": 0, - "default": 100 + "x-example": -1, + "default": -1 }, "in": "query" }, diff --git a/app/config/specs/open-api3-latest-console.json b/app/config/specs/open-api3-latest-console.json index d9e216ed14..bf2314458f 100644 --- a/app/config/specs/open-api3-latest-console.json +++ b/app/config/specs/open-api3-latest-console.json @@ -3386,13 +3386,13 @@ }, { "name": "quality", - "description": "Image quality. Pass an integer between 0 to 100. Defaults to 100.", + "description": "Image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.", "required": false, "schema": { "type": "integer", "format": "int32", - "x-example": 0, - "default": 100 + "x-example": -1, + "default": -1 }, "in": "query" } @@ -3518,13 +3518,13 @@ }, { "name": "quality", - "description": "Image quality. Pass an integer between 0 to 100. Defaults to 100.", + "description": "Image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.", "required": false, "schema": { "type": "integer", "format": "int32", - "x-example": 0, - "default": 100 + "x-example": -1, + "default": -1 }, "in": "query" } @@ -4064,13 +4064,13 @@ }, { "name": "quality", - "description": "Image quality. Pass an integer between 0 to 100. Defaults to 100.", + "description": "Image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.", "required": false, "schema": { "type": "integer", "format": "int32", - "x-example": 0, - "default": 100 + "x-example": -1, + "default": -1 }, "in": "query" } @@ -8044,26 +8044,6 @@ } ], "description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." - }, - { - "name": "createDocuments", - "parameters": [ - "databaseId", - "collectionId", - "documents" - ], - "required": [ - "databaseId", - "collectionId", - "documents" - ], - "responses": [ - { - "code": 201, - "model": "#\/components\/schemas\/documentList" - } - ], - "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." } ], "auth": { @@ -8967,6 +8947,14 @@ "items": { "type": "string" } + }, + "lengths": { + "type": "array", + "description": "Length of index. Maximum of 100", + "x-example": null, + "items": { + "type": "integer" + } } }, "required": [ @@ -25729,6 +25717,7 @@ "remix", "lynx", "flutter", + "react-native", "vite", "other" ], @@ -26372,6 +26361,7 @@ "remix", "lynx", "flutter", + "react-native", "vite", "other" ], @@ -29143,13 +29133,13 @@ }, { "name": "quality", - "description": "Preview image quality. Pass an integer between 0 to 100. Defaults to 100.", + "description": "Preview image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.", "required": false, "schema": { "type": "integer", "format": "int32", - "x-example": 0, - "default": 100 + "x-example": -1, + "default": -1 }, "in": "query" }, @@ -37161,6 +37151,15 @@ }, "x-example": [] }, + "lengths": { + "type": "array", + "description": "Index attributes length.", + "items": { + "type": "integer", + "format": "int32" + }, + "x-example": [] + }, "orders": { "type": "array", "description": "Index orders.", @@ -37187,6 +37186,7 @@ "status", "error", "attributes", + "lengths", "$createdAt", "$updatedAt" ] diff --git a/app/config/specs/open-api3-latest-server.json b/app/config/specs/open-api3-latest-server.json index 509337fc81..c9f99b0188 100644 --- a/app/config/specs/open-api3-latest-server.json +++ b/app/config/specs/open-api3-latest-server.json @@ -3068,13 +3068,13 @@ }, { "name": "quality", - "description": "Image quality. Pass an integer between 0 to 100. Defaults to 100.", + "description": "Image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.", "required": false, "schema": { "type": "integer", "format": "int32", - "x-example": 0, - "default": 100 + "x-example": -1, + "default": -1 }, "in": "query" } @@ -3202,13 +3202,13 @@ }, { "name": "quality", - "description": "Image quality. Pass an integer between 0 to 100. Defaults to 100.", + "description": "Image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.", "required": false, "schema": { "type": "integer", "format": "int32", - "x-example": 0, - "default": 100 + "x-example": -1, + "default": -1 }, "in": "query" } @@ -3752,13 +3752,13 @@ }, { "name": "quality", - "description": "Image quality. Pass an integer between 0 to 100. Defaults to 100.", + "description": "Image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.", "required": false, "schema": { "type": "integer", "format": "int32", - "x-example": 0, - "default": 100 + "x-example": -1, + "default": -1 }, "in": "query" } @@ -7525,26 +7525,6 @@ } ], "description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." - }, - { - "name": "createDocuments", - "parameters": [ - "databaseId", - "collectionId", - "documents" - ], - "required": [ - "databaseId", - "collectionId", - "documents" - ], - "responses": [ - { - "code": 201, - "model": "#\/components\/schemas\/documentList" - } - ], - "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." } ], "auth": { @@ -8368,6 +8348,14 @@ "items": { "type": "string" } + }, + "lengths": { + "type": "array", + "description": "Length of index. Maximum of 100", + "x-example": null, + "items": { + "type": "integer" + } } }, "required": [ @@ -17281,6 +17269,7 @@ "remix", "lynx", "flutter", + "react-native", "vite", "other" ], @@ -17696,6 +17685,7 @@ "remix", "lynx", "flutter", + "react-native", "vite", "other" ], @@ -20423,13 +20413,13 @@ }, { "name": "quality", - "description": "Preview image quality. Pass an integer between 0 to 100. Defaults to 100.", + "description": "Preview image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.", "required": false, "schema": { "type": "integer", "format": "int32", - "x-example": 0, - "default": 100 + "x-example": -1, + "default": -1 }, "in": "query" }, @@ -26940,6 +26930,15 @@ }, "x-example": [] }, + "lengths": { + "type": "array", + "description": "Index attributes length.", + "items": { + "type": "integer", + "format": "int32" + }, + "x-example": [] + }, "orders": { "type": "array", "description": "Index orders.", @@ -26966,6 +26965,7 @@ "status", "error", "attributes", + "lengths", "$createdAt", "$updatedAt" ] diff --git a/app/config/specs/swagger2-latest-client.json b/app/config/specs/swagger2-latest-client.json index 5bb98a8c0f..f60a2549b1 100644 --- a/app/config/specs/swagger2-latest-client.json +++ b/app/config/specs/swagger2-latest-client.json @@ -3524,12 +3524,12 @@ }, { "name": "quality", - "description": "Image quality. Pass an integer between 0 to 100. Defaults to 100.", + "description": "Image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.", "required": false, "type": "integer", "format": "int32", - "x-example": 0, - "default": 100, + "x-example": -1, + "default": -1, "in": "query" } ] @@ -3655,12 +3655,12 @@ }, { "name": "quality", - "description": "Image quality. Pass an integer between 0 to 100. Defaults to 100.", + "description": "Image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.", "required": false, "type": "integer", "format": "int32", - "x-example": 0, - "default": 100, + "x-example": -1, + "default": -1, "in": "query" } ] @@ -4205,12 +4205,12 @@ }, { "name": "quality", - "description": "Image quality. Pass an integer between 0 to 100. Defaults to 100.", + "description": "Image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.", "required": false, "type": "integer", "format": "int32", - "x-example": 0, - "default": 100, + "x-example": -1, + "default": -1, "in": "query" } ] @@ -4625,26 +4625,6 @@ } ], "description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." - }, - { - "name": "createDocuments", - "parameters": [ - "databaseId", - "collectionId", - "documents" - ], - "required": [ - "databaseId", - "collectionId", - "documents" - ], - "responses": [ - { - "code": 201, - "model": "#\/definitions\/documentList" - } - ], - "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." } ], "auth": { @@ -6557,12 +6537,12 @@ }, { "name": "quality", - "description": "Preview image quality. Pass an integer between 0 to 100. Defaults to 100.", + "description": "Preview image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.", "required": false, "type": "integer", "format": "int32", - "x-example": 0, - "default": 100, + "x-example": -1, + "default": -1, "in": "query" }, { diff --git a/app/config/specs/swagger2-latest-console.json b/app/config/specs/swagger2-latest-console.json index bf430b6e63..6db1ccbd15 100644 --- a/app/config/specs/swagger2-latest-console.json +++ b/app/config/specs/swagger2-latest-console.json @@ -3545,12 +3545,12 @@ }, { "name": "quality", - "description": "Image quality. Pass an integer between 0 to 100. Defaults to 100.", + "description": "Image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.", "required": false, "type": "integer", "format": "int32", - "x-example": 0, - "default": 100, + "x-example": -1, + "default": -1, "in": "query" } ] @@ -3676,12 +3676,12 @@ }, { "name": "quality", - "description": "Image quality. Pass an integer between 0 to 100. Defaults to 100.", + "description": "Image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.", "required": false, "type": "integer", "format": "int32", - "x-example": 0, - "default": 100, + "x-example": -1, + "default": -1, "in": "query" } ] @@ -4226,12 +4226,12 @@ }, { "name": "quality", - "description": "Image quality. Pass an integer between 0 to 100. Defaults to 100.", + "description": "Image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.", "required": false, "type": "integer", "format": "int32", - "x-example": 0, - "default": 100, + "x-example": -1, + "default": -1, "in": "query" } ] @@ -8173,26 +8173,6 @@ } ], "description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." - }, - { - "name": "createDocuments", - "parameters": [ - "databaseId", - "collectionId", - "documents" - ], - "required": [ - "databaseId", - "collectionId", - "documents" - ], - "responses": [ - { - "code": 201, - "model": "#\/definitions\/documentList" - } - ], - "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." } ], "auth": { @@ -9062,6 +9042,15 @@ "items": { "type": "string" } + }, + "lengths": { + "type": "array", + "description": "Length of index. Maximum of 100", + "default": [], + "x-example": null, + "items": { + "type": "integer" + } } }, "required": [ @@ -25992,6 +25981,7 @@ "remix", "lynx", "flutter", + "react-native", "vite", "other" ], @@ -26638,6 +26628,7 @@ "remix", "lynx", "flutter", + "react-native", "vite", "other" ], @@ -29401,12 +29392,12 @@ }, { "name": "quality", - "description": "Preview image quality. Pass an integer between 0 to 100. Defaults to 100.", + "description": "Preview image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.", "required": false, "type": "integer", "format": "int32", - "x-example": 0, - "default": 100, + "x-example": -1, + "default": -1, "in": "query" }, { @@ -37393,6 +37384,15 @@ }, "x-example": [] }, + "lengths": { + "type": "array", + "description": "Index attributes length.", + "items": { + "type": "integer", + "format": "int32" + }, + "x-example": [] + }, "orders": { "type": "array", "description": "Index orders.", @@ -37419,6 +37419,7 @@ "status", "error", "attributes", + "lengths", "$createdAt", "$updatedAt" ] diff --git a/app/config/specs/swagger2-latest-server.json b/app/config/specs/swagger2-latest-server.json index 302a486e1f..5a979359e5 100644 --- a/app/config/specs/swagger2-latest-server.json +++ b/app/config/specs/swagger2-latest-server.json @@ -3223,12 +3223,12 @@ }, { "name": "quality", - "description": "Image quality. Pass an integer between 0 to 100. Defaults to 100.", + "description": "Image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.", "required": false, "type": "integer", "format": "int32", - "x-example": 0, - "default": 100, + "x-example": -1, + "default": -1, "in": "query" } ] @@ -3356,12 +3356,12 @@ }, { "name": "quality", - "description": "Image quality. Pass an integer between 0 to 100. Defaults to 100.", + "description": "Image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.", "required": false, "type": "integer", "format": "int32", - "x-example": 0, - "default": 100, + "x-example": -1, + "default": -1, "in": "query" } ] @@ -3910,12 +3910,12 @@ }, { "name": "quality", - "description": "Image quality. Pass an integer between 0 to 100. Defaults to 100.", + "description": "Image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.", "required": false, "type": "integer", "format": "int32", - "x-example": 0, - "default": 100, + "x-example": -1, + "default": -1, "in": "query" } ] @@ -7644,26 +7644,6 @@ } ], "description": "Create a new Document. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." - }, - { - "name": "createDocuments", - "parameters": [ - "databaseId", - "collectionId", - "documents" - ], - "required": [ - "databaseId", - "collectionId", - "documents" - ], - "responses": [ - { - "code": 201, - "model": "#\/definitions\/documentList" - } - ], - "description": "Create new Documents. Before using this route, you should create a new collection resource using either a [server integration](https:\/\/appwrite.io\/docs\/server\/databases#databasesCreateCollection) API or directly from your database console." } ], "auth": { @@ -8460,6 +8440,15 @@ "items": { "type": "string" } + }, + "lengths": { + "type": "array", + "description": "Length of index. Maximum of 100", + "default": [], + "x-example": null, + "items": { + "type": "integer" + } } }, "required": [ @@ -17579,6 +17568,7 @@ "remix", "lynx", "flutter", + "react-native", "vite", "other" ], @@ -18007,6 +17997,7 @@ "remix", "lynx", "flutter", + "react-native", "vite", "other" ], @@ -20730,12 +20721,12 @@ }, { "name": "quality", - "description": "Preview image quality. Pass an integer between 0 to 100. Defaults to 100.", + "description": "Preview image quality. Pass an integer between 0 to 100. Defaults to keep existing image quality.", "required": false, "type": "integer", "format": "int32", - "x-example": 0, - "default": 100, + "x-example": -1, + "default": -1, "in": "query" }, { @@ -27240,6 +27231,15 @@ }, "x-example": [] }, + "lengths": { + "type": "array", + "description": "Index attributes length.", + "items": { + "type": "integer", + "format": "int32" + }, + "x-example": [] + }, "orders": { "type": "array", "description": "Index orders.", @@ -27266,6 +27266,7 @@ "status", "error", "attributes", + "lengths", "$createdAt", "$updatedAt" ] diff --git a/composer.lock b/composer.lock index e8d3fb11e0..c68d6bf4d7 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": "18d31817580d569f001c88d865dcbfc6", + "content-hash": "735023e2b70ce47fe65985f195b257bd", "packages": [ { "name": "adhocore/jwt", @@ -709,16 +709,16 @@ }, { "name": "google/protobuf", - "version": "v4.30.2", + "version": "v4.31.0", "source": { "type": "git", "url": "https://github.com/protocolbuffers/protobuf-php.git", - "reference": "a4c4d8565b40b9f76debc9dfeb221412eacb8ced" + "reference": "d59e31ce4bf0e4b48728e90c4d880839edb5be07" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/a4c4d8565b40b9f76debc9dfeb221412eacb8ced", - "reference": "a4c4d8565b40b9f76debc9dfeb221412eacb8ced", + "url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/d59e31ce4bf0e4b48728e90c4d880839edb5be07", + "reference": "d59e31ce4bf0e4b48728e90c4d880839edb5be07", "shasum": "" }, "require": { @@ -747,9 +747,9 @@ "proto" ], "support": { - "source": "https://github.com/protocolbuffers/protobuf-php/tree/v4.30.2" + "source": "https://github.com/protocolbuffers/protobuf-php/tree/v4.31.0" }, - "time": "2025-03-26T18:01:50+00:00" + "time": "2025-05-14T16:17:23+00:00" }, { "name": "league/csv", @@ -3499,16 +3499,16 @@ }, { "name": "utopia-php/database", - "version": "0.68.1", + "version": "0.69.2", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "72b2e2c0b875028f7d9dd755f6d4524b693c6507" + "reference": "60591ab073bb80bb9843338754b679bb8169e4ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/72b2e2c0b875028f7d9dd755f6d4524b693c6507", - "reference": "72b2e2c0b875028f7d9dd755f6d4524b693c6507", + "url": "https://api.github.com/repos/utopia-php/database/zipball/60591ab073bb80bb9843338754b679bb8169e4ed", + "reference": "60591ab073bb80bb9843338754b679bb8169e4ed", "shasum": "" }, "require": { @@ -3549,9 +3549,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.68.1" + "source": "https://github.com/utopia-php/database/tree/0.69.2" }, - "time": "2025-05-09T10:08:53+00:00" + "time": "2025-05-14T07:51:44+00:00" }, { "name": "utopia-php/detector", @@ -3793,16 +3793,16 @@ }, { "name": "utopia-php/image", - "version": "0.8.2", + "version": "0.8.3", "source": { "type": "git", "url": "https://github.com/utopia-php/image.git", - "reference": "6c736965177f9a9e71311e22b80cfa88511768e9" + "reference": "8820b0e53b3636b7bdf815e92394d333fef06f26" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/image/zipball/6c736965177f9a9e71311e22b80cfa88511768e9", - "reference": "6c736965177f9a9e71311e22b80cfa88511768e9", + "url": "https://api.github.com/repos/utopia-php/image/zipball/8820b0e53b3636b7bdf815e92394d333fef06f26", + "reference": "8820b0e53b3636b7bdf815e92394d333fef06f26", "shasum": "" }, "require": { @@ -3836,9 +3836,9 @@ ], "support": { "issues": "https://github.com/utopia-php/image/issues", - "source": "https://github.com/utopia-php/image/tree/0.8.2" + "source": "https://github.com/utopia-php/image/tree/0.8.3" }, - "time": "2025-04-08T11:31:45+00:00" + "time": "2025-05-15T10:39:28+00:00" }, { "name": "utopia-php/locale", @@ -3947,16 +3947,16 @@ }, { "name": "utopia-php/messaging", - "version": "0.16.0", + "version": "0.17.0", "source": { "type": "git", "url": "https://github.com/utopia-php/messaging.git", - "reference": "5f3083697102b1821d6624938186761b1e09c54e" + "reference": "c51915d0e030db3a3add37f1561751d18b2d9a85" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/messaging/zipball/5f3083697102b1821d6624938186761b1e09c54e", - "reference": "5f3083697102b1821d6624938186761b1e09c54e", + "url": "https://api.github.com/repos/utopia-php/messaging/zipball/c51915d0e030db3a3add37f1561751d18b2d9a85", + "reference": "c51915d0e030db3a3add37f1561751d18b2d9a85", "shasum": "" }, "require": { @@ -3992,9 +3992,9 @@ ], "support": { "issues": "https://github.com/utopia-php/messaging/issues", - "source": "https://github.com/utopia-php/messaging/tree/0.16.0" + "source": "https://github.com/utopia-php/messaging/tree/0.17.0" }, - "time": "2025-02-18T08:27:00+00:00" + "time": "2025-05-12T16:14:08+00:00" }, { "name": "utopia-php/migration", @@ -4376,16 +4376,16 @@ }, { "name": "utopia-php/storage", - "version": "0.18.10", + "version": "0.18.12", "source": { "type": "git", "url": "https://github.com/utopia-php/storage.git", - "reference": "76f31158f4251abb207f7a9b16f7cb0bfdb3b39e" + "reference": "9a2556c39b5f4d9f8e79111fd34ec889b7bb1e97" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/storage/zipball/76f31158f4251abb207f7a9b16f7cb0bfdb3b39e", - "reference": "76f31158f4251abb207f7a9b16f7cb0bfdb3b39e", + "url": "https://api.github.com/repos/utopia-php/storage/zipball/9a2556c39b5f4d9f8e79111fd34ec889b7bb1e97", + "reference": "9a2556c39b5f4d9f8e79111fd34ec889b7bb1e97", "shasum": "" }, "require": { @@ -4398,9 +4398,10 @@ "ext-xz": "*", "ext-zlib": "*", "ext-zstd": "*", - "php": ">=8.0", + "php": ">=8.1", "utopia-php/framework": "0.*.*", - "utopia-php/system": "0.*.*" + "utopia-php/system": "0.*.*", + "utopia-php/telemetry": "0.1.*" }, "require-dev": { "laravel/pint": "1.2.*", @@ -4427,9 +4428,9 @@ ], "support": { "issues": "https://github.com/utopia-php/storage/issues", - "source": "https://github.com/utopia-php/storage/tree/0.18.10" + "source": "https://github.com/utopia-php/storage/tree/0.18.12" }, - "time": "2025-03-03T10:47:54+00:00" + "time": "2025-05-15T07:55:58+00:00" }, { "name": "utopia-php/swoole", @@ -8239,7 +8240,7 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": {}, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { @@ -8263,5 +8264,5 @@ "platform-overrides": { "php": "8.3" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.3.0" }