import type { DeploymentRole } from '@/lib/config/deployment-role'; export const SERVER_MANAGED_PROVIDER_REQUIRED_MESSAGE = 'This deployment only permits providers configured by the server operator.'; export type ProviderAccessDecision = | { allowed: true; /** Managed credentials and endpoints are authoritative over client input. */ acceptClientConfiguration: boolean; } | { allowed: false; reason: 'server-managed-provider-required'; }; /** * Pure deployment policy for provider-backed network calls. * * A dedicated public server must never turn a caller-supplied key/base URL into * an outbound request. Other roles keep the desktop/operations BYOK behaviour, * while an operator-configured provider remains authoritative in every role. */ export function decideProviderAccess( role: DeploymentRole, isServerConfigured: boolean, ): ProviderAccessDecision { if (role === 'server' && !isServerConfigured) { return { allowed: false, reason: 'server-managed-provider-required' }; } return { allowed: true, acceptClientConfiguration: !isServerConfigured, }; } export class ServerManagedProviderRequiredError extends Error { readonly statusCode = 403; readonly errorCode = 'FORBIDDEN'; constructor() { super(SERVER_MANAGED_PROVIDER_REQUIRED_MESSAGE); this.name = 'ServerManagedProviderRequiredError'; } } export function assertProviderAccess( role: DeploymentRole, isServerConfigured: boolean, ): Extract { const decision = decideProviderAccess(role, isServerConfigured); if (!decision.allowed) { throw new ServerManagedProviderRequiredError(); } return decision; } export function isServerManagedProviderRequiredError( error: unknown, ): error is ServerManagedProviderRequiredError { return error instanceof ServerManagedProviderRequiredError; }