/** * Validate `BARE_OS_SEED_DHT_BOOTSTRAP_JSON`. * Accepts either string entries "host:port" or objects { host, port, addressClass? }. * Returns normalized `host:port` strings for safe proc exposure. * @param {string} raw * @returns {string[]} */ export function parseSeedDhtBootstrapJson(raw) { const s = String(raw || '').trim() if (!s) return [] let parsed try { parsed = JSON.parse(s) } catch { throw new Error('BARE_OS_SEED_DHT_BOOTSTRAP_JSON must be valid JSON') } if (!Array.isArray(parsed)) { throw new Error('BARE_OS_SEED_DHT_BOOTSTRAP_JSON must be a JSON array') } /** @type {string[]} */ const out = [] for (const row of parsed.slice(0, 64)) { if (typeof row === 'string') { const n = normalizeHostPort(row) if (!n) { throw new Error('Invalid DHT bootstrap entry (expected host:port string)') } out.push(n) continue } if (!row || typeof row !== 'object' || Array.isArray(row)) { throw new Error('Invalid DHT bootstrap entry (expected string or object)') } const host = String(row.host || '').trim() const port = Number.parseInt(String(row.port || ''), 10) if (!host || !Number.isFinite(port) || port < 1 || port > 65535) { throw new Error('Invalid DHT bootstrap object (host/port)') } const cls = String(row.addressClass || '').trim().toLowerCase() if (cls && !['ipv4', 'ipv6', 'relay', 'local', 'wan'].includes(cls)) { throw new Error('Invalid DHT bootstrap object (addressClass)') } out.push(`${host}:${port}`) } return out } /** * @param {string} s * @returns {string | null} */ function normalizeHostPort(s) { const m = String(s || '').trim().match(/^(.+):([0-9]{1,5})$/) if (!m) return null const host = String(m[1] || '').trim() const port = Number.parseInt(String(m[2] || ''), 10) if (!host || !Number.isFinite(port) || port < 1 || port > 65535) return null return `${host}:${port}` }