v1.1.0: session guard on all game routes + register + sign-in screen (ISS-107)
CI / build + unit + e2e (pull_request) Failing after 26m20s

This commit is contained in:
2026-09-26 14:40:56 +00:00
parent 21dd37f88c
commit b0f1bd8b67
54 changed files with 1002 additions and 91 deletions
+12 -1
View File
@@ -4,16 +4,20 @@ import path from 'node:path';
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
import { getLocalPlayer, updateLocalPlayerEconomy } from '@/lib/db/localPlayer';
import { getGameDb } from '@/lib/db/client';
import { createSession } from '@/lib/auth';
import { PLANE_TYPES } from '@/lib/game/catalog';
import { POST } from './route';
let dir: string;
let sessionId: string;
beforeAll(async () => {
// Same pattern as app/api/state/route.test.ts: point the DB singleton at a
// throwaway file (fresh module registry per test file → fresh singleton).
dir = await fs.mkdtemp(path.join(os.tmpdir(), 'flight-buy-api-'));
process.env.FLIGHT_DB_PATH = path.join(dir, 'buy.db');
// v1.1.0 (ISS-107): action routes are session-guarded — mint a session for the seeded admin user.
sessionId = await createSession(await getGameDb(), 'admin-kamilkrzywda');
});
afterAll(async () => {
@@ -21,7 +25,14 @@ afterAll(async () => {
await fs.rm(dir, { recursive: true, force: true });
});
const post = (body: unknown) => POST(new Request('http://localhost/api/market/buy-plane', { method: 'POST', body: JSON.stringify(body) }));
const post = (body: unknown) =>
POST(
new Request('http://localhost/api/market/buy-plane', {
method: 'POST',
headers: { 'X-Flight-Session': sessionId },
body: JSON.stringify(body),
}),
);
describe('POST /api/market/buy-plane', () => {
it('rejects a missing model, unknown fields and unknown models with 400', async () => {
+1 -1
View File
@@ -27,5 +27,5 @@ export async function POST(req: Request) {
}
const model = input.model;
return performAction((inst) => buyPlane(inst, model));
return performAction(req, (inst) => buyPlane(inst, model));
}
+12 -1
View File
@@ -6,16 +6,20 @@ import { afterAll, beforeAll, describe, expect, it } from 'vitest';
import * as schema from '@/lib/db/schema';
import { getLocalPlayer } from '@/lib/db/localPlayer';
import { getGameDb } from '@/lib/db/client';
import { createSession } from '@/lib/auth';
import { PLANE_TYPES, SELL_FRACTION } from '@/lib/game/catalog';
import { POST } from './route';
let dir: string;
let sessionId: string;
beforeAll(async () => {
// Same pattern as app/api/state/route.test.ts: point the DB singleton at a
// throwaway file (fresh module registry per test file → fresh singleton).
dir = await fs.mkdtemp(path.join(os.tmpdir(), 'flight-sell-api-'));
process.env.FLIGHT_DB_PATH = path.join(dir, 'sell.db');
// v1.1.0 (ISS-107): action routes are session-guarded — mint a session for the seeded admin user.
sessionId = await createSession(await getGameDb(), 'admin-kamilkrzywda');
});
afterAll(async () => {
@@ -23,7 +27,14 @@ afterAll(async () => {
await fs.rm(dir, { recursive: true, force: true });
});
const post = (body: unknown) => POST(new Request('http://localhost/api/market/sell-plane', { method: 'POST', body: JSON.stringify(body) }));
const post = (body: unknown) =>
POST(
new Request('http://localhost/api/market/sell-plane', {
method: 'POST',
headers: { 'X-Flight-Session': sessionId },
body: JSON.stringify(body),
}),
);
describe('POST /api/market/sell-plane', () => {
it('rejects a missing planeId and unknown fields with 400', async () => {
+1 -1
View File
@@ -27,5 +27,5 @@ export async function POST(req: Request) {
}
const planeId = input.planeId;
return performAction((inst) => sellPlane(inst, planeId));
return performAction(req, (inst) => sellPlane(inst, planeId));
}