CI / build + unit + e2e (pull_request) Failing after 12m34s
New terminal status 'ignored' + ignorePackage action + POST /api/packages/{packageId}/ignore
(no body, no penalty; top-up logic refills the market). Ignore button per open-package row in
the Jobs tab. OpenAPI gains the 13th endpoint; unit tests for the action (happy/409x5/404),
engine terminal-status coverage, and a new e2e spec test.
70 lines
3.4 KiB
TypeScript
70 lines
3.4 KiB
TypeScript
import { integer, real, sqliteTable, text } from 'drizzle-orm/sqlite-core';
|
||
|
||
// Drizzle schema for the game state. Column names/types here are the source of
|
||
// truth; the matching CREATE TABLE statements live in lib/db/client.ts (DDL) and
|
||
// must stay in sync with this file.
|
||
|
||
export const planes = sqliteTable('planes', {
|
||
id: text('id').primaryKey().notNull(),
|
||
model: text('model').notNull(),
|
||
status: text('status', { enum: ['available', 'flying'] }).notNull(),
|
||
fuel: real('fuel').notNull(),
|
||
maxFuel: real('max_fuel').notNull(),
|
||
locationIcao: text('location_icao').notNull(),
|
||
// Current flight destination (v0.12.0) — set by fly, cleared on arrival. The
|
||
// plane's origin is always its locationIcao while flying.
|
||
destIcao: text('dest_icao'),
|
||
lat: real('lat').notNull(),
|
||
lon: real('lon').notNull(),
|
||
// Sim-clock departure time of the current flight (null when available). While
|
||
// flying, `fuel` is frozen at its departure value — live position/fuel are pure
|
||
// functions of the clock (lib/sim/movement.ts), recomputed on read.
|
||
departureSimTime: integer('departure_sim_time'),
|
||
// Queue of upcoming legs NOT yet started (v0.25.0, ISS-043) — ordered JSON array
|
||
// of ICAO strings ('[]' when empty). The ACTIVE leg stays destIcao +
|
||
// departureSimTime; on landing the engine auto-chains queue[0] if fuel covers it.
|
||
queue: text('queue').notNull().default('[]'),
|
||
});
|
||
|
||
// Cargo packages (v0.12.0) replace the old contracts table end-to-end: a package
|
||
// is one cargo unit origin → dest with a reward and deadline. 'loaded' = bound to
|
||
// a plane's slot; it stays bound ('expired') or pays out ('delivered') when the
|
||
// plane arrives at its destination airport.
|
||
export const packages = sqliteTable('packages', {
|
||
id: text('id').primaryKey().notNull(),
|
||
originIcao: text('origin_icao').notNull(),
|
||
destIcao: text('dest_icao').notNull(),
|
||
reward: real('reward').notNull(),
|
||
cargoType: text('cargo_type').notNull(),
|
||
cargoCount: integer('cargo_count').notNull(),
|
||
// Package weight in kg (v0.27.0, ISS-045) — drives load validation (plane payload)
|
||
// and the per-kg part of the payout. Pre-existing rows backfill to the default.
|
||
weightKg: real('weight_kg').notNull().default(2000),
|
||
deadlineSimTime: integer('deadline_sim_time').notNull(),
|
||
// 'expired' = an open OR loaded package whose deadline passed on a tick. Loaded
|
||
// expired packages keep occupying their slot, deliver no reward, and abandon free.
|
||
// 'ignored' (v0.29.0, ISS-047 part B) = a dismissed open job — terminal, leaves the market.
|
||
status: text('status', { enum: ['open', 'loaded', 'delivered', 'expired', 'abandoned', 'ignored'] }).notNull(),
|
||
planeId: text('plane_id'),
|
||
createdSimTime: integer('created_sim_time').notNull(),
|
||
});
|
||
|
||
export const account = sqliteTable('account', {
|
||
cash: real('cash').notNull(),
|
||
reputation: real('reputation').notNull(),
|
||
});
|
||
|
||
export const simState = sqliteTable('sim_state', {
|
||
clockMs: integer('clock_ms').notNull(),
|
||
timeScale: real('time_scale').notNull(),
|
||
paused: integer('paused', { mode: 'boolean' }).notNull(),
|
||
// Real-time (Date.now()) of the last tick — the tick-on-read engine advances
|
||
// clockMs by (now - lastRealTickMs) × timeScale, clamped per tick.
|
||
lastRealTickMs: integer('last_real_tick_ms').notNull(),
|
||
});
|
||
|
||
export type PlaneRow = typeof planes.$inferSelect;
|
||
export type PackageRow = typeof packages.$inferSelect;
|
||
export type AccountRow = typeof account.$inferSelect;
|
||
export type SimStateRow = typeof simState.$inferSelect;
|