Files
Flight-Ops/lib/openapi.ts
T

219 lines
6.4 KiB
TypeScript

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: 'Flight Ops API',
description:
'JSON API for Flight Ops — EU airport data for the map, the live game-state snapshot, and app metadata.',
// 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/airports': {
get: {
summary: 'List EU airports',
description:
'All fixed-wing EU airports (large, medium and seaplane bases) as a GeoJSON FeatureCollection.',
operationId: 'listAirports',
responses: {
200: {
description: 'GeoJSON FeatureCollection of EU airports',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/AirportFeatureCollection' },
},
},
},
},
},
},
'/api/state': {
get: {
summary: 'Game state snapshot',
description:
'Full current game state for client polling — account, sim clock, planes and contracts. Read-only.',
operationId: 'getState',
responses: {
200: {
description: 'Current game state',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/StateSnapshot' },
},
},
},
},
},
},
'/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' },
},
},
},
},
},
},
},
components: {
schemas: {
AppVersion: {
type: 'object',
properties: {
version: { type: 'string', description: 'Semver of the running build' },
},
required: ['version'],
},
AirportFeatureCollection: {
type: 'object',
properties: {
type: { const: 'FeatureCollection' },
features: {
type: 'array',
items: { $ref: '#/components/schemas/AirportFeature' },
},
},
required: ['type', 'features'],
},
AirportFeature: {
type: 'object',
properties: {
type: { const: 'Feature' },
geometry: { $ref: '#/components/schemas/PointGeometry' },
properties: { $ref: '#/components/schemas/AirportProperties' },
},
required: ['type', 'geometry', 'properties'],
},
PointGeometry: {
type: 'object',
properties: {
type: { const: 'Point' },
coordinates: {
type: 'array',
description: '[longitude, latitude]',
items: { type: 'number' },
minItems: 2,
maxItems: 2,
},
},
required: ['type', 'coordinates'],
},
AirportProperties: {
type: 'object',
properties: {
name: { type: 'string' },
icao: { type: 'string' },
lat: { type: 'number' },
lon: { type: 'number' },
},
required: ['name', 'icao', 'lat', 'lon'],
},
StateSnapshot: {
type: 'object',
properties: {
account: { $ref: '#/components/schemas/AccountState' },
simState: { $ref: '#/components/schemas/SimState' },
planes: {
type: 'array',
items: { $ref: '#/components/schemas/PlaneState' },
},
contracts: {
type: 'array',
items: { $ref: '#/components/schemas/ContractState' },
},
},
required: ['account', 'simState', 'planes', 'contracts'],
},
AccountState: {
type: 'object',
properties: {
cash: { type: 'number' },
reputation: { type: 'number' },
},
required: ['cash', 'reputation'],
},
SimState: {
type: 'object',
properties: {
clockMs: { type: 'integer', description: 'Sim-clock epoch ms (game time)' },
timeScale: { type: 'number', minimum: 1, maximum: 60 },
paused: { type: 'boolean' },
},
required: ['clockMs', 'timeScale', 'paused'],
},
PlaneState: {
type: 'object',
properties: {
id: { type: 'string' },
model: { type: 'string' },
status: { enum: ['available', 'flying'] },
fuel: { type: 'number' },
maxFuel: { type: 'number' },
locationIcao: { type: 'string' },
locationName: { type: 'string' },
contractId: { type: ['string', 'null'] },
lat: { type: 'number' },
lon: { type: 'number' },
},
required: [
'id',
'model',
'status',
'fuel',
'maxFuel',
'locationIcao',
'locationName',
'contractId',
'lat',
'lon',
],
},
ContractState: {
type: 'object',
properties: {
id: { type: 'string' },
originIcao: { type: 'string' },
originName: { type: 'string' },
destIcao: { type: 'string' },
destName: { type: 'string' },
reward: { type: 'number' },
cargoType: { type: 'string' },
cargoCount: { type: 'integer' },
deadlineSimTime: { type: 'integer', description: 'Sim-clock epoch ms (game time)' },
status: { enum: ['open', 'accepted', 'completed'] },
planeId: { type: ['string', 'null'] },
createdSimTime: { type: 'integer' },
},
required: [
'id',
'originIcao',
'originName',
'destIcao',
'destName',
'reward',
'cargoType',
'cargoCount',
'deadlineSimTime',
'status',
'planeId',
'createdSimTime',
],
},
},
},
};