+37
src/lib/db.ts
+37
src/lib/db.ts
···
120
120
return rows.length === 0;
121
121
};
122
122
123
+
export const isDomainRegistered = async (domain: string) => {
124
+
const domainLower = domain.toLowerCase().trim();
125
+
126
+
// Check wisp.place subdomains
127
+
const wispDomain = await db`
128
+
SELECT did, domain, rkey FROM domains WHERE domain = ${domainLower}
129
+
`;
130
+
131
+
if (wispDomain.length > 0) {
132
+
return {
133
+
registered: true,
134
+
type: 'wisp' as const,
135
+
domain: wispDomain[0].domain,
136
+
did: wispDomain[0].did,
137
+
rkey: wispDomain[0].rkey
138
+
};
139
+
}
140
+
141
+
// Check custom domains
142
+
const customDomain = await db`
143
+
SELECT id, domain, did, rkey, verified FROM custom_domains WHERE domain = ${domainLower}
144
+
`;
145
+
146
+
if (customDomain.length > 0) {
147
+
return {
148
+
registered: true,
149
+
type: 'custom' as const,
150
+
domain: customDomain[0].domain,
151
+
did: customDomain[0].did,
152
+
rkey: customDomain[0].rkey,
153
+
verified: customDomain[0].verified
154
+
};
155
+
}
156
+
157
+
return { registered: false };
158
+
};
159
+
123
160
export const claimDomain = async (did: string, handle: string): Promise<string> => {
124
161
const h = handle.trim().toLowerCase();
125
162
if (!isValidHandle(h)) throw new Error('invalid_handle');
+34
-6
src/routes/domain.ts
+34
-6
src/routes/domain.ts
···
6
6
claimDomain,
7
7
getDomainByDid,
8
8
isDomainAvailable,
9
+
isDomainRegistered,
9
10
isValidHandle,
10
11
toDomain,
11
12
updateDomain,
···
22
23
23
24
export const domainRoutes = (client: NodeOAuthClient) =>
24
25
new Elysia({ prefix: '/api/domain' })
25
-
.derive(async ({ cookie }) => {
26
-
const auth = await requireAuth(client, cookie)
27
-
return { auth }
28
-
})
26
+
// Public endpoints (no auth required)
29
27
.get('/check', async ({ query }) => {
30
28
try {
31
29
const handle = (query.handle || "")
32
30
.trim()
33
31
.toLowerCase();
34
-
32
+
35
33
if (!isValidHandle(handle)) {
36
34
return {
37
35
available: false,
38
36
reason: "invalid"
39
37
};
40
38
}
41
-
39
+
42
40
const available = await isDomainAvailable(handle);
43
41
return {
44
42
available,
···
50
48
available: false
51
49
};
52
50
}
51
+
})
52
+
.get('/registered', async ({ query, set }) => {
53
+
try {
54
+
const domain = (query.domain || "").trim().toLowerCase();
55
+
56
+
if (!domain) {
57
+
set.status = 400;
58
+
return { error: 'Domain parameter required' };
59
+
}
60
+
61
+
const result = await isDomainRegistered(domain);
62
+
63
+
// For Caddy on-demand TLS: 200 = allow, 404 = deny
64
+
if (result.registered) {
65
+
set.status = 200;
66
+
return result;
67
+
} else {
68
+
set.status = 404;
69
+
return { registered: false };
70
+
}
71
+
} catch (err) {
72
+
console.error("domain/registered error", err);
73
+
set.status = 500;
74
+
return { error: 'Failed to check domain' };
75
+
}
76
+
})
77
+
// Authenticated endpoints (require auth)
78
+
.derive(async ({ cookie }) => {
79
+
const auth = await requireAuth(client, cookie)
80
+
return { auth }
53
81
})
54
82
.post('/claim', async ({ body, auth }) => {
55
83
try {