import { createPassport } from "@assistant-ui/passport"; import type { createPinboard } from "./server.js"; export namespace pinboardEnv { export type Source = Record; export type Result = { redisUrl: string; options: Omit; }; } const msOf = (env: pinboardEnv.Source, name: string): number | undefined => { const raw = env[name]; if (raw === undefined || raw === "") return undefined; const value = Number(raw); if (!Number.isFinite(value) || value <= 0) { throw new Error(`${name} must be a positive number of milliseconds`); } return value; }; export const redisEndpointForLogs = (redisUrl: string): string => { try { const parsed = new URL(redisUrl); if (parsed.protocol === "memory:") return "memory:"; return `${parsed.protocol}//${parsed.host}${parsed.pathname}`; } catch { return "[configured]"; } }; /** PINBOARD_* env surface shared by the node and workerd entries; throws on invalid values. */ export const pinboardEnv = (env: pinboardEnv.Source): pinboardEnv.Result => { const redisUrl = env["REDIS_URL"] ?? "redis://localhost:6379"; // {providers, namespaces?}; secret fields and static token accept {env: "NAME"}. const rawPassport = env["PINBOARD_PASSPORT"]; if (rawPassport === undefined || rawPassport === "") { throw new Error("PINBOARD_PASSPORT is required"); } let passport: createPinboard.Options["passport"]; let namespaces: createPinboard.Options["namespaces"]; try { const parsed = JSON.parse(rawPassport) as { providers: Parameters[0]["providers"]; namespaces?: createPinboard.Options["namespaces"]; }; namespaces = parsed.namespaces; passport = createPassport({ providers: parsed.providers }, { env }); } catch (error) { throw new Error(`PINBOARD_PASSPORT is invalid: ${String(error)}`); } const shardsRaw = env["PINBOARD_SHARDS"]; const shards = shardsRaw === undefined || shardsRaw === "" ? undefined : Number(shardsRaw); if (shards !== undefined && (!Number.isInteger(shards) || shards < 1)) { throw new Error("PINBOARD_SHARDS must be an integer >= 1"); } const epochRaw = env["PINBOARD_EPOCH"]; const epoch = epochRaw === undefined || epochRaw === "" ? undefined : Number(epochRaw); if (epoch !== undefined && (!Number.isInteger(epoch) || epoch < 0)) { throw new Error("PINBOARD_EPOCH must be an integer >= 0"); } const hostnameAwareRaw = env["PINBOARD_HOSTNAME_AWARE"]; if ( hostnameAwareRaw !== undefined && !["", "0", "1", "true", "false"].includes(hostnameAwareRaw) ) { throw new Error("PINBOARD_HOSTNAME_AWARE must be 1/0/true/false"); } const hostnameAware = hostnameAwareRaw === "1" || hostnameAwareRaw === "true"; const balanceFactorRaw = env["PINBOARD_AFFINITY_BALANCE_FACTOR"]; const balanceFactor = balanceFactorRaw === undefined || balanceFactorRaw === "" ? undefined : Number(balanceFactorRaw); if (balanceFactor !== undefined && !(balanceFactor > 1)) { throw new Error("PINBOARD_AFFINITY_BALANCE_FACTOR must be a number > 1"); } // Comma-separated proxy IPs/CIDRs whose X-Forwarded-For hops are trusted, // or "*" to trust XFF outright. const trustedProxiesRaw = env["PINBOARD_TRUSTED_PROXIES"]; const trustedProxies = trustedProxiesRaw === undefined || trustedProxiesRaw === "" ? undefined : trustedProxiesRaw.trim() === "*" ? ("*" as const) : trustedProxiesRaw.split(",").map((entry) => entry.trim()); return { redisUrl, options: { passport, namespaces, durability: { sweepIntervalMs: msOf(env, "PINBOARD_SWEEP_INTERVAL_MS") }, leaseTtlMs: msOf(env, "PINBOARD_LEASE_TTL_MS"), verifyTimeoutMs: msOf(env, "PINBOARD_VERIFY_TIMEOUT_MS"), keyPrefix: env["PINBOARD_KEY_PREFIX"], shards, hostnameAware, epoch, affinity: { balanceFactor, trustedProxies }, }, }; };