Skip to content

Commit 67ac694

Browse files
Update CI node versions, enhance .gitignore, and refine type handling in API client and storage functions
1 parent 1f70755 commit 67ac694

12 files changed

Lines changed: 35 additions & 30 deletions

File tree

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515

1616
strategy:
1717
matrix:
18-
node-version: [20, 22]
18+
node-version: [22, 24]
1919

2020
steps:
2121
- name: Checkout code

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,4 +144,8 @@ vite.config.js.timestamp-*
144144
vite.config.ts.timestamp-*
145145

146146
# Database
147-
*.db
147+
*.db
148+
149+
# OS files
150+
.DS_Store
151+
Thumbs.db

shared/src/storage/mcp-api-client.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { httpGet, httpPost, WEB_API_BASE } from '../utils/http-client'
66
export async function getTicTacToeGameForMCP(gameId: string): Promise<GameSession<TicTacToeGameState> | undefined> {
77
try {
88
// Get all games and find the one we want
9-
const games = await httpGet(`${WEB_API_BASE}/api/games/tic-tac-toe`)
9+
const games = await httpGet<GameSession<TicTacToeGameState>[]>(`${WEB_API_BASE}/api/games/tic-tac-toe`)
1010
return games.find((game: GameSession<TicTacToeGameState>) => game.gameState?.id === gameId)
1111
} catch (error) {
1212
console.error('Error fetching tic-tac-toe game via API:', error)
@@ -35,7 +35,7 @@ export async function makeTicTacToeMove(gameId: string, move: TicTacToeMove, pla
3535

3636
export async function getRPSGameForMCP(gameId: string): Promise<GameSession<RPSGameState> | undefined> {
3737
try {
38-
const games = await httpGet(`${WEB_API_BASE}/api/games/rock-paper-scissors/mcp`)
38+
const games = await httpGet<GameSession<RPSGameState>[]>(`${WEB_API_BASE}/api/games/rock-paper-scissors/mcp`)
3939
return games.find((game: GameSession<RPSGameState>) => game.gameState?.id === gameId)
4040
} catch (error) {
4141
console.error('Error fetching RPS game via API:', error)

shared/src/storage/sqlite-storage.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ async function initializeDatabase(): Promise<sqlite3.Database> {
126126
}
127127

128128
// Helper function to run database queries
129-
async function runQuery(sql: string, params: any[] = []): Promise<any> {
129+
async function runQuery(sql: string, params: unknown[] = []): Promise<{ lastID: number | null; changes: number }> {
130130
try {
131131
const database = await initializeDatabase()
132132
if (!database) {
@@ -151,7 +151,7 @@ async function runQuery(sql: string, params: any[] = []): Promise<any> {
151151
}
152152

153153
// Helper function to get single row
154-
async function getRow(sql: string, params: any[] = []): Promise<any> {
154+
async function getRow(sql: string, params: unknown[] = []): Promise<Record<string, unknown> | undefined> {
155155
try {
156156
const database = await initializeDatabase()
157157
if (!database) {
@@ -162,7 +162,7 @@ async function getRow(sql: string, params: any[] = []): Promise<any> {
162162
if (err) {
163163
reject(err)
164164
} else {
165-
resolve(row)
165+
resolve(row as Record<string, unknown> | undefined)
166166
}
167167
})
168168
})
@@ -176,7 +176,7 @@ async function getRow(sql: string, params: any[] = []): Promise<any> {
176176
}
177177

178178
// Helper function to get all rows
179-
async function getAllRows(sql: string, params: any[] = []): Promise<any[]> {
179+
async function getAllRows(sql: string, params: unknown[] = []): Promise<Record<string, unknown>[]> {
180180
try {
181181
const database = await initializeDatabase()
182182
if (!database) {
@@ -187,7 +187,7 @@ async function getAllRows(sql: string, params: any[] = []): Promise<any[]> {
187187
if (err) {
188188
reject(err)
189189
} else {
190-
resolve(rows || [])
190+
resolve((rows || []) as Record<string, unknown>[])
191191
}
192192
})
193193
})
@@ -205,7 +205,7 @@ export async function getTicTacToeGame(gameId: string): Promise<GameSession<TicT
205205
try {
206206
const row = await getRow('SELECT game_session FROM tic_tac_toe_games WHERE id = ?', [gameId])
207207
if (row) {
208-
return JSON.parse(row.game_session)
208+
return JSON.parse(row.game_session as string)
209209
}
210210
return undefined
211211
} catch (error) {
@@ -234,7 +234,7 @@ export async function setTicTacToeGame(gameId: string, gameSession: GameSession<
234234
export async function getAllTicTacToeGames(): Promise<GameSession<TicTacToeGameState>[]> {
235235
try {
236236
const rows = await getAllRows('SELECT game_session FROM tic_tac_toe_games ORDER BY updated_at DESC')
237-
return rows.map(row => JSON.parse(row.game_session))
237+
return rows.map(row => JSON.parse(row.game_session as string))
238238
} catch (error) {
239239
if (process.env.NODE_ENV !== 'test') {
240240
console.error('Error getting all tic-tac-toe games:', error)
@@ -260,7 +260,7 @@ export async function getRPSGame(gameId: string): Promise<GameSession<RPSGameSta
260260
try {
261261
const row = await getRow('SELECT game_session FROM rps_games WHERE id = ?', [gameId])
262262
if (row) {
263-
return JSON.parse(row.game_session)
263+
return JSON.parse(row.game_session as string)
264264
}
265265
return undefined
266266
} catch (error) {
@@ -289,7 +289,7 @@ export async function setRPSGame(gameId: string, gameSession: GameSession<RPSGam
289289
export async function getAllRPSGames(): Promise<GameSession<RPSGameState>[]> {
290290
try {
291291
const rows = await getAllRows('SELECT game_session FROM rps_games ORDER BY updated_at DESC')
292-
return rows.map(row => JSON.parse(row.game_session))
292+
return rows.map(row => JSON.parse(row.game_session as string))
293293
} catch (error) {
294294
if (process.env.NODE_ENV !== 'test') {
295295
console.error('Error getting all RPS games:', error)

shared/src/testing/api-test-utils.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,16 +102,16 @@ export function createMockGameSession<T extends BaseGameState>(gameState: T, gam
102102
* Use this to create consistent mocks across API route tests
103103
*/
104104
export function createSharedGameMocks(gameClass: string): {
105-
mockImplementation: Record<string, unknown>;
105+
mockImplementation: () => Promise<Record<string, unknown>>;
106106
mockGame: ReturnType<typeof createGameMock>;
107107
} {
108108
const mockGame = createGameMock()
109109

110110
return {
111-
mockImplementation: {
112-
...vi.importActual('@turn-based-mcp/shared'),
111+
mockImplementation: async () => ({
112+
...await vi.importActual('@turn-based-mcp/shared/constants'),
113113
[gameClass]: vi.fn().mockImplementation(() => mockGame)
114-
},
114+
}),
115115
mockGame
116116
}
117117
}

shared/src/utils/http-client.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export const WEB_API_BASE = process.env.WEB_API_BASE || 'http://localhost:3000'
1515
* @returns Promise resolving to the JSON response
1616
* @throws Error if the request fails or returns non-2xx status
1717
*/
18-
export async function httpGet<T = any>(url: string): Promise<T> {
18+
export async function httpGet<T = unknown>(url: string): Promise<T> {
1919
const response = await fetch(url)
2020
if (!response.ok) {
2121
throw new Error(`HTTP ${response.status}: ${response.statusText}`)
@@ -31,7 +31,7 @@ export async function httpGet<T = any>(url: string): Promise<T> {
3131
* @returns Promise resolving to the JSON response
3232
* @throws Error if the request fails or returns non-2xx status
3333
*/
34-
export async function httpPost<T = any>(url: string, data: unknown): Promise<T> {
34+
export async function httpPost<T = unknown>(url: string, data: unknown): Promise<T> {
3535
const response = await fetch(url, {
3636
method: 'POST',
3737
headers: { 'Content-Type': 'application/json' },

web/next-env.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/// <reference types="next" />
22
/// <reference types="next/image-types/global" />
3+
import "./.next/types/routes.d.ts";
34

45
// NOTE: This file should not be edited
56
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.

web/src/app/api/games/rock-paper-scissors/[id]/move/route.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type { GameSession, RPSGameState, RPSMove } from '@turn-based-mcp/shared'
44

55
// Mock dependencies BEFORE importing the route - use factory functions for proper setup
66
// In vitest v4, mocks used as constructors must use 'function' syntax
7-
vi.mock('@turn-based-mcp/shared', () => {
7+
vi.mock('@turn-based-mcp/shared', async () => {
88
const mockGame = {
99
getInitialState: vi.fn(),
1010
validateMove: vi.fn(),
@@ -14,7 +14,7 @@ vi.mock('@turn-based-mcp/shared', () => {
1414
};
1515

1616
return {
17-
...vi.importActual('@turn-based-mcp/shared'),
17+
...await vi.importActual('@turn-based-mcp/shared/constants'),
1818
RockPaperScissorsGame: vi.fn(function() { return mockGame; }),
1919
__mockGameInstance: mockGame
2020
};

web/src/app/api/games/rock-paper-scissors/route.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ const mockGame = vi.hoisted(() => ({
1414

1515
// Mock dependencies BEFORE importing the route
1616
// In vitest v4, mocks used as constructors must use 'function' syntax
17-
vi.mock('@turn-based-mcp/shared', () => ({
18-
...vi.importActual('@turn-based-mcp/shared'),
17+
vi.mock('@turn-based-mcp/shared', async () => ({
18+
...await vi.importActual('@turn-based-mcp/shared/constants'),
1919
RockPaperScissorsGame: vi.fn(function() { return mockGame; })
2020
}));
2121

web/src/app/api/games/tic-tac-toe/[id]/move/route.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type { GameSession, TicTacToeGameState, TicTacToeMove } from '@turn-based
44

55
// Mock dependencies BEFORE importing the route - use factory functions for proper setup
66
// In vitest v4, mocks used as constructors must use 'function' syntax
7-
vi.mock('@turn-based-mcp/shared', () => {
7+
vi.mock('@turn-based-mcp/shared', async () => {
88
const mockGame = {
99
getInitialState: vi.fn(),
1010
validateMove: vi.fn(),
@@ -14,7 +14,7 @@ vi.mock('@turn-based-mcp/shared', () => {
1414
};
1515

1616
return {
17-
...vi.importActual('@turn-based-mcp/shared'),
17+
...await vi.importActual('@turn-based-mcp/shared/constants'),
1818
TicTacToeGame: vi.fn(function() { return mockGame; }),
1919
getTicTacToeGame: vi.fn(),
2020
setTicTacToeGame: vi.fn(),

0 commit comments

Comments
 (0)