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:
@@ -187,6 +187,16 @@ test("reversible: 'ledger' without revert() is refused at registration", () => {
|
||||
assert.equal(typeof registries.eventAction('demo.thing.do').revert, 'function')
|
||||
})
|
||||
|
||||
test('progress() is optional, must be a function, and never reaches the catalog (1.12.0)', () => {
|
||||
assert.throws(() => register('demo', [ok({ progress: { label: 'x' } })]), /progress must be a function/)
|
||||
register('demo', [ok({ progress: async () => ({ label: 'Things', left: 1, of: 2 }) })])
|
||||
assert.equal(typeof registries.eventAction('demo.thing.do').progress, 'function')
|
||||
assert.equal(registries.allEventActions().find((a) => a.id === 'demo.thing.do').progress, undefined)
|
||||
registries._reset()
|
||||
register('demo', [ok()])
|
||||
assert.equal(registries.eventAction('demo.thing.do').progress, null)
|
||||
})
|
||||
|
||||
test('perform() is required and cost must be a function', () => {
|
||||
assert.throws(() => register('demo', [ok({ perform: undefined })]), /has no perform\(\)/)
|
||||
assert.throws(() => register('demo', [ok({ cost: { 'demo.things': 1 } })]), /cost must be a function/)
|
||||
|
||||
Reference in New Issue
Block a user