fuzzyworld

word-waltz / commit

missing files

a0df624b260cdb11f1a554f335b5e4645804a9cc · Pavel Safronov · 2026-03-23 16:46:29 -0700 · parents f755bca6cbef

missing files
 README.md                     | 30 +++++++++++-----------
 cspell.json                   | 44 ++++++++++++++++----------------
 package.json                  |  2 +-
 scripts/cleanup-old-games.js  | 58 +++++++++++++++++++++----------------------
 src/components/Keyboard.ts    |  2 +-
 src/components/Scoreboard.ts  |  2 +-
 src/components/ShareDialog.ts |  2 +-
 src/components/WordPicker.ts  |  2 +-
 src/components/WordleBoard.ts |  2 +-
 src/firebase/gameService.ts   |  2 +-
 src/index.html                | 13 ++++++----
 src/styles/main.css           |  2 +-
 src/types.ts                  | 32 ++++++++++++------------
 tsconfig.json                 | 43 +++++++++++++++++---------------
 14 files changed, 121 insertions(+), 115 deletions(-)

diff --git a/README.md b/README.md
index d86988c..8bb6eaa 100644
--- a/README.md
+++ b/README.md
@@ -16,14 +16,14 @@ A two-player, asynchronous Wordle duel. You challenge your opponent with a secre
 
 ## Tech stack
 
-| Concern | Tool |
-| --- | --- |
-| Build | [Vite](https://vitejs.dev/) (static output) |
-| Hosting | [GitLab Pages](https://docs.gitlab.com/ee/user/project/pages/) |
+| Concern      | Tool                                                             |
+| ------------ | ---------------------------------------------------------------- |
+| Build        | [Vite](https://vitejs.dev/) (static output)                      |
+| Hosting      | [GitLab Pages](https://docs.gitlab.com/ee/user/project/pages/)   |
 | Game storage | [Firebase Firestore](https://firebase.google.com/docs/firestore) |
-| Encryption | Web Crypto API (AES-GCM, 256-bit) |
-| QR codes | [qrcode](https://www.npmjs.com/package/qrcode) |
-| Language | TypeScript (strict mode, ES modules) |
+| Encryption   | Web Crypto API (AES-GCM, 256-bit)                                |
+| QR codes     | [qrcode](https://www.npmjs.com/package/qrcode)                   |
+| Language     | TypeScript (strict mode, ES modules)                             |
 
 ## Security model — URL-keyed encryption
 
@@ -48,14 +48,14 @@ https://your-app.gitlab.io/game/#gameId=xxxx&key=base64encodedkey
 ## Scoring
 
 | Guesses taken | Points |
-| --- | --- |
-| 1 | 6 |
-| 2 | 5 |
-| 3 | 4 |
-| 4 | 3 |
-| 5 | 2 |
-| 6 | 1 |
-| Failed (> 6) | 0 |
+| ------------- | ------ |
+| 1             | 6      |
+| 2             | 5      |
+| 3             | 4      |
+| 4             | 3      |
+| 5             | 2      |
+| 6             | 1      |
+| Failed (> 6)  | 0      |
 
 Scores accumulate across rounds. There is no set game length — keep playing as long as you like.
 
diff --git a/cspell.json b/cspell.json
index ed76067..705bdef 100644
--- a/cspell.json
+++ b/cspell.json
@@ -1,23 +1,23 @@
 {
-  "$schema": "https://raw.githubusercontent.com/streetsidesoftware/cspell/main/packages/cspell-types/cspell.schema.json",
-  "version": "0.2",
-  "language": "en",
-  "words": [
-    "ciphertext",
-    "Firestore",
-    "firestore",
-    "firebaseapp",
-    "firebasestorage",
-    "idempotent",
-    "initialisation",
-    "qrcode",
-    "serialisation",
-    "unencrypted",
-    "Wordle"
-  ],
-  "ignorePaths": [
-    "node_modules",
-    "dist",
-    "package-lock.json"
-  ]
-}
+    "$schema": "https://raw.githubusercontent.com/streetsidesoftware/cspell/main/packages/cspell-types/cspell.schema.json",
+    "version": "0.2",
+    "language": "en",
+    "words": [
+        "ciphertext",
+        "Firestore",
+        "firestore",
+        "firebaseapp",
+        "firebasestorage",
+        "idempotent",
+        "initialisation",
+        "qrcode",
+        "serialisation",
+        "unencrypted",
+        "Wordle"
+    ],
+    "ignorePaths": [
+        "node_modules",
+        "dist",
+        "package-lock.json"
+    ]
+}
\ No newline at end of file
diff --git a/package.json b/package.json
index 94c6103..60398f2 100644
--- a/package.json
+++ b/package.json
@@ -22,4 +22,4 @@
     "typescript": "^6.0.2",
     "vite": "^5.2.0"
   }
-}
+}
\ No newline at end of file
diff --git a/scripts/cleanup-old-games.js b/scripts/cleanup-old-games.js
index 0e9714a..5dfe179 100644
--- a/scripts/cleanup-old-games.js
+++ b/scripts/cleanup-old-games.js
@@ -22,12 +22,12 @@ const RETENTION_DAYS = 30;
 const BATCH_SIZE = 500; // Firestore max batch-write size
 
 function requireEnv(name) {
-  const value = process.env[name];
-  if (!value) {
-    console.error(`Error: required environment variable "${name}" is not set.`);
-    process.exit(1);
-  }
-  return value;
+    const value = process.env[name];
+    if (!value) {
+        console.error(`Error: required environment variable "${name}" is not set.`);
+        process.exit(1);
+    }
+    return value;
 }
 
 const serviceAccount = JSON.parse(requireEnv('FIREBASE_SERVICE_ACCOUNT_JSON'));
@@ -39,35 +39,35 @@ const db = getFirestore();
 const cutoffMs = Date.now() - RETENTION_DAYS * 24 * 60 * 60 * 1000;
 
 async function deleteOldGames() {
-  console.log(
-    `Querying for games with lastPlayed < ${new Date(cutoffMs).toISOString()} ` +
-    `(older than ${RETENTION_DAYS} days)…`
-  );
+    console.log(
+        `Querying for games with lastPlayed < ${new Date(cutoffMs).toISOString()} ` +
+        `(older than ${RETENTION_DAYS} days)…`
+    );
 
-  const snapshot = await db
-    .collection('games')
-    .where('lastPlayed', '<', cutoffMs)
-    .get();
+    const snapshot = await db
+        .collection('games')
+        .where('lastPlayed', '<', cutoffMs)
+        .get();
 
-  if (snapshot.empty) {
-    console.log('No stale games found. Nothing to delete.');
-    return;
-  }
+    if (snapshot.empty) {
+        console.log('No stale games found. Nothing to delete.');
+        return;
+    }
 
-  console.log(`Found ${snapshot.size} stale game(s). Deleting in batches…`);
+    console.log(`Found ${snapshot.size} stale game(s). Deleting in batches…`);
 
-  const docs = snapshot.docs;
-  for (let i = 0; i < docs.length; i += BATCH_SIZE) {
-    const batch = db.batch();
-    docs.slice(i, i + BATCH_SIZE).forEach((doc) => batch.delete(doc.ref));
-    await batch.commit();
-    console.log(`  Deleted ${Math.min(i + BATCH_SIZE, docs.length)} / ${docs.length}`);
-  }
+    const docs = snapshot.docs;
+    for (let i = 0; i < docs.length; i += BATCH_SIZE) {
+        const batch = db.batch();
+        docs.slice(i, i + BATCH_SIZE).forEach((doc) => batch.delete(doc.ref));
+        await batch.commit();
+        console.log(`  Deleted ${Math.min(i + BATCH_SIZE, docs.length)} / ${docs.length}`);
+    }
 
-  console.log('Cleanup complete.');
+    console.log('Cleanup complete.');
 }
 
 deleteOldGames().catch((err) => {
-  console.error('Cleanup failed:', err);
-  process.exit(1);
+    console.error('Cleanup failed:', err);
+    process.exit(1);
 });
diff --git a/src/components/Keyboard.ts b/src/components/Keyboard.ts
index 11f6b08..8bcfa70 100644
--- a/src/components/Keyboard.ts
+++ b/src/components/Keyboard.ts
@@ -16,5 +16,5 @@ interface KeyboardProps {
 // TODO: implement keyboard layout and coloring
 export function mountKeyboard(container: HTMLElement, props: KeyboardProps): () => void {
   // TODO
-  return function cleanup() {};
+  return function cleanup() { };
 }
diff --git a/src/components/Scoreboard.ts b/src/components/Scoreboard.ts
index d5428e1..45eadaa 100644
--- a/src/components/Scoreboard.ts
+++ b/src/components/Scoreboard.ts
@@ -14,5 +14,5 @@ interface ScoreboardProps {
 // TODO: implement scoreboard UI
 export function mountScoreboard(container: HTMLElement, props: ScoreboardProps): () => void {
   // TODO
-  return function cleanup() {};
+  return function cleanup() { };
 }
diff --git a/src/components/ShareDialog.ts b/src/components/ShareDialog.ts
index 93b5285..ed90541 100644
--- a/src/components/ShareDialog.ts
+++ b/src/components/ShareDialog.ts
@@ -12,5 +12,5 @@ interface ShareDialogProps {
 // TODO: implement share dialog with qrcode rendering
 export function mountShareDialog(container: HTMLElement, props: ShareDialogProps): () => void {
   // TODO: use the `qrcode` package to render a QR code canvas
-  return function cleanup() {};
+  return function cleanup() { };
 }
diff --git a/src/components/WordPicker.ts b/src/components/WordPicker.ts
index 54d2472..4752bd3 100644
--- a/src/components/WordPicker.ts
+++ b/src/components/WordPicker.ts
@@ -12,5 +12,5 @@ interface WordPickerProps {
 // TODO: implement word picker UI
 export function mountWordPicker(container: HTMLElement, props: WordPickerProps): () => void {
   // TODO
-  return function cleanup() {};
+  return function cleanup() { };
 }
diff --git a/src/components/WordleBoard.ts b/src/components/WordleBoard.ts
index 9a6b98e..2cd9e08 100644
--- a/src/components/WordleBoard.ts
+++ b/src/components/WordleBoard.ts
@@ -19,5 +19,5 @@ interface WordleBoardProps {
 // TODO: implement board rendering and guess logic
 export function mountWordleBoard(container: HTMLElement, props: WordleBoardProps): () => void {
   // TODO
-  return function cleanup() {};
+  return function cleanup() { };
 }
diff --git a/src/firebase/gameService.ts b/src/firebase/gameService.ts
index 5343a17..21c80de 100644
--- a/src/firebase/gameService.ts
+++ b/src/firebase/gameService.ts
@@ -42,5 +42,5 @@ export function subscribeToGame(
   onUpdate: (envelope: EncryptedEnvelope) => void,
 ): () => void {
   // TODO
-  return function unsubscribe() {};
+  return function unsubscribe() { };
 }
diff --git a/src/index.html b/src/index.html
index 7c6f7b3..7329f5c 100644
--- a/src/index.html
+++ b/src/index.html
@@ -1,13 +1,16 @@
 <!DOCTYPE html>
 <html lang="en">
-  <head>
+
+<head>
     <meta charset="UTF-8" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
     <title>Word Waltz</title>
     <link rel="stylesheet" href="./styles/main.css" />
-  </head>
-  <body>
+</head>
+
+<body>
     <div id="app"></div>
     <script type="module" src="./main.ts"></script>
-  </body>
-</html>
+</body>
+
+</html>
\ No newline at end of file
diff --git a/src/styles/main.css b/src/styles/main.css
index 7afa655..5f912da 100644
--- a/src/styles/main.css
+++ b/src/styles/main.css
@@ -1,3 +1,3 @@
 /* Word Waltz — global styles */
 
-/* TODO: design system, tile colors, keyboard layout, responsive layout */
+/* TODO: design system, tile colors, keyboard layout, responsive layout */
\ No newline at end of file
diff --git a/src/types.ts b/src/types.ts
index 4b20d37..37d3ff9 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -9,32 +9,32 @@
 export type PlayerId = 'a' | 'b';
 
 export interface Player {
-  name: string;
-  score: number;
+    name: string;
+    score: number;
 }
 
 export interface Round {
-  challenger: PlayerId;
-  word: string;
-  guesses: string[];
-  solved: boolean;
-  score: number;
+    challenger: PlayerId;
+    word: string;
+    guesses: string[];
+    solved: boolean;
+    score: number;
 }
 
 export interface GameState {
-  players: Record<PlayerId, Player>;
-  rounds: Round[];
-  currentRound: number;
-  turn: 'pick' | 'solve';
-  createdAt: number;
-  updatedAt: number;
+    players: Record<PlayerId, Player>;
+    rounds: Round[];
+    currentRound: number;
+    turn: 'pick' | 'solve';
+    createdAt: number;
+    updatedAt: number;
 }
 
 /** The shape stored in Firestore (encrypted envelope + one plaintext field). */
 export interface EncryptedEnvelope {
-  iv: string;
-  ciphertext: string;
-  lastPlayed: number;
+    iv: string;
+    ciphertext: string;
+    lastPlayed: number;
 }
 
 /** The encrypted part only — passed in by callers of createGame / updateGame. */
diff --git a/tsconfig.json b/tsconfig.json
index ad79e54..0b70058 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,21 +1,24 @@
 {
-  "compilerOptions": {
-    "target": "ES2020",
-    "useDefineForClassFields": true,
-    "module": "ESNext",
-    "lib": ["ES2020", "DOM", "DOM.Iterable"],
-    "skipLibCheck": true,
-
-    /* Vite-recommended module resolution */
-    "moduleResolution": "bundler",
-    "allowImportingTsExtensions": true,
-    "resolveJsonModule": true,
-    "isolatedModules": true,
-
-    /* tsc is type-check only; Vite/esbuild handles emit */
-    "noEmit": true,
-
-    "strict": true
-  },
-  "include": ["src"]
-}
+    "compilerOptions": {
+        "target": "ES2020",
+        "useDefineForClassFields": true,
+        "module": "ESNext",
+        "lib": [
+            "ES2020",
+            "DOM",
+            "DOM.Iterable"
+        ],
+        "skipLibCheck": true,
+        /* Vite-recommended module resolution */
+        "moduleResolution": "bundler",
+        "allowImportingTsExtensions": true,
+        "resolveJsonModule": true,
+        "isolatedModules": true,
+        /* tsc is type-check only; Vite/esbuild handles emit */
+        "noEmit": true,
+        "strict": true
+    },
+    "include": [
+        "src"
+    ]
+}
\ No newline at end of file