diff --git a/package.json b/package.json
index 5a2e77773d..7d9d660304 100644
--- a/package.json
+++ b/package.json
@@ -95,5 +95,5 @@
"svelte-preprocess"
]
},
- "packageManager": "pnpm@10.15.1"
+ "packageManager": "pnpm@10.18.3"
}
diff --git a/src/lib/components/domains/cnameTable.svelte b/src/lib/components/domains/cnameTable.svelte
index b198524da2..e6216c4dea 100644
--- a/src/lib/components/domains/cnameTable.svelte
+++ b/src/lib/components/domains/cnameTable.svelte
@@ -1,6 +1,7 @@
@@ -23,15 +37,25 @@
{domain}
- {#if verified === true}
+ {#if ruleStatus === 'created'}
+
+ {:else if ruleStatus === 'verifying'}
+
+ {:else if ruleStatus === 'unverified'}
+
+ {:else if verified === true}
- {:else if verified === false}
-
{/if}
- Add the following record on your DNS provider. Note that DNS changes may take time to
- propagate fully.
+ Add the following {$regionalConsoleVariables._APP_DOMAIN_TARGET_CAA
+ ? 'records'
+ : 'record'} on your DNS provider. Note that DNS changes may take up to 48 hours to propagate
+ fully.
@@ -43,7 +67,7 @@
CNAME
- {subdomain}
+ {subdomain || '@'}
+ {#if $regionalConsoleVariables._APP_DOMAIN_TARGET_CAA}
+
+
+
+ CAA
+
+
+
+ @
+
+
+
+
+ {/if}
diff --git a/src/lib/components/domains/index.ts b/src/lib/components/domains/index.ts
new file mode 100644
index 0000000000..8571098162
--- /dev/null
+++ b/src/lib/components/domains/index.ts
@@ -0,0 +1,5 @@
+export { default as ViewLogsModal } from './viewLogsModal.svelte';
+export { default as CnameTable } from './cnameTable.svelte';
+export { default as DnsRecordsAction } from './dnsRecordsAction.svelte';
+export { default as NameserverTable } from './nameserverTable.svelte';
+export { default as RecordTable } from './recordTable.svelte';
diff --git a/src/lib/components/domains/nameserverTable.svelte b/src/lib/components/domains/nameserverTable.svelte
index a08de42080..57a08151ed 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 = undefined,
+ ruleStatus = undefined
+ }: {
+ domain: string;
+ verified?: boolean | undefined;
+ ruleStatus?: string | undefined;
+ } = $props();
const nameserverList = $regionalConsoleVariables?._APP_DOMAINS_NAMESERVERS
? $regionalConsoleVariables?._APP_DOMAINS_NAMESERVERS?.split(',')
@@ -16,10 +23,18 @@
{domain}
- {#if verified === true}
+ {#if ruleStatus === 'created'}
+
+ {:else if ruleStatus === 'verifying'}
+
+ {:else if ruleStatus === 'unverified'}
+
+ {:else if verified === true}
- {:else if verified === false}
-
{/if}
diff --git a/src/lib/components/domains/recordTable.svelte b/src/lib/components/domains/recordTable.svelte
index 14683b7218..d55ec16d91 100644
--- a/src/lib/components/domains/recordTable.svelte
+++ b/src/lib/components/domains/recordTable.svelte
@@ -9,20 +9,58 @@
Alert
} from '@appwrite.io/pink-svelte';
import { regionalConsoleVariables } from '$routes/(console)/project-[region]-[project]/store';
+ import { isCloud } from '$lib/system';
+ import { getSubdomain } from '$lib/helpers/tlds';
- export let domain: string;
- export let verified = undefined;
- export let variant: 'cname' | 'a' | 'aaaa';
- export let service: 'sites' | 'general' = 'general';
+ let {
+ domain,
+ verified = undefined,
+ variant,
+ service = 'general',
+ ruleStatus = undefined,
+ onNavigateToNameservers = () => {},
+ onNavigateToA = () => {},
+ onNavigateToAAAA = () => {}
+ }: {
+ domain: string;
+ verified?: boolean | undefined;
+ variant: 'cname' | 'a' | 'aaaa';
+ service?: 'sites' | 'functions' | 'general';
+ ruleStatus?: string | undefined;
+ onNavigateToNameservers?: () => void;
+ onNavigateToA?: () => void;
+ onNavigateToAAAA?: () => void;
+ } = $props();
- let subdomain = domain?.split('.')?.slice(0, -2)?.join('.');
+ const subdomain = $derived(getSubdomain(domain));
+
+ const aTabVisible = $derived(
+ !isCloud &&
+ Boolean($regionalConsoleVariables._APP_DOMAIN_TARGET_A) &&
+ $regionalConsoleVariables._APP_DOMAIN_TARGET_A !== '127.0.0.1'
+ );
+ const aaaaTabVisible = $derived(
+ !isCloud &&
+ Boolean($regionalConsoleVariables._APP_DOMAIN_TARGET_AAAA) &&
+ $regionalConsoleVariables._APP_DOMAIN_TARGET_AAAA !== '::1'
+ );
+
+ const caaText = $derived(
+ $regionalConsoleVariables._APP_DOMAIN_TARGET_CAA?.includes(' ')
+ ? $regionalConsoleVariables._APP_DOMAIN_TARGET_CAA
+ : `0 issue "${$regionalConsoleVariables._APP_DOMAIN_TARGET_CAA}"`
+ );
function setTarget() {
switch (variant) {
case 'cname':
- return service === 'general'
- ? $regionalConsoleVariables._APP_DOMAIN_TARGET_CNAME
- : $regionalConsoleVariables._APP_DOMAIN_SITES;
+ if (service === 'sites') {
+ return $regionalConsoleVariables._APP_DOMAIN_SITES;
+ } else if (service === 'functions') {
+ return $regionalConsoleVariables._APP_DOMAIN_FUNCTIONS;
+ } else {
+ return $regionalConsoleVariables._APP_DOMAIN_TARGET_CNAME;
+ }
case 'a':
return $regionalConsoleVariables._APP_DOMAIN_TARGET_A;
case 'aaaa':
@@ -37,15 +75,25 @@
{domain}
- {#if verified === true}
+ {#if ruleStatus === 'created'}
+
+ {:else if ruleStatus === 'verifying'}
+
+ {:else if ruleStatus === 'unverified'}
+
+ {:else if verified === true}
- {:else if verified === false}
-
{/if}
- Add the following record on your DNS provider. Note that DNS changes may take time to
- propagate fully.
+ Add the following {$regionalConsoleVariables._APP_DOMAIN_TARGET_CAA
+ ? 'records'
+ : 'record'} on your DNS provider. Note that DNS changes may take up to 48 hours to propagate
+ fully.
@@ -62,17 +110,45 @@
+ {#if $regionalConsoleVariables._APP_DOMAIN_TARGET_CAA}
+
+
+
+ CAA
+
+
+
+ @
+
+
+
+
+ {/if}
- {#if variant === 'cname'}
-
- If your domain uses CAA records, ensure certainly.com is authorized — otherwise, SSL
- setup may fail. A list of all domain providers and their DNS setting is available here.
-
+ {#if variant === 'cname' && !subdomain}
+ {#if isCloud}
+
+ Since is an apex domain,
+ CNAME record is only supported by certain providers. If yours doesn't, please verify
+ using
+ nameservers instead.
+
+ {:else if aTabVisible || aaaaTabVisible}
+
+ Since is an apex domain,
+ CNAME record is only supported by certain providers. If yours doesn't, please verify
+ using
+ {#if aTabVisible}
+ A record
+ {#if aaaaTabVisible}
+ or AAAA record{/if}
+ {:else if aaaaTabVisible}
+ AAAA record
+ {/if} instead.
+
+ {/if}
{:else}
A list of all domain providers and their DNS setting is available
-
+
diff --git a/src/lib/components/index.ts b/src/lib/components/index.ts
index df9a3ceeaf..6f8932f874 100644
--- a/src/lib/components/index.ts
+++ b/src/lib/components/index.ts
@@ -87,6 +87,7 @@ export { default as RegionEndpoint } from './regionEndpoint.svelte';
export { default as ExpirationInput } from './expirationInput.svelte';
export { default as EstimatedCard } from './estimatedCard.svelte';
export { default as SortButton, type SortDirection } from './sortButton.svelte';
+export * from './domains';
export { default as SendVerificationEmailModal } from './account/sendVerificationEmailModal.svelte';
export { default as MultiSelectionTable } from './multiSelectTable.svelte';
export * from './multiSelectTable.svelte';
diff --git a/src/lib/helpers/date.ts b/src/lib/helpers/date.ts
index 2d56c1cb6a..78aa554948 100644
--- a/src/lib/helpers/date.ts
+++ b/src/lib/helpers/date.ts
@@ -206,6 +206,21 @@ export function timeFromNow(datetime: string): string {
return dayjs().to(dayjs(datetime));
}
+export function timeFromNowShort(datetime: string): string {
+ if (!datetime) {
+ return 'unknown time';
+ }
+ if (!isValidDate(datetime)) {
+ return 'invalid date';
+ }
+
+ const timeStr = dayjs().to(dayjs(datetime));
+ return timeStr
+ .replace('second', 'sec') // seconds > secs
+ .replace('minute', 'min') // minutes > mins
+ .replace('hour', 'hr'); // hours > hrs
+}
+
export function hoursToDays(hours: number) {
if (hours > 24) {
return `${Math.floor(hours / 24)} days`;
diff --git a/src/lib/helpers/tlds.ts b/src/lib/helpers/tlds.ts
index 6de3c38887..84fabf2c39 100644
--- a/src/lib/helpers/tlds.ts
+++ b/src/lib/helpers/tlds.ts
@@ -4,7 +4,7 @@ import { parse } from 'tldts';
* Returns the apex/root domain from a full domain string.
*/
export function getApexDomain(domain: string): string | null {
- return parse(domain).domain;
+ return parse(domain, { allowPrivateDomains: true }).domain;
}
/**
@@ -13,8 +13,17 @@ export function getApexDomain(domain: string): string | null {
export function isASubdomain(domain: string | null): boolean {
if (!domain) return false;
- const { domain: apex, subdomain } = parse(domain);
+ const { domain: apex, subdomain } = parse(domain, { allowPrivateDomains: true });
if (!apex) return false;
return !!subdomain;
}
+
+/**
+ * Returns the subdomain part from a full domain string.
+ */
+export function getSubdomain(domain: string): string {
+ if (!domain) return '';
+
+ return parse(domain, { allowPrivateDomains: true }).subdomain || '';
+}
diff --git a/src/routes/(console)/organization-[organization]/domains/domain-[domain]/+page.svelte b/src/routes/(console)/organization-[organization]/domains/domain-[domain]/+page.svelte
index d6ce25571b..b24836bad7 100644
--- a/src/routes/(console)/organization-[organization]/domains/domain-[domain]/+page.svelte
+++ b/src/routes/(console)/organization-[organization]/domains/domain-[domain]/+page.svelte
@@ -118,7 +118,7 @@
Navigate to your domain provider and update the nameservers to and .
- Note that DNS changes may take time to propagate fully.
+ Note that DNS changes may take up to 48 hours to propagate fully.
+ import { onMount } from 'svelte';
+ import { page } from '$app/state';
+ import { realtime } from '$lib/stores/sdk';
+ import { Dependencies } from '$lib/constants';
+ import { invalidate } from '$app/navigation';
+
+ onMount(() => {
+ return realtime
+ .forProject(page.params.region, page.params.project)
+ .subscribe('console', (response) => {
+ if (
+ response.events.includes('rules.*.update') ||
+ response.events.includes('rules.*.create') ||
+ response.events.includes('rules.*.delete')
+ ) {
+ if ((response.payload as any)?.deploymentResourceId === page.params.function) {
+ invalidate(Dependencies.FUNCTION_DOMAINS);
+ }
+ }
+ });
+ });
+
+
+
diff --git a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/+page.ts b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/+page.ts
index 4145bf8283..ef5bda9391 100644
--- a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/+page.ts
+++ b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/+page.ts
@@ -28,7 +28,7 @@ export const load: PageLoad = async ({ depends, params, url, route, parent }) =>
Query.equal('trigger', RuleTrigger.MANUAL),
Query.limit(limit),
Query.offset(offset),
- Query.orderDesc(''),
+ Query.orderDesc('$updatedAt'),
...parsedQueries.values()
],
search: search || undefined
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 f913e4c91a..4ae4fd15af 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,25 +48,20 @@
async function addDomain() {
const apexDomain = getApexDomain(domainName);
- let domain = data.domains?.domains.find((d: Models.Domain) => d.domain === apexDomain);
+ let domain: Models.Domain;
- if (apexDomain && !domain && isCloud) {
- try {
- domain = await sdk.forConsole.domains.create({
+ if (isCloud && apexDomain) {
+ sdk.forConsole.domains
+ .create({
teamId: $project.teamId,
domain: apexDomain
+ })
+ .then((createdDomain) => {
+ domain = createdDomain;
+ })
+ .catch(() => {
+ // Empty as domain creation error needs to be silent
});
- } catch (error) {
- // 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;
- }
- }
}
try {
@@ -100,10 +95,13 @@
if (rule?.status === 'verified') {
await goto(routeBase);
await invalidate(Dependencies.FUNCTION_DOMAINS);
+ if (isCloud && domain) {
+ sdk.forConsole.domains.updateNameservers({ domainId: domain.$id }).catch(() => {
+ // Empty as domain update error needs to be silent
+ });
+ }
} else {
- await goto(
- `${routeBase}/add-domain/verify-${domainName}?rule=${rule.$id}&domain=${domain.$id}`
- );
+ await goto(`${routeBase}/add-domain/verify-${domainName}?rule=${rule.$id}`);
await invalidate(Dependencies.FUNCTION_DOMAINS);
}
} catch (error) {
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 4db9c86d72..852d1fcd69 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
@@ -12,6 +12,7 @@
import { Button, Form } from '$lib/elements/forms';
import { sdk } from '$lib/stores/sdk';
import { organization } from '$lib/stores/organization';
+ import type { Models } from '@appwrite.io/console';
import { addNotification } from '$lib/stores/notifications';
import { goto, invalidate } from '$app/navigation';
import { Dependencies } from '$lib/constants';
@@ -20,7 +21,7 @@
import Wizard from '$lib/layout/wizard.svelte';
import { base } from '$app/paths';
import { writable } from 'svelte/store';
- import { isASubdomain } from '$lib/helpers/tlds';
+ import { getApexDomain } from '$lib/helpers/tlds';
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';
@@ -28,12 +29,10 @@
let { data } = $props();
const ruleId = page.url.searchParams.get('rule');
- const domainId = page.url.searchParams.get('domain');
- const isSubDomain = $derived.by(() => isASubdomain(page.params.domain));
let selectedTab = $state<'cname' | 'nameserver' | 'a' | 'aaaa'>('nameserver');
$effect(() => {
- if ($regionalConsoleVariables._APP_DOMAIN_TARGET_CNAME && isSubDomain) {
+ if ($regionalConsoleVariables._APP_DOMAIN_FUNCTIONS) {
selectedTab = 'cname';
} else if (!isCloud && $regionalConsoleVariables._APP_DOMAIN_TARGET_A) {
selectedTab = 'a';
@@ -49,28 +48,53 @@
let isSubmitting = $state(writable(false));
async function verify() {
- const isNewDomain =
- data.domainsList.domains.find((rule) => rule.domain === page.params.domain) ===
- undefined;
try {
- if (selectedTab !== 'nameserver') {
- const ruleData = await sdk
- .forProject(page.params.region, page.params.project)
- .proxy.updateRuleVerification({ ruleId });
- verified = ruleData.status === 'verified';
- } else if (isNewDomain && isCloud) {
- const domainData = await sdk.forConsole.domains.create({
- teamId: $organization.$id,
- domain: page.params.domain
- });
- verified = domainData.nameservers.toLowerCase() === 'appwrite';
- } else if (!isNewDomain && isCloud) {
- const domain = await sdk.forConsole.domains.updateNameservers({ domainId });
- verified = domain.nameservers.toLowerCase() === 'appwrite';
- if (!verified)
- throw new Error(
- 'Domain verification failed. Please check your domain settings or try again later'
+ if (isCloud) {
+ const apexDomain = getApexDomain(data.proxyRule.domain);
+ if (apexDomain) {
+ sdk.forConsole.domains
+ .create({
+ teamId: $organization.$id,
+ domain: apexDomain
+ })
+ .then((domainData) => {
+ if (domainData.nameservers.toLowerCase() === 'appwrite') {
+ verified = true;
+ }
+ })
+ .catch(() => {
+ // Empty as domain creation error needs to be silent
+ });
+
+ const domain = data.domainsList.domains.find(
+ (d: Models.Domain) => d.domain === apexDomain
);
+ if (domain) {
+ sdk.forConsole.domains
+ .updateNameservers({
+ domainId: domain.$id
+ })
+ .then((output) => {
+ if (output.nameservers.toLowerCase() === 'appwrite') {
+ verified = true;
+ }
+ })
+ .catch(() => {
+ // Empty as domain update error needs to be silent
+ });
+ }
+ }
+ }
+
+ const ruleData = await sdk
+ .forProject(page.params.region, page.params.project)
+ .proxy.updateRuleVerification({ ruleId });
+
+ verified = ruleData.status === 'verified';
+ if (!verified) {
+ throw new Error(
+ 'Domain verification failed. Please check your domain settings or try again later'
+ );
}
addNotification({
@@ -96,7 +120,7 @@
.forProject(page.params.region, page.params.project)
.proxy.deleteRule({ ruleId });
}
- await goto(`${routeBase}/add-domain?domain=${page.params.domain}`);
+ await goto(`${routeBase}/add-domain?domain=${data.proxyRule.domain}`);
}
@@ -113,7 +137,7 @@
- {page.params.domain}
+ {data.proxyRule.domain}
Change
@@ -124,7 +148,7 @@
- {#if isSubDomain && !!$regionalConsoleVariables._APP_DOMAIN_TARGET_CNAME && $regionalConsoleVariables._APP_DOMAIN_TARGET_CNAME !== 'localhost'}
+ {#if !!$regionalConsoleVariables._APP_DOMAIN_FUNCTIONS && $regionalConsoleVariables._APP_DOMAIN_FUNCTIONS !== 'localhost'}
(selectedTab = 'cname')}
@@ -160,9 +184,20 @@
{#if selectedTab === 'nameserver'}
-
+
{:else}
-
+ (selectedTab = 'nameserver')}
+ onNavigateToA={() => (selectedTab = 'a')}
+ onNavigateToAAAA={() => (selectedTab = 'aaaa')} />
{/if}
diff --git a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/add-domain/verify-[domain]/+page.ts b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/add-domain/verify-[domain]/+page.ts
index b89c933306..4345a9f741 100644
--- a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/add-domain/verify-[domain]/+page.ts
+++ b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/add-domain/verify-[domain]/+page.ts
@@ -3,9 +3,14 @@ import { isCloud } from '$lib/system';
import { Dependencies } from '$lib/constants.js';
import { type Models, Query } from '@appwrite.io/console';
-export const load = async ({ depends, parent }) => {
- const { organization } = await parent();
- depends(Dependencies.DOMAINS);
+export const load = async ({ params, parent, depends, url }) => {
+ const { function: func, organization } = await parent();
+ depends(Dependencies.FUNCTION_DOMAINS);
+
+ const ruleId = url.searchParams.get('rule');
+ if (!ruleId) {
+ throw new Error('Rule ID is required');
+ }
let domainsList: Models.DomainsList;
if (isCloud) {
@@ -14,7 +19,11 @@ export const load = async ({ depends, parent }) => {
});
}
+ const proxyRule = await sdk.forProject(params.region, params.project).proxy.getRule({ ruleId });
+
return {
- domainsList
+ function: func,
+ domainsList,
+ proxyRule
};
};
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 8ccd491e2b..d59bce63eb 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
@@ -6,9 +6,13 @@
import { invalidate } from '$app/navigation';
import { Submit, trackEvent, trackError } from '$lib/actions/analytics';
import { Dependencies } from '$lib/constants';
- import RecordsCard from './recordsCard.svelte';
import type { Models } from '@appwrite.io/console';
+ import { Divider, Tabs } from '@appwrite.io/pink-svelte';
+ import { isCloud } from '$lib/system';
import { page } from '$app/state';
+ 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';
let {
show = $bindable(false),
@@ -18,35 +22,117 @@
selectedProxyRule: Models.ProxyRule;
} = $props();
+ let selectedTab = $state<'cname' | 'nameserver' | 'a' | 'aaaa'>('nameserver');
+
+ $effect(() => {
+ if ($regionalConsoleVariables._APP_DOMAIN_FUNCTIONS) {
+ selectedTab = 'cname';
+ } else if (!isCloud && $regionalConsoleVariables._APP_DOMAIN_TARGET_A) {
+ selectedTab = 'a';
+ } else if (!isCloud && $regionalConsoleVariables._APP_DOMAIN_TARGET_AAAA) {
+ selectedTab = 'aaaa';
+ } else {
+ selectedTab = 'nameserver';
+ }
+ });
+
+ let verified = $state(false);
+ let retryError = $state(null);
let error = $state(null);
+
+ $effect(() => {
+ error = retryError || selectedProxyRule?.verificationLogs || null;
+ });
+
async function retryProxyRule() {
try {
- await sdk
+ retryError = null;
+ const domain = await sdk
.forProject(page.params.region, page.params.project)
.proxy.updateRuleVerification({ ruleId: selectedProxyRule.$id });
+
+ verified = domain.status === 'verified';
await invalidate(Dependencies.FUNCTION_DOMAINS);
- show = false;
- addNotification({
- type: 'success',
- message: `${selectedProxyRule.domain} has been verified`
- });
+
+ if (verified) {
+ show = false;
+ addNotification({
+ type: 'success',
+ message: `${selectedProxyRule.domain} has been verified`
+ });
+ } else {
+ retryError =
+ 'Domain verification failed. Please check your domain settings or try again later';
+ }
trackEvent(Submit.DomainUpdateVerification);
} catch (e) {
- error = e.message;
+ retryError =
+ e.message ??
+ 'Domain verification failed. Please check your domain settings or try again later';
trackError(e, Submit.DomainUpdateVerification);
}
}
$effect(() => {
if (!show) {
- error = null;
+ retryError = null;
}
});
- {#if selectedProxyRule}
-
+
+
+ {#if !!$regionalConsoleVariables._APP_DOMAIN_FUNCTIONS && $regionalConsoleVariables._APP_DOMAIN_FUNCTIONS !== 'localhost'}
+ (selectedTab = 'cname')}
+ active={selectedTab === 'cname'}>
+ CNAME
+
+ {/if}
+ {#if isCloud}
+ (selectedTab = 'nameserver')}
+ active={selectedTab === 'nameserver'}>
+ Nameservers
+
+ {/if}
+ {#if !isCloud && !!$regionalConsoleVariables._APP_DOMAIN_TARGET_A && $regionalConsoleVariables._APP_DOMAIN_TARGET_A !== '127.0.0.1'}
+ (selectedTab = 'a')}
+ active={selectedTab === 'a'}>
+ A
+
+ {/if}
+ {#if !isCloud && !!$regionalConsoleVariables._APP_DOMAIN_TARGET_AAAA && $regionalConsoleVariables._APP_DOMAIN_TARGET_AAAA !== '::1'}
+ (selectedTab = 'aaaa')}
+ active={selectedTab === 'aaaa'}>
+ AAAA
+
+ {/if}
+
+
+
+ {#if selectedTab === 'nameserver'}
+
+ {:else}
+ (selectedTab = 'nameserver')}
+ onNavigateToA={() => (selectedTab = 'a')}
+ onNavigateToAAAA={() => (selectedTab = 'aaaa')} />
{/if}
diff --git a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/store.ts b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/store.ts
index 902fb3e3e8..5f36c6bc17 100644
--- a/src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/store.ts
+++ b/src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/store.ts
@@ -7,7 +7,7 @@ export const columns = writable([
title: 'Domain',
type: 'string',
format: 'string',
- width: { min: 200 }
+ width: { min: 300 }
},
{
@@ -15,5 +15,12 @@ export const columns = writable([
title: 'Target',
type: 'string',
width: { min: 120, max: 400 }
+ },
+
+ {
+ id: 'updated',
+ title: '',
+ type: 'string',
+ width: { min: 160, max: 180 }
}
]);
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 80f8663d44..c1ca0d71f4 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
@@ -3,10 +3,16 @@
import { Link } from '$lib/elements';
import { Button } from '$lib/elements/forms';
import type { Models } from '@appwrite.io/console';
- import { IconDotsHorizontal, IconRefresh, IconTrash } from '@appwrite.io/pink-icons-svelte';
+ import {
+ IconDotsHorizontal,
+ IconRefresh,
+ IconTerminal,
+ IconTrash
+ } from '@appwrite.io/pink-icons-svelte';
import {
ActionMenu,
Badge,
+ Divider,
Icon,
Layout,
Popover,
@@ -15,9 +21,11 @@
} from '@appwrite.io/pink-svelte';
import DeleteDomainModal from './deleteDomainModal.svelte';
import RetryDomainModal from './retryDomainModal.svelte';
+ import { ViewLogsModal } from '$lib/components';
import { columns } from './store';
import { regionalProtocol } from '$routes/(console)/project-[region]-[project]/store';
- import DnsRecordsAction from '$lib/components/domains/dnsRecordsAction.svelte';
+ import { DnsRecordsAction } from '$lib/components';
+ import { timeFromNowShort } from '$lib/helpers/date';
let {
proxyRules,
@@ -29,6 +37,7 @@
let showDelete = $state(false);
let showRetry = $state(false);
+ let showLogs = $state(false);
let selectedProxyRule: Models.ProxyRule = $state(null);
const proxyTarget = (proxy: Models.ProxyRule) => {
@@ -49,7 +58,7 @@
{/each}
- {#each proxyRules.rules as proxyRule}
+ {#each proxyRules.rules as proxyRule (proxyRule.$id)}
{#each $columns as column}
@@ -57,24 +66,90 @@
{proxyRule.domain}
- {#if proxyRule.status === 'verifying'}
-
- {:else if proxyRule.status !== 'verified'}
-
+ {#if proxyRule.status === 'created'}
+
+
+ {
+ e.preventDefault();
+ selectedProxyRule = proxyRule;
+ showRetry = true;
+ }}>
+ Retry
+
+
+ {:else if proxyRule.status === 'verifying'}
+
+
+ {#if proxyRule.logs && proxyRule.logs.length > 0}
+ {
+ e.preventDefault();
+ selectedProxyRule = proxyRule;
+ showLogs = true;
+ }}>
+ View logs
+
+ {/if}
+
+ {:else if proxyRule.status === 'unverified'}
+
+
+ {#if proxyRule.logs && proxyRule.logs.length > 0}
+ {
+ e.preventDefault();
+ selectedProxyRule = proxyRule;
+ showLogs = true;
+ }}>
+ View logs
+
+ {/if}
+
{/if}
{:else if column.id === 'target'}
{proxyTarget(proxyRule)}
+ {:else if column.id === 'updated'}
+
+ {#if proxyRule.status !== 'verified'}
+
+ {#if proxyRule.status === 'created'}
+ Checked {timeFromNowShort(proxyRule.$updatedAt)}
+ {:else if proxyRule.status === 'verifying'}
+ Updated {timeFromNowShort(proxyRule.$updatedAt)}
+ {:else if proxyRule.status === 'unverified'}
+ Failed {timeFromNowShort(proxyRule.$updatedAt)}
+ {/if}
+
+ {/if}
+
{/if}
{/each}
@@ -93,6 +168,17 @@
+ {#if proxyRule.logs && proxyRule.logs.length > 0}
+ {
+ selectedProxyRule = proxyRule;
+ showLogs = true;
+ toggle(e);
+ }}>
+ View logs
+
+ {/if}
{#if proxyRule.status !== 'verified' && proxyRule.status !== 'verifying'}
{/if}
+ {#if proxyRule.logs && proxyRule.logs.length > 0}
+
+ {/if}
{/if}
+
+{#if showLogs}
+
+{/if}
+
+
diff --git a/src/routes/(console)/project-[region]-[project]/settings/domains/add-domain/+page.svelte b/src/routes/(console)/project-[region]-[project]/settings/domains/add-domain/+page.svelte
index 90d5a21595..634f74a224 100644
--- a/src/routes/(console)/project-[region]-[project]/settings/domains/add-domain/+page.svelte
+++ b/src/routes/(console)/project-[region]-[project]/settings/domains/add-domain/+page.svelte
@@ -16,8 +16,6 @@
const routeBase = `${base}/project-${page.params.region}-${page.params.project}/settings/domains`;
- let { data } = $props();
-
let formComponent: Form;
let isSubmitting = $state(writable(false));
let domainName = $state('');
@@ -30,25 +28,20 @@
async function addDomain() {
const apexDomain = getApexDomain(domainName);
- let domain = data.domains?.domains.find((d: Models.Domain) => d.domain === apexDomain);
+ let domain: Models.Domain;
- if (apexDomain && !domain && isCloud) {
- try {
- domain = await sdk.forConsole.domains.create({
+ if (isCloud && apexDomain) {
+ sdk.forConsole.domains
+ .create({
teamId: $project.teamId,
domain: apexDomain
+ })
+ .then((createdDomain) => {
+ domain = createdDomain;
+ })
+ .catch(() => {
+ // Empty as domain creation error needs to be silent
});
- } catch (error) {
- // 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;
- }
- }
}
try {
@@ -58,18 +51,13 @@
if (rule?.status === 'verified') {
await goto(routeBase);
await invalidate(Dependencies.DOMAINS);
- } else {
- let redirect = `${routeBase}/add-domain/verify-${domainName}?rule=${rule.$id}`;
-
- if (isCloud) {
- /**
- * Domains are only on cloud!
- * Self-hosted instances have rules.
- */
- redirect += `&domain=${domain.$id}`;
+ if (isCloud && domain) {
+ sdk.forConsole.domains.updateNameservers({ domainId: domain.$id }).catch(() => {
+ // Empty as domain update error needs to be silent
+ });
}
-
- await goto(redirect);
+ } else {
+ await goto(`${routeBase}/add-domain/verify-${domainName}?rule=${rule.$id}`);
await invalidate(Dependencies.DOMAINS);
}
} catch (error) {
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 a6c23790f5..3695f3a4de 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
@@ -12,6 +12,7 @@
import { Button, Form } from '$lib/elements/forms';
import { sdk } from '$lib/stores/sdk';
import { organization } from '$lib/stores/organization';
+ import type { Models } from '@appwrite.io/console';
import { addNotification } from '$lib/stores/notifications';
import { goto, invalidate } from '$app/navigation';
import { Dependencies } from '$lib/constants';
@@ -20,7 +21,7 @@
import Wizard from '$lib/layout/wizard.svelte';
import { base } from '$app/paths';
import { writable } from 'svelte/store';
- import { isASubdomain } from '$lib/helpers/tlds';
+ import { getApexDomain } from '$lib/helpers/tlds';
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';
@@ -28,13 +29,11 @@
let { data } = $props();
const ruleId = page.url.searchParams.get('rule');
- const domainId = page.url.searchParams.get('domain');
- const isSubDomain = $derived.by(() => isASubdomain(page.params.domain));
let selectedTab = $state<'cname' | 'nameserver' | 'a' | 'aaaa'>('nameserver');
$effect(() => {
- if ($regionalConsoleVariables._APP_DOMAIN_TARGET_CNAME && isSubDomain) {
+ if ($regionalConsoleVariables._APP_DOMAIN_TARGET_CNAME) {
selectedTab = 'cname';
} else if (!isCloud && $regionalConsoleVariables._APP_DOMAIN_TARGET_A) {
selectedTab = 'a';
@@ -50,30 +49,54 @@
const isSubmitting = writable(false);
async function verify() {
- const isNewDomain =
- data.domainsList.domains.find((rule) => rule.domain === page.params.domain) ===
- undefined;
try {
- if (selectedTab !== 'nameserver') {
- const ruleData = await sdk
- .forProject(page.params.region, page.params.project)
- .proxy.updateRuleVerification({ ruleId });
- verified = ruleData.status === 'verified';
- } else if (isNewDomain && isCloud) {
- const domainData = await sdk.forConsole.domains.create({
- teamId: $organization.$id,
- domain: page.params.domain
- });
- verified = domainData.nameservers.toLowerCase() === 'appwrite';
- } else if (!isNewDomain && isCloud) {
- const domain = await sdk.forConsole.domains.updateNameservers({
- domainId
- });
- verified = domain.nameservers.toLowerCase() === 'appwrite';
- if (!verified)
- throw new Error(
- 'Domain verification failed. Please check your domain settings or try again later'
+ if (isCloud) {
+ const apexDomain = getApexDomain(data.proxyRule.domain);
+ console.log('apexDomain', apexDomain);
+ if (apexDomain) {
+ sdk.forConsole.domains
+ .create({
+ teamId: $organization.$id,
+ domain: apexDomain
+ })
+ .then((domainData) => {
+ if (domainData.nameservers.toLowerCase() === 'appwrite') {
+ verified = true;
+ }
+ })
+ .catch(() => {
+ // Empty as domain creation error needs to be silent
+ });
+
+ const domain = data.domainsList.domains.find(
+ (d: Models.Domain) => d.domain === apexDomain
);
+ if (domain) {
+ sdk.forConsole.domains
+ .updateNameservers({
+ domainId: domain.$id
+ })
+ .then((output) => {
+ if (output.nameservers.toLowerCase() === 'appwrite') {
+ verified = true;
+ }
+ })
+ .catch(() => {
+ // Empty as domain update error needs to be silent
+ });
+ }
+ }
+ }
+
+ const ruleData = await sdk
+ .forProject(page.params.region, page.params.project)
+ .proxy.updateRuleVerification({ ruleId });
+
+ verified = ruleData.status === 'verified';
+ if (!verified) {
+ throw new Error(
+ 'Domain verification failed. Please check your domain settings or try again later'
+ );
}
addNotification({
@@ -98,7 +121,7 @@
.forProject(page.params.region, page.params.project)
.proxy.deleteRule({ ruleId });
}
- await goto(`${routeBase}/add-domain?domain=${page.params.domain}`);
+ await goto(`${routeBase}/add-domain?domain=${data.proxyRule.domain}`);
}
@@ -115,7 +138,7 @@
- {page.params.domain}
+ {data.proxyRule.domain}
Change
@@ -126,7 +149,7 @@
- {#if isSubDomain && !!$regionalConsoleVariables._APP_DOMAIN_TARGET_CNAME && $regionalConsoleVariables._APP_DOMAIN_TARGET_CNAME !== 'localhost'}
+ {#if !!$regionalConsoleVariables._APP_DOMAIN_TARGET_CNAME && $regionalConsoleVariables._APP_DOMAIN_TARGET_CNAME !== 'localhost'}
(selectedTab = 'cname')}
@@ -162,9 +185,19 @@
{#if selectedTab === 'nameserver'}
-
+
{:else}
-
+ (selectedTab = 'nameserver')}
+ onNavigateToA={() => (selectedTab = 'a')}
+ onNavigateToAAAA={() => (selectedTab = 'aaaa')} />
{/if}
diff --git a/src/routes/(console)/project-[region]-[project]/settings/domains/add-domain/verify-[domain]/+page.ts b/src/routes/(console)/project-[region]-[project]/settings/domains/add-domain/verify-[domain]/+page.ts
index b89c933306..a5c8d1ad14 100644
--- a/src/routes/(console)/project-[region]-[project]/settings/domains/add-domain/verify-[domain]/+page.ts
+++ b/src/routes/(console)/project-[region]-[project]/settings/domains/add-domain/verify-[domain]/+page.ts
@@ -3,10 +3,15 @@ import { isCloud } from '$lib/system';
import { Dependencies } from '$lib/constants.js';
import { type Models, Query } from '@appwrite.io/console';
-export const load = async ({ depends, parent }) => {
- const { organization } = await parent();
+export const load = async ({ params, parent, depends, url }) => {
+ const { project, organization } = await parent();
depends(Dependencies.DOMAINS);
+ const ruleId = url.searchParams.get('rule');
+ if (!ruleId) {
+ throw new Error('Rule ID is required');
+ }
+
let domainsList: Models.DomainsList;
if (isCloud) {
domainsList = await sdk.forConsole.domains.list({
@@ -14,7 +19,11 @@ export const load = async ({ depends, parent }) => {
});
}
+ const proxyRule = await sdk.forProject(params.region, params.project).proxy.getRule({ ruleId });
+
return {
- domainsList
+ project,
+ domainsList,
+ proxyRule
};
};
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 844a2c94be..772fef3827 100644
--- a/src/routes/(console)/project-[region]-[project]/settings/domains/retryDomainModal.svelte
+++ b/src/routes/(console)/project-[region]-[project]/settings/domains/retryDomainModal.svelte
@@ -7,8 +7,12 @@
import { Submit, trackEvent, trackError } from '$lib/actions/analytics';
import { Dependencies } from '$lib/constants';
import type { Models } from '@appwrite.io/console';
- import CnameTable from '$lib/components/domains/cnameTable.svelte';
+ import { Divider, Tabs } from '@appwrite.io/pink-svelte';
+ import { isCloud } from '$lib/system';
import { page } from '$app/state';
+ 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';
let {
show = $bindable(),
@@ -18,37 +22,117 @@
selectedDomain: Models.ProxyRule;
} = $props();
+ let selectedTab = $state<'cname' | 'nameserver' | 'a' | 'aaaa'>('nameserver');
+
+ $effect(() => {
+ if ($regionalConsoleVariables._APP_DOMAIN_TARGET_CNAME) {
+ selectedTab = 'cname';
+ } else if (!isCloud && $regionalConsoleVariables._APP_DOMAIN_TARGET_A) {
+ selectedTab = 'a';
+ } else if (!isCloud && $regionalConsoleVariables._APP_DOMAIN_TARGET_AAAA) {
+ selectedTab = 'aaaa';
+ } else {
+ selectedTab = 'nameserver';
+ }
+ });
+
+ let verified = $state(false);
+ let retryError = $state(null);
let error = $state(null);
+
+ $effect(() => {
+ error = retryError || selectedDomain?.verificationLogs || null;
+ });
+
async function retryDomain() {
try {
- await sdk
+ retryError = null;
+ const domain = await sdk
.forProject(page.params.region, page.params.project)
.proxy.updateRuleVerification({ ruleId: selectedDomain.$id });
+
+ verified = domain.status === 'verified';
await invalidate(Dependencies.DOMAINS);
- show = false;
- addNotification({
- type: 'success',
- message: `${selectedDomain.domain} has been verified`
- });
+
+ if (verified) {
+ show = false;
+ addNotification({
+ type: 'success',
+ message: `${selectedDomain.domain} has been verified`
+ });
+ } else {
+ retryError =
+ 'Domain verification failed. Please check your domain settings or try again later';
+ }
trackEvent(Submit.DomainUpdateVerification);
} catch (e) {
- error = e.message;
+ retryError =
+ e.message ??
+ 'Domain verification failed. Please check your domain settings or try again later';
trackError(e, Submit.DomainUpdateVerification);
}
}
$effect(() => {
if (!show) {
- error = null;
+ retryError = null;
}
});
- {#if selectedDomain}
-
+
+ {#if !!$regionalConsoleVariables._APP_DOMAIN_TARGET_CNAME && $regionalConsoleVariables._APP_DOMAIN_TARGET_CNAME !== 'localhost'}
+ (selectedTab = 'cname')}
+ active={selectedTab === 'cname'}>
+ CNAME
+
+ {/if}
+ {#if isCloud}
+ (selectedTab = 'nameserver')}
+ active={selectedTab === 'nameserver'}>
+ Nameservers
+
+ {/if}
+ {#if !isCloud && !!$regionalConsoleVariables._APP_DOMAIN_TARGET_A && $regionalConsoleVariables._APP_DOMAIN_TARGET_A !== '127.0.0.1'}
+ (selectedTab = 'a')}
+ active={selectedTab === 'a'}>
+ A
+
+ {/if}
+ {#if !isCloud && !!$regionalConsoleVariables._APP_DOMAIN_TARGET_AAAA && $regionalConsoleVariables._APP_DOMAIN_TARGET_AAAA !== '::1'}
+ (selectedTab = 'aaaa')}
+ active={selectedTab === 'aaaa'}>
+ AAAA
+
+ {/if}
+
+
+
+ {#if selectedTab === 'nameserver'}
+
+ {:else}
+
+ ruleStatus={selectedDomain.status}
+ onNavigateToNameservers={() => (selectedTab = 'nameserver')}
+ onNavigateToA={() => (selectedTab = 'a')}
+ onNavigateToAAAA={() => (selectedTab = 'aaaa')} />
{/if}
diff --git a/src/routes/(console)/project-[region]-[project]/settings/domains/table.svelte b/src/routes/(console)/project-[region]-[project]/settings/domains/table.svelte
index e28db33a94..4471fcbeb8 100644
--- a/src/routes/(console)/project-[region]-[project]/settings/domains/table.svelte
+++ b/src/routes/(console)/project-[region]-[project]/settings/domains/table.svelte
@@ -3,10 +3,16 @@
import { Link } from '$lib/elements';
import { Button } from '$lib/elements/forms';
import type { Models } from '@appwrite.io/console';
- import { IconDotsHorizontal, IconRefresh, IconTrash } from '@appwrite.io/pink-icons-svelte';
+ import {
+ IconDotsHorizontal,
+ IconRefresh,
+ IconTerminal,
+ IconTrash
+ } from '@appwrite.io/pink-icons-svelte';
import {
ActionMenu,
Badge,
+ Divider,
Icon,
Layout,
Popover,
@@ -15,8 +21,10 @@
} from '@appwrite.io/pink-svelte';
import DeleteDomainModal from './deleteDomainModal.svelte';
import RetryDomainModal from './retryDomainModal.svelte';
+ import { ViewLogsModal } from '$lib/components';
import { regionalProtocol } from '../../store';
- import DnsRecordsAction from '$lib/components/domains/dnsRecordsAction.svelte';
+ import { DnsRecordsAction } from '$lib/components';
+ import { timeFromNowShort } from '$lib/helpers/date';
let {
domains,
@@ -28,6 +36,7 @@
let showDelete = $state(false);
let showRetry = $state(false);
+ let showLogs = $state(false);
let selectedDomain: Models.ProxyRule = $state(null);
const columns = [
@@ -36,7 +45,13 @@
title: 'Domain',
type: 'string',
format: 'string',
- width: { min: 200, max: 550 }
+ width: { min: 300, max: 550 }
+ },
+ {
+ id: 'updated',
+ title: '',
+ type: 'string',
+ width: { min: 160, max: 180 }
}
];
@@ -58,20 +73,86 @@
{domain.domain}
- {#if domain.status === 'verifying'}
-
- {:else if domain.status !== 'verified'}
-
+ {#if domain.status === 'created'}
+
+
+ {
+ e.preventDefault();
+ selectedDomain = domain;
+ showRetry = true;
+ }}>
+ Retry
+
+
+ {:else if domain.status === 'verifying'}
+
+
+ {#if domain.logs && domain.logs.length > 0}
+ {
+ e.preventDefault();
+ selectedDomain = domain;
+ showLogs = true;
+ }}>
+ View logs
+
+ {/if}
+
+ {:else if domain.status === 'unverified'}
+
+
+ {#if domain.logs && domain.logs.length > 0}
+ {
+ e.preventDefault();
+ selectedDomain = domain;
+ showLogs = true;
+ }}>
+ View logs
+
+ {/if}
+
+ {/if}
+
+ {:else if column.id === 'updated'}
+
+ {#if domain.status !== 'verified'}
+
+ {#if domain.status === 'created'}
+ Checked {timeFromNowShort(domain.$updatedAt)}
+ {:else if domain.status === 'verifying'}
+ Updated {timeFromNowShort(domain.$updatedAt)}
+ {:else if domain.status === 'unverified'}
+ Failed {timeFromNowShort(domain.$updatedAt)}
+ {/if}
+
{/if}
{/if}
@@ -92,6 +173,17 @@
+ {#if domain.logs && domain.logs.length > 0}
+ {
+ selectedDomain = domain;
+ showLogs = true;
+ toggle(e);
+ }}>
+ View logs
+
+ {/if}
{#if domain.status !== 'verified' && domain.status !== 'verifying'}
{/if}
+ {#if domain.logs && domain.logs.length > 0}
+
+ {/if}
{/if}
+
+{#if showLogs}
+
+{/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 f0b6df34a3..07430eb9d8 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
@@ -57,27 +57,21 @@
async function addDomain() {
const apexDomain = getApexDomain(domainName);
- let domain = data.domains?.domains.find((d: Models.Domain) => d.domain === apexDomain);
-
+ let domain: Models.Domain;
const isSiteDomain = domainName.endsWith($regionalConsoleVariables._APP_DOMAIN_SITES);
- if (isCloud && apexDomain && !domain && !isSiteDomain) {
- try {
- domain = await sdk.forConsole.domains.create({
+ if (isCloud && apexDomain && !isSiteDomain) {
+ sdk.forConsole.domains
+ .create({
teamId: $project.teamId,
domain: apexDomain
+ })
+ .then((createdDomain) => {
+ domain = createdDomain;
+ })
+ .catch(() => {
+ // Empty as domain creation error needs to be silent
});
- } catch (error) {
- // 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;
- }
- }
}
try {
@@ -111,6 +105,11 @@
if (rule?.status === 'verified') {
await goto(routeBase);
await invalidate(Dependencies.SITES_DOMAINS);
+ if (isCloud && domain) {
+ sdk.forConsole.domains.updateNameservers({ domainId: domain.$id }).catch(() => {
+ // Empty as domain update error needs to be silent
+ });
+ }
} else {
await goto(`${routeBase}/add-domain/verify-${domainName}?rule=${rule.$id}`);
await invalidate(Dependencies.SITES_DOMAINS);
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 8422d783a0..dad247b10f 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
@@ -12,6 +12,7 @@
import { Button, Form } from '$lib/elements/forms';
import { sdk } from '$lib/stores/sdk';
import { organization } from '$lib/stores/organization';
+ import type { Models } from '@appwrite.io/console';
import { addNotification } from '$lib/stores/notifications';
import { goto, invalidate } from '$app/navigation';
import { Dependencies } from '$lib/constants';
@@ -20,7 +21,7 @@
import Wizard from '$lib/layout/wizard.svelte';
import { base } from '$app/paths';
import { writable } from 'svelte/store';
- import { isASubdomain } from '$lib/helpers/tlds';
+ import { getApexDomain } from '$lib/helpers/tlds';
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';
@@ -28,12 +29,11 @@
let { data } = $props();
const ruleId = page.url.searchParams.get('rule');
- const isSubDomain = $derived.by(() => isASubdomain(page.params.domain));
let selectedTab = $state<'cname' | 'nameserver' | 'a' | 'aaaa'>('nameserver');
$effect(() => {
- if ($regionalConsoleVariables._APP_DOMAIN_TARGET_CNAME && isSubDomain) {
+ if ($regionalConsoleVariables._APP_DOMAIN_SITES) {
selectedTab = 'cname';
} else if (!isCloud && $regionalConsoleVariables._APP_DOMAIN_TARGET_A) {
selectedTab = 'a';
@@ -50,23 +50,50 @@
let isSubmitting = $state(writable(false));
async function verify() {
- const isNewDomain =
- data.domainsList.domains.findIndex((rule) => rule.domain === page.params.domain) === -1;
try {
- if (selectedTab !== 'nameserver') {
- const ruleData = await sdk
- .forProject(page.params.region, page.params.project)
- .proxy.updateRuleVerification({ ruleId });
- verified = ruleData.status === 'verified';
- 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: page.params.domain
- });
- verified = domainData.nameservers.toLowerCase() === 'appwrite';
+ if (isCloud) {
+ const apexDomain = getApexDomain(data.proxyRule.domain);
+ if (apexDomain) {
+ sdk.forConsole.domains
+ .create({
+ teamId: $organization.$id,
+ domain: apexDomain
+ })
+ .then((domainData) => {
+ if (domainData.nameservers.toLowerCase() === 'appwrite') {
+ verified = true;
+ }
+ })
+ .catch(() => {
+ // Empty as domain creation error needs to be silent
+ });
+
+ const domain = data.domainsList.domains.find(
+ (d: Models.Domain) => d.domain === apexDomain
+ );
+ if (domain) {
+ sdk.forConsole.domains
+ .updateNameservers({
+ domainId: domain.$id
+ })
+ .then((output) => {
+ if (output.nameservers.toLowerCase() === 'appwrite') {
+ verified = true;
+ }
+ })
+ .catch(() => {
+ // Empty as domain update error needs to be silent
+ });
+ }
+ }
+ }
+
+ const ruleData = await sdk
+ .forProject(page.params.region, page.params.project)
+ .proxy.updateRuleVerification({ ruleId });
+
+ verified = ruleData.status === 'verified';
+ if (!verified) {
throw new Error(
'Domain verification failed. Please check your domain settings or try again later'
);
@@ -95,7 +122,7 @@
.forProject(page.params.region, page.params.project)
.proxy.deleteRule({ ruleId });
}
- await goto(`${routeBase}/add-domain?domain=${page.params.domain}`);
+ await goto(`${routeBase}/add-domain?domain=${data.proxyRule.domain}`);
}
@@ -112,7 +139,7 @@
- {page.params.domain}
+ {data.proxyRule.domain}
Change
@@ -123,7 +150,7 @@
- {#if isSubDomain && !!$regionalConsoleVariables._APP_DOMAIN_TARGET_CNAME && $regionalConsoleVariables._APP_DOMAIN_TARGET_CNAME !== 'localhost'}
+ {#if !!$regionalConsoleVariables._APP_DOMAIN_SITES && $regionalConsoleVariables._APP_DOMAIN_SITES !== 'localhost'}
(selectedTab = 'cname')}
@@ -159,13 +186,20 @@
{#if selectedTab === 'nameserver'}
-
+
{:else}
+ domain={data.proxyRule.domain}
+ ruleStatus={data.proxyRule.status}
+ onNavigateToNameservers={() => (selectedTab = 'nameserver')}
+ onNavigateToA={() => (selectedTab = 'a')}
+ onNavigateToAAAA={() => (selectedTab = 'aaaa')} />
{/if}
diff --git a/src/routes/(console)/project-[region]-[project]/sites/site-[site]/domains/add-domain/verify-[domain]/+page.ts b/src/routes/(console)/project-[region]-[project]/sites/site-[site]/domains/add-domain/verify-[domain]/+page.ts
index 570e1b27a2..d16a243637 100644
--- a/src/routes/(console)/project-[region]-[project]/sites/site-[site]/domains/add-domain/verify-[domain]/+page.ts
+++ b/src/routes/(console)/project-[region]-[project]/sites/site-[site]/domains/add-domain/verify-[domain]/+page.ts
@@ -3,10 +3,15 @@ import { isCloud } from '$lib/system';
import { Dependencies } from '$lib/constants.js';
import { type Models, Query } from '@appwrite.io/console';
-export const load = async ({ parent, depends }) => {
+export const load = async ({ params, parent, depends, url }) => {
const { site, organization } = await parent();
depends(Dependencies.SITES_DOMAINS);
+ const ruleId = url.searchParams.get('rule');
+ if (!ruleId) {
+ throw new Error('Rule ID is required');
+ }
+
let domainsList: Models.DomainsList;
if (isCloud) {
domainsList = await sdk.forConsole.domains.list({
@@ -14,8 +19,11 @@ export const load = async ({ parent, depends }) => {
});
}
+ const proxyRule = await sdk.forProject(params.region, params.project).proxy.getRule({ ruleId });
+
return {
site,
- domainsList
+ domainsList,
+ proxyRule
};
};
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 949d8079c9..a148830f02 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
@@ -10,7 +10,6 @@
import { Divider, Tabs } from '@appwrite.io/pink-svelte';
import { isCloud } from '$lib/system';
import { page } from '$app/state';
- import { isASubdomain } from '$lib/helpers/tlds';
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';
@@ -23,12 +22,10 @@
selectedProxyRule: Models.ProxyRule;
} = $props();
- const isSubDomain = $derived.by(() => isASubdomain(selectedProxyRule?.domain));
-
let selectedTab = $state<'cname' | 'nameserver' | 'a' | 'aaaa'>('nameserver');
$effect(() => {
- if ($regionalConsoleVariables._APP_DOMAIN_TARGET_CNAME && isSubDomain) {
+ if ($regionalConsoleVariables._APP_DOMAIN_SITES) {
selectedTab = 'cname';
} else if (!isCloud && $regionalConsoleVariables._APP_DOMAIN_TARGET_A) {
selectedTab = 'a';
@@ -39,26 +36,37 @@
}
});
- let error = $state(null);
let verified = $state(false);
+ let retryError = $state(null);
+ let error = $state(null);
+
+ $effect(() => {
+ error = retryError || selectedProxyRule?.verificationLogs || null;
+ });
async function retryDomain() {
try {
+ retryError = null;
const domain = await sdk
.forProject(page.params.region, page.params.project)
.proxy.updateRuleVerification({ ruleId: selectedProxyRule.$id });
- show = false;
verified = domain.status === 'verified';
await invalidate(Dependencies.SITES_DOMAINS);
- addNotification({
- type: 'success',
- message: `${selectedProxyRule.domain} has been verified`
- });
+ if (verified) {
+ show = false;
+ addNotification({
+ type: 'success',
+ message: `${selectedProxyRule.domain} has been verified`
+ });
+ } else {
+ retryError =
+ 'Domain verification failed. Please check your domain settings or try again later';
+ }
trackEvent(Submit.DomainUpdateVerification);
} catch (e) {
- error =
+ retryError =
e.message ??
'Domain verification failed. Please check your domain settings or try again later';
trackError(e, Submit.DomainUpdateVerification);
@@ -67,7 +75,7 @@
$effect(() => {
if (!show) {
- error = null;
+ retryError = null;
}
});
@@ -75,7 +83,7 @@
- {#if isSubDomain && !!$regionalConsoleVariables._APP_DOMAIN_TARGET_CNAME && $regionalConsoleVariables._APP_DOMAIN_TARGET_CNAME !== 'localhost'}
+ {#if !!$regionalConsoleVariables._APP_DOMAIN_SITES && $regionalConsoleVariables._APP_DOMAIN_SITES !== 'localhost'}
(selectedTab = 'cname')}
@@ -111,13 +119,20 @@
{#if selectedTab === 'nameserver'}
-
+
{:else}
+ domain={selectedProxyRule.domain}
+ ruleStatus={selectedProxyRule.status}
+ onNavigateToNameservers={() => (selectedTab = 'nameserver')}
+ onNavigateToA={() => (selectedTab = 'a')}
+ onNavigateToAAAA={() => (selectedTab = 'aaaa')} />
{/if}
diff --git a/src/routes/(console)/project-[region]-[project]/sites/site-[site]/domains/store.ts b/src/routes/(console)/project-[region]-[project]/sites/site-[site]/domains/store.ts
index 902fb3e3e8..5f36c6bc17 100644
--- a/src/routes/(console)/project-[region]-[project]/sites/site-[site]/domains/store.ts
+++ b/src/routes/(console)/project-[region]-[project]/sites/site-[site]/domains/store.ts
@@ -7,7 +7,7 @@ export const columns = writable([
title: 'Domain',
type: 'string',
format: 'string',
- width: { min: 200 }
+ width: { min: 300 }
},
{
@@ -15,5 +15,12 @@ export const columns = writable([
title: 'Target',
type: 'string',
width: { min: 120, max: 400 }
+ },
+
+ {
+ id: 'updated',
+ title: '',
+ type: 'string',
+ width: { min: 160, max: 180 }
}
]);
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 b5b755480d..9c78f780eb 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
@@ -21,10 +21,11 @@
} from '@appwrite.io/pink-svelte';
import DeleteDomainModal from './deleteDomainModal.svelte';
import RetryDomainModal from './retryDomainModal.svelte';
- import ViewLogsModal from './viewLogsModal.svelte';
+ import { ViewLogsModal } from '$lib/components';
import { columns } from './store';
import { regionalProtocol } from '$routes/(console)/project-[region]-[project]/store';
- import DnsRecordsAction from '$lib/components/domains/dnsRecordsAction.svelte';
+ import { DnsRecordsAction } from '$lib/components';
+ import { timeFromNowShort } from '$lib/helpers/date';
let {
proxyRules,
@@ -65,25 +66,91 @@
{rule.domain}
- {#if rule.status === 'verifying'}
-
- {:else if rule.status !== 'verified'}
-
+ {#if rule.status === 'created'}
+
+
+ {
+ e.preventDefault();
+ selectedProxyRule = rule;
+ showRetry = true;
+ }}>
+ Retry
+
+
+ {:else if rule.status === 'verifying'}
+
+
+ {#if rule.logs && rule.logs.length > 0}
+ {
+ e.preventDefault();
+ selectedProxyRule = rule;
+ showLogs = true;
+ }}>
+ View logs
+
+ {/if}
+
+ {:else if rule.status === 'unverified'}
+
+
+ {#if rule.logs && rule.logs.length > 0}
+ {
+ e.preventDefault();
+ selectedProxyRule = rule;
+ showLogs = true;
+ }}>
+ View logs
+
+ {/if}
+
{/if}
{:else if column.id === 'target'}
{proxyTarget(rule)}
+ {:else if column.id === 'updated'}
+
+ {#if rule.status !== 'verified'}
+
+ {#if rule.status === 'created'}
+ Checked {timeFromNowShort(rule.$updatedAt)}
+ {:else if rule.status === 'verifying'}
+ Updated {timeFromNowShort(rule.$updatedAt)}
+ {:else if rule.status === 'unverified'}
+ Failed {timeFromNowShort(rule.$updatedAt)}
+ {/if}
+
+ {/if}
+
{/if}
{/each}
@@ -102,7 +169,7 @@
- {#if rule.logs && (rule.status === 'unverified' || rule.status === 'verifying')}
+ {#if rule.logs && rule.logs.length > 0}
{
@@ -125,7 +192,7 @@
{/if}
- {#if rule.logs && (rule.status === 'unverified' || rule.status === 'verifying')}
+ {#if rule.logs && rule.logs.length > 0}