Files
fusion/packages/core/src/settings-validation.ts
gsxdsm b8045b6f2b feat(core): add locale primitives and GlobalSettings.language (U1)
Add SUPPORTED_LOCALES (en, zh-CN, zh-TW, fr, es), Locale, DEFAULT_LOCALE,
isLocale, and validateLocale to @fusion/core, plus an optional
GlobalSettings.language field registered in the schema defaults and keys.
Locale primitives live in types.ts so the dashboard's @fusion/core->types.ts
Vite alias can reach them. language defaults to undefined (resolve-at-runtime).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 07:51:25 -07:00

207 lines
6.8 KiB
TypeScript

import type {
DirectMergeCommitStrategy,
GithubAuthMode,
HeartbeatPromptTemplate,
HeartbeatScopeDisciplineMode,
Locale,
SandboxBackendName,
SandboxFailureMode,
SandboxPolicy,
SandboxProjectSettings,
UnavailableNodePolicy,
} from "./types.js";
import { isLocale } from "./types.js";
const UNAVAILABLE_NODE_POLICIES: readonly UnavailableNodePolicy[] = ["block", "fallback-local"] as const;
const DIRECT_MERGE_COMMIT_STRATEGIES: readonly DirectMergeCommitStrategy[] = ["auto", "always-squash", "always-rebase"] as const;
const GITHUB_AUTH_MODES: readonly GithubAuthMode[] = ["gh-cli", "token"] as const;
const GITHUB_REPO_SLUG_PATTERN = /^[A-Za-z0-9._-]+\/[A-Za-z0-9._-]+$/;
const HEARTBEAT_SCOPE_DISCIPLINE_MODES: readonly HeartbeatScopeDisciplineMode[] = [
"strict",
"lite",
"off",
] as const;
const HEARTBEAT_PROMPT_TEMPLATES: readonly HeartbeatPromptTemplate[] = [
"default",
"compact",
] as const;
export const SANDBOX_BACKEND_NAMES: readonly SandboxBackendName[] = [
"native",
"sandbox-exec",
"bubblewrap",
"docker",
"podman",
"custom",
] as const;
export const SANDBOX_FAILURE_MODES: readonly SandboxFailureMode[] = ["fail-hard", "fallback-native"] as const;
/**
* Validates a project unavailable-node routing policy value.
*
* Returns the normalized policy value when valid, otherwise undefined.
*/
export function validateUnavailableNodePolicy(value: unknown): UnavailableNodePolicy | undefined {
if (value === undefined) {
return undefined;
}
if (typeof value !== "string") {
return undefined;
}
return (UNAVAILABLE_NODE_POLICIES as readonly string[]).includes(value)
? (value as UnavailableNodePolicy)
: undefined;
}
/** Returns a validated UI locale for global settings, otherwise undefined. */
export function validateLocale(value: unknown): Locale | undefined {
if (value === undefined) {
return undefined;
}
return isLocale(value) ? value : undefined;
}
/** Returns a validated direct-merge commit strategy for project settings, otherwise undefined. */
export function validateDirectMergeCommitStrategy(value: unknown): DirectMergeCommitStrategy | undefined {
if (value === undefined) {
return undefined;
}
if (typeof value !== "string") {
return undefined;
}
return (DIRECT_MERGE_COMMIT_STRATEGIES as readonly string[]).includes(value)
? (value as DirectMergeCommitStrategy)
: undefined;
}
/** Returns a validated GitHub auth mode for project settings, otherwise undefined. */
export function validateGithubAuthMode(value: unknown): GithubAuthMode | undefined {
if (value === undefined) {
return undefined;
}
if (typeof value !== "string") {
return undefined;
}
return (GITHUB_AUTH_MODES as readonly string[]).includes(value) ? (value as GithubAuthMode) : undefined;
}
/** Returns a validated owner/repo GitHub slug, otherwise undefined. Empty string is treated as unset. */
export function validateGithubRepoSlug(value: unknown): string | undefined {
if (value === undefined) {
return undefined;
}
if (typeof value !== "string") {
return undefined;
}
const trimmed = value.trim();
if (trimmed.length === 0) {
return undefined;
}
return GITHUB_REPO_SLUG_PATTERN.test(trimmed) ? trimmed : undefined;
}
/** Returns a validated heartbeat scope-discipline mode for project/agent settings, otherwise undefined. */
export function validateHeartbeatScopeDisciplineMode(value: unknown): HeartbeatScopeDisciplineMode | undefined {
if (value === undefined) {
return undefined;
}
if (typeof value !== "string") {
return undefined;
}
return (HEARTBEAT_SCOPE_DISCIPLINE_MODES as readonly string[]).includes(value)
? (value as HeartbeatScopeDisciplineMode)
: undefined;
}
/** Returns a validated heartbeat prompt template for project/agent settings, otherwise undefined. */
export function validateHeartbeatPromptTemplate(value: unknown): HeartbeatPromptTemplate | undefined {
if (value === undefined) {
return undefined;
}
if (typeof value !== "string") {
return undefined;
}
return (HEARTBEAT_PROMPT_TEMPLATES as readonly string[]).includes(value)
? (value as HeartbeatPromptTemplate)
: undefined;
}
/** Returns a validated sandbox backend name for project settings, otherwise undefined. */
export function validateSandboxBackendName(value: unknown): SandboxBackendName | undefined {
if (value === undefined) {
return undefined;
}
if (typeof value !== "string") {
return undefined;
}
return (SANDBOX_BACKEND_NAMES as readonly string[]).includes(value) ? (value as SandboxBackendName) : undefined;
}
/** Returns a validated sandbox failure mode for project settings, otherwise undefined. */
export function validateSandboxFailureMode(value: unknown): SandboxFailureMode | undefined {
if (value === undefined) {
return undefined;
}
if (typeof value !== "string") {
return undefined;
}
return (SANDBOX_FAILURE_MODES as readonly string[]).includes(value) ? (value as SandboxFailureMode) : undefined;
}
/** Returns a validated sandbox policy object for project settings, otherwise undefined. */
export function validateSandboxPolicy(value: unknown): SandboxPolicy | undefined {
if (value === undefined || value === null || Array.isArray(value) || typeof value !== "object") {
return undefined;
}
const raw = value as { allowNetwork?: unknown; allowedPaths?: unknown };
const policy: SandboxPolicy = {};
if (typeof raw.allowNetwork === "boolean") {
policy.allowNetwork = raw.allowNetwork;
}
if (Array.isArray(raw.allowedPaths)) {
const candidatePaths = raw.allowedPaths;
const hasOnlyValidPaths = candidatePaths.every(
(entry) => typeof entry === "string" && entry.length > 0 && !entry.includes("..") && !entry.startsWith("~"),
);
if (hasOnlyValidPaths) {
policy.allowedPaths = candidatePaths as string[];
}
}
if (policy.allowNetwork === undefined && policy.allowedPaths === undefined) {
return undefined;
}
return policy;
}
/** Returns validated sandbox project settings, otherwise undefined. */
export function validateSandboxProjectSettings(value: unknown): SandboxProjectSettings | undefined {
if (value === undefined || value === null || Array.isArray(value) || typeof value !== "object") {
return undefined;
}
const raw = value as {
backend?: unknown;
policy?: unknown;
failureMode?: unknown;
};
const backend = validateSandboxBackendName(raw.backend);
const policy = validateSandboxPolicy(raw.policy);
const failureMode = validateSandboxFailureMode(raw.failureMode);
if (backend === undefined && policy === undefined && failureMode === undefined) {
return undefined;
}
return {
...(backend !== undefined ? { backend } : {}),
...(policy !== undefined ? { policy } : {}),
...(failureMode !== undefined ? { failureMode } : {}),
};
}