An AT Protocol PDS
1import type { MoonstoneEnv } from '@ewanc26/moonstone-config'
2import { logger } from './logger.js'
3import { createRequire } from 'node:module'
4
5const require = createRequire(import.meta.url)
6
7type NativeAddon = {
8 ensureValidHandle(handle: string): void
9 ensureValidDid(did: string): void
10 resolveDid(did: string, plcUrl: string, timeoutMs: number): Promise<Record<string, unknown> | null>
11}
12
13function loadNative(): NativeAddon | null {
14 try {
15 return require('@ewanc26/moonstone-native') as NativeAddon
16 } catch {
17 logger.warn(
18 'moonstone-native addon not built — skipping Rust-backed startup validation. ' +
19 'Run `pnpm --filter @ewanc26/moonstone-native build` to enable.',
20 )
21 return null
22 }
23}
24
25export async function validateStartup(env: MoonstoneEnv): Promise<void> {
26 const native = loadNative()
27 if (!native) return
28
29 const hostname = env.PDS_HOSTNAME
30 const did = env.PDS_SERVICE_DID ?? `did:web:${hostname}`
31 const plcUrl = env.PDS_PLC_URL
32 const devMode = env.PDS_DEV_MODE
33
34 try {
35 native.ensureValidHandle(hostname)
36 } catch (e) {
37 throw new Error(`PDS_HOSTNAME "${hostname}" is not a valid ATProto handle: ${(e as Error).message}`)
38 }
39
40 try {
41 native.ensureValidDid(did)
42 } catch (e) {
43 throw new Error(`Service DID "${did}" is invalid: ${(e as Error).message}`)
44 }
45
46 if (!devMode) {
47 logger.info({ did, plcUrl }, 'moonstone: resolving PDS DID document for pre-flight check')
48 try {
49 const doc = await native.resolveDid(did, plcUrl, 5000)
50 if (doc) {
51 logger.info({ did }, 'moonstone: DID document found')
52 } else {
53 logger.warn({ did, plcUrl }, 'moonstone: DID document not yet registered — expected for first-time setup')
54 }
55 } catch (e) {
56 logger.warn({ did, err: (e as Error).message }, 'moonstone: DID resolution failed during startup — continuing anyway')
57 }
58 }
59
60 logger.info({ hostname, did }, 'moonstone: startup validation passed')
61}