// The module API version — the single number a module's `coreApi` range is // checked against (docs/website/MODULE_API.md §1.1). // // Bump minor when a member is ADDED to ctx or a new register* call appears; // major when one is removed, its signature changes, or its behaviour changes // without a signature change. A core-internal refactor behind an unchanged // member is not a bump. // // Deliberately separate from PROTOCOL_VERSION (which versions the shard wire and // has nothing to say about a website module) and from any module's own version. // 1.9.0 - a sixth registration call: `api.registerEngagementSeeds({ templates, // ruleGroups })` (docs/website/ENGAGEMENT.md Phase 11b, decision 7). A module // could declare a trigger from 1.7.0 and could never say what the mail should // READ like: `templateSeeds.js` and `coreRules.js` are core files with core // arrays in them, so a module's notification was core's generic body or nothing. // Additions only, so minor: every module written against 1.8.0 keeps working and // simply seeds nothing. // // **What a module has to know about it beyond the new name**, because the two // halves behave differently on purpose: // // - **Templates are re-ensured on every boot**, under `seed_key` / // `seed_version` / `customized` - so bumping a body's `seedVersion` reaches // every deployment except the ones where an operator edited that row, and a // template added in a later module version reaches everyone. // - **Rules are one-shot, per named GROUP.** Re-ensuring one would resurrect a // rule an operator deleted and reset one they enabled, so each group carries // its own settings guard. A rule appended to an existing group therefore // reaches FRESH INSTALLS ONLY; one that must reach deployments already // stamped takes a new group key. That is 11a's seed-key finding as an API // rather than as a warning, and the module makes the choice knowingly. // // Two things it deliberately does not permit. A seeded rule is always // `enabled = 0` - it is not a parameter - which is Q3's invariant surviving // contact with the largest seed set in the workstream. And a module may not mark // a template `protected`: that flag means "the system breaks without this body", // which is true of a password reset and of nothing a module ships, and a module // setting it would take an operator's delete button away. // // It runs from `modules/lifecycle.js` `boot()` rather than `seedDefaults()`, and // that is forced rather than chosen: core seeds before `app.js` is required, and // requiring `app.js` is what runs the loader. // 1.8.0 - a seventh value in the audience ceiling lattice: `admin`, a child of // `staff` (docs/website/ENGAGEMENT.md Phase 11, decision 1). A module may now // declare `ceiling: 'admin'` on a trigger or an audience, so the set of values // `registerEventTriggers` and `registerAudiences` accept grew. Additions only, // so minor: every declaration valid before is valid now, no stored value // changes, and module-uo's `coreApi: "^1.3.0"` still resolves. // // It exists because Phase 11's operator-facing triggers - `uo.audit.staff_action`, // `uo.economy.milestone`, `uo.world.saved` - are described everywhere as // admin-audience, and the narrowest value the lattice had was `staff`, which // means admin / editor / moderator. Ceilinging them there would have permitted a // rule that mails the staff audit digest to every editor. // // **What a module has to know about it beyond the new name.** `admin` is the one // pair in the tree with real containment - every admin is staff - so it is the // only place `permits` is true between two non-`authenticated` values: // `permits('staff', 'admin')` holds and nothing else of that shape does. A // trigger ceilinged `staff` therefore accepts an `admin` audience, which is the // intended narrowing, and the reverse is refused as it should be. // 1.7.0 — the engagement contract (docs/website/ENGAGEMENT.md Phase 2). // Additions only, so minor: `api.registerEventTriggers([...])`, // `api.registerAudiences([...])`, `ctx.events.emit(triggerId, envelope)` and // `ctx.inbox.push(userId, item)`. module-uo's `coreApi: "^1.3.0"` still resolves. // // **As in 1.6.0, the number covered the whole surface and the members arrived by // phase, and all of them have now arrived.** `ctx.inbox.push` threw until Phase 7 // built the in-app channel and the table behind it — the same choice, for the // same reason: a member of 1.7.0 that were absent would have made the version a // lie, and one that silently accepted data into a table that did not exist would // have been worse than either. **Filling it in is NOT a bump**: the signature is // the one 1.7.0 declared, and a module written against it needs no change. What a // module WILL see differently is the throw becoming a write, which is the whole // point of the phase. // // One thing here is not a member and is still part of the contract: a trigger id // and a notification-stream id share ONE namespace (ENGAGEMENT.md §7.2, settled // by the org lead in Phase 2). An id has exactly one owner across both facets, // so a module cannot attach a payload contract to another module's stream. That // tightens a rule rather than changing a signature, and nothing registrable // before this bump becomes unregistrable after it — the id grammar was RELAXED // in the same change (`_` is now legal inside a segment). // // 1.6.0 — the Team surface (docs/website/TEAMS.md Part 11). Additions only, so // minor: `api.registerTeamProvider({ getTeams, getTeamMembers, getTeamLeaders })`, // `ctx.teams.publish(event)`, `ctx.teams.reconcile({ reason })`, // `ctx.teams.activity.push(items)`, `api.registerSlashCommands([...])`, and the // client slots `team.overview` / `team.member.row`. module-uo's `coreApi: // "^1.3.0"` still resolves. // // **The number covers the whole surface; the members arrived by phase, and all of // them have now arrived.** `activity.push` landed with the Team activity feed // (§4, phase 3) and `registerSlashCommands` with the Discord commands (§7.1, // phase 7); until each did, it was present and THREW rather than being absent or, // worse, silently accepting data into a table that did not exist. Nothing in // 1.6.0 throws any more. // // 1.5.0 — a CLIENT addition: `PublicLayout` takes an optional `shell` prop that // renders the page body wrapper core's own pages write by hand (MODULE_API.md // §3.4). Minor, not major: §3.4 makes *changing* a kit component's props a major // bump because that breaks a call already written, and adding an optional one // breaks nothing — omitting `shell` is 1.4.0's behaviour exactly. Nothing on the // server changed; this file bumps for the reason below. Found by the Integration // Kit's acceptance run (docs/modules/kit-acceptance.md), where a module built // exactly as the kit teaches rendered outside the site's page column. // // 1.4.0 — no member changed. §2.7 gained one prohibition: a module does not open // a connection to a game server from the website process; it talks to a sidecar, // which owns the durable copy of the game's state. Minor rather than major // because the SURFACE is identical to 1.3.0 — module-uo's `coreApi: "^1.3.0"` // still resolves, and it already complies — but a module written against 1.3.0 // could satisfy every member and still be built the wrong way round, which is // what this number now says. The one §2.7 rule with no CI behind it: an outbound // socket is not statically detectable the way an internal require is. // // 1.3.0 — three CLIENT additions from Phase 3 slice 3: a nav item may carry an // `icon`, core declares a `player.invite.accepted` slot, and `window.__rg.api` // gained `BASE` (which §3.5 always specified and shared.js never published). // Nothing on the server changed; this file bumps for the reason below. // // 1.2.0 — the CLIENT registry gained `registerExtension` and core gained client // extension slots (MODULE_API.md §3.7): the twin of this half's declareSlot / // registerExtension, for module content inside a core *page* rather than under a // core route prefix. Nothing on the server changed, and this file bumps anyway — // the two halves state ONE version, because a module declares a single `coreApi` // range and is served one chunk (client/src/modules/version.js). // // 1.1.0 — `ctx` gained `activity.log`, `users.getById` and `site.baseUrl`, each // because module-uo's extraction needed it and none of them could be vendored: // an admin action a module performs belongs in core's one audit log, the // extension slot needs the user its prefix names, and §2.7 forbids a module // reading core's `APP_BASE_URL` for itself. Additions only, so minor. const MODULE_API_VERSION = '1.9.0' module.exports = { MODULE_API_VERSION }