import pkg from '@/package.json'; // OpenAPI 3.1 document for the app's public JSON API, kept in code so it can be // served machine-readable at /api/openapi (see AGENTS.md "## API"). Must be updated // whenever an endpoint changes. export const openApiSpec = { openapi: '3.1.0', info: { title: 'SpaceWanderer API', description: 'JSON API for SpaceWanderer — a single-player turn-based space adventure (one save, no accounts). World endpoints: read the generated world state and jump between adjacent solar systems.', // Sourced from package.json so it stays in sync with every version bump. version: pkg.version, }, // Empty url = current origin (the spec is served from the same host that runs the API). servers: [{ url: '' }], paths: { '/api/version': { get: { summary: 'App version', description: 'The running app version, read from package.json.', operationId: 'getVersion', responses: { 200: { description: 'Current app version', content: { 'application/json': { schema: { $ref: '#/components/schemas/AppVersion' }, }, }, }, }, }, }, '/api/world': { get: { summary: 'World state', description: 'The full world of the single active save — every known solar system, jump routes and the turn counter. Auto-initializes a new game (seeded world generation) when no save exists yet.', operationId: 'getWorld', responses: { 200: { description: 'Current world state', content: { 'application/json': { schema: { $ref: '#/components/schemas/WorldState' }, }, }, }, }, }, }, '/api/jump': { post: { summary: 'Jump to an adjacent solar system', description: 'Validates that the target is a jump route away from the current system, sets it as current (discovering it if new and generating its neighbours), increments the turn counter and writes a jump event. Returns the fresh world state.', operationId: 'jumpToSystem', requestBody: { required: true, content: { 'application/json': { schema: { $ref: '#/components/schemas/JumpRequest' }, }, }, }, responses: { 200: { description: 'Fresh world state after the jump', content: { 'application/json': { schema: { $ref: '#/components/schemas/WorldState' }, }, }, }, 400: { description: 'Malformed body or non-integer systemId', content: { 'application/json': { schema: { $ref: '#/components/schemas/Error' }, }, }, }, 404: { description: 'Unknown system id', content: { 'application/json': { schema: { $ref: '#/components/schemas/Error' }, }, }, }, 409: { description: 'Target is not adjacent to the current system (or is the current system itself)', content: { 'application/json': { schema: { $ref: '#/components/schemas/Error' }, }, }, }, }, }, }, }, components: { schemas: { AppVersion: { type: 'object', properties: { version: { type: 'string', description: 'Semver of the running build' }, }, required: ['version'], }, WorldSystem: { type: 'object', properties: { id: { type: 'integer' }, name: { type: 'string' }, x: { type: 'number', description: '0–100 chart coordinate' }, y: { type: 'number', description: '0–100 chart coordinate' }, discovered: { type: 'boolean' }, current: { type: 'boolean', description: 'True for the system the ship is in now' }, }, required: ['id', 'name', 'x', 'y', 'discovered', 'current'], }, WorldState: { type: 'object', properties: { systems: { type: 'array', items: { $ref: '#/components/schemas/WorldSystem' } }, edges: { type: 'array', description: 'Undirected jump routes as [fromId, toId] pairs (sorted, deduped)', items: { type: 'array', items: { type: 'integer' }, minItems: 2, maxItems: 2, }, }, turn: { type: 'integer', description: 'Turn counter — one per jump' }, }, required: ['systems', 'edges', 'turn'], }, JumpRequest: { type: 'object', properties: { systemId: { type: 'integer', description: 'solar_systems.id of the jump target' }, }, required: ['systemId'], }, Error: { type: 'object', properties: { error: { type: 'string' }, }, required: ['error'], }, }, }, };