diff --git a/bun.lock b/bun.lock
index 49d8619da..ff9de653b 100644
--- a/bun.lock
+++ b/bun.lock
@@ -24,7 +24,6 @@
"deep-equal": "^2.2.3",
"echarts": "^5.6.0",
"flatted": "^3.4.2",
- "@appwrite.io/console": "https://pkg.vc/-/@appwrite/@appwrite.io/console@67539a6",
"ignore": "^6.0.2",
"nanoid": "^5.1.7",
"nanotar": "^0.3.0",
@@ -41,7 +40,7 @@
"@melt-ui/svelte": "^0.86.6",
"@playwright/test": "^1.58.2",
"@sveltejs/adapter-static": "^3.0.10",
- "@sveltejs/kit": "^2.55.0",
+ "@sveltejs/kit": "^2.57.1",
"@sveltejs/vite-plugin-svelte": "^5.1.1",
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^6.9.1",
@@ -435,7 +434,7 @@
"@sveltejs/adapter-static": ["@sveltejs/adapter-static@3.0.10", "", { "peerDependencies": { "@sveltejs/kit": "^2.0.0" } }, "sha512-7D9lYFWJmB7zxZyTE/qxjksvMqzMuYrrsyh1f4AlZqeZeACPRySjbC3aFiY55wb1tWUaKOQG9PVbm74JcN2Iew=="],
- "@sveltejs/kit": ["@sveltejs/kit@2.55.0", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/cookie": "^0.6.0", "acorn": "^8.14.1", "cookie": "^0.6.0", "devalue": "^5.6.4", "esm-env": "^1.2.2", "kleur": "^4.1.5", "magic-string": "^0.30.5", "mrmime": "^2.0.0", "set-cookie-parser": "^3.0.0", "sirv": "^3.0.0" }, "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 || ^7.0.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 || ^8.0.0" }, "optionalPeers": ["@opentelemetry/api", "typescript"], "bin": { "svelte-kit": "svelte-kit.js" } }, "sha512-MdFRjevVxmAknf2NbaUkDF16jSIzXMWd4Nfah0Qp8TtQVoSp3bV4jKt8mX7z7qTUTWvgSaxtR0EG5WJf53gcuA=="],
+ "@sveltejs/kit": ["@sveltejs/kit@2.57.1", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/cookie": "^0.6.0", "acorn": "^8.14.1", "cookie": "^0.6.0", "devalue": "^5.6.4", "esm-env": "^1.2.2", "kleur": "^4.1.5", "magic-string": "^0.30.5", "mrmime": "^2.0.0", "set-cookie-parser": "^3.0.0", "sirv": "^3.0.0" }, "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 || ^7.0.0", "svelte": "^4.0.0 || ^5.0.0-next.0", "typescript": "^5.3.3 || ^6.0.0", "vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0 || ^8.0.0" }, "optionalPeers": ["@opentelemetry/api", "typescript"], "bin": { "svelte-kit": "svelte-kit.js" } }, "sha512-VRdSbB96cI1EnRh09CqmnQqP/YJvET5buj8S6k7CxaJqBJD4bw4fRKDjcarAj/eX9k2eHifQfDH8NtOh+ZxxPw=="],
"@sveltejs/vite-plugin-svelte": ["@sveltejs/vite-plugin-svelte@5.1.1", "", { "dependencies": { "@sveltejs/vite-plugin-svelte-inspector": "^4.0.1", "debug": "^4.4.1", "deepmerge": "^4.3.1", "kleur": "^4.1.5", "magic-string": "^0.30.17", "vitefu": "^1.0.6" }, "peerDependencies": { "svelte": "^5.0.0", "vite": "^6.0.0" } }, "sha512-Y1Cs7hhTc+a5E9Va/xwKlAJoariQyHY+5zBgCZg4PFWNYQ1nMN9sjK1zhw1gK69DuqVP++sht/1GZg1aRwmAXQ=="],
diff --git a/package.json b/package.json
index 74c0c7948..f14d08510 100644
--- a/package.json
+++ b/package.json
@@ -55,7 +55,7 @@
"@melt-ui/svelte": "^0.86.6",
"@playwright/test": "^1.58.2",
"@sveltejs/adapter-static": "^3.0.10",
- "@sveltejs/kit": "^2.55.0",
+ "@sveltejs/kit": "^2.57.1",
"@sveltejs/vite-plugin-svelte": "^5.1.1",
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^6.9.1",
diff --git a/src/lib/components/billing/planComparisonBox.svelte b/src/lib/components/billing/planComparisonBox.svelte
index 7a71d2f01..74c617584 100644
--- a/src/lib/components/billing/planComparisonBox.svelte
+++ b/src/lib/components/billing/planComparisonBox.svelte
@@ -86,6 +86,18 @@
{formatNum(currentPlan.executions)} executions
+ {#if currentPlan.domains > 0}
+
+
+
+ Limited to {currentPlan.domains} custom {pluralize(
+ currentPlan.domains,
+ 'domain'
+ )}
+ per project
+
+
+ {/if}
{:else}
@@ -105,12 +117,22 @@
-
Limited to {formatNum(currentPlan.executions)} executions
+ {#if currentPlan.domains > 0}
+ -
+ Limited to {currentPlan.domains} custom {pluralize(
+ currentPlan.domains,
+ 'domain'
+ )} per project
+
+ {:else}
+ - Unlimited custom domains
+ {/if}
{/if}
{:else if planHasGroup(selectedTab, BillingPlanGroup.Pro)}
Everything in the Free plan, plus:
- - Unlimited databases, buckets, functions
+ - Unlimited databases, buckets, functions, and custom domains
- Unlimited seats
- {currentPlan.bandwidth}GB bandwidth
- {currentPlan.storage}GB storage
diff --git a/src/lib/stores/billing.ts b/src/lib/stores/billing.ts
index 3454d2ba7..7f85293ec 100644
--- a/src/lib/stores/billing.ts
+++ b/src/lib/stores/billing.ts
@@ -200,6 +200,7 @@ export type PlanServices =
| 'bandwidthAddon'
| 'buckets'
| 'databases'
+ | 'domains'
| 'executions'
| 'executionsAddon'
| 'fileSize'
@@ -316,6 +317,7 @@ export function checkForProjectLimitation(plan: string, id: PlanServices) {
switch (id) {
case 'databases':
+ case 'domains':
case 'functions':
case 'buckets':
case 'members': // Only applies to Free plan now
diff --git a/src/routes/(console)/organization-[organization]/domains/+page.svelte b/src/routes/(console)/organization-[organization]/domains/+page.svelte
index 650c287b5..dbd8e07d6 100644
--- a/src/routes/(console)/organization-[organization]/domains/+page.svelte
+++ b/src/routes/(console)/organization-[organization]/domains/+page.svelte
@@ -34,11 +34,11 @@
import { View } from '$lib/helpers/load';
import type { Models } from '@appwrite.io/console';
- export let data;
+ let { data } = $props();
- let showDelete = false;
- let showRetry = false;
- let selectedDomain: Models.Domain = null;
+ let showDelete = $state(false);
+ let showRetry = $state(false);
+ let selectedDomain = $state(null);
const isDomainVerified = (domain: Models.Domain) => {
return domain.nameservers.toLowerCase() === 'appwrite';
diff --git a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/+page.svelte b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/+page.svelte
index 46599175e..5b6618386 100644
--- a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/+page.svelte
+++ b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/+page.svelte
@@ -6,16 +6,26 @@
import Container from '$lib/layout/container.svelte';
import type { Models } from '@appwrite.io/console';
import { IconPlus } from '@appwrite.io/pink-icons-svelte';
- import { Card, Empty, Icon, Layout } from '@appwrite.io/pink-svelte';
+ import { Card, Empty, Icon, Layout, Tooltip } from '@appwrite.io/pink-svelte';
import DeleteDomainModal from './deleteDomainModal.svelte';
import RetryDomainModal from './retryDomainModal.svelte';
import SearchQuery from '$lib/components/searchQuery.svelte';
import { app } from '$lib/stores/app';
import { Click, trackEvent } from '$lib/actions/analytics';
+ import {
+ BODY_TOOLTIP_MAX_WIDTH,
+ BODY_TOOLTIP_WRAPPER_STYLE_PRELINE
+ } from '$lib/helpers/tooltipContent';
+ import { isServiceLimited } from '$lib/stores/billing';
+ import { organization } from '$lib/stores/organization';
import Table from './table.svelte';
let { data } = $props();
+ const isDomainLimitReached = $derived(
+ isServiceLimited('domains', $organization, data.proxyRules.total)
+ );
+
let showDelete = $state(false);
let showRetry = $state(false);
let selectedProxyRule: Models.ProxyRule = null;
@@ -24,16 +34,28 @@
-
+
+
+
+
+
+
+ You have reached the maximum number of custom domains for your plan.
+
+
+
{#if data.proxyRules.total}
@@ -70,12 +92,24 @@
size="s"
ariaLabel="add domain">Documentation
-
+
+
+
+
+
+
+ You have reached the maximum number of custom domains for your plan.
+
+
+
diff --git a/src/routes/(console)/project-[region]-[project]/settings/domains/+page.svelte b/src/routes/(console)/project-[region]-[project]/settings/domains/+page.svelte
index 1ba22bc3f..d4a0431a8 100644
--- a/src/routes/(console)/project-[region]-[project]/settings/domains/+page.svelte
+++ b/src/routes/(console)/project-[region]-[project]/settings/domains/+page.svelte
@@ -5,13 +5,23 @@
import { Button } from '$lib/elements/forms';
import Container from '$lib/layout/container.svelte';
import { IconPlus } from '@appwrite.io/pink-icons-svelte';
- import { Card, Empty, Icon } from '@appwrite.io/pink-svelte';
+ import { Card, Empty, Icon, Tooltip } from '@appwrite.io/pink-svelte';
import { app } from '$lib/stores/app';
import { Click, trackEvent } from '$lib/actions/analytics';
+ import {
+ BODY_TOOLTIP_MAX_WIDTH,
+ BODY_TOOLTIP_WRAPPER_STYLE_PRELINE
+ } from '$lib/helpers/tooltipContent';
+ import { isServiceLimited } from '$lib/stores/billing';
+ import { organization } from '$lib/stores/organization';
import Table from './table.svelte';
import { ResponsiveContainerHeader } from '$lib/layout';
let { data } = $props();
+
+ const isDomainLimitReached = $derived(
+ isServiceLimited('domains', $organization, data.rules.total)
+ );
@@ -20,16 +30,28 @@
hideView
searchPlaceholder="Search by domain"
analyticsSource="settings_domain_overview">
-
+
+
+
+
+
+
+ You have reached the maximum number of custom domains for your plan.
+
+
+
{#if data.rules.total}
@@ -64,12 +86,24 @@
size="s"
ariaLabel="add domain">Documentation
-
+
+
+
+
+
+
+ You have reached the maximum number of custom domains for your plan.
+
+
+
diff --git a/src/routes/(console)/project-[region]-[project]/sites/site-[site]/domains/+page.svelte b/src/routes/(console)/project-[region]-[project]/sites/site-[site]/domains/+page.svelte
index 8ffd2bfc6..a63fb073c 100644
--- a/src/routes/(console)/project-[region]-[project]/sites/site-[site]/domains/+page.svelte
+++ b/src/routes/(console)/project-[region]-[project]/sites/site-[site]/domains/+page.svelte
@@ -5,28 +5,50 @@
import { Button } from '$lib/elements/forms';
import Container from '$lib/layout/container.svelte';
import { IconPlus } from '@appwrite.io/pink-icons-svelte';
- import { Card, Empty, Icon, Layout } from '@appwrite.io/pink-svelte';
+ import { Card, Empty, Icon, Layout, Tooltip } from '@appwrite.io/pink-svelte';
import SearchQuery from '$lib/components/searchQuery.svelte';
import { app } from '$lib/stores/app';
import { Click, trackEvent } from '$lib/actions/analytics';
+ import {
+ BODY_TOOLTIP_MAX_WIDTH,
+ BODY_TOOLTIP_WRAPPER_STYLE_PRELINE
+ } from '$lib/helpers/tooltipContent';
+ import { isServiceLimited } from '$lib/stores/billing';
+ import { organization } from '$lib/stores/organization';
import Table from './table.svelte';
- export let data;
+ let { data } = $props();
+
+ const isDomainLimitReached = $derived(
+ isServiceLimited('domains', $organization, data.proxyRules.total)
+ );
-
+
+
+
+
+
+
+ You have reached the maximum number of custom domains for your plan.
+
+
+
{#if data.proxyRules.total}
@@ -62,12 +84,24 @@
size="s"
ariaLabel="add domain">Documentation
-
+
+
+
+
+
+
+ You have reached the maximum number of custom domains for your plan.
+
+
+