import type { ResultsSnapshot } from '../src/types/screen.js' function object(value: unknown): Record { if (!value || typeof value !== 'object' || Array.isArray(value)) throw new Error('Некорректный снимок результатов') return value as Record } function list(value: unknown): unknown[] { if (!Array.isArray(value)) throw new Error('Некорректный список результатов') return value } function text(value: unknown): string { if (typeof value !== 'string') throw new Error('Некорректный текст результатов') return value } function integer(value: unknown, minimum = -2147483648): number { if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < minimum) throw new Error('Некорректное число результатов') return value } // Сохраняем только поля публичной таблицы, без участников, паролей и токенов. export function parseResults(value: unknown, packageKey: string): ResultsSnapshot { const data = object(value) if (data.packageKey !== packageKey || !/^[a-f0-9]{64}$/.test(packageKey)) throw new Error('Результаты относятся к другой игре') const captured = Date.parse(text(data.capturedAt)) if (!Number.isFinite(captured)) throw new Error('Некорректное время снимка результатов') const questions = list(data.questions).map((value) => { const q = object(value) return { code: text(q.code), text: text(q.text) } }) const codes = new Set(questions.map((q) => q.code)) if (codes.size !== questions.length || codes.has('')) throw new Error('Повтор или отсутствие кода вопроса') const teams = list(data.teams).map((value) => { const team = object(value) const answers = list(team.answers).map((value) => { const a = object(value) return { questionCode: text(a.questionCode), score: integer(a.score) } }) if ( new Set(answers.map((a) => a.questionCode)).size !== answers.length || answers.some((a) => !codes.has(a.questionCode)) ) throw new Error('Некорректные ответы результатов') return { id: text(team.id), name: text(team.name), place: integer(team.place, 1), totalScore: integer(team.totalScore), actionsCount: integer(team.actionsCount, 0), answers, } }) if (teams.some((team) => !team.id) || new Set(teams.map((t) => t.id)).size !== teams.length) throw new Error('Повтор или отсутствие команды') return { packageKey, capturedAt: new Date(captured).toISOString(), questions, teams } }