feat: fase 2+3 — expansion masiva multi-perfil + bug fixes + hardening
Fase 2 (expansion): - Francesca: +6 etapas matematicas (5-10), +7 etapas lectura (3-9), +2 ortografia - Sebastian: +8 etapas matematicas (4-11), +6 lectura, +3 historia, +3 geografia, +1 banderas - Nuevas paginas: ortografia, lectura, geografia, matematicas - ~900 ejercicios nuevos, paridad ~500 por perfil Fase 3 (bug fixes + hardening): - Fix: SessionLog auto-create en grade route - Fix: engine cache (no borrar antes de revisar) - Fix: FSRS cards actualizadas en flujo curriculum - Fix: responseMs real (no hardcodeado 3000) - Fix: options dentro de content en sebastian etapa-1 - Fix: trazo-letra consonantes crash - Security: execFileSync anti-command-injection en TTS - DB: 18 cascade deletes + indices + unique constraints - APIs debug: reset, state, seed - Docker: espeak-ng + prisma + user/group - E2E: 23 tests nuevos (curriculum-flow.spec.ts) - Code review: tailwind colors, middleware dev mode, eslint config Verificado: tsc exit 0, build exit 0, 61 E2E tests pass
This commit is contained in:
+13
-5
@@ -1,5 +1,5 @@
|
||||
import { NextRequest, NextResponse } from "next/server"
|
||||
import { execSync } from "child_process"
|
||||
import { execFileSync } from "child_process"
|
||||
import { existsSync, mkdirSync } from "fs"
|
||||
import { createHash } from "crypto"
|
||||
import { readFile, mkdir } from "fs/promises"
|
||||
@@ -24,15 +24,23 @@ export async function GET(request: NextRequest) {
|
||||
return NextResponse.json({ error: "text param required (max 200 chars)" }, { status: 400 })
|
||||
}
|
||||
|
||||
// Sanitize: only allow alphanumeric, spaces, and common punctuation
|
||||
if (!/^[\w\sáéíóúñüÁÉÍÓÚÑÜ.,;:!¿?¡()\-]+$/.test(text)) {
|
||||
return NextResponse.json({ error: "Invalid text characters" }, { status: 400 })
|
||||
}
|
||||
|
||||
await ensureCacheDir()
|
||||
const cachePath = getCachePath(text)
|
||||
|
||||
if (!existsSync(cachePath)) {
|
||||
try {
|
||||
execSync(
|
||||
`espeak-ng -v es-mx -s 140 -p 60 "${text.replace(/"/g, '\\"')}" -w "${cachePath}"`,
|
||||
{ timeout: 10000 },
|
||||
)
|
||||
execFileSync("espeak-ng", [
|
||||
"-v", "es-mx",
|
||||
"-s", "140",
|
||||
"-p", "60",
|
||||
"-w", cachePath,
|
||||
text,
|
||||
], { timeout: 10000 })
|
||||
} catch {
|
||||
return NextResponse.json({ error: "TTS generation failed" }, { status: 500 })
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user