From acda4c2fc44f2040ffdf015e97e156bcced93b5f Mon Sep 17 00:00:00 2001 From: Hikari Date: Fri, 6 Mar 2026 23:56:55 -0800 Subject: [PATCH] fix: resolve pre-existing TypeScript strictness build errors - Add @types/node to API devDependencies - Create HonoEnv type and apply to all routers + auth middleware for proper context.get/set("discordId") typing - Use conditional spreads for exactOptionalPropertyTypes dailyChallenges in GameContext, tick engine, and prestige route - Use conditional spread for optional signature in SaveRequest calls - Add non-null assertions in shuffle/template index for noUncheckedIndexedAccess - Cast GameState to never for Prisma InputJsonValue fields - Exclude vite.config.ts from web tsconfig (it runs in Node context) --- apps/api/package.json | 1 + apps/api/src/middleware/auth.ts | 5 +- apps/api/src/routes/auth.ts | 2 +- apps/api/src/routes/prestige.ts | 5 +- apps/api/src/routes/profile.ts | 3 +- apps/api/src/services/dailyChallenges.ts | 4 +- apps/api/src/types/hono.ts | 1 + apps/web/src/context/GameContext.tsx | 6 +- apps/web/tsconfig.json | 2 +- pnpm-lock.yaml | 71 +++++++++++++++--------- 10 files changed, 61 insertions(+), 39 deletions(-) create mode 100644 apps/api/src/types/hono.ts diff --git a/apps/api/package.json b/apps/api/package.json index 8f2f50f..86bcfe0 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -22,6 +22,7 @@ "devDependencies": { "@nhcarrigan/eslint-config": "5.2.0", "@nhcarrigan/typescript-config": "4.0.0", + "@types/node": "25.3.5", "@vitest/coverage-v8": "3.0.8", "eslint": "9.22.0", "tsx": "4.19.3", diff --git a/apps/api/src/middleware/auth.ts b/apps/api/src/middleware/auth.ts index 69c3489..21a9a23 100644 --- a/apps/api/src/middleware/auth.ts +++ b/apps/api/src/middleware/auth.ts @@ -1,7 +1,8 @@ -import type { Context, Next } from "hono"; +import type { MiddlewareHandler } from "hono"; +import type { HonoEnv } from "../types/hono.js"; import { verifyToken } from "../services/jwt.js"; -export const authMiddleware = async (context: Context, next: Next): Promise => { +export const authMiddleware: MiddlewareHandler = async (context, next) => { const authorization = context.req.header("Authorization"); if (!authorization?.startsWith("Bearer ")) { diff --git a/apps/api/src/routes/auth.ts b/apps/api/src/routes/auth.ts index bd358a2..022d4e3 100644 --- a/apps/api/src/routes/auth.ts +++ b/apps/api/src/routes/auth.ts @@ -68,7 +68,7 @@ authRouter.get("/callback", async (context) => { await prisma.gameState.create({ data: { discordId: player.discordId, - state: initialState, + state: initialState as unknown as never, updatedAt: now, }, }); diff --git a/apps/api/src/routes/prestige.ts b/apps/api/src/routes/prestige.ts index 66b0a09..589d25f 100644 --- a/apps/api/src/routes/prestige.ts +++ b/apps/api/src/routes/prestige.ts @@ -1,5 +1,6 @@ import type { BuyPrestigeUpgradeRequest, GameState, PrestigeRequest } from "@elysium/types"; import { Hono } from "hono"; +import type { HonoEnv } from "../types/hono.js"; import { prisma } from "../db/client.js"; import { authMiddleware } from "../middleware/auth.js"; import { DEFAULT_PRESTIGE_UPGRADES } from "../data/prestigeUpgrades.js"; @@ -10,7 +11,7 @@ import { isEligibleForPrestige, } from "../services/prestige.js"; -export const prestigeRouter = new Hono(); +export const prestigeRouter = new Hono(); prestigeRouter.use("*", authMiddleware); @@ -55,7 +56,7 @@ prestigeRouter.post("/", async (context) => { // Preserve daily challenges across the prestige reset and apply any crystal rewards const finalState: GameState = { ...newState, - dailyChallenges: updatedDailyChallenges, + ...(updatedDailyChallenges !== undefined ? { dailyChallenges: updatedDailyChallenges } : {}), resources: { ...newState.resources, crystals: newState.resources.crystals + challengeCrystals, diff --git a/apps/api/src/routes/profile.ts b/apps/api/src/routes/profile.ts index df91c30..ad93078 100644 --- a/apps/api/src/routes/profile.ts +++ b/apps/api/src/routes/profile.ts @@ -5,10 +5,11 @@ import type { } from "@elysium/types"; import { DEFAULT_PROFILE_SETTINGS } from "@elysium/types"; import { Hono } from "hono"; +import type { HonoEnv } from "../types/hono.js"; import { prisma } from "../db/client.js"; import { authMiddleware } from "../middleware/auth.js"; -export const profileRouter = new Hono(); +export const profileRouter = new Hono(); const VALID_NUMBER_FORMATS = new Set(["suffix", "scientific", "engineering"]); diff --git a/apps/api/src/services/dailyChallenges.ts b/apps/api/src/services/dailyChallenges.ts index 7e43abe..9a921f0 100644 --- a/apps/api/src/services/dailyChallenges.ts +++ b/apps/api/src/services/dailyChallenges.ts @@ -25,7 +25,7 @@ const shuffleWithSeed = (arr: T[], seed: number): T[] => { const result = [...arr]; for (let i = result.length - 1; i > 0; i--) { const j = Math.floor(seededRandom(seed + i) * (i + 1)); - [result[i], result[j]] = [result[j], result[i]]; + [result[i], result[j]] = [result[j]!, result[i]!]; } return result; }; @@ -48,7 +48,7 @@ export const generateDailyChallenges = (dateStr: string): DailyChallenge[] => { return selectedTypes.map((type, index) => { const templates = DAILY_CHALLENGE_TEMPLATES.filter((t) => t.type === type); const templateIndex = Math.floor(seededRandom(seed + index * 100) * templates.length); - const template = templates[templateIndex]; + const template = templates[templateIndex]!; return { id: `${dateStr}_${type}`, diff --git a/apps/api/src/types/hono.ts b/apps/api/src/types/hono.ts new file mode 100644 index 0000000..6f1d344 --- /dev/null +++ b/apps/api/src/types/hono.ts @@ -0,0 +1 @@ +export type HonoEnv = { Variables: { discordId: string } }; diff --git a/apps/web/src/context/GameContext.tsx b/apps/web/src/context/GameContext.tsx index 37441e5..55fa7b8 100644 --- a/apps/web/src/context/GameContext.tsx +++ b/apps/web/src/context/GameContext.tsx @@ -174,7 +174,7 @@ export const GameProvider = ({ children }: { children: React.ReactNode }): React if (stateRef.current && !isSyncingRef.current) { void saveGame({ state: stateRef.current, - signature: signatureRef.current ?? undefined, + ...(signatureRef.current !== null ? { signature: signatureRef.current } : {}), }).then((response) => { setLastSavedAt(response.savedAt); if (response.signature) { @@ -222,7 +222,7 @@ export const GameProvider = ({ children }: { children: React.ReactNode }): React try { const response = await saveGame({ state: stateRef.current, - signature: signatureRef.current ?? undefined, + ...(signatureRef.current !== null ? { signature: signatureRef.current } : {}), }); setSyncError(null); setLastSavedAt(response.savedAt); @@ -267,7 +267,7 @@ export const GameProvider = ({ children }: { children: React.ReactNode }): React totalGoldEarned: prev.player.totalGoldEarned + clickPower, totalClicks: prev.player.totalClicks + 1, }, - dailyChallenges: updatedDailyChallenges, + ...(updatedDailyChallenges !== undefined ? { dailyChallenges: updatedDailyChallenges } : {}), }; }); }, []); diff --git a/apps/web/tsconfig.json b/apps/web/tsconfig.json index ab23d1e..be2a8f7 100644 --- a/apps/web/tsconfig.json +++ b/apps/web/tsconfig.json @@ -7,5 +7,5 @@ "lib": ["ES2022", "DOM", "DOM.Iterable"], "target": "ES2022" }, - "exclude": ["test/**/*.ts", "test/**/*.tsx"] + "exclude": ["test/**/*.ts", "test/**/*.tsx", "vite.config.ts"] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 88bc570..59674c6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -35,13 +35,16 @@ importers: devDependencies: '@nhcarrigan/eslint-config': specifier: 5.2.0 - version: 5.2.0(@typescript-eslint/utils@8.56.1(eslint@9.22.0)(typescript@5.8.2))(eslint@9.22.0)(playwright@1.58.2)(react@19.0.0)(typescript@5.8.2)(vitest@3.0.8(jsdom@26.0.0)(tsx@4.19.3)) + version: 5.2.0(@typescript-eslint/utils@8.56.1(eslint@9.22.0)(typescript@5.8.2))(eslint@9.22.0)(playwright@1.58.2)(react@19.0.0)(typescript@5.8.2)(vitest@3.0.8(@types/node@25.3.5)(jsdom@26.0.0)(tsx@4.19.3)) '@nhcarrigan/typescript-config': specifier: 4.0.0 version: 4.0.0(typescript@5.8.2) + '@types/node': + specifier: 25.3.5 + version: 25.3.5 '@vitest/coverage-v8': specifier: 3.0.8 - version: 3.0.8(vitest@3.0.8(jsdom@26.0.0)(tsx@4.19.3)) + version: 3.0.8(vitest@3.0.8(@types/node@25.3.5)(jsdom@26.0.0)(tsx@4.19.3)) eslint: specifier: 9.22.0 version: 9.22.0 @@ -53,7 +56,7 @@ importers: version: 5.8.2 vitest: specifier: 3.0.8 - version: 3.0.8(jsdom@26.0.0)(tsx@4.19.3) + version: 3.0.8(@types/node@25.3.5)(jsdom@26.0.0)(tsx@4.19.3) apps/web: dependencies: @@ -69,7 +72,7 @@ importers: devDependencies: '@nhcarrigan/eslint-config': specifier: 5.2.0 - version: 5.2.0(@typescript-eslint/utils@8.56.1(eslint@9.22.0)(typescript@5.8.2))(eslint@9.22.0)(playwright@1.58.2)(react@19.0.0)(typescript@5.8.2)(vitest@3.0.8(jsdom@26.0.0)(tsx@4.19.3)) + version: 5.2.0(@typescript-eslint/utils@8.56.1(eslint@9.22.0)(typescript@5.8.2))(eslint@9.22.0)(playwright@1.58.2)(react@19.0.0)(typescript@5.8.2)(vitest@3.0.8(@types/node@25.3.5)(jsdom@26.0.0)(tsx@4.19.3)) '@nhcarrigan/typescript-config': specifier: 4.0.0 version: 4.0.0(typescript@5.8.2) @@ -81,10 +84,10 @@ importers: version: 19.0.4(@types/react@19.0.10) '@vitejs/plugin-react': specifier: 4.3.4 - version: 4.3.4(vite@6.2.1(tsx@4.19.3)) + version: 4.3.4(vite@6.2.1(@types/node@25.3.5)(tsx@4.19.3)) '@vitest/coverage-v8': specifier: 3.0.8 - version: 3.0.8(vitest@3.0.8(jsdom@26.0.0)(tsx@4.19.3)) + version: 3.0.8(vitest@3.0.8(@types/node@25.3.5)(jsdom@26.0.0)(tsx@4.19.3)) eslint: specifier: 9.22.0 version: 9.22.0 @@ -96,16 +99,16 @@ importers: version: 5.8.2 vite: specifier: 6.2.1 - version: 6.2.1(tsx@4.19.3) + version: 6.2.1(@types/node@25.3.5)(tsx@4.19.3) vitest: specifier: 3.0.8 - version: 3.0.8(jsdom@26.0.0)(tsx@4.19.3) + version: 3.0.8(@types/node@25.3.5)(jsdom@26.0.0)(tsx@4.19.3) packages/types: devDependencies: '@nhcarrigan/eslint-config': specifier: 5.2.0 - version: 5.2.0(@typescript-eslint/utils@8.56.1(eslint@9.22.0)(typescript@5.8.2))(eslint@9.22.0)(playwright@1.58.2)(react@19.0.0)(typescript@5.8.2)(vitest@3.0.8(jsdom@26.0.0)(tsx@4.19.3)) + version: 5.2.0(@typescript-eslint/utils@8.56.1(eslint@9.22.0)(typescript@5.8.2))(eslint@9.22.0)(playwright@1.58.2)(react@19.0.0)(typescript@5.8.2)(vitest@3.0.8(@types/node@25.3.5)(jsdom@26.0.0)(tsx@4.19.3)) '@nhcarrigan/typescript-config': specifier: 4.0.0 version: 4.0.0(typescript@5.8.2) @@ -888,6 +891,9 @@ packages: '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + '@types/node@25.3.5': + resolution: {integrity: sha512-oX8xrhvpiyRCQkG1MFchB09f+cXftgIXb3a7UUa4Y3wpmZPw5tyZGTLWhlESOLq1Rq6oDlc8npVU2/9xiCuXMA==} + '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -2601,6 +2607,9 @@ packages: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} + undici-types@7.18.2: + resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + update-browserslist-db@1.2.3: resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} hasBin: true @@ -3201,7 +3210,7 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@nhcarrigan/eslint-config@5.2.0(@typescript-eslint/utils@8.56.1(eslint@9.22.0)(typescript@5.8.2))(eslint@9.22.0)(playwright@1.58.2)(react@19.0.0)(typescript@5.8.2)(vitest@3.0.8(jsdom@26.0.0)(tsx@4.19.3))': + '@nhcarrigan/eslint-config@5.2.0(@typescript-eslint/utils@8.56.1(eslint@9.22.0)(typescript@5.8.2))(eslint@9.22.0)(playwright@1.58.2)(react@19.0.0)(typescript@5.8.2)(vitest@3.0.8(@types/node@25.3.5)(jsdom@26.0.0)(tsx@4.19.3))': dependencies: '@eslint-community/eslint-plugin-eslint-comments': 4.4.1(eslint@9.22.0) '@eslint/compat': 1.2.4(eslint@9.22.0) @@ -3210,7 +3219,7 @@ snapshots: '@stylistic/eslint-plugin': 2.12.1(eslint@9.22.0)(typescript@5.8.2) '@typescript-eslint/eslint-plugin': 8.19.0(@typescript-eslint/parser@8.19.0(eslint@9.22.0)(typescript@5.8.2))(eslint@9.22.0)(typescript@5.8.2) '@typescript-eslint/parser': 8.19.0(eslint@9.22.0)(typescript@5.8.2) - '@vitest/eslint-plugin': 1.1.24(@typescript-eslint/utils@8.56.1(eslint@9.22.0)(typescript@5.8.2))(eslint@9.22.0)(typescript@5.8.2)(vitest@3.0.8(jsdom@26.0.0)(tsx@4.19.3)) + '@vitest/eslint-plugin': 1.1.24(@typescript-eslint/utils@8.56.1(eslint@9.22.0)(typescript@5.8.2))(eslint@9.22.0)(typescript@5.8.2)(vitest@3.0.8(@types/node@25.3.5)(jsdom@26.0.0)(tsx@4.19.3)) eslint: 9.22.0 eslint-plugin-deprecation: 3.0.0(eslint@9.22.0)(typescript@5.8.2) eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.19.0(eslint@9.22.0)(typescript@5.8.2))(eslint@9.22.0) @@ -3223,7 +3232,7 @@ snapshots: playwright: 1.58.2 react: 19.0.0 typescript: 5.8.2 - vitest: 3.0.8(jsdom@26.0.0)(tsx@4.19.3) + vitest: 3.0.8(@types/node@25.3.5)(jsdom@26.0.0)(tsx@4.19.3) transitivePeerDependencies: - '@typescript-eslint/utils' - eslint-import-resolver-typescript @@ -3400,6 +3409,10 @@ snapshots: '@types/json5@0.0.29': {} + '@types/node@25.3.5': + dependencies: + undici-types: 7.18.2 + '@types/normalize-package-data@2.4.4': {} '@types/react-dom@19.0.4(@types/react@19.0.10)': @@ -3576,18 +3589,18 @@ snapshots: '@typescript-eslint/types': 8.56.1 eslint-visitor-keys: 5.0.1 - '@vitejs/plugin-react@4.3.4(vite@6.2.1(tsx@4.19.3))': + '@vitejs/plugin-react@4.3.4(vite@6.2.1(@types/node@25.3.5)(tsx@4.19.3))': dependencies: '@babel/core': 7.29.0 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.29.0) '@types/babel__core': 7.20.5 react-refresh: 0.14.2 - vite: 6.2.1(tsx@4.19.3) + vite: 6.2.1(@types/node@25.3.5)(tsx@4.19.3) transitivePeerDependencies: - supports-color - '@vitest/coverage-v8@3.0.8(vitest@3.0.8(jsdom@26.0.0)(tsx@4.19.3))': + '@vitest/coverage-v8@3.0.8(vitest@3.0.8(@types/node@25.3.5)(jsdom@26.0.0)(tsx@4.19.3))': dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 1.0.2 @@ -3601,17 +3614,17 @@ snapshots: std-env: 3.10.0 test-exclude: 7.0.2 tinyrainbow: 2.0.0 - vitest: 3.0.8(jsdom@26.0.0)(tsx@4.19.3) + vitest: 3.0.8(@types/node@25.3.5)(jsdom@26.0.0)(tsx@4.19.3) transitivePeerDependencies: - supports-color - '@vitest/eslint-plugin@1.1.24(@typescript-eslint/utils@8.56.1(eslint@9.22.0)(typescript@5.8.2))(eslint@9.22.0)(typescript@5.8.2)(vitest@3.0.8(jsdom@26.0.0)(tsx@4.19.3))': + '@vitest/eslint-plugin@1.1.24(@typescript-eslint/utils@8.56.1(eslint@9.22.0)(typescript@5.8.2))(eslint@9.22.0)(typescript@5.8.2)(vitest@3.0.8(@types/node@25.3.5)(jsdom@26.0.0)(tsx@4.19.3))': dependencies: '@typescript-eslint/utils': 8.56.1(eslint@9.22.0)(typescript@5.8.2) eslint: 9.22.0 optionalDependencies: typescript: 5.8.2 - vitest: 3.0.8(jsdom@26.0.0)(tsx@4.19.3) + vitest: 3.0.8(@types/node@25.3.5)(jsdom@26.0.0)(tsx@4.19.3) '@vitest/expect@3.0.8': dependencies: @@ -3620,13 +3633,13 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/mocker@3.0.8(vite@6.2.1(tsx@4.19.3))': + '@vitest/mocker@3.0.8(vite@6.2.1(@types/node@25.3.5)(tsx@4.19.3))': dependencies: '@vitest/spy': 3.0.8 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 6.2.1(tsx@4.19.3) + vite: 6.2.1(@types/node@25.3.5)(tsx@4.19.3) '@vitest/pretty-format@3.0.8': dependencies: @@ -5490,6 +5503,8 @@ snapshots: has-symbols: 1.1.0 which-boxed-primitive: 1.1.1 + undici-types@7.18.2: {} + update-browserslist-db@1.2.3(browserslist@4.28.1): dependencies: browserslist: 4.28.1 @@ -5505,13 +5520,13 @@ snapshots: spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 - vite-node@3.0.8(tsx@4.19.3): + vite-node@3.0.8(@types/node@25.3.5)(tsx@4.19.3): dependencies: cac: 6.7.14 debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 6.2.1(tsx@4.19.3) + vite: 6.2.1(@types/node@25.3.5)(tsx@4.19.3) transitivePeerDependencies: - '@types/node' - jiti @@ -5526,19 +5541,20 @@ snapshots: - tsx - yaml - vite@6.2.1(tsx@4.19.3): + vite@6.2.1(@types/node@25.3.5)(tsx@4.19.3): dependencies: esbuild: 0.25.12 postcss: 8.5.8 rollup: 4.59.0 optionalDependencies: + '@types/node': 25.3.5 fsevents: 2.3.3 tsx: 4.19.3 - vitest@3.0.8(jsdom@26.0.0)(tsx@4.19.3): + vitest@3.0.8(@types/node@25.3.5)(jsdom@26.0.0)(tsx@4.19.3): dependencies: '@vitest/expect': 3.0.8 - '@vitest/mocker': 3.0.8(vite@6.2.1(tsx@4.19.3)) + '@vitest/mocker': 3.0.8(vite@6.2.1(@types/node@25.3.5)(tsx@4.19.3)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.0.8 '@vitest/snapshot': 3.0.8 @@ -5554,10 +5570,11 @@ snapshots: tinyexec: 0.3.2 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 6.2.1(tsx@4.19.3) - vite-node: 3.0.8(tsx@4.19.3) + vite: 6.2.1(@types/node@25.3.5)(tsx@4.19.3) + vite-node: 3.0.8(@types/node@25.3.5)(tsx@4.19.3) why-is-node-running: 2.3.0 optionalDependencies: + '@types/node': 25.3.5 jsdom: 26.0.0 transitivePeerDependencies: - jiti