export const VIP98K_RUNTIME_CONFIG_KEY = "vip98k_runtime_config"; export type Vip98kRuntimeConfig = { submissionTimeoutMs: number; modelSubmissionTimeoutMs: Record; maxSubmissionAttempts: number; submissionRetryBaseDelayMs: number; referenceCacheTtlMs: number; referenceCacheMaxEntries: number; }; export const defaultVip98kRuntimeConfig: Vip98kRuntimeConfig = { submissionTimeoutMs: 120_000, modelSubmissionTimeoutMs: { "nano-banana-pro": 240_000, }, maxSubmissionAttempts: 3, submissionRetryBaseDelayMs: 5_000, referenceCacheTtlMs: 7 * 24 * 60 * 60 * 1000, referenceCacheMaxEntries: 2_000, }; function clampInteger( value: unknown, fallback: number, minimum: number, maximum: number, ) { const numeric = Number(value); if (!Number.isFinite(numeric)) return fallback; return Math.min(maximum, Math.max(minimum, Math.round(numeric))); } function normalizeModelTimeouts(value: unknown) { const configured = value && typeof value === "object" && !Array.isArray(value) ? (value as Record) : {}; const normalized: Record = { ...defaultVip98kRuntimeConfig.modelSubmissionTimeoutMs, }; for (const [modelId, timeout] of Object.entries(configured)) { const normalizedModelId = modelId.trim().toLowerCase(); if (!normalizedModelId || normalizedModelId.length > 160) continue; normalized[normalizedModelId] = clampInteger( timeout, defaultVip98kRuntimeConfig.submissionTimeoutMs, 30_000, 10 * 60_000, ); } return normalized; } export function normalizeVip98kRuntimeConfig(value: unknown): Vip98kRuntimeConfig { const raw = value && typeof value === "object" && !Array.isArray(value) ? (value as Record) : {}; return { submissionTimeoutMs: clampInteger( raw.submissionTimeoutMs, defaultVip98kRuntimeConfig.submissionTimeoutMs, 30_000, 10 * 60_000, ), modelSubmissionTimeoutMs: normalizeModelTimeouts( raw.modelSubmissionTimeoutMs, ), maxSubmissionAttempts: clampInteger( raw.maxSubmissionAttempts, defaultVip98kRuntimeConfig.maxSubmissionAttempts, 1, 5, ), submissionRetryBaseDelayMs: clampInteger( raw.submissionRetryBaseDelayMs, defaultVip98kRuntimeConfig.submissionRetryBaseDelayMs, 1_000, 60_000, ), referenceCacheTtlMs: clampInteger( raw.referenceCacheTtlMs, defaultVip98kRuntimeConfig.referenceCacheTtlMs, 5 * 60_000, 30 * 24 * 60 * 60_000, ), referenceCacheMaxEntries: clampInteger( raw.referenceCacheMaxEntries, defaultVip98kRuntimeConfig.referenceCacheMaxEntries, 100, 10_000, ), }; } export function resolveVip98kSubmissionTimeoutMs( modelId: string, config: Vip98kRuntimeConfig, ) { return ( config.modelSubmissionTimeoutMs[modelId.trim().toLowerCase()] || config.submissionTimeoutMs ); }