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:
@@ -343,6 +343,31 @@ test('a live run carries its phase LABEL, and never the spec behind it', async (
|
||||
assert.equal(JSON.stringify(page).includes('core.announce'), false)
|
||||
})
|
||||
|
||||
test('only the live occurrence carries progress, asked for the reader (1.12.0)', async () => {
|
||||
const progress = require('../src/events/progress')
|
||||
const original = progress.forRun
|
||||
const asked = []
|
||||
progress.forRun = async (run, { viewer }) => {
|
||||
asked.push({ run: run.id, viewer })
|
||||
return [{ label: 'Bandits', left: 3, of: 8 }]
|
||||
}
|
||||
try {
|
||||
store.runs[0].status = 'running'
|
||||
const page = await publicModel.event('the-yew-invasion', { userId: 42 })
|
||||
assert.deepEqual(page.event.current.progress, [{ label: 'Bandits', left: 3, of: 8 }])
|
||||
assert.deepEqual(asked, [{ run: 3692, viewer: { userId: 42 } }])
|
||||
for (const o of [...page.event.upcoming, ...page.event.past]) assert.equal(o.progress, undefined)
|
||||
|
||||
store.runs[0].status = 'completed'
|
||||
asked.length = 0
|
||||
const done = await publicModel.event('the-yew-invasion')
|
||||
assert.equal(done.event.current, null)
|
||||
assert.equal(asked.length, 0, 'a finished run is not asked')
|
||||
} finally {
|
||||
progress.forRun = original
|
||||
}
|
||||
})
|
||||
|
||||
test('a phase the pinned version does not name renders nothing rather than an id', async () => {
|
||||
store.runs[0].status = 'running'
|
||||
store.runs[0].current_phase = 'a-phase-since-renamed'
|
||||
|
||||
Reference in New Issue
Block a user