/** * The ONE base-app touch-point — PLAN_RELAY_AGENT T17 (INDEX §0, EXPLORE §3 "Zero code change"). * APPENDS `https://..` to the base app's ALLOWED_ORIGINS env (idempotent), * as CONFIG — NO `src/` code edit. AUGMENTS, never weakens, the Origin/CSWSH check: existing * origins are always preserved (EXPLORE §3 "do not weaken the check"). * * PLAN_NATIVE_TUNNEL S2: the DNS zone label is PARAMETERIZED. Relay callers keep the historical * `term` zone (default), while native-tunnel hosts pass `terminal` so the base app trusts * `https://.terminal.`. The default is preserved so existing callers/tests are * unaffected — the zone is opt-in per call, never hard-flipped. */ import { existsSync, readFileSync, writeFileSync } from 'node:fs' export interface OriginFsDeps { exists(path: string): boolean read(path: string): string write(path: string, content: string): void } const defaultFs: OriginFsDeps = { exists: existsSync, read: (p) => readFileSync(p, 'utf8'), write: (p, c) => writeFileSync(p, c), } /** Default DNS zone label (relay hosts). Native-tunnel hosts pass `terminal`. */ export const DEFAULT_ORIGIN_ZONE = 'term' const KEY = 'ALLOWED_ORIGINS' /** Compose the subdomain origin the base app must trust: `https://..`. */ export function subdomainOrigin( subdomain: string, domain: string, zone: string = DEFAULT_ORIGIN_ZONE, ): string { return `https://${subdomain}.${zone}.${domain}` } /** * Merge `origin` into a comma-separated ALLOWED_ORIGINS value, preserving every existing origin and * de-duplicating. Returns the merged CSV; never removes an origin. Pure/immutable. */ export function mergeOrigins(current: string | undefined, origin: string): string { const origins = (current ?? '') .split(',') .map((s) => s.trim()) .filter((s) => s.length > 0) if (origins.includes(origin)) return origins.join(',') return [...origins, origin].join(',') } function upsertOriginLine(content: string, origin: string): string { const lines = content.length === 0 ? [] : content.split('\n') let found = false const next = lines.map((line) => { if (!line.startsWith(`${KEY}=`)) return line found = true return `${KEY}=${mergeOrigins(line.slice(KEY.length + 1), origin)}` }) if (!found) next.push(`${KEY}=${origin}`) return next.join('\n') } /** * Idempotently append the subdomain origin to ALLOWED_ORIGINS in `baseAppEnvPath`. Never removes an * existing origin. Creates the file/line if absent. `zone` selects the DNS zone label (default * preserves relay callers). */ export function ensureAllowedOrigin( baseAppEnvPath: string, subdomain: string, domain: string, fs: OriginFsDeps = defaultFs, zone: string = DEFAULT_ORIGIN_ZONE, ): void { const origin = subdomainOrigin(subdomain, domain, zone) const existing = fs.exists(baseAppEnvPath) ? fs.read(baseAppEnvPath) : '' const updated = upsertOriginLine(existing, origin) fs.write(baseAppEnvPath, updated.endsWith('\n') ? updated : `${updated}\n`) }