Files
suaveplan/openspec/archive/2026-05-24-game-server-core/proposal.md
2026-05-27 23:29:53 +01:00

5.3 KiB
Raw Blame History

Wave A — @suaveplan/game-server core foundation

Package: @suaveplan/game-server Status: PROPOSED Type: extends existing genesis package (0.1.0) Design: ./design.md (inline below) Spec delta: ./specs/game-server/spec.md

Why

Wave A ships the core foundation of @suaveplan/game-server that every later wave (engine, session, state, matchmaking, transport) depends on: the four core interfaces (IGameLogic, IPlayerManager, ISessionManager, IStateManager) with runtime conformance harnesses, the GameEvents typed payload map plus its GAME_EVENT_KEYS registry, the GameEventEmitter typed pub/sub with ergonomic helpers (safeEmit, waitFor, onN, onMultiple), and the AbstractGameLogic Template-Method base class for concrete games. The package already shipped DIContainer, the GameServerError registry, and the Zod-validated core types in the prior change enterprise-game-server-core; Wave A is an additive extension that fills the interfaces / events / abstract-base layer behind a single 0.1.0 publish.

Without this Wave the downstream waves (B: session manager + player manager, C: state manager + replay, D: matchmaking + transport plugins) have no contract to implement against. Shipping it as one isolated wave keeps the surface reviewable, the coverage gate enforceable on the whole package, and the dependent slices unblocked.

What changes

  • ADDED: core/types/core.types.ts — ConnectionStatus, PlayerConnection, SessionNode, SessionData, StateChangeEvent, GameEvents map.
  • ADDED: core/interfaces/i-game-logic/ — IGameLogic<TState, TMove> interface and runIGameLogicConformance harness.
  • ADDED: core/interfaces/i-player-manager/ — IPlayerManager and runIPlayerManagerConformance.
  • ADDED: core/interfaces/i-session-manager/ — ISessionManager and runISessionManagerConformance.
  • ADDED: core/interfaces/i-state-manager/ — IStateManager<TState> and runIStateManagerConformance.
  • ADDED: core/events/game-events/ — GAME_EVENT_KEYS array + isGameEventKey predicate.
  • ADDED: core/events/game-event-emitter/ — GameEventEmitter typed pub/sub with safeEmit / waitFor / onN / onMultiple / per-key listener cap.
  • ADDED: core/abstract-game-logic/ — AbstractGameLogic<TState, TMove> Template-Method base class with injected Clock + IdGenerator and OTel instrumentation.
  • EXTENDED: errors/game-server-error.ts — six new codes (INVALID_MOVE, PLAYER_ALREADY_EXISTS, PLAYER_NOT_FOUND, LISTENER_LIMIT_EXCEEDED, INVALID_LISTENER_COUNT, EVENT_WAIT_TIMEOUT) raised by the new core surface.
  • EXTENDED: root src/index.ts — additive named re-exports for the new Wave A surface.
  • EXTENDED: package.json exports map — 8 new subpath entries, one per feature module.

Impact

Affected dependents

bunx turbo ls --filter=...@suaveplan/game-server enumerates dependents of this package. As of Wave A landing, no genesis package consumes @suaveplan/game-server yet — this is a foundation wave for @suaveplan/game-loop, @suaveplan/game-state-schemas, and the api-plugin-game-server family that will land in Waves B–D.

  • @suaveplan/game-server (self) — [x] tests run / [x] docs reviewed / [ ] no action needed.
  • No external dependents — verified by bunx turbo ls --filter=...@suaveplan/game-server.

Parity Checklist

Capability Upstream Migrated Notes
IGameLogic interface YES YES Genesis tightens any → generic TState/TMove.
Inline AbstractGameLogic in IGameLogic.ts YES UP Genesis splits to its own feature dir.
IPlayerManager interface YES YES Returns ReadonlyArray<PlayerConnection>.
ISessionManager interface YES YES Returns ReadonlyArray<SessionNode>.
IStateManager interface YES YES Readonly<TState> instead of DeepReadonly.
GameEvents map YES UP Variadic tuples collapsed to single-payload objects.
GameEventEmitter extending Node EventEmitter YES UP Self-contained typed emitter; same surface +typed errors.
Wildcard [key: string]: any[] index signature YES NO Scoped out: closed map keeps lint/type safety; downstream needing wildcard analytics can subscribe to GAME_EVENT_KEYS directly.
AbstractGameLogic Template Method YES UP Adds injected Clock + IdGenerator, typed errors, OTel instruments.
cloneState JSON round-trip YES YES
Hook methods (beforeMoveProcessing, etc.) YES YES
Player roster (addPlayer / removePlayer) YES UP Throws GameServerError not plain Error.
Conformance harnesses NO UP Genesis-original — makes interfaces runtime-testable.

Rationale for the single scope-out (wildcard analytics:*): the upstream signature [key: symbol]: any[] defeats type safety and is unused inside the core/ slice; downstream analytics packages can extend GameEvents via module augmentation if needed.

Migration

Wave A is additive — no existing public-surface item is renamed or removed. Consumers of the prior 0.1.0 surface (DIContainer, GameServerError, Zod parsers, types) keep working unchanged. The new error codes extend the registry; pattern-match consumers should not care because none of the new codes were thrown previously.