export type PromptSequenceCharacter = { id: string name: string description: string } export type PromptSequenceScene = { id: string title: string style: string settings: string characters: PromptSequenceCharacter[] prompt: string } export type PromptSequence = { id: string name: string scenes: PromptSequenceScene[] createdAt: number updatedAt: number } export const PROMPT_SEQUENCE_NAME_MAX = 80 export const PROMPT_SEQUENCE_FIELD_MAX = 50_000 export const PROMPT_SEQUENCE_TITLE_MAX = 60 export { newId, emptyCharacter, emptyScene, cloneSceneForNext, formatCharacterLine, assembleSceneText, assembleSequenceText } from '../shared/prompt-sequences.mjs' import { newId, emptyCharacter, emptyScene } from '../shared/prompt-sequences.mjs' export function normalizePromptSequenceName(raw: unknown) { return String(raw || '').trim().replace(/\s+/g, ' ').slice(0, PROMPT_SEQUENCE_NAME_MAX) } export function normalizePromptSequenceField(raw: unknown) { return String(raw || '').replace(/\r\n/g, '\n').slice(0, PROMPT_SEQUENCE_FIELD_MAX) } export function normalizePromptSequenceTitle(raw: unknown, fallback: string) { const title = String(raw || '').trim().replace(/\s+/g, ' ').slice(0, PROMPT_SEQUENCE_TITLE_MAX) return title || fallback } export function normalizeCharacter(raw: unknown): PromptSequenceCharacter { const rec = (raw && typeof raw === 'object' ? raw : {}) as Record return { id: String(rec.id || '').trim() || newId(), name: String(rec.name || '').trim().slice(0, 120), description: normalizePromptSequenceField(rec.description).trim() } } export function normalizeScene(raw: unknown, index: number): PromptSequenceScene { const rec = (raw && typeof raw === 'object' ? raw : {}) as Record const characters = Array.isArray(rec.characters) ? rec.characters.map(normalizeCharacter) : [emptyCharacter()] return { id: String(rec.id || '').trim() || newId(), title: normalizePromptSequenceTitle(rec.title, `Scene ${index + 1}`), style: normalizePromptSequenceField(rec.style), settings: normalizePromptSequenceField(rec.settings), characters: characters.length ? characters : [emptyCharacter()], prompt: normalizePromptSequenceField(rec.prompt) } } export function normalizePromptSequence(raw: unknown): PromptSequence | null { if (!raw || typeof raw !== 'object') return null const rec = raw as Record const name = normalizePromptSequenceName(rec.name) if (!name) return null const scenesRaw = Array.isArray(rec.scenes) ? rec.scenes : [] const scenes = scenesRaw.map((scene, index) => normalizeScene(scene, index)) const createdAt = Number(rec.createdAt) || Date.now() return { id: String(rec.id || '').trim() || newId(), name, scenes: scenes.length ? scenes : [emptyScene(1)], createdAt, updatedAt: Number(rec.updatedAt) || createdAt } }