// Gestión de templates persistentes import { readFile, writeFile, mkdir } from 'fs/promises' import { existsSync } from 'fs' import { join } from 'path' export interface Operation { op: string [key: string]: any } export interface TemplateVariable { name: string label?: string defaultValue?: string } export interface PrintTemplate { id: string name: string description?: string operations: Operation[] variables: TemplateVariable[] createdAt: string updatedAt: string } // Regex para detectar {{nombre}}, {{nombre:label}}, {{nombre:label:default}} const VARIABLE_REGEX = /\{\{(\w+)(?::([^:}]+))?(?::([^}]+))?\}\}/g // Extraer variables de las operaciones export function extractVariables(operations: Operation[]): TemplateVariable[] { const variablesMap = new Map() for (const op of operations) { // Buscar en campos que pueden contener variables const searchFields = ['value', 'data'] for (const field of searchFields) { if (typeof op[field] === 'string') { const matches = op[field].matchAll(VARIABLE_REGEX) for (const match of matches) { const [, name, label, defaultValue] = match // Solo guardar la primera definición de cada variable if (!variablesMap.has(name)) { variablesMap.set(name, { name, label: label || undefined, defaultValue: defaultValue || undefined }) } } } } } return Array.from(variablesMap.values()) } // Resolver variables en operaciones reemplazando {{nombre}} con valores export function resolveVariables( operations: Operation[], values: Record = {} ): Operation[] { return JSON.parse(JSON.stringify(operations)).map((op: Operation) => { for (const [key, val] of Object.entries(op)) { if (typeof val === 'string') { op[key] = val.replace(VARIABLE_REGEX, (_, name) => values[name] ?? '') } } return op }) } export interface TemplatesStore { templates: PrintTemplate[] } // Directorio de datos persistentes const DATA_DIR = join(process.cwd(), 'data') const TEMPLATES_FILE = join(DATA_DIR, 'templates.json') // Asegurar que el directorio existe async function ensureDataDir(): Promise { if (!existsSync(DATA_DIR)) { await mkdir(DATA_DIR, { recursive: true }) } } // Leer store de templates export async function readTemplatesStore(): Promise { await ensureDataDir() try { const data = await readFile(TEMPLATES_FILE, 'utf-8') return JSON.parse(data) } catch { // Si no existe el archivo, retornar store vacío return { templates: [] } } } // Guardar store de templates export async function writeTemplatesStore(store: TemplatesStore): Promise { await ensureDataDir() await writeFile(TEMPLATES_FILE, JSON.stringify(store, null, 2), 'utf-8') } // Generar ID único function generateId(): string { return `template_${Date.now()}_${Math.random().toString(36).substring(2, 9)}` } // CRUD Operations export async function getAllTemplates(): Promise { const store = await readTemplatesStore() return store.templates } export async function getTemplateById(id: string): Promise { const store = await readTemplatesStore() return store.templates.find(t => t.id === id) || null } export async function createTemplate(data: { name: string description?: string operations: Operation[] }): Promise { const store = await readTemplatesStore() const now = new Date().toISOString() const template: PrintTemplate = { id: generateId(), name: data.name, description: data.description || '', operations: data.operations, variables: extractVariables(data.operations), createdAt: now, updatedAt: now } store.templates.push(template) await writeTemplatesStore(store) return template } export async function updateTemplate(id: string, data: Partial<{ name: string description: string operations: Operation[] }>): Promise { const store = await readTemplatesStore() const index = store.templates.findIndex(t => t.id === id) if (index === -1) return null // Si se actualizan las operaciones, recalcular las variables const variables = data.operations ? extractVariables(data.operations) : store.templates[index].variables store.templates[index] = { ...store.templates[index], ...data, variables, updatedAt: new Date().toISOString() } await writeTemplatesStore(store) return store.templates[index] } export async function deleteTemplate(id: string): Promise { const store = await readTemplatesStore() const index = store.templates.findIndex(t => t.id === id) if (index === -1) return false store.templates.splice(index, 1) await writeTemplatesStore(store) return true } export async function duplicateTemplate(id: string): Promise { const template = await getTemplateById(id) if (!template) return null return createTemplate({ name: `${template.name} (copia)`, description: template.description, operations: JSON.parse(JSON.stringify(template.operations)) }) }