Skip to content

Commit 0ba7a6b

Browse files
authored
Merge pull request #2704 from appwrite/ser-287
2 parents ba54f8d + 1a01859 commit 0ba7a6b

26 files changed

Lines changed: 855 additions & 305 deletions

File tree

src/lib/components/domains/recordTable.svelte

Lines changed: 103 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,56 @@
99
Alert
1010
} from '@appwrite.io/pink-svelte';
1111
import { regionalConsoleVariables } from '$routes/(console)/project-[region]-[project]/store';
12+
import { getSubdomain } from '$lib/helpers/tlds';
13+
import { isCloud } from '$lib/system';
1214
13-
export let domain: string;
14-
export let verified = undefined;
15-
export let variant: 'cname' | 'a' | 'aaaa';
16-
export let service: 'sites' | 'general' = 'general';
15+
let {
16+
domain,
17+
verified = undefined,
18+
variant,
19+
service = 'general',
20+
ruleStatus = undefined,
21+
onNavigateToNameservers = () => {},
22+
onNavigateToA = () => {},
23+
onNavigateToAAAA = () => {}
24+
}: {
25+
domain: string;
26+
verified?: boolean;
27+
variant: 'cname' | 'a' | 'aaaa';
28+
service?: 'sites' | 'functions' | 'general';
29+
ruleStatus?: 'created' | 'verifying' | 'unverified' | 'verified';
30+
onNavigateToNameservers?: () => void;
31+
onNavigateToA?: () => void;
32+
onNavigateToAAAA?: () => void;
33+
} = $props();
1734
18-
let subdomain = domain?.split('.')?.slice(0, -2)?.join('.');
35+
const subdomain = $derived(getSubdomain(domain));
36+
const caaText = $derived(
37+
$regionalConsoleVariables._APP_DOMAIN_TARGET_CAA?.includes(' ')
38+
? $regionalConsoleVariables._APP_DOMAIN_TARGET_CAA
39+
: `0 issue "${$regionalConsoleVariables._APP_DOMAIN_TARGET_CAA}"`
40+
);
41+
const aTabVisible = $derived(
42+
!isCloud &&
43+
Boolean($regionalConsoleVariables._APP_DOMAIN_TARGET_A) &&
44+
$regionalConsoleVariables._APP_DOMAIN_TARGET_A !== '127.0.0.1'
45+
);
46+
const aaaaTabVisible = $derived(
47+
!isCloud &&
48+
Boolean($regionalConsoleVariables._APP_DOMAIN_TARGET_AAAA) &&
49+
$regionalConsoleVariables._APP_DOMAIN_TARGET_AAAA !== '::1'
50+
);
1951
2052
function setTarget() {
2153
switch (variant) {
2254
case 'cname':
23-
return service === 'general'
24-
? $regionalConsoleVariables._APP_DOMAIN_TARGET_CNAME
25-
: $regionalConsoleVariables._APP_DOMAIN_SITES;
55+
if (service === 'sites') {
56+
return $regionalConsoleVariables._APP_DOMAIN_SITES;
57+
} else if (service === 'functions') {
58+
return $regionalConsoleVariables._APP_DOMAIN_FUNCTIONS;
59+
} else {
60+
return $regionalConsoleVariables._APP_DOMAIN_TARGET_CNAME;
61+
}
2662
case 'a':
2763
return $regionalConsoleVariables._APP_DOMAIN_TARGET_A;
2864
case 'aaaa':
@@ -37,15 +73,31 @@
3773
<Typography.Text variant="l-500" color="--fgcolor-neutral-primary">
3874
{domain}
3975
</Typography.Text>
40-
{#if verified === true}
41-
<Badge variant="secondary" type="success" size="xs" content="Verified" />
42-
{:else if verified === false}
43-
<Badge variant="secondary" type="warning" size="xs" content="Verification failed" />
76+
{#if verified !== undefined}
77+
{#if ruleStatus === 'created'}
78+
<Badge
79+
variant="secondary"
80+
type="error"
81+
size="xs"
82+
content="Verification failed" />
83+
{:else if ruleStatus === 'verifying'}
84+
<Badge variant="secondary" size="xs" content="Generating certificate" />
85+
{:else if ruleStatus === 'unverified'}
86+
<Badge
87+
variant="secondary"
88+
type="error"
89+
size="xs"
90+
content="Certificate generation failed" />
91+
{:else if verified === true}
92+
<Badge variant="secondary" type="success" size="xs" content="Verified" />
93+
{/if}
4494
{/if}
4595
</Layout.Stack>
4696
<Typography.Text variant="m-400">
47-
Add the following record on your DNS provider. Note that DNS changes may take time to
48-
propagate fully.
97+
Add the following {$regionalConsoleVariables._APP_DOMAIN_TARGET_CAA
98+
? 'records'
99+
: 'record'} on your DNS provider. Note that DNS changes may take up to 48 hours to propagate
100+
fully.
49101
</Typography.Text>
50102
</Layout.Stack>
51103

@@ -62,17 +114,45 @@
62114
<InteractiveText variant="copy" isVisible text={setTarget()} />
63115
</Table.Cell>
64116
</Table.Row.Base>
117+
{#if $regionalConsoleVariables._APP_DOMAIN_TARGET_CAA}
118+
<Table.Row.Base {root}>
119+
<Table.Cell {root}>
120+
<Layout.Stack gap="s" direction="row" alignItems="center">
121+
<span>CAA</span>
122+
<Badge variant="secondary" size="xs" content="Recommended" />
123+
</Layout.Stack>
124+
</Table.Cell>
125+
<Table.Cell {root}>@</Table.Cell>
126+
<Table.Cell {root}>
127+
<InteractiveText variant="copy" isVisible text={caaText} />
128+
</Table.Cell>
129+
</Table.Row.Base>
130+
{/if}
65131
</Table.Root>
66132
<Layout.Stack gap="s" direction="row" alignItems="center">
67-
{#if variant === 'cname'}
68-
<Alert.Inline>
69-
If your domain uses CAA records, ensure certainly.com is authorized — otherwise, SSL
70-
setup may fail. A list of all domain providers and their DNS setting is available <Link
71-
variant="muted"
72-
external
73-
href="https://appwrite.io/docs/advanced/platform/custom-domains">here</Link
74-
>.
75-
</Alert.Inline>
133+
{#if variant === 'cname' && !subdomain}
134+
{#if isCloud}
135+
<Alert.Inline>
136+
Since <Badge variant="secondary" size="s" content={domain} /> is an apex domain,
137+
CNAME record is only supported by certain providers. If yours doesn't, please verify
138+
using
139+
<Link variant="muted" on:click={onNavigateToNameservers}>nameservers</Link> instead.
140+
</Alert.Inline>
141+
{:else if aTabVisible || aaaaTabVisible}
142+
<Alert.Inline>
143+
Since <Badge variant="secondary" size="s" content={domain} /> is an apex domain,
144+
CNAME record is only supported by certain providers. If yours doesn't, please verify
145+
using
146+
{#if aTabVisible}
147+
<Link variant="muted" on:click={onNavigateToA}>A record</Link>
148+
{#if aaaaTabVisible}
149+
or <Link variant="muted" on:click={onNavigateToAAAA}>AAAA record</Link
150+
>{/if}
151+
{:else if aaaaTabVisible}
152+
<Link variant="muted" on:click={onNavigateToAAAA}>AAAA record</Link>
153+
{/if} instead.
154+
</Alert.Inline>
155+
{/if}
76156
{:else}
77157
<Typography.Text variant="m-400" color="--fgcolor-neutral-secondary">
78158
A list of all domain providers and their DNS setting is available <Link

src/routes/(console)/project-[region]-[project]/sites/site-[site]/domains/viewLogsModal.svelte renamed to src/lib/components/domains/viewLogsModal.svelte

File renamed without changes.

src/lib/helpers/tlds.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,12 @@ export function isASubdomain(domain: string | null): boolean {
1818

1919
return !!subdomain;
2020
}
21+
22+
/**
23+
* Returns the subdomain part from a full domain string.
24+
*/
25+
export function getSubdomain(domain: string): string {
26+
if (!domain) return '';
27+
28+
return parse(domain, { allowPrivateDomains: true }).subdomain || '';
29+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<script lang="ts">
2+
import { onMount } from 'svelte';
3+
import { page } from '$app/state';
4+
import { realtime } from '$lib/stores/sdk';
5+
import { Dependencies } from '$lib/constants';
6+
import { invalidate } from '$app/navigation';
7+
import { ProxyRuleDeploymentResourceType, type Models } from '@appwrite.io/console';
8+
9+
onMount(() => {
10+
return realtime.forProject(page.params.region, ['console', 'project'], (response) => {
11+
if (response.events.includes('rules.*.update')) {
12+
const proxyRule = response.payload as Models.ProxyRule;
13+
if (
14+
proxyRule.deploymentResourceType === ProxyRuleDeploymentResourceType.Function &&
15+
proxyRule.deploymentResourceId === page.params.function
16+
) {
17+
invalidate(Dependencies.FUNCTION_DOMAINS);
18+
}
19+
}
20+
});
21+
});
22+
</script>
23+
24+
<slot />

src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/add-domain/+page.svelte

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
4949
async function addDomain() {
5050
const apexDomain = getApexDomain(domainName);
51-
let domain = data.domains?.domains.find((d: Models.Domain) => d.domain === apexDomain);
51+
let domain = data.domainsList.domains.find((d: Models.Domain) => d.domain === apexDomain);
5252
5353
if (apexDomain && !domain && isCloud) {
5454
try {
@@ -57,15 +57,7 @@
5757
domain: apexDomain
5858
});
5959
} catch (error) {
60-
// apex might already be added on organization level, skip.
61-
const alreadyAdded = error?.type === 'domain_already_exists';
62-
if (!alreadyAdded) {
63-
addNotification({
64-
type: 'error',
65-
message: error.message
66-
});
67-
return;
68-
}
60+
// Apex domain creation error needs to be silent.
6961
}
7062
}
7163
@@ -101,9 +93,7 @@
10193
await goto(routeBase);
10294
await invalidate(Dependencies.FUNCTION_DOMAINS);
10395
} else {
104-
await goto(
105-
`${routeBase}/add-domain/verify-${domainName}?rule=${rule.$id}&domain=${domain.$id}`
106-
);
96+
await goto(`${routeBase}/add-domain/verify-${domainName}?rule=${rule.$id}`);
10797
await invalidate(Dependencies.FUNCTION_DOMAINS);
10898
}
10999
} catch (error) {

src/routes/(console)/project-[region]-[project]/functions/function-[function]/domains/add-domain/+page.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { sdk } from '$lib/stores/sdk';
2-
import { Query } from '@appwrite.io/console';
2+
import { Query, type Models } from '@appwrite.io/console';
33
import { RuleTrigger, RuleType } from '$lib/stores/sdk';
44
import { Dependencies } from '$lib/constants';
55
import { isCloud } from '$lib/system';
@@ -8,7 +8,7 @@ export const load = async ({ parent, depends, params }) => {
88
const { function: func, organization } = await parent();
99
depends(Dependencies.DOMAINS, Dependencies.FUNCTION_DOMAINS);
1010

11-
const [rules, installations, domains] = await Promise.all([
11+
const [rules, installations, domainsList] = await Promise.all([
1212
sdk.forProject(params.region, params.project).proxy.listRules({
1313
queries: [
1414
Query.equal('type', RuleType.DEPLOYMENT),
@@ -18,13 +18,13 @@ export const load = async ({ parent, depends, params }) => {
1818
sdk.forProject(params.region, params.project).vcs.listInstallations(),
1919
isCloud
2020
? sdk.forConsole.domains.list({ queries: [Query.equal('teamId', organization.$id)] })
21-
: Promise.resolve(null)
21+
: Promise.resolve<Models.DomainsList>({ total: 0, domains: [] })
2222
]);
2323

2424
return {
2525
func,
2626
rules,
27-
domains,
27+
domainsList,
2828
installations,
2929
branches:
3030
func?.installationId && func?.providerRepositoryId

0 commit comments

Comments
 (0)