docs(kit): pin core 1.19.0; teach the public demo's module members
The pin moves from 6890a74 (1.17.0) to 69998ec (1.19.0, website#224), past 1.18.0 (website#223). Both are the public demo (DEMO_MODE.md §10 step 3). The chapters were read again for both versions: - Chapter 2: a new section on a public demo site, covering demoLocks in module.json, ctx.demoMode and api.onDemoSeed (1.18.0). The call count becomes twenty. - Chapter 5: a paragraph on an event action's demoRefuses (1.19.0), and a line in the action listing. The one other core change in the window (website#221) is a wording fix on core's Teams panel and nothing a module sees. The template declares none of the new members, so template/module.json's coreApi becomes ^1.19.0 for the equality check only. Checks run at the new pin: - checkCoreApi, links, rename sites and chapter paths all pass, and so do the script tests (10 and 11). - The template's imports, build, externals and swagger checks pass. - Tests pass: server 82, client 20. - The template was loaded as `examplegame` into a real core at this ref through core's own loader, with DEMO_MODE unset and with it true, and it registered both times. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
@@ -147,8 +147,9 @@ statement of your dependencies, and it makes a test double for it — see
|
||||
|
||||
## What you register
|
||||
|
||||
Nineteen calls, all synchronous and all listed in [§2.4][api]: fifteen
|
||||
registrations, the two lifecycle hooks, and the two identity-link hooks. Five of the
|
||||
Twenty calls, all synchronous and all listed in [§2.4][api]: fifteen
|
||||
registrations, the two lifecycle hooks, the two identity-link hooks, and the demo's
|
||||
seed hook. Five of the
|
||||
registrations are the event system's, and [chapter 5](05-events.md) has those. What
|
||||
is worth knowing is not their signatures but the model behind them.
|
||||
|
||||
@@ -537,6 +538,55 @@ api.onIdentityLinked(async ({ userId, provider, subject, displayName }) => {})
|
||||
module made from it is yours to keep or remove.
|
||||
- Neither hook can mint a session or change who is signed in.
|
||||
|
||||
### On a public demo site
|
||||
|
||||
A site can run as a public demo (`MODULE_API_VERSION` 1.18.0). Anybody signs in with
|
||||
published logins, nothing destructive is allowed, and the site is wiped and seeded
|
||||
again every couple of hours. It is the same image with one flag set,
|
||||
`DEMO_MODE=true`. Core locks its own routes; yours are yours to declare, and three
|
||||
members are for that. With the flag off none of them changes anything, except that
|
||||
`demoLocks` is still validated.
|
||||
|
||||
```json
|
||||
"demoLocks": [
|
||||
{ "method": "PUT", "path": "/admin/mygame/servers/:id" },
|
||||
{ "method": "DELETE", "path": "/admin/mygame/servers/:id" }
|
||||
]
|
||||
```
|
||||
|
||||
(The template has no write routes, so this is a shape rather than one of its files.)
|
||||
|
||||
- **`demoLocks` in `module.json` lists your write routes that the demo refuses.**
|
||||
Core answers a match `403 { code: 'DEMO_LOCKED', message }` before your handler
|
||||
runs, the same body it gives for its own locks, so the site's one toast explains
|
||||
it. Writes only (`POST`, `PUT`, `PATCH`, `DELETE`), in your routers' own `:param`
|
||||
syntax with an optional trailing `/*`, and under one of your declared `mounts`.
|
||||
**It is validated on every boot, demo or not**, so a wrong entry fails on your
|
||||
machine rather than only on the demo.
|
||||
- **`ctx.demoMode` is for a lock a route list cannot express**, one that depends on
|
||||
what is in the request rather than which URL it went to. The Rust module refuses a
|
||||
console command by its first word, and a plugin's config file by the plugin that
|
||||
owns it. Check it in your handler and answer with the same `403` body. It is also
|
||||
how you hide the rare read that must never be shown on a demo, such as a file
|
||||
holding credentials; `demoLocks` takes writes only.
|
||||
- **`api.onDemoSeed(fn)` writes your rows into the demo's fresh database.** The seed
|
||||
calls `fn(data, { accounts })`: `data` is your section of the fixture
|
||||
(`modules.<id>`, with every `"$env:NAME"` string already replaced) and `accounts`
|
||||
maps each demo username to its user id. Core never writes your tables. **Upsert,
|
||||
never insert**: the seed may run more than once on one database, and core seeds
|
||||
its own content only the first time but calls your hook on every run. A fixture section for a module with no hook fails the seed, and so does a
|
||||
hook that throws.
|
||||
- **Lock at the server, never in the UI.** A request sent with `curl`, or from an
|
||||
old app build, must be refused exactly like a click. Your pages may explain a lock;
|
||||
they must not hide or disable a control as the way of locking it.
|
||||
- **Declaring `demoLocks` needs `coreApi` `^1.18.0`**, because an older core rejects
|
||||
the unknown key. Using only the other two should declare it as well: an older core
|
||||
has no `onDemoSeed`, and its `ctx.demoMode` is `undefined`, which reads as "not a
|
||||
demo".
|
||||
|
||||
An event step the demo should refuse when it is saved is
|
||||
[chapter 5](05-events.md)'s `demoRefuses`.
|
||||
|
||||
## The schema fragment
|
||||
|
||||
`template/server/db/schema.sql` is your tables. It is replayed **in full, at every
|
||||
|
||||
@@ -150,6 +150,7 @@ api.registerEventActions([{
|
||||
async revert({ runId, resources, idempotencyKey }) {}, // required iff 'ledger'
|
||||
async reconcile({ runId, resources }) {}, // optional
|
||||
async progress({ runId, stepId, idempotencyKey, params, resources, viewer }) {}, // optional, 1.12.0
|
||||
async demoRefuses(params) {}, // optional, 1.19.0
|
||||
}])
|
||||
```
|
||||
|
||||
@@ -189,6 +190,22 @@ event's public page and in the app.
|
||||
already cache, not from a fresh round trip to the game per reader.
|
||||
- **Failure.** A throw or a late answer costs a line, never the page.
|
||||
|
||||
**`demoRefuses` keeps a step off a public demo** (MODULE_API 1.19.0). A demo site
|
||||
([chapter 2](02-website-module.md)) lets anybody author an event, and some steps must
|
||||
never be saved there: the Rust module refuses a console command that would stop the
|
||||
server. Core asks `demoRefuses(params)` only with `DEMO_MODE` on, for every step,
|
||||
when a definition is created, saved or published, with the step's checked params.
|
||||
|
||||
- **The answer.** A sentence refuses the whole write with `403 DEMO_LOCKED`, and the
|
||||
author reads it as written, so phrase it for them: *"quit" is turned off on the
|
||||
demo site.* `null` lets the step through.
|
||||
- **It is a pure check.** No database, no game, nothing changed. A throw refuses too,
|
||||
with core's own sentence, because a lock that cannot decide fails closed.
|
||||
- **Check again in `perform()`**, behind `ctx.demoMode`. A version published before
|
||||
your list grew is never asked again, so the save cannot be the only lock.
|
||||
- **It needs `coreApi` `^1.19.0`.** An older core never asks it, and the save goes
|
||||
through without a word.
|
||||
|
||||
**`example` is required on every param, optional ones included.** It is the
|
||||
authoring form's placeholder. It is one word at declaration time and it is
|
||||
unreconstructable afterwards by anybody who did not write the action.
|
||||
|
||||
@@ -1,10 +1,23 @@
|
||||
{
|
||||
"repo": "https://gitea.whitlocktech.com/RunicGateway/website.git",
|
||||
"branch": "main",
|
||||
"ref": "6890a74c7c4ad5690509e8c163e477d7f7b399e7",
|
||||
"ref": "69998ec54854d46681def92985a2b299ee3582a6",
|
||||
"why": [
|
||||
"The core this kit is written against, pinned to a commit rather than a branch.",
|
||||
"",
|
||||
"2026-10-26: moved from 6890a74 (1.17.0) to 69998ec (1.19.0, website#224),",
|
||||
"past 1.18.0 (website#223). Both are the public demo (DEMO_MODE.md), and the",
|
||||
"chapters were read again for both versions:",
|
||||
"- 1.18.0: demoLocks in module.json, ctx.demoMode and api.onDemoSeed",
|
||||
" (chapter 2 gains a section, and its call count becomes twenty);",
|
||||
"- 1.19.0: an event action's demoRefuses (chapter 5, a paragraph and a line",
|
||||
" in the action listing).",
|
||||
"The one other core change in the window (website#221) is a wording fix on",
|
||||
"core's Teams panel and nothing a module sees. The template declares none of",
|
||||
"the new members, so nothing it does changed meaning; module.json's coreApi",
|
||||
"becomes ^1.19.0 for the equality check. The real core run was repeated at",
|
||||
"this ref, with the template as the only module in the directory.",
|
||||
"",
|
||||
"2026-10-23: moved from 0a37a44 (1.12.0) to 6890a74 (1.17.0, website#220,",
|
||||
"the cutover that brought Steam sign-in and the Rust last fixes to `main`),",
|
||||
"past 1.13.0 to 1.16.0, which reached `main` together on 2026-10-22. The",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"id": "examplegame",
|
||||
"name": "Example Game",
|
||||
"version": "0.1.0",
|
||||
"coreApi": "^1.17.0",
|
||||
"coreApi": "^1.19.0",
|
||||
"server": "server/index.js",
|
||||
"client": { "entry": "client/dist/entry.js" },
|
||||
"schema": "server/db/schema.sql",
|
||||
|
||||
Reference in New Issue
Block a user