Files
Synapsis/src/lib/swarm/node-domain.ts
T
cyph3rasi 6edf8991fa Repair swarm bootstrap seed for new and existing nodes
Hop-State: A_06FP90SDWE5709BB1G6J4B8
Hop-Proposal: R_06FP90RS27BNBV5H5N053A0
Hop-Task: T_06FP905Q50D1ZFPC56N3DZG
Hop-Attempt: AT_06FP905Q50E6P72ZMVT4038
2026-07-14 23:42:26 -07:00

70 lines
1.9 KiB
TypeScript

import { parse } from 'tldts';
const LEGACY_SWARM_SEED_DOMAINS: Readonly<Record<string, string>> = {
'node.synapsis.social': 'synapsis.social',
};
export function normalizeNodeDomain(domain: string): string {
return domain
.trim()
.toLowerCase()
.replace(/^https?:\/\//, '')
.replace(/\/.*$/, '')
.replace(/^@/, '');
}
/**
* Return the canonical host for a publicly addressable swarm node.
*
* The swarm is a public network, so local development hosts, IP addresses,
* special-use names, and made-up TLDs must never enter the node registry.
* Ports are retained because a public hostname may intentionally expose
* Synapsis on a non-standard port.
*/
export function getPublicSwarmDomain(value: string | null | undefined): string | null {
if (!value) return null;
const normalized = normalizeNodeDomain(value);
if (!normalized) return null;
try {
const url = new URL(`https://${normalized}`);
if (url.username || url.password) return null;
const hostname = url.hostname.toLowerCase().replace(/\.$/, '');
const result = parse(hostname, {
allowPrivateDomains: false,
detectSpecialUse: true,
});
if (
!result.domain ||
result.isIcann !== true ||
result.isIp ||
result.isSpecialUse
) {
return null;
}
return url.port ? `${hostname}:${url.port}` : hostname;
} catch {
return null;
}
}
export function isPublicSwarmDomain(value: string | null | undefined): boolean {
return getPublicSwarmDomain(value) !== null;
}
/**
* Resolve retired bootstrap hostnames to the node identity they represent.
* This keeps upgraded nodes working even before their persisted seed rows are
* rewritten by the accompanying data migration.
*/
export function getCanonicalSwarmSeedDomain(value: string | null | undefined): string | null {
const domain = getPublicSwarmDomain(value);
if (!domain) return null;
return LEGACY_SWARM_SEED_DOMAINS[domain] ?? domain;
}