Merge branch '1.7.x' into fix-scopes

This commit is contained in:
Darshan
2025-05-16 11:05:19 +05:30
committed by GitHub
33 changed files with 444 additions and 456 deletions
+1 -1
View File
@@ -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 => [
+17
View File
@@ -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',
+1 -1
View File
@@ -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,
@@ -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": {
@@ -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": {
@@ -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": {
+12 -32
View File
@@ -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"
},
+32 -32
View File
@@ -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"
},
@@ -37163,6 +37153,15 @@
},
"x-example": []
},
"lengths": {
"type": "array",
"description": "Index attributes length.",
"items": {
"type": "integer",
"format": "int32"
},
"x-example": []
},
"orders": {
"type": "array",
"description": "Index orders.",
@@ -37189,6 +37188,7 @@
"status",
"error",
"attributes",
"lengths",
"$createdAt",
"$updatedAt"
]
+32 -32
View File
@@ -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"
},
@@ -27129,6 +27119,15 @@
},
"x-example": []
},
"lengths": {
"type": "array",
"description": "Index attributes length.",
"items": {
"type": "integer",
"format": "int32"
},
"x-example": []
},
"orders": {
"type": "array",
"description": "Index orders.",
@@ -27155,6 +27154,7 @@
"status",
"error",
"attributes",
"lengths",
"$createdAt",
"$updatedAt"
]
@@ -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": {
@@ -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": {
@@ -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": {
+12 -32
View File
@@ -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"
},
{
+33 -32
View File
@@ -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"
},
{
@@ -37395,6 +37386,15 @@
},
"x-example": []
},
"lengths": {
"type": "array",
"description": "Index attributes length.",
"items": {
"type": "integer",
"format": "int32"
},
"x-example": []
},
"orders": {
"type": "array",
"description": "Index orders.",
@@ -37421,6 +37421,7 @@
"status",
"error",
"attributes",
"lengths",
"$createdAt",
"$updatedAt"
]
+33 -32
View File
@@ -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"
},
{
@@ -27428,6 +27419,15 @@
},
"x-example": []
},
"lengths": {
"type": "array",
"description": "Index attributes length.",
"items": {
"type": "integer",
"format": "int32"
},
"x-example": []
},
"orders": {
"type": "array",
"description": "Index orders.",
@@ -27454,6 +27454,7 @@
"status",
"error",
"attributes",
"lengths",
"$createdAt",
"$updatedAt"
]
+12 -3
View File
@@ -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',
]),
],
+3 -3
View File
@@ -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));
+24 -27
View File
@@ -2813,11 +2813,12 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/indexes')
->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('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 $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));
@@ -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,8 +2899,7 @@ 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] ??= null;
if ($attributeArray === true) {
$lengths[$i] = Database::ARRAY_INDEX_LENGTH;
$orders[$i] = null;
@@ -3204,25 +3201,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.')
@@ -4742,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) {
+1 -1
View File
@@ -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)
+4 -1
View File
@@ -1090,7 +1090,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
);
+18 -21
View File
@@ -509,29 +509,26 @@ 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('deviceForSites', function ($project, Telemetry $telemetry) {
return new Device\Telemetry($telemetry, getDevice(APP_STORAGE_SITES . '/app-' . $project->getId()));
}, ['project', 'telemetry']);
App::setResource('deviceForImports', function ($project, Telemetry $telemetry) {
return new Device\Telemetry($telemetry, getDevice(APP_STORAGE_IMPORTS . '/app-' . $project->getId()));
}, ['project', 'telemetry']);
App::setResource('deviceForFunctions', function ($project, Telemetry $telemetry) {
return new Device\Telemetry($telemetry, getDevice(APP_STORAGE_FUNCTIONS . '/app-' . $project->getId()));
}, ['project', 'telemetry']);
App::setResource('deviceForSites', function ($project) {
return getDevice(APP_STORAGE_SITES . '/app-' . $project->getId());
}, ['project']);
App::setResource('deviceForImports', function (Document $project) {
return getDevice(APP_STORAGE_IMPORTS . '/app-' . $project->getId());
}, ['project']);
App::setResource('deviceForFunctions', function ($project) {
return getDevice(APP_STORAGE_FUNCTIONS . '/app-' . $project->getId());
}, ['project']);
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
{
+23 -18
View File
@@ -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,29 +337,31 @@ Server::setResource('pools', function (Registry $register) {
return $register->get('pools');
}, ['register']);
Server::setResource('deviceForSites', function (Document $project) {
return getDevice(APP_STORAGE_SITES . '/app-' . $project->getId());
}, ['project']);
Server::setResource('telemetry', fn () => new NoTelemetry());
Server::setResource('deviceForImports', function (Document $project) {
return getDevice(APP_STORAGE_IMPORTS . '/app-' . $project->getId());
}, ['project']);
Server::setResource('deviceForSites', function (Document $project, Telemetry $telemetry) {
return new Device\Telemetry($telemetry, getDevice(APP_STORAGE_SITES . '/app-' . $project->getId()));
}, ['project', 'telemetry']);
Server::setResource('deviceForFunctions', function (Document $project) {
return getDevice(APP_STORAGE_FUNCTIONS . '/app-' . $project->getId());
}, ['project']);
Server::setResource('deviceForImports', function (Document $project, Telemetry $telemetry) {
return new Device\Telemetry($telemetry, getDevice(APP_STORAGE_IMPORTS . '/app-' . $project->getId()));
}, ['project', 'telemetry']);
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',
+2 -2
View File
@@ -53,7 +53,7 @@
"utopia-php/cli": "0.15.*",
"utopia-php/config": "0.2.*",
"utopia-php/detector": "0.1.*",
"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.*",
@@ -61,7 +61,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.*",
Generated
+36 -35
View File
@@ -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"
}
+6 -1
View File
@@ -1 +1,6 @@
# Change log
# Change log
## 0.7.4
* Upgrade dependencies to resolve PlatformConstants error with Expo 53
* Update doc examples to use new multi-region endpoint
+11 -11
View File
@@ -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');
@@ -91,13 +88,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";
@@ -202,10 +204,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()]);
}
}
@@ -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(
@@ -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);
@@ -66,17 +72,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 +103,7 @@ class ScheduleFunctions extends ScheduleBase
->setProject($schedule['project'])
->trigger();
$this->recordEnqueueDelay($schedule['schedule']);
$this->recordEnqueueDelay($delayConfig['nextDate']);
}
$queue->reclaim();
@@ -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']]);
});
}
@@ -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) {
@@ -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.',
+95 -2
View File
@@ -1422,9 +1422,102 @@ trait DatabasesBase
return $data;
}
/**
* @depends testCreateIndexes
*/
* @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'],
'x-appwrite-key' => $this->getProject()['apiKey']
], [
'key' => 'lengthTestIndex',
'type' => 'key',
'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'],
'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']);
// 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'],
'x-appwrite-key' => $this->getProject()['apiKey']
], [
'key' => 'lengthOverrideTestIndex',
'type' => 'key',
'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([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", [
'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
*/
public function testListIndexes(array $data): void
{
$databaseId = $data['databaseId'];
@@ -110,7 +110,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([
@@ -121,12 +121,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