feat(custom-domain): enable UI for custom domain (#10062)

This commit is contained in:
Antoine Moreaux
2025-02-10 09:43:13 +01:00
committed by GitHub
parent f8c653f153
commit 1b98f40f17
13 changed files with 305 additions and 343 deletions

View File

@ -1,48 +1,23 @@
import { createUnionType, Field, ObjectType } from '@nestjs/graphql';
import { Field, ObjectType } from '@nestjs/graphql';
@ObjectType()
class CustomHostnameOwnershipVerificationTxt {
class CustomHostnameVerification {
@Field(() => String)
type: 'txt';
validationType: 'ownership' | 'ssl' | 'redirection';
@Field(() => String)
name: string;
type: 'txt' | 'cname';
@Field(() => String)
key: string;
@Field(() => String)
status: string;
@Field(() => String)
value: string;
}
@ObjectType()
class CustomHostnameOwnershipVerificationHttp {
@Field()
type: 'http';
@Field(() => String)
body: string;
@Field(() => String)
url: string;
}
const CustomHostnameOwnershipVerification = createUnionType({
name: 'OwnershipVerification',
types: () =>
[
CustomHostnameOwnershipVerificationTxt,
CustomHostnameOwnershipVerificationHttp,
] as const,
resolveType(value) {
if ('type' in value && value.type === 'txt') {
return CustomHostnameOwnershipVerificationTxt;
}
if ('type' in value && value.type === 'http') {
return CustomHostnameOwnershipVerificationHttp;
}
return null;
},
});
@ObjectType()
export class CustomHostnameDetails {
@Field(() => String)
@ -51,25 +26,6 @@ export class CustomHostnameDetails {
@Field(() => String)
hostname: string;
@Field(() => [CustomHostnameOwnershipVerification])
ownershipVerifications: Array<typeof CustomHostnameOwnershipVerification>;
@Field(() => String, { nullable: true })
status?:
| 'active'
| 'pending'
| 'active_redeploying'
| 'moved'
| 'pending_deletion'
| 'deleted'
| 'pending_blocked'
| 'pending_migration'
| 'pending_provisioned'
| 'test_pending'
| 'test_active'
| 'test_active_apex'
| 'test_blocked'
| 'test_failed'
| 'provisioned'
| 'blocked';
@Field(() => [CustomHostnameVerification])
records: Array<CustomHostnameVerification>;
}

View File

@ -283,44 +283,59 @@ export class DomainManagerService {
return {
id: response.result[0].id,
hostname: response.result[0].hostname,
status: response.result[0].status,
ownershipVerifications: [
records: [
response.result[0].ownership_verification,
response.result[0].ownership_verification_http,
].reduce(
(acc, ownershipVerification) => {
if (!ownershipVerification) return acc;
...(response.result[0].ssl?.validation_records ?? []),
]
.map<CustomHostnameDetails['records'][0] | undefined>(
(record: Record<string, string>) => {
if (!record) return;
if (
'http_body' in ownershipVerification &&
'http_url' in ownershipVerification &&
ownershipVerification.http_body &&
ownershipVerification.http_url
) {
acc.push({
type: 'http',
body: ownershipVerification.http_body,
url: ownershipVerification.http_url,
});
}
if (
'txt_name' in record &&
'txt_value' in record &&
record.txt_name &&
record.txt_value
) {
return {
validationType: 'ssl' as const,
type: 'txt' as const,
status: response.result[0].ssl.status ?? 'pending',
key: record.txt_name,
value: record.txt_value,
};
}
if (
'type' in ownershipVerification &&
ownershipVerification.type === 'txt' &&
ownershipVerification.value &&
ownershipVerification.name
) {
acc.push({
type: 'txt',
value: ownershipVerification.value,
name: ownershipVerification.name,
});
}
return acc;
},
[] as CustomHostnameDetails['ownershipVerifications'],
),
if (
'type' in record &&
record.type === 'txt' &&
record.value &&
record.name
) {
return {
validationType: 'ownership' as const,
type: 'txt' as const,
status: response.result[0].status ?? 'pending',
key: record.name,
value: record.value,
};
}
},
)
.filter(isDefined)
.concat([
{
validationType: 'redirection' as const,
type: 'cname' as const,
status:
response.result[0].verification_errors?.[0] ===
'custom hostname does not CNAME to this zone.'
? 'error'
: 'success',
key: response.result[0].hostname,
value: this.getFrontUrl().hostname,
},
]),
};
}

View File

@ -2,7 +2,7 @@
import { Field, InputType } from '@nestjs/graphql';
import { IsOptional, IsBoolean, IsString } from 'class-validator';
import { IsOptional, IsString } from 'class-validator';
@InputType()
export class GetAuthorizationUrlInput {

View File

@ -222,7 +222,7 @@ export class WorkspaceResolver {
@Query(() => CustomHostnameDetails, { nullable: true })
@UseGuards(WorkspaceAuthGuard)
async getHostnameDetails(
async getCustomHostnameDetails(
@AuthWorkspace() { hostname }: Workspace,
): Promise<CustomHostnameDetails | undefined> {
if (!hostname) return undefined;