test: complete persistence and browser safety net

This commit is contained in:
2026-08-14 13:43:37 +02:00
parent 9a4da41b49
commit 545eb013bd
14 changed files with 392 additions and 120 deletions
+9 -3
View File
@@ -30,6 +30,12 @@ function wantsEdit(req: express.Request) {
return editingEnabled && req.query.edit === '1'
}
function isoTimestamp(value: unknown) {
if (!value) return undefined
const parsed = new Date(String(value))
return Number.isFinite(parsed.getTime()) ? parsed.toISOString() : undefined
}
async function assembleLevel(levelId: string, playthroughId = `default:${levelId}`, authorMode = false): Promise<CaseState | null> {
const levelResult = await pool.query<{ id: string; title: string; subtitle: string; status: string }>(
'SELECT id, title, subtitle, status FROM osint.levels WHERE id = $1', [levelId],
@@ -72,8 +78,8 @@ async function assembleLevel(levelId: string, playthroughId = `default:${levelId
])
const stateByWidget = new Map(authorMode ? [] : stateResult.rows.map(row => [row.widget_id, row]))
const documents: CaseDocument[] = widgetsResult.rows.filter(w => w.widget_type === 'document').map(w => { const override = stateByWidget.get(w.id)?.config || {}; const publishedAt = String(override.publishedAt || w.published_at || ''); return ({
id: w.id, title: String(override.title || w.title), kind: w.config.kind || 'DOCUMENT', date: publishedAt.slice(0, 10) || w.config.date || '', publishedAt: publishedAt || undefined,
const documents: CaseDocument[] = widgetsResult.rows.filter(w => w.widget_type === 'document').map(w => { const override = stateByWidget.get(w.id)?.config || {}; const publishedAt = isoTimestamp(override.publishedAt || w.published_at); return ({
id: w.id, title: String(override.title || w.title), kind: w.config.kind || 'DOCUMENT', date: publishedAt?.slice(0, 10) || w.config.date || '', publishedAt,
body: w.config.body || [], fileType: (override.fileType || w.config.fileType || (w.mime_type?.startsWith('image/') ? 'image' : 'file')) as CaseDocument['fileType'], metadata: (override.metadata || w.config.metadata || {}) as Record<string, string>,
assetId: w.asset_id, fileName: w.original_name, mimeType: w.mime_type, fileSize: w.byte_size,
regions: regionsResult.rows.filter(r => r.document_widget_id === w.id).map(r => ({ id: r.region_key, label: r.label, excerpt: r.excerpt, date: r.event_date })),
@@ -291,7 +297,7 @@ if (fs.existsSync(dist)) { app.use(express.static(dist)); app.get('*splat', (_re
const port = Number(process.env.PORT || 8787)
export const server = app.listen(port, '0.0.0.0', () => console.log(`GUPI OSINT Board listening on http://localhost:${port}`))
async function shutdown() { server.close(); await pool.end(); process.exit(0) }
if (!process.env.VITEST) {
if (!process.env.VITEST && process.env.OSINT_MANAGED_SERVER !== 'true') {
process.on('SIGTERM', shutdown)
process.on('SIGINT', shutdown)
}