Files
runicgateway.com/src/config/sidebar.mjs
wtclaude ecc556d7ac
All checks were successful
PR checks / checks (pull_request) Successful in 2m11s
feat(docs): phase 16 - the RunicNPC subgroup, its API carried in full and drift-checked
PLAN.md §16 phase 16, with the org lead's D72-D74 (count of record 74).

- Eight pages nested in the Rust group at /docs/rust/runicnpc/ (D72): the
  overview, Install RunicNPC, Commands, NPC profiles, NPC placements, Cost and
  caps, Profile fields (the one field reference the editor, rnpc.profile set,
  the data file and the API all share) and The API.
- The API page carries every call, hook and data shape (D62), in the site's
  own words, with no decision numbers and no per-call version history (D74).
  Signatures print from src/data/runicnpc.mjs through Signature.astro.
- checkReference.mjs gains two sections. Against docs main:runicnpc/API.md:
  the API version, 24 call and 10 hook signatures, and the field names of the
  profile, RunicNpc_List rows, placements, routes and owners (D73), plus
  exactly one <Signature> per call on api.mdx. Against runicnpc-rust
  main:plugin/RunicNPC.cs: console verbs, permissions, place options and
  config keys. Six planted drifts all failed before it was trusted.
- checkSidebar and checkTerms read nested sidebar groups via flatLabels().
- The Rust overview, Events zones and rewards, and Canonical documents link
  the new pages; the canonical documents gain the four runicnpc/ docs.

Both NPC admin screens were walked on the walk site first (D36); nothing was
saved. npm run verify is green.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
2026-10-22 15:49:07 -05:00

259 lines
11 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* The documentation sidebar — PLAN.md §10 "Documentation": five core groups, then one group
* per game after them (§16, D60).
*
* The pages themselves land in phases 7 and 8. This file exists in phase 1 because the
* shape of the journey is a design decision that is already made, and because a sidebar
* written up front is what stops the docs from being organised by repository. A reader
* should never need to know that `link`, `servuo-plugins` and `installer` are three
* repositories in order to connect a game server (§10).
*
* `autogenerate` is deliberately NOT used: the order of "Getting started" is the
* installation path from §10, and alphabetical order would scramble it.
*
* Entries are added as their pages are written — Starlight fails the build on a link to a
* page that does not exist, which is the behaviour we want.
*/
export const docsSidebar = [
{
label: 'Getting started',
items: [
{ label: 'What is Runic Gateway?', slug: 'docs' },
{ label: 'Requirements', slug: 'docs/getting-started/requirements' },
{ label: 'Install the site', slug: 'docs/getting-started/install-the-site' },
{ label: 'First run', slug: 'docs/getting-started/first-run' },
{ label: 'Install a game module', slug: 'docs/getting-started/install-a-game-module' },
{ label: 'Connect your game server', slug: 'docs/getting-started/connect-a-game-server' },
{ label: 'Verify the whole stack', slug: 'docs/getting-started/verify-the-whole-stack' },
],
},
{
label: 'Administration',
items: [
{ label: 'Configuration', slug: 'docs/administration/configuration' },
{ label: 'Branding and theming', slug: 'docs/administration/branding-and-theming' },
{ label: 'Navigation and pages', slug: 'docs/administration/navigation-and-pages' },
{ label: 'Content', slug: 'docs/administration/content' },
{ label: 'Users and roles', slug: 'docs/administration/users-and-roles' },
{ label: 'Authentication', slug: 'docs/administration/authentication' },
{ label: 'Teams', slug: 'docs/administration/teams' },
{ label: 'Scheduled events', slug: 'docs/administration/events' },
{ label: 'Moderation', slug: 'docs/administration/moderation' },
{ label: 'Notifications and email', slug: 'docs/administration/notifications-and-email' },
{ label: 'Engagement rules', slug: 'docs/administration/engagement-rules' },
{ label: 'Message templates', slug: 'docs/administration/message-templates' },
{ label: 'Managing modules', slug: 'docs/administration/managing-modules' },
{ label: 'Maintenance and upgrades', slug: 'docs/administration/maintenance-and-upgrades' },
{ label: 'Troubleshooting', slug: 'docs/administration/troubleshooting' },
],
},
{
label: 'Modules',
items: [
{ label: 'The module system', slug: 'docs/modules/the-module-system' },
{ label: 'Installing modules', slug: 'docs/modules/installing-modules' },
{ label: 'Module lifecycle', slug: 'docs/modules/module-lifecycle' },
{ label: 'The module manifest', slug: 'docs/modules/the-module-manifest' },
{ label: 'The module API', slug: 'docs/modules/the-module-api' },
{ label: 'Building a module', slug: 'docs/modules/building-a-module' },
{ label: 'The Integration Kit', slug: 'docs/modules/the-integration-kit' },
{ label: 'Testing and release', slug: 'docs/modules/testing-and-release' },
],
},
{
label: 'Architecture',
items: [
{ label: 'System architecture', slug: 'docs/architecture/system-architecture' },
{ label: 'The bridge', slug: 'docs/architecture/the-bridge' },
{ label: 'Authentication architecture', slug: 'docs/architecture/authentication-architecture' },
{ label: 'Teams architecture', slug: 'docs/architecture/teams-architecture' },
{ label: 'Events architecture', slug: 'docs/architecture/events-architecture' },
{ label: 'Protocol versions', slug: 'docs/architecture/protocol-versions' },
],
},
{
label: 'Reference',
items: [
{ label: 'Environment variables', slug: 'docs/reference/environment-variables' },
{ label: 'Installer CLI', slug: 'docs/reference/installer-cli' },
{ label: 'HTTP API', slug: 'docs/reference/http-api' },
{ label: 'Canonical documents', slug: 'docs/reference/canonical-documents' },
],
},
// One group per game, after Reference (PLAN.md §16, D60). Everything above this line is
// core and is held to core's words by checkTerms.mjs (D63, D64). A group whose label is a
// game's `name` in platform.json is that game's group, and may use that game's words — so
// the label is load-bearing: renaming it here without renaming the game turns it core.
{
label: 'Ultima Online',
items: [
{ label: 'The Ultima Online module', slug: 'docs/ultima-online' },
{ label: 'Connect a ServUO shard', slug: 'docs/ultima-online/connect-a-servuo-shard' },
{ label: 'Verify the bridge', slug: 'docs/ultima-online/verify-the-bridge' },
{ label: 'The shard connection', slug: 'docs/ultima-online/the-shard-connection' },
{ label: 'Client files', slug: 'docs/ultima-online/client-files' },
{ label: 'Troubleshooting', slug: 'docs/ultima-online/troubleshooting' },
{ label: 'Bridge.cfg', slug: 'docs/ultima-online/bridge-cfg' },
{ label: 'sidecar.toml', slug: 'docs/ultima-online/sidecar-toml' },
{ label: 'Shard event catalog', slug: 'docs/ultima-online/event-catalog' },
],
},
{
label: 'Rust',
items: [
{ label: 'The Rust module', slug: 'docs/rust' },
{ label: 'Install the bridge', slug: 'docs/rust/install-the-bridge' },
{ label: 'Connect the site', slug: 'docs/rust/connect-the-site' },
{ label: 'Verify the bridge', slug: 'docs/rust/verify-the-bridge' },
{ label: 'Linking Steam accounts', slug: 'docs/rust/linking-steam-accounts' },
{ label: 'Permissions and groups', slug: 'docs/rust/permissions-and-groups' },
{ label: 'Mod config from the site', slug: 'docs/rust/mod-config' },
{ label: 'Who sees who is online', slug: 'docs/rust/who-sees-who-is-online' },
{ label: 'Events, zones and rewards', slug: 'docs/rust/events-zones-and-rewards' },
{ label: 'Optional plugins', slug: 'docs/rust/optional-plugins' },
{ label: 'The live map', slug: 'docs/rust/the-live-map' },
{ label: 'Troubleshooting', slug: 'docs/rust/troubleshooting' },
{ label: 'sidecar.toml', slug: 'docs/rust/sidecar-toml' },
{ label: 'RunicGateway.json', slug: 'docs/rust/runicgateway-json' },
{ label: 'Event kinds', slug: 'docs/rust/event-kinds' },
// §16, D61/D72: RunicNPC is a subgroup of Rust, nested so it reads as part of the game.
{
label: 'RunicNPC',
items: [
{ label: 'RunicNPC', slug: 'docs/rust/runicnpc' },
{ label: 'Install RunicNPC', slug: 'docs/rust/runicnpc/install' },
{ label: 'Commands', slug: 'docs/rust/runicnpc/commands' },
{ label: 'NPC profiles', slug: 'docs/rust/runicnpc/npc-profiles' },
{ label: 'NPC placements', slug: 'docs/rust/runicnpc/npc-placements' },
{ label: 'Cost and caps', slug: 'docs/rust/runicnpc/cost-and-caps' },
{ label: 'Profile fields', slug: 'docs/rust/runicnpc/profile-fields' },
{ label: 'The API', slug: 'docs/rust/runicnpc/api' },
],
},
],
},
];
/**
* The tree §10 planned, kept as the record of what was intended — every page it names now
* exists, as of phase 8.
*
* It was the phases 7/8 checklist, and a checklist with nothing left on it is no longer
* pulling its weight: it is a second copy of the tree above, maintained by hand, and it had
* already drifted once (phase 7 added `Content` under D37 and this list was not updated,
* which nothing caught because nothing reads it). `checkSidebar.mjs` now asserts the two
* agree, which is what makes keeping it safe.
*
* Not exported into the Starlight config.
*/
export const plannedSidebar = {
'Getting started': [
'What is Runic Gateway?',
'Requirements',
'Install the site',
'First run',
'Install a game module',
'Connect your game server',
'Verify the whole stack',
],
Administration: [
'Configuration',
'Branding and theming',
'Navigation and pages',
'Content',
'Users and roles',
'Authentication',
'Teams',
'Scheduled events',
'Moderation',
'Notifications and email',
'Engagement rules',
'Message templates',
'Managing modules',
'Maintenance and upgrades',
'Troubleshooting',
],
Modules: [
'The module system',
'Installing modules',
'Module lifecycle',
'The module manifest',
'The module API',
'Building a module',
'The Integration Kit',
'Testing and release',
],
Architecture: [
'System architecture',
'The bridge',
'Authentication architecture',
'Teams architecture',
'Events architecture',
'Protocol versions',
],
Reference: [
'Environment variables',
'Installer CLI',
'HTTP API',
'Canonical documents',
],
'Ultima Online': [
'The Ultima Online module',
'Connect a ServUO shard',
'Verify the bridge',
'The shard connection',
'Client files',
'Troubleshooting',
'Bridge.cfg',
'sidecar.toml',
'Shard event catalog',
],
// PLAN.md §16, D70 (phase 15). RunicNPC's subgroup lands in phase 16 (D61).
Rust: [
'The Rust module',
'Install the bridge',
'Connect the site',
'Verify the bridge',
'Linking Steam accounts',
'Permissions and groups',
'Mod config from the site',
'Who sees who is online',
'Events, zones and rewards',
'Optional plugins',
'The live map',
'Troubleshooting',
'sidecar.toml',
'RunicGateway.json',
'Event kinds',
{
RunicNPC: [
'RunicNPC',
'Install RunicNPC',
'Commands',
'NPC profiles',
'NPC placements',
'Cost and caps',
'Profile fields',
'The API',
],
},
],
};
/**
* A group's items as flat labels, a nested group's pages written `Group › Page` after the
* group's own label. Both trees go through this, so `checkSidebar.mjs` compares nested
* groups as strictly as top-level ones, and `checkTerms.mjs` reads every label.
*
* In `docsSidebar` a nested group is `{ label, items }`; in `plannedSidebar` it is
* `{ Label: [pages] }`.
*/
export function flatLabels(items) {
return items.flatMap((item) => {
if (typeof item === 'string') return [item];
if (Array.isArray(item.items)) return [item.label, ...flatLabels(item.items).map((l) => `${item.label} › ${l}`)];
if ('label' in item) return [item.label];
return Object.entries(item).flatMap(([label, pages]) => [label, ...flatLabels(pages).map((l) => `${label} › ${l}`)]);
});
}