@@ -5,16 +5,16 @@ import { getDomainMapping } from '@/lib/domains'
5
5
6
6
export default {
7
7
Query : {
8
- customDomain : async ( parent , { subName } , { models } ) => {
9
- return models . customDomain . findUnique ( { where : { subName } } )
8
+ domain : async ( parent , { subName } , { models } ) => {
9
+ return models . domain . findUnique ( { where : { subName } , include : { verifications : true } } )
10
10
} ,
11
- domainMapping : async ( parent , { domain } , { models } ) => {
12
- const mapping = await getDomainMapping ( domain )
11
+ domainMapping : async ( parent , { domainName } , { models } ) => {
12
+ const mapping = await getDomainMapping ( domainName )
13
13
return mapping
14
14
}
15
15
} ,
16
16
Mutation : {
17
- setCustomDomain : async ( parent , { subName, domain } , { me, models } ) => {
17
+ setDomain : async ( parent , { subName, domainName } , { me, models } ) => {
18
18
if ( ! me ) {
19
19
throw new GqlAuthenticationError ( )
20
20
}
@@ -28,45 +28,27 @@ export default {
28
28
throw new GqlInputError ( 'you do not own this sub' )
29
29
}
30
30
31
- domain = domain . trim ( ) // protect against trailing spaces
32
- if ( domain && ! validateSchema ( customDomainSchema , { domain } ) ) {
31
+ domainName = domainName . trim ( ) // protect against trailing spaces
32
+ if ( domainName && ! validateSchema ( customDomainSchema , { domainName } ) ) {
33
33
throw new GqlInputError ( 'invalid domain format' )
34
34
}
35
35
36
- const existing = await models . customDomain . findUnique ( { where : { subName } } )
36
+ const existing = await models . domain . findUnique ( { where : { subName } } )
37
37
38
- if ( domain ) {
39
- if ( existing && existing . domain === domain && existing . status !== 'HOLD' ) {
38
+ if ( domainName ) {
39
+ if ( existing && existing . domainName === domainName && existing . status !== 'HOLD' ) {
40
40
throw new GqlInputError ( 'domain already set' )
41
41
}
42
42
43
43
const initializeDomain = {
44
- domain,
45
- createdAt : new Date ( ) ,
46
- status : 'PENDING' ,
47
- verification : {
48
- dns : {
49
- state : 'PENDING' ,
50
- cname : 'stacker.news' ,
51
- // generate a random txt record only if it's a new domain
52
- txt : existing ?. domain === domain && existing . verification . dns . txt
53
- ? existing . verification . dns . txt
54
- : randomBytes ( 32 ) . toString ( 'base64' )
55
- } ,
56
- ssl : {
57
- state : 'WAITING' ,
58
- arn : null ,
59
- cname : null ,
60
- value : null
61
- }
62
- }
44
+ domainName,
45
+ updatedAt : new Date ( ) ,
46
+ status : 'PENDING'
63
47
}
64
48
65
- const updatedDomain = await models . customDomain . upsert ( {
49
+ const updatedDomain = await models . domain . upsert ( {
66
50
where : { subName } ,
67
- update : {
68
- ...initializeDomain
69
- } ,
51
+ update : initializeDomain ,
70
52
create : {
71
53
...initializeDomain ,
72
54
sub : {
@@ -75,6 +57,55 @@ export default {
75
57
}
76
58
} )
77
59
60
+ const existingVerifications = await models . domainVerification . findMany ( {
61
+ where : { domainId : updatedDomain . id }
62
+ } )
63
+
64
+ const existingVerificationMap = Object . fromEntries ( existingVerifications . map ( v => [ v . type , v ] ) )
65
+
66
+ const verifications = {
67
+ CNAME : {
68
+ domainId : updatedDomain . id ,
69
+ type : 'CNAME' ,
70
+ state : 'PENDING' ,
71
+ host : domainName ,
72
+ value : 'stacker.news'
73
+ } ,
74
+ TXT : {
75
+ domainId : updatedDomain . id ,
76
+ type : 'TXT' ,
77
+ state : 'PENDING' ,
78
+ host : '_snverify.' + domainName ,
79
+ value : existing . status === 'HOLD' ? existingVerificationMap . TXT ?. value : randomBytes ( 32 ) . toString ( 'base64' )
80
+ } ,
81
+ SSL : {
82
+ domainId : updatedDomain . id ,
83
+ type : 'SSL' ,
84
+ state : 'WAITING' ,
85
+ host : null ,
86
+ value : null ,
87
+ sslArn : null
88
+ }
89
+ }
90
+
91
+ const initializeVerifications = Object . entries ( verifications ) . map ( ( [ type , verification ] ) =>
92
+ models . domainVerification . upsert ( {
93
+ where : {
94
+ domainId_type : {
95
+ domainId : updatedDomain . id ,
96
+ type
97
+ }
98
+ } ,
99
+ update : verification ,
100
+ create : {
101
+ ...verification ,
102
+ domain : { connect : { id : updatedDomain . id } }
103
+ }
104
+ } )
105
+ )
106
+
107
+ await Promise . all ( initializeVerifications )
108
+
78
109
// schedule domain verification in 30 seconds
79
110
await models . $executeRaw `
80
111
INSERT INTO pgboss.job (name, data, retrylimit, retrydelay, startafter, keepuntil)
@@ -94,7 +125,7 @@ export default {
94
125
WHERE name = 'domainVerification'
95
126
AND data->>'domainId' = ${ existing . id } ::TEXT`
96
127
97
- return await models . customDomain . delete ( { where : { subName } } )
128
+ return await models . domain . delete ( { where : { subName } } )
98
129
} catch ( error ) {
99
130
console . error ( error )
100
131
throw new GqlInputError ( 'failed to delete domain' )
0 commit comments