import type { z } from "zod"; import { playerStateSchema, serverTimeSchema } from "./entities"; import { acknowledgeSummariesRequestSchema, acknowledgeSummariesResponseSchema, assignPilotRequestSchema, bayResponseSchema, buyShipRequestSchema, claimGoalRequestSchema, companyResponseSchema, contractBoardRequestSchema, contractBoardResponseSchema, createDispatchRequestSchema, createGuestResponseSchema, devAddCreditsRequestSchema, devAdvanceClockRequestSchema, devAdvanceClockResponseSchema, devPilotRequestSchema, devShipRequestSchema, dispatchOfficeResponseSchema, dispatchResponseSchema, emergencyFuelRequestSchema, emptyRequestSchema, exportSaveResponseSchema, hirePilotRequestSchema, importSaveRequestSchema, leaseBayRequestSchema, pilotModeRequestSchema, pilotOrdersRequestSchema, pilotResponseSchema, refuelPolicyRequestSchema, refuelRequestSchema, renameCompanyRequestSchema, repayLoanRequestSchema, restPilotRequestSchema, shipResponseSchema, spendSkillPointRequestSchema, spendingFloorRequestSchema, startUpgradeRequestSchema, unassignPilotRequestSchema, } from "./requests"; export interface RouteDef { method: "GET" | "POST"; /** Under `/api` (decision 0.5.20). `:name` segments are path parameters. */ path: string; /** Path parameters plus body: every `:name` in the path is a field here. */ request: z.ZodType; /** Body of the 2xx response. Errors always use `errorResponseSchema`. */ response: z.ZodType; /** Whether it needs a company (was: a session, before CR-014). */ auth: boolean; } /** Every endpoint of the base game: the contract between server and client. */ export const routes = { getServerTime: { method: "GET", path: "/api/time", request: emptyRequestSchema, response: serverTimeSchema, auth: false, }, createGuest: { method: "POST", path: "/api/guest", request: emptyRequestSchema, response: createGuestResponseSchema, auth: false, }, getPlayerState: { method: "GET", path: "/api/state", request: emptyRequestSchema, response: playerStateSchema, auth: true, }, getContractBoard: { method: "GET", path: "/api/locations/:locationId/board", request: contractBoardRequestSchema, response: contractBoardResponseSchema, auth: true, }, getTutorialBoard: { method: "GET", path: "/api/tutorial/board", request: emptyRequestSchema, response: contractBoardResponseSchema, auth: true, }, createDispatch: { method: "POST", path: "/api/dispatches", request: createDispatchRequestSchema, response: dispatchResponseSchema, auth: true, }, buyShip: { method: "POST", path: "/api/ships", request: buyShipRequestSchema, response: shipResponseSchema, auth: true, }, startUpgrade: { method: "POST", path: "/api/ships/:shipId/upgrades", request: startUpgradeRequestSchema, response: shipResponseSchema, auth: true, }, /** CR-015: fill the tank (or buy `amountFu`) at the ship's location. */ refuelShip: { method: "POST", path: "/api/ships/:shipId/refuel", request: refuelRequestSchema, response: shipResponseSchema, auth: true, }, setRefuelPolicy: { method: "POST", path: "/api/ships/:shipId/refuel-policy", request: refuelPolicyRequestSchema, response: shipResponseSchema, auth: true, }, /** CR-015: fuel for the cheapest way out, added to the loan (decision 0.5.99). */ orderEmergencyFuel: { method: "POST", path: "/api/ships/:shipId/emergency-fuel", request: emergencyFuelRequestSchema, response: shipResponseSchema, auth: true, }, leaseBay: { method: "POST", path: "/api/bays", request: leaseBayRequestSchema, response: bayResponseSchema, auth: true, }, hirePilot: { method: "POST", path: "/api/pilots", request: hirePilotRequestSchema, response: pilotResponseSchema, auth: true, }, assignPilot: { method: "POST", path: "/api/pilots/:pilotId/assign", request: assignPilotRequestSchema, response: pilotResponseSchema, auth: true, }, unassignPilot: { method: "POST", path: "/api/pilots/:pilotId/unassign", request: unassignPilotRequestSchema, response: pilotResponseSchema, auth: true, }, restPilot: { method: "POST", path: "/api/pilots/:pilotId/rest", request: restPilotRequestSchema, response: pilotResponseSchema, auth: true, }, spendSkillPoint: { method: "POST", path: "/api/pilots/:pilotId/skills", request: spendSkillPointRequestSchema, response: pilotResponseSchema, auth: true, }, /** CR-021: Independent pilots (decisions 0.5.123–0.5.127). */ buyDispatchOffice: { method: "POST", path: "/api/company/dispatch-office", request: emptyRequestSchema, response: dispatchOfficeResponseSchema, auth: true, }, setPilotMode: { method: "POST", path: "/api/pilots/:pilotId/mode", request: pilotModeRequestSchema, response: pilotResponseSchema, auth: true, }, setPilotOrders: { method: "POST", path: "/api/pilots/:pilotId/orders", request: pilotOrdersRequestSchema, response: pilotResponseSchema, auth: true, }, setSpendingFloor: { method: "POST", path: "/api/company/spending-floor", request: spendingFloorRequestSchema, response: dispatchOfficeResponseSchema, auth: true, }, acknowledgeSummaries: { method: "POST", path: "/api/summaries/acknowledge", request: acknowledgeSummariesRequestSchema, response: acknowledgeSummariesResponseSchema, auth: true, }, /** CR-022: the welcome cards are closed for this company (decision 0.5.131). */ markWelcomeSeen: { method: "POST", path: "/api/welcome/seen", request: emptyRequestSchema, response: playerStateSchema, auth: true, }, acceptDeal: { method: "POST", path: "/api/deal/accept", request: emptyRequestSchema, response: playerStateSchema, auth: true, }, /** On the device only (CR-014): the save as an export code. */ exportSave: { method: "GET", path: "/api/save/export", request: emptyRequestSchema, response: exportSaveResponseSchema, auth: true, }, /** On the device only (CR-014): replaces this device's company with an exported one. */ importSave: { method: "POST", path: "/api/save/import", request: importSaveRequestSchema, response: createGuestResponseSchema, auth: false, }, /** Non-production only (CR-011): not registered when NODE_ENV is production. */ devAdvanceClock: { method: "POST", path: "/api/test/advance-clock", request: devAdvanceClockRequestSchema, response: devAdvanceClockResponseSchema, auth: true, }, devAddCredits: { method: "POST", path: "/api/test/add-credits", request: devAddCreditsRequestSchema, response: companyResponseSchema, auth: true, }, devPilot: { method: "POST", path: "/api/test/pilot", request: devPilotRequestSchema, response: playerStateSchema, auth: true, }, devShip: { method: "POST", path: "/api/test/ship", request: devShipRequestSchema, response: playerStateSchema, auth: true, }, devDiscoverAll: { method: "POST", path: "/api/test/discover-all", request: emptyRequestSchema, response: playerStateSchema, auth: true, }, newCompany: { method: "POST", path: "/api/company/new", request: emptyRequestSchema, response: playerStateSchema, auth: true, }, renameCompany: { method: "POST", path: "/api/company/name", request: renameCompanyRequestSchema, response: companyResponseSchema, auth: true, }, repayLoan: { method: "POST", path: "/api/loan/repay", request: repayLoanRequestSchema, response: companyResponseSchema, auth: true, }, claimGoal: { method: "POST", path: "/api/goals/:goalId/claim", request: claimGoalRequestSchema, response: companyResponseSchema, auth: true, }, } as const satisfies Record; export type Routes = typeof routes; export type RouteName = keyof Routes; export type RouteRequest = z.input; export type RouteResponse = z.output;