feat(events): an event action's progress() on a live run's public page (MODULE_API 1.12.0)
An event action may declare an optional `progress(envelope)`: how its
step stands while the run is live. Core accepts two shapes and
interprets neither:
- a count: { label, left, of }, rendered "Bandits: 3 of 8 left";
- a percentage: { label, percent }, rendered "The Juggernaut: 62%".
How core asks:
- `events/progress.js` asks each step of a live run whose action has
one. It passes the step's own held ledger rows and the reader's
account id, so the module applies its own visibility.
- Each call has a 2 s deadline. A throw, a late answer or any other
shape is a line not shown, never an error on the page.
- One answer per run and reader is cached for 5 s.
- The public event's live occurrence carries the lines as `progress`.
The route takes an optional session for the reader.
- The page renders them under the phase label and re-reads them every
15 s while the event is live.
Core stays game-agnostic: no game's words are in it. Additive, so a
minor bump. Module-uo declares ^1.10.0, registers no action with
progress(), and its actions and pages are unchanged.
From RunicNPC stage 8 (D304, D305).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
@@ -435,14 +435,14 @@ async function resolveAudience(id, params = {}) {
|
||||
/**
|
||||
* Every declaration WITHOUT its callables — what the admin catalog serves.
|
||||
*
|
||||
* `perform`, `revert`, `reconcile` and `cost` are stripped for the same reason `resolve` is
|
||||
* `perform`, `revert`, `reconcile`, `cost` and `progress` are stripped for the same reason `resolve` is
|
||||
* stripped from an audience and `handler` from a slash command: this is the
|
||||
* object that leaves the process, and the browser's whole relationship with an
|
||||
* action is naming one by id. §F's "a module registers actions server-side and
|
||||
* adds no routes for them" is only true if the functions never ride out.
|
||||
*/
|
||||
const allEventActions = () =>
|
||||
[...eventActions.values()].map(({ perform, revert, reconcile, cost, ...rest }) => rest)
|
||||
[...eventActions.values()].map(({ perform, revert, reconcile, cost, progress, ...rest }) => rest)
|
||||
|
||||
/** One declaration, callables included. The runner's lookup (Phase 2). */
|
||||
const eventAction = (id) => eventActions.get(id) || null
|
||||
@@ -1041,7 +1041,7 @@ function checkActionParam(actionId, entry, seen) {
|
||||
}
|
||||
|
||||
/**
|
||||
* `registerEventActions([{ id, label, risk, reversible, version, budgetMs, cost, params, perform, revert, reconcile }])`.
|
||||
* `registerEventActions([{ id, label, risk, reversible, version, budgetMs, cost, params, perform, revert, reconcile, progress }])`.
|
||||
*
|
||||
* A typed verb core may ask a registrant to carry out. Everything decidable from
|
||||
* the argument alone is decided here, at the call; the collision — is this id
|
||||
@@ -1118,6 +1118,12 @@ function checkEventActionShape(entry) {
|
||||
if (a.cost !== undefined && typeof a.cost !== 'function') {
|
||||
throw new Error(`registerEventActions: ${a.id} cost must be a function of its params`)
|
||||
}
|
||||
// 1.12.0, optional: how a live run's step stands, for its public page
|
||||
// (`events/progress.js`). Any action may declare it; an action that ledgers
|
||||
// nothing can still say something about the world it changed.
|
||||
if (a.progress !== undefined && typeof a.progress !== 'function') {
|
||||
throw new Error(`registerEventActions: ${a.id} progress must be a function`)
|
||||
}
|
||||
|
||||
const version = a.version === undefined ? 1 : a.version
|
||||
if (!Number.isInteger(version) || version < 1) {
|
||||
@@ -1150,6 +1156,7 @@ function checkEventActionShape(entry) {
|
||||
perform: a.perform,
|
||||
revert: a.revert || null,
|
||||
reconcile: a.reconcile || null,
|
||||
progress: a.progress || null,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user