import type { SCUMMigrationRecord, SCUMPlayer, SCUMTrajectory, SCUMTrajectoryPoint } from "./contracts.js"; export function transitionalReadOnly>(payload: T, recordedAt: string, sourceRecordId?: string): SCUMMigrationRecord { return { provenance: "transitional-read-only", payload, recordedAt, sourceRecordId }; } export function pluginOwned>(payload: T, recordedAt: string): SCUMMigrationRecord { return { provenance: "plugin", payload, recordedAt }; } export function migratePlayerRecord(record: Record): SCUMMigrationRecord | null { const id = text(record.id); const gamePlayerId = text(record.gamePlayerId); const displayName = text(record.displayName); if (!id || !gamePlayerId || !displayName) return null; return transitionalReadOnly({ id, gamePlayerId, displayName, lastSeenAt: optionalText(record.lastSeenAt), status: record.online === true ? "online" : "unknown" }, optionalText(record.updatedAt) ?? new Date(0).toISOString(), id); } export function migrateTrajectoryRecord(record: Record): SCUMTrajectory | null { const subjectId = text(record.playerRecordId) ?? text(record.vehicleId); const subjectType = text(record.playerRecordId) ? "player" : "vehicle"; const points = Array.isArray(record.points) ? record.points.map(migratePoint).filter((point): point is SCUMTrajectoryPoint => point !== null) : []; return subjectId && points.length ? { subjectId, subjectType, points, provenance: "transitional-read-only" } : null; } function migratePoint(value: unknown): SCUMTrajectoryPoint | null { if (!value || typeof value !== "object") return null; const record = value as Record; const x = number(record.mapX) ?? number(record.worldX); const y = number(record.mapY) ?? number(record.worldY); const occurredAt = text(record.recordedAt) ?? text(record.occurredAt); if (x === undefined || y === undefined || !occurredAt) return null; return { occurredAt, subjectId: text(record.playerRecordId) ?? text(record.vehicleId) ?? "unknown", subjectType: text(record.playerRecordId) ? "player" : "vehicle", x, y, z: number(record.worldZ), source: "transitional-read-only" }; } function text(value: unknown): string | undefined { return typeof value === "string" && value.trim() ? value : undefined; } function optionalText(value: unknown): string | undefined { return text(value); } function number(value: unknown): number | undefined { return typeof value === "number" && Number.isFinite(value) ? value : undefined; }