From 9f46f435943021c36f647259ed0830e60b985b5e Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Thu, 21 May 2026 17:13:45 +0400 Subject: [PATCH] feat: support concurrent chunk uploads --- .npmrc | 1 + README.md | 4 +- docs/examples/advisor/delete-report.md | 15 + docs/examples/advisor/get-insight.md | 16 + .../get.md => advisor/get-report.md} | 8 +- docs/examples/advisor/list-insights.md | 17 + docs/examples/advisor/list-reports.md | 16 + docs/examples/avatars/get-screenshot.md | 2 +- docs/examples/console/get-email-template.md | 16 + .../console/list-organization-scopes.md | 13 + docs/examples/presences/delete.md | 15 + docs/examples/presences/get-usage.md | 15 + docs/examples/presences/get.md | 15 + docs/examples/presences/list.md | 17 + docs/examples/presences/update-presence.md | 21 + docs/examples/presences/upsert.md | 20 + docs/examples/project/create-ephemeral-key.md | 4 +- docs/examples/project/create-key.md | 4 +- docs/examples/project/get-email-template.md | 6 +- .../examples/project/get-o-auth-2-provider.md | 4 +- docs/examples/project/get-policy.md | 4 +- docs/examples/project/get.md | 13 + docs/examples/project/update-auth-method.md | 4 +- ...md => update-deny-aliased-email-policy.md} | 2 +- .../examples/project/update-email-template.md | 6 +- docs/examples/project/update-key.md | 4 +- .../project/update-o-auth-2-google.md | 4 +- docs/examples/project/update-protocol.md | 4 +- docs/examples/project/update-service.md | 4 +- docs/examples/project/update-smtp.md | 4 +- docs/examples/projects/create.md | 11 +- docs/examples/usage/list-events.md | 16 + docs/examples/usage/list-gauges.md | 16 + package-lock.json | 4 +- package.json | 2 +- src/channel.ts | 15 +- src/client.ts | 123 +++- src/enums/appwrite-migration-resource.ts | 1 + src/enums/o-auth-provider.ts | 2 - ...th-method.ts => project-auth-method-id.ts} | 2 +- ...e-type.ts => project-email-template-id.ts} | 2 +- ...le.ts => project-email-template-locale.ts} | 2 +- src/enums/project-key-scopes.ts | 96 +++ ...t.ts => project-o-auth-2-google-prompt.ts} | 2 +- src/enums/project-o-auth-provider-id.ts | 47 ++ ...project-policy.ts => project-policy-id.ts} | 2 +- ...{protocol-id.ts => project-protocol-id.ts} | 2 +- .../{service-id.ts => project-service-id.ts} | 3 +- .../{secure.ts => project-smtp-secure.ts} | 2 +- src/enums/query-suggestion-resource.ts | 3 + src/enums/scopes.ts | 7 + src/index.ts | 21 +- src/models.ts | 672 +++++++++++------- src/services/advisor.ts | 309 ++++++++ src/services/console.ts | 84 +++ src/services/presences.ts | 437 ++++++++++++ src/services/project.ts | 307 ++++---- src/services/projects.ts | 128 +--- src/services/realtime.ts | 161 ++++- src/services/usage.ts | 130 ++++ 60 files changed, 2263 insertions(+), 624 deletions(-) create mode 100644 .npmrc create mode 100644 docs/examples/advisor/delete-report.md create mode 100644 docs/examples/advisor/get-insight.md rename docs/examples/{projects/get.md => advisor/get-report.md} (56%) create mode 100644 docs/examples/advisor/list-insights.md create mode 100644 docs/examples/advisor/list-reports.md create mode 100644 docs/examples/console/get-email-template.md create mode 100644 docs/examples/console/list-organization-scopes.md create mode 100644 docs/examples/presences/delete.md create mode 100644 docs/examples/presences/get-usage.md create mode 100644 docs/examples/presences/get.md create mode 100644 docs/examples/presences/list.md create mode 100644 docs/examples/presences/update-presence.md create mode 100644 docs/examples/presences/upsert.md create mode 100644 docs/examples/project/get.md rename docs/examples/project/{update-deny-canonical-email-policy.md => update-deny-aliased-email-policy.md} (83%) create mode 100644 docs/examples/usage/list-events.md create mode 100644 docs/examples/usage/list-gauges.md rename src/enums/{auth-method.ts => project-auth-method-id.ts} (84%) rename src/enums/{email-template-type.ts => project-email-template-id.ts} (86%) rename src/enums/{email-template-locale.ts => project-email-template-locale.ts} (98%) create mode 100644 src/enums/project-key-scopes.ts rename src/enums/{prompt.ts => project-o-auth-2-google-prompt.ts} (67%) create mode 100644 src/enums/project-o-auth-provider-id.ts rename src/enums/{project-policy.ts => project-policy-id.ts} (92%) rename src/enums/{protocol-id.ts => project-protocol-id.ts} (69%) rename src/enums/{service-id.ts => project-service-id.ts} (88%) rename src/enums/{secure.ts => project-smtp-secure.ts} (52%) create mode 100644 src/services/advisor.ts create mode 100644 src/services/presences.ts create mode 100644 src/services/usage.ts diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000..7253a5ce --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +min-release-age=7 diff --git a/README.md b/README.md index daed6142..8cf6f116 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Appwrite Console SDK ![License](https://img.shields.io/github/license/appwrite/sdk-for-console.svg?style=flat-square) -![Version](https://img.shields.io/badge/api%20version-1.9.4-blue.svg?style=flat-square) +![Version](https://img.shields.io/badge/api%20version-1.9.5-blue.svg?style=flat-square) [![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) @@ -33,7 +33,7 @@ import { Client, Account } from "@appwrite.io/console"; To install with a CDN (content delivery network) add the following scripts to the bottom of your tag, but before you use any Appwrite services: ```html - + ``` diff --git a/docs/examples/advisor/delete-report.md b/docs/examples/advisor/delete-report.md new file mode 100644 index 00000000..d549dddb --- /dev/null +++ b/docs/examples/advisor/delete-report.md @@ -0,0 +1,15 @@ +```javascript +import { Client, Advisor } from "@appwrite.io/console"; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const advisor = new Advisor(client); + +const result = await advisor.deleteReport({ + reportId: '' +}); + +console.log(result); +``` diff --git a/docs/examples/advisor/get-insight.md b/docs/examples/advisor/get-insight.md new file mode 100644 index 00000000..bf59a7ed --- /dev/null +++ b/docs/examples/advisor/get-insight.md @@ -0,0 +1,16 @@ +```javascript +import { Client, Advisor } from "@appwrite.io/console"; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const advisor = new Advisor(client); + +const result = await advisor.getInsight({ + reportId: '', + insightId: '' +}); + +console.log(result); +``` diff --git a/docs/examples/projects/get.md b/docs/examples/advisor/get-report.md similarity index 56% rename from docs/examples/projects/get.md rename to docs/examples/advisor/get-report.md index b8856f8e..cdb46636 100644 --- a/docs/examples/projects/get.md +++ b/docs/examples/advisor/get-report.md @@ -1,14 +1,14 @@ ```javascript -import { Client, Projects } from "@appwrite.io/console"; +import { Client, Advisor } from "@appwrite.io/console"; const client = new Client() .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint .setProject(''); // Your project ID -const projects = new Projects(client); +const advisor = new Advisor(client); -const result = await projects.get({ - projectId: '' +const result = await advisor.getReport({ + reportId: '' }); console.log(result); diff --git a/docs/examples/advisor/list-insights.md b/docs/examples/advisor/list-insights.md new file mode 100644 index 00000000..e3d97867 --- /dev/null +++ b/docs/examples/advisor/list-insights.md @@ -0,0 +1,17 @@ +```javascript +import { Client, Advisor } from "@appwrite.io/console"; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const advisor = new Advisor(client); + +const result = await advisor.listInsights({ + reportId: '', + queries: [], // optional + total: false // optional +}); + +console.log(result); +``` diff --git a/docs/examples/advisor/list-reports.md b/docs/examples/advisor/list-reports.md new file mode 100644 index 00000000..5cf736e5 --- /dev/null +++ b/docs/examples/advisor/list-reports.md @@ -0,0 +1,16 @@ +```javascript +import { Client, Advisor } from "@appwrite.io/console"; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const advisor = new Advisor(client); + +const result = await advisor.listReports({ + queries: [], // optional + total: false // optional +}); + +console.log(result); +``` diff --git a/docs/examples/avatars/get-screenshot.md b/docs/examples/avatars/get-screenshot.md index 0f7a9216..cfbe46a3 100644 --- a/docs/examples/avatars/get-screenshot.md +++ b/docs/examples/avatars/get-screenshot.md @@ -20,7 +20,7 @@ const result = avatars.getScreenshot({ userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15', // optional fullpage: true, // optional locale: 'en-US', // optional - timezone: Timezone.AmericaNewYork, // optional + timezone: Timezone.AfricaAbidjan, // optional latitude: 37.7749, // optional longitude: -122.4194, // optional accuracy: 100, // optional diff --git a/docs/examples/console/get-email-template.md b/docs/examples/console/get-email-template.md new file mode 100644 index 00000000..8f16d121 --- /dev/null +++ b/docs/examples/console/get-email-template.md @@ -0,0 +1,16 @@ +```javascript +import { Client, Console, ProjectEmailTemplateId, ProjectEmailTemplateLocale } from "@appwrite.io/console"; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const xconsole = new Console(client); + +const result = await xconsole.getEmailTemplate({ + templateId: ProjectEmailTemplateId.Verification, + locale: ProjectEmailTemplateLocale.Af // optional +}); + +console.log(result); +``` diff --git a/docs/examples/console/list-organization-scopes.md b/docs/examples/console/list-organization-scopes.md new file mode 100644 index 00000000..0253b965 --- /dev/null +++ b/docs/examples/console/list-organization-scopes.md @@ -0,0 +1,13 @@ +```javascript +import { Client, Console } from "@appwrite.io/console"; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const xconsole = new Console(client); + +const result = await xconsole.listOrganizationScopes(); + +console.log(result); +``` diff --git a/docs/examples/presences/delete.md b/docs/examples/presences/delete.md new file mode 100644 index 00000000..7773d3a2 --- /dev/null +++ b/docs/examples/presences/delete.md @@ -0,0 +1,15 @@ +```javascript +import { Client, Presences } from "@appwrite.io/console"; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const presences = new Presences(client); + +const result = await presences.delete({ + presenceId: '' +}); + +console.log(result); +``` diff --git a/docs/examples/presences/get-usage.md b/docs/examples/presences/get-usage.md new file mode 100644 index 00000000..5f954980 --- /dev/null +++ b/docs/examples/presences/get-usage.md @@ -0,0 +1,15 @@ +```javascript +import { Client, Presences, UsageRange } from "@appwrite.io/console"; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const presences = new Presences(client); + +const result = await presences.getUsage({ + range: UsageRange.24h // optional +}); + +console.log(result); +``` diff --git a/docs/examples/presences/get.md b/docs/examples/presences/get.md new file mode 100644 index 00000000..c2d4ca0d --- /dev/null +++ b/docs/examples/presences/get.md @@ -0,0 +1,15 @@ +```javascript +import { Client, Presences } from "@appwrite.io/console"; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const presences = new Presences(client); + +const result = await presences.get({ + presenceId: '' +}); + +console.log(result); +``` diff --git a/docs/examples/presences/list.md b/docs/examples/presences/list.md new file mode 100644 index 00000000..5cd70b44 --- /dev/null +++ b/docs/examples/presences/list.md @@ -0,0 +1,17 @@ +```javascript +import { Client, Presences } from "@appwrite.io/console"; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const presences = new Presences(client); + +const result = await presences.list({ + queries: [], // optional + total: false, // optional + ttl: 0 // optional +}); + +console.log(result); +``` diff --git a/docs/examples/presences/update-presence.md b/docs/examples/presences/update-presence.md new file mode 100644 index 00000000..f735ef39 --- /dev/null +++ b/docs/examples/presences/update-presence.md @@ -0,0 +1,21 @@ +```javascript +import { Client, Presences, Permission, Role } from "@appwrite.io/console"; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const presences = new Presences(client); + +const result = await presences.updatePresence({ + presenceId: '', + userId: '', + status: '', // optional + expiresAt: '2020-10-15T06:38:00.000+00:00', // optional + metadata: {}, // optional + permissions: [Permission.read(Role.any())], // optional + purge: false // optional +}); + +console.log(result); +``` diff --git a/docs/examples/presences/upsert.md b/docs/examples/presences/upsert.md new file mode 100644 index 00000000..fa7d6cba --- /dev/null +++ b/docs/examples/presences/upsert.md @@ -0,0 +1,20 @@ +```javascript +import { Client, Presences, Permission, Role } from "@appwrite.io/console"; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const presences = new Presences(client); + +const result = await presences.upsert({ + presenceId: '', + userId: '', + status: '', + permissions: [Permission.read(Role.any())], // optional + expiresAt: '2020-10-15T06:38:00.000+00:00', // optional + metadata: {} // optional +}); + +console.log(result); +``` diff --git a/docs/examples/project/create-ephemeral-key.md b/docs/examples/project/create-ephemeral-key.md index c41bb809..233f3b8e 100644 --- a/docs/examples/project/create-ephemeral-key.md +++ b/docs/examples/project/create-ephemeral-key.md @@ -1,5 +1,5 @@ ```javascript -import { Client, Project, Scopes } from "@appwrite.io/console"; +import { Client, Project, ProjectKeyScopes } from "@appwrite.io/console"; const client = new Client() .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint @@ -8,7 +8,7 @@ const client = new Client() const project = new Project(client); const result = await project.createEphemeralKey({ - scopes: [Scopes.ProjectRead], + scopes: [ProjectKeyScopes.ProjectRead], duration: 600 }); diff --git a/docs/examples/project/create-key.md b/docs/examples/project/create-key.md index 362d4ca0..b0feb14f 100644 --- a/docs/examples/project/create-key.md +++ b/docs/examples/project/create-key.md @@ -1,5 +1,5 @@ ```javascript -import { Client, Project, Scopes } from "@appwrite.io/console"; +import { Client, Project, ProjectKeyScopes } from "@appwrite.io/console"; const client = new Client() .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint @@ -10,7 +10,7 @@ const project = new Project(client); const result = await project.createKey({ keyId: '', name: '', - scopes: [Scopes.ProjectRead], + scopes: [ProjectKeyScopes.ProjectRead], expire: '2020-10-15T06:38:00.000+00:00' // optional }); diff --git a/docs/examples/project/get-email-template.md b/docs/examples/project/get-email-template.md index 90eb063c..48e3b230 100644 --- a/docs/examples/project/get-email-template.md +++ b/docs/examples/project/get-email-template.md @@ -1,5 +1,5 @@ ```javascript -import { Client, Project, EmailTemplateType, EmailTemplateLocale } from "@appwrite.io/console"; +import { Client, Project, ProjectEmailTemplateId, ProjectEmailTemplateLocale } from "@appwrite.io/console"; const client = new Client() .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint @@ -8,8 +8,8 @@ const client = new Client() const project = new Project(client); const result = await project.getEmailTemplate({ - templateId: EmailTemplateType.Verification, - locale: EmailTemplateLocale.Af // optional + templateId: ProjectEmailTemplateId.Verification, + locale: ProjectEmailTemplateLocale.Af // optional }); console.log(result); diff --git a/docs/examples/project/get-o-auth-2-provider.md b/docs/examples/project/get-o-auth-2-provider.md index cb07b451..ed4d8092 100644 --- a/docs/examples/project/get-o-auth-2-provider.md +++ b/docs/examples/project/get-o-auth-2-provider.md @@ -1,5 +1,5 @@ ```javascript -import { Client, Project, OAuthProvider } from "@appwrite.io/console"; +import { Client, Project, ProjectOAuthProviderId } from "@appwrite.io/console"; const client = new Client() .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint @@ -8,7 +8,7 @@ const client = new Client() const project = new Project(client); const result = await project.getOAuth2Provider({ - providerId: OAuthProvider.Amazon + providerId: ProjectOAuthProviderId.Amazon }); console.log(result); diff --git a/docs/examples/project/get-policy.md b/docs/examples/project/get-policy.md index 45fec071..be06807f 100644 --- a/docs/examples/project/get-policy.md +++ b/docs/examples/project/get-policy.md @@ -1,5 +1,5 @@ ```javascript -import { Client, Project, ProjectPolicy } from "@appwrite.io/console"; +import { Client, Project, ProjectPolicyId } from "@appwrite.io/console"; const client = new Client() .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint @@ -8,7 +8,7 @@ const client = new Client() const project = new Project(client); const result = await project.getPolicy({ - policyId: ProjectPolicy.PasswordDictionary + policyId: ProjectPolicyId.PasswordDictionary }); console.log(result); diff --git a/docs/examples/project/get.md b/docs/examples/project/get.md new file mode 100644 index 00000000..2d4d9f94 --- /dev/null +++ b/docs/examples/project/get.md @@ -0,0 +1,13 @@ +```javascript +import { Client, Project } from "@appwrite.io/console"; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const project = new Project(client); + +const result = await project.get(); + +console.log(result); +``` diff --git a/docs/examples/project/update-auth-method.md b/docs/examples/project/update-auth-method.md index fc0dfdfd..e92f1245 100644 --- a/docs/examples/project/update-auth-method.md +++ b/docs/examples/project/update-auth-method.md @@ -1,5 +1,5 @@ ```javascript -import { Client, Project, AuthMethod } from "@appwrite.io/console"; +import { Client, Project, ProjectAuthMethodId } from "@appwrite.io/console"; const client = new Client() .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint @@ -8,7 +8,7 @@ const client = new Client() const project = new Project(client); const result = await project.updateAuthMethod({ - methodId: AuthMethod.EmailPassword, + methodId: ProjectAuthMethodId.EmailPassword, enabled: false }); diff --git a/docs/examples/project/update-deny-canonical-email-policy.md b/docs/examples/project/update-deny-aliased-email-policy.md similarity index 83% rename from docs/examples/project/update-deny-canonical-email-policy.md rename to docs/examples/project/update-deny-aliased-email-policy.md index 5b223975..f9a253de 100644 --- a/docs/examples/project/update-deny-canonical-email-policy.md +++ b/docs/examples/project/update-deny-aliased-email-policy.md @@ -7,7 +7,7 @@ const client = new Client() const project = new Project(client); -const result = await project.updateDenyCanonicalEmailPolicy({ +const result = await project.updateDenyAliasedEmailPolicy({ enabled: false }); diff --git a/docs/examples/project/update-email-template.md b/docs/examples/project/update-email-template.md index 2ede3e88..7b2951f9 100644 --- a/docs/examples/project/update-email-template.md +++ b/docs/examples/project/update-email-template.md @@ -1,5 +1,5 @@ ```javascript -import { Client, Project, EmailTemplateType, EmailTemplateLocale } from "@appwrite.io/console"; +import { Client, Project, ProjectEmailTemplateId, ProjectEmailTemplateLocale } from "@appwrite.io/console"; const client = new Client() .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint @@ -8,8 +8,8 @@ const client = new Client() const project = new Project(client); const result = await project.updateEmailTemplate({ - templateId: EmailTemplateType.Verification, - locale: EmailTemplateLocale.Af, // optional + templateId: ProjectEmailTemplateId.Verification, + locale: ProjectEmailTemplateLocale.Af, // optional subject: '', // optional message: '', // optional senderName: '', // optional diff --git a/docs/examples/project/update-key.md b/docs/examples/project/update-key.md index 3d3282d4..636419e0 100644 --- a/docs/examples/project/update-key.md +++ b/docs/examples/project/update-key.md @@ -1,5 +1,5 @@ ```javascript -import { Client, Project, Scopes } from "@appwrite.io/console"; +import { Client, Project, ProjectKeyScopes } from "@appwrite.io/console"; const client = new Client() .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint @@ -10,7 +10,7 @@ const project = new Project(client); const result = await project.updateKey({ keyId: '', name: '', - scopes: [Scopes.ProjectRead], + scopes: [ProjectKeyScopes.ProjectRead], expire: '2020-10-15T06:38:00.000+00:00' // optional }); diff --git a/docs/examples/project/update-o-auth-2-google.md b/docs/examples/project/update-o-auth-2-google.md index b4ecf45f..c84567de 100644 --- a/docs/examples/project/update-o-auth-2-google.md +++ b/docs/examples/project/update-o-auth-2-google.md @@ -1,5 +1,5 @@ ```javascript -import { Client, Project, Prompt } from "@appwrite.io/console"; +import { Client, Project, ProjectOAuth2GooglePrompt } from "@appwrite.io/console"; const client = new Client() .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint @@ -10,7 +10,7 @@ const project = new Project(client); const result = await project.updateOAuth2Google({ clientId: '', // optional clientSecret: '', // optional - prompt: [Prompt.None], // optional + prompt: [ProjectOAuth2GooglePrompt.None], // optional enabled: false // optional }); diff --git a/docs/examples/project/update-protocol.md b/docs/examples/project/update-protocol.md index ffdc8e56..e966ad7c 100644 --- a/docs/examples/project/update-protocol.md +++ b/docs/examples/project/update-protocol.md @@ -1,5 +1,5 @@ ```javascript -import { Client, Project, ProtocolId } from "@appwrite.io/console"; +import { Client, Project, ProjectProtocolId } from "@appwrite.io/console"; const client = new Client() .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint @@ -8,7 +8,7 @@ const client = new Client() const project = new Project(client); const result = await project.updateProtocol({ - protocolId: ProtocolId.Rest, + protocolId: ProjectProtocolId.Rest, enabled: false }); diff --git a/docs/examples/project/update-service.md b/docs/examples/project/update-service.md index 460a809f..b3b1ffd3 100644 --- a/docs/examples/project/update-service.md +++ b/docs/examples/project/update-service.md @@ -1,5 +1,5 @@ ```javascript -import { Client, Project, ServiceId } from "@appwrite.io/console"; +import { Client, Project, ProjectServiceId } from "@appwrite.io/console"; const client = new Client() .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint @@ -8,7 +8,7 @@ const client = new Client() const project = new Project(client); const result = await project.updateService({ - serviceId: ServiceId.Account, + serviceId: ProjectServiceId.Account, enabled: false }); diff --git a/docs/examples/project/update-smtp.md b/docs/examples/project/update-smtp.md index 0fefca64..c2236be5 100644 --- a/docs/examples/project/update-smtp.md +++ b/docs/examples/project/update-smtp.md @@ -1,5 +1,5 @@ ```javascript -import { Client, Project, Secure } from "@appwrite.io/console"; +import { Client, Project, ProjectSMTPSecure } from "@appwrite.io/console"; const client = new Client() .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint @@ -16,7 +16,7 @@ const result = await project.updateSMTP({ senderName: '', // optional replyToEmail: 'email@example.com', // optional replyToName: '', // optional - secure: Secure.Tls, // optional + secure: ProjectSMTPSecure.Tls, // optional enabled: false // optional }); diff --git a/docs/examples/projects/create.md b/docs/examples/projects/create.md index eb8749de..21b9488a 100644 --- a/docs/examples/projects/create.md +++ b/docs/examples/projects/create.md @@ -11,16 +11,7 @@ const result = await projects.create({ projectId: '', name: '', teamId: '', - region: Region.Fra, // optional - description: '', // optional - logo: '', // optional - url: 'https://example.com', // optional - legalName: '', // optional - legalCountry: '', // optional - legalState: '', // optional - legalCity: '', // optional - legalAddress: '', // optional - legalTaxId: '' // optional + region: Region.Fra // optional }); console.log(result); diff --git a/docs/examples/usage/list-events.md b/docs/examples/usage/list-events.md new file mode 100644 index 00000000..c8767f08 --- /dev/null +++ b/docs/examples/usage/list-events.md @@ -0,0 +1,16 @@ +```javascript +import { Client, Usage } from "@appwrite.io/console"; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const usage = new Usage(client); + +const result = await usage.listEvents({ + queries: [], // optional + total: false // optional +}); + +console.log(result); +``` diff --git a/docs/examples/usage/list-gauges.md b/docs/examples/usage/list-gauges.md new file mode 100644 index 00000000..fe14dc55 --- /dev/null +++ b/docs/examples/usage/list-gauges.md @@ -0,0 +1,16 @@ +```javascript +import { Client, Usage } from "@appwrite.io/console"; + +const client = new Client() + .setEndpoint('https://.cloud.appwrite.io/v1') // Your API Endpoint + .setProject(''); // Your project ID + +const usage = new Usage(client); + +const result = await usage.listGauges({ + queries: [], // optional + total: false // optional +}); + +console.log(result); +``` diff --git a/package-lock.json b/package-lock.json index 685364d8..bbeff03c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@appwrite.io/console", - "version": "13.0.0", + "version": "13.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@appwrite.io/console", - "version": "13.0.0", + "version": "13.1.0", "license": "BSD-3-Clause", "dependencies": { "json-bigint": "1.0.0" diff --git a/package.json b/package.json index 93313761..17c9e470 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "@appwrite.io/console", "homepage": "https://appwrite.io/support", "description": "Appwrite is an open-source self-hosted backend server that abstracts and simplifies complex and repetitive development tasks behind a very simple REST API", - "version": "13.0.0", + "version": "13.1.0", "license": "BSD-3-Clause", "main": "dist/cjs/sdk.js", "exports": { diff --git a/src/channel.ts b/src/channel.ts index a5d7ee38..d4618a36 100644 --- a/src/channel.ts +++ b/src/channel.ts @@ -11,9 +11,10 @@ interface Func { _fn: any } interface Execution { _exec: any } interface Team { _team: any } interface Membership { _mem: any } +interface Presence { _presence: any } interface Resolved { _res: any } -type Actionable = Document | Row | File | Team | Membership; +type Actionable = Document | Row | File | Team | Membership | Presence; function normalize(id: string): string { if (id === undefined || id === null) { @@ -82,7 +83,7 @@ export class Channel { return this.resolve("create"); } - upsert(this: Channel): Channel { + upsert(this: Channel): Channel { return this.resolve("upsert"); } @@ -123,6 +124,10 @@ export class Channel { return new Channel(["memberships", normalize(id)]); } + static presence(id: string) { + return new Channel(["presences", normalize(id)]); + } + static account(): string { return "account"; } @@ -151,8 +156,12 @@ export class Channel { static memberships(): string { return "memberships"; } + + static presences(): string { + return "presences"; + } } // Export types for backward compatibility with realtime -export type ActionableChannel = Channel | Channel | Channel | Channel | Channel | Channel; +export type ActionableChannel = Channel | Channel | Channel | Channel | Channel | Channel | Channel; export type ResolvedChannel = Channel; diff --git a/src/client.ts b/src/client.ts index 8db723f2..97e80fa4 100644 --- a/src/client.ts +++ b/src/client.ts @@ -390,8 +390,8 @@ class Client { 'x-sdk-name': 'Console', 'x-sdk-platform': 'console', 'x-sdk-language': 'web', - 'x-sdk-version': '13.0.0', - 'X-Appwrite-Response-Format': '1.9.4', + 'x-sdk-version': '13.1.0', + 'X-Appwrite-Response-Format': '1.9.5', }; /** @@ -978,41 +978,114 @@ class Client { return await this.call(method, url, headers, originalPayload); } - let start = 0; - let response = null; + const totalChunks = Math.ceil(file.size / Client.CHUNK_SIZE); + + // Upload first chunk alone to get the upload ID + const firstChunkEnd = Math.min(Client.CHUNK_SIZE, file.size); + const firstChunkHeaders = { ...headers, 'content-range': `bytes 0-${firstChunkEnd - 1}/${file.size}` }; + const firstChunk = file.slice(0, firstChunkEnd); + const firstPayload = { ...originalPayload }; + firstPayload[fileParam] = new File([firstChunk], file.name); + + let response = await this.call(method, url, firstChunkHeaders, firstPayload); + const uploadId = response?.$id; + + if (onProgress && typeof onProgress === 'function') { + onProgress({ + $id: uploadId, + progress: Math.round((firstChunkEnd / file.size) * 100), + sizeUploaded: firstChunkEnd, + chunksTotal: totalChunks, + chunksUploaded: 1 + }); + } - while (start < file.size) { - let end = start + Client.CHUNK_SIZE; // Prepare end for the next chunk - if (end >= file.size) { - end = file.size; // Adjust for the last chunk to include the last byte - } + if (totalChunks === 1) { + return response; + } + + // Prepare remaining chunks + const chunks: { index: number; start: number; end: number }[] = []; + for (let i = 1; i < totalChunks; i++) { + const start = i * Client.CHUNK_SIZE; + const end = Math.min(start + Client.CHUNK_SIZE, file.size); + chunks.push({ index: i, start, end }); + } - headers['content-range'] = `bytes ${start}-${end-1}/${file.size}`; - const chunk = file.slice(start, end); + // Upload remaining chunks with max concurrency of 8 + const CONCURRENCY = 8; + let completedCount = 1; + let uploadedBytes = firstChunkEnd; + let lastResponse = response; - let payload = { ...originalPayload }; - payload[fileParam] = new File([chunk], file.name); + const isUploadComplete = (chunkResponse: any) => { + const chunksUploaded = chunkResponse?.chunksUploaded; + const chunksTotal = chunkResponse?.chunksTotal ?? totalChunks; + return typeof chunksUploaded === 'number' && typeof chunksTotal === 'number' && chunksUploaded >= chunksTotal; + }; - response = await this.call(method, url, headers, payload); + const uploadChunk = async (chunk: typeof chunks[0]) => { + const chunkHeaders = { ...headers }; + if (uploadId) { + chunkHeaders['x-appwrite-id'] = uploadId; + } + chunkHeaders['content-range'] = `bytes ${chunk.start}-${chunk.end - 1}/${file.size}`; + + const chunkBlob = file.slice(chunk.start, chunk.end); + const chunkPayload = { ...originalPayload }; + chunkPayload[fileParam] = new File([chunkBlob], file.name); + + const chunkResponse = await this.call(method, url, chunkHeaders, chunkPayload); + + completedCount++; + uploadedBytes += (chunk.end - chunk.start); + + if (isUploadComplete(chunkResponse)) { + lastResponse = chunkResponse; + } if (onProgress && typeof onProgress === 'function') { onProgress({ - $id: response.$id, - progress: Math.round((end / file.size) * 100), - sizeUploaded: end, - chunksTotal: Math.ceil(file.size / Client.CHUNK_SIZE), - chunksUploaded: Math.ceil(end / Client.CHUNK_SIZE) + $id: uploadId, + progress: Math.round((uploadedBytes / file.size) * 100), + sizeUploaded: uploadedBytes, + chunksTotal: totalChunks, + chunksUploaded: completedCount }); } - if (response && response.$id) { - headers['x-appwrite-id'] = response.$id; - } + return chunkResponse; + }; - start = end; - } + await new Promise((resolve, reject) => { + let nextChunk = 0; + let inFlight = 0; + let completed = 0; + + const uploadNext = () => { + if (completed === chunks.length) { + resolve(); + return; + } + + while (inFlight < CONCURRENCY && nextChunk < chunks.length) { + const chunk = chunks[nextChunk++]; + inFlight++; + + uploadChunk(chunk) + .then(() => { + inFlight--; + completed++; + uploadNext(); + }) + .catch(reject); + } + }; + + uploadNext(); + }); - return response; + return lastResponse; } async ping(): Promise { diff --git a/src/enums/appwrite-migration-resource.ts b/src/enums/appwrite-migration-resource.ts index 71acb705..c8dee275 100644 --- a/src/enums/appwrite-migration-resource.ts +++ b/src/enums/appwrite-migration-resource.ts @@ -24,5 +24,6 @@ export enum AppwriteMigrationResource { Site = 'site', Sitedeployment = 'site-deployment', Sitevariable = 'site-variable', + Platform = 'platform', Backuppolicy = 'backup-policy', } \ No newline at end of file diff --git a/src/enums/o-auth-provider.ts b/src/enums/o-auth-provider.ts index 06189633..cc9e340b 100644 --- a/src/enums/o-auth-provider.ts +++ b/src/enums/o-auth-provider.ts @@ -42,6 +42,4 @@ export enum OAuthProvider { Yandex = 'yandex', Zoho = 'zoho', Zoom = 'zoom', - GithubImagine = 'githubImagine', - GoogleImagine = 'googleImagine', } \ No newline at end of file diff --git a/src/enums/auth-method.ts b/src/enums/project-auth-method-id.ts similarity index 84% rename from src/enums/auth-method.ts rename to src/enums/project-auth-method-id.ts index d5800ad9..a05c217e 100644 --- a/src/enums/auth-method.ts +++ b/src/enums/project-auth-method-id.ts @@ -1,4 +1,4 @@ -export enum AuthMethod { +export enum ProjectAuthMethodId { Emailpassword = 'email-password', Magicurl = 'magic-url', Emailotp = 'email-otp', diff --git a/src/enums/email-template-type.ts b/src/enums/project-email-template-id.ts similarity index 86% rename from src/enums/email-template-type.ts rename to src/enums/project-email-template-id.ts index 2a561bf0..b5aba1a6 100644 --- a/src/enums/email-template-type.ts +++ b/src/enums/project-email-template-id.ts @@ -1,4 +1,4 @@ -export enum EmailTemplateType { +export enum ProjectEmailTemplateId { Verification = 'verification', MagicSession = 'magicSession', Recovery = 'recovery', diff --git a/src/enums/email-template-locale.ts b/src/enums/project-email-template-locale.ts similarity index 98% rename from src/enums/email-template-locale.ts rename to src/enums/project-email-template-locale.ts index 82656b89..b5bb7cf8 100644 --- a/src/enums/email-template-locale.ts +++ b/src/enums/project-email-template-locale.ts @@ -1,4 +1,4 @@ -export enum EmailTemplateLocale { +export enum ProjectEmailTemplateLocale { Af = 'af', Arae = 'ar-ae', Arbh = 'ar-bh', diff --git a/src/enums/project-key-scopes.ts b/src/enums/project-key-scopes.ts new file mode 100644 index 00000000..fe019965 --- /dev/null +++ b/src/enums/project-key-scopes.ts @@ -0,0 +1,96 @@ +export enum ProjectKeyScopes { + ProjectRead = 'project.read', + ProjectWrite = 'project.write', + KeysRead = 'keys.read', + KeysWrite = 'keys.write', + PlatformsRead = 'platforms.read', + PlatformsWrite = 'platforms.write', + MocksRead = 'mocks.read', + MocksWrite = 'mocks.write', + PoliciesRead = 'policies.read', + PoliciesWrite = 'policies.write', + ProjectPoliciesRead = 'project.policies.read', + ProjectPoliciesWrite = 'project.policies.write', + TemplatesRead = 'templates.read', + TemplatesWrite = 'templates.write', + Oauth2Read = 'oauth2.read', + Oauth2Write = 'oauth2.write', + UsersRead = 'users.read', + UsersWrite = 'users.write', + SessionsRead = 'sessions.read', + SessionsWrite = 'sessions.write', + TeamsRead = 'teams.read', + TeamsWrite = 'teams.write', + DatabasesRead = 'databases.read', + DatabasesWrite = 'databases.write', + TablesRead = 'tables.read', + TablesWrite = 'tables.write', + ColumnsRead = 'columns.read', + ColumnsWrite = 'columns.write', + IndexesRead = 'indexes.read', + IndexesWrite = 'indexes.write', + RowsRead = 'rows.read', + RowsWrite = 'rows.write', + CollectionsRead = 'collections.read', + CollectionsWrite = 'collections.write', + AttributesRead = 'attributes.read', + AttributesWrite = 'attributes.write', + DocumentsRead = 'documents.read', + DocumentsWrite = 'documents.write', + BucketsRead = 'buckets.read', + BucketsWrite = 'buckets.write', + FilesRead = 'files.read', + FilesWrite = 'files.write', + TokensRead = 'tokens.read', + TokensWrite = 'tokens.write', + FunctionsRead = 'functions.read', + FunctionsWrite = 'functions.write', + ExecutionsRead = 'executions.read', + ExecutionsWrite = 'executions.write', + ExecutionRead = 'execution.read', + ExecutionWrite = 'execution.write', + SitesRead = 'sites.read', + SitesWrite = 'sites.write', + LogRead = 'log.read', + LogWrite = 'log.write', + ProvidersRead = 'providers.read', + ProvidersWrite = 'providers.write', + TopicsRead = 'topics.read', + TopicsWrite = 'topics.write', + SubscribersRead = 'subscribers.read', + SubscribersWrite = 'subscribers.write', + TargetsRead = 'targets.read', + TargetsWrite = 'targets.write', + MessagesRead = 'messages.read', + MessagesWrite = 'messages.write', + RulesRead = 'rules.read', + RulesWrite = 'rules.write', + WebhooksRead = 'webhooks.read', + WebhooksWrite = 'webhooks.write', + LocaleRead = 'locale.read', + AvatarsRead = 'avatars.read', + HealthRead = 'health.read', + AssistantRead = 'assistant.read', + MigrationsRead = 'migrations.read', + MigrationsWrite = 'migrations.write', + SchedulesRead = 'schedules.read', + SchedulesWrite = 'schedules.write', + VcsRead = 'vcs.read', + VcsWrite = 'vcs.write', + InsightsRead = 'insights.read', + InsightsWrite = 'insights.write', + ReportsRead = 'reports.read', + ReportsWrite = 'reports.write', + PresencesRead = 'presences.read', + PresencesWrite = 'presences.write', + BackupsPoliciesRead = 'backups.policies.read', + BackupsPoliciesWrite = 'backups.policies.write', + ArchivesRead = 'archives.read', + ArchivesWrite = 'archives.write', + RestorationsRead = 'restorations.read', + RestorationsWrite = 'restorations.write', + DomainsRead = 'domains.read', + DomainsWrite = 'domains.write', + EventsRead = 'events.read', + UsageRead = 'usage.read', +} \ No newline at end of file diff --git a/src/enums/prompt.ts b/src/enums/project-o-auth-2-google-prompt.ts similarity index 67% rename from src/enums/prompt.ts rename to src/enums/project-o-auth-2-google-prompt.ts index 9bb101fa..75db98ec 100644 --- a/src/enums/prompt.ts +++ b/src/enums/project-o-auth-2-google-prompt.ts @@ -1,4 +1,4 @@ -export enum Prompt { +export enum ProjectOAuth2GooglePrompt { None = 'none', Consent = 'consent', SelectAccount = 'select_account', diff --git a/src/enums/project-o-auth-provider-id.ts b/src/enums/project-o-auth-provider-id.ts new file mode 100644 index 00000000..e35d6ef0 --- /dev/null +++ b/src/enums/project-o-auth-provider-id.ts @@ -0,0 +1,47 @@ +export enum ProjectOAuthProviderId { + Amazon = 'amazon', + Apple = 'apple', + Auth0 = 'auth0', + Authentik = 'authentik', + Autodesk = 'autodesk', + Bitbucket = 'bitbucket', + Bitly = 'bitly', + Box = 'box', + Dailymotion = 'dailymotion', + Discord = 'discord', + Disqus = 'disqus', + Dropbox = 'dropbox', + Etsy = 'etsy', + Facebook = 'facebook', + Figma = 'figma', + Fusionauth = 'fusionauth', + Github = 'github', + Gitlab = 'gitlab', + Google = 'google', + Keycloak = 'keycloak', + Kick = 'kick', + Linkedin = 'linkedin', + Microsoft = 'microsoft', + Notion = 'notion', + Oidc = 'oidc', + Okta = 'okta', + Paypal = 'paypal', + PaypalSandbox = 'paypalSandbox', + Podio = 'podio', + Salesforce = 'salesforce', + Slack = 'slack', + Spotify = 'spotify', + Stripe = 'stripe', + Tradeshift = 'tradeshift', + TradeshiftBox = 'tradeshiftBox', + Twitch = 'twitch', + Wordpress = 'wordpress', + X = 'x', + Yahoo = 'yahoo', + Yammer = 'yammer', + Yandex = 'yandex', + Zoho = 'zoho', + Zoom = 'zoom', + GithubImagine = 'githubImagine', + GoogleImagine = 'googleImagine', +} \ No newline at end of file diff --git a/src/enums/project-policy.ts b/src/enums/project-policy-id.ts similarity index 92% rename from src/enums/project-policy.ts rename to src/enums/project-policy-id.ts index d52bf99a..2031ce9b 100644 --- a/src/enums/project-policy.ts +++ b/src/enums/project-policy-id.ts @@ -1,4 +1,4 @@ -export enum ProjectPolicy { +export enum ProjectPolicyId { Passworddictionary = 'password-dictionary', Passwordhistory = 'password-history', Passwordpersonaldata = 'password-personal-data', diff --git a/src/enums/protocol-id.ts b/src/enums/project-protocol-id.ts similarity index 69% rename from src/enums/protocol-id.ts rename to src/enums/project-protocol-id.ts index 94d9095f..10a89c21 100644 --- a/src/enums/protocol-id.ts +++ b/src/enums/project-protocol-id.ts @@ -1,4 +1,4 @@ -export enum ProtocolId { +export enum ProjectProtocolId { Rest = 'rest', Graphql = 'graphql', Websocket = 'websocket', diff --git a/src/enums/service-id.ts b/src/enums/project-service-id.ts similarity index 88% rename from src/enums/service-id.ts rename to src/enums/project-service-id.ts index 29281124..01f844a8 100644 --- a/src/enums/service-id.ts +++ b/src/enums/project-service-id.ts @@ -1,4 +1,4 @@ -export enum ServiceId { +export enum ProjectServiceId { Account = 'account', Avatars = 'avatars', Databases = 'databases', @@ -16,4 +16,5 @@ export enum ServiceId { Graphql = 'graphql', Migrations = 'migrations', Messaging = 'messaging', + Advisor = 'advisor', } \ No newline at end of file diff --git a/src/enums/secure.ts b/src/enums/project-smtp-secure.ts similarity index 52% rename from src/enums/secure.ts rename to src/enums/project-smtp-secure.ts index 0ab54cf8..d3d37687 100644 --- a/src/enums/secure.ts +++ b/src/enums/project-smtp-secure.ts @@ -1,4 +1,4 @@ -export enum Secure { +export enum ProjectSMTPSecure { Tls = 'tls', Ssl = 'ssl', } \ No newline at end of file diff --git a/src/enums/query-suggestion-resource.ts b/src/enums/query-suggestion-resource.ts index 5663198a..506c3a65 100644 --- a/src/enums/query-suggestion-resource.ts +++ b/src/enums/query-suggestion-resource.ts @@ -27,6 +27,8 @@ export enum QuerySuggestionResource { Repositories = 'repositories', VcsComments = 'vcscomments', VcsCommentLocks = 'vcscommentlocks', + Reports = 'reports', + Insights = 'insights', Users = 'users', Cache = 'cache', Tokens = 'tokens', @@ -70,5 +72,6 @@ export enum QuerySuggestionResource { ResourceTokens = 'resourcetokens', Transactions = 'transactions', TransactionLogs = 'transactionlogs', + PresenceLogs = 'presencelogs', Stats = 'stats', } \ No newline at end of file diff --git a/src/enums/scopes.ts b/src/enums/scopes.ts index 532eb75c..69af4d56 100644 --- a/src/enums/scopes.ts +++ b/src/enums/scopes.ts @@ -78,6 +78,12 @@ export enum Scopes { SchedulesWrite = 'schedules.write', VcsRead = 'vcs.read', VcsWrite = 'vcs.write', + InsightsRead = 'insights.read', + InsightsWrite = 'insights.write', + ReportsRead = 'reports.read', + ReportsWrite = 'reports.write', + PresencesRead = 'presences.read', + PresencesWrite = 'presences.write', BackupsPoliciesRead = 'backups.policies.read', BackupsPoliciesWrite = 'backups.policies.write', ArchivesRead = 'archives.read', @@ -87,6 +93,7 @@ export enum Scopes { DomainsRead = 'domains.read', DomainsWrite = 'domains.write', EventsRead = 'events.read', + UsageRead = 'usage.read', ProjectsRead = 'projects.read', ProjectsWrite = 'projects.write', DevKeysRead = 'devKeys.read', diff --git a/src/index.ts b/src/index.ts index 3acb7d9f..37c577f7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -23,14 +23,17 @@ export { Manager } from './services/manager'; export { Messaging } from './services/messaging'; export { Migrations } from './services/migrations'; export { Organizations } from './services/organizations'; +export { Presences } from './services/presences'; export { Project } from './services/project'; export { Projects } from './services/projects'; export { Proxy } from './services/proxy'; +export { Advisor } from './services/advisor'; export { Sites } from './services/sites'; export { Storage } from './services/storage'; export { TablesDB } from './services/tables-db'; export { Teams } from './services/teams'; export { Tokens } from './services/tokens'; +export { Usage } from './services/usage'; export { Users } from './services/users'; export { Vcs } from './services/vcs'; export { VectorsDB } from './services/vectors-db'; @@ -59,6 +62,8 @@ export { BackupServices } from './enums/backup-services'; export { Platform } from './enums/platform'; export { ConsoleResourceType } from './enums/console-resource-type'; export { QuerySuggestionResource } from './enums/query-suggestion-resource'; +export { ProjectEmailTemplateId } from './enums/project-email-template-id'; +export { ProjectEmailTemplateLocale } from './enums/project-email-template-locale'; export { UsageRange } from './enums/usage-range'; export { RelationshipType } from './enums/relationship-type'; export { RelationMutate } from './enums/relation-mutate'; @@ -84,14 +89,14 @@ export { FirebaseMigrationResource } from './enums/firebase-migration-resource'; export { NHostMigrationResource } from './enums/n-host-migration-resource'; export { SupabaseMigrationResource } from './enums/supabase-migration-resource'; export { Addon } from './enums/addon'; -export { AuthMethod } from './enums/auth-method'; -export { Prompt } from './enums/prompt'; -export { ProjectPolicy } from './enums/project-policy'; -export { ProtocolId } from './enums/protocol-id'; -export { ServiceId } from './enums/service-id'; -export { Secure } from './enums/secure'; -export { EmailTemplateType } from './enums/email-template-type'; -export { EmailTemplateLocale } from './enums/email-template-locale'; +export { ProjectAuthMethodId } from './enums/project-auth-method-id'; +export { ProjectKeyScopes } from './enums/project-key-scopes'; +export { ProjectOAuth2GooglePrompt } from './enums/project-o-auth-2-google-prompt'; +export { ProjectOAuthProviderId } from './enums/project-o-auth-provider-id'; +export { ProjectPolicyId } from './enums/project-policy-id'; +export { ProjectProtocolId } from './enums/project-protocol-id'; +export { ProjectServiceId } from './enums/project-service-id'; +export { ProjectSMTPSecure } from './enums/project-smtp-secure'; export { ProjectUsageRange } from './enums/project-usage-range'; export { Region } from './enums/region'; export { Status } from './enums/status'; diff --git a/src/models.ts b/src/models.ts index cef64a94..152b2bdc 100644 --- a/src/models.ts +++ b/src/models.ts @@ -7,6 +7,9 @@ import { DetectionRuntimeType } from "./enums/detection-runtime-type" import { DeploymentStatus } from "./enums/deployment-status" import { ExecutionTrigger } from "./enums/execution-trigger" import { ExecutionStatus } from "./enums/execution-status" +import { ProjectAuthMethodId } from "./enums/project-auth-method-id" +import { ProjectServiceId } from "./enums/project-service-id" +import { ProjectProtocolId } from "./enums/project-protocol-id" import { OAuth2GooglePrompt } from "./enums/o-auth-2-google-prompt" import { PlatformType } from "./enums/platform-type" import { HealthAntivirusStatus } from "./enums/health-antivirus-status" @@ -53,6 +56,20 @@ export namespace Models { documents: Document[]; } + /** + * Presences List + */ + export type PresenceList = { + /** + * Total number of presences that matched your query. + */ + total: number; + /** + * List of presences. + */ + presences: Presence[]; + } + /** * Tables List */ @@ -817,6 +834,34 @@ export namespace Models { embeddings: Embedding[]; } + /** + * Insights List + */ + export type InsightList = { + /** + * Total number of insights that matched your query. + */ + total: number; + /** + * List of insights. + */ + insights: Insight[]; + } + + /** + * Reports List + */ + export type ReportList = { + /** + * Total number of reports that matched your query. + */ + total: number; + /** + * List of reports. + */ + reports: Report[]; + } + /** * Database */ @@ -848,11 +893,11 @@ export namespace Models { /** * Database backup policies. */ - policies: Index[]; + policies: BackupPolicy[]; /** * Database backup archives. */ - archives: Collection[]; + archives: BackupArchive[]; } /** @@ -3183,6 +3228,49 @@ export namespace Models { [__default]: true; }; + /** + * Presence + */ + export type Presence = { + /** + * Presence ID. + */ + $id: string; + /** + * Presence creation date in ISO 8601 format. + */ + $createdAt: string; + /** + * Presence update date in ISO 8601 format. + */ + $updatedAt: string; + /** + * Presence permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). + */ + $permissions: string[]; + /** + * User ID. + */ + userId: string; + /** + * Presence status. + */ + status?: string; + /** + * Presence source. + */ + source: string; + /** + * Presence expiry date in ISO 8601 format. + */ + expiresAt?: string; + } + + export type DefaultPresence = Presence & { + [key: string]: any; + [__default]: true; + }; + /** * Log */ @@ -3784,6 +3872,10 @@ export namespace Models { * File original size in bytes. */ sizeOriginal: number; + /** + * File actual stored size in bytes after compression and/or encryption. + */ + sizeActual: number; /** * Total number of chunks available */ @@ -5056,132 +5148,12 @@ export namespace Models { * Project name. */ name: string; - /** - * Project description. - */ - description: string; /** * Project team ID. */ teamId: string; /** - * Project logo file ID. - */ - logo: string; - /** - * Project website URL. - */ - url: string; - /** - * Company legal name. - */ - legalName: string; - /** - * Country code in [ISO 3166-1](http://en.wikipedia.org/wiki/ISO_3166-1) two-character format. - */ - legalCountry: string; - /** - * State name. - */ - legalState: string; - /** - * City name. - */ - legalCity: string; - /** - * Company Address. - */ - legalAddress: string; - /** - * Company Tax ID. - */ - legalTaxId: string; - /** - * Session duration in seconds. - */ - authDuration: number; - /** - * Max users allowed. 0 is unlimited. - */ - authLimit: number; - /** - * Max sessions allowed per user. 100 maximum. - */ - authSessionsLimit: number; - /** - * Max allowed passwords in the history list per user. Max passwords limit allowed in history is 20. Use 0 for disabling password history. - */ - authPasswordHistory: number; - /** - * Whether or not to check user's password against most commonly used passwords. - */ - authPasswordDictionary: boolean; - /** - * Whether or not to check the user password for similarity with their personal data. - */ - authPersonalDataCheck: boolean; - /** - * Whether or not to disallow disposable email addresses during signup and email updates. - */ - authDisposableEmails: boolean; - /** - * Whether or not to require canonical email addresses during signup and email updates. - */ - authCanonicalEmails: boolean; - /** - * Whether or not to disallow free email addresses during signup and email updates. - */ - authFreeEmails: boolean; - /** - * An array of mock numbers and their corresponding verification codes (OTPs). - */ - authMockNumbers: MockNumber[]; - /** - * Whether or not to send session alert emails to users. - */ - authSessionAlerts: boolean; - /** - * Whether or not to show user names in the teams membership response. - */ - authMembershipsUserName: boolean; - /** - * Whether or not to show user emails in the teams membership response. - */ - authMembershipsUserEmail: boolean; - /** - * Whether or not to show user MFA status in the teams membership response. - */ - authMembershipsMfa: boolean; - /** - * Whether or not to show user IDs in the teams membership response. - */ - authMembershipsUserId: boolean; - /** - * Whether or not to show user phone numbers in the teams membership response. - */ - authMembershipsUserPhone: boolean; - /** - * Whether or not all existing sessions should be invalidated on password change - */ - authInvalidateSessions: boolean; - /** - * List of Auth Providers. - */ - oAuthProviders: AuthProvider[]; - /** - * List of Platforms. - */ - platforms: (Models.PlatformWeb | Models.PlatformApple | Models.PlatformAndroid | Models.PlatformWindows | Models.PlatformLinux)[]; - /** - * List of Webhooks. - */ - webhooks: Webhook[]; - /** - * List of API Keys. - */ - keys: Key[]; - /** - * List of dev keys. + * Deprecated since 1.9.5: List of dev keys. */ devKeys: DevKey[]; /** @@ -5241,129 +5213,75 @@ export namespace Models { */ status: string; /** - * Email/Password auth method status - */ - authEmailPassword: boolean; - /** - * Magic URL auth method status - */ - authUsersAuthMagicURL: boolean; - /** - * Email (OTP) auth method status - */ - authEmailOtp: boolean; - /** - * Anonymous auth method status - */ - authAnonymous: boolean; - /** - * Invites auth method status - */ - authInvites: boolean; - /** - * JWT auth method status - */ - authJWT: boolean; - /** - * Phone auth method status - */ - authPhone: boolean; - /** - * Account service status - */ - serviceStatusForAccount: boolean; - /** - * Avatars service status - */ - serviceStatusForAvatars: boolean; - /** - * Databases (legacy) service status + * List of auth methods. */ - serviceStatusForDatabases: boolean; + authMethods: ProjectAuthMethod[]; /** - * TablesDB service status + * List of services. */ - serviceStatusForTablesdb: boolean; + services: ProjectService[]; /** - * Locale service status + * List of protocols. */ - serviceStatusForLocale: boolean; + protocols: ProjectProtocol[]; /** - * Health service status - */ - serviceStatusForHealth: boolean; - /** - * Project service status - */ - serviceStatusForProject: boolean; - /** - * Storage service status - */ - serviceStatusForStorage: boolean; - /** - * Teams service status - */ - serviceStatusForTeams: boolean; - /** - * Users service status - */ - serviceStatusForUsers: boolean; - /** - * VCS service status - */ - serviceStatusForVcs: boolean; - /** - * Sites service status - */ - serviceStatusForSites: boolean; - /** - * Functions service status - */ - serviceStatusForFunctions: boolean; - /** - * Proxy service status - */ - serviceStatusForProxy: boolean; - /** - * GraphQL service status + * Project region */ - serviceStatusForGraphql: boolean; + region: string; /** - * Migrations service status + * Billing limits reached */ - serviceStatusForMigrations: boolean; + billingLimits?: BillingLimits; /** - * Messaging service status + * Project blocks information */ - serviceStatusForMessaging: boolean; + blocks: Block[]; /** - * REST protocol status + * Last time the project was accessed via console. Used with plan's projectInactivityDays to determine if project is paused. */ - protocolStatusForRest: boolean; + consoleAccessedAt: string; + } + + /** + * ProjectAuthMethod + */ + export type ProjectAuthMethod = { /** - * GraphQL protocol status + * Auth method ID. */ - protocolStatusForGraphql: boolean; + $id: ProjectAuthMethodId; /** - * Websocket protocol status + * Auth method status. */ - protocolStatusForWebsocket: boolean; + enabled: boolean; + } + + /** + * ProjectService + */ + export type ProjectService = { /** - * Project region + * Service ID. */ - region: string; + $id: ProjectServiceId; /** - * Billing limits reached + * Service status. */ - billingLimits: BillingLimits; + enabled: boolean; + } + + /** + * ProjectProtocol + */ + export type ProjectProtocol = { /** - * Project blocks information + * Protocol ID. */ - blocks: Block[]; + $id: ProjectProtocolId; /** - * Last time the project was accessed via console. Used with plan's projectInactivityDays to determine if project is paused. + * Protocol status. */ - consoleAccessedAt: string; + enabled: boolean; } /** @@ -6668,32 +6586,6 @@ export namespace Models { userMFA: boolean; } - /** - * AuthProvider - */ - export type AuthProvider = { - /** - * Auth Provider. - */ - key: string; - /** - * Auth Provider name. - */ - name: string; - /** - * OAuth 2.0 application ID. - */ - appId: string; - /** - * OAuth 2.0 application secret. Might be JSON string if provider requires extra configuration. This property is write-only and always returned empty. - */ - secret: string; - /** - * Auth Provider is active and can be used to create session. - */ - enabled: boolean; - } - /** * Platform Web */ @@ -7322,6 +7214,24 @@ export namespace Models { sessions: Metric[]; } + /** + * UsagePresence + */ + export type UsagePresence = { + /** + * Time range of the usage stats. + */ + range: string; + /** + * Current total number of online users. + */ + usersOnlineTotal: number; + /** + * Aggregated number of online users per period. + */ + presences: Metric[]; + } + /** * StorageUsage */ @@ -8964,6 +8874,10 @@ export namespace Models { * Number of functions to be migrated. */ function: number; + /** + * Number of platforms to be migrated. + */ + platform: number; /** * Number of sites to be migrated. */ @@ -8992,6 +8906,160 @@ export namespace Models { * Version of the Appwrite instance to be migrated. */ version: string; + /** + * Number of backup policies to be migrated. + */ + backuppolicy: number; + } + + /** + * Insight + */ + export type Insight = { + /** + * Insight ID. + */ + $id: string; + /** + * Insight creation date in ISO 8601 format. + */ + $createdAt: string; + /** + * Insight update date in ISO 8601 format. + */ + $updatedAt: string; + /** + * Parent report ID. Insights always belong to a report. + */ + reportId: string; + /** + * Insight type. One of databaseIndex (legacy), tablesDBIndex, documentsDBIndex, vectorsDBIndex, databasePerformance, sitePerformance, siteAccessibility, siteSeo, functionPerformance. The index types are engine-specific so each CTA can pair the right service+method (databases.createIndex, tablesDB.createIndex, documentsDB.createIndex, or vectorsDB.createIndex). + */ + type: string; + /** + * Insight severity. One of info, warning, critical. + */ + severity: string; + /** + * Insight status. One of active, dismissed. + */ + status: string; + /** + * Type of the resource the insight is about. Plural noun, e.g. databases, sites, functions. + */ + resourceType: string; + /** + * ID of the resource the insight is about. + */ + resourceId: string; + /** + * Plural noun for the parent resource that contains the insight's resource, e.g. an insight about a column index on a table → resourceType=indexes, parentResourceType=tables. Empty when the resource has no parent. + */ + parentResourceType: string; + /** + * ID of the parent resource. Empty when the resource has no parent. + */ + parentResourceId: string; + /** + * Insight title. + */ + title: string; + /** + * Short markdown summary describing the insight. + */ + summary: string; + /** + * List of call-to-action buttons attached to this insight. + */ + ctas: InsightCTA[]; + /** + * Time the insight was analyzed in ISO 8601 format. + */ + analyzedAt?: string; + /** + * Time the insight was dismissed in ISO 8601 format. Empty when not dismissed. + */ + dismissedAt?: string; + /** + * User ID that dismissed the insight. Empty when not dismissed. + */ + dismissedBy?: string; + } + + /** + * InsightCTA + */ + export type InsightCTA = { + /** + * Human-readable label for the CTA, used in UI. + */ + label: string; + /** + * Public API service (SDK namespace) the client should invoke. Must match the engine that owns the resource — for index suggestions: databases (legacy), tablesDB, documentsDB, or vectorsDB. + */ + service: string; + /** + * Public API method on the chosen service the client should invoke when this CTA is triggered. + */ + method: string; + /** + * Parameter map the client should pass to the service method when this CTA is triggered. Keys match the target API's parameter names (e.g. databaseId/tableId/columns for tablesDB, databaseId/collectionId/attributes for the legacy Databases API). + */ + params: object; + } + + /** + * Report + */ + export type Report = { + /** + * Report ID. + */ + $id: string; + /** + * Report creation date in ISO 8601 format. + */ + $createdAt: string; + /** + * Report update date in ISO 8601 format. + */ + $updatedAt: string; + /** + * ID of the third-party app that submitted the report. + */ + appId: string; + /** + * Analyzer that produced this report. e.g. lighthouse, audit, databaseAnalyzer. + */ + type: string; + /** + * Short, human-readable title for the report. + */ + title: string; + /** + * Markdown summary describing the report. + */ + summary: string; + /** + * Plural noun describing what the report analyzes, e.g. databases, sites, urls. + */ + targetType: string; + /** + * Free-form target identifier (URL for lighthouse, resource ID for db). + */ + target: string; + /** + * Categories covered by the report, e.g. performance, accessibility. + */ + categories: string[]; + /** + * Insights nested under this report. + */ + insights: Insight[]; + /** + * Time the report was analyzed in ISO 8601 format. + */ + analyzedAt?: string; } /** @@ -9739,35 +9807,35 @@ export namespace Models { /** * Bandwidth limit */ - bandwidth: number; + bandwidth?: number; /** * Storage limit */ - storage: number; + storage?: number; /** * Users limit */ - users: number; + users?: number; /** * Executions limit */ - executions: number; + executions?: number; /** * GBHours limit */ - GBHours: number; + GBHours?: number; /** * Image transformations limit */ - imageTransformations: number; + imageTransformations?: number; /** * Auth phone limit */ - authPhone: number; + authPhone?: number; /** * Budget limit percentage */ - budgetLimit: number; + budgetLimit?: number; } /** @@ -10309,7 +10377,7 @@ export namespace Models { /** * Billing limits reached */ - billingLimits: BillingLimits; + billingLimits?: BillingLimits; /** * Billing plan selected for downgrade. */ @@ -10610,6 +10678,98 @@ export namespace Models { roles: string[]; } + /** + * usageEvent + */ + export type UsageEvent = { + /** + * The metric key. + */ + metric: string; + /** + * The metric value. + */ + value: number; + /** + * The event timestamp. + */ + time: string; + /** + * The API endpoint path. + */ + path: string; + /** + * The HTTP method. + */ + method: string; + /** + * HTTP status code. Stored as string to preserve unset state (empty string = not available). + */ + status: string; + /** + * The resource type. + */ + resourceType: string; + /** + * The resource ID. + */ + resourceId: string; + /** + * Country code in [ISO 3166-1](http://en.wikipedia.org/wiki/ISO_3166-1) two-character format. + */ + countryCode: string; + /** + * The user agent string. + */ + userAgent: string; + } + + /** + * Usage events list + */ + export type UsageEventList = { + /** + * Total number of events that matched your query. + */ + total: number; + /** + * List of events. + */ + events: UsageEvent[]; + } + + /** + * usageGauge + */ + export type UsageGauge = { + /** + * The metric key. + */ + metric: string; + /** + * The current snapshot value. + */ + value: number; + /** + * The snapshot timestamp. + */ + time: string; + } + + /** + * Usage gauges list + */ + export type UsageGaugeList = { + /** + * Total number of gauges that matched your query. + */ + total: number; + /** + * List of gauges. + */ + gauges: UsageGauge[]; + } + /** * UsageOrganization */ diff --git a/src/services/advisor.ts b/src/services/advisor.ts new file mode 100644 index 00000000..ed87a3fa --- /dev/null +++ b/src/services/advisor.ts @@ -0,0 +1,309 @@ +import { Service } from '../service'; +import { AppwriteException, Client, type Payload, UploadProgress } from '../client'; +import type { Models } from '../models'; + + +export class Advisor { + client: Client; + + constructor(client: Client) { + this.client = client; + } + + /** + * Get a list of all the project's analyzer reports. You can use the query params to filter your results. + * + * + * @param {string[]} params.queries - Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: appId, type, targetType, target, analyzedAt + * @param {boolean} params.total - When set to false, the total count returned will be 0 and will not be calculated. + * @throws {AppwriteException} + * @returns {Promise} + */ + listReports(params?: { queries?: string[], total?: boolean }): Promise; + /** + * Get a list of all the project's analyzer reports. You can use the query params to filter your results. + * + * + * @param {string[]} queries - Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: appId, type, targetType, target, analyzedAt + * @param {boolean} total - When set to false, the total count returned will be 0 and will not be calculated. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + listReports(queries?: string[], total?: boolean): Promise; + listReports( + paramsOrFirst?: { queries?: string[], total?: boolean } | string[], + ...rest: [(boolean)?] + ): Promise { + let params: { queries?: string[], total?: boolean }; + + if (!paramsOrFirst || (paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) { + params = (paramsOrFirst || {}) as { queries?: string[], total?: boolean }; + } else { + params = { + queries: paramsOrFirst as string[], + total: rest[0] as boolean + }; + } + + const queries = params.queries; + const total = params.total; + + + const apiPath = '/reports'; + const payload: Payload = {}; + if (typeof queries !== 'undefined') { + payload['queries'] = queries; + } + if (typeof total !== 'undefined') { + payload['total'] = total; + } + const uri = new URL(this.client.config.endpoint + apiPath); + + const apiHeaders: { [header: string]: string } = { + } + + return this.client.call( + 'get', + uri, + apiHeaders, + payload + ); + } + + /** + * Get an analyzer report by its unique ID. The response includes the report's metadata and the nested insights it produced. + * + * + * @param {string} params.reportId - Report ID. + * @throws {AppwriteException} + * @returns {Promise} + */ + getReport(params: { reportId: string }): Promise; + /** + * Get an analyzer report by its unique ID. The response includes the report's metadata and the nested insights it produced. + * + * + * @param {string} reportId - Report ID. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + getReport(reportId: string): Promise; + getReport( + paramsOrFirst: { reportId: string } | string + ): Promise { + let params: { reportId: string }; + + if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) { + params = (paramsOrFirst || {}) as { reportId: string }; + } else { + params = { + reportId: paramsOrFirst as string + }; + } + + const reportId = params.reportId; + + if (typeof reportId === 'undefined') { + throw new AppwriteException('Missing required parameter: "reportId"'); + } + + const apiPath = '/reports/{reportId}'.replace('{reportId}', reportId); + const payload: Payload = {}; + const uri = new URL(this.client.config.endpoint + apiPath); + + const apiHeaders: { [header: string]: string } = { + } + + return this.client.call( + 'get', + uri, + apiHeaders, + payload + ); + } + + /** + * Delete an analyzer report by its unique ID. Nested insights and CTA metadata are removed asynchronously by the deletes worker. + * + * + * @param {string} params.reportId - Report ID. + * @throws {AppwriteException} + * @returns {Promise<{}>} + */ + deleteReport(params: { reportId: string }): Promise<{}>; + /** + * Delete an analyzer report by its unique ID. Nested insights and CTA metadata are removed asynchronously by the deletes worker. + * + * + * @param {string} reportId - Report ID. + * @throws {AppwriteException} + * @returns {Promise<{}>} + * @deprecated Use the object parameter style method for a better developer experience. + */ + deleteReport(reportId: string): Promise<{}>; + deleteReport( + paramsOrFirst: { reportId: string } | string + ): Promise<{}> { + let params: { reportId: string }; + + if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) { + params = (paramsOrFirst || {}) as { reportId: string }; + } else { + params = { + reportId: paramsOrFirst as string + }; + } + + const reportId = params.reportId; + + if (typeof reportId === 'undefined') { + throw new AppwriteException('Missing required parameter: "reportId"'); + } + + const apiPath = '/reports/{reportId}'.replace('{reportId}', reportId); + const payload: Payload = {}; + const uri = new URL(this.client.config.endpoint + apiPath); + + const apiHeaders: { [header: string]: string } = { + 'content-type': 'application/json', + } + + return this.client.call( + 'delete', + uri, + apiHeaders, + payload + ); + } + + /** + * List the insights produced under a single analyzer report. You can use the query params to filter your results further. + * + * + * @param {string} params.reportId - Parent report ID. + * @param {string[]} params.queries - Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: type, severity, status, resourceType, resourceId, parentResourceType, parentResourceId, analyzedAt, dismissedAt, dismissedBy + * @param {boolean} params.total - When set to false, the total count returned will be 0 and will not be calculated. + * @throws {AppwriteException} + * @returns {Promise} + */ + listInsights(params: { reportId: string, queries?: string[], total?: boolean }): Promise; + /** + * List the insights produced under a single analyzer report. You can use the query params to filter your results further. + * + * + * @param {string} reportId - Parent report ID. + * @param {string[]} queries - Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter on the following attributes: type, severity, status, resourceType, resourceId, parentResourceType, parentResourceId, analyzedAt, dismissedAt, dismissedBy + * @param {boolean} total - When set to false, the total count returned will be 0 and will not be calculated. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + listInsights(reportId: string, queries?: string[], total?: boolean): Promise; + listInsights( + paramsOrFirst: { reportId: string, queries?: string[], total?: boolean } | string, + ...rest: [(string[])?, (boolean)?] + ): Promise { + let params: { reportId: string, queries?: string[], total?: boolean }; + + if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) { + params = (paramsOrFirst || {}) as { reportId: string, queries?: string[], total?: boolean }; + } else { + params = { + reportId: paramsOrFirst as string, + queries: rest[0] as string[], + total: rest[1] as boolean + }; + } + + const reportId = params.reportId; + const queries = params.queries; + const total = params.total; + + if (typeof reportId === 'undefined') { + throw new AppwriteException('Missing required parameter: "reportId"'); + } + + const apiPath = '/reports/{reportId}/insights'.replace('{reportId}', reportId); + const payload: Payload = {}; + if (typeof queries !== 'undefined') { + payload['queries'] = queries; + } + if (typeof total !== 'undefined') { + payload['total'] = total; + } + const uri = new URL(this.client.config.endpoint + apiPath); + + const apiHeaders: { [header: string]: string } = { + } + + return this.client.call( + 'get', + uri, + apiHeaders, + payload + ); + } + + /** + * Get an insight by its unique ID, scoped to its parent report. + * + * + * @param {string} params.reportId - Parent report ID. + * @param {string} params.insightId - Insight ID. + * @throws {AppwriteException} + * @returns {Promise} + */ + getInsight(params: { reportId: string, insightId: string }): Promise; + /** + * Get an insight by its unique ID, scoped to its parent report. + * + * + * @param {string} reportId - Parent report ID. + * @param {string} insightId - Insight ID. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + getInsight(reportId: string, insightId: string): Promise; + getInsight( + paramsOrFirst: { reportId: string, insightId: string } | string, + ...rest: [(string)?] + ): Promise { + let params: { reportId: string, insightId: string }; + + if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) { + params = (paramsOrFirst || {}) as { reportId: string, insightId: string }; + } else { + params = { + reportId: paramsOrFirst as string, + insightId: rest[0] as string + }; + } + + const reportId = params.reportId; + const insightId = params.insightId; + + if (typeof reportId === 'undefined') { + throw new AppwriteException('Missing required parameter: "reportId"'); + } + if (typeof insightId === 'undefined') { + throw new AppwriteException('Missing required parameter: "insightId"'); + } + + const apiPath = '/reports/{reportId}/insights/{insightId}'.replace('{reportId}', reportId).replace('{insightId}', insightId); + const payload: Payload = {}; + const uri = new URL(this.client.config.endpoint + apiPath); + + const apiHeaders: { [header: string]: string } = { + } + + return this.client.call( + 'get', + uri, + apiHeaders, + payload + ); + } +} diff --git a/src/services/console.ts b/src/services/console.ts index 8e26188b..278fc464 100644 --- a/src/services/console.ts +++ b/src/services/console.ts @@ -5,6 +5,8 @@ import type { Models } from '../models'; import { Platform } from '../enums/platform'; import { ConsoleResourceType } from '../enums/console-resource-type'; import { QuerySuggestionResource } from '../enums/query-suggestion-resource'; +import { ProjectEmailTemplateId } from '../enums/project-email-template-id'; +import { ProjectEmailTemplateLocale } from '../enums/project-email-template-locale'; export class Console { client: Client; @@ -431,6 +433,29 @@ export class Console { ); } + /** + * List all scopes available for organization API keys, along with a description for each scope. + * + * @throws {AppwriteException} + * @returns {Promise} + */ + listOrganizationScopes(): Promise { + + const apiPath = '/console/scopes/organization'; + const payload: Payload = {}; + const uri = new URL(this.client.config.endpoint + apiPath); + + const apiHeaders: { [header: string]: string } = { + } + + return this.client.call( + 'get', + uri, + apiHeaders, + payload + ); + } + /** * List all scopes available for project API keys, along with a description for each scope. * @@ -781,6 +806,65 @@ export class Console { ); } + /** + * Get the Appwrite built-in default email template for the specified type and locale. Always returns the unmodified default, ignoring any custom project overrides. + * + * @param {ProjectEmailTemplateId} params.templateId - Email template type. Can be one of: verification, magicSession, recovery, invitation, mfaChallenge, sessionAlert, otpSession + * @param {ProjectEmailTemplateLocale} params.locale - Template locale. If left empty, the fallback locale (en) will be used. + * @throws {AppwriteException} + * @returns {Promise} + */ + getEmailTemplate(params: { templateId: ProjectEmailTemplateId, locale?: ProjectEmailTemplateLocale }): Promise; + /** + * Get the Appwrite built-in default email template for the specified type and locale. Always returns the unmodified default, ignoring any custom project overrides. + * + * @param {ProjectEmailTemplateId} templateId - Email template type. Can be one of: verification, magicSession, recovery, invitation, mfaChallenge, sessionAlert, otpSession + * @param {ProjectEmailTemplateLocale} locale - Template locale. If left empty, the fallback locale (en) will be used. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + getEmailTemplate(templateId: ProjectEmailTemplateId, locale?: ProjectEmailTemplateLocale): Promise; + getEmailTemplate( + paramsOrFirst: { templateId: ProjectEmailTemplateId, locale?: ProjectEmailTemplateLocale } | ProjectEmailTemplateId, + ...rest: [(ProjectEmailTemplateLocale)?] + ): Promise { + let params: { templateId: ProjectEmailTemplateId, locale?: ProjectEmailTemplateLocale }; + + if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst) && ('templateId' in paramsOrFirst || 'locale' in paramsOrFirst))) { + params = (paramsOrFirst || {}) as { templateId: ProjectEmailTemplateId, locale?: ProjectEmailTemplateLocale }; + } else { + params = { + templateId: paramsOrFirst as ProjectEmailTemplateId, + locale: rest[0] as ProjectEmailTemplateLocale + }; + } + + const templateId = params.templateId; + const locale = params.locale; + + if (typeof templateId === 'undefined') { + throw new AppwriteException('Missing required parameter: "templateId"'); + } + + const apiPath = '/console/templates/email/{templateId}'.replace('{templateId}', templateId); + const payload: Payload = {}; + if (typeof locale !== 'undefined') { + payload['locale'] = locale; + } + const uri = new URL(this.client.config.endpoint + apiPath); + + const apiHeaders: { [header: string]: string } = { + } + + return this.client.call( + 'get', + uri, + apiHeaders, + payload + ); + } + /** * Get all Environment Variables that are relevant for the console. * diff --git a/src/services/presences.ts b/src/services/presences.ts new file mode 100644 index 00000000..373a2530 --- /dev/null +++ b/src/services/presences.ts @@ -0,0 +1,437 @@ +import { Service } from '../service'; +import { AppwriteException, Client, type Payload, UploadProgress } from '../client'; +import type { Models } from '../models'; + +import { UsageRange } from '../enums/usage-range'; + +export class Presences { + client: Client; + + constructor(client: Client) { + this.client = client; + } + + /** + * List presence logs. Expired entries are filtered out automatically. + * + * + * @param {string[]} params.queries - Array of query strings generated using the Query class provided by the SDK. + * @param {boolean} params.total - When set to false, the total count returned will be 0 and will not be calculated. + * @param {number} params.ttl - TTL (seconds) for caching list responses. Responses are stored in an in-memory key-value cache, keyed per project, collection, schema version (attributes and indexes), caller authorization roles, and the exact query — so users with different permissions never share cached entries. Schema changes invalidate cached entries automatically; document writes do not, so choose a TTL you are comfortable serving as stale data. Set to 0 to disable caching. Must be between 0 and 86400 (24 hours). + * @throws {AppwriteException} + * @returns {Promise>} + */ + list(params?: { queries?: string[], total?: boolean, ttl?: number }): Promise>; + /** + * List presence logs. Expired entries are filtered out automatically. + * + * + * @param {string[]} queries - Array of query strings generated using the Query class provided by the SDK. + * @param {boolean} total - When set to false, the total count returned will be 0 and will not be calculated. + * @param {number} ttl - TTL (seconds) for caching list responses. Responses are stored in an in-memory key-value cache, keyed per project, collection, schema version (attributes and indexes), caller authorization roles, and the exact query — so users with different permissions never share cached entries. Schema changes invalidate cached entries automatically; document writes do not, so choose a TTL you are comfortable serving as stale data. Set to 0 to disable caching. Must be between 0 and 86400 (24 hours). + * @throws {AppwriteException} + * @returns {Promise>} + * @deprecated Use the object parameter style method for a better developer experience. + */ + list(queries?: string[], total?: boolean, ttl?: number): Promise>; + list( + paramsOrFirst?: { queries?: string[], total?: boolean, ttl?: number } | string[], + ...rest: [(boolean)?, (number)?] + ): Promise> { + let params: { queries?: string[], total?: boolean, ttl?: number }; + + if (!paramsOrFirst || (paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) { + params = (paramsOrFirst || {}) as { queries?: string[], total?: boolean, ttl?: number }; + } else { + params = { + queries: paramsOrFirst as string[], + total: rest[0] as boolean, + ttl: rest[1] as number + }; + } + + const queries = params.queries; + const total = params.total; + const ttl = params.ttl; + + + const apiPath = '/presences'; + const payload: Payload = {}; + if (typeof queries !== 'undefined') { + payload['queries'] = queries; + } + if (typeof total !== 'undefined') { + payload['total'] = total; + } + if (typeof ttl !== 'undefined') { + payload['ttl'] = ttl; + } + const uri = new URL(this.client.config.endpoint + apiPath); + + const apiHeaders: { [header: string]: string } = { + } + + return this.client.call( + 'get', + uri, + apiHeaders, + payload + ); + } + + /** + * Get presence usage metrics, including the current total of online users and historical online user counts for the selected time range. + * + * + * @param {UsageRange} params.range - Date range. + * @throws {AppwriteException} + * @returns {Promise} + */ + getUsage(params?: { range?: UsageRange }): Promise; + /** + * Get presence usage metrics, including the current total of online users and historical online user counts for the selected time range. + * + * + * @param {UsageRange} range - Date range. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + getUsage(range?: UsageRange): Promise; + getUsage( + paramsOrFirst?: { range?: UsageRange } | UsageRange + ): Promise { + let params: { range?: UsageRange }; + + if (!paramsOrFirst || (paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst) && ('range' in paramsOrFirst))) { + params = (paramsOrFirst || {}) as { range?: UsageRange }; + } else { + params = { + range: paramsOrFirst as UsageRange + }; + } + + const range = params.range; + + + const apiPath = '/presences/usage'; + const payload: Payload = {}; + if (typeof range !== 'undefined') { + payload['range'] = range; + } + const uri = new URL(this.client.config.endpoint + apiPath); + + const apiHeaders: { [header: string]: string } = { + } + + return this.client.call( + 'get', + uri, + apiHeaders, + payload + ); + } + + /** + * Get a presence log by its unique ID. Entries whose `expiresAt` is in the past are treated as not found. + * + * + * @param {string} params.presenceId - Presence unique ID. + * @throws {AppwriteException} + * @returns {Promise} + */ + get(params: { presenceId: string }): Promise; + /** + * Get a presence log by its unique ID. Entries whose `expiresAt` is in the past are treated as not found. + * + * + * @param {string} presenceId - Presence unique ID. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + get(presenceId: string): Promise; + get( + paramsOrFirst: { presenceId: string } | string + ): Promise { + let params: { presenceId: string }; + + if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) { + params = (paramsOrFirst || {}) as { presenceId: string }; + } else { + params = { + presenceId: paramsOrFirst as string + }; + } + + const presenceId = params.presenceId; + + if (typeof presenceId === 'undefined') { + throw new AppwriteException('Missing required parameter: "presenceId"'); + } + + const apiPath = '/presences/{presenceId}'.replace('{presenceId}', presenceId); + const payload: Payload = {}; + const uri = new URL(this.client.config.endpoint + apiPath); + + const apiHeaders: { [header: string]: string } = { + } + + return this.client.call( + 'get', + uri, + apiHeaders, + payload + ); + } + + /** + * Create or update a presence log by its user ID. + * + * + * @param {string} params.presenceId - Presence unique ID. + * @param {string} params.userId - User ID. + * @param {string} params.status - Presence status. + * @param {string[]} params.permissions - An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string} params.expiresAt - Presence expiry datetime. + * @param {object} params.metadata - Presence metadata object. + * @throws {AppwriteException} + * @returns {Promise} + */ + upsert(params: { presenceId: string, userId: string, status: string, permissions?: string[], expiresAt?: string, metadata?: object }): Promise; + /** + * Create or update a presence log by its user ID. + * + * + * @param {string} presenceId - Presence unique ID. + * @param {string} userId - User ID. + * @param {string} status - Presence status. + * @param {string[]} permissions - An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {string} expiresAt - Presence expiry datetime. + * @param {object} metadata - Presence metadata object. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + upsert(presenceId: string, userId: string, status: string, permissions?: string[], expiresAt?: string, metadata?: object): Promise; + upsert( + paramsOrFirst: { presenceId: string, userId: string, status: string, permissions?: string[], expiresAt?: string, metadata?: object } | string, + ...rest: [(string)?, (string)?, (string[])?, (string)?, (object)?] + ): Promise { + let params: { presenceId: string, userId: string, status: string, permissions?: string[], expiresAt?: string, metadata?: object }; + + if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) { + params = (paramsOrFirst || {}) as { presenceId: string, userId: string, status: string, permissions?: string[], expiresAt?: string, metadata?: object }; + } else { + params = { + presenceId: paramsOrFirst as string, + userId: rest[0] as string, + status: rest[1] as string, + permissions: rest[2] as string[], + expiresAt: rest[3] as string, + metadata: rest[4] as object + }; + } + + const presenceId = params.presenceId; + const userId = params.userId; + const status = params.status; + const permissions = params.permissions; + const expiresAt = params.expiresAt; + const metadata = params.metadata; + + if (typeof presenceId === 'undefined') { + throw new AppwriteException('Missing required parameter: "presenceId"'); + } + if (typeof userId === 'undefined') { + throw new AppwriteException('Missing required parameter: "userId"'); + } + if (typeof status === 'undefined') { + throw new AppwriteException('Missing required parameter: "status"'); + } + + const apiPath = '/presences/{presenceId}'.replace('{presenceId}', presenceId); + const payload: Payload = {}; + if (typeof userId !== 'undefined') { + payload['userId'] = userId; + } + if (typeof status !== 'undefined') { + payload['status'] = status; + } + if (typeof permissions !== 'undefined') { + payload['permissions'] = permissions; + } + if (typeof expiresAt !== 'undefined') { + payload['expiresAt'] = expiresAt; + } + if (typeof metadata !== 'undefined') { + payload['metadata'] = metadata; + } + const uri = new URL(this.client.config.endpoint + apiPath); + + const apiHeaders: { [header: string]: string } = { + 'content-type': 'application/json', + } + + return this.client.call( + 'put', + uri, + apiHeaders, + payload + ); + } + + /** + * Update a presence log by its unique ID. Using the patch method you can pass only specific fields that will get updated. + * + * + * @param {string} params.presenceId - Presence unique ID. + * @param {string} params.userId - User ID. + * @param {string} params.status - Presence status. + * @param {string} params.expiresAt - Presence expiry datetime. + * @param {object} params.metadata - Presence metadata object. + * @param {string[]} params.permissions - An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {boolean} params.purge - When true, purge cached responses used by list presences endpoint. + * @throws {AppwriteException} + * @returns {Promise} + */ + updatePresence(params: { presenceId: string, userId: string, status?: string, expiresAt?: string, metadata?: object, permissions?: string[], purge?: boolean }): Promise; + /** + * Update a presence log by its unique ID. Using the patch method you can pass only specific fields that will get updated. + * + * + * @param {string} presenceId - Presence unique ID. + * @param {string} userId - User ID. + * @param {string} status - Presence status. + * @param {string} expiresAt - Presence expiry datetime. + * @param {object} metadata - Presence metadata object. + * @param {string[]} permissions - An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions). + * @param {boolean} purge - When true, purge cached responses used by list presences endpoint. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + updatePresence(presenceId: string, userId: string, status?: string, expiresAt?: string, metadata?: object, permissions?: string[], purge?: boolean): Promise; + updatePresence( + paramsOrFirst: { presenceId: string, userId: string, status?: string, expiresAt?: string, metadata?: object, permissions?: string[], purge?: boolean } | string, + ...rest: [(string)?, (string)?, (string)?, (object)?, (string[])?, (boolean)?] + ): Promise { + let params: { presenceId: string, userId: string, status?: string, expiresAt?: string, metadata?: object, permissions?: string[], purge?: boolean }; + + if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) { + params = (paramsOrFirst || {}) as { presenceId: string, userId: string, status?: string, expiresAt?: string, metadata?: object, permissions?: string[], purge?: boolean }; + } else { + params = { + presenceId: paramsOrFirst as string, + userId: rest[0] as string, + status: rest[1] as string, + expiresAt: rest[2] as string, + metadata: rest[3] as object, + permissions: rest[4] as string[], + purge: rest[5] as boolean + }; + } + + const presenceId = params.presenceId; + const userId = params.userId; + const status = params.status; + const expiresAt = params.expiresAt; + const metadata = params.metadata; + const permissions = params.permissions; + const purge = params.purge; + + if (typeof presenceId === 'undefined') { + throw new AppwriteException('Missing required parameter: "presenceId"'); + } + if (typeof userId === 'undefined') { + throw new AppwriteException('Missing required parameter: "userId"'); + } + + const apiPath = '/presences/{presenceId}'.replace('{presenceId}', presenceId); + const payload: Payload = {}; + if (typeof userId !== 'undefined') { + payload['userId'] = userId; + } + if (typeof status !== 'undefined') { + payload['status'] = status; + } + if (typeof expiresAt !== 'undefined') { + payload['expiresAt'] = expiresAt; + } + if (typeof metadata !== 'undefined') { + payload['metadata'] = metadata; + } + if (typeof permissions !== 'undefined') { + payload['permissions'] = permissions; + } + if (typeof purge !== 'undefined') { + payload['purge'] = purge; + } + const uri = new URL(this.client.config.endpoint + apiPath); + + const apiHeaders: { [header: string]: string } = { + 'content-type': 'application/json', + } + + return this.client.call( + 'patch', + uri, + apiHeaders, + payload + ); + } + + /** + * Delete a presence log by its unique ID. + * + * + * @param {string} params.presenceId - Presence unique ID. + * @throws {AppwriteException} + * @returns {Promise<{}>} + */ + delete(params: { presenceId: string }): Promise<{}>; + /** + * Delete a presence log by its unique ID. + * + * + * @param {string} presenceId - Presence unique ID. + * @throws {AppwriteException} + * @returns {Promise<{}>} + * @deprecated Use the object parameter style method for a better developer experience. + */ + delete(presenceId: string): Promise<{}>; + delete( + paramsOrFirst: { presenceId: string } | string + ): Promise<{}> { + let params: { presenceId: string }; + + if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) { + params = (paramsOrFirst || {}) as { presenceId: string }; + } else { + params = { + presenceId: paramsOrFirst as string + }; + } + + const presenceId = params.presenceId; + + if (typeof presenceId === 'undefined') { + throw new AppwriteException('Missing required parameter: "presenceId"'); + } + + const apiPath = '/presences/{presenceId}'.replace('{presenceId}', presenceId); + const payload: Payload = {}; + const uri = new URL(this.client.config.endpoint + apiPath); + + const apiHeaders: { [header: string]: string } = { + 'content-type': 'application/json', + } + + return this.client.call( + 'delete', + uri, + apiHeaders, + payload + ); + } +} diff --git a/src/services/project.ts b/src/services/project.ts index 727f6dd5..721ebf99 100644 --- a/src/services/project.ts +++ b/src/services/project.ts @@ -2,16 +2,16 @@ import { Service } from '../service'; import { AppwriteException, Client, type Payload, UploadProgress } from '../client'; import type { Models } from '../models'; -import { AuthMethod } from '../enums/auth-method'; -import { Scopes } from '../enums/scopes'; -import { Prompt } from '../enums/prompt'; -import { OAuthProvider } from '../enums/o-auth-provider'; -import { ProjectPolicy } from '../enums/project-policy'; -import { ProtocolId } from '../enums/protocol-id'; -import { ServiceId } from '../enums/service-id'; -import { Secure } from '../enums/secure'; -import { EmailTemplateType } from '../enums/email-template-type'; -import { EmailTemplateLocale } from '../enums/email-template-locale'; +import { ProjectAuthMethodId } from '../enums/project-auth-method-id'; +import { ProjectKeyScopes } from '../enums/project-key-scopes'; +import { ProjectOAuth2GooglePrompt } from '../enums/project-o-auth-2-google-prompt'; +import { ProjectOAuthProviderId } from '../enums/project-o-auth-provider-id'; +import { ProjectPolicyId } from '../enums/project-policy-id'; +import { ProjectProtocolId } from '../enums/project-protocol-id'; +import { ProjectServiceId } from '../enums/project-service-id'; +import { ProjectSMTPSecure } from '../enums/project-smtp-secure'; +import { ProjectEmailTemplateId } from '../enums/project-email-template-id'; +import { ProjectEmailTemplateLocale } from '../enums/project-email-template-locale'; import { ProjectUsageRange } from '../enums/project-usage-range'; export class Project { @@ -21,6 +21,29 @@ export class Project { this.client = client; } + /** + * Get a project. + * + * @throws {AppwriteException} + * @returns {Promise} + */ + get(): Promise { + + const apiPath = '/project'; + const payload: Payload = {}; + const uri = new URL(this.client.config.endpoint + apiPath); + + const apiHeaders: { [header: string]: string } = { + } + + return this.client.call( + 'get', + uri, + apiHeaders, + payload + ); + } + /** * Delete a project. * @@ -48,33 +71,33 @@ export class Project { /** * Update properties of a specific auth method. Use this endpoint to enable or disable a method in your project. * - * @param {AuthMethod} params.methodId - Auth Method ID. Possible values: email-password,magic-url,email-otp,anonymous,invites,jwt,phone + * @param {ProjectAuthMethodId} params.methodId - Auth Method ID. Possible values: email-password,magic-url,email-otp,anonymous,invites,jwt,phone * @param {boolean} params.enabled - Auth method status. * @throws {AppwriteException} * @returns {Promise} */ - updateAuthMethod(params: { methodId: AuthMethod, enabled: boolean }): Promise; + updateAuthMethod(params: { methodId: ProjectAuthMethodId, enabled: boolean }): Promise; /** * Update properties of a specific auth method. Use this endpoint to enable or disable a method in your project. * - * @param {AuthMethod} methodId - Auth Method ID. Possible values: email-password,magic-url,email-otp,anonymous,invites,jwt,phone + * @param {ProjectAuthMethodId} methodId - Auth Method ID. Possible values: email-password,magic-url,email-otp,anonymous,invites,jwt,phone * @param {boolean} enabled - Auth method status. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. */ - updateAuthMethod(methodId: AuthMethod, enabled: boolean): Promise; + updateAuthMethod(methodId: ProjectAuthMethodId, enabled: boolean): Promise; updateAuthMethod( - paramsOrFirst: { methodId: AuthMethod, enabled: boolean } | AuthMethod, + paramsOrFirst: { methodId: ProjectAuthMethodId, enabled: boolean } | ProjectAuthMethodId, ...rest: [(boolean)?] ): Promise { - let params: { methodId: AuthMethod, enabled: boolean }; + let params: { methodId: ProjectAuthMethodId, enabled: boolean }; if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst) && ('methodId' in paramsOrFirst || 'enabled' in paramsOrFirst))) { - params = (paramsOrFirst || {}) as { methodId: AuthMethod, enabled: boolean }; + params = (paramsOrFirst || {}) as { methodId: ProjectAuthMethodId, enabled: boolean }; } else { params = { - methodId: paramsOrFirst as AuthMethod, + methodId: paramsOrFirst as ProjectAuthMethodId, enabled: rest[0] as boolean }; } @@ -174,12 +197,12 @@ export class Project { * * @param {string} params.keyId - Key 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. * @param {string} params.name - Key name. Max length: 128 chars. - * @param {Scopes[]} params.scopes - Key scopes list. Maximum of 100 scopes are allowed. + * @param {ProjectKeyScopes[]} params.scopes - Key scopes list. Maximum of 100 scopes are allowed. * @param {string} params.expire - Expiration time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Use null for unlimited expiration. * @throws {AppwriteException} * @returns {Promise} */ - createKey(params: { keyId: string, name: string, scopes: Scopes[], expire?: string }): Promise; + createKey(params: { keyId: string, name: string, scopes: ProjectKeyScopes[], expire?: string }): Promise; /** * Create a new API key. It's recommended to have multiple API keys with strict scopes for separate functions within your project. * @@ -187,26 +210,26 @@ export class Project { * * @param {string} keyId - Key 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. * @param {string} name - Key name. Max length: 128 chars. - * @param {Scopes[]} scopes - Key scopes list. Maximum of 100 scopes are allowed. + * @param {ProjectKeyScopes[]} scopes - Key scopes list. Maximum of 100 scopes are allowed. * @param {string} expire - Expiration time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Use null for unlimited expiration. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. */ - createKey(keyId: string, name: string, scopes: Scopes[], expire?: string): Promise; + createKey(keyId: string, name: string, scopes: ProjectKeyScopes[], expire?: string): Promise; createKey( - paramsOrFirst: { keyId: string, name: string, scopes: Scopes[], expire?: string } | string, - ...rest: [(string)?, (Scopes[])?, (string)?] + paramsOrFirst: { keyId: string, name: string, scopes: ProjectKeyScopes[], expire?: string } | string, + ...rest: [(string)?, (ProjectKeyScopes[])?, (string)?] ): Promise { - let params: { keyId: string, name: string, scopes: Scopes[], expire?: string }; + let params: { keyId: string, name: string, scopes: ProjectKeyScopes[], expire?: string }; if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) { - params = (paramsOrFirst || {}) as { keyId: string, name: string, scopes: Scopes[], expire?: string }; + params = (paramsOrFirst || {}) as { keyId: string, name: string, scopes: ProjectKeyScopes[], expire?: string }; } else { params = { keyId: paramsOrFirst as string, name: rest[0] as string, - scopes: rest[1] as Scopes[], + scopes: rest[1] as ProjectKeyScopes[], expire: rest[2] as string }; } @@ -259,35 +282,35 @@ export class Project { * * You can also create a standard API key if you need a longer-lived key instead. * - * @param {Scopes[]} params.scopes - Key scopes list. Maximum of 100 scopes are allowed. + * @param {ProjectKeyScopes[]} params.scopes - Key scopes list. Maximum of 100 scopes are allowed. * @param {number} params.duration - Time in seconds before ephemeral key expires. Maximum duration is 3600 seconds. * @throws {AppwriteException} * @returns {Promise} */ - createEphemeralKey(params: { scopes: Scopes[], duration: number }): Promise; + createEphemeralKey(params: { scopes: ProjectKeyScopes[], duration: number }): Promise; /** * Create a new ephemeral API key. It's recommended to have multiple API keys with strict scopes for separate functions within your project. * * You can also create a standard API key if you need a longer-lived key instead. * - * @param {Scopes[]} scopes - Key scopes list. Maximum of 100 scopes are allowed. + * @param {ProjectKeyScopes[]} scopes - Key scopes list. Maximum of 100 scopes are allowed. * @param {number} duration - Time in seconds before ephemeral key expires. Maximum duration is 3600 seconds. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. */ - createEphemeralKey(scopes: Scopes[], duration: number): Promise; + createEphemeralKey(scopes: ProjectKeyScopes[], duration: number): Promise; createEphemeralKey( - paramsOrFirst: { scopes: Scopes[], duration: number } | Scopes[], + paramsOrFirst: { scopes: ProjectKeyScopes[], duration: number } | ProjectKeyScopes[], ...rest: [(number)?] ): Promise { - let params: { scopes: Scopes[], duration: number }; + let params: { scopes: ProjectKeyScopes[], duration: number }; if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst) && ('scopes' in paramsOrFirst || 'duration' in paramsOrFirst))) { - params = (paramsOrFirst || {}) as { scopes: Scopes[], duration: number }; + params = (paramsOrFirst || {}) as { scopes: ProjectKeyScopes[], duration: number }; } else { params = { - scopes: paramsOrFirst as Scopes[], + scopes: paramsOrFirst as ProjectKeyScopes[], duration: rest[0] as number }; } @@ -380,37 +403,37 @@ export class Project { * * @param {string} params.keyId - Key ID. * @param {string} params.name - Key name. Max length: 128 chars. - * @param {Scopes[]} params.scopes - Key scopes list. Maximum of 100 scopes are allowed. + * @param {ProjectKeyScopes[]} params.scopes - Key scopes list. Maximum of 100 scopes are allowed. * @param {string} params.expire - Expiration time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Use null for unlimited expiration. * @throws {AppwriteException} * @returns {Promise} */ - updateKey(params: { keyId: string, name: string, scopes: Scopes[], expire?: string }): Promise; + updateKey(params: { keyId: string, name: string, scopes: ProjectKeyScopes[], expire?: string }): Promise; /** * Update a key by its unique ID. Use this endpoint to update the name, scopes, or expiration time of an API key. * * @param {string} keyId - Key ID. * @param {string} name - Key name. Max length: 128 chars. - * @param {Scopes[]} scopes - Key scopes list. Maximum of 100 scopes are allowed. + * @param {ProjectKeyScopes[]} scopes - Key scopes list. Maximum of 100 scopes are allowed. * @param {string} expire - Expiration time in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Use null for unlimited expiration. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. */ - updateKey(keyId: string, name: string, scopes: Scopes[], expire?: string): Promise; + updateKey(keyId: string, name: string, scopes: ProjectKeyScopes[], expire?: string): Promise; updateKey( - paramsOrFirst: { keyId: string, name: string, scopes: Scopes[], expire?: string } | string, - ...rest: [(string)?, (Scopes[])?, (string)?] + paramsOrFirst: { keyId: string, name: string, scopes: ProjectKeyScopes[], expire?: string } | string, + ...rest: [(string)?, (ProjectKeyScopes[])?, (string)?] ): Promise { - let params: { keyId: string, name: string, scopes: Scopes[], expire?: string }; + let params: { keyId: string, name: string, scopes: ProjectKeyScopes[], expire?: string }; if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) { - params = (paramsOrFirst || {}) as { keyId: string, name: string, scopes: Scopes[], expire?: string }; + params = (paramsOrFirst || {}) as { keyId: string, name: string, scopes: ProjectKeyScopes[], expire?: string }; } else { params = { keyId: paramsOrFirst as string, name: rest[0] as string, - scopes: rest[1] as Scopes[], + scopes: rest[1] as ProjectKeyScopes[], expire: rest[2] as string }; } @@ -2165,37 +2188,37 @@ export class Project { * * @param {string} params.clientId - 'Client ID' of Google OAuth2 app. For example: 120000000095-92ifjb00000000000000000000g7ijfb.apps.googleusercontent.com * @param {string} params.clientSecret - 'Client Secret' of Google OAuth2 app. For example: GOCSPX-2k8gsR0000000000000000VNahJj - * @param {Prompt[]} params.prompt - Array of Google OAuth2 prompt values. If "none" is included, it must be the only element. "none" means: don't display any authentication or consent screens. Must not be specified with other values. "consent" means: prompt the user for consent. "select_account" means: prompt the user to select an account. + * @param {ProjectOAuth2GooglePrompt[]} params.prompt - Array of Google OAuth2 prompt values. If "none" is included, it must be the only element. "none" means: don't display any authentication or consent screens. Must not be specified with other values. "consent" means: prompt the user for consent. "select_account" means: prompt the user to select an account. * @param {boolean} params.enabled - 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. * @throws {AppwriteException} * @returns {Promise} */ - updateOAuth2Google(params?: { clientId?: string, clientSecret?: string, prompt?: Prompt[], enabled?: boolean }): Promise; + updateOAuth2Google(params?: { clientId?: string, clientSecret?: string, prompt?: ProjectOAuth2GooglePrompt[], enabled?: boolean }): Promise; /** * Update the project OAuth2 Google configuration. * * @param {string} clientId - 'Client ID' of Google OAuth2 app. For example: 120000000095-92ifjb00000000000000000000g7ijfb.apps.googleusercontent.com * @param {string} clientSecret - 'Client Secret' of Google OAuth2 app. For example: GOCSPX-2k8gsR0000000000000000VNahJj - * @param {Prompt[]} prompt - Array of Google OAuth2 prompt values. If "none" is included, it must be the only element. "none" means: don't display any authentication or consent screens. Must not be specified with other values. "consent" means: prompt the user for consent. "select_account" means: prompt the user to select an account. + * @param {ProjectOAuth2GooglePrompt[]} prompt - Array of Google OAuth2 prompt values. If "none" is included, it must be the only element. "none" means: don't display any authentication or consent screens. Must not be specified with other values. "consent" means: prompt the user for consent. "select_account" means: prompt the user to select an account. * @param {boolean} enabled - 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. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. */ - updateOAuth2Google(clientId?: string, clientSecret?: string, prompt?: Prompt[], enabled?: boolean): Promise; + updateOAuth2Google(clientId?: string, clientSecret?: string, prompt?: ProjectOAuth2GooglePrompt[], enabled?: boolean): Promise; updateOAuth2Google( - paramsOrFirst?: { clientId?: string, clientSecret?: string, prompt?: Prompt[], enabled?: boolean } | string, - ...rest: [(string)?, (Prompt[])?, (boolean)?] + paramsOrFirst?: { clientId?: string, clientSecret?: string, prompt?: ProjectOAuth2GooglePrompt[], enabled?: boolean } | string, + ...rest: [(string)?, (ProjectOAuth2GooglePrompt[])?, (boolean)?] ): Promise { - let params: { clientId?: string, clientSecret?: string, prompt?: Prompt[], enabled?: boolean }; + let params: { clientId?: string, clientSecret?: string, prompt?: ProjectOAuth2GooglePrompt[], enabled?: boolean }; if (!paramsOrFirst || (paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) { - params = (paramsOrFirst || {}) as { clientId?: string, clientSecret?: string, prompt?: Prompt[], enabled?: boolean }; + params = (paramsOrFirst || {}) as { clientId?: string, clientSecret?: string, prompt?: ProjectOAuth2GooglePrompt[], enabled?: boolean }; } else { params = { clientId: paramsOrFirst as string, clientSecret: rest[0] as string, - prompt: rest[1] as Prompt[], + prompt: rest[1] as ProjectOAuth2GooglePrompt[], enabled: rest[2] as boolean }; } @@ -3841,30 +3864,30 @@ export class Project { /** * Get a single OAuth2 provider configuration. Credential fields (client secret, p8 file, key/team IDs) are write-only and always returned empty. * - * @param {OAuthProvider} params.providerId - OAuth2 provider key. For example: github, google, apple. + * @param {ProjectOAuthProviderId} params.providerId - OAuth2 provider key. For example: github, google, apple. * @throws {AppwriteException} * @returns {Promise} */ - getOAuth2Provider(params: { providerId: OAuthProvider }): Promise; + getOAuth2Provider(params: { providerId: ProjectOAuthProviderId }): Promise; /** * Get a single OAuth2 provider configuration. Credential fields (client secret, p8 file, key/team IDs) are write-only and always returned empty. * - * @param {OAuthProvider} providerId - OAuth2 provider key. For example: github, google, apple. + * @param {ProjectOAuthProviderId} providerId - OAuth2 provider key. For example: github, google, apple. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. */ - getOAuth2Provider(providerId: OAuthProvider): Promise; + getOAuth2Provider(providerId: ProjectOAuthProviderId): Promise; getOAuth2Provider( - paramsOrFirst: { providerId: OAuthProvider } | OAuthProvider + paramsOrFirst: { providerId: ProjectOAuthProviderId } | ProjectOAuthProviderId ): Promise { - let params: { providerId: OAuthProvider }; + let params: { providerId: ProjectOAuthProviderId }; if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst) && ('providerId' in paramsOrFirst))) { - params = (paramsOrFirst || {}) as { providerId: OAuthProvider }; + params = (paramsOrFirst || {}) as { providerId: ProjectOAuthProviderId }; } else { params = { - providerId: paramsOrFirst as OAuthProvider + providerId: paramsOrFirst as ProjectOAuthProviderId }; } @@ -4856,23 +4879,23 @@ export class Project { } /** - * Configures if email aliases such as subaddresses and emails with suffixes are denied during new users sign-ups and email updates. + * Configures if aliased emails such as subaddresses and emails with suffixes are denied during new users sign-ups and email updates. * - * @param {boolean} params.enabled - Set whether or not to block email aliases during signup and email updates. + * @param {boolean} params.enabled - Set whether or not to block aliased emails during signup and email updates. * @throws {AppwriteException} * @returns {Promise} */ - updateDenyCanonicalEmailPolicy(params: { enabled: boolean }): Promise; + updateDenyAliasedEmailPolicy(params: { enabled: boolean }): Promise; /** - * Configures if email aliases such as subaddresses and emails with suffixes are denied during new users sign-ups and email updates. + * Configures if aliased emails such as subaddresses and emails with suffixes are denied during new users sign-ups and email updates. * - * @param {boolean} enabled - Set whether or not to block email aliases during signup and email updates. + * @param {boolean} enabled - Set whether or not to block aliased emails during signup and email updates. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. */ - updateDenyCanonicalEmailPolicy(enabled: boolean): Promise; - updateDenyCanonicalEmailPolicy( + updateDenyAliasedEmailPolicy(enabled: boolean): Promise; + updateDenyAliasedEmailPolicy( paramsOrFirst: { enabled: boolean } | boolean ): Promise { let params: { enabled: boolean }; @@ -4891,7 +4914,7 @@ export class Project { throw new AppwriteException('Missing required parameter: "enabled"'); } - const apiPath = '/project/policies/deny-canonical-email'; + const apiPath = '/project/policies/deny-aliased-email'; const payload: Payload = {}; if (typeof enabled !== 'undefined') { payload['enabled'] = enabled; @@ -5548,30 +5571,30 @@ export class Project { /** * Get a policy by its unique ID. This endpoint returns the current configuration for the requested project policy. * - * @param {ProjectPolicy} params.policyId - Policy ID. Can be one of: password-dictionary, password-history, password-personal-data, session-alert, session-duration, session-invalidation, session-limit, user-limit, membership-privacy. + * @param {ProjectPolicyId} params.policyId - Policy ID. Can be one of: password-dictionary, password-history, password-personal-data, session-alert, session-duration, session-invalidation, session-limit, user-limit, membership-privacy. * @throws {AppwriteException} * @returns {Promise} */ - getPolicy(params: { policyId: ProjectPolicy }): Promise; + getPolicy(params: { policyId: ProjectPolicyId }): Promise; /** * Get a policy by its unique ID. This endpoint returns the current configuration for the requested project policy. * - * @param {ProjectPolicy} policyId - Policy ID. Can be one of: password-dictionary, password-history, password-personal-data, session-alert, session-duration, session-invalidation, session-limit, user-limit, membership-privacy. + * @param {ProjectPolicyId} policyId - Policy ID. Can be one of: password-dictionary, password-history, password-personal-data, session-alert, session-duration, session-invalidation, session-limit, user-limit, membership-privacy. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. */ - getPolicy(policyId: ProjectPolicy): Promise; + getPolicy(policyId: ProjectPolicyId): Promise; getPolicy( - paramsOrFirst: { policyId: ProjectPolicy } | ProjectPolicy + paramsOrFirst: { policyId: ProjectPolicyId } | ProjectPolicyId ): Promise { - let params: { policyId: ProjectPolicy }; + let params: { policyId: ProjectPolicyId }; if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst) && ('policyId' in paramsOrFirst))) { - params = (paramsOrFirst || {}) as { policyId: ProjectPolicy }; + params = (paramsOrFirst || {}) as { policyId: ProjectPolicyId }; } else { params = { - policyId: paramsOrFirst as ProjectPolicy + policyId: paramsOrFirst as ProjectPolicyId }; } @@ -5599,33 +5622,33 @@ export class Project { /** * Update properties of a specific protocol. Use this endpoint to enable or disable a protocol in your project. * - * @param {ProtocolId} params.protocolId - Protocol name. Can be one of: rest, graphql, websocket + * @param {ProjectProtocolId} params.protocolId - Protocol name. Can be one of: rest, graphql, websocket * @param {boolean} params.enabled - Protocol status. * @throws {AppwriteException} * @returns {Promise} */ - updateProtocol(params: { protocolId: ProtocolId, enabled: boolean }): Promise; + updateProtocol(params: { protocolId: ProjectProtocolId, enabled: boolean }): Promise; /** * Update properties of a specific protocol. Use this endpoint to enable or disable a protocol in your project. * - * @param {ProtocolId} protocolId - Protocol name. Can be one of: rest, graphql, websocket + * @param {ProjectProtocolId} protocolId - Protocol name. Can be one of: rest, graphql, websocket * @param {boolean} enabled - Protocol status. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. */ - updateProtocol(protocolId: ProtocolId, enabled: boolean): Promise; + updateProtocol(protocolId: ProjectProtocolId, enabled: boolean): Promise; updateProtocol( - paramsOrFirst: { protocolId: ProtocolId, enabled: boolean } | ProtocolId, + paramsOrFirst: { protocolId: ProjectProtocolId, enabled: boolean } | ProjectProtocolId, ...rest: [(boolean)?] ): Promise { - let params: { protocolId: ProtocolId, enabled: boolean }; + let params: { protocolId: ProjectProtocolId, enabled: boolean }; if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst) && ('protocolId' in paramsOrFirst || 'enabled' in paramsOrFirst))) { - params = (paramsOrFirst || {}) as { protocolId: ProtocolId, enabled: boolean }; + params = (paramsOrFirst || {}) as { protocolId: ProjectProtocolId, enabled: boolean }; } else { params = { - protocolId: paramsOrFirst as ProtocolId, + protocolId: paramsOrFirst as ProjectProtocolId, enabled: rest[0] as boolean }; } @@ -5662,33 +5685,33 @@ export class Project { /** * Update properties of a specific service. Use this endpoint to enable or disable a service in your project. * - * @param {ServiceId} params.serviceId - Service name. Can be one of: account, avatars, databases, tablesdb, locale, health, project, storage, teams, users, vcs, sites, functions, proxy, graphql, migrations, messaging + * @param {ProjectServiceId} params.serviceId - Service name. Can be one of: account, avatars, databases, tablesdb, locale, health, project, storage, teams, users, vcs, sites, functions, proxy, graphql, migrations, messaging, advisor * @param {boolean} params.enabled - Service status. * @throws {AppwriteException} * @returns {Promise} */ - updateService(params: { serviceId: ServiceId, enabled: boolean }): Promise; + updateService(params: { serviceId: ProjectServiceId, enabled: boolean }): Promise; /** * Update properties of a specific service. Use this endpoint to enable or disable a service in your project. * - * @param {ServiceId} serviceId - Service name. Can be one of: account, avatars, databases, tablesdb, locale, health, project, storage, teams, users, vcs, sites, functions, proxy, graphql, migrations, messaging + * @param {ProjectServiceId} serviceId - Service name. Can be one of: account, avatars, databases, tablesdb, locale, health, project, storage, teams, users, vcs, sites, functions, proxy, graphql, migrations, messaging, advisor * @param {boolean} enabled - Service status. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. */ - updateService(serviceId: ServiceId, enabled: boolean): Promise; + updateService(serviceId: ProjectServiceId, enabled: boolean): Promise; updateService( - paramsOrFirst: { serviceId: ServiceId, enabled: boolean } | ServiceId, + paramsOrFirst: { serviceId: ProjectServiceId, enabled: boolean } | ProjectServiceId, ...rest: [(boolean)?] ): Promise { - let params: { serviceId: ServiceId, enabled: boolean }; + let params: { serviceId: ProjectServiceId, enabled: boolean }; if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst) && ('serviceId' in paramsOrFirst || 'enabled' in paramsOrFirst))) { - params = (paramsOrFirst || {}) as { serviceId: ServiceId, enabled: boolean }; + params = (paramsOrFirst || {}) as { serviceId: ProjectServiceId, enabled: boolean }; } else { params = { - serviceId: paramsOrFirst as ServiceId, + serviceId: paramsOrFirst as ProjectServiceId, enabled: rest[0] as boolean }; } @@ -5727,44 +5750,44 @@ export class Project { * * @param {string} params.host - SMTP server hostname (domain) * @param {number} params.port - SMTP server port - * @param {string} params.username - SMTP server username. Leave empty for no authorization. - * @param {string} params.password - SMTP server password. Leave empty for no authorization. This property is stored securely and cannot be read in future (write-only). - * @param {string} params.senderEmail - Email address shown in inbox as the sender of the email. - * @param {string} params.senderName - Name shown in inbox as the sender of the email. - * @param {string} params.replyToEmail - Email used when user replies to the email. - * @param {string} params.replyToName - Name used when user replies to the email. - * @param {Secure} params.secure - Configures if communication with SMTP server is encrypted. Allowed values are: tls, ssl. Leave empty for no encryption. + * @param {string} params.username - SMTP server username. Pass an empty string to clear a previously set value. + * @param {string} params.password - SMTP server password. Pass an empty string to clear a previously set value. This property is stored securely and cannot be read in future (write-only). + * @param {string} params.senderEmail - Email address shown in inbox as the sender of the email. Pass an empty string to clear a previously set value. + * @param {string} params.senderName - Name shown in inbox as the sender of the email. Pass an empty string to clear a previously set value. + * @param {string} params.replyToEmail - Email used when user replies to the email. Pass an empty string to clear a previously set value. + * @param {string} params.replyToName - Name used when user replies to the email. Pass an empty string to clear a previously set value. + * @param {ProjectSMTPSecure} params.secure - Configures if communication with SMTP server is encrypted. Allowed values are: tls, ssl. Leave empty for no encryption. * @param {boolean} params.enabled - Enable or disable custom SMTP. Custom SMTP is useful for branding purposes, but also allows use of custom email templates. * @throws {AppwriteException} * @returns {Promise} */ - updateSMTP(params?: { host?: string, port?: number, username?: string, password?: string, senderEmail?: string, senderName?: string, replyToEmail?: string, replyToName?: string, secure?: Secure, enabled?: boolean }): Promise; + updateSMTP(params?: { host?: string, port?: number, username?: string, password?: string, senderEmail?: string, senderName?: string, replyToEmail?: string, replyToName?: string, secure?: ProjectSMTPSecure, enabled?: boolean }): Promise; /** * Update the SMTP configuration for your project. Use this endpoint to configure your project's SMTP provider with your custom settings for sending transactional emails. * * @param {string} host - SMTP server hostname (domain) * @param {number} port - SMTP server port - * @param {string} username - SMTP server username. Leave empty for no authorization. - * @param {string} password - SMTP server password. Leave empty for no authorization. This property is stored securely and cannot be read in future (write-only). - * @param {string} senderEmail - Email address shown in inbox as the sender of the email. - * @param {string} senderName - Name shown in inbox as the sender of the email. - * @param {string} replyToEmail - Email used when user replies to the email. - * @param {string} replyToName - Name used when user replies to the email. - * @param {Secure} secure - Configures if communication with SMTP server is encrypted. Allowed values are: tls, ssl. Leave empty for no encryption. + * @param {string} username - SMTP server username. Pass an empty string to clear a previously set value. + * @param {string} password - SMTP server password. Pass an empty string to clear a previously set value. This property is stored securely and cannot be read in future (write-only). + * @param {string} senderEmail - Email address shown in inbox as the sender of the email. Pass an empty string to clear a previously set value. + * @param {string} senderName - Name shown in inbox as the sender of the email. Pass an empty string to clear a previously set value. + * @param {string} replyToEmail - Email used when user replies to the email. Pass an empty string to clear a previously set value. + * @param {string} replyToName - Name used when user replies to the email. Pass an empty string to clear a previously set value. + * @param {ProjectSMTPSecure} secure - Configures if communication with SMTP server is encrypted. Allowed values are: tls, ssl. Leave empty for no encryption. * @param {boolean} enabled - Enable or disable custom SMTP. Custom SMTP is useful for branding purposes, but also allows use of custom email templates. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. */ - updateSMTP(host?: string, port?: number, username?: string, password?: string, senderEmail?: string, senderName?: string, replyToEmail?: string, replyToName?: string, secure?: Secure, enabled?: boolean): Promise; + updateSMTP(host?: string, port?: number, username?: string, password?: string, senderEmail?: string, senderName?: string, replyToEmail?: string, replyToName?: string, secure?: ProjectSMTPSecure, enabled?: boolean): Promise; updateSMTP( - paramsOrFirst?: { host?: string, port?: number, username?: string, password?: string, senderEmail?: string, senderName?: string, replyToEmail?: string, replyToName?: string, secure?: Secure, enabled?: boolean } | string, - ...rest: [(number)?, (string)?, (string)?, (string)?, (string)?, (string)?, (string)?, (Secure)?, (boolean)?] + paramsOrFirst?: { host?: string, port?: number, username?: string, password?: string, senderEmail?: string, senderName?: string, replyToEmail?: string, replyToName?: string, secure?: ProjectSMTPSecure, enabled?: boolean } | string, + ...rest: [(number)?, (string)?, (string)?, (string)?, (string)?, (string)?, (string)?, (ProjectSMTPSecure)?, (boolean)?] ): Promise { - let params: { host?: string, port?: number, username?: string, password?: string, senderEmail?: string, senderName?: string, replyToEmail?: string, replyToName?: string, secure?: Secure, enabled?: boolean }; + let params: { host?: string, port?: number, username?: string, password?: string, senderEmail?: string, senderName?: string, replyToEmail?: string, replyToName?: string, secure?: ProjectSMTPSecure, enabled?: boolean }; if (!paramsOrFirst || (paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) { - params = (paramsOrFirst || {}) as { host?: string, port?: number, username?: string, password?: string, senderEmail?: string, senderName?: string, replyToEmail?: string, replyToName?: string, secure?: Secure, enabled?: boolean }; + params = (paramsOrFirst || {}) as { host?: string, port?: number, username?: string, password?: string, senderEmail?: string, senderName?: string, replyToEmail?: string, replyToName?: string, secure?: ProjectSMTPSecure, enabled?: boolean }; } else { params = { host: paramsOrFirst as string, @@ -5775,7 +5798,7 @@ export class Project { senderName: rest[4] as string, replyToEmail: rest[5] as string, replyToName: rest[6] as string, - secure: rest[7] as Secure, + secure: rest[7] as ProjectSMTPSecure, enabled: rest[8] as boolean }; } @@ -5955,46 +5978,46 @@ export class Project { /** * Update a custom email template for the specified locale and type. Use this endpoint to modify the content of your email templates. * - * @param {EmailTemplateType} params.templateId - Custom email template type. Can be one of: verification, magicSession, recovery, invitation, mfaChallenge, sessionAlert, otpSession - * @param {EmailTemplateLocale} params.locale - Custom email template locale. If left empty, the fallback locale (en) will be used. + * @param {ProjectEmailTemplateId} params.templateId - Custom email template type. Can be one of: verification, magicSession, recovery, invitation, mfaChallenge, sessionAlert, otpSession + * @param {ProjectEmailTemplateLocale} params.locale - Custom email template locale. If left empty, the fallback locale (en) will be used. * @param {string} params.subject - Subject of the email template. Can be up to 255 characters. * @param {string} params.message - Plain or HTML body of the email template message. Can be up to 10MB of content. * @param {string} params.senderName - Name of the email sender. - * @param {string} params.senderEmail - Email of the sender. - * @param {string} params.replyToEmail - Reply to email. + * @param {string} params.senderEmail - Email of the sender. Pass an empty string to clear a previously set value. + * @param {string} params.replyToEmail - Reply to email. Pass an empty string to clear a previously set value. * @param {string} params.replyToName - Reply to name. * @throws {AppwriteException} * @returns {Promise} */ - updateEmailTemplate(params: { templateId: EmailTemplateType, locale?: EmailTemplateLocale, subject?: string, message?: string, senderName?: string, senderEmail?: string, replyToEmail?: string, replyToName?: string }): Promise; + updateEmailTemplate(params: { templateId: ProjectEmailTemplateId, locale?: ProjectEmailTemplateLocale, subject?: string, message?: string, senderName?: string, senderEmail?: string, replyToEmail?: string, replyToName?: string }): Promise; /** * Update a custom email template for the specified locale and type. Use this endpoint to modify the content of your email templates. * - * @param {EmailTemplateType} templateId - Custom email template type. Can be one of: verification, magicSession, recovery, invitation, mfaChallenge, sessionAlert, otpSession - * @param {EmailTemplateLocale} locale - Custom email template locale. If left empty, the fallback locale (en) will be used. + * @param {ProjectEmailTemplateId} templateId - Custom email template type. Can be one of: verification, magicSession, recovery, invitation, mfaChallenge, sessionAlert, otpSession + * @param {ProjectEmailTemplateLocale} locale - Custom email template locale. If left empty, the fallback locale (en) will be used. * @param {string} subject - Subject of the email template. Can be up to 255 characters. * @param {string} message - Plain or HTML body of the email template message. Can be up to 10MB of content. * @param {string} senderName - Name of the email sender. - * @param {string} senderEmail - Email of the sender. - * @param {string} replyToEmail - Reply to email. + * @param {string} senderEmail - Email of the sender. Pass an empty string to clear a previously set value. + * @param {string} replyToEmail - Reply to email. Pass an empty string to clear a previously set value. * @param {string} replyToName - Reply to name. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. */ - updateEmailTemplate(templateId: EmailTemplateType, locale?: EmailTemplateLocale, subject?: string, message?: string, senderName?: string, senderEmail?: string, replyToEmail?: string, replyToName?: string): Promise; + updateEmailTemplate(templateId: ProjectEmailTemplateId, locale?: ProjectEmailTemplateLocale, subject?: string, message?: string, senderName?: string, senderEmail?: string, replyToEmail?: string, replyToName?: string): Promise; updateEmailTemplate( - paramsOrFirst: { templateId: EmailTemplateType, locale?: EmailTemplateLocale, subject?: string, message?: string, senderName?: string, senderEmail?: string, replyToEmail?: string, replyToName?: string } | EmailTemplateType, - ...rest: [(EmailTemplateLocale)?, (string)?, (string)?, (string)?, (string)?, (string)?, (string)?] + paramsOrFirst: { templateId: ProjectEmailTemplateId, locale?: ProjectEmailTemplateLocale, subject?: string, message?: string, senderName?: string, senderEmail?: string, replyToEmail?: string, replyToName?: string } | ProjectEmailTemplateId, + ...rest: [(ProjectEmailTemplateLocale)?, (string)?, (string)?, (string)?, (string)?, (string)?, (string)?] ): Promise { - let params: { templateId: EmailTemplateType, locale?: EmailTemplateLocale, subject?: string, message?: string, senderName?: string, senderEmail?: string, replyToEmail?: string, replyToName?: string }; + let params: { templateId: ProjectEmailTemplateId, locale?: ProjectEmailTemplateLocale, subject?: string, message?: string, senderName?: string, senderEmail?: string, replyToEmail?: string, replyToName?: string }; if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst) && ('templateId' in paramsOrFirst || 'locale' in paramsOrFirst || 'subject' in paramsOrFirst || 'message' in paramsOrFirst || 'senderName' in paramsOrFirst || 'senderEmail' in paramsOrFirst || 'replyToEmail' in paramsOrFirst || 'replyToName' in paramsOrFirst))) { - params = (paramsOrFirst || {}) as { templateId: EmailTemplateType, locale?: EmailTemplateLocale, subject?: string, message?: string, senderName?: string, senderEmail?: string, replyToEmail?: string, replyToName?: string }; + params = (paramsOrFirst || {}) as { templateId: ProjectEmailTemplateId, locale?: ProjectEmailTemplateLocale, subject?: string, message?: string, senderName?: string, senderEmail?: string, replyToEmail?: string, replyToName?: string }; } else { params = { - templateId: paramsOrFirst as EmailTemplateType, - locale: rest[0] as EmailTemplateLocale, + templateId: paramsOrFirst as ProjectEmailTemplateId, + locale: rest[0] as ProjectEmailTemplateLocale, subject: rest[1] as string, message: rest[2] as string, senderName: rest[3] as string, @@ -6060,34 +6083,34 @@ export class Project { /** * Get a custom email template for the specified locale and type. This endpoint returns the template content, subject, and other configuration details. * - * @param {EmailTemplateType} params.templateId - Custom email template type. Can be one of: verification, magicSession, recovery, invitation, mfaChallenge, sessionAlert, otpSession - * @param {EmailTemplateLocale} params.locale - Custom email template locale. If left empty, the fallback locale (en) will be used. + * @param {ProjectEmailTemplateId} params.templateId - Custom email template type. Can be one of: verification, magicSession, recovery, invitation, mfaChallenge, sessionAlert, otpSession + * @param {ProjectEmailTemplateLocale} params.locale - Custom email template locale. If left empty, the fallback locale (en) will be used. * @throws {AppwriteException} * @returns {Promise} */ - getEmailTemplate(params: { templateId: EmailTemplateType, locale?: EmailTemplateLocale }): Promise; + getEmailTemplate(params: { templateId: ProjectEmailTemplateId, locale?: ProjectEmailTemplateLocale }): Promise; /** * Get a custom email template for the specified locale and type. This endpoint returns the template content, subject, and other configuration details. * - * @param {EmailTemplateType} templateId - Custom email template type. Can be one of: verification, magicSession, recovery, invitation, mfaChallenge, sessionAlert, otpSession - * @param {EmailTemplateLocale} locale - Custom email template locale. If left empty, the fallback locale (en) will be used. + * @param {ProjectEmailTemplateId} templateId - Custom email template type. Can be one of: verification, magicSession, recovery, invitation, mfaChallenge, sessionAlert, otpSession + * @param {ProjectEmailTemplateLocale} locale - Custom email template locale. If left empty, the fallback locale (en) will be used. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. */ - getEmailTemplate(templateId: EmailTemplateType, locale?: EmailTemplateLocale): Promise; + getEmailTemplate(templateId: ProjectEmailTemplateId, locale?: ProjectEmailTemplateLocale): Promise; getEmailTemplate( - paramsOrFirst: { templateId: EmailTemplateType, locale?: EmailTemplateLocale } | EmailTemplateType, - ...rest: [(EmailTemplateLocale)?] + paramsOrFirst: { templateId: ProjectEmailTemplateId, locale?: ProjectEmailTemplateLocale } | ProjectEmailTemplateId, + ...rest: [(ProjectEmailTemplateLocale)?] ): Promise { - let params: { templateId: EmailTemplateType, locale?: EmailTemplateLocale }; + let params: { templateId: ProjectEmailTemplateId, locale?: ProjectEmailTemplateLocale }; if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst) && ('templateId' in paramsOrFirst || 'locale' in paramsOrFirst))) { - params = (paramsOrFirst || {}) as { templateId: EmailTemplateType, locale?: EmailTemplateLocale }; + params = (paramsOrFirst || {}) as { templateId: ProjectEmailTemplateId, locale?: ProjectEmailTemplateLocale }; } else { params = { - templateId: paramsOrFirst as EmailTemplateType, - locale: rest[0] as EmailTemplateLocale + templateId: paramsOrFirst as ProjectEmailTemplateId, + locale: rest[0] as ProjectEmailTemplateLocale }; } diff --git a/src/services/projects.ts b/src/services/projects.ts index e5721313..22fb0006 100644 --- a/src/services/projects.ts +++ b/src/services/projects.ts @@ -86,19 +86,10 @@ export class Projects { * @param {string} params.name - Project name. Max length: 128 chars. * @param {string} params.teamId - Team unique ID. * @param {Region} params.region - Project Region. - * @param {string} params.description - Project description. Max length: 256 chars. - * @param {string} params.logo - Project logo. - * @param {string} params.url - Project URL. - * @param {string} params.legalName - Project legal Name. Max length: 256 chars. - * @param {string} params.legalCountry - Project legal Country. Max length: 256 chars. - * @param {string} params.legalState - Project legal State. Max length: 256 chars. - * @param {string} params.legalCity - Project legal City. Max length: 256 chars. - * @param {string} params.legalAddress - Project legal Address. Max length: 256 chars. - * @param {string} params.legalTaxId - Project legal Tax ID. Max length: 256 chars. * @throws {AppwriteException} * @returns {Promise} */ - create(params: { projectId: string, name: string, teamId: string, region?: Region, description?: string, logo?: string, url?: string, legalName?: string, legalCountry?: string, legalState?: string, legalCity?: string, legalAddress?: string, legalTaxId?: string }): Promise; + create(params: { projectId: string, name: string, teamId: string, region?: Region }): Promise; /** * Create a new project. You can create a maximum of 100 projects per account. * @@ -106,43 +97,25 @@ export class Projects { * @param {string} name - Project name. Max length: 128 chars. * @param {string} teamId - Team unique ID. * @param {Region} region - Project Region. - * @param {string} description - Project description. Max length: 256 chars. - * @param {string} logo - Project logo. - * @param {string} url - Project URL. - * @param {string} legalName - Project legal Name. Max length: 256 chars. - * @param {string} legalCountry - Project legal Country. Max length: 256 chars. - * @param {string} legalState - Project legal State. Max length: 256 chars. - * @param {string} legalCity - Project legal City. Max length: 256 chars. - * @param {string} legalAddress - Project legal Address. Max length: 256 chars. - * @param {string} legalTaxId - Project legal Tax ID. Max length: 256 chars. * @throws {AppwriteException} * @returns {Promise} * @deprecated Use the object parameter style method for a better developer experience. */ - create(projectId: string, name: string, teamId: string, region?: Region, description?: string, logo?: string, url?: string, legalName?: string, legalCountry?: string, legalState?: string, legalCity?: string, legalAddress?: string, legalTaxId?: string): Promise; + create(projectId: string, name: string, teamId: string, region?: Region): Promise; create( - paramsOrFirst: { projectId: string, name: string, teamId: string, region?: Region, description?: string, logo?: string, url?: string, legalName?: string, legalCountry?: string, legalState?: string, legalCity?: string, legalAddress?: string, legalTaxId?: string } | string, - ...rest: [(string)?, (string)?, (Region)?, (string)?, (string)?, (string)?, (string)?, (string)?, (string)?, (string)?, (string)?, (string)?] + paramsOrFirst: { projectId: string, name: string, teamId: string, region?: Region } | string, + ...rest: [(string)?, (string)?, (Region)?] ): Promise { - let params: { projectId: string, name: string, teamId: string, region?: Region, description?: string, logo?: string, url?: string, legalName?: string, legalCountry?: string, legalState?: string, legalCity?: string, legalAddress?: string, legalTaxId?: string }; + let params: { projectId: string, name: string, teamId: string, region?: Region }; if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) { - params = (paramsOrFirst || {}) as { projectId: string, name: string, teamId: string, region?: Region, description?: string, logo?: string, url?: string, legalName?: string, legalCountry?: string, legalState?: string, legalCity?: string, legalAddress?: string, legalTaxId?: string }; + params = (paramsOrFirst || {}) as { projectId: string, name: string, teamId: string, region?: Region }; } else { params = { projectId: paramsOrFirst as string, name: rest[0] as string, teamId: rest[1] as string, - region: rest[2] as Region, - description: rest[3] as string, - logo: rest[4] as string, - url: rest[5] as string, - legalName: rest[6] as string, - legalCountry: rest[7] as string, - legalState: rest[8] as string, - legalCity: rest[9] as string, - legalAddress: rest[10] as string, - legalTaxId: rest[11] as string + region: rest[2] as Region }; } @@ -150,15 +123,6 @@ export class Projects { const name = params.name; const teamId = params.teamId; const region = params.region; - const description = params.description; - const logo = params.logo; - const url = params.url; - const legalName = params.legalName; - const legalCountry = params.legalCountry; - const legalState = params.legalState; - const legalCity = params.legalCity; - const legalAddress = params.legalAddress; - const legalTaxId = params.legalTaxId; if (typeof projectId === 'undefined') { throw new AppwriteException('Missing required parameter: "projectId"'); @@ -184,33 +148,6 @@ export class Projects { if (typeof region !== 'undefined') { payload['region'] = region; } - if (typeof description !== 'undefined') { - payload['description'] = description; - } - if (typeof logo !== 'undefined') { - payload['logo'] = logo; - } - if (typeof url !== 'undefined') { - payload['url'] = url; - } - if (typeof legalName !== 'undefined') { - payload['legalName'] = legalName; - } - if (typeof legalCountry !== 'undefined') { - payload['legalCountry'] = legalCountry; - } - if (typeof legalState !== 'undefined') { - payload['legalState'] = legalState; - } - if (typeof legalCity !== 'undefined') { - payload['legalCity'] = legalCity; - } - if (typeof legalAddress !== 'undefined') { - payload['legalAddress'] = legalAddress; - } - if (typeof legalTaxId !== 'undefined') { - payload['legalTaxId'] = legalTaxId; - } const uri = new URL(this.client.config.endpoint + apiPath); const apiHeaders: { [header: string]: string } = { @@ -225,57 +162,6 @@ export class Projects { ); } - /** - * Get a project by its unique ID. This endpoint allows you to retrieve the project's details, including its name, description, team, region, and other metadata. - * - * @param {string} params.projectId - Project unique ID. - * @throws {AppwriteException} - * @returns {Promise} - */ - get(params: { projectId: string }): Promise; - /** - * Get a project by its unique ID. This endpoint allows you to retrieve the project's details, including its name, description, team, region, and other metadata. - * - * @param {string} projectId - Project unique ID. - * @throws {AppwriteException} - * @returns {Promise} - * @deprecated Use the object parameter style method for a better developer experience. - */ - get(projectId: string): Promise; - get( - paramsOrFirst: { projectId: string } | string - ): Promise { - let params: { projectId: string }; - - if ((paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) { - params = (paramsOrFirst || {}) as { projectId: string }; - } else { - params = { - projectId: paramsOrFirst as string - }; - } - - const projectId = params.projectId; - - if (typeof projectId === 'undefined') { - throw new AppwriteException('Missing required parameter: "projectId"'); - } - - const apiPath = '/projects/{projectId}'.replace('{projectId}', projectId); - const payload: Payload = {}; - const uri = new URL(this.client.config.endpoint + apiPath); - - const apiHeaders: { [header: string]: string } = { - } - - return this.client.call( - 'get', - uri, - apiHeaders, - payload - ); - } - /** * Update a project by its unique ID. * diff --git a/src/services/realtime.ts b/src/services/realtime.ts index a1368b9e..7aebdaa6 100644 --- a/src/services/realtime.ts +++ b/src/services/realtime.ts @@ -52,10 +52,30 @@ export type RealtimeResponseConnected = { } export type RealtimeRequest = { - type: 'authentication' | 'subscribe' | 'unsubscribe'; + type: 'authentication' | 'subscribe' | 'unsubscribe' | 'presence'; data: any; } +export type RealtimePresence = { + $id: string; + $sequence?: string | number; + $createdAt: string; + $updatedAt: string; + $permissions: string[]; + userInternalId: string; + userId: string; + status?: string; + source: string; + metadata?: Record; +} + +export type RealtimePresenceCreate = { + status: string; + presenceId: string; + permissions?: string[]; + metadata?: Record; +} + type RealtimeRequestSubscribeRow = { subscriptionId?: string; channels: string[]; @@ -73,7 +93,6 @@ export class Realtime { private readonly TYPE_EVENT = 'event'; private readonly TYPE_PONG = 'pong'; private readonly TYPE_CONNECTED = 'connected'; - private readonly TYPE_RESPONSE = 'response'; private readonly DEBOUNCE_MS = 1; private readonly HEARTBEAT_INTERVAL = 20000; // 20 seconds in milliseconds @@ -81,7 +100,13 @@ export class Realtime { private socket?: WebSocket; private activeSubscriptions = new Map>(); private pendingSubscribes = new Map(); + private pendingPresence?: Record; + private appConnected = false; private heartbeatTimer?: number; + // Single-flight lock for createSocket(). When set, concurrent callers join + // this promise instead of issuing a second `new WebSocket(...)`. Cleared + // after the underlying connect resolves or rejects. + private socketCreationPromise?: Promise; private subCallDepth = 0; private reconnectAttempts = 0; @@ -142,8 +167,33 @@ export class Realtime { } } + /** + * Idempotent socket opener. Both `subscribe()` and `upsertPresence()` can + * call this; the single-flight lock (`socketCreationPromise`) guarantees + * only one `new WebSocket(...)` is ever in flight, so concurrent callers + * join the same connection attempt instead of opening duplicates. + * + * Returns early when a healthy socket is already present. + */ private async createSocket(): Promise { - if (this.activeSubscriptions.size === 0) { + // Fast path: a usable socket is already there. No need to open another. + if (this.socket && this.socket.readyState < WebSocket.CLOSING) { + return; + } + // Another caller is already opening one — join it. + if (this.socketCreationPromise) { + return this.socketCreationPromise; + } + this.socketCreationPromise = this.createSocketLocked().finally(() => { + this.socketCreationPromise = undefined; + }); + return this.socketCreationPromise; + } + + private async createSocketLocked(): Promise { + // Nothing to do if there's neither a subscription nor a queued presence + // that needs the wire. (Reconnect cleanup path also flows through here.) + if (this.activeSubscriptions.size === 0 && !this.pendingPresence) { this.reconnect = false; await this.closeSocket(); return; @@ -176,6 +226,15 @@ export class Realtime { } return new Promise((resolve, reject) => { + // Re-check the entry guard synchronously. `disconnect()` may have + // run during the `await this.closeSocket()` above (or any other + // await between the original guard and here), clearing every + // subscription and the pending presence. In that case opening a + // fresh socket would leak a connection with nothing attached. + if (this.activeSubscriptions.size === 0 && !this.pendingPresence) { + resolve(); + return; + } try { const connectionId = ++this.connectionId; const socket = (this.socket = new WebSocket(url)); @@ -206,6 +265,7 @@ export class Realtime { if (connectionId !== this.connectionId || socket !== this.socket) { return; } + this.appConnected = false; this.stopHeartbeat(); this.onCloseCallbacks.forEach(callback => callback()); @@ -326,7 +386,19 @@ export class Realtime { public async disconnect(): Promise { this.activeSubscriptions.clear(); this.pendingSubscribes.clear(); + this.pendingPresence = undefined; + this.appConnected = false; this.reconnect = false; + // Drop the in-flight single-flight slot. Promises can't be cancelled, + // so the underlying createSocketLocked() promise may stay pending + // forever — e.g. when closeSocket() below tears down a CONNECTING + // socket, the `close` event fires but `open`/`error` never do, and + // the inner `new Promise(...)` only resolves on those. Without this + // line, the next subscribe()/upsertPresence() would join the orphan + // promise via the single-flight gate and hang, leaving its pending + // subscription queued with no socket ever opened. Mirrors the Swift + // template's socketCreationTask cancel in disconnect(). + this.socketCreationPromise = undefined; await this.closeSocket(); } @@ -334,6 +406,18 @@ export class Realtime { if (!this.socket || this.socket.readyState !== WebSocket.OPEN) { return; } + // The WebSocket 'open' event fires when the TCP/upgrade handshake + // completes — but the server only accepts `subscribe` frames after + // it has emitted its own application-level `connected` event (which + // flips `appConnected` to true in handleResponseConnected). Sending + // before then triggers a policy-violation close on real Appwrite, + // which reconnects, which sends early again — i.e. a duplicate- + // socket loop. handleResponseConnected re-enqueues every active + // subscription and calls this method again once it's safe, so the + // queued rows are guaranteed to be sent. + if (!this.appConnected) { + return; + } if (this.pendingSubscribes.size < 1) { return; @@ -532,6 +616,66 @@ export class Realtime { return { unsubscribe, update, close }; } + /** + * Fire-and-forget presence upsert. Records the latest payload in state so + * that — if the WebSocket isn't open yet, or later reconnects — only the + * most recent presence is automatically (re)sent on the next `connected` + * event. Repeated calls while the socket is closed collapse to the latest + * payload (older ones are discarded). + * + * Returns a `Promise` for API consistency; the promise resolves as + * soon as the payload has been stored and the opportunistic send attempted. + * + * @param {RealtimePresenceCreate} params - Presence payload (status and presenceId required, permissions/metadata optional) + */ + public async upsertPresence(params: RealtimePresenceCreate): Promise { + const data: Record = { + status: params.status, + presenceId: params.presenceId, + }; + if (params.permissions !== undefined) { + data.permissions = params.permissions; + } + if (params.metadata !== undefined) { + data.metadata = params.metadata; + } + + this.pendingPresence = data; + + // Both subscribe() and upsertPresence() may need to open the socket. + // createSocket() is single-flight (see `socketCreationPromise`), so + // calling it here is a no-op when a connection is already in flight or + // healthy. Fire-and-forget keeps the documented fire-and-forget shape + // of upsertPresence: the returned Promise resolves as soon as the + // payload is stored. + if (!this.socket || this.socket.readyState >= WebSocket.CLOSING) { + this.createSocket().catch((error) => { + console.error('Failed to open realtime socket for presence:', error); + }); + } + + // Opportunistic send for the case where the socket is already past the + // `connected` handshake. The gate inside flushPendingPresence keeps + // this a no-op until appConnected flips to true. + this.flushPendingPresence(); + } + + private flushPendingPresence(): void { + if (!this.pendingPresence) { + return; + } + if (!this.socket || this.socket.readyState !== WebSocket.OPEN) { + return; + } + if (!this.appConnected) { + return; + } + this.socket.send(JSONbig.stringify({ + type: 'presence', + data: this.pendingPresence + })); + } + private handleMessage(message: RealtimeResponse): void { if (!message.type) { return; @@ -550,9 +694,6 @@ export class Realtime { case this.TYPE_PONG: // Handle pong response if needed break; - case this.TYPE_RESPONSE: - this.handleResponseAction(message); - break; } } @@ -585,7 +726,9 @@ export class Realtime { for (const subscriptionId of this.activeSubscriptions.keys()) { this.enqueuePendingSubscribe(subscriptionId); } + this.appConnected = true; this.sendPendingSubscribes(); + this.flushPendingPresence(); } private handleResponseError(message: RealtimeResponse): void { @@ -626,10 +769,4 @@ export class Realtime { }); } } - - private handleResponseAction(_message: RealtimeResponse): void { - // The SDK generates subscriptionIds client-side and sends them on every - // subscribe/unsubscribe, so subscribe/unsubscribe acks carry no state - // the SDK needs to reconcile. - } } diff --git a/src/services/usage.ts b/src/services/usage.ts new file mode 100644 index 00000000..ba131a6d --- /dev/null +++ b/src/services/usage.ts @@ -0,0 +1,130 @@ +import { Service } from '../service'; +import { AppwriteException, Client, type Payload, UploadProgress } from '../client'; +import type { Models } from '../models'; + + +export class Usage { + client: Client; + + constructor(client: Client) { + this.client = client; + } + + /** + * Query usage event metrics from the usage database. Returns individual event rows with full metadata. Pass Query objects as JSON strings to filter, paginate, and order results. Supported query methods: equal, greaterThanEqual, lessThanEqual, orderAsc, orderDesc, limit, offset. Supported filter attributes: metric, path, method, status, resource, resourceId, country, userAgent, time (these match the underlying column names — note that the response surfaces `resource` as `resourceType` and `country` as `countryCode`). When no time filter is supplied the endpoint defaults to the last 7 days. Default `limit(100)` is applied if none is given; user-supplied limits are capped at 500. The `total` field is capped at 5000 to keep counts predictable — pass `total=false` to skip the count entirely. + * + * @param {string[]} params.queries - Array of query strings as JSON. Supported: equal("metric", [...]), equal("path", [...]), equal("method", [...]), equal("status", [...]), equal("resource", [...]), equal("resourceId", [...]), equal("country", [...]), equal("userAgent", [...]), greaterThanEqual("time", "..."), lessThanEqual("time", "..."), orderAsc("time"), orderDesc("time"), limit(N), offset(N). + * @param {boolean} params.total - When set to false, the total count returned will be 0 and will not be calculated. + * @throws {AppwriteException} + * @returns {Promise} + */ + listEvents(params?: { queries?: string[], total?: boolean }): Promise; + /** + * Query usage event metrics from the usage database. Returns individual event rows with full metadata. Pass Query objects as JSON strings to filter, paginate, and order results. Supported query methods: equal, greaterThanEqual, lessThanEqual, orderAsc, orderDesc, limit, offset. Supported filter attributes: metric, path, method, status, resource, resourceId, country, userAgent, time (these match the underlying column names — note that the response surfaces `resource` as `resourceType` and `country` as `countryCode`). When no time filter is supplied the endpoint defaults to the last 7 days. Default `limit(100)` is applied if none is given; user-supplied limits are capped at 500. The `total` field is capped at 5000 to keep counts predictable — pass `total=false` to skip the count entirely. + * + * @param {string[]} queries - Array of query strings as JSON. Supported: equal("metric", [...]), equal("path", [...]), equal("method", [...]), equal("status", [...]), equal("resource", [...]), equal("resourceId", [...]), equal("country", [...]), equal("userAgent", [...]), greaterThanEqual("time", "..."), lessThanEqual("time", "..."), orderAsc("time"), orderDesc("time"), limit(N), offset(N). + * @param {boolean} total - When set to false, the total count returned will be 0 and will not be calculated. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + listEvents(queries?: string[], total?: boolean): Promise; + listEvents( + paramsOrFirst?: { queries?: string[], total?: boolean } | string[], + ...rest: [(boolean)?] + ): Promise { + let params: { queries?: string[], total?: boolean }; + + if (!paramsOrFirst || (paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) { + params = (paramsOrFirst || {}) as { queries?: string[], total?: boolean }; + } else { + params = { + queries: paramsOrFirst as string[], + total: rest[0] as boolean + }; + } + + const queries = params.queries; + const total = params.total; + + + const apiPath = '/usage/events'; + const payload: Payload = {}; + if (typeof queries !== 'undefined') { + payload['queries'] = queries; + } + if (typeof total !== 'undefined') { + payload['total'] = total; + } + const uri = new URL(this.client.config.endpoint + apiPath); + + const apiHeaders: { [header: string]: string } = { + } + + return this.client.call( + 'get', + uri, + apiHeaders, + payload + ); + } + + /** + * Query usage gauge metrics (point-in-time resource snapshots) from the usage database. Returns individual gauge snapshots with metric, value, and timestamp. Pass Query objects as JSON strings to filter, paginate, and order results. Supported query methods: equal, greaterThanEqual, lessThanEqual, orderAsc, orderDesc, limit, offset. Supported filter attributes: metric, time. Use `orderDesc("time"), limit(1)` to fetch the most recent snapshot. When no time filter is supplied the endpoint defaults to the last 7 days. Default `limit(100)` is applied if none is given; user-supplied limits are capped at 500. The `total` field is capped at 5000 to keep counts predictable — pass `total=false` to skip the count entirely. + * + * @param {string[]} params.queries - Array of query strings as JSON. Supported: equal("metric", [...]), greaterThanEqual("time", "..."), lessThanEqual("time", "..."), orderAsc("time"), orderDesc("time"), limit(N), offset(N). + * @param {boolean} params.total - When set to false, the total count returned will be 0 and will not be calculated. + * @throws {AppwriteException} + * @returns {Promise} + */ + listGauges(params?: { queries?: string[], total?: boolean }): Promise; + /** + * Query usage gauge metrics (point-in-time resource snapshots) from the usage database. Returns individual gauge snapshots with metric, value, and timestamp. Pass Query objects as JSON strings to filter, paginate, and order results. Supported query methods: equal, greaterThanEqual, lessThanEqual, orderAsc, orderDesc, limit, offset. Supported filter attributes: metric, time. Use `orderDesc("time"), limit(1)` to fetch the most recent snapshot. When no time filter is supplied the endpoint defaults to the last 7 days. Default `limit(100)` is applied if none is given; user-supplied limits are capped at 500. The `total` field is capped at 5000 to keep counts predictable — pass `total=false` to skip the count entirely. + * + * @param {string[]} queries - Array of query strings as JSON. Supported: equal("metric", [...]), greaterThanEqual("time", "..."), lessThanEqual("time", "..."), orderAsc("time"), orderDesc("time"), limit(N), offset(N). + * @param {boolean} total - When set to false, the total count returned will be 0 and will not be calculated. + * @throws {AppwriteException} + * @returns {Promise} + * @deprecated Use the object parameter style method for a better developer experience. + */ + listGauges(queries?: string[], total?: boolean): Promise; + listGauges( + paramsOrFirst?: { queries?: string[], total?: boolean } | string[], + ...rest: [(boolean)?] + ): Promise { + let params: { queries?: string[], total?: boolean }; + + if (!paramsOrFirst || (paramsOrFirst && typeof paramsOrFirst === 'object' && !Array.isArray(paramsOrFirst))) { + params = (paramsOrFirst || {}) as { queries?: string[], total?: boolean }; + } else { + params = { + queries: paramsOrFirst as string[], + total: rest[0] as boolean + }; + } + + const queries = params.queries; + const total = params.total; + + + const apiPath = '/usage/gauges'; + const payload: Payload = {}; + if (typeof queries !== 'undefined') { + payload['queries'] = queries; + } + if (typeof total !== 'undefined') { + payload['total'] = total; + } + const uri = new URL(this.client.config.endpoint + apiPath); + + const apiHeaders: { [header: string]: string } = { + } + + return this.client.call( + 'get', + uri, + apiHeaders, + payload + ); + } +}