diff --git a/server/db/seedDemo.js b/server/db/seedDemo.js index 66fbd34..38cf540 100644 --- a/server/db/seedDemo.js +++ b/server/db/seedDemo.js @@ -17,6 +17,9 @@ // 5. `demo_state` — when the next wipe is due and the published logins, for // the banner and the sign-in page (§6). // +// With the events it also switches on, in the events switchboard, every action +// those events' steps use — otherwise a seeded event cannot run (§7.3). +// // A string `"$env:NAME"` anywhere in the fixture is replaced with that variable, // so the rig's sidecar token lives in the host's .env and never in the repo. An // unset variable fails the run rather than seeding an empty credential. @@ -106,6 +109,26 @@ function checkFixture(fixture) { return problems } +/** + * Every action a seeded event's steps use, once each, in first-use order. + * + * A fresh database has no switchboard rows, so every `change` and `irreversible` + * action starts disabled (EVENTS.md §K) — and a seeded event that answers "not + * enabled on this deployment" when a visitor runs it is a showcase that does not + * show (step-5 walk, W1). The seed switches on exactly these and nothing else. + */ +function eventActionIds(events = []) { + const ids = [] + for (const e of events) { + for (const phase of e?.spec?.phases || []) { + for (const step of phase?.steps || []) { + if (step?.actionId && !ids.includes(step.actionId)) ids.push(step.actionId) + } + } + } + return ids +} + // ── The run ──────────────────────────────────────────────────────────────── /* eslint-disable global-require */ @@ -174,11 +197,18 @@ async function writeContent(fixture, authorId) { if (!pub.ok) throw new Error(`event "${input.name || input.title}" did not publish: ${(pub.errors || []).join('; ')}`) } } + // Uncapped, like a switch an admin flips without filling the cap boxes: the + // deny list (DM11) is what keeps a visitor's own command step harmless, and the + // wipe takes the row away with the rest of the database. + const actionSettings = require('../src/model/events/eventActionSettings.db') + const enabled = eventActionIds(content.events) + for (const actionId of enabled) await actionSettings.put(actionId, { enabled: true, caps: {} }, authorId) log.info('content written', { posts: (content.posts || []).length, wiki: (content.wiki || []).length, pages: (content.pages || []).length, events: (content.events || []).length, + actionsEnabled: enabled, }) } @@ -251,4 +281,4 @@ if (require.main === module) { })() } -module.exports = { resolveEnv, nextResetAt, checkFixture, run } +module.exports = { resolveEnv, nextResetAt, checkFixture, eventActionIds, run } diff --git a/server/test/demoModule.test.js b/server/test/demoModule.test.js index 5998264..4de6d9d 100644 --- a/server/test/demoModule.test.js +++ b/server/test/demoModule.test.js @@ -20,7 +20,7 @@ const db = require('../src/utils/db') const registries = require('../src/modules/registries') const settingsDb = require('../src/model/settings/settings.db') const settings = require('../src/model/settings/settings.model') -const { resolveEnv, nextResetAt, checkFixture } = require('../db/seedDemo') +const { resolveEnv, nextResetAt, checkFixture, eventActionIds } = require('../db/seedDemo') after(() => db.close()) afterEach(() => { @@ -212,6 +212,17 @@ test('checkFixture accepts the four accounts and refuses anything that would lea assert.match(checkFixture({ ...GOOD, modules: [] }).join('\n'), /modules must be an object/) }) +test('eventActionIds lists each action the seeded events use, once, and the shipped fixture names all three', () => { + const step = (actionId) => ({ actionId, params: {} }) + const ev = (...phases) => ({ spec: { phases: phases.map((steps) => ({ steps: steps.map(step) })) } }) + assert.deepEqual(eventActionIds([ev(['a.run', 'core.wait'], ['a.run']), ev(['b.pay']), {}, { spec: {} }]), + ['a.run', 'core.wait', 'b.pay']) + assert.deepEqual(eventActionIds(), []) + + const fixture = require('../../deploy/demo/seed.json') // eslint-disable-line global-require + assert.deepEqual(eventActionIds(fixture.content.events), ['rust.command.run', 'rust.dt.start', 'rust.coins.pay']) +}) + test('seed:demo refuses to run off the demo', async () => { const { run } = require('../db/seedDemo') // eslint-disable-line global-require await assert.rejects(() => run('anything.json'), /only with DEMO_MODE=true/)