import { buildDemoStringPreview, formatDemoDurationFromMillis, type DemoWorkspaceKey, } from "./demo-workspace"; export type AddKeyDraft = { name: string; value: string; ttlMillis: string; }; export type AddKeyDraftErrors = Partial>; export function validateAddKeyDraft(draft: AddKeyDraft): AddKeyDraftErrors { const errors: AddKeyDraftErrors = {}; if (!draft.name.trim()) { errors.name = "Redis key name must not be empty."; } const ttlValue = draft.ttlMillis.trim(); if (ttlValue) { if (!/^\d+$/.test(ttlValue)) { errors.ttlMillis = "TTL must be an integer number of milliseconds when provided."; } else if (Number.parseInt(ttlValue, 10) <= 0) { errors.ttlMillis = "TTL must be greater than zero when provided."; } } return errors; } export function parseOptionalTtlMillis(value: string) { const normalized = value.trim(); if (!normalized) { return null; } const parsed = Number.parseInt(normalized, 10); return Number.isFinite(parsed) ? parsed : null; } export function findDuplicateKeyName( keys: T[], keyName: string, ) { const normalized = keyName.trim(); return keys.some((key) => key.name === normalized); } export function createDemoKeyRecord(draft: AddKeyDraft): DemoWorkspaceKey { const keyName = draft.name.trim(); const ttlMillis = parseOptionalTtlMillis(draft.ttlMillis); return { id: keyName, name: keyName, type: "string", ttl: ttlMillis === null ? "persistent" : formatDemoDurationFromMillis(ttlMillis), preview: buildDemoStringPreview(draft.value), editable: true, value: draft.value, summary: "String-only Add Key flow stays aligned to the bounded create contract and keeps the new key visible in the current workspace scope.", }; }