fuzzyworld

word-waltz / files / src / types.ts

types.ts

Blame: the commit that last changed each line · file · history

f755bca6 2026-03-23 Pavel Safronov1/**
2 * types.ts — shared game-state types
3 *
4 * These types mirror the Firestore document structure described in AGENTS.md.
5 * The Firestore document contains only { iv, ciphertext, lastPlayed }.
6 * Everything below lives inside the decrypted ciphertext.
7 */
8
9export type PlayerId = 'a' | 'b';
10
11export interface Player {
a0df624b 2026-03-23 Pavel Safronov12 name: string;
13 score: number;
f755bca6 2026-03-23 Pavel Safronov14}
15
16export interface Round {
a0df624b 2026-03-23 Pavel Safronov17 challenger: PlayerId;
18 word: string;
19 guesses: string[];
20 solved: boolean;
21 score: number;
f755bca6 2026-03-23 Pavel Safronov22}
23
24export interface GameState {
a0df624b 2026-03-23 Pavel Safronov25 players: Record<PlayerId, Player>;
26 rounds: Round[];
27 currentRound: number;
28 turn: 'pick' | 'solve';
29 createdAt: number;
30 updatedAt: number;
f755bca6 2026-03-23 Pavel Safronov31}
32
8008bb36 2026-03-26 Pavel Safronov33// ---------------------------------------------------------------------------
34// Solo mode — stored locally in localStorage, no Firestore involved.
35// ---------------------------------------------------------------------------
36
37export interface SoloRound {
38 word: string;
39 guesses: string[];
40 solved: boolean;
41 score: number;
42}
43
44export interface SoloGameState {
45 playerName: string;
46 totalScore: number;
47 rounds: SoloRound[];
48 /** Index of the round currently being played (last element of rounds[]). */
49 currentRound: number;
50 createdAt: number;
51 updatedAt: number;
52}
53
51cb47e7 2026-03-26 Pavel Safronov54// ---------------------------------------------------------------------------
55// Push notifications — stored in plaintext alongside the encrypted envelope.
56//
57// pushSubs: each player's Web Push subscription JSON, stored so the Cloud
58// Function can send a push without decrypting the game state.
59//
60// pendingNotification: written by the acting player when the turn changes;
61// consumed (and cleared) by the Cloud Function to fire the push.
62// The gameUrl intentionally omits the #key fragment so the encryption key
63// is never stored in Firestore — the recipient's device already has it in
64// localStorage, and the notification click opens the home screen.
65// ---------------------------------------------------------------------------
66
67export interface PendingNotification {
68 player: PlayerId;
69 message: string;
70 /** Base URL of the app (e.g. https://host/word-waltz/) — no key. */
71 gameUrl: string;
72}
73
74/** Firestore document fields added by the push notification layer. */
75export interface PushFields {
76 /** JSON-serialized PushSubscription per player (may be absent). */
77 pushSubs?: { a?: string | null; b?: string | null };
78 /** Set by the acting player; consumed + cleared by the Cloud Function. */
79 pendingNotification?: PendingNotification | null;
80}
81
82/** The shape stored in Firestore (encrypted envelope + plaintext fields). */
83export interface EncryptedEnvelope extends PushFields {
a0df624b 2026-03-23 Pavel Safronov84 iv: string;
85 ciphertext: string;
86 lastPlayed: number;
f755bca6 2026-03-23 Pavel Safronov87}
88
89/** The encrypted part only — passed in by callers of createGame / updateGame. */
51cb47e7 2026-03-26 Pavel Safronov90export type Encrypted = Pick<EncryptedEnvelope, 'iv' | 'ciphertext'>;