The anonymous surface an event was always for: GET /public/events, /public/events/:slug and /public/events/series/:slug, plus GET /player/events/history, and the four screens over them. Four org-lead decisions taken up front: split Phase 14 into 14a (website) and 14b (the app); add a `listed` flag rather than letting `state` mean both schedulable and announced; put the `events` capability string in the version block rather than publishing core as a pseudo-module; and drop "venue" from the spec rather than adding a field nothing had ever built. `listed` is announcement, not permission. Publishing is what makes a definition runnable, so without a separate flag a surprise event would have to be advertised in order to be allowed to happen. It is a column, a switch in Phase 13's editor, and three SQL predicates -- never a filter applied after a read, which works exactly as well until the first caller that forgets. The public shapes are a projection, and the projection is the security boundary: nothing is spread, so a column added to event_runs next year does not ride out through it. The spec, health, cleanup, claims, errors and member_key are all absent by construction. The six public event triggers gained `eventUrl` (version 1 -> 2), carrying ?run= because the page lives at the definition's slug while every trigger is about one occurrence. notify.event-started gained the button, at seedVersion 2. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016wDDVXWMDz82WqE1i969r4
43 lines
2.3 KiB
JavaScript
43 lines
2.3 KiB
JavaScript
// ── Public API version / identity ──────────────────────────────────────────
|
|
//
|
|
// A tiny, dependency-free descriptor of this backend, surfaced on GET
|
|
// /public/status and GET /public/version. A client (notably the Android app)
|
|
// uses it to:
|
|
// • positively recognize a Runic Gateway backend on first-run (the `service`
|
|
// tag), instead of guessing from an incidental response shape; and
|
|
// • run a version-mismatch guard — compare `api` against the contract the
|
|
// client was built against and surface a clear "update required" state
|
|
// rather than mis-parsing a future, changed response.
|
|
//
|
|
// `api` is the coarse contract version (bumped only on a breaking re-shape, which
|
|
// would be a v2 mount); `server` is the informational package version.
|
|
//
|
|
// ── `capabilities` (Phase 14a) ──
|
|
//
|
|
// Opaque strings naming what CORE serves beyond the surface every backend has —
|
|
// the same idea as a module's `capabilities` on GET /public/modules, and
|
|
// deliberately the same word, so a client feature-detects one way rather than
|
|
// two. They are a different LIST because core is not a module: publishing core
|
|
// as a pseudo-module would leave a client unable to tell "this backend has
|
|
// events" from "a module called core happens to be installed", which is exactly
|
|
// the distinction the loader exists to make.
|
|
//
|
|
// The value is in what is ABSENT. A backend released before Events answers this
|
|
// object with no `capabilities` key at all, so a client can tell an older site
|
|
// from one that simply has nothing on its calendar — which it could not do by
|
|
// probing /public/events, where "not built" and "temporarily down" look alike.
|
|
//
|
|
// Static, because these are compiled-in features rather than installed ones:
|
|
// a core that has these routes always has them. An unknown string is to be
|
|
// treated as absent, exactly as MODULE_API.md §2.1 says of a module's.
|
|
|
|
const pkg = require('../../package.json')
|
|
|
|
module.exports = {
|
|
service: 'runic-gateway', // stable backend identifier for first-run detection
|
|
api: 'v1', // API contract version (matches the /api/v1 mount)
|
|
server: pkg.version || '0.0.0', // server package version (informational)
|
|
// What core serves beyond the baseline. See the note above.
|
|
capabilities: ['events'],
|
|
}
|