fabro/apps/fabro-web/app/lib/config.server.ts
Bryan Helmkamp 0e0c45d05c Designate retros as experimental, disable by default via [features] flag
Move retro control from [fabro] retro to [features] retros in project
config. Default changes from true to false — retros are now opt-in.
Add retros field to server config Features struct, OpenAPI spec,
TypeScript client, and web app config. Update docs with experimental
warning and new enablement instructions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 20:36:32 -04:00

112 lines
2.6 KiB
TypeScript

import { readFileSync } from "node:fs";
import { homedir } from "node:os";
import { join } from "node:path";
import { parse } from "smol-toml";
interface AuthConfig {
provider: "github" | "tailscale" | "insecure_disabled";
allowed_usernames: string[];
}
interface ApiConfig {
base_url: string;
authentication_strategy: "jwt" | "insecure_disabled";
}
interface GitConfig {
provider: "github";
app_id: string | null;
client_id: string | null;
slug: string | null;
}
interface Features {
session_sandboxes: boolean;
retros: boolean;
}
interface WebConfig {
url: string;
auth: AuthConfig;
}
interface AppConfig {
web: WebConfig;
api: ApiConfig;
git: GitConfig;
features: Features;
}
const AUTH_DEFAULTS: AuthConfig = {
provider: "github",
allowed_usernames: [],
};
const WEB_DEFAULTS: WebConfig = {
url: "http://localhost:5173",
auth: AUTH_DEFAULTS,
};
const API_DEFAULTS: ApiConfig = {
base_url: "http://localhost:3000",
authentication_strategy: "jwt",
};
const GIT_DEFAULTS: GitConfig = {
provider: "github",
app_id: null,
client_id: null,
slug: null,
};
const FEATURES_DEFAULTS: Features = {
session_sandboxes: false,
retros: false,
};
export const FABRO_CONFIG_PATH = join(homedir(), ".fabro", "server.toml");
function loadAppConfig(): AppConfig {
const configPath = FABRO_CONFIG_PATH;
let raw: Record<string, unknown> = {};
try {
raw = parse(readFileSync(configPath, "utf-8")) as Record<string, unknown>;
} catch {
// File doesn't exist or is unreadable — use defaults
}
const rawWeb = (raw.web ?? {}) as Record<string, unknown>;
const rawWebAuth = (rawWeb.auth ?? {}) as Partial<AuthConfig>;
const rawApi = (raw.api ?? {}) as Partial<ApiConfig>;
const rawGit = (raw.git ?? {}) as Partial<GitConfig>;
const rawFeatures = (raw.features ?? {}) as Partial<Features>;
const demo = process.env.FABRO_DEMO === "1";
return {
web: {
...WEB_DEFAULTS,
url: (rawWeb.url as string) ?? WEB_DEFAULTS.url,
auth: demo
? { provider: "insecure_disabled", allowed_usernames: [] }
: { ...AUTH_DEFAULTS, ...rawWebAuth },
},
api: demo
? { ...API_DEFAULTS, ...rawApi, authentication_strategy: "insecure_disabled" }
: { ...API_DEFAULTS, ...rawApi },
git: { ...GIT_DEFAULTS, ...rawGit },
features: { ...FEATURES_DEFAULTS, ...rawFeatures },
};
}
/** Loaded once at module init; call reloadAppConfig() to pick up changes. */
let appConfig: AppConfig = loadAppConfig();
export function getAppConfig(): AppConfig {
return appConfig;
}
export function reloadAppConfig(): void {
appConfig = loadAppConfig();
}