diff --git a/package.json b/package.json index a2e1778fe..6ff0f771a 100644 --- a/package.json +++ b/package.json @@ -22,12 +22,13 @@ }, "dependencies": { "@ai-sdk/svelte": "^1.1.24", - "@appwrite.io/console": "https://pkg.vc/-/@appwrite/@appwrite.io/console@f21fc7f", + "@appwrite.io/console": "https://pkg.vc/-/@appwrite/@appwrite.io/console@9c55755", "@appwrite.io/pink-icons": "0.25.0", - "@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@865e2fc", + "@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@bbad65f", "@appwrite.io/pink-legacy": "^1.0.3", - "@appwrite.io/pink-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@865e2fc", + "@appwrite.io/pink-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@bbad65f", "@faker-js/faker": "^9.9.0", + "@plausible-analytics/tracker": "^0.4.4", "@popperjs/core": "^2.11.8", "@sentry/sveltekit": "^8.38.0", "@stripe/stripe-js": "^3.5.0", @@ -42,7 +43,6 @@ "ignore": "^6.0.2", "nanoid": "^5.1.5", "nanotar": "^0.1.1", - "plausible-tracker": "^0.3.9", "pretty-bytes": "^6.1.1", "prismjs": "^1.30.0", "remarkable": "^2.0.1", @@ -57,7 +57,7 @@ "@melt-ui/svelte": "^0.86.5", "@playwright/test": "^1.55.1", "@sveltejs/adapter-static": "^3.0.8", - "@sveltejs/kit": "^2.42.1", + "@sveltejs/kit": "^2.49.5", "@sveltejs/vite-plugin-svelte": "^5.0.3", "@testing-library/dom": "^10.4.0", "@testing-library/jest-dom": "^6.6.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9a968c01e..d01808519 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,29 +12,32 @@ importers: specifier: ^1.1.24 version: 1.1.24(svelte@5.25.3)(zod@3.24.3) '@appwrite.io/console': - specifier: https://pkg.vc/-/@appwrite/@appwrite.io/console@f21fc7f - version: https://pkg.vc/-/@appwrite/@appwrite.io/console@f21fc7f + specifier: https://pkg.vc/-/@appwrite/@appwrite.io/console@9c55755 + version: https://pkg.vc/-/@appwrite/@appwrite.io/console@9c55755 '@appwrite.io/pink-icons': specifier: 0.25.0 version: 0.25.0 '@appwrite.io/pink-icons-svelte': - specifier: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@865e2fc - version: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@865e2fc(svelte@5.25.3) + specifier: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@bbad65f + version: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@bbad65f(svelte@5.25.3) '@appwrite.io/pink-legacy': specifier: ^1.0.3 version: 1.0.3 '@appwrite.io/pink-svelte': - specifier: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@865e2fc - version: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@865e2fc(svelte@5.25.3) + specifier: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@bbad65f + version: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@bbad65f(svelte@5.25.3) '@faker-js/faker': specifier: ^9.9.0 version: 9.9.0 + '@plausible-analytics/tracker': + specifier: ^0.4.4 + version: 0.4.4 '@popperjs/core': specifier: ^2.11.8 version: 2.11.8 '@sentry/sveltekit': specifier: ^8.38.0 - version: 8.55.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.30.0)(@sveltejs/kit@2.42.1(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)) + version: 8.55.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.30.0)(@sveltejs/kit@2.49.5(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(typescript@5.8.2)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)) '@stripe/stripe-js': specifier: ^3.5.0 version: 3.5.0 @@ -71,9 +74,6 @@ importers: nanotar: specifier: ^0.1.1 version: 0.1.1 - plausible-tracker: - specifier: ^0.3.9 - version: 0.3.9 pretty-bytes: specifier: ^6.1.1 version: 6.1.1 @@ -110,10 +110,10 @@ importers: version: 1.56.1 '@sveltejs/adapter-static': specifier: ^3.0.8 - version: 3.0.8(@sveltejs/kit@2.42.1(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0))) + version: 3.0.8(@sveltejs/kit@2.49.5(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(typescript@5.8.2)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0))) '@sveltejs/kit': - specifier: ^2.42.1 - version: 2.42.1(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)) + specifier: ^2.49.5 + version: 2.49.5(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(typescript@5.8.2)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)) '@sveltejs/vite-plugin-svelte': specifier: ^5.0.3 version: 5.0.3(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)) @@ -272,17 +272,17 @@ packages: '@analytics/type-utils@0.6.2': resolution: {integrity: sha512-TD+xbmsBLyYy/IxFimW/YL/9L2IEnM7/EoV9Aeh56U64Ify8o27HJcKjo38XY9Tcn0uOq1AX3thkKgvtWvwFQg==} - '@appwrite.io/console@https://pkg.vc/-/@appwrite/@appwrite.io/console@f21fc7f': - resolution: {tarball: https://pkg.vc/-/@appwrite/@appwrite.io/console@f21fc7f} - version: 1.10.0 + '@appwrite.io/console@https://pkg.vc/-/@appwrite/@appwrite.io/console@9c55755': + resolution: {tarball: https://pkg.vc/-/@appwrite/@appwrite.io/console@9c55755} + version: 2.1.0 '@appwrite.io/pink-icons-svelte@2.0.0-RC.1': resolution: {integrity: sha512-iLFlV55hj8mGuAbmxJGenxN5RaZMmVT4GJb9dv/MP1xBAtYibFq7JvBcxm18qV2KU8c31Rntf+Ub4GL7HwqTYg==} peerDependencies: svelte: ^4.0.0 - '@appwrite.io/pink-icons-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@865e2fc': - resolution: {tarball: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@865e2fc} + '@appwrite.io/pink-icons-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@bbad65f': + resolution: {tarball: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@bbad65f} version: 2.0.0-RC.1 peerDependencies: svelte: ^4.0.0 @@ -296,8 +296,8 @@ packages: '@appwrite.io/pink-legacy@1.0.3': resolution: {integrity: sha512-GGde5fmPhs+s6/3aFeMPc/kKADG/gTFkYQSy6oBN8pK0y0XNCLrZZgBv+EBbdhwdtqVEWXa0X85Mv9w7jcIlwQ==} - '@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@865e2fc': - resolution: {tarball: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@865e2fc} + '@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@bbad65f': + resolution: {tarball: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@bbad65f} version: 2.0.0-RC.2 peerDependencies: svelte: ^4.0.0 @@ -364,8 +364,8 @@ packages: engines: {node: '>=6.0.0'} hasBin: true - '@babel/parser@7.28.5': - resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} + '@babel/parser@7.28.6': + resolution: {integrity: sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==} engines: {node: '>=6.0.0'} hasBin: true @@ -385,8 +385,8 @@ packages: resolution: {integrity: sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==} engines: {node: '>=6.9.0'} - '@babel/types@7.28.5': - resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} + '@babel/types@7.28.6': + resolution: {integrity: sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==} engines: {node: '>=6.9.0'} '@csstools/color-helpers@5.0.2': @@ -1008,6 +1008,9 @@ packages: resolution: {integrity: sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==} engines: {node: '>= 10.0.0'} + '@plausible-analytics/tracker@0.4.4': + resolution: {integrity: sha512-fz0NOYUEYXtg1TBaPEEvtcBq3FfmLFuTe1VZw4M8sTWX129br5dguu3M15+plOQnc181ShYe67RfwhKgK89VnA==} + '@playwright/test@1.56.1': resolution: {integrity: sha512-vSMYtL/zOcFpvJCW71Q/OEGQb7KYBPAdKh35WNSkaZA75JlAO8ED8UN6GUNTm3drWomcbcqRPFqQbLae8yBTdg==} engines: {node: '>=18'} @@ -1279,18 +1282,21 @@ packages: peerDependencies: '@sveltejs/kit': ^2.0.0 - '@sveltejs/kit@2.42.1': - resolution: {integrity: sha512-SoWdb/OxEKHMlXZ78eNZa4pR1YdOGnUfcFj5NylJv+ZaTrnHK5xapw+7RJP2MiS1D4T+sEH25/tmMtmEl8p6VA==} + '@sveltejs/kit@2.49.5': + resolution: {integrity: sha512-dCYqelr2RVnWUuxc+Dk/dB/SjV/8JBndp1UovCyCZdIQezd8TRwFLNZctYkzgHxRJtaNvseCSRsuuHPeUgIN/A==} engines: {node: '>=18.13'} hasBin: true peerDependencies: '@opentelemetry/api': ^1.0.0 '@sveltejs/vite-plugin-svelte': ^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0 svelte: ^4.0.0 || ^5.0.0-next.0 + typescript: ^5.3.3 vite: ^5.0.3 || ^6.0.0 || ^7.0.0-beta.0 peerDependenciesMeta: '@opentelemetry/api': optional: true + typescript: + optional: true '@sveltejs/vite-plugin-svelte-inspector@4.0.1': resolution: {integrity: sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw==} @@ -1882,6 +1888,9 @@ packages: csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + d3-array@3.2.4: resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} engines: {node: '>=12'} @@ -2072,8 +2081,8 @@ packages: engines: {node: '>=0.10'} hasBin: true - devalue@5.3.2: - resolution: {integrity: sha512-UDsjUbpQn9kvm68slnrs+mfxwFkIflOhkanmyabZ8zOYk8SMEIbJ3TK+88g70hSIeytu4y18f0z/hYHMTrXIWw==} + devalue@5.6.2: + resolution: {integrity: sha512-nPRkjWzzDQlsejL1WVifk5rvcFi/y1onBRxjaFMjZeR9mFpqu2gmAZ9xUB9/IEanEP/vBtGeGganC/GO1fmufg==} devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} @@ -2900,10 +2909,6 @@ packages: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} - plausible-tracker@0.3.9: - resolution: {integrity: sha512-hMhneYm3GCPyQon88SZrVJx+LlqhM1kZFQbuAgXPoh/Az2YvO1B6bitT9qlhpiTdJlsT5lsr3gPmzoVjb5CDXA==} - engines: {node: '>=10'} - playwright-core@1.56.1: resolution: {integrity: sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==} engines: {node: '>=18'} @@ -3131,14 +3136,14 @@ packages: engines: {node: '>=10'} hasBin: true - seroval-plugins@1.3.3: - resolution: {integrity: sha512-16OL3NnUBw8JG1jBLUoZJsLnQq0n5Ua6aHalhJK4fMQkz1lqR7Osz1sA30trBtd9VUDc2NgkuRCn8+/pBwqZ+w==} + seroval-plugins@1.4.2: + resolution: {integrity: sha512-X7p4MEDTi+60o2sXZ4bnDBhgsUYDSkQEvzYZuJyFqWg9jcoPsHts5nrg5O956py2wyt28lUrBxk0M0/wU8URpA==} engines: {node: '>=10'} peerDependencies: seroval: ^1.0 - seroval@1.3.2: - resolution: {integrity: sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ==} + seroval@1.4.2: + resolution: {integrity: sha512-N3HEHRCZYn3cQbsC4B5ldj9j+tHdf4JZoYPlcI4rRYu0Xy4qN8MQf1Z08EibzB0WpgRG5BGK08FTrmM66eSzKQ==} engines: {node: '>=10'} set-cookie-parser@2.7.1: @@ -3823,13 +3828,13 @@ snapshots: '@analytics/type-utils@0.6.2': {} - '@appwrite.io/console@https://pkg.vc/-/@appwrite/@appwrite.io/console@f21fc7f': {} + '@appwrite.io/console@https://pkg.vc/-/@appwrite/@appwrite.io/console@9c55755': {} '@appwrite.io/pink-icons-svelte@2.0.0-RC.1(svelte@5.25.3)': dependencies: svelte: 5.25.3 - '@appwrite.io/pink-icons-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@865e2fc(svelte@5.25.3)': + '@appwrite.io/pink-icons-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@bbad65f(svelte@5.25.3)': dependencies: svelte: 5.25.3 @@ -3842,7 +3847,7 @@ snapshots: '@appwrite.io/pink-icons': 1.0.0 the-new-css-reset: 1.11.3 - '@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@865e2fc(svelte@5.25.3)': + '@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@bbad65f(svelte@5.25.3)': dependencies: '@appwrite.io/pink-icons-svelte': 2.0.0-RC.1(svelte@5.25.3) '@floating-ui/dom': 1.6.13 @@ -3945,9 +3950,9 @@ snapshots: dependencies: '@babel/types': 7.27.0 - '@babel/parser@7.28.5': + '@babel/parser@7.28.6': dependencies: - '@babel/types': 7.28.5 + '@babel/types': 7.28.6 '@babel/runtime@7.27.0': dependencies: @@ -3976,7 +3981,7 @@ snapshots: '@babel/helper-string-parser': 7.25.9 '@babel/helper-validator-identifier': 7.25.9 - '@babel/types@7.28.5': + '@babel/types@7.28.6': dependencies: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 @@ -4575,6 +4580,8 @@ snapshots: '@parcel/watcher-win32-x64': 2.5.1 optional: true + '@plausible-analytics/tracker@0.4.4': {} + '@playwright/test@1.56.1': dependencies: playwright: 1.56.1 @@ -4796,14 +4803,14 @@ snapshots: magic-string: 0.30.7 svelte: 5.25.3 - '@sentry/sveltekit@8.55.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.30.0)(@sveltejs/kit@2.42.1(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0))': + '@sentry/sveltekit@8.55.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.30.0)(@sveltejs/kit@2.49.5(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(typescript@5.8.2)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0))': dependencies: '@sentry/core': 8.55.0 '@sentry/node': 8.55.0 '@sentry/opentelemetry': 8.55.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.30.0) '@sentry/svelte': 8.55.0(svelte@5.25.3) '@sentry/vite-plugin': 2.22.6 - '@sveltejs/kit': 2.42.1(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)) + '@sveltejs/kit': 2.49.5(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(typescript@5.8.2)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)) magic-string: 0.30.7 magicast: 0.2.8 sorcery: 1.0.0 @@ -4875,11 +4882,11 @@ snapshots: dependencies: acorn: 8.15.0 - '@sveltejs/adapter-static@3.0.8(@sveltejs/kit@2.42.1(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))': + '@sveltejs/adapter-static@3.0.8(@sveltejs/kit@2.49.5(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(typescript@5.8.2)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))': dependencies: - '@sveltejs/kit': 2.42.1(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)) + '@sveltejs/kit': 2.49.5(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(typescript@5.8.2)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)) - '@sveltejs/kit@2.42.1(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0))': + '@sveltejs/kit@2.49.5(@opentelemetry/api@1.9.0)(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(typescript@5.8.2)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0))': dependencies: '@standard-schema/spec': 1.0.0 '@sveltejs/acorn-typescript': 1.0.5(acorn@8.15.0) @@ -4887,7 +4894,7 @@ snapshots: '@types/cookie': 0.6.0 acorn: 8.15.0 cookie: 0.6.0 - devalue: 5.3.2 + devalue: 5.6.2 esm-env: 1.2.2 kleur: 4.1.5 magic-string: 0.30.18 @@ -4899,6 +4906,7 @@ snapshots: vite: 7.0.6(@types/node@22.13.14)(sass@1.86.0) optionalDependencies: '@opentelemetry/api': 1.9.0 + typescript: 5.8.2 '@sveltejs/vite-plugin-svelte-inspector@4.0.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0)))(svelte@5.25.3)(vite@7.0.6(@types/node@22.13.14)(sass@1.86.0))': dependencies: @@ -5292,7 +5300,7 @@ snapshots: '@vue/compiler-core@3.5.13': dependencies: - '@babel/parser': 7.28.5 + '@babel/parser': 7.28.6 '@vue/shared': 3.5.13 entities: 4.5.0 estree-walker: 2.0.2 @@ -5305,7 +5313,7 @@ snapshots: '@vue/compiler-sfc@3.5.13': dependencies: - '@babel/parser': 7.28.5 + '@babel/parser': 7.28.6 '@vue/compiler-core': 3.5.13 '@vue/compiler-dom': 3.5.13 '@vue/compiler-ssr': 3.5.13 @@ -5334,7 +5342,7 @@ snapshots: '@vue/reactivity': 3.5.13 '@vue/runtime-core': 3.5.13 '@vue/shared': 3.5.13 - csstype: 3.1.3 + csstype: 3.2.3 '@vue/server-renderer@3.5.13(vue@3.5.13(typescript@5.8.2))': dependencies: @@ -5619,6 +5627,8 @@ snapshots: csstype@3.1.3: {} + csstype@3.2.3: {} + d3-array@3.2.4: dependencies: internmap: 2.0.3 @@ -5836,7 +5846,7 @@ snapshots: detect-libc@1.0.3: optional: true - devalue@5.3.2: {} + devalue@5.6.2: {} devlop@1.1.0: dependencies: @@ -6675,8 +6685,6 @@ snapshots: picomatch@4.0.3: {} - plausible-tracker@0.3.9: {} - playwright-core@1.56.1: {} playwright@1.56.1: @@ -6903,11 +6911,11 @@ snapshots: semver@7.7.1: {} - seroval-plugins@1.3.3(seroval@1.3.2): + seroval-plugins@1.4.2(seroval@1.4.2): dependencies: - seroval: 1.3.2 + seroval: 1.4.2 - seroval@1.3.2: {} + seroval@1.4.2: {} set-cookie-parser@2.7.1: {} @@ -6984,9 +6992,9 @@ snapshots: solid-js@1.9.5: dependencies: - csstype: 3.1.3 - seroval: 1.3.2 - seroval-plugins: 1.3.3(seroval@1.3.2) + csstype: 3.2.3 + seroval: 1.4.2 + seroval-plugins: 1.4.2(seroval@1.4.2) solid-swr-store@0.10.7(solid-js@1.9.5)(swr-store@0.10.6): dependencies: diff --git a/src/lib/actions/analytics.ts b/src/lib/actions/analytics.ts index dea8860b5..cfd42ae8f 100644 --- a/src/lib/actions/analytics.ts +++ b/src/lib/actions/analytics.ts @@ -1,5 +1,5 @@ import Analytics, { type AnalyticsPlugin } from 'analytics'; -import Plausible from 'plausible-tracker'; +import { init, track } from '@plausible-analytics/tracker'; import { get } from 'svelte/store'; import { page } from '$app/state'; import { user } from '$lib/stores/user'; @@ -11,30 +11,30 @@ import { getReferrerAndUtmSource, getTrackedQueryParams } from '$lib/helpers/utm function plausible(domain: string): AnalyticsPlugin { if (!browser) return { name: 'analytics-plugin-plausible' }; - const instance = Plausible({ - domain + init({ + domain, + autoCapturePageviews: false }); return { name: 'analytics-plugin-plausible', page: ({ payload }) => { - instance.trackPageview({ + track('pageview', { url: payload.properties.path, - referrer: payload.properties.referrer, - deviceWidth: payload.properties.width + props: { + referrer: payload.properties.referrer, + deviceWidth: String(payload.properties.width) + } }); }, track: ({ payload }) => { - instance.trackEvent( - payload.event, - { - props: payload.properties - }, - { - url: payload.properties.path, - deviceWidth: payload.properties.width + track(payload.event, { + url: payload.properties.path, + props: { + ...payload.properties, + deviceWidth: String(payload.properties.width) } - ); + }); }, loaded: () => true }; @@ -247,6 +247,7 @@ export enum Submit { ProjectDelete = 'submit_project_delete', ProjectUpdateName = 'submit_project_update_name', ProjectUpdateTeam = 'submit_project_update_team', + ProjectUpdateLabels = 'submit_project_update_labels', ProjectService = 'submit_project_service', ProjectUpdateSMTP = 'submit_project_update_smtp', MemberCreate = 'submit_member_create', diff --git a/src/lib/components/backupRestoreBox.svelte b/src/lib/components/backupRestoreBox.svelte index f1de9d3ba..05cb96e8f 100644 --- a/src/lib/components/backupRestoreBox.svelte +++ b/src/lib/components/backupRestoreBox.svelte @@ -5,7 +5,6 @@ import { isCloud, isSelfHosted } from '$lib/system'; import { organization } from '$lib/stores/organization'; import { BillingPlan, Dependencies } from '$lib/constants'; - import type { BackupArchive, BackupRestoration } from '$lib/sdk/backups'; import { goto, invalidate } from '$app/navigation'; import { page } from '$app/state'; import { addNotification } from '$lib/stores/notifications'; @@ -13,10 +12,11 @@ import { getProjectId } from '$lib/helpers/project'; import { toLocaleDate } from '$lib/helpers/date'; import { Typography } from '@appwrite.io/pink-svelte'; + import { type Models } from '@appwrite.io/console'; const backupRestoreItems: { - archives: Map; - restorations: Map; + archives: Map; + restorations: Map; } = { archives: new Map(), restorations: new Map() @@ -117,7 +117,7 @@ if (which === 'restorations') lastDatabaseRestorationId = null; } - function backupName(item: BackupArchive | BackupRestoration, key: string) { + function backupName(item: Models.BackupArchive | Models.BackupRestoration, key: string) { const column = key === 'archives' ? '$createdAt' : 'startedAt'; return toLocaleDate(item[column]); diff --git a/src/lib/components/domains/nameserverTable.svelte b/src/lib/components/domains/nameserverTable.svelte index a08de4208..66c7c165d 100644 --- a/src/lib/components/domains/nameserverTable.svelte +++ b/src/lib/components/domains/nameserverTable.svelte @@ -3,8 +3,15 @@ import { Badge, Layout, Typography, Table, InteractiveText } from '@appwrite.io/pink-svelte'; - export let domain: string; - export let verified = undefined; + let { + domain, + verified, + ruleStatus + }: { + domain: string; + verified?: boolean; + ruleStatus?: 'created' | 'verifying' | 'unverified' | 'verified'; + } = $props(); const nameserverList = $regionalConsoleVariables?._APP_DOMAINS_NAMESERVERS ? $regionalConsoleVariables?._APP_DOMAINS_NAMESERVERS?.split(',') @@ -16,14 +23,24 @@ {domain} - {#if verified === true} - - {:else if verified === false} - + {#if verified !== undefined} + {#if ruleStatus === 'created'} + + {:else if ruleStatus === 'verifying'} + + {:else if ruleStatus === 'unverified'} + + {:else if verified === true} + + {/if} {/if} - Add the following nameservers on your DNS provider. Note that changes may take up to 48 + Add the following nameservers on your DNS provider. Note that DNS changes may take up to 48 hours to propagate fully. diff --git a/src/lib/components/domains/recordTable.svelte b/src/lib/components/domains/recordTable.svelte index 6dc145e35..dd0c305e7 100644 --- a/src/lib/components/domains/recordTable.svelte +++ b/src/lib/components/domains/recordTable.svelte @@ -14,10 +14,10 @@ let { domain, - verified = undefined, + verified, variant, service = 'general', - ruleStatus = undefined, + ruleStatus, onNavigateToNameservers = () => {}, onNavigateToA = () => {}, onNavigateToAAAA = () => {} @@ -115,7 +115,9 @@ {variant.toUpperCase()} - {subdomain || '@'} + + + diff --git a/src/lib/helpers/buildTimeout.ts b/src/lib/helpers/buildTimeout.ts index 3915811c2..3f767c840 100644 --- a/src/lib/helpers/buildTimeout.ts +++ b/src/lib/helpers/buildTimeout.ts @@ -15,21 +15,31 @@ function isBuildTimedOut(createdAt: string, status: string, timeoutSeconds: numb const created = new Date(createdAt); const elapsedSeconds = Math.floor((Date.now() - created.getTime()) / 1000); - return elapsedSeconds > timeoutSeconds; + return elapsedSeconds >= timeoutSeconds; } /** * Gets the effective status for a build, considering timeout */ export function getEffectiveBuildStatus( - originalStatus: string, - createdAt: string, + deployment: Models.Deployment, consoleVariables: Models.ConsoleVariables | undefined ): string { + const originalStatus = deployment.status; + const createdAt = deployment.$createdAt; + const timeoutSeconds = getBuildTimeoutSeconds(consoleVariables); if (isBuildTimedOut(createdAt, originalStatus, timeoutSeconds)) { return 'failed'; } + + const isReady = originalStatus === 'ready'; + const hasScreenshot = deployment.screenshotLight && deployment.screenshotDark; + + if (isReady && !hasScreenshot) { + return 'finalizing'; + } + return originalStatus; } diff --git a/src/lib/helpers/executionTimeout.ts b/src/lib/helpers/executionTimeout.ts new file mode 100644 index 000000000..4468350fe --- /dev/null +++ b/src/lib/helpers/executionTimeout.ts @@ -0,0 +1,37 @@ +import type { Models } from '@appwrite.io/console'; + +/** + * Checks if an execution has exceeded the maximum execution timeout duration + */ +function isExecutionTimedOut(createdAt: string, status: string, timeoutSeconds: number): boolean { + if (!['waiting', 'processing'].includes(status)) { + return false; + } + + if (!timeoutSeconds || timeoutSeconds <= 0) { + return false; + } + + const created = new Date(createdAt); + const elapsedSeconds = Math.floor((Date.now() - created.getTime()) / 1000); + + return elapsedSeconds >= timeoutSeconds; +} + +/** + * Gets the effective status for an execution, considering timeout + */ +export function getEffectiveExecutionStatus( + execution: Models.Execution, + func: Models.Function +): string { + const originalStatus = execution.status; + const createdAt = execution.$createdAt; + + const timeoutSeconds = func.timeout; + if (isExecutionTimedOut(createdAt, originalStatus, timeoutSeconds)) { + return 'failed'; + } + + return originalStatus; +} diff --git a/src/lib/profiles/css/base.css b/src/lib/profiles/css/base.css new file mode 100644 index 000000000..ae0218c27 --- /dev/null +++ b/src/lib/profiles/css/base.css @@ -0,0 +1,6 @@ +.responsive-table { + overflow: hidden; + width: 100%; + scrollbar-width: thin; + position: relative; +} diff --git a/src/lib/sdk/backups.ts b/src/lib/sdk/backups.ts deleted file mode 100644 index 43cb6eb8b..000000000 --- a/src/lib/sdk/backups.ts +++ /dev/null @@ -1,332 +0,0 @@ -import { AppwriteException, Client, type Payload } from '@appwrite.io/console'; - -export type BackupPolicyList = { - total: number; - policies: BackupPolicy[]; -}; - -export type BackupArchiveList = { - total: number; - archives: BackupArchive[]; -}; - -export type BackupRestorationList = { - total: number; - restorations: BackupRestoration[]; -}; - -export type BackupPolicy = { - $id: string; - name: string; - $createdAt: string; - $updatedAt: string; - services: string[]; - resources: string[]; - resourceId?: string; - resourceType?: string; - retention: number; - schedule: string; - enabled: boolean; -}; - -export type BackupArchive = { - $id: string; - $createdAt: string; - $updatedAt: string; - policyId: string; - size: number; - status: string; - startedAt: string; - migrationId: string; - services: string[]; - resources: string[]; - resourceId?: string; - resourceType?: string; -}; - -export type BackupRestoration = { - $id: string; - $createdAt: string; - $updatedAt: string; - archiveId: string; - policyId: string; - status: string; - startedAt: string; - migrationId: string; - services: string[]; - resources: string[]; - options: string; -}; - -export class Backups { - client: Client; - - constructor(client: Client) { - this.client = client; - } - - async createArchive(services: string[], resourceId?: string): Promise { - if (typeof services === 'undefined') { - throw new AppwriteException('Missing required parameter: "services"'); - } - const apiPath = '/backups/archives'; - const payload: Payload = {}; - if (typeof services !== 'undefined') { - payload['services'] = services; - } - if (typeof resourceId !== 'undefined') { - payload['resourceId'] = resourceId; - } - const uri = new URL(this.client.config.endpoint + apiPath); - - const apiHeaders: { [header: string]: string } = { - 'content-type': 'application/json' - }; - - return await this.client.call('post', uri, apiHeaders, payload); - } - - async deleteArchive(archiveId: string): Promise { - if (typeof archiveId === 'undefined') { - throw new AppwriteException('Missing required parameter: "archiveId"'); - } - const apiPath = '/backups/archives/{archiveId}'.replace('{archiveId}', archiveId); - const payload: Payload = {}; - const uri = new URL(this.client.config.endpoint + apiPath); - - const apiHeaders: { [header: string]: string } = { - 'content-type': 'application/json' - }; - - return await this.client.call('delete', uri, apiHeaders, payload); - } - - async listArchives(queries?: string[]): Promise { - const apiPath = '/backups/archives'; - const payload: Payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - const uri = new URL(this.client.config.endpoint + apiPath); - - const apiHeaders: { [header: string]: string } = { - 'content-type': 'application/json' - }; - - return await this.client.call('get', uri, apiHeaders, payload); - } - - async getArchive(archiveId: string): Promise { - if (typeof archiveId === 'undefined') { - throw new AppwriteException('Missing required parameter: "archiveId"'); - } - const apiPath = '/backups/archives/{archiveId}'.replace('{archiveId}', archiveId); - const payload: Payload = {}; - const uri = new URL(this.client.config.endpoint + apiPath); - - const apiHeaders: { [header: string]: string } = { - 'content-type': 'application/json' - }; - - return await this.client.call('get', uri, apiHeaders, payload); - } - - async listPolicies(queries?: string[]): Promise { - const apiPath = '/backups/policies'; - const payload: Payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - const uri = new URL(this.client.config.endpoint + apiPath); - - const apiHeaders: { [header: string]: string } = { - 'content-type': 'application/json' - }; - - return await this.client.call('get', uri, apiHeaders, payload); - } - - async createPolicy( - policyId: string, - services: string[], - retention: number, - schedule: string, - name?: string, - resourceId?: string, - enabled?: boolean - ): Promise { - if (typeof policyId === 'undefined') { - throw new AppwriteException('Missing required parameter: "policyId"'); - } - if (typeof services === 'undefined') { - throw new AppwriteException('Missing required parameter: "services"'); - } - if (typeof retention === 'undefined') { - throw new AppwriteException('Missing required parameter: "retention"'); - } - if (typeof schedule === 'undefined') { - throw new AppwriteException('Missing required parameter: "schedule"'); - } - const apiPath = '/backups/policies'; - const payload: Payload = {}; - if (typeof policyId !== 'undefined') { - payload['policyId'] = policyId; - } - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof services !== 'undefined') { - payload['services'] = services; - } - if (typeof resourceId !== 'undefined') { - payload['resourceId'] = resourceId; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - if (typeof retention !== 'undefined') { - payload['retention'] = retention; - } - if (typeof schedule !== 'undefined') { - payload['schedule'] = schedule; - } - const uri = new URL(this.client.config.endpoint + apiPath); - - const apiHeaders: { [header: string]: string } = { - 'content-type': 'application/json' - }; - - return await this.client.call('post', uri, apiHeaders, payload); - } - - async getPolicy(policyId: string): Promise { - if (typeof policyId === 'undefined') { - throw new AppwriteException('Missing required parameter: "policyId"'); - } - const apiPath = '/backups/policies/{policyId}'.replace('{policyId}', policyId); - const payload: Payload = {}; - const uri = new URL(this.client.config.endpoint + apiPath); - - const apiHeaders: { [header: string]: string } = { - 'content-type': 'application/json' - }; - - return await this.client.call('get', uri, apiHeaders, payload); - } - - async updatePolicy( - policyId: string, - name?: string, - retention?: number, - schedule?: string, - enabled?: boolean - ): Promise { - if (typeof policyId === 'undefined') { - throw new AppwriteException('Missing required parameter: "policyId"'); - } - const apiPath = '/backups/policies/{policyId}'.replace('{policyId}', policyId); - const payload: Payload = {}; - if (typeof name !== 'undefined') { - payload['name'] = name; - } - if (typeof retention !== 'undefined') { - payload['retention'] = retention; - } - if (typeof schedule !== 'undefined') { - payload['schedule'] = schedule; - } - if (typeof enabled !== 'undefined') { - payload['enabled'] = enabled; - } - const uri = new URL(this.client.config.endpoint + apiPath); - - const apiHeaders: { [header: string]: string } = { - 'content-type': 'application/json' - }; - - return await this.client.call('patch', uri, apiHeaders, payload); - } - - async deletePolicy(policyId: string): Promise { - if (typeof policyId === 'undefined') { - throw new AppwriteException('Missing required parameter: "policyId"'); - } - const apiPath = '/backups/policies/{policyId}'.replace('{policyId}', policyId); - const payload: Payload = {}; - const uri = new URL(this.client.config.endpoint + apiPath); - - const apiHeaders: { [header: string]: string } = { - 'content-type': 'application/json' - }; - - return await this.client.call('delete', uri, apiHeaders, payload); - } - - async createRestoration( - archiveId: string, - services: string[], - newResourceId?: string, - newResourceName?: string - ): Promise { - if (typeof archiveId === 'undefined') { - throw new AppwriteException('Missing required parameter: "archiveId"'); - } - if (typeof services === 'undefined') { - throw new AppwriteException('Missing required parameter: "services"'); - } - const apiPath = '/backups/restoration'; - const payload: Payload = {}; - if (typeof archiveId !== 'undefined') { - payload['archiveId'] = archiveId; - } - if (typeof services !== 'undefined') { - payload['services'] = services; - } - if (typeof newResourceId !== 'undefined') { - payload['newResourceId'] = newResourceId; - } - if (typeof newResourceName !== 'undefined') { - payload['newResourceName'] = newResourceName; - } - const uri = new URL(this.client.config.endpoint + apiPath); - - const apiHeaders: { [header: string]: string } = { - 'content-type': 'application/json' - }; - - return await this.client.call('post', uri, apiHeaders, payload); - } - - async listRestorations(queries?: string[]): Promise { - const apiPath = '/backups/restorations'; - const payload: Payload = {}; - if (typeof queries !== 'undefined') { - payload['queries'] = queries; - } - const uri = new URL(this.client.config.endpoint + apiPath); - - const apiHeaders: { [header: string]: string } = { - 'content-type': 'application/json' - }; - - return await this.client.call('get', uri, apiHeaders, payload); - } - - async getRestoration(restorationId: string): Promise { - if (typeof restorationId === 'undefined') { - throw new AppwriteException('Missing required parameter: "restorationId"'); - } - const apiPath = '/backups/restorations/{restorationId}'.replace( - '{restorationId}', - restorationId - ); - const payload: Payload = {}; - const uri = new URL(this.client.config.endpoint + apiPath); - - const apiHeaders: { [header: string]: string } = { - 'content-type': 'application/json' - }; - - return await this.client.call('get', uri, apiHeaders, payload); - } -} diff --git a/src/lib/stores/database.ts b/src/lib/stores/database.ts index 4c93859ce..648708bd0 100644 --- a/src/lib/stores/database.ts +++ b/src/lib/stores/database.ts @@ -27,9 +27,9 @@ export async function checkForDatabaseBackupPolicies( if (isCloud && backupsEnabled) { try { - const policies = await sdk - .forProject(region, projectId) - .backups.listPolicies([Query.limit(1), Query.equal('resourceId', database.$id)]); + const policies = await sdk.forProject(region, projectId).backups.listPolicies({ + queries: [Query.limit(1), Query.equal('resourceId', database.$id)] + }); total = policies.total; } catch (e) { diff --git a/src/lib/stores/sdk.ts b/src/lib/stores/sdk.ts index 05f9f54db..d7e0cc7b9 100644 --- a/src/lib/stores/sdk.ts +++ b/src/lib/stores/sdk.ts @@ -3,6 +3,7 @@ import { Account, Assistant, Avatars, + Backups, Client, Console, Functions, @@ -26,7 +27,6 @@ import { Organizations } from '@appwrite.io/console'; import { Billing } from '../sdk/billing'; -import { Backups } from '../sdk/backups'; import { Sources } from '$lib/sdk/sources'; import { REGION_FRA, diff --git a/src/routes/(console)/+layout.ts b/src/routes/(console)/+layout.ts index 44956eb5d..af48c0671 100644 --- a/src/routes/(console)/+layout.ts +++ b/src/routes/(console)/+layout.ts @@ -18,7 +18,7 @@ export const load: LayoutLoad = async ({ depends, parent }) => { sdk.forConsole.account.getPrefs(), isCloud ? sdk.forConsole.billing.getPlansInfo() : null, fetch(`${endpoint}/health/version`, { - headers: { 'X-Appwrite-Project': project } + headers: { 'X-Appwrite-Project': project as string } }).then((response) => response.json() as { version?: string }), sdk.forConsole.console.variables() ]); diff --git a/src/routes/(console)/organization-[organization]/+page.svelte b/src/routes/(console)/organization-[organization]/+page.svelte index 83c40623c..37ef03204 100644 --- a/src/routes/(console)/organization-[organization]/+page.svelte +++ b/src/routes/(console)/organization-[organization]/+page.svelte @@ -170,7 +170,7 @@ - + {#if $canWriteProjects} {#if projectCreationDisabled && reachedProjectLimit} diff --git a/src/routes/(console)/organization-[organization]/+page.ts b/src/routes/(console)/organization-[organization]/+page.ts index 98dfed44b..fc4256b03 100644 --- a/src/routes/(console)/organization-[organization]/+page.ts +++ b/src/routes/(console)/organization-[organization]/+page.ts @@ -24,8 +24,12 @@ export const load: PageLoad = async ({ params, url, route, depends, parent }) => const archivedPage = Number.isFinite(archivedPageRaw) && archivedPageRaw > 0 ? archivedPageRaw : 1; const archivedOffset = pageToOffset(archivedPage, limit); - const common = [Query.equal('teamId', params.organization)]; - const active = isCloud + + const searchQueries = search + ? [Query.or([Query.search('search', search), Query.contains('labels', search)])] + : []; + const commonQueries = [Query.equal('teamId', params.organization)]; + const activeQueries = isCloud ? [Query.or([Query.equal('status', 'active'), Query.isNull('status')])] : []; @@ -35,10 +39,10 @@ export const load: PageLoad = async ({ params, url, route, depends, parent }) => Query.offset(offset), Query.limit(limit), Query.orderDesc(''), - ...common, - ...active - ], - search: search || undefined + ...commonQueries, + ...searchQueries, + ...activeQueries + ] }), isCloud ? sdk.forConsole.projects.list({ @@ -46,20 +50,18 @@ export const load: PageLoad = async ({ params, url, route, depends, parent }) => Query.offset(archivedOffset), Query.limit(limit), Query.orderDesc(''), - ...common, + ...commonQueries, + ...searchQueries, Query.equal('status', 'archived') - ], - search: search || undefined + ] }) : Promise.resolve({ projects: [], total: 0 }), sdk.forConsole.projects.list({ - queries: [...common, ...active], - search: search || undefined + queries: [...commonQueries, ...activeQueries, ...searchQueries] }), isCloud ? sdk.forConsole.projects.list({ - queries: [...common, Query.equal('status', 'archived')], - search: search || undefined + queries: [...commonQueries, ...searchQueries, Query.equal('status', 'archived')] }) : Promise.resolve({ projects: [], total: 0 }) ]); diff --git a/src/routes/(console)/organization-[organization]/domains/+page.svelte b/src/routes/(console)/organization-[organization]/domains/+page.svelte index ec6c271e0..477786e8f 100644 --- a/src/routes/(console)/organization-[organization]/domains/+page.svelte +++ b/src/routes/(console)/organization-[organization]/domains/+page.svelte @@ -93,9 +93,9 @@ {#if !isDomainVerified(domain)} + size="xs" /> {/if} {:else if column.id === 'registrar'} diff --git a/src/routes/(console)/organization-[organization]/domains/add-domain/+page.svelte b/src/routes/(console)/organization-[organization]/domains/add-domain/+page.svelte index c6953c2e3..a1066a09a 100644 --- a/src/routes/(console)/organization-[organization]/domains/add-domain/+page.svelte +++ b/src/routes/(console)/organization-[organization]/domains/add-domain/+page.svelte @@ -1,6 +1,7 @@ - + {#each $columns as { id, title } (id)} diff --git a/src/routes/(console)/organization-[organization]/domains/recordsCard.svelte b/src/routes/(console)/organization-[organization]/domains/recordsCard.svelte index 6d3d8b41a..edfec5903 100644 --- a/src/routes/(console)/organization-[organization]/domains/recordsCard.svelte +++ b/src/routes/(console)/organization-[organization]/domains/recordsCard.svelte @@ -39,7 +39,7 @@ if (verified) { addNotification({ type: 'success', - message: 'Domain verified' + message: 'Domain verified successfully' }); await goto(routeBase); @@ -76,7 +76,7 @@ {#if verified === false} {:else if verified === true} @@ -84,8 +84,8 @@ {/if} - Add the following nameservers on your DNS provider. Note that changes may take up to - 48 hours to propagate fully. + Add the following nameservers on your DNS provider. Note that DNS changes may take + up to 48 hours to propagate fully. diff --git a/src/routes/(console)/organization-[organization]/domains/retryDomainModal.svelte b/src/routes/(console)/organization-[organization]/domains/retryDomainModal.svelte index de237930a..5dab1876e 100644 --- a/src/routes/(console)/organization-[organization]/domains/retryDomainModal.svelte +++ b/src/routes/(console)/organization-[organization]/domains/retryDomainModal.svelte @@ -32,17 +32,20 @@ const domain = await sdk.forConsole.domains.updateNameservers({ domainId: selectedDomain.$id }); - if (domain.nameservers.toLowerCase() === 'appwrite') { - show = false; - addNotification({ - type: 'success', - message: `${selectedDomain.domain} has been verified` - }); - } else { - error = - 'Domain verification failed. Please check your domain settings or try again later'; - } + await Promise.all([invalidate(Dependencies.DOMAIN), invalidate(Dependencies.DOMAINS)]); + + const verified = domain?.nameservers.toLowerCase() === 'appwrite'; + if (!verified) { + throw new Error( + 'Domain verification failed. Please check your domain settings or try again later' + ); + } + show = false; + addNotification({ + type: 'success', + message: 'Domain verified successfully' + }); trackEvent(Submit.DomainUpdateVerification); } catch (e) { error = e.message; @@ -64,8 +67,8 @@ >{selectedDomain.domain} - Add the following nameservers on your DNS provider. Note that changes may take up to 48 - hours to propagate fully. + Add the following nameservers on your DNS provider. Note that DNS changes may take up to + 48 hours to propagate fully. diff --git a/src/routes/(console)/project-[region]-[project]/databases/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/+page.svelte index e413399e8..adba24b05 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/+page.svelte @@ -77,7 +77,11 @@ {#if data.view === 'grid'} {:else} - +
{/if} , policies: Record; + let lastBackups: Record = {}; + let policies: Record = {}; if (isCloud && backupsEnabled) { [policies, lastBackups] = await Promise.all([ @@ -86,19 +86,21 @@ async function fetchDatabasesAndBackups( async function fetchPolicies(databases: Models.DatabaseList, params: RouteParams) { if (isSelfHosted) return {}; - const databasePolicies: Record = {}; + const databasePolicies: Record = {}; await Promise.all( databases.databases.map(async (database) => { try { const { policies } = await sdk .forProject(params.region, params.project) - .backups.listPolicies([ - // TODO: are all needed!? - // Query.limit(3), - Query.equal('resourceType', 'database'), - Query.equal('resourceId', database.$id) - ]); + .backups.listPolicies({ + queries: [ + // TODO: are all needed!? + // Query.limit(3), + Query.equal('resourceType', 'database'), + Query.equal('resourceId', database.$id) + ] + }); if (policies.length > 0) { databasePolicies[database.$id] = policies; @@ -122,12 +124,14 @@ async function fetchLastBackups(databases: Models.DatabaseList, params: RoutePar try { const { archives } = await sdk .forProject(params.region, params.project) - .backups.listArchives([ - Query.limit(1), - Query.orderDesc('$createdAt'), - Query.equal('resourceType', 'database'), - Query.equal('resourceId', database.$id) - ]); + .backups.listArchives({ + queries: [ + Query.limit(1), + Query.orderDesc('$createdAt'), + Query.equal('resourceType', 'database'), + Query.equal('resourceId', database.$id) + ] + }); if (archives.length > 0) { lastBackups[database.$id] = timeFromNow(archives[0].$createdAt); diff --git a/src/routes/(console)/project-[region]-[project]/databases/create.svelte b/src/routes/(console)/project-[region]-[project]/databases/create.svelte index f00b68e59..3fc1736dd 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/create.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/create.svelte @@ -61,16 +61,14 @@ const totalPoliciesPromise = totalPolicies.map((policy) => { cronExpression(policy); - return sdk - .forProject(page.params.region, page.params.project) - .backups.createPolicy( - ID.unique(), - ['databases'], - policy.retained, - policy.schedule, - policy.label, - resourceId - ); + return sdk.forProject(page.params.region, page.params.project).backups.createPolicy({ + policyId: ID.unique(), + services: ['databases'], + retention: policy.retained, + schedule: policy.schedule, + name: policy.label, + resourceId + }); }); await Promise.all(totalPoliciesPromise); diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/backups/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/backups/+page.svelte index 99521078d..e64490541 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/backups/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/backups/+page.svelte @@ -66,9 +66,10 @@ const createManualBackup = async () => { try { - await sdk - .forProject(page.params.region, page.params.project) - .backups.createArchive(['databases'], data.database.$id); + await sdk.forProject(page.params.region, page.params.project).backups.createArchive({ + services: ['databases'], + resourceId: data.database.$id + }); await invalidate(Dependencies.BACKUPS); addNotification({ type: 'success', @@ -119,16 +120,14 @@ const totalPoliciesPromise = totalPolicies.map((policy) => { cronExpression(policy); - return sdk - .forProject(page.params.region, page.params.project) - .backups.createPolicy( - ID.unique(), - ['databases'], - policy.retained, - policy.schedule, - policy.label, - data.database.$id - ); + return sdk.forProject(page.params.region, page.params.project).backups.createPolicy({ + policyId: ID.unique(), + services: ['databases'], + retention: policy.retained, + schedule: policy.schedule, + name: policy.label, + resourceId: data.database.$id + }); }); try { diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/backups/+page.ts b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/backups/+page.ts index 52d9e65c9..60d9bfb21 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/backups/+page.ts +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/backups/+page.ts @@ -2,8 +2,8 @@ import { getLimit, getPage, getView, pageToOffset, View } from '$lib/helpers/loa import { Dependencies, PAGE_LIMIT } from '$lib/constants'; import { sdk } from '$lib/stores/sdk'; import { Query } from '@appwrite.io/console'; -import type { BackupArchive, BackupArchiveList, BackupPolicyList } from '$lib/sdk/backups'; import { isCloud } from '$lib/system'; +import { type Models } from '@appwrite.io/console'; export const load = async ({ params, url, route, depends, parent }) => { depends(Dependencies.BACKUPS); @@ -13,8 +13,8 @@ export const load = async ({ params, url, route, depends, parent }) => { const view = getView(url, route, View.Grid); const offset = pageToOffset(page, limit); - let backups: BackupArchiveList = { total: 0, archives: [] }; - let policies: BackupPolicyList = { total: 0, policies: [] }; + let backups: Models.BackupArchiveList = { total: 0, archives: [] }; + let policies: Models.BackupPolicyList = { total: 0, policies: [] }; // already loaded by parent. const { currentPlan } = await parent(); @@ -23,23 +23,23 @@ export const load = async ({ params, url, route, depends, parent }) => { if (isCloud && backupsEnabled) { try { [backups, policies] = await Promise.all([ - sdk - .forProject(params.region, params.project) - .backups.listArchives([ + sdk.forProject(params.region, params.project).backups.listArchives({ + queries: [ Query.limit(limit), Query.offset(offset), Query.orderDesc('$createdAt'), Query.equal('resourceType', 'database'), Query.equal('resourceId', params.database) - ]), + ] + }), - sdk - .forProject(params.region, params.project) - .backups.listPolicies([ + sdk.forProject(params.region, params.project).backups.listPolicies({ + queries: [ Query.orderDesc('$createdAt'), Query.equal('resourceType', 'database'), Query.equal('resourceId', params.database) - ]) + ] + }) ]); } catch (e) { // ignore @@ -59,17 +59,17 @@ export const load = async ({ params, url, route, depends, parent }) => { }; }; -const groupArchivesByPolicy = (archives: BackupArchive[]) => { +const groupArchivesByPolicy = (archives: Models.BackupArchive[]) => { return archives.reduce((acc, archive) => { if (!acc.has(archive.policyId)) { acc.set(archive.policyId, []); } acc.get(archive.policyId)!.push(archive); return acc; - }, new Map()); + }, new Map()); }; -const getLatestBackupForPolicies = (policyIdMap: Map) => { +const getLatestBackupForPolicies = (policyIdMap: Map) => { const latestBackups = new Map(); for (const [policyId, archives] of policyIdMap) { const latestBackup = archives.sort( diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/backups/policy.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/backups/policy.svelte index e4ccd8b91..f73fc68a9 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/backups/policy.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/backups/policy.svelte @@ -11,7 +11,6 @@ import { toLocaleDateTime } from '$lib/helpers/date'; import EmptyDark from '$lib/images/backups/backups-dark.png'; import EmptyLight from '$lib/images/backups/backups-light.png'; - import type { BackupPolicy, BackupPolicyList } from '$lib/sdk/backups'; import { backupFrequencies } from '$lib/helpers/backups'; import { Click, trackEvent } from '$lib/actions/analytics'; import { @@ -27,21 +26,22 @@ import { Confirm } from '$lib/components/index.js'; import Ellipse from './components/Ellipse.svelte'; import { page } from '$app/state'; + import { type Models } from '@appwrite.io/console'; let showDelete = false; - let selectedPolicy: BackupPolicy = null; + let selectedPolicy: Models.BackupPolicy = null; let showEveryPolicy = false; export let showCreatePolicy = false; - export let policies: BackupPolicyList; + export let policies: Models.BackupPolicyList; export let lastBackupDates: Record; async function deletePolicy() { try { - await sdk - .forProject(page.params.region, page.params.project) - .backups.deletePolicy(selectedPolicy.$id); + await sdk.forProject(page.params.region, page.params.project).backups.deletePolicy({ + policyId: selectedPolicy.$id + }); addNotification({ type: 'success', message: 'Backup policy has been deleted' diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/backups/table.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/backups/table.svelte index 7cee5aacc..5cd807592 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/backups/table.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/backups/table.svelte @@ -15,10 +15,9 @@ import { addNotification } from '$lib/stores/notifications'; import { invalidate } from '$app/navigation'; import { calculateSize } from '$lib/helpers/sizeConvertion'; - import { ID } from '@appwrite.io/console'; + import { ID, type Models } from '@appwrite.io/console'; import { columns } from './store'; import { database } from '../store'; - import type { BackupArchive, BackupPolicy } from '$lib/sdk/backups'; import { Click, Submit, trackError, trackEvent } from '$lib/actions/analytics'; import { copy } from '$lib/helpers/copy'; import { LabelCard } from '$lib/components/index.js'; @@ -53,7 +52,7 @@ } = $props(); let showDelete = $state(false); - let selectedBackup: BackupArchive | null = $state(null); + let selectedBackup: Models.BackupArchive | null = $state(null); let showDropdown = []; @@ -87,15 +86,15 @@ ); }); - function getPolicyDetails(policyId: string | null): BackupPolicy | null { + function getPolicyDetails(policyId: string | null): Models.BackupPolicy | null { return data.policies.policies.find((policy) => policy.$id === policyId); } - function getCleanBackupName(backup: BackupArchive): string { + function getCleanBackupName(backup: Models.BackupArchive): string { return toLocaleDateTime(backup.$createdAt).replaceAll(',', ''); } - function getBackupStatus(backup: BackupArchive) { + function getBackupStatus(backup: Models.BackupArchive) { switch (backup.status) { case 'pending': return 'pending'; @@ -115,7 +114,7 @@ try { await sdk .forProject(page.params.region, page.params.project) - .backups.deleteArchive(archiveId); + .backups.deleteArchive({ archiveId }); addNotification({ type: 'success', @@ -135,7 +134,9 @@ async function deleteBackups(batchDelete: DeleteOperation): Promise { const result = await batchDelete((archiveId) => - sdk.forProject(page.params.region, page.params.project).backups.deleteArchive(archiveId) + sdk + .forProject(page.params.region, page.params.project) + .backups.deleteArchive({ archiveId }) ); try { @@ -160,12 +161,12 @@ try { await sdk .forProject(page.params.region, page.params.project) - .backups.createRestoration( - selectedBackup.$id, - ['databases'], - newDatabaseInfo.id ?? ID.unique(), - newDatabaseInfo.name - ); + .backups.createRestoration({ + archiveId: selectedBackup.$id, + services: ['databases'], + newResourceId: newDatabaseInfo.id ?? ID.unique(), + newResourceName: newDatabaseInfo.name + }); await invalidate(Dependencies.BACKUPS); addNotification({ diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/types/relationship.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/types/relationship.svelte index f790579c5..fccc94df4 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/types/relationship.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/types/relationship.svelte @@ -297,7 +297,7 @@ ; + databases: Models.DatabaseList; + lastBackups: Record; + policies: Record; + } = $props(); function getPolicyDescription(cron: string): string { const [minute, hour, dayOfMonth, , dayOfWeek] = cron.split(' '); @@ -19,6 +28,10 @@ if (minute !== '*' && hour === '*') return 'Hourly'; if (hour !== '*') return 'Daily'; } + + function getPoliciesDescription(policies: Models.BackupPolicy[] | null): string { + return policies?.map((policy) => getPolicyDescription(policy.schedule)).join(', ') ?? ''; + } @@ -27,7 +40,7 @@ {title} {/each} - {#each data.databases.databases as database (database.$id)} + {#each databases.databases as database (database.$id)} {@const tableId = tables[database?.$id] ?? null} {@const tableHref = tableId ? `/table-${tableId}` : ''} @@ -45,18 +58,16 @@ {:else if column.id === 'name'} {database.name} {:else if column.id === 'backup'} - {@const policies = data.policies?.[database.$id] ?? null} - {@const lastBackup = data.lastBackups?.[database.$id] ?? null} - {@const description = policies - ?.map((policy: BackupPolicy) => getPolicyDescription(policy.schedule)) - .join(', ')} + {@const backupPolicies = policies?.[database.$id] ?? null} + {@const lastBackup = lastBackups?.[database.$id] ?? null} + {@const description = getPoliciesDescription(backupPolicies)} - {#if !policies} + {#if !backupPolicies} -
+
diff --git a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/deployment-[deployment]/+page.svelte b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/deployment-[deployment]/+page.svelte index 9a9b47b2e..140524354 100644 --- a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/deployment-[deployment]/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/deployment-[deployment]/+page.svelte @@ -41,11 +41,7 @@ let { data } = $props(); let effectiveStatus = $derived( - getEffectiveBuildStatus( - data.deployment.status, - data.deployment.$createdAt, - $regionalConsoleVariables - ) + getEffectiveBuildStatus(data.deployment, $regionalConsoleVariables) ); let showDelete = $state(false); let showCancel = $state(false); diff --git a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/add-domain/+page.svelte b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/add-domain/+page.svelte index 89f2bb4c2..6a9d3183a 100644 --- a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/add-domain/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/add-domain/+page.svelte @@ -48,16 +48,24 @@ async function addDomain() { const apexDomain = getApexDomain(domainName); - let domain = data.domainsList.domains.find((d: Models.Domain) => d.domain === apexDomain); + const domain = data.domainsList.domains.find((d: Models.Domain) => d.domain === apexDomain); if (apexDomain && !domain && isCloud) { try { - domain = await sdk.forConsole.domains.create({ + await sdk.forConsole.domains.create({ teamId: $project.teamId, domain: apexDomain }); } catch (error) { - // Apex domain creation error needs to be silent. + // apex might already be added on organization level, skip. + const alreadyAdded = error?.type === 'domain_already_exists'; + if (!alreadyAdded) { + addNotification({ + type: 'error', + message: error.message + }); + return; + } } } @@ -89,12 +97,18 @@ functionId: page.params.function }); } - if (rule?.status === 'verified') { + + await invalidate(Dependencies.FUNCTION_DOMAINS); + + const verified = rule?.status !== 'created'; + if (verified) { + addNotification({ + type: 'success', + message: 'Domain verified successfully' + }); await goto(routeBase); - await invalidate(Dependencies.FUNCTION_DOMAINS); } else { await goto(`${routeBase}/add-domain/verify-${domainName}?rule=${rule.$id}`); - await invalidate(Dependencies.FUNCTION_DOMAINS); } } catch (error) { addNotification({ diff --git a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/add-domain/verify-[domain]/+page.svelte b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/add-domain/verify-[domain]/+page.svelte index 41d1b541e..07f3c49d4 100644 --- a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/add-domain/verify-[domain]/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/add-domain/verify-[domain]/+page.svelte @@ -11,7 +11,6 @@ } from '@appwrite.io/pink-svelte'; import { Button, Form } from '$lib/elements/forms'; import { sdk } from '$lib/stores/sdk'; - import { organization } from '$lib/stores/organization'; import { addNotification } from '$lib/stores/notifications'; import { goto, invalidate } from '$app/navigation'; import { Dependencies } from '$lib/constants'; @@ -23,6 +22,7 @@ import NameserverTable from '$lib/components/domains/nameserverTable.svelte'; import RecordTable from '$lib/components/domains/recordTable.svelte'; import { regionalConsoleVariables } from '$routes/(console)/project-[region]-[project]/store'; + import { getApexDomain } from '$lib/helpers/tlds.js'; let { data } = $props(); @@ -44,6 +44,7 @@ ); const showNSTab = isCloud; + let proxyRule = $derived(data.proxyRule); let selectedTab = $state<'cname' | 'nameserver' | 'a' | 'aaaa'>(getDefaultTab()); let routeBase = `${base}/project-${page.params.region}-${page.params.project}/functions/function-${page.params.function}/domains`; let verified: boolean | undefined = $state(undefined); @@ -54,44 +55,35 @@ } async function verify() { - const isNewDomain = - data.domainsList.domains.find((rule) => rule.domain === data.proxyRule.domain) === - undefined; + verified = undefined; + try { - if (selectedTab !== 'nameserver') { - const ruleData = await sdk - .forProject(page.params.region, page.params.project) - .proxy.updateRuleVerification({ ruleId }); - verified = ruleData.status === 'verified'; + const apexDomain = getApexDomain(proxyRule.domain); + const domain = data.domainsList.domains.find((d) => d.domain === apexDomain); - // This means domain verification using DNS records hasn't succeeded and the rule is still in initial state. - if (ruleData.status === 'created') { - throw new Error( - 'Domain verification failed. Please check your domain settings or try again later' - ); - } - } else if (isNewDomain && isCloud) { - const domainData = await sdk.forConsole.domains.create({ - teamId: $organization.$id, - domain: data.proxyRule.domain - }); - verified = domainData.nameservers.toLowerCase() === 'appwrite'; - } - - if (verified) { - addNotification({ - type: 'success', - message: 'Domain added successfully' - }); - } else { - addNotification({ - type: 'info', - message: 'Verification in progress' + if (isCloud && domain) { + await sdk.forConsole.domains.updateNameservers({ + domainId: domain.$id }); } + } catch (error) { + // Ignore error + } + + try { + proxyRule = await sdk + .forProject(page.params.region, page.params.project) + .proxy.updateRuleVerification({ ruleId }); + + await Promise.all([ + invalidate(Dependencies.DOMAINS), + invalidate(Dependencies.FUNCTION_DOMAINS) + ]); await goto(routeBase); - await invalidate(Dependencies.DOMAINS); - await invalidate(Dependencies.FUNCTION_DOMAINS); + addNotification({ + type: 'success', + message: 'Domain verified successfully' + }); } catch (error) { verified = false; isSubmitting.set(false); @@ -108,7 +100,7 @@ .forProject(page.params.region, page.params.project) .proxy.deleteRule({ ruleId }); } - await goto(`${routeBase}/add-domain?domain=${data.proxyRule.domain}`); + await goto(`${routeBase}/add-domain?domain=${proxyRule.domain}`); } @@ -125,7 +117,7 @@ - {data.proxyRule.domain} + {proxyRule.domain} @@ -172,14 +164,17 @@ {#if selectedTab === 'nameserver'} - + {:else} (selectedTab = 'nameserver')} onNavigateToA={() => (selectedTab = 'a')} onNavigateToAAAA={() => (selectedTab = 'aaaa')} /> diff --git a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/recordsCard.svelte b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/recordsCard.svelte index 07a2da2c4..55e9b5a95 100644 --- a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/recordsCard.svelte +++ b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/recordsCard.svelte @@ -25,8 +25,8 @@ - Add the following nameservers on your DNS provider. Note that changes may take - up to 48 hours to propagate fully. + Add the following nameservers on your DNS provider. Note that DNS changes may + take up to 48 hours to propagate fully. diff --git a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/retryDomainModal.svelte b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/retryDomainModal.svelte index 391321a9b..bc90344d6 100644 --- a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/retryDomainModal.svelte +++ b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/retryDomainModal.svelte @@ -13,13 +13,16 @@ import { Divider, Tabs } from '@appwrite.io/pink-svelte'; import NameserverTable from '$lib/components/domains/nameserverTable.svelte'; import RecordTable from '$lib/components/domains/recordTable.svelte'; + import { getApexDomain } from '$lib/helpers/tlds'; let { show = $bindable(false), - selectedProxyRule + selectedProxyRule, + domainsList }: { show: boolean; selectedProxyRule: Models.ProxyRule; + domainsList?: Models.DomainsList; } = $props(); const showCNAMETab = $derived( @@ -40,43 +43,42 @@ let selectedTab = $state<'cname' | 'nameserver' | 'a' | 'aaaa'>(getDefaultTab()); let error = $state(null); - let verified = $state(false); + let verified: boolean | undefined = $state(undefined); function getDefaultTab() { return showCNAMETab ? 'cname' : showATab ? 'a' : showAAAATab ? 'aaaa' : 'nameserver'; } async function retryProxyRule() { + error = null; + verified = undefined; + try { - error = null; - const proxyRule = await sdk + const apexDomain = getApexDomain(selectedProxyRule.domain); + const domain = domainsList?.domains.find((d) => d.domain === apexDomain); + if (isCloud && domain) { + await sdk.forConsole.domains.updateNameservers({ + domainId: domain.$id + }); + } + } catch { + // Ignore error + } + + try { + selectedProxyRule = await sdk .forProject(page.params.region, page.params.project) .proxy.updateRuleVerification({ ruleId: selectedProxyRule.$id }); - verified = proxyRule.status === 'verified'; await invalidate(Dependencies.FUNCTION_DOMAINS); - - // This means domain verification using DNS records hasn't succeeded and the rule is still in initial state. - if (proxyRule.status === 'created') { - throw new Error( - 'Domain verification failed. Please check your domain settings or try again later' - ); - } - - if (verified) { - addNotification({ - type: 'success', - message: `${selectedProxyRule.domain} has been verified` - }); - } else { - addNotification({ - type: 'info', - message: 'Verification in progress' - }); - } show = false; + addNotification({ + type: 'success', + message: 'Domain verified successfully' + }); trackEvent(Submit.DomainUpdateVerification); } catch (e) { + verified = false; error = e.message ?? 'Domain verification failed. Please check your domain settings or try again later'; @@ -130,7 +132,10 @@ {#if selectedTab === 'nameserver'} - + {:else} ([ title: 'Domain', type: 'string', format: 'string', - width: { min: 300 } + width: { min: 600 } }, { id: 'target', title: 'Target', type: 'string', - width: { min: 120, max: 400 } + width: { min: 160, max: 400 } }, { diff --git a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/table.svelte b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/table.svelte index 83daf1ffe..6f1693571 100644 --- a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/table.svelte +++ b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/table.svelte @@ -222,7 +222,7 @@ {/if} {#if showRetry} - + {/if} {#if showLogs} diff --git a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/executions/sheet.svelte b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/executions/sheet.svelte index 7cddff0bb..bde1b909f 100644 --- a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/executions/sheet.svelte +++ b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/executions/sheet.svelte @@ -23,6 +23,8 @@ import { logStatusConverter } from './store'; import { LogsRequest, LogsResponse } from '$lib/components/logs'; import { timer } from '$lib/actions/timer'; + import { getEffectiveExecutionStatus } from '$lib/helpers/executionTimeout'; + import { func } from '../store'; export let selectedLogId: string; export let logs: Models.Execution[]; @@ -47,6 +49,7 @@ } $: selectedLog = logs?.find((log) => log.$id === selectedLogId); + $: effectiveStatus = selectedLog ? getEffectiveExecutionStatus(selectedLog, $func) : null; $: isFirstLog = logs.findIndex((log) => log.$id === selectedLogId) === 0; $: isLastLog = logs.findIndex((log) => log.$id === selectedLogId) === logs.length - 1; @@ -113,12 +116,12 @@
+ status={logStatusConverter(effectiveStatus)} + label={capitalize(effectiveStatus)}>
diff --git a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/executions/table.svelte b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/executions/table.svelte index 1e6915c38..f2431f02e 100644 --- a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/executions/table.svelte +++ b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/executions/table.svelte @@ -18,6 +18,7 @@ import DualTimeView from '$lib/components/dualTimeView.svelte'; import { func } from '../store'; import { sdk } from '$lib/stores/sdk'; + import { getEffectiveExecutionStatus } from '$lib/helpers/executionTimeout'; import { page } from '$app/state'; import { Submit, trackError, trackEvent } from '$lib/actions/analytics'; import { invalidate } from '$app/navigation'; @@ -66,6 +67,7 @@ {#snippet children(root)} {#each executions.executions as log (log.$id)} + {@const effectiveStatus = getEffectiveExecutionStatus(log, $func)}
+ status={logStatusConverter(effectiveStatus)} + label={capitalize(effectiveStatus)}>
diff --git a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/table.svelte b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/table.svelte index 94672a8d6..a70bf52d5 100644 --- a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/table.svelte +++ b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/table.svelte @@ -95,8 +95,7 @@ {#snippet children(root)} {#each data.deploymentList.deployments as deployment (deployment.$id)} {@const effectiveStatus = getEffectiveBuildStatus( - deployment.status, - deployment.$createdAt, + deployment, $regionalConsoleVariables )} {#if $project} - {#if $canWriteProjects} + + d.domain === apexDomain); + const domain = data.domainsList.domains.find((d: Models.Domain) => d.domain === apexDomain); if (apexDomain && !domain && isCloud) { try { - domain = await sdk.forConsole.domains.create({ + await sdk.forConsole.domains.create({ teamId: $project.teamId, domain: apexDomain }); } catch (error) { - // Apex domain creation error needs to be silent. + // apex might already be added on organization level, skip. + const alreadyAdded = error?.type === 'domain_already_exists'; + if (!alreadyAdded) { + addNotification({ + type: 'error', + message: error.message + }); + return; + } } } @@ -47,12 +55,18 @@ const rule = await sdk .forProject(page.params.region, page.params.project) .proxy.createAPIRule({ domain: domainName.toLocaleLowerCase() }); - if (rule?.status === 'verified') { + + await invalidate(Dependencies.DOMAINS); + + const verified = rule?.status !== 'created'; + if (verified) { + addNotification({ + type: 'success', + message: 'Domain verified successfully' + }); await goto(routeBase); - await invalidate(Dependencies.DOMAINS); } else { await goto(`${routeBase}/add-domain/verify-${domainName}?rule=${rule.$id}`); - await invalidate(Dependencies.DOMAINS); } } catch (error) { addNotification({ diff --git a/src/routes/(console)/project-[region]-[project]/settings/domains/add-domain/verify-[domain]/+page.svelte b/src/routes/(console)/project-[region]-[project]/settings/domains/add-domain/verify-[domain]/+page.svelte index f0312de38..93f725eb0 100644 --- a/src/routes/(console)/project-[region]-[project]/settings/domains/add-domain/verify-[domain]/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/settings/domains/add-domain/verify-[domain]/+page.svelte @@ -11,7 +11,6 @@ } from '@appwrite.io/pink-svelte'; import { Button, Form } from '$lib/elements/forms'; import { sdk } from '$lib/stores/sdk'; - import { organization } from '$lib/stores/organization'; import { addNotification } from '$lib/stores/notifications'; import { goto, invalidate } from '$app/navigation'; import { Dependencies } from '$lib/constants'; @@ -23,6 +22,7 @@ import NameserverTable from '$lib/components/domains/nameserverTable.svelte'; import RecordTable from '$lib/components/domains/recordTable.svelte'; import { regionalConsoleVariables } from '$routes/(console)/project-[region]-[project]/store'; + import { getApexDomain } from '$lib/helpers/tlds.js'; let { data } = $props(); @@ -44,8 +44,8 @@ ); const showNSTab = isCloud; + let proxyRule = $derived(data.proxyRule); let selectedTab = $state<'cname' | 'nameserver' | 'a' | 'aaaa'>(getDefaultTab()); - const routeBase = `${base}/project-${page.params.region}-${page.params.project}/settings/domains`; let verified: boolean | undefined = $state(undefined); const isSubmitting = writable(false); @@ -55,43 +55,31 @@ } async function verify() { - const isNewDomain = - data.domainsList.domains.find((rule) => rule.domain === data.proxyRule.domain) === - undefined; + verified = undefined; + try { - if (selectedTab !== 'nameserver') { - const ruleData = await sdk - .forProject(page.params.region, page.params.project) - .proxy.updateRuleVerification({ ruleId }); - verified = ruleData.status === 'verified'; - - // This means domain verification using DNS records hasn't succeeded and the rule is still in initial state. - if (ruleData.status === 'created') { - throw new Error( - 'Domain verification failed. Please check your domain settings or try again later' - ); - } - } else if (isNewDomain && isCloud) { - const domainData = await sdk.forConsole.domains.create({ - teamId: $organization.$id, - domain: data.proxyRule.domain - }); - verified = domainData.nameservers.toLowerCase() === 'appwrite'; - } - - if (verified) { - addNotification({ - type: 'success', - message: 'Domain added successfully' - }); - } else { - addNotification({ - type: 'info', - message: 'Verification in progress' + const apexDomain = getApexDomain(proxyRule.domain); + const domain = data.domainsList.domains.find((d) => d.domain === apexDomain); + if (isCloud && domain) { + await sdk.forConsole.domains.updateNameservers({ + domainId: domain.$id }); } - await goto(routeBase); + } catch (error) { + // Ignore error + } + + try { + proxyRule = await sdk + .forProject(page.params.region, page.params.project) + .proxy.updateRuleVerification({ ruleId }); + await invalidate(Dependencies.DOMAINS); + await goto(routeBase); + addNotification({ + type: 'success', + message: 'Domain verified successfully' + }); } catch (error) { verified = false; isSubmitting.set(false); @@ -108,7 +96,7 @@ .forProject(page.params.region, page.params.project) .proxy.deleteRule({ ruleId }); } - await goto(`${routeBase}/add-domain?domain=${data.proxyRule.domain}`); + await goto(`${routeBase}/add-domain?domain=${proxyRule.domain}`); } @@ -125,7 +113,7 @@ - {data.proxyRule.domain} + {proxyRule.domain} @@ -172,14 +160,17 @@ {#if selectedTab === 'nameserver'} - + {:else} (selectedTab = 'nameserver')} onNavigateToA={() => (selectedTab = 'a')} onNavigateToAAAA={() => (selectedTab = 'aaaa')} /> diff --git a/src/routes/(console)/project-[region]-[project]/settings/domains/retryDomainModal.svelte b/src/routes/(console)/project-[region]-[project]/settings/domains/retryDomainModal.svelte index bd77890a8..1098b8d3f 100644 --- a/src/routes/(console)/project-[region]-[project]/settings/domains/retryDomainModal.svelte +++ b/src/routes/(console)/project-[region]-[project]/settings/domains/retryDomainModal.svelte @@ -13,13 +13,16 @@ import { Divider, Tabs } from '@appwrite.io/pink-svelte'; import NameserverTable from '$lib/components/domains/nameserverTable.svelte'; import RecordTable from '$lib/components/domains/recordTable.svelte'; + import { getApexDomain } from '$lib/helpers/tlds'; let { show = $bindable(), - selectedProxyRule + selectedProxyRule, + domainsList }: { show: boolean; selectedProxyRule: Models.ProxyRule; + domainsList?: Models.DomainsList; } = $props(); const showCNAMETab = $derived( @@ -40,43 +43,42 @@ let selectedTab = $state<'cname' | 'nameserver' | 'a' | 'aaaa'>(getDefaultTab()); let error = $state(null); - let verified = $state(false); + let verified: boolean | undefined = $state(undefined); function getDefaultTab() { return showCNAMETab ? 'cname' : showATab ? 'a' : showAAAATab ? 'aaaa' : 'nameserver'; } async function retryDomain() { + error = null; + verified = undefined; + try { - error = null; - const proxyRule = await sdk + const apexDomain = getApexDomain(selectedProxyRule.domain); + const domain = domainsList?.domains.find((d) => d.domain === apexDomain); + if (isCloud && domain) { + await sdk.forConsole.domains.updateNameservers({ + domainId: domain.$id + }); + } + } catch { + // Ignore error + } + + try { + selectedProxyRule = await sdk .forProject(page.params.region, page.params.project) .proxy.updateRuleVerification({ ruleId: selectedProxyRule.$id }); - verified = proxyRule.status === 'verified'; await invalidate(Dependencies.DOMAINS); - - // This means domain verification using DNS records hasn't succeeded and the rule is still in initial state. - if (proxyRule.status === 'created') { - throw new Error( - 'Domain verification failed. Please check your domain settings or try again later' - ); - } - - if (verified) { - addNotification({ - type: 'success', - message: `${selectedProxyRule.domain} has been verified` - }); - } else { - addNotification({ - type: 'info', - message: 'Verification in progress' - }); - } show = false; + addNotification({ + type: 'success', + message: 'Domain verified successfully' + }); trackEvent(Submit.DomainUpdateVerification); } catch (e) { + verified = false; error = e.message ?? 'Domain verification failed. Please check your domain settings or try again later'; @@ -130,7 +132,10 @@ {#if selectedTab === 'nameserver'} - + {:else} + {/if} {#if showLogs} diff --git a/src/routes/(console)/project-[region]-[project]/settings/updateLabels.svelte b/src/routes/(console)/project-[region]-[project]/settings/updateLabels.svelte new file mode 100644 index 000000000..21d324ec4 --- /dev/null +++ b/src/routes/(console)/project-[region]-[project]/settings/updateLabels.svelte @@ -0,0 +1,102 @@ + + +
+ + Labels + Categorize and manage your projects for easy searching based on specific criteria by assigning + them customizable labels. + + + {#key labels.length} + + {/key} + + {#each suggestedLabels as suggestedLabel} + { + if (!labels.includes(suggestedLabel)) { + labels = [...labels, suggestedLabel]; + } else { + labels = labels.filter((e) => e !== suggestedLabel); + } + }}> + + {suggestedLabel} + + {/each} + + {error ? error : 'Only alphanumeric characters are allowed'} + + + + + + + + diff --git a/src/routes/(console)/project-[region]-[project]/sites/(components)/deploymentActionMenu.svelte b/src/routes/(console)/project-[region]-[project]/sites/(components)/deploymentActionMenu.svelte index 231611a16..aada935e8 100644 --- a/src/routes/(console)/project-[region]-[project]/sites/(components)/deploymentActionMenu.svelte +++ b/src/routes/(console)/project-[region]-[project]/sites/(components)/deploymentActionMenu.svelte @@ -54,8 +54,7 @@ {@const effectiveStatus = getEffectiveBuildStatus( - deployment.status, - deployment.$createdAt, + deployment, $regionalConsoleVariables )} {#if !inCard} diff --git a/src/routes/(console)/project-[region]-[project]/sites/(components)/logs.svelte b/src/routes/(console)/project-[region]-[project]/sites/(components)/logs.svelte index 7fae6d0ab..51c407652 100644 --- a/src/routes/(console)/project-[region]-[project]/sites/(components)/logs.svelte +++ b/src/routes/(console)/project-[region]-[project]/sites/(components)/logs.svelte @@ -6,6 +6,7 @@ case 'ready': return 'success'; case 'building': + case 'finalizing': return 'warning'; case 'processing': return undefined; @@ -40,9 +41,7 @@ emptyCopy?: string; } = $props(); - let effectiveStatus = $derived( - getEffectiveBuildStatus(deployment.status, deployment.$createdAt, $regionalConsoleVariables) - ); + let effectiveStatus = $derived(getEffectiveBuildStatus(deployment, $regionalConsoleVariables)); function setCopy() { if (effectiveStatus === 'failed') { @@ -73,7 +72,7 @@ variant="secondary" type={badgeTypeDeployment(effectiveStatus)} /> - + {/if} diff --git a/src/routes/(console)/project-[region]-[project]/sites/(components)/logsTimer.svelte b/src/routes/(console)/project-[region]-[project]/sites/(components)/logsTimer.svelte index 47bc28da3..79a00f541 100644 --- a/src/routes/(console)/project-[region]-[project]/sites/(components)/logsTimer.svelte +++ b/src/routes/(console)/project-[region]-[project]/sites/(components)/logsTimer.svelte @@ -7,15 +7,13 @@ import { Layout, Spinner, Typography } from '@appwrite.io/pink-svelte'; - let { status, deployment }: { status: string; deployment: Models.Deployment } = $props(); + let { deployment }: { deployment: Models.Deployment } = $props(); - let effectiveStatus = $derived( - getEffectiveBuildStatus(status, deployment.$createdAt, $regionalConsoleVariables) - ); + let effectiveStatus = $derived(getEffectiveBuildStatus(deployment, $regionalConsoleVariables)); - {#if ['processing', 'building'].includes(effectiveStatus)} + {#if ['processing', 'building', 'finalizing'].includes(effectiveStatus)}

diff --git a/src/routes/(console)/project-[region]-[project]/sites/(components)/siteCard.svelte b/src/routes/(console)/project-[region]-[project]/sites/(components)/siteCard.svelte index 78ad644f4..eb392282a 100644 --- a/src/routes/(console)/project-[region]-[project]/sites/(components)/siteCard.svelte +++ b/src/routes/(console)/project-[region]-[project]/sites/(components)/siteCard.svelte @@ -42,9 +42,7 @@ footer?: Snippet; } = $props(); - let effectiveStatus = $derived( - getEffectiveBuildStatus(deployment.status, deployment.$createdAt, $regionalConsoleVariables) - ); + let effectiveStatus = $derived(getEffectiveBuildStatus(deployment, $regionalConsoleVariables)); let show = $state(false); const totalSize = $derived(humanFileSize(deployment?.totalSize ?? 0)); diff --git a/src/routes/(console)/project-[region]-[project]/sites/create-site/deploying/+page.svelte b/src/routes/(console)/project-[region]-[project]/sites/create-site/deploying/+page.svelte index 3cb100543..b41104e09 100644 --- a/src/routes/(console)/project-[region]-[project]/sites/create-site/deploying/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/sites/create-site/deploying/+page.svelte @@ -12,32 +12,76 @@ import { onMount } from 'svelte'; import { getFrameworkIcon } from '$lib/stores/sites'; import type { Models } from '@appwrite.io/console'; + import { getEffectiveBuildStatus } from '$lib/helpers/buildTimeout'; + import { regionalConsoleVariables } from '$routes/(console)/project-[region]-[project]/store'; let { data } = $props(); let deployment = $state(data.deployment); + let skipScreenshotTimeout: ReturnType | null = $state(null); + + let effectiveStatus = $derived(getEffectiveBuildStatus(deployment, $regionalConsoleVariables)); onMount(() => { - return realtime.forConsole(page.params.region, 'console', async (response) => { - if ( - response.events.includes( - `sites.${data.site.$id}.deployments.${data.deployment.$id}.update` - ) - ) { - deployment = response.payload as Models.Deployment; - if (deployment.status === 'ready') { - const resolvedUrl = resolve( - '/(console)/project-[region]-[project]/sites/create-site/finish', - { - region: page.params.region, - project: page.params.project + const timeoutCleanup = () => { + if (skipScreenshotTimeout) { + clearTimeout(skipScreenshotTimeout); + skipScreenshotTimeout = null; + } + }; + + const realtimeUnsubscribe = realtime.forConsole( + page.params.region, + 'console', + async (response) => { + if ( + response.events.includes( + `sites.${data.site.$id}.deployments.${data.deployment.$id}.update` + ) + ) { + deployment = response.payload as Models.Deployment; + + const isReady = deployment.status === 'ready'; + + const isFinished = + isReady && deployment.screenshotLight && deployment.screenshotDark; + + // Fallback mechanism + // If ready but not finished for over 30 seconds, go anyway + if (isReady && !skipScreenshotTimeout) { + skipScreenshotTimeout = setTimeout(async () => { + goToFinishScreen(); + }, 30000); + } + + if (isReady && isFinished) { + if (skipScreenshotTimeout) { + clearTimeout(skipScreenshotTimeout); + skipScreenshotTimeout = null; } - ); - await goto(`${resolvedUrl}?site=${data.site.$id}`); + + goToFinishScreen(); + } } } - }); + ); + + return () => { + realtimeUnsubscribe(); + timeoutCleanup(); + }; }); + + async function goToFinishScreen() { + const resolvedUrl = resolve( + '/(console)/project-[region]-[project]/sites/create-site/finish', + { + region: page.params.region, + project: page.params.project + } + ); + await goto(`${resolvedUrl}?site=${data.site.$id}`); + } - {#if ['processing', 'building'].includes(data.deployment.status)} + {#if ['processing', 'building', 'finalizing'].includes(effectiveStatus)} Deployment will continue in the background diff --git a/src/routes/(console)/project-[region]-[project]/sites/site-[site]/deployments/deployment-[deployment]/+page.svelte b/src/routes/(console)/project-[region]-[project]/sites/site-[site]/deployments/deployment-[deployment]/+page.svelte index 1d418842f..c28f5f50b 100644 --- a/src/routes/(console)/project-[region]-[project]/sites/site-[site]/deployments/deployment-[deployment]/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/sites/site-[site]/deployments/deployment-[deployment]/+page.svelte @@ -26,9 +26,7 @@ let { data }: PageProps = $props(); let deployment = $derived(data.deployment); - let effectiveStatus = $derived( - getEffectiveBuildStatus(deployment.status, deployment.$createdAt, $regionalConsoleVariables) - ); + let effectiveStatus = $derived(getEffectiveBuildStatus(deployment, $regionalConsoleVariables)); let showRedeploy = $state(false); let showActivate = $state(false); @@ -90,7 +88,7 @@ hideDivider> - + diff --git a/src/routes/(console)/project-[region]-[project]/sites/site-[site]/deployments/table.svelte b/src/routes/(console)/project-[region]-[project]/sites/site-[site]/deployments/table.svelte index d135498a6..3dac48976 100644 --- a/src/routes/(console)/project-[region]-[project]/sites/site-[site]/deployments/table.svelte +++ b/src/routes/(console)/project-[region]-[project]/sites/site-[site]/deployments/table.svelte @@ -82,10 +82,10 @@ {#snippet children(root)} {#each data.deploymentList.deployments as deployment (deployment.$id)} {@const effectiveStatus = getEffectiveBuildStatus( - deployment.status, - deployment.$createdAt, + deployment, $regionalConsoleVariables )} + {@const displayStatus = effectiveStatus === 'finalizing' ? 'ready' : effectiveStatus} {:else} + status={deploymentStatusConverter(displayStatus)} + label={capitalize(displayStatus)} /> {/if} {:else if column.id === 'type'} diff --git a/src/routes/(console)/project-[region]-[project]/sites/site-[site]/deploymentsOverview.svelte b/src/routes/(console)/project-[region]-[project]/sites/site-[site]/deploymentsOverview.svelte index 1816d005c..f9f2f8c0e 100644 --- a/src/routes/(console)/project-[region]-[project]/sites/site-[site]/deploymentsOverview.svelte +++ b/src/routes/(console)/project-[region]-[project]/sites/site-[site]/deploymentsOverview.svelte @@ -66,6 +66,12 @@ {#each deploymentList?.deployments as deployment (deployment.$id)} + {@const effectiveStatus = getEffectiveBuildStatus( + deployment, + $regionalConsoleVariables + )} + {@const displayStatus = + effectiveStatus === 'finalizing' ? 'ready' : effectiveStatus} @@ -73,18 +79,12 @@ {deployment.$id} - {@const status = deployment.status} - {@const effectiveStatus = getEffectiveBuildStatus( - status, - deployment.$createdAt, - $regionalConsoleVariables - )} {#if activeDeployment?.$id === deployment?.$id} {:else} + status={deploymentStatusConverter(displayStatus)} + label={capitalize(displayStatus)} /> {/if} diff --git a/src/routes/(console)/project-[region]-[project]/sites/site-[site]/domains/add-domain/+page.svelte b/src/routes/(console)/project-[region]-[project]/sites/site-[site]/domains/add-domain/+page.svelte index b4288a1f9..90f8c679d 100644 --- a/src/routes/(console)/project-[region]-[project]/sites/site-[site]/domains/add-domain/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/sites/site-[site]/domains/add-domain/+page.svelte @@ -58,16 +58,24 @@ async function addDomain() { const apexDomain = getApexDomain(domainName); const isSiteDomain = domainName.endsWith($regionalConsoleVariables._APP_DOMAIN_SITES); - let domain = data.domainsList.domains.find((d) => d.domain === apexDomain); + const domain = data.domainsList.domains.find((d) => d.domain === apexDomain); if (isCloud && apexDomain && !domain && !isSiteDomain) { try { - domain = await sdk.forConsole.domains.create({ + await sdk.forConsole.domains.create({ teamId: $project.teamId, domain: apexDomain }); } catch (error) { - // Apex domain creation error needs to be silent. + // apex might already be added on organization level, skip. + const alreadyAdded = error?.type === 'domain_already_exists'; + if (!alreadyAdded) { + addNotification({ + type: 'error', + message: error.message + }); + return; + } } } @@ -99,12 +107,18 @@ siteId: page.params.site }); } - if (rule?.status === 'verified') { + + await invalidate(Dependencies.SITES_DOMAINS); + + const verified = rule?.status !== 'created'; + if (verified) { + addNotification({ + type: 'success', + message: 'Domain verified successfully' + }); await goto(routeBase); - await invalidate(Dependencies.SITES_DOMAINS); } else { await goto(`${routeBase}/add-domain/verify-${domainName}?rule=${rule.$id}`); - await invalidate(Dependencies.SITES_DOMAINS); } } catch (error) { addNotification({ diff --git a/src/routes/(console)/project-[region]-[project]/sites/site-[site]/domains/add-domain/verify-[domain]/+page.svelte b/src/routes/(console)/project-[region]-[project]/sites/site-[site]/domains/add-domain/verify-[domain]/+page.svelte index 80fba1842..83eb4f33d 100644 --- a/src/routes/(console)/project-[region]-[project]/sites/site-[site]/domains/add-domain/verify-[domain]/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/sites/site-[site]/domains/add-domain/verify-[domain]/+page.svelte @@ -11,7 +11,6 @@ } from '@appwrite.io/pink-svelte'; import { Button, Form } from '$lib/elements/forms'; import { sdk } from '$lib/stores/sdk'; - import { organization } from '$lib/stores/organization'; import { addNotification } from '$lib/stores/notifications'; import { goto, invalidate } from '$app/navigation'; import { Dependencies } from '$lib/constants'; @@ -23,6 +22,7 @@ import RecordTable from '$lib/components/domains/recordTable.svelte'; import NameserverTable from '$lib/components/domains/nameserverTable.svelte'; import { regionalConsoleVariables } from '$routes/(console)/project-[region]-[project]/store'; + import { getApexDomain } from '$lib/helpers/tlds.js'; let { data } = $props(); @@ -44,6 +44,7 @@ ); const showNSTab = isCloud; + let proxyRule = $derived(data.proxyRule); let selectedTab = $state<'cname' | 'nameserver' | 'a' | 'aaaa'>(getDefaultTab()); let routeBase = `${base}/project-${page.params.region}-${page.params.project}/sites/site-${page.params.site}/domains`; let verified: boolean | undefined = $state(undefined); @@ -54,44 +55,34 @@ } async function verify() { - const isNewDomain = - data.domainsList.domains.findIndex((rule) => rule.domain === data.proxyRule.domain) === - -1; + verified = undefined; + try { - if (selectedTab !== 'nameserver') { - const ruleData = await sdk - .forProject(page.params.region, page.params.project) - .proxy.updateRuleVerification({ ruleId }); - verified = ruleData.status === 'verified'; - - // This means domain verification using DNS records hasn't succeeded and the rule is still in initial state. - if (ruleData.status === 'created') { - throw new Error( - 'Domain verification failed. Please check your domain settings or try again later' - ); - } - } else if (isNewDomain && isCloud) { - const domainData = await sdk.forConsole.domains.create({ - teamId: $organization.$id, - domain: data.proxyRule.domain - }); - verified = domainData.nameservers.toLowerCase() === 'appwrite'; - } - - if (verified) { - addNotification({ - type: 'success', - message: 'Domain added successfully' - }); - } else { - addNotification({ - type: 'info', - message: 'Verification in progress' + const apexDomain = getApexDomain(proxyRule.domain); + const domain = data.domainsList.domains.find((d) => d.domain === apexDomain); + if (isCloud && domain) { + await sdk.forConsole.domains.updateNameservers({ + domainId: domain.$id }); } + } catch (error) { + // Ignore error + } + + try { + proxyRule = await sdk + .forProject(page.params.region, page.params.project) + .proxy.updateRuleVerification({ ruleId }); + + await Promise.all([ + invalidate(Dependencies.DOMAINS), + invalidate(Dependencies.SITES_DOMAINS) + ]); await goto(routeBase); - await invalidate(Dependencies.DOMAINS); - await invalidate(Dependencies.SITES_DOMAINS); + addNotification({ + type: 'success', + message: 'Domain verified successfully' + }); } catch (error) { verified = false; isSubmitting.set(false); @@ -108,7 +99,7 @@ .forProject(page.params.region, page.params.project) .proxy.deleteRule({ ruleId }); } - await goto(`${routeBase}/add-domain?domain=${data.proxyRule.domain}`); + await goto(`${routeBase}/add-domain?domain=${proxyRule.domain}`); } @@ -125,7 +116,7 @@ - {data.proxyRule.domain} + {proxyRule.domain}
@@ -172,14 +163,17 @@ {#if selectedTab === 'nameserver'} - + {:else} (selectedTab = 'nameserver')} onNavigateToA={() => (selectedTab = 'a')} onNavigateToAAAA={() => (selectedTab = 'aaaa')} /> diff --git a/src/routes/(console)/project-[region]-[project]/sites/site-[site]/domains/retryDomainModal.svelte b/src/routes/(console)/project-[region]-[project]/sites/site-[site]/domains/retryDomainModal.svelte index 6e36ac2ec..56fa02b6d 100644 --- a/src/routes/(console)/project-[region]-[project]/sites/site-[site]/domains/retryDomainModal.svelte +++ b/src/routes/(console)/project-[region]-[project]/sites/site-[site]/domains/retryDomainModal.svelte @@ -13,13 +13,16 @@ import NameserverTable from '$lib/components/domains/nameserverTable.svelte'; import RecordTable from '$lib/components/domains/recordTable.svelte'; import { regionalConsoleVariables } from '$routes/(console)/project-[region]-[project]/store'; + import { getApexDomain } from '$lib/helpers/tlds'; let { show = $bindable(false), - selectedProxyRule + selectedProxyRule, + domainsList }: { show: boolean; selectedProxyRule: Models.ProxyRule; + domainsList?: Models.DomainsList; } = $props(); const showCNAMETab = $derived( @@ -40,43 +43,42 @@ let selectedTab = $state<'cname' | 'nameserver' | 'a' | 'aaaa'>(getDefaultTab()); let error = $state(null); - let verified = $state(false); + let verified: boolean | undefined = $state(undefined); function getDefaultTab() { return showCNAMETab ? 'cname' : showATab ? 'a' : showAAAATab ? 'aaaa' : 'nameserver'; } async function retryDomain() { + error = null; + verified = undefined; + try { - error = null; - const proxyRule = await sdk + const apexDomain = getApexDomain(selectedProxyRule.domain); + const domain = domainsList?.domains.find((d) => d.domain === apexDomain); + if (isCloud && domain) { + await sdk.forConsole.domains.updateNameservers({ + domainId: domain.$id + }); + } + } catch { + // Ignore error + } + + try { + selectedProxyRule = await sdk .forProject(page.params.region, page.params.project) .proxy.updateRuleVerification({ ruleId: selectedProxyRule.$id }); - verified = proxyRule.status === 'verified'; await invalidate(Dependencies.SITES_DOMAINS); - - // This means domain verification using DNS records hasn't succeeded and the rule is still in initial state. - if (proxyRule.status === 'created') { - throw new Error( - 'Domain verification failed. Please check your domain settings or try again later' - ); - } - - if (verified) { - addNotification({ - type: 'success', - message: `${selectedProxyRule.domain} has been verified` - }); - } else { - addNotification({ - type: 'info', - message: 'Verification in progress' - }); - } show = false; + addNotification({ + type: 'success', + message: 'Domain verified successfully' + }); trackEvent(Submit.DomainUpdateVerification); } catch (e) { + verified = false; error = e.message ?? 'Domain verification failed. Please check your domain settings or try again later'; @@ -130,7 +132,10 @@ {#if selectedTab === 'nameserver'} - + {:else} ([ title: 'Domain', type: 'string', format: 'string', - width: { min: 300 } + width: { min: 600 } }, { id: 'target', title: 'Target', type: 'string', - width: { min: 120, max: 400 } + width: { min: 160, max: 400 } }, { diff --git a/src/routes/(console)/project-[region]-[project]/sites/site-[site]/domains/table.svelte b/src/routes/(console)/project-[region]-[project]/sites/site-[site]/domains/table.svelte index a3921aeaa..b1a1b4447 100644 --- a/src/routes/(console)/project-[region]-[project]/sites/site-[site]/domains/table.svelte +++ b/src/routes/(console)/project-[region]-[project]/sites/site-[site]/domains/table.svelte @@ -222,7 +222,7 @@ {/if} {#if showRetry} - + {/if} {#if showLogs} diff --git a/src/routes/(public)/(guest)/register/invite/[slug]/+page.svelte b/src/routes/(public)/(guest)/register/invite/[slug]/+page.svelte index 898d16358..fdd6c247a 100644 --- a/src/routes/(public)/(guest)/register/invite/[slug]/+page.svelte +++ b/src/routes/(public)/(guest)/register/invite/[slug]/+page.svelte @@ -57,7 +57,7 @@ const res = await fetch(`${endpoint}/account/invite`, { method: 'POST', headers: { - 'X-Appwrite-Project': project, + 'X-Appwrite-Project': project as string, 'Content-Type': 'application/json' }, body: JSON.stringify({ diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 571542d06..c1d724892 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -17,6 +17,7 @@ import { ThemeDark, ThemeLight, ThemeDarkCloud, ThemeLightCloud } from '../themes'; import { isSmallViewport, updateViewport } from '$lib/stores/viewport'; import { feedback } from '$lib/stores/feedback'; + import '$lib/profiles/css/base.css'; function resolveTheme(theme: AppStore['themeInUse']) { switch (theme) {