712086ddca
Показ анимации кубиков игрокам, закрытие оверлеев с окнами, ручной ввод количества, меньший радиус кисти, блок спонсоров в «О программе»; плюс черновик game systems / character sheet. Co-authored-by: Cursor <cursoragent@cursor.com>
35 lines
1020 B
TypeScript
35 lines
1020 B
TypeScript
import { createHash } from 'node:crypto';
|
|
|
|
import type { SystemDefinition } from './types';
|
|
|
|
/** Canonical JSON for stable hashing (sorted keys). */
|
|
export function canonicalJson(value: unknown): string {
|
|
return JSON.stringify(sortKeys(value));
|
|
}
|
|
|
|
function sortKeys(value: unknown): unknown {
|
|
if (Array.isArray(value)) return value.map(sortKeys);
|
|
if (value && typeof value === 'object') {
|
|
const obj = value as Record<string, unknown>;
|
|
const out: Record<string, unknown> = {};
|
|
for (const key of Object.keys(obj).sort()) {
|
|
out[key] = sortKeys(obj[key]);
|
|
}
|
|
return out;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
export function snapshotHash(system: SystemDefinition): string {
|
|
const payload = {
|
|
id: system.id,
|
|
schemaVersion: system.schemaVersion,
|
|
revision: system.revision,
|
|
bricks: system.bricks,
|
|
creationRules: system.creationRules,
|
|
sheetLayout: system.sheetLayout,
|
|
compendium: system.compendium,
|
|
};
|
|
return createHash('sha256').update(canonicalJson(payload)).digest('hex');
|
|
}
|