diff --git a/src/lib/stores/migration.ts b/src/lib/stores/migration.ts index 756f63661f..64f9bfc3d8 100644 --- a/src/lib/stores/migration.ts +++ b/src/lib/stores/migration.ts @@ -11,11 +11,38 @@ export type MigrationResource = | AppwriteMigrationResource | FirebaseMigrationResource | NHostMigrationResource - | SupabaseMigrationResource; + | SupabaseMigrationResource + | 'platform' + | 'api-key' + | 'project-variable' + | 'webhook' + | 'auth-methods' + | 'protocols' + | 'labels' + | 'services' + | 'policies' + | 'smtp' + | 'rule'; // Appwrite enum is the superset of all provider resources — used as a // provider-agnostic reference. The addResource guard filters by provider. -export const MigrationResources = AppwriteMigrationResource; +// Project-level singleton resources (Platform, ApiKey, ProjectVariable, +// Webhook, AuthMethods, Protocols, Labels, Services, Policies) are augmented +// locally until @appwrite.io/console SDK is regenerated. +export const MigrationResources = { + ...AppwriteMigrationResource, + Platform: 'platform', + ApiKey: 'api-key', + ProjectVariable: 'project-variable', + Webhook: 'webhook', + AuthMethods: 'auth-methods', + Protocols: 'protocols', + Labels: 'labels', + Services: 'services', + Policies: 'policies', + SMTP: 'smtp', + Rule: 'rule' +} as const; type ProviderResourceMap = { appwrite: AppwriteMigrationResource[]; @@ -50,6 +77,35 @@ const initialFormData = { }, backups: { root: false + }, + authMethods: { + root: false + }, + protocols: { + root: false + }, + labels: { + root: false + }, + services: { + root: false + }, + policies: { + root: false + }, + smtp: { + root: false + }, + customDomains: { + root: false + }, + integrations: { + root: false, + apiKeys: false + }, + settings: { + root: false, + webhooks: false } }; @@ -88,11 +144,35 @@ export const ResourcesFriendly = { topic: { singular: 'Topic', plural: 'Topics' }, subscriber: { singular: 'Subscriber', plural: 'Subscribers' }, message: { singular: 'Message', plural: 'Messages' }, - 'backup-policy': { singular: 'Backup Policy', plural: 'Backup Policies' } + 'backup-policy': { singular: 'Backup Policy', plural: 'Backup Policies' }, + platform: { singular: 'Platform', plural: 'Platforms' }, + 'api-key': { singular: 'API Key', plural: 'API Keys' }, + 'project-variable': { singular: 'Project Variable', plural: 'Project Variables' }, + webhook: { singular: 'Webhook', plural: 'Webhooks' }, + 'auth-methods': { singular: 'Auth method config', plural: 'Auth method config' }, + protocols: { singular: 'Protocol config', plural: 'Protocol config' }, + labels: { singular: 'Project labels', plural: 'Project labels' }, + services: { singular: 'Services config', plural: 'Services config' }, + policies: { singular: 'Policies config', plural: 'Policies config' }, + smtp: { singular: 'SMTP config', plural: 'SMTP config' }, + rule: { singular: 'Custom domain', plural: 'Custom domains' } }; export const providerResources: ProviderResourceMap = { - appwrite: Object.values(AppwriteMigrationResource), + appwrite: [ + ...Object.values(AppwriteMigrationResource), + MigrationResources.AuthMethods as AppwriteMigrationResource, + MigrationResources.Protocols as AppwriteMigrationResource, + MigrationResources.Labels as AppwriteMigrationResource, + MigrationResources.Services as AppwriteMigrationResource, + MigrationResources.Policies as AppwriteMigrationResource, + MigrationResources.SMTP as AppwriteMigrationResource, + MigrationResources.Rule as AppwriteMigrationResource, + MigrationResources.Platform as AppwriteMigrationResource, + MigrationResources.ApiKey as AppwriteMigrationResource, + MigrationResources.ProjectVariable as AppwriteMigrationResource, + MigrationResources.Webhook as AppwriteMigrationResource + ], supabase: Object.values(SupabaseMigrationResource), nhost: Object.values(NHostMigrationResource), firebase: Object.values(FirebaseMigrationResource) @@ -155,6 +235,39 @@ export const migrationFormToResources =

( if (formData.backups.root) { addResource(MigrationResources.Backuppolicy); } + if (formData.authMethods.root) { + addResource(MigrationResources.AuthMethods); + } + if (formData.protocols.root) { + addResource(MigrationResources.Protocols); + } + if (formData.labels.root) { + addResource(MigrationResources.Labels); + } + if (formData.services.root) { + addResource(MigrationResources.Services); + } + if (formData.policies.root) { + addResource(MigrationResources.Policies); + } + if (formData.smtp.root) { + addResource(MigrationResources.SMTP); + } + if (formData.customDomains.root) { + addResource(MigrationResources.Rule); + } + if (formData.integrations.root) { + addResource(MigrationResources.Platform); + if (formData.integrations.apiKeys) { + addResource(MigrationResources.ApiKey); + } + } + if (formData.settings.root) { + addResource(MigrationResources.ProjectVariable); + if (formData.settings.webhooks) { + addResource(MigrationResources.Webhook); + } + } return resources as ProviderResourceMap[P]; }; @@ -234,6 +347,41 @@ export const resourcesToMigrationForm = (resources: MigrationResource[]): Migrat if (resources.includes(MigrationResources.Backuppolicy)) { formData.backups.root = true; } + if (resources.includes(MigrationResources.AuthMethods)) { + formData.authMethods.root = true; + } + if (resources.includes(MigrationResources.Protocols)) { + formData.protocols.root = true; + } + if (resources.includes(MigrationResources.Labels)) { + formData.labels.root = true; + } + if (resources.includes(MigrationResources.Services)) { + formData.services.root = true; + } + if (resources.includes(MigrationResources.Policies)) { + formData.policies.root = true; + } + if (resources.includes(MigrationResources.SMTP)) { + formData.smtp.root = true; + } + if (resources.includes(MigrationResources.Rule)) { + formData.customDomains.root = true; + } + if (resources.includes(MigrationResources.Platform)) { + formData.integrations.root = true; + } + if (resources.includes(MigrationResources.ApiKey)) { + formData.integrations.root = true; + formData.integrations.apiKeys = true; + } + if (resources.includes(MigrationResources.ProjectVariable)) { + formData.settings.root = true; + } + if (resources.includes(MigrationResources.Webhook)) { + formData.settings.root = true; + formData.settings.webhooks = true; + } return formData; }; diff --git a/src/routes/(console)/(migration-wizard)/resource-form.svelte b/src/routes/(console)/(migration-wizard)/resource-form.svelte index 7b863f7b79..003ba4462a 100644 --- a/src/routes/(console)/(migration-wizard)/resource-form.svelte +++ b/src/routes/(console)/(migration-wizard)/resource-form.svelte @@ -119,6 +119,48 @@ return resources.includes(MigrationResources.Backuppolicy); } + if (groupKey === 'authMethods') { + return resources.includes(MigrationResources.AuthMethods); + } + + if (groupKey === 'protocols') { + return resources.includes(MigrationResources.Protocols); + } + + if (groupKey === 'labels') { + return resources.includes(MigrationResources.Labels); + } + + if (groupKey === 'services') { + return resources.includes(MigrationResources.Services); + } + + if (groupKey === 'policies') { + return resources.includes(MigrationResources.Policies); + } + + if (groupKey === 'smtp') { + return resources.includes(MigrationResources.SMTP); + } + + if (groupKey === 'customDomains') { + return resources.includes(MigrationResources.Rule); + } + + if (groupKey === 'integrations') { + return ( + resources.includes(MigrationResources.Platform) || + resources.includes(MigrationResources.ApiKey) + ); + } + + if (groupKey === 'settings') { + return ( + resources.includes(MigrationResources.ProjectVariable) || + resources.includes(MigrationResources.Webhook) + ); + } + const groupToResource: Record = { users: MigrationResources.User, databases: MigrationResources.Database @@ -140,7 +182,16 @@ storage: 'bucket', sites: 'site', messaging: 'provider', - backups: 'backup-policy' + backups: 'backup-policy', + authMethods: 'auth-methods', + protocols: 'protocols', + labels: 'labels', + services: 'services', + policies: 'policies', + smtp: 'smtp', + customDomains: 'rule', + integrations: 'platform', + settings: 'project-variable' }; return map[groupKey] || groupKey; }; diff --git a/src/routes/(console)/project-[region]-[project]/settings/migrations/(import)/importReport.svelte b/src/routes/(console)/project-[region]-[project]/settings/migrations/(import)/importReport.svelte index 991426918c..0accfe4010 100644 --- a/src/routes/(console)/project-[region]-[project]/settings/migrations/(import)/importReport.svelte +++ b/src/routes/(console)/project-[region]-[project]/settings/migrations/(import)/importReport.svelte @@ -36,6 +36,35 @@ }, backups: { root: 'Backup policies' + }, + authMethods: { + root: 'Auth methods' + }, + protocols: { + root: 'Protocols' + }, + labels: { + root: 'Project labels' + }, + services: { + root: 'Services' + }, + policies: { + root: 'Security policies' + }, + smtp: { + root: 'Custom SMTP' + }, + customDomains: { + root: 'Custom domains' + }, + integrations: { + root: 'Platforms', + apiKeys: 'Include API keys' + }, + settings: { + root: 'Project variables', + webhooks: 'Include webhooks' } }; @@ -62,6 +91,36 @@ }, backups: { root: 'Import all backup policies' + }, + authMethods: { + root: 'Import the project auth method flags (email/password, magic URL, JWT, phone, etc.)' + }, + protocols: { + root: 'Import the project protocol flags (REST / GraphQL / WebSocket)' + }, + labels: { + root: 'Import the project-level RBAC label array' + }, + services: { + root: 'Import the project service enable/disable flags (Account, Databases, Functions, GraphQL, etc.)' + }, + policies: { + root: 'Import the project security policies (password rules, session behavior, user limits, membership privacy)' + }, + smtp: { + root: 'Import the project custom SMTP configuration (the password is not exposed by the SDK and stays on the destination)' + }, + customDomains: { + root: 'Import manually-added custom-domain proxy rules (API, function, site, redirect). Auto-generated `.appwrite.network` rules are skipped — they are recreated by parent Function/Site migration.' + }, + integrations: { + root: 'Import all platforms (web, Flutter, iOS, Android, etc.)', + apiKeys: 'Import all API keys with their scopes and expiration' + }, + settings: { + root: 'Import all project-level variables (secret values are not exposed by the SDK and will be migrated empty)', + webhooks: + 'Import all webhooks (signing secrets are not exposed by the SDK; the destination regenerates a fresh signature key for each)' } };