diff --git a/CHANGELOG.md b/CHANGELOG.md index eca2e74..b9a9ccf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Change Log +## 30.0.0 + +* Stable release of the dedicated database APIs: `mysql`, `postgresql`, `mongo`, `documentsDB`, and `vectorsDB` services, previously released as release candidates +* Breaking: `tablesDB.cutoverMigration` is renamed to `tablesDB.createCutover` +* Added: Cloudflare and Resend OAuth providers +* Added: `usageAggregateOnlyMetrics` on the `BillingPlan` model +* Fixed: `transactionId` is accepted again by `documentsDB` and `vectorsDB` `createDocument` and `createDocuments` +* Updated: `X-Appwrite-Response-Format` is now `2.0.0` +* Updated: `FrameworkAdapter.fallbackFile` is now optional + ## 30.0.0-rc.1 * Breaking: `EmbeddingModel` no longer offers `embedding-gemma` or `bge-small` diff --git a/README.md b/README.md index 0afbcba..bd76997 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # Appwrite PHP SDK ![License](https://img.shields.io/github/license/appwrite/sdk-for-php.svg?style=flat-square&v=1) -![Version](https://img.shields.io/badge/api%20version-1.9.6-blue.svg?style=flat-square&v=1) +![Version](https://img.shields.io/badge/api%20version-2.0.0-blue.svg?style=flat-square&v=1) [![Build Status](https://img.shields.io/travis/com/appwrite/sdk-generator?style=flat-square)](https://travis-ci.com/appwrite/sdk-generator) [![Twitter Account](https://img.shields.io/twitter/follow/appwrite?color=00acee&label=twitter&style=flat-square)](https://twitter.com/appwrite) [![Discord](https://img.shields.io/discord/564160730845151244?label=discord&style=flat-square)](https://appwrite.io/discord) -**This SDK is compatible with Appwrite server version 1.9.x. For older versions, please check [previous releases](https://github.com/appwrite/sdk-for-php/releases).** +**This SDK targets Appwrite server version 1.9.x as shipped on Appwrite Cloud.** Self-hosted releases can lag behind Cloud — if you run an older self-hosted build, use a matching older SDK from [previous releases](https://github.com/appwrite/sdk-for-php/releases) when APIs differ. Appwrite is an open-source backend as a service server that abstracts and simplifies complex and repetitive development tasks behind a very simple to use REST API. Appwrite aims to help you develop your apps faster and in a more secure way. Use the PHP SDK to integrate your app with the Appwrite server to easily start interacting with all of Appwrite backend APIs and tools. For full API documentation and tutorials go to [https://appwrite.io/docs](https://appwrite.io/docs) diff --git a/docs/account.md b/docs/account.md index 4ed4475..f285087 100644 --- a/docs/account.md +++ b/docs/account.md @@ -635,7 +635,7 @@ A user is limited to 10 active sessions at a time by default. [Learn more about | Field Name | Type | Description | Default | | --- | --- | --- | --- | -| provider | string | **Required** OAuth2 Provider. Currently, supported providers are: amazon, apple, appwrite, auth0, authentik, autodesk, bitbucket, bitly, box, dailymotion, discord, disqus, dropbox, etsy, facebook, figma, fusionauth, github, gitlab, google, huggingface, keycloak, kick, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, x, yahoo, yammer, yandex, zoho, zoom. | | +| provider | string | **Required** OAuth2 Provider. Currently, supported providers are: amazon, apple, appwrite, auth0, authentik, autodesk, bitbucket, bitly, box, cloudflare, dailymotion, discord, disqus, dropbox, etsy, facebook, figma, fusionauth, github, gitlab, google, huggingface, keycloak, kick, linkedin, microsoft, notion, oidc, okta, paypal, paypalSandbox, podio, resend, salesforce, slack, spotify, stripe, tradeshift, tradeshiftBox, twitch, wordpress, x, yahoo, yammer, yandex, zoho, zoom. | | | success | string | URL to redirect back to your app after a successful login attempt. Only URLs from hostnames in your project's platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API. | | | failure | string | URL to redirect back to your app after a failed login attempt. Only URLs from hostnames in your project's platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API. | | | scopes | array | A list of custom OAuth2 scopes. Check each provider internal docs for a list of supported scopes. Maximum of 100 scopes are allowed, each 4096 characters long. | [] | diff --git a/docs/avatars.md b/docs/avatars.md index d9f421f..367d29f 100644 --- a/docs/avatars.md +++ b/docs/avatars.md @@ -118,7 +118,7 @@ GET https://cloud.appwrite.io/v1/avatars/photo ** Returns the best available profile photo for a user. The endpoint tries each source in priority order and returns the first successful result: OAuth2 identity photo, Gravatar, Libravatar, Appwrite Initials, built-in static fallback. -The photo resolves for the currently authenticated user unless `userId` points at another user. Passing `emailHash` and/or `name` resolves the avatar from those values alone: the hash is looked up on Gravatar and Libravatar, the name is rendered as initials, and the user's own identity photos, email, and name leave the chain so they never shadow the avatar being asked for. Emails are only ever accepted pre-hashed, so no address ends up in a URL. ** +Passing `userId` — `current()` for the authenticated user — resolves the photo from everything known about that user: identity photos, email, and name. An explicit `emailHash` or `name` then overrides just that value, and the user's remaining sources stay in the chain. Without `userId`, passing `emailHash` and/or `name` resolves the avatar from those values alone: the hash is looked up on Gravatar and Libravatar, the name is rendered as initials, and the session user stays out of the chain so their own photo never shadows the avatar being asked for. When nothing is passed, the photo resolves for the currently authenticated user. Emails are only ever accepted pre-hashed, so no address ends up in a URL. ** ### Parameters @@ -129,9 +129,9 @@ The photo resolves for the currently authenticated user unless `userId` points a | quality | integer | Output image quality between 0 and 100. Defaults to 100. | 100 | | output | string | Output image format. Defaults to 'png'. | png | | rating | string | Maximum image rating to fetch from Gravatar/Libravatar. Defaults to 'g'. | g | -| userId | string | User ID to resolve the photo for. Defaults to 'current()' for the currently authenticated user. | current() | -| emailHash | string | SHA256 hash of the lowercase, trimmed email address to look up on Gravatar and Libravatar instead of the user's own photo sources. Pass the hash, never the address itself. | | -| name | string | Name to render initials from instead of the user's own photo sources. Max length: 128 chars. | | +| userId | string | User ID to resolve the photo for. Pass 'current()' for the currently authenticated user. When omitted, the session user is used only if no emailHash and no name is passed. | | +| emailHash | string | SHA256 hash of the lowercase, trimmed email address to look up on Gravatar and Libravatar instead of the user's own email. Pass the hash, never the address itself. | | +| name | string | Name to render initials from instead of the user's own name. Max length: 128 chars. | | ```http request diff --git a/docs/documentsdb.md b/docs/documentsdb.md index 6f585a2..49e3a09 100644 --- a/docs/documentsdb.md +++ b/docs/documentsdb.md @@ -282,6 +282,7 @@ POST https://cloud.appwrite.io/v1/documentsdb/{databaseId}/collections/{collecti | documentId | string | Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars. | | | data | object | Document data as JSON object. | {} | | permissions | array | An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). | | +| transactionId | string | Transaction ID for staging the operation. | | ```http request @@ -297,6 +298,7 @@ POST https://cloud.appwrite.io/v1/documentsdb/{databaseId}/collections/{collecti | databaseId | string | **Required** Database ID. | | | collectionId | string | **Required** Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection). Make sure to define attributes before creating documents. | | | documents | array | Array of documents data as JSON objects. | [] | +| transactionId | string | Transaction ID for staging the operation. | | ```http request diff --git a/docs/examples/documentsdb/create-document.md b/docs/examples/documentsdb/create-document.md index dc88f16..4b894f4 100644 --- a/docs/examples/documentsdb/create-document.md +++ b/docs/examples/documentsdb/create-document.md @@ -24,6 +24,7 @@ $result = $documentsDB->createDocument( 'age' => 30, 'isAdmin' => false ], - permissions: [Permission::read(Role::any())] // optional + permissions: [Permission::read(Role::any())], // optional + transactionId: '' // optional ); ``` diff --git a/docs/examples/documentsdb/create-documents.md b/docs/examples/documentsdb/create-documents.md index e8f0ded..ec6a435 100644 --- a/docs/examples/documentsdb/create-documents.md +++ b/docs/examples/documentsdb/create-documents.md @@ -14,6 +14,7 @@ $documentsDB = new DocumentsDB($client); $result = $documentsDB->createDocuments( databaseId: '', collectionId: '', - documents: [] + documents: [], + transactionId: '' // optional ); ``` diff --git a/docs/examples/project/update-o-auth-2-cloudflare.md b/docs/examples/project/update-o-auth-2-cloudflare.md new file mode 100644 index 0000000..95e98cb --- /dev/null +++ b/docs/examples/project/update-o-auth-2-cloudflare.md @@ -0,0 +1,19 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setKey(''); // Your secret API key + +$project = new Project($client); + +$result = $project->updateOAuth2Cloudflare( + clientId: '', // optional + clientSecret: '', // optional + enabled: false // optional +); +``` diff --git a/docs/examples/project/update-o-auth-2-resend.md b/docs/examples/project/update-o-auth-2-resend.md new file mode 100644 index 0000000..89c0ba7 --- /dev/null +++ b/docs/examples/project/update-o-auth-2-resend.md @@ -0,0 +1,19 @@ +```php +setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + ->setProject('') // Your project ID + ->setKey(''); // Your secret API key + +$project = new Project($client); + +$result = $project->updateOAuth2Resend( + clientId: '', // optional + clientSecret: '', // optional + enabled: false // optional +); +``` diff --git a/docs/examples/tablesdb/cutover-migration.md b/docs/examples/tablesdb/create-cutover.md similarity index 91% rename from docs/examples/tablesdb/cutover-migration.md rename to docs/examples/tablesdb/create-cutover.md index 624449e..b07aa3c 100644 --- a/docs/examples/tablesdb/cutover-migration.md +++ b/docs/examples/tablesdb/create-cutover.md @@ -11,7 +11,7 @@ $client = (new Client()) $tablesDB = new TablesDB($client); -$result = $tablesDB->cutoverMigration( +$result = $tablesDB->createCutover( databaseId: '', migrationId: '' ); diff --git a/docs/examples/vectorsdb/create-document.md b/docs/examples/vectorsdb/create-document.md index e024efe..b97f81e 100644 --- a/docs/examples/vectorsdb/create-document.md +++ b/docs/examples/vectorsdb/create-document.md @@ -28,6 +28,7 @@ $result = $vectorsDB->createDocument( 'key' => 'value' ] ], - permissions: [Permission::read(Role::any())] // optional + permissions: [Permission::read(Role::any())], // optional + transactionId: '' // optional ); ``` diff --git a/docs/examples/vectorsdb/create-documents.md b/docs/examples/vectorsdb/create-documents.md index 07b5894..2d1c9c2 100644 --- a/docs/examples/vectorsdb/create-documents.md +++ b/docs/examples/vectorsdb/create-documents.md @@ -14,6 +14,7 @@ $vectorsDB = new VectorsDB($client); $result = $vectorsDB->createDocuments( databaseId: '', collectionId: '', - documents: [] + documents: [], + transactionId: '' // optional ); ``` diff --git a/docs/mongo.md b/docs/mongo.md index 7ec032f..084c9fc 100644 --- a/docs/mongo.md +++ b/docs/mongo.md @@ -307,7 +307,7 @@ DELETE https://cloud.appwrite.io/v1/mongo/{databaseId}/branches/{branchId} PATCH https://cloud.appwrite.io/v1/mongo/{databaseId}/credentials ``` -** Rotate the primary connection credentials for a dedicated database. Generates a new password and updates the database atomically. Previous credentials stop working immediately. Returns the database with a refreshed connection string carrying the new password. ** +** Queue a rotation of the primary connection credentials for a dedicated database. A hibernated database is woken by the worker before rotation. List database operations until the returned operation reaches a terminal status, then fetch the database again for the refreshed connection string. ** ### Parameters diff --git a/docs/mysql.md b/docs/mysql.md index c88ce40..ced7ece 100644 --- a/docs/mysql.md +++ b/docs/mysql.md @@ -307,7 +307,7 @@ DELETE https://cloud.appwrite.io/v1/mysql/{databaseId}/branches/{branchId} PATCH https://cloud.appwrite.io/v1/mysql/{databaseId}/credentials ``` -** Rotate the primary connection credentials for a dedicated database. Generates a new password and updates the database atomically. Previous credentials stop working immediately. Returns the database with a refreshed connection string carrying the new password. ** +** Queue a rotation of the primary connection credentials for a dedicated database. A hibernated database is woken by the worker before rotation. List database operations until the returned operation reaches a terminal status, then fetch the database again for the refreshed connection string. ** ### Parameters diff --git a/docs/postgresql.md b/docs/postgresql.md index 982d69f..d1af41f 100644 --- a/docs/postgresql.md +++ b/docs/postgresql.md @@ -307,7 +307,7 @@ DELETE https://cloud.appwrite.io/v1/postgresql/{databaseId}/branches/{branchId} PATCH https://cloud.appwrite.io/v1/postgresql/{databaseId}/credentials ``` -** Rotate the primary connection credentials for a dedicated database. Generates a new password and updates the database atomically. Previous credentials stop working immediately. Returns the database with a refreshed connection string carrying the new password. ** +** Queue a rotation of the primary connection credentials for a dedicated database. A hibernated database is woken by the worker before rotation. List database operations until the returned operation reaches a terminal status, then fetch the database again for the refreshed connection string. ** ### Parameters diff --git a/docs/project.md b/docs/project.md index dc09a76..85e7a37 100644 --- a/docs/project.md +++ b/docs/project.md @@ -363,6 +363,21 @@ PATCH https://cloud.appwrite.io/v1/project/oauth2/box | enabled | boolean | OAuth2 sign-in method status. Set to true to enable new session creation. Setting to true will trigger end-to-end credentials validation, and will throw if the credentials are invalid. | | +```http request +PATCH https://cloud.appwrite.io/v1/project/oauth2/cloudflare +``` + +** Update the project OAuth2 Cloudflare configuration. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| clientId | string | 'Client ID' of Cloudflare OAuth2 app. For example: 4b866000000000000000000000c9e4e2 | | +| clientSecret | string | 'Client Secret' of Cloudflare OAuth2 app. For example: cfoc_5Q6YRl0000000000000000000000000000000000003d214f | | +| enabled | boolean | OAuth2 sign-in method status. Set to true to enable new session creation. Setting to true will trigger end-to-end credentials validation, and will throw if the credentials are invalid. | | + + ```http request PATCH https://cloud.appwrite.io/v1/project/oauth2/dailymotion ``` @@ -707,6 +722,21 @@ PATCH https://cloud.appwrite.io/v1/project/oauth2/podio | enabled | boolean | OAuth2 sign-in method status. Set to true to enable new session creation. Setting to true will trigger end-to-end credentials validation, and will throw if the credentials are invalid. | | +```http request +PATCH https://cloud.appwrite.io/v1/project/oauth2/resend +``` + +** Update the project OAuth2 Resend configuration. ** + +### Parameters + +| Field Name | Type | Description | Default | +| --- | --- | --- | --- | +| clientId | string | 'Client ID' of Resend OAuth2 app. For example: f47ac10b-58cc-4372-a567-0e02b2c3d479 | | +| clientSecret | string | 'Client Secret' of Resend OAuth2 app. For example: 9c1e4b00000000000000000000000000000000000000000000000000a72d5f4 | | +| enabled | boolean | OAuth2 sign-in method status. Set to true to enable new session creation. Setting to true will trigger end-to-end credentials validation, and will throw if the credentials are invalid. | | + + ```http request PATCH https://cloud.appwrite.io/v1/project/oauth2/salesforce ``` diff --git a/docs/tablesdb.md b/docs/tablesdb.md index bdd7882..4e1b191 100644 --- a/docs/tablesdb.md +++ b/docs/tablesdb.md @@ -238,7 +238,7 @@ DELETE https://cloud.appwrite.io/v1/tablesdb/{databaseId}/migrations/{migrationI ```http request -POST https://cloud.appwrite.io/v1/tablesdb/{databaseId}/migrations/{migrationId}/cutover +POST https://cloud.appwrite.io/v1/tablesdb/{databaseId}/migrations/{migrationId}/cutovers ``` ** Cut a verified TablesDB migration over to its dedicated compute. Only applies to a migration created with `autoCutover` disabled, which waits at `ready_to_cutover` until this is called. The routing flip happens shortly after this returns, with a brief read-only window. One call buys one attempt: a cutover that fails a check returns the migration to `verifying` and parks it again, so call this once more to retry. ** diff --git a/docs/vectorsdb.md b/docs/vectorsdb.md index c2db2cb..d63113b 100644 --- a/docs/vectorsdb.md +++ b/docs/vectorsdb.md @@ -281,6 +281,7 @@ POST https://cloud.appwrite.io/v1/vectorsdb/{databaseId}/collections/{collection | documentId | string | Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars. | | | data | object | Document data as JSON object. | {} | | permissions | array | An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). | | +| transactionId | string | Transaction ID for staging the operation. | | ```http request @@ -296,6 +297,7 @@ POST https://cloud.appwrite.io/v1/vectorsdb/{databaseId}/collections/{collection | databaseId | string | **Required** Database ID. | | | collectionId | string | **Required** Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection). Make sure to define attributes before creating documents. | | | documents | array | Array of documents data as JSON objects. | [] | +| transactionId | string | Transaction ID for staging the operation. | | ```http request diff --git a/src/Appwrite/Client.php b/src/Appwrite/Client.php index 562580f..0335259 100644 --- a/src/Appwrite/Client.php +++ b/src/Appwrite/Client.php @@ -43,11 +43,11 @@ class Client * */ protected array $headers = [ - 'user-agent' => 'AppwritePHPSDK/30.0.0-rc.1 ()', + 'user-agent' => 'AppwritePHPSDK/30.0.0 ()', 'x-sdk-name' => 'PHP', 'x-sdk-platform' => 'server', 'x-sdk-language' => 'php', - 'x-sdk-version' => '30.0.0-rc.1', + 'x-sdk-version' => '30.0.0', ]; /** @@ -110,7 +110,7 @@ class Client public function __construct() { $this->requestFactory = new RequestFactory(); - $this->headers['X-Appwrite-Response-Format'] = '1.9.6'; + $this->headers['X-Appwrite-Response-Format'] = '2.0.0'; } /** diff --git a/src/Appwrite/Enums/OAuthProvider.php b/src/Appwrite/Enums/OAuthProvider.php index 69900ef..0a6cf91 100644 --- a/src/Appwrite/Enums/OAuthProvider.php +++ b/src/Appwrite/Enums/OAuthProvider.php @@ -18,6 +18,7 @@ class OAuthProvider implements JsonSerializable, Stringable private static OAuthProvider $BITBUCKET; private static OAuthProvider $BITLY; private static OAuthProvider $BOX; + private static OAuthProvider $CLOUDFLARE; private static OAuthProvider $DAILYMOTION; private static OAuthProvider $DISCORD; private static OAuthProvider $DISQUS; @@ -40,6 +41,7 @@ class OAuthProvider implements JsonSerializable, Stringable private static OAuthProvider $PAYPAL; private static OAuthProvider $PAYPALSANDBOX; private static OAuthProvider $PODIO; + private static OAuthProvider $RESEND; private static OAuthProvider $SALESFORCE; private static OAuthProvider $SLACK; private static OAuthProvider $SPOTIFY; @@ -123,6 +125,12 @@ public static function BOX(): OAuthProvider return self::$BOX; } + public static function CLOUDFLARE(): OAuthProvider + { + self::$CLOUDFLARE ??= new OAuthProvider('cloudflare'); + + return self::$CLOUDFLARE; + } public static function DAILYMOTION(): OAuthProvider { self::$DAILYMOTION ??= new OAuthProvider('dailymotion'); @@ -255,6 +263,12 @@ public static function PODIO(): OAuthProvider return self::$PODIO; } + public static function RESEND(): OAuthProvider + { + self::$RESEND ??= new OAuthProvider('resend'); + + return self::$RESEND; + } public static function SALESFORCE(): OAuthProvider { self::$SALESFORCE ??= new OAuthProvider('salesforce'); @@ -352,6 +366,7 @@ public static function from(string $value): self 'bitbucket' => self::BITBUCKET(), 'bitly' => self::BITLY(), 'box' => self::BOX(), + 'cloudflare' => self::CLOUDFLARE(), 'dailymotion' => self::DAILYMOTION(), 'discord' => self::DISCORD(), 'disqus' => self::DISQUS(), @@ -374,6 +389,7 @@ public static function from(string $value): self 'paypal' => self::PAYPAL(), 'paypalSandbox' => self::PAYPALSANDBOX(), 'podio' => self::PODIO(), + 'resend' => self::RESEND(), 'salesforce' => self::SALESFORCE(), 'slack' => self::SLACK(), 'spotify' => self::SPOTIFY(), diff --git a/src/Appwrite/Enums/ProjectKeyScopes.php b/src/Appwrite/Enums/ProjectKeyScopes.php index 408eb9c..cdab332 100644 --- a/src/Appwrite/Enums/ProjectKeyScopes.php +++ b/src/Appwrite/Enums/ProjectKeyScopes.php @@ -57,12 +57,16 @@ class ProjectKeyScopes implements JsonSerializable, Stringable private static ProjectKeyScopes $DOCUMENTSDBCOLLECTIONSWRITE; private static ProjectKeyScopes $DOCUMENTSDBDOCUMENTSREAD; private static ProjectKeyScopes $DOCUMENTSDBDOCUMENTSWRITE; + private static ProjectKeyScopes $DOCUMENTSDBINDEXESREAD; + private static ProjectKeyScopes $DOCUMENTSDBINDEXESWRITE; private static ProjectKeyScopes $VECTORSDBREAD; private static ProjectKeyScopes $VECTORSDBWRITE; private static ProjectKeyScopes $VECTORSDBCOLLECTIONSREAD; private static ProjectKeyScopes $VECTORSDBCOLLECTIONSWRITE; private static ProjectKeyScopes $VECTORSDBDOCUMENTSREAD; private static ProjectKeyScopes $VECTORSDBDOCUMENTSWRITE; + private static ProjectKeyScopes $VECTORSDBINDEXESREAD; + private static ProjectKeyScopes $VECTORSDBINDEXESWRITE; private static ProjectKeyScopes $BUCKETSREAD; private static ProjectKeyScopes $BUCKETSWRITE; private static ProjectKeyScopes $FILESREAD; @@ -429,6 +433,18 @@ public static function DOCUMENTSDBDOCUMENTSWRITE(): ProjectKeyScopes return self::$DOCUMENTSDBDOCUMENTSWRITE; } + public static function DOCUMENTSDBINDEXESREAD(): ProjectKeyScopes + { + self::$DOCUMENTSDBINDEXESREAD ??= new ProjectKeyScopes('documentsdb.indexes.read'); + + return self::$DOCUMENTSDBINDEXESREAD; + } + public static function DOCUMENTSDBINDEXESWRITE(): ProjectKeyScopes + { + self::$DOCUMENTSDBINDEXESWRITE ??= new ProjectKeyScopes('documentsdb.indexes.write'); + + return self::$DOCUMENTSDBINDEXESWRITE; + } public static function VECTORSDBREAD(): ProjectKeyScopes { self::$VECTORSDBREAD ??= new ProjectKeyScopes('vectorsdb.read'); @@ -465,6 +481,18 @@ public static function VECTORSDBDOCUMENTSWRITE(): ProjectKeyScopes return self::$VECTORSDBDOCUMENTSWRITE; } + public static function VECTORSDBINDEXESREAD(): ProjectKeyScopes + { + self::$VECTORSDBINDEXESREAD ??= new ProjectKeyScopes('vectorsdb.indexes.read'); + + return self::$VECTORSDBINDEXESREAD; + } + public static function VECTORSDBINDEXESWRITE(): ProjectKeyScopes + { + self::$VECTORSDBINDEXESWRITE ??= new ProjectKeyScopes('vectorsdb.indexes.write'); + + return self::$VECTORSDBINDEXESWRITE; + } public static function BUCKETSREAD(): ProjectKeyScopes { self::$BUCKETSREAD ??= new ProjectKeyScopes('buckets.read'); @@ -895,12 +923,16 @@ public static function from(string $value): self 'documentsdb.collections.write' => self::DOCUMENTSDBCOLLECTIONSWRITE(), 'documentsdb.documents.read' => self::DOCUMENTSDBDOCUMENTSREAD(), 'documentsdb.documents.write' => self::DOCUMENTSDBDOCUMENTSWRITE(), + 'documentsdb.indexes.read' => self::DOCUMENTSDBINDEXESREAD(), + 'documentsdb.indexes.write' => self::DOCUMENTSDBINDEXESWRITE(), 'vectorsdb.read' => self::VECTORSDBREAD(), 'vectorsdb.write' => self::VECTORSDBWRITE(), 'vectorsdb.collections.read' => self::VECTORSDBCOLLECTIONSREAD(), 'vectorsdb.collections.write' => self::VECTORSDBCOLLECTIONSWRITE(), 'vectorsdb.documents.read' => self::VECTORSDBDOCUMENTSREAD(), 'vectorsdb.documents.write' => self::VECTORSDBDOCUMENTSWRITE(), + 'vectorsdb.indexes.read' => self::VECTORSDBINDEXESREAD(), + 'vectorsdb.indexes.write' => self::VECTORSDBINDEXESWRITE(), 'buckets.read' => self::BUCKETSREAD(), 'buckets.write' => self::BUCKETSWRITE(), 'files.read' => self::FILESREAD(), diff --git a/src/Appwrite/Enums/ProjectOAuthProviderId.php b/src/Appwrite/Enums/ProjectOAuthProviderId.php index 71c58df..1d797c8 100644 --- a/src/Appwrite/Enums/ProjectOAuthProviderId.php +++ b/src/Appwrite/Enums/ProjectOAuthProviderId.php @@ -18,6 +18,7 @@ class ProjectOAuthProviderId implements JsonSerializable, Stringable private static ProjectOAuthProviderId $BITBUCKET; private static ProjectOAuthProviderId $BITLY; private static ProjectOAuthProviderId $BOX; + private static ProjectOAuthProviderId $CLOUDFLARE; private static ProjectOAuthProviderId $DAILYMOTION; private static ProjectOAuthProviderId $DISCORD; private static ProjectOAuthProviderId $DISQUS; @@ -40,6 +41,7 @@ class ProjectOAuthProviderId implements JsonSerializable, Stringable private static ProjectOAuthProviderId $PAYPAL; private static ProjectOAuthProviderId $PAYPALSANDBOX; private static ProjectOAuthProviderId $PODIO; + private static ProjectOAuthProviderId $RESEND; private static ProjectOAuthProviderId $SALESFORCE; private static ProjectOAuthProviderId $SLACK; private static ProjectOAuthProviderId $SPOTIFY; @@ -123,6 +125,12 @@ public static function BOX(): ProjectOAuthProviderId return self::$BOX; } + public static function CLOUDFLARE(): ProjectOAuthProviderId + { + self::$CLOUDFLARE ??= new ProjectOAuthProviderId('cloudflare'); + + return self::$CLOUDFLARE; + } public static function DAILYMOTION(): ProjectOAuthProviderId { self::$DAILYMOTION ??= new ProjectOAuthProviderId('dailymotion'); @@ -255,6 +263,12 @@ public static function PODIO(): ProjectOAuthProviderId return self::$PODIO; } + public static function RESEND(): ProjectOAuthProviderId + { + self::$RESEND ??= new ProjectOAuthProviderId('resend'); + + return self::$RESEND; + } public static function SALESFORCE(): ProjectOAuthProviderId { self::$SALESFORCE ??= new ProjectOAuthProviderId('salesforce'); @@ -352,6 +366,7 @@ public static function from(string $value): self 'bitbucket' => self::BITBUCKET(), 'bitly' => self::BITLY(), 'box' => self::BOX(), + 'cloudflare' => self::CLOUDFLARE(), 'dailymotion' => self::DAILYMOTION(), 'discord' => self::DISCORD(), 'disqus' => self::DISQUS(), @@ -374,6 +389,7 @@ public static function from(string $value): self 'paypal' => self::PAYPAL(), 'paypalSandbox' => self::PAYPALSANDBOX(), 'podio' => self::PODIO(), + 'resend' => self::RESEND(), 'salesforce' => self::SALESFORCE(), 'slack' => self::SLACK(), 'spotify' => self::SPOTIFY(), diff --git a/src/Appwrite/Models/BillingPlan.php b/src/Appwrite/Models/BillingPlan.php index 73d1a0d..add36cb 100644 --- a/src/Appwrite/Models/BillingPlan.php +++ b/src/Appwrite/Models/BillingPlan.php @@ -84,6 +84,7 @@ * @param int|null $members members * @param int|null $activityLogs activity log days * @param array|null $usageLogsIntervals usage log time intervals allowed for this plan (e.g. 15m, 1h, 1d). + * @param array|null $usageAggregateOnlyMetrics metrics this plan only records as a total. they cannot be broken down by dimension or filtered, because the stored events cover a fraction of the real traffic. * @param bool|null $backupsEnabled does plan support backup policies. * @param int|null $backupPolicies how many policies does plan support * @param BillingPlanLimits|null $limits plan specific limits @@ -157,6 +158,7 @@ public function __construct( public ?int $members = null, public ?int $activityLogs = null, public ?array $usageLogsIntervals = null, + public ?array $usageAggregateOnlyMetrics = null, public ?bool $backupsEnabled = null, public ?int $backupPolicies = null, public ?BillingPlanLimits $limits = null, @@ -427,6 +429,7 @@ functions: $data['functions'], members: $data['members'] ?? null, activityLogs: $data['activityLogs'] ?? null, usageLogsIntervals: $data['usageLogsIntervals'] ?? null, + usageAggregateOnlyMetrics: $data['usageAggregateOnlyMetrics'] ?? null, backupsEnabled: $data['backupsEnabled'] ?? null, backupPolicies: $data['backupPolicies'] ?? null, limits: array_key_exists('limits', $data) ? static::hydrateTypedValue(BillingPlanLimits::class, $data['limits'], true) : null, @@ -478,6 +481,7 @@ public function toArray(): array 'activityLogs' => static::serializeValue($this->activityLogs), 'usageLogs' => static::serializeValue($this->usageLogs), 'usageLogsIntervals' => static::serializeValue($this->usageLogsIntervals), + 'usageAggregateOnlyMetrics' => static::serializeValue($this->usageAggregateOnlyMetrics), 'projectInactivityDays' => static::serializeValue($this->projectInactivityDays), 'alertLimit' => static::serializeValue($this->alertLimit), 'usage' => static::serializeValue($this->usage), diff --git a/src/Appwrite/Models/DedicatedDatabase.php b/src/Appwrite/Models/DedicatedDatabase.php index a1560b5..28ad149 100644 --- a/src/Appwrite/Models/DedicatedDatabase.php +++ b/src/Appwrite/Models/DedicatedDatabase.php @@ -25,11 +25,12 @@ * @param string $engine database engine: postgresql, mysql, or mongodb. null until the backing reports one. * @param string $version database engine version. * @param string $specification specification identifier. - * @param string $backend database backend provider. possible values: prisma, edge. + * @param string $backend database backend provider. possible values: edge. * @param string $hostname database hostname for connections. * @param int $connectionPort database port for connections. derived from the engine when the backing has not reported one yet. * @param string $connectionUser database username for connections. * @param string $connectionPassword database password for connections. + * @param int $credentialGeneration committed generation of the primary connection credentials. null until the rotation contract has been initialized. * @param string $connectionString full database connection string (uri format). * @param bool $ssl whether ssl/tls is required for client connections. * @param string $status database status. possible values: provisioning, ready, inactive, paused, failed, deleted, restoring, scaling. @@ -80,6 +81,7 @@ public function __construct( public int $connectionPort, public string $connectionUser, public string $connectionPassword, + public int $credentialGeneration, public string $connectionString, public bool $ssl, public string $status, @@ -164,6 +166,9 @@ public static function from(array $data): static if (!array_key_exists('connectionPassword', $data)) { throw new \InvalidArgumentException('Missing required field "connectionPassword" for ' . static::class . '.'); } + if (!array_key_exists('credentialGeneration', $data)) { + throw new \InvalidArgumentException('Missing required field "credentialGeneration" for ' . static::class . '.'); + } if (!array_key_exists('connectionString', $data)) { throw new \InvalidArgumentException('Missing required field "connectionString" for ' . static::class . '.'); } @@ -276,6 +281,7 @@ public static function from(array $data): static connectionPort: $data['connectionPort'], connectionUser: $data['connectionUser'], connectionPassword: $data['connectionPassword'], + credentialGeneration: $data['credentialGeneration'], connectionString: $data['connectionString'], ssl: $data['ssl'], status: $data['status'], @@ -333,6 +339,7 @@ public function toArray(): array 'connectionPort' => static::serializeValue($this->connectionPort), 'connectionUser' => static::serializeValue($this->connectionUser), 'connectionPassword' => static::serializeValue($this->connectionPassword), + 'credentialGeneration' => static::serializeValue($this->credentialGeneration), 'connectionString' => static::serializeValue($this->connectionString), 'ssl' => static::serializeValue($this->ssl), 'status' => static::serializeValue($this->status), diff --git a/src/Appwrite/Models/DedicatedDatabaseOperation.php b/src/Appwrite/Models/DedicatedDatabaseOperation.php index d52ebcf..228f5b5 100644 --- a/src/Appwrite/Models/DedicatedDatabaseOperation.php +++ b/src/Appwrite/Models/DedicatedDatabaseOperation.php @@ -19,7 +19,7 @@ * @param string $id operation id. * @param string $createdAt operation creation time in iso 8601 format. * @param string $databaseId database id the operation ran against. - * @param string $type operation type, such as provision, update, restore, pausing, resuming, failover, backup-create or cross-region-enable. + * @param string $type operation type, such as provision, update, credentials-update, restore, pausing, resuming, failover, backup-create or cross-region-enable. * @param string $status operation status. possible values: queued (accepted and waiting to resume), running (in progress), completed (finished successfully), failed (ended in an error). * @param int $attempts number of times this operation has been attempted. * @param string $errorCode machine-readable failure code. `interrupted` marks an attempt that ended before its outcome could be confirmed. diff --git a/src/Appwrite/Models/FrameworkAdapter.php b/src/Appwrite/Models/FrameworkAdapter.php index b1e6b01..82727ba 100644 --- a/src/Appwrite/Models/FrameworkAdapter.php +++ b/src/Appwrite/Models/FrameworkAdapter.php @@ -20,14 +20,14 @@ * @param string $installCommand default command to download dependencies. * @param string $buildCommand default command to build site into output directory. * @param string $outputDirectory default output directory of build. - * @param string $fallbackFile name of fallback file to use instead of 404 page. if null, appwrite 404 page will be displayed. + * @param string|null $fallbackFile name of fallback file to use instead of 404 page. if null, appwrite 404 page will be displayed. */ public function __construct( public string $key, public string $installCommand, public string $buildCommand, public string $outputDirectory, - public string $fallbackFile + public ?string $fallbackFile = null ) { } @@ -48,16 +48,13 @@ public static function from(array $data): static if (!array_key_exists('outputDirectory', $data)) { throw new \InvalidArgumentException('Missing required field "outputDirectory" for ' . static::class . '.'); } - if (!array_key_exists('fallbackFile', $data)) { - throw new \InvalidArgumentException('Missing required field "fallbackFile" for ' . static::class . '.'); - } return new static( key: $data['key'], installCommand: $data['installCommand'], buildCommand: $data['buildCommand'], outputDirectory: $data['outputDirectory'], - fallbackFile: $data['fallbackFile'] + fallbackFile: $data['fallbackFile'] ?? null ); } diff --git a/src/Appwrite/Models/OAuth2Cloudflare.php b/src/Appwrite/Models/OAuth2Cloudflare.php new file mode 100644 index 0000000..1d5e973 --- /dev/null +++ b/src/Appwrite/Models/OAuth2Cloudflare.php @@ -0,0 +1,70 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('$id', $data)) { + throw new \InvalidArgumentException('Missing required field "$id" for ' . static::class . '.'); + } + if (!array_key_exists('enabled', $data)) { + throw new \InvalidArgumentException('Missing required field "enabled" for ' . static::class . '.'); + } + if (!array_key_exists('clientId', $data)) { + throw new \InvalidArgumentException('Missing required field "clientId" for ' . static::class . '.'); + } + if (!array_key_exists('clientSecret', $data)) { + throw new \InvalidArgumentException('Missing required field "clientSecret" for ' . static::class . '.'); + } + + return new static( + id: $data['$id'], + enabled: $data['enabled'], + clientId: $data['clientId'], + clientSecret: $data['clientSecret'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + return [ + '$id' => static::serializeValue($this->id), + 'enabled' => static::serializeValue($this->enabled), + 'clientId' => static::serializeValue($this->clientId), + 'clientSecret' => static::serializeValue($this->clientSecret) + ]; + } +} diff --git a/src/Appwrite/Models/OAuth2Resend.php b/src/Appwrite/Models/OAuth2Resend.php new file mode 100644 index 0000000..5e741b9 --- /dev/null +++ b/src/Appwrite/Models/OAuth2Resend.php @@ -0,0 +1,70 @@ + $data + */ + public static function from(array $data): static + { + if (!array_key_exists('$id', $data)) { + throw new \InvalidArgumentException('Missing required field "$id" for ' . static::class . '.'); + } + if (!array_key_exists('enabled', $data)) { + throw new \InvalidArgumentException('Missing required field "enabled" for ' . static::class . '.'); + } + if (!array_key_exists('clientId', $data)) { + throw new \InvalidArgumentException('Missing required field "clientId" for ' . static::class . '.'); + } + if (!array_key_exists('clientSecret', $data)) { + throw new \InvalidArgumentException('Missing required field "clientSecret" for ' . static::class . '.'); + } + + return new static( + id: $data['$id'], + enabled: $data['enabled'], + clientId: $data['clientId'], + clientSecret: $data['clientSecret'] + ); + } + + /** + * @return array + */ + public function toArray(): array + { + return [ + '$id' => static::serializeValue($this->id), + 'enabled' => static::serializeValue($this->enabled), + 'clientId' => static::serializeValue($this->clientId), + 'clientSecret' => static::serializeValue($this->clientSecret) + ]; + } +} diff --git a/src/Appwrite/Services/Avatars.php b/src/Appwrite/Services/Avatars.php index 39ef900..7d59419 100644 --- a/src/Appwrite/Services/Avatars.php +++ b/src/Appwrite/Services/Avatars.php @@ -300,13 +300,16 @@ public function getInitials(?string $name = null, ?int $width = null, ?int $heig * OAuth2 identity photo, Gravatar, Libravatar, Appwrite Initials, built-in * static fallback. * - * The photo resolves for the currently authenticated user unless `userId` - * points at another user. Passing `emailHash` and/or `name` resolves the - * avatar from those values alone: the hash is looked up on Gravatar and - * Libravatar, the name is rendered as initials, and the user's own identity - * photos, email, and name leave the chain so they never shadow the avatar - * being asked for. Emails are only ever accepted pre-hashed, so no address - * ends up in a URL. + * Passing `userId` — `current()` for the authenticated user — resolves + * the photo from everything known about that user: identity photos, email, + * and name. An explicit `emailHash` or `name` then overrides just that value, + * and the user's remaining sources stay in the chain. Without `userId`, + * passing `emailHash` and/or `name` resolves the avatar from those values + * alone: the hash is looked up on Gravatar and Libravatar, the name is + * rendered as initials, and the session user stays out of the chain so their + * own photo never shadows the avatar being asked for. When nothing is passed, + * the photo resolves for the currently authenticated user. Emails are only + * ever accepted pre-hashed, so no address ends up in a URL. * * @throws AppwriteException */ diff --git a/src/Appwrite/Services/DocumentsDB.php b/src/Appwrite/Services/DocumentsDB.php index 3919a7d..7947b14 100644 --- a/src/Appwrite/Services/DocumentsDB.php +++ b/src/Appwrite/Services/DocumentsDB.php @@ -746,7 +746,7 @@ public function listDocuments(string $databaseId, string $collectionId, ?array $ * * @throws AppwriteException */ - public function createDocument(string $databaseId, string $collectionId, string $documentId, array $data, ?array $permissions = null): \Appwrite\Models\Document + public function createDocument(string $databaseId, string $collectionId, string $documentId, array $data, ?array $permissions = null, ?string $transactionId = null): \Appwrite\Models\Document { $apiPath = str_replace( ['{databaseId}', '{collectionId}'], @@ -764,6 +764,10 @@ public function createDocument(string $databaseId, string $collectionId, string $apiParams['permissions'] = $permissions; } + if (!is_null($transactionId)) { + $apiParams['transactionId'] = $transactionId; + } + $apiHeaders = []; $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); $apiHeaders['content-type'] = 'application/json'; @@ -791,7 +795,7 @@ public function createDocument(string $databaseId, string $collectionId, string * * @throws AppwriteException */ - public function createDocuments(string $databaseId, string $collectionId, array $documents): \Appwrite\Models\DocumentList + public function createDocuments(string $databaseId, string $collectionId, array $documents, ?string $transactionId = null): \Appwrite\Models\DocumentList { $apiPath = str_replace( ['{databaseId}', '{collectionId}'], @@ -804,6 +808,10 @@ public function createDocuments(string $databaseId, string $collectionId, array $apiParams['collectionId'] = $collectionId; $apiParams['documents'] = $documents; + if (!is_null($transactionId)) { + $apiParams['transactionId'] = $transactionId; + } + $apiHeaders = []; $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); $apiHeaders['content-type'] = 'application/json'; diff --git a/src/Appwrite/Services/Mongo.php b/src/Appwrite/Services/Mongo.php index 71c6eda..21771ec 100644 --- a/src/Appwrite/Services/Mongo.php +++ b/src/Appwrite/Services/Mongo.php @@ -797,14 +797,14 @@ public function deleteBranch(string $databaseId, string $branchId): \Appwrite\Mo } /** - * Rotate the primary connection credentials for a dedicated database. - * Generates a new password and updates the database atomically. Previous - * credentials stop working immediately. Returns the database with a refreshed - * connection string carrying the new password. + * Queue a rotation of the primary connection credentials for a dedicated + * database. A hibernated database is woken by the worker before rotation. + * List database operations until the returned operation reaches a terminal + * status, then fetch the database again for the refreshed connection string. * * @throws AppwriteException */ - public function updateCredentials(string $databaseId): \Appwrite\Models\DedicatedDatabase + public function updateCredentials(string $databaseId): \Appwrite\Models\DedicatedDatabaseOperation { $apiPath = str_replace( ['{databaseId}'], @@ -831,7 +831,7 @@ public function updateCredentials(string $databaseId): \Appwrite\Models\Dedicate throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); } - return \Appwrite\Models\DedicatedDatabase::from($response); + return \Appwrite\Models\DedicatedDatabaseOperation::from($response); } /** diff --git a/src/Appwrite/Services/Mysql.php b/src/Appwrite/Services/Mysql.php index 36cb6f8..95f4cd3 100644 --- a/src/Appwrite/Services/Mysql.php +++ b/src/Appwrite/Services/Mysql.php @@ -797,14 +797,14 @@ public function deleteBranch(string $databaseId, string $branchId): \Appwrite\Mo } /** - * Rotate the primary connection credentials for a dedicated database. - * Generates a new password and updates the database atomically. Previous - * credentials stop working immediately. Returns the database with a refreshed - * connection string carrying the new password. + * Queue a rotation of the primary connection credentials for a dedicated + * database. A hibernated database is woken by the worker before rotation. + * List database operations until the returned operation reaches a terminal + * status, then fetch the database again for the refreshed connection string. * * @throws AppwriteException */ - public function updateCredentials(string $databaseId): \Appwrite\Models\DedicatedDatabase + public function updateCredentials(string $databaseId): \Appwrite\Models\DedicatedDatabaseOperation { $apiPath = str_replace( ['{databaseId}'], @@ -831,7 +831,7 @@ public function updateCredentials(string $databaseId): \Appwrite\Models\Dedicate throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); } - return \Appwrite\Models\DedicatedDatabase::from($response); + return \Appwrite\Models\DedicatedDatabaseOperation::from($response); } /** diff --git a/src/Appwrite/Services/Postgresql.php b/src/Appwrite/Services/Postgresql.php index 5ed1127..536e573 100644 --- a/src/Appwrite/Services/Postgresql.php +++ b/src/Appwrite/Services/Postgresql.php @@ -797,14 +797,14 @@ public function deleteBranch(string $databaseId, string $branchId): \Appwrite\Mo } /** - * Rotate the primary connection credentials for a dedicated database. - * Generates a new password and updates the database atomically. Previous - * credentials stop working immediately. Returns the database with a refreshed - * connection string carrying the new password. + * Queue a rotation of the primary connection credentials for a dedicated + * database. A hibernated database is woken by the worker before rotation. + * List database operations until the returned operation reaches a terminal + * status, then fetch the database again for the refreshed connection string. * * @throws AppwriteException */ - public function updateCredentials(string $databaseId): \Appwrite\Models\DedicatedDatabase + public function updateCredentials(string $databaseId): \Appwrite\Models\DedicatedDatabaseOperation { $apiPath = str_replace( ['{databaseId}'], @@ -831,7 +831,7 @@ public function updateCredentials(string $databaseId): \Appwrite\Models\Dedicate throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); } - return \Appwrite\Models\DedicatedDatabase::from($response); + return \Appwrite\Models\DedicatedDatabaseOperation::from($response); } /** diff --git a/src/Appwrite/Services/Project.php b/src/Appwrite/Services/Project.php index 04a2c15..1829218 100644 --- a/src/Appwrite/Services/Project.php +++ b/src/Appwrite/Services/Project.php @@ -961,6 +961,43 @@ public function updateOAuth2Box(?string $clientId = null, ?string $clientSecret return \Appwrite\Models\OAuth2Box::from($response); } + /** + * Update the project OAuth2 Cloudflare configuration. + * + * @throws AppwriteException + */ + public function updateOAuth2Cloudflare(?string $clientId = null, ?string $clientSecret = null, ?bool $enabled = null): \Appwrite\Models\OAuth2Cloudflare + { + $apiPath = str_replace( + [], + [], + '/project/oauth2/cloudflare' + ); + + $apiParams = []; + $apiParams['clientId'] = $clientId; + $apiParams['clientSecret'] = $clientSecret; + $apiParams['enabled'] = $enabled; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_PATCH, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\OAuth2Cloudflare::from($response); + } + /** * Update the project OAuth2 Dailymotion configuration. * @@ -1789,6 +1826,43 @@ public function updateOAuth2Podio(?string $clientId = null, ?string $clientSecre return \Appwrite\Models\OAuth2Podio::from($response); } + /** + * Update the project OAuth2 Resend configuration. + * + * @throws AppwriteException + */ + public function updateOAuth2Resend(?string $clientId = null, ?string $clientSecret = null, ?bool $enabled = null): \Appwrite\Models\OAuth2Resend + { + $apiPath = str_replace( + [], + [], + '/project/oauth2/resend' + ); + + $apiParams = []; + $apiParams['clientId'] = $clientId; + $apiParams['clientSecret'] = $clientSecret; + $apiParams['enabled'] = $enabled; + + $apiHeaders = []; + $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); + $apiHeaders['content-type'] = 'application/json'; + $apiHeaders['accept'] = 'application/json'; + + $response = $this->client->call( + Client::METHOD_PATCH, + $apiPath, + $apiHeaders, + $apiParams + ); + + if (!is_array($response)) { + throw new \UnexpectedValueException('Expected array response when hydrating a response model.'); + } + + return \Appwrite\Models\OAuth2Resend::from($response); + } + /** * Update the project OAuth2 Salesforce configuration. * @@ -2276,7 +2350,7 @@ public function updateOAuth2Zoom(?string $clientId = null, ?string $clientSecret * * @throws AppwriteException */ - public function getOAuth2Provider(ProjectOAuthProviderId $providerId): \Appwrite\Models\OAuth2Github|\Appwrite\Models\OAuth2Discord|\Appwrite\Models\OAuth2Figma|\Appwrite\Models\OAuth2Dropbox|\Appwrite\Models\OAuth2Dailymotion|\Appwrite\Models\OAuth2Bitbucket|\Appwrite\Models\OAuth2Bitly|\Appwrite\Models\OAuth2Box|\Appwrite\Models\OAuth2Autodesk|\Appwrite\Models\OAuth2Google|\Appwrite\Models\OAuth2Zoom|\Appwrite\Models\OAuth2Zoho|\Appwrite\Models\OAuth2Yandex|\Appwrite\Models\OAuth2X|\Appwrite\Models\OAuth2WordPress|\Appwrite\Models\OAuth2Twitch|\Appwrite\Models\OAuth2Stripe|\Appwrite\Models\OAuth2Spotify|\Appwrite\Models\OAuth2Slack|\Appwrite\Models\OAuth2Podio|\Appwrite\Models\OAuth2Notion|\Appwrite\Models\OAuth2Salesforce|\Appwrite\Models\OAuth2Yahoo|\Appwrite\Models\OAuth2HuggingFace|\Appwrite\Models\OAuth2Linkedin|\Appwrite\Models\OAuth2Disqus|\Appwrite\Models\OAuth2Amazon|\Appwrite\Models\OAuth2Etsy|\Appwrite\Models\OAuth2Facebook|\Appwrite\Models\OAuth2Tradeshift|\Appwrite\Models\OAuth2Paypal|\Appwrite\Models\OAuth2Gitlab|\Appwrite\Models\OAuth2Authentik|\Appwrite\Models\OAuth2Auth0|\Appwrite\Models\OAuth2FusionAuth|\Appwrite\Models\OAuth2Keycloak|\Appwrite\Models\OAuth2Oidc|\Appwrite\Models\OAuth2Apple|\Appwrite\Models\OAuth2Okta|\Appwrite\Models\OAuth2Kick|\Appwrite\Models\OAuth2Microsoft + public function getOAuth2Provider(ProjectOAuthProviderId $providerId): \Appwrite\Models\OAuth2Github|\Appwrite\Models\OAuth2Discord|\Appwrite\Models\OAuth2Figma|\Appwrite\Models\OAuth2Dropbox|\Appwrite\Models\OAuth2Dailymotion|\Appwrite\Models\OAuth2Bitbucket|\Appwrite\Models\OAuth2Bitly|\Appwrite\Models\OAuth2Box|\Appwrite\Models\OAuth2Autodesk|\Appwrite\Models\OAuth2Google|\Appwrite\Models\OAuth2Zoom|\Appwrite\Models\OAuth2Zoho|\Appwrite\Models\OAuth2Yandex|\Appwrite\Models\OAuth2X|\Appwrite\Models\OAuth2WordPress|\Appwrite\Models\OAuth2Twitch|\Appwrite\Models\OAuth2Stripe|\Appwrite\Models\OAuth2Spotify|\Appwrite\Models\OAuth2Slack|\Appwrite\Models\OAuth2Podio|\Appwrite\Models\OAuth2Notion|\Appwrite\Models\OAuth2Salesforce|\Appwrite\Models\OAuth2Yahoo|\Appwrite\Models\OAuth2HuggingFace|\Appwrite\Models\OAuth2Resend|\Appwrite\Models\OAuth2Cloudflare|\Appwrite\Models\OAuth2Linkedin|\Appwrite\Models\OAuth2Disqus|\Appwrite\Models\OAuth2Amazon|\Appwrite\Models\OAuth2Etsy|\Appwrite\Models\OAuth2Facebook|\Appwrite\Models\OAuth2Tradeshift|\Appwrite\Models\OAuth2Paypal|\Appwrite\Models\OAuth2Gitlab|\Appwrite\Models\OAuth2Authentik|\Appwrite\Models\OAuth2Auth0|\Appwrite\Models\OAuth2FusionAuth|\Appwrite\Models\OAuth2Keycloak|\Appwrite\Models\OAuth2Oidc|\Appwrite\Models\OAuth2Apple|\Appwrite\Models\OAuth2Okta|\Appwrite\Models\OAuth2Kick|\Appwrite\Models\OAuth2Microsoft { $apiPath = str_replace( ['{providerId}'], @@ -2398,6 +2472,14 @@ public function getOAuth2Provider(ProjectOAuthProviderId $providerId): \Appwrite return \Appwrite\Models\OAuth2HuggingFace::from($response); } + if (($response['$id'] ?? null) === 'resend') { + return \Appwrite\Models\OAuth2Resend::from($response); + } + + if (($response['$id'] ?? null) === 'cloudflare') { + return \Appwrite\Models\OAuth2Cloudflare::from($response); + } + if (($response['$id'] ?? null) === 'linkedin') { return \Appwrite\Models\OAuth2Linkedin::from($response); } diff --git a/src/Appwrite/Services/TablesDB.php b/src/Appwrite/Services/TablesDB.php index 8bdd3dd..73dfe40 100644 --- a/src/Appwrite/Services/TablesDB.php +++ b/src/Appwrite/Services/TablesDB.php @@ -669,12 +669,12 @@ public function deleteMigration(string $databaseId, string $migrationId): string * * @throws AppwriteException */ - public function cutoverMigration(string $databaseId, string $migrationId): \Appwrite\Models\DatabaseMigration + public function createCutover(string $databaseId, string $migrationId): \Appwrite\Models\DatabaseMigration { $apiPath = str_replace( ['{databaseId}', '{migrationId}'], [$databaseId, $migrationId], - '/tablesdb/{databaseId}/migrations/{migrationId}/cutover' + '/tablesdb/{databaseId}/migrations/{migrationId}/cutovers' ); $apiParams = []; diff --git a/src/Appwrite/Services/VectorsDB.php b/src/Appwrite/Services/VectorsDB.php index b22626c..45d9820 100644 --- a/src/Appwrite/Services/VectorsDB.php +++ b/src/Appwrite/Services/VectorsDB.php @@ -742,7 +742,7 @@ public function listDocuments(string $databaseId, string $collectionId, ?array $ * * @throws AppwriteException */ - public function createDocument(string $databaseId, string $collectionId, string $documentId, array $data, ?array $permissions = null): \Appwrite\Models\Document + public function createDocument(string $databaseId, string $collectionId, string $documentId, array $data, ?array $permissions = null, ?string $transactionId = null): \Appwrite\Models\Document { $apiPath = str_replace( ['{databaseId}', '{collectionId}'], @@ -760,6 +760,10 @@ public function createDocument(string $databaseId, string $collectionId, string $apiParams['permissions'] = $permissions; } + if (!is_null($transactionId)) { + $apiParams['transactionId'] = $transactionId; + } + $apiHeaders = []; $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); $apiHeaders['content-type'] = 'application/json'; @@ -787,7 +791,7 @@ public function createDocument(string $databaseId, string $collectionId, string * * @throws AppwriteException */ - public function createDocuments(string $databaseId, string $collectionId, array $documents): \Appwrite\Models\DocumentList + public function createDocuments(string $databaseId, string $collectionId, array $documents, ?string $transactionId = null): \Appwrite\Models\DocumentList { $apiPath = str_replace( ['{databaseId}', '{collectionId}'], @@ -800,6 +804,10 @@ public function createDocuments(string $databaseId, string $collectionId, array $apiParams['collectionId'] = $collectionId; $apiParams['documents'] = $documents; + if (!is_null($transactionId)) { + $apiParams['transactionId'] = $transactionId; + } + $apiHeaders = []; $apiHeaders['X-Appwrite-Project'] = $this->client->getConfig('project'); $apiHeaders['content-type'] = 'application/json'; diff --git a/tests/Appwrite/Services/DocumentsDBTest.php b/tests/Appwrite/Services/DocumentsDBTest.php index 3a9ffdd..183fdef 100644 --- a/tests/Appwrite/Services/DocumentsDBTest.php +++ b/tests/Appwrite/Services/DocumentsDBTest.php @@ -979,6 +979,7 @@ public function testMethodCreateFailover(): void "connectionPort" => 5432, "connectionUser" => "appwrite_user", "connectionPassword" => "••••••••", + "credentialGeneration" => 1, "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", "ssl" => true, "status" => "ready", diff --git a/tests/Appwrite/Services/MongoTest.php b/tests/Appwrite/Services/MongoTest.php index e8b0a46..aaa2b0e 100644 --- a/tests/Appwrite/Services/MongoTest.php +++ b/tests/Appwrite/Services/MongoTest.php @@ -40,6 +40,7 @@ public function testMethodList(): void "connectionPort" => 5432, "connectionUser" => "appwrite_user", "connectionPassword" => "••••••••", + "credentialGeneration" => 1, "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", "ssl" => true, "status" => "ready", @@ -104,6 +105,7 @@ public function testMethodCreate(): void "connectionPort" => 5432, "connectionUser" => "appwrite_user", "connectionPassword" => "••••••••", + "credentialGeneration" => 1, "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", "ssl" => true, "status" => "ready", @@ -205,6 +207,7 @@ public function testMethodGet(): void "connectionPort" => 5432, "connectionUser" => "appwrite_user", "connectionPassword" => "••••••••", + "credentialGeneration" => 1, "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", "ssl" => true, "status" => "ready", @@ -269,6 +272,7 @@ public function testMethodUpdate(): void "connectionPort" => 5432, "connectionUser" => "appwrite_user", "connectionPassword" => "••••••••", + "credentialGeneration" => 1, "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", "ssl" => true, "status" => "ready", @@ -632,7 +636,7 @@ public function testMethodListBranches(): void "password" => "********", "ssl" => true, "engine" => "postgresql", - "connectionString" => "postgresql://appwrite:****@db-myproject-mydb-a1b2c3d4.fra.appwrite.center:5432/db-myproject-mydb-a1b2c3d4?sslmode=disable" + "connectionString" => "postgresql://appwrite:****@db-myproject-mydb-a1b2c3d4.fra.appwrite.center:5432/db-myproject-mydb-a1b2c3d4?sslmode=require" ] ] ]; @@ -667,6 +671,7 @@ public function testMethodCreateBranch(): void "connectionPort" => 5432, "connectionUser" => "appwrite_user", "connectionPassword" => "••••••••", + "credentialGeneration" => 1, "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", "ssl" => true, "status" => "ready", @@ -731,6 +736,7 @@ public function testMethodDeleteBranch(): void "connectionPort" => 5432, "connectionUser" => "appwrite_user", "connectionPassword" => "••••••••", + "credentialGeneration" => 1, "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", "ssl" => true, "status" => "ready", @@ -784,50 +790,12 @@ public function testMethodUpdateCredentials(): void $data = [ "\$id" => "5e5ea5c16897e", "\$createdAt" => "2020-10-15T06:38:00.000+00:00", - "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", - "projectId" => "5e5ea5c16897e", - "name" => "My Production Database", - "api" => "postgresql", - "engine" => "postgresql", - "version" => "16", - "specification" => "s-2vcpu-2gb", - "backend" => "edge", - "hostname" => "db-myproject-mydb.fra.appwrite.center", - "connectionPort" => 5432, - "connectionUser" => "appwrite_user", - "connectionPassword" => "••••••••", - "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", - "ssl" => true, - "status" => "ready", - "containerStatus" => "active", - "lifecycleState" => "active", - "idleTimeoutMinutes" => 15, - "cpu" => 2000, - "memory" => 4096, - "storage" => 100, - "storageClass" => "ssd", - "storageMaxGb" => 100, - "nodePool" => "db-pool-4vcpu-8gb", - "replicas" => 2, - "syncMode" => "async", - "networkMaxConnections" => 500, - "networkIdleTimeoutSeconds" => 900, - "networkIPAllowlist" => [], - "backupEnabled" => true, - "pitr" => true, - "pitrRetentionDays" => 14, - "storageAutoscaling" => true, - "storageAutoscalingThresholdPercent" => 85, - "storageAutoscalingMaxGb" => 500, - "maintenanceWindowDay" => "sun", - "maintenanceWindowHourUtc" => 3, - "metricsEnabled" => true, - "sqlApiEnabled" => true, - "sqlApiAllowedStatements" => [], - "sqlApiMaxRows" => 10000, - "sqlApiMaxBytes" => 10485760, - "sqlApiTimeoutSeconds" => 30, - "error" => "[ERROR]" + "databaseId" => "5e5ea5c16897e", + "type" => "update", + "status" => "completed", + "attempts" => 1, + "errorCode" => "Interrupted", + "errorMessage" => "[ERRORMESSAGE]" ]; $this->client @@ -841,7 +809,7 @@ public function testMethodUpdateCredentials(): void "" ); - $this->assertInstanceOf(\Appwrite\Models\DedicatedDatabase::class, $response); + $this->assertInstanceOf(\Appwrite\Models\DedicatedDatabaseOperation::class, $response); } public function testMethodCreateFailover(): void { @@ -860,6 +828,7 @@ public function testMethodCreateFailover(): void "connectionPort" => 5432, "connectionUser" => "appwrite_user", "connectionPassword" => "••••••••", + "credentialGeneration" => 1, "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", "ssl" => true, "status" => "ready", @@ -924,6 +893,7 @@ public function testMethodUpdateMaintenance(): void "connectionPort" => 5432, "connectionUser" => "appwrite_user", "connectionPassword" => "••••••••", + "credentialGeneration" => 1, "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", "ssl" => true, "status" => "ready", @@ -990,6 +960,7 @@ public function testMethodCreateMigration(): void "connectionPort" => 5432, "connectionUser" => "appwrite_user", "connectionPassword" => "••••••••", + "credentialGeneration" => 1, "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", "ssl" => true, "status" => "ready", @@ -1278,6 +1249,7 @@ public function testMethodCreateUpgrade(): void "connectionPort" => 5432, "connectionUser" => "appwrite_user", "connectionPassword" => "••••••••", + "credentialGeneration" => 1, "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", "ssl" => true, "status" => "ready", diff --git a/tests/Appwrite/Services/MysqlTest.php b/tests/Appwrite/Services/MysqlTest.php index 04478bf..85f067a 100644 --- a/tests/Appwrite/Services/MysqlTest.php +++ b/tests/Appwrite/Services/MysqlTest.php @@ -40,6 +40,7 @@ public function testMethodList(): void "connectionPort" => 5432, "connectionUser" => "appwrite_user", "connectionPassword" => "••••••••", + "credentialGeneration" => 1, "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", "ssl" => true, "status" => "ready", @@ -104,6 +105,7 @@ public function testMethodCreate(): void "connectionPort" => 5432, "connectionUser" => "appwrite_user", "connectionPassword" => "••••••••", + "credentialGeneration" => 1, "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", "ssl" => true, "status" => "ready", @@ -205,6 +207,7 @@ public function testMethodGet(): void "connectionPort" => 5432, "connectionUser" => "appwrite_user", "connectionPassword" => "••••••••", + "credentialGeneration" => 1, "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", "ssl" => true, "status" => "ready", @@ -269,6 +272,7 @@ public function testMethodUpdate(): void "connectionPort" => 5432, "connectionUser" => "appwrite_user", "connectionPassword" => "••••••••", + "credentialGeneration" => 1, "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", "ssl" => true, "status" => "ready", @@ -632,7 +636,7 @@ public function testMethodListBranches(): void "password" => "********", "ssl" => true, "engine" => "postgresql", - "connectionString" => "postgresql://appwrite:****@db-myproject-mydb-a1b2c3d4.fra.appwrite.center:5432/db-myproject-mydb-a1b2c3d4?sslmode=disable" + "connectionString" => "postgresql://appwrite:****@db-myproject-mydb-a1b2c3d4.fra.appwrite.center:5432/db-myproject-mydb-a1b2c3d4?sslmode=require" ] ] ]; @@ -667,6 +671,7 @@ public function testMethodCreateBranch(): void "connectionPort" => 5432, "connectionUser" => "appwrite_user", "connectionPassword" => "••••••••", + "credentialGeneration" => 1, "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", "ssl" => true, "status" => "ready", @@ -731,6 +736,7 @@ public function testMethodDeleteBranch(): void "connectionPort" => 5432, "connectionUser" => "appwrite_user", "connectionPassword" => "••••••••", + "credentialGeneration" => 1, "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", "ssl" => true, "status" => "ready", @@ -784,50 +790,12 @@ public function testMethodUpdateCredentials(): void $data = [ "\$id" => "5e5ea5c16897e", "\$createdAt" => "2020-10-15T06:38:00.000+00:00", - "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", - "projectId" => "5e5ea5c16897e", - "name" => "My Production Database", - "api" => "postgresql", - "engine" => "postgresql", - "version" => "16", - "specification" => "s-2vcpu-2gb", - "backend" => "edge", - "hostname" => "db-myproject-mydb.fra.appwrite.center", - "connectionPort" => 5432, - "connectionUser" => "appwrite_user", - "connectionPassword" => "••••••••", - "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", - "ssl" => true, - "status" => "ready", - "containerStatus" => "active", - "lifecycleState" => "active", - "idleTimeoutMinutes" => 15, - "cpu" => 2000, - "memory" => 4096, - "storage" => 100, - "storageClass" => "ssd", - "storageMaxGb" => 100, - "nodePool" => "db-pool-4vcpu-8gb", - "replicas" => 2, - "syncMode" => "async", - "networkMaxConnections" => 500, - "networkIdleTimeoutSeconds" => 900, - "networkIPAllowlist" => [], - "backupEnabled" => true, - "pitr" => true, - "pitrRetentionDays" => 14, - "storageAutoscaling" => true, - "storageAutoscalingThresholdPercent" => 85, - "storageAutoscalingMaxGb" => 500, - "maintenanceWindowDay" => "sun", - "maintenanceWindowHourUtc" => 3, - "metricsEnabled" => true, - "sqlApiEnabled" => true, - "sqlApiAllowedStatements" => [], - "sqlApiMaxRows" => 10000, - "sqlApiMaxBytes" => 10485760, - "sqlApiTimeoutSeconds" => 30, - "error" => "[ERROR]" + "databaseId" => "5e5ea5c16897e", + "type" => "update", + "status" => "completed", + "attempts" => 1, + "errorCode" => "Interrupted", + "errorMessage" => "[ERRORMESSAGE]" ]; $this->client @@ -841,7 +809,7 @@ public function testMethodUpdateCredentials(): void "" ); - $this->assertInstanceOf(\Appwrite\Models\DedicatedDatabase::class, $response); + $this->assertInstanceOf(\Appwrite\Models\DedicatedDatabaseOperation::class, $response); } public function testMethodCreateExecution(): void { @@ -890,6 +858,7 @@ public function testMethodCreateFailover(): void "connectionPort" => 5432, "connectionUser" => "appwrite_user", "connectionPassword" => "••••••••", + "credentialGeneration" => 1, "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", "ssl" => true, "status" => "ready", @@ -954,6 +923,7 @@ public function testMethodUpdateMaintenance(): void "connectionPort" => 5432, "connectionUser" => "appwrite_user", "connectionPassword" => "••••••••", + "credentialGeneration" => 1, "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", "ssl" => true, "status" => "ready", @@ -1020,6 +990,7 @@ public function testMethodCreateMigration(): void "connectionPort" => 5432, "connectionUser" => "appwrite_user", "connectionPassword" => "••••••••", + "credentialGeneration" => 1, "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", "ssl" => true, "status" => "ready", @@ -1364,6 +1335,7 @@ public function testMethodCreateUpgrade(): void "connectionPort" => 5432, "connectionUser" => "appwrite_user", "connectionPassword" => "••••••••", + "credentialGeneration" => 1, "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", "ssl" => true, "status" => "ready", diff --git a/tests/Appwrite/Services/PostgresqlTest.php b/tests/Appwrite/Services/PostgresqlTest.php index 4c90a6e..f420491 100644 --- a/tests/Appwrite/Services/PostgresqlTest.php +++ b/tests/Appwrite/Services/PostgresqlTest.php @@ -40,6 +40,7 @@ public function testMethodList(): void "connectionPort" => 5432, "connectionUser" => "appwrite_user", "connectionPassword" => "••••••••", + "credentialGeneration" => 1, "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", "ssl" => true, "status" => "ready", @@ -104,6 +105,7 @@ public function testMethodCreate(): void "connectionPort" => 5432, "connectionUser" => "appwrite_user", "connectionPassword" => "••••••••", + "credentialGeneration" => 1, "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", "ssl" => true, "status" => "ready", @@ -205,6 +207,7 @@ public function testMethodGet(): void "connectionPort" => 5432, "connectionUser" => "appwrite_user", "connectionPassword" => "••••••••", + "credentialGeneration" => 1, "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", "ssl" => true, "status" => "ready", @@ -269,6 +272,7 @@ public function testMethodUpdate(): void "connectionPort" => 5432, "connectionUser" => "appwrite_user", "connectionPassword" => "••••••••", + "credentialGeneration" => 1, "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", "ssl" => true, "status" => "ready", @@ -632,7 +636,7 @@ public function testMethodListBranches(): void "password" => "********", "ssl" => true, "engine" => "postgresql", - "connectionString" => "postgresql://appwrite:****@db-myproject-mydb-a1b2c3d4.fra.appwrite.center:5432/db-myproject-mydb-a1b2c3d4?sslmode=disable" + "connectionString" => "postgresql://appwrite:****@db-myproject-mydb-a1b2c3d4.fra.appwrite.center:5432/db-myproject-mydb-a1b2c3d4?sslmode=require" ] ] ]; @@ -667,6 +671,7 @@ public function testMethodCreateBranch(): void "connectionPort" => 5432, "connectionUser" => "appwrite_user", "connectionPassword" => "••••••••", + "credentialGeneration" => 1, "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", "ssl" => true, "status" => "ready", @@ -731,6 +736,7 @@ public function testMethodDeleteBranch(): void "connectionPort" => 5432, "connectionUser" => "appwrite_user", "connectionPassword" => "••••••••", + "credentialGeneration" => 1, "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", "ssl" => true, "status" => "ready", @@ -784,50 +790,12 @@ public function testMethodUpdateCredentials(): void $data = [ "\$id" => "5e5ea5c16897e", "\$createdAt" => "2020-10-15T06:38:00.000+00:00", - "\$updatedAt" => "2020-10-15T06:38:00.000+00:00", - "projectId" => "5e5ea5c16897e", - "name" => "My Production Database", - "api" => "postgresql", - "engine" => "postgresql", - "version" => "16", - "specification" => "s-2vcpu-2gb", - "backend" => "edge", - "hostname" => "db-myproject-mydb.fra.appwrite.center", - "connectionPort" => 5432, - "connectionUser" => "appwrite_user", - "connectionPassword" => "••••••••", - "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", - "ssl" => true, - "status" => "ready", - "containerStatus" => "active", - "lifecycleState" => "active", - "idleTimeoutMinutes" => 15, - "cpu" => 2000, - "memory" => 4096, - "storage" => 100, - "storageClass" => "ssd", - "storageMaxGb" => 100, - "nodePool" => "db-pool-4vcpu-8gb", - "replicas" => 2, - "syncMode" => "async", - "networkMaxConnections" => 500, - "networkIdleTimeoutSeconds" => 900, - "networkIPAllowlist" => [], - "backupEnabled" => true, - "pitr" => true, - "pitrRetentionDays" => 14, - "storageAutoscaling" => true, - "storageAutoscalingThresholdPercent" => 85, - "storageAutoscalingMaxGb" => 500, - "maintenanceWindowDay" => "sun", - "maintenanceWindowHourUtc" => 3, - "metricsEnabled" => true, - "sqlApiEnabled" => true, - "sqlApiAllowedStatements" => [], - "sqlApiMaxRows" => 10000, - "sqlApiMaxBytes" => 10485760, - "sqlApiTimeoutSeconds" => 30, - "error" => "[ERROR]" + "databaseId" => "5e5ea5c16897e", + "type" => "update", + "status" => "completed", + "attempts" => 1, + "errorCode" => "Interrupted", + "errorMessage" => "[ERRORMESSAGE]" ]; $this->client @@ -841,7 +809,7 @@ public function testMethodUpdateCredentials(): void "" ); - $this->assertInstanceOf(\Appwrite\Models\DedicatedDatabase::class, $response); + $this->assertInstanceOf(\Appwrite\Models\DedicatedDatabaseOperation::class, $response); } public function testMethodCreateExecution(): void { @@ -918,6 +886,7 @@ public function testMethodCreateExtension(): void "connectionPort" => 5432, "connectionUser" => "appwrite_user", "connectionPassword" => "••••••••", + "credentialGeneration" => 1, "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", "ssl" => true, "status" => "ready", @@ -983,6 +952,7 @@ public function testMethodDeleteExtension(): void "connectionPort" => 5432, "connectionUser" => "appwrite_user", "connectionPassword" => "••••••••", + "credentialGeneration" => 1, "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", "ssl" => true, "status" => "ready", @@ -1048,6 +1018,7 @@ public function testMethodCreateFailover(): void "connectionPort" => 5432, "connectionUser" => "appwrite_user", "connectionPassword" => "••••••••", + "credentialGeneration" => 1, "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", "ssl" => true, "status" => "ready", @@ -1112,6 +1083,7 @@ public function testMethodUpdateMaintenance(): void "connectionPort" => 5432, "connectionUser" => "appwrite_user", "connectionPassword" => "••••••••", + "credentialGeneration" => 1, "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", "ssl" => true, "status" => "ready", @@ -1178,6 +1150,7 @@ public function testMethodCreateMigration(): void "connectionPort" => 5432, "connectionUser" => "appwrite_user", "connectionPassword" => "••••••••", + "credentialGeneration" => 1, "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", "ssl" => true, "status" => "ready", @@ -1522,6 +1495,7 @@ public function testMethodCreateUpgrade(): void "connectionPort" => 5432, "connectionUser" => "appwrite_user", "connectionPassword" => "••••••••", + "credentialGeneration" => 1, "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", "ssl" => true, "status" => "ready", diff --git a/tests/Appwrite/Services/ProjectTest.php b/tests/Appwrite/Services/ProjectTest.php index edd1009..0d0b6cb 100644 --- a/tests/Appwrite/Services/ProjectTest.php +++ b/tests/Appwrite/Services/ProjectTest.php @@ -817,6 +817,26 @@ public function testMethodUpdateOAuth2Box(): void $this->assertInstanceOf(\Appwrite\Models\OAuth2Box::class, $response); } + public function testMethodUpdateOAuth2Cloudflare(): void + { + $data = [ + "\$id" => "github", + "enabled" => true, + "clientId" => "4b866000000000000000000000c9e4e2", + "clientSecret" => "cfoc_5Q6YRl0000000000000000000000000000000000003d214f" + ]; + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->project->updateOAuth2Cloudflare(); + + $this->assertInstanceOf(\Appwrite\Models\OAuth2Cloudflare::class, $response); + } public function testMethodUpdateOAuth2Dailymotion(): void { $data = [ @@ -1270,6 +1290,26 @@ public function testMethodUpdateOAuth2Podio(): void $this->assertInstanceOf(\Appwrite\Models\OAuth2Podio::class, $response); } + public function testMethodUpdateOAuth2Resend(): void + { + $data = [ + "\$id" => "github", + "enabled" => true, + "clientId" => "f47ac10b-58cc-4372-a567-0e02b2c3d479", + "clientSecret" => "9c1e4b00000000000000000000000000000000000000000000000000a72d5f4" + ]; + + $this->client + ->allows()->call(Mockery::any(), Mockery::any(), Mockery::any(), Mockery::any()) + ->andReturn($data); + $this->client + ->allows()->getConfig(Mockery::any()) + ->andReturn(''); + + $response = $this->project->updateOAuth2Resend(); + + $this->assertInstanceOf(\Appwrite\Models\OAuth2Resend::class, $response); + } public function testMethodUpdateOAuth2Salesforce(): void { $data = [ diff --git a/tests/Appwrite/Services/SitesTest.php b/tests/Appwrite/Services/SitesTest.php index b80a554..1dd5e5a 100644 --- a/tests/Appwrite/Services/SitesTest.php +++ b/tests/Appwrite/Services/SitesTest.php @@ -174,8 +174,7 @@ public function testMethodListFrameworks(): void "key" => "static", "installCommand" => "npm install", "buildCommand" => "npm run build", - "outputDirectory" => "./dist", - "fallbackFile" => "index.html" + "outputDirectory" => "./dist" ] ] ] diff --git a/tests/Appwrite/Services/TablesDBTest.php b/tests/Appwrite/Services/TablesDBTest.php index 010f38c..51b883a 100644 --- a/tests/Appwrite/Services/TablesDBTest.php +++ b/tests/Appwrite/Services/TablesDBTest.php @@ -330,6 +330,7 @@ public function testMethodCreateFailover(): void "connectionPort" => 5432, "connectionUser" => "appwrite_user", "connectionPassword" => "••••••••", + "credentialGeneration" => 1, "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", "ssl" => true, "status" => "ready", @@ -507,7 +508,7 @@ public function testMethodDeleteMigration(): void $this->assertSame($data, $response); } - public function testMethodCutoverMigration(): void + public function testMethodCreateCutover(): void { $data = [ "\$id" => "5e5ea5c16897e", @@ -536,7 +537,7 @@ public function testMethodCutoverMigration(): void ->allows()->getConfig(Mockery::any()) ->andReturn(''); - $response = $this->tablesDB->cutoverMigration( + $response = $this->tablesDB->createCutover( "", "" ); diff --git a/tests/Appwrite/Services/VectorsDBTest.php b/tests/Appwrite/Services/VectorsDBTest.php index 5e07adb..fdb22e7 100644 --- a/tests/Appwrite/Services/VectorsDBTest.php +++ b/tests/Appwrite/Services/VectorsDBTest.php @@ -959,6 +959,7 @@ public function testMethodCreateFailover(): void "connectionPort" => 5432, "connectionUser" => "appwrite_user", "connectionPassword" => "••••••••", + "credentialGeneration" => 1, "connectionString" => "postgresql://user:pass@db-myproject-mydb.fra.appwrite.center:5432/postgres?sslmode=require", "ssl" => true, "status" => "ready",