Conversation
Documents the RoomPlugin system (definePlugins, lifecycle ordering, message handler rules, typed state access, isolated testing) and the first-party IdleKickPlugin shipped at colyseus/plugins/idle-kick. Assisted-by: Claude Opus 4.7
Documents the WebRTC signaling plugin shipped at colyseus/plugins/webrtc, including the signaling message table, client-side WebRTCClient API from @colyseus/webrtc/client, and the maxPayload caveat for SDP-heavy exchanges. Assisted-by: Claude Opus 4.7
Assisted-by: Claude Opus 4.7
…ions Rewrite the Room Plugins page around the array form of `definePlugins([...])`: each plugin owns its key via `readonly pluginName`, so `this.plugins.<key>` autocomplete works without the user picking a name. The keyed-record form is kept as "Multiple instances of the same plugin" for when the same class is mounted twice. Document `static dependencies` (auto-pull-in of prerequisite plugins, zero-arg constructors, transitive resolution, dedup by class) and add a warning callout against `<this>` in the `plugins =` initializer — it triggers a TS7022 cycle and collapses autocomplete to `any`. The canonical pattern is a type alias declared outside the room class. Two new plugin pages: UniqueSessionPlugin (one concurrent session per user, reject/replace) and TrackUserSessionsPlugin (per-user reverse index in Presence — explicit install when the admin Active rooms tab should surface a user's current room). Assisted-by: Claude Opus 4.7
- Unify section skeleton: Features → Installation → Mounting → Usage → Password protection - Lead with Features right after the intro on both pages - Sentence-case headings; consistent app.config.ts code samples - playground: drop Screenshots/Rooms wrapper, promote API endpoints to top level Assisted-by: Claude Opus 4.7
…layer - Rewrite pages/database.mdx around @colyseus/database (GameDatabase, services, matchmaker driver, custom schema), with Drizzle/BYO as the secondary fallback - Cover dialects (SQLite default, PostgreSQL; PGlite as lower-profile option), migration strategies, room plugins, and feature overviews (auth, cloud saves, leaderboards, live configs, analytics/moderation/notes) - Move Database from the Tools section to API Reference in the nav Assisted-by: Claude Opus 4.7
…o-end
database.mdx:
- Promote Authentication to a top-level ### section under @colyseus/database
with what's-wired-automatically bullets, minimal setup, admin helpers,
and customization pointer
- Update cloud saves to the current save(userId, data, slot?, expectedVersion?)
signature; document delete()
- Reframe "Custom schema" as "Customizing built-in table schemas" with a
full table of the 10 built-in tables and which service uses each
- Simplify the configs Zod example to .default({}) (inner field defaults
fill the object)
auth/module.mdx:
- Top-of-page callout pointing to the database integration
- Frame the Backend API section as the manual path
auth.mdx (landing):
- Lead with the database-backed path as the fastest route
- Add a Database-backed card alongside the existing three
auth/room.mdx:
- Callout noting JWT revocation is automatic when @colyseus/database is wired
- New "With @colyseus/database" section showing db.auth.isBanned() in onAuth
auth/http.mdx:
- Add an HTTP Routes (createEndpoint) tab — auth.middleware() works in both
Express and createMiddleware modes
- Callout on revocation-awareness when @colyseus/database is in use
server/http-routes.mdx:
- New ### JWT Authentication subsection documenting auth.middleware() as the
canonical JWT gate for createEndpoint, with the same revocation callout
Assisted-by: Claude Opus 4.7
Replace the icon Cards with a 5-row table mapping common questions
("How do I authenticate a room join?", "How do I gate a new HTTP route?")
to the page that answers each one. Keep the recommended-path Callout
above the table as the lede.
The Cards previously duplicated the table's destinations; the table
gives readers a one-glance "where do I go" rather than a row of
icon+title-only links.
Assisted-by: Claude Opus 4.7
@colyseus/database AuthService.ban() now folds the tokenVersion bump into the same UPDATE as the ban fields — the package-side fix removes the foot-gun where ban() alone left existing JWTs valid until expiry. Doc changes reflect the new behavior: - pages/auth.mdx: scenario 3 (revoke/force-logout) no longer says "bans don't bump tokenVersion — pair with bumpTokenVersion()"; bans now invalidate live tokens on their own. Refactored /auth landing as an intent-based FAQ with Cards-per-scenario along the way (Common scenarios, 7 entries). - pages/auth/room.mdx: top callout + "With @colyseus/database" section drop the pair-with-bump caveat. - pages/auth/http.mdx, pages/server/http-routes.mdx: revocation callouts now name ban() alongside bumpTokenVersion() as both invalidating live tokens. - pages/database.mdx: JWT-session-revocation bullet rewritten to describe ban() as atomic ban+bump; bumpTokenVersion() positioned as the standalone lever for non-ban revocation. Assisted-by: Claude Opus 4.7
New section:
- pages/admin.mdx — landing page covering install, mount (router + Express),
bootstrap, hardening checklist, full AdminOptions reference. Recommends
auth.settings.onResetPassword for reset emails (player-side flow already
handles delivery) over the panel-specific onResetRequest.
- pages/admin/authentication.mdx — sessions, JWT cookies, 3-role hierarchy,
scoped mods, admin.guard() for gating monitor/playground/custom routes,
password reset, rate limits.
- pages/admin/resources.mdx — defineAdminResource(), list/form/show/create,
per-row + bulk actions, policies, FK auto-linking, audit log.
- pages/admin/dashboard.mdx — 5 preset widgets, custom widgets, 4 render
modes (kpi/table/list/json), polling, 12-column grid.
- pages/admin/rooms.mdx — built-in room inspector (kick/lock/state edit/
dispose), multi-process visibility, RBAC defaults.
- pages/admin/_meta.tsx — sidebar order.
- pages/_meta.tsx — Admin Panel entry in API Reference (after Database).
Reusable component:
- components/scenario-card.tsx — <ScenarioGrid> + <ScenarioCard icon title
href>{children}</ScenarioCard> for landing-page intent indexes.
- style.css — .scenario-grid / .scenario-card with hover lift, shadow,
150ms transitions; theme-agnostic via rgba.
Refactored:
- pages/auth.mdx — collapsed 7 vertical scenario sections into a single
ScenarioGrid with 7 ScenarioCards.
Assisted-by: Claude Opus 4.7
Apply the new CLAUDE.md writing guideline ("Plain, approachable prose.
Skip marketing copy and hedging adverbs; keep the why alongside the
what.") across the admin section. Smaller, more surgical pass than the
previous attempt: cut marketing language ("ships with", "bundles") and
hedging adverbs ("typically", "generally"), but preserve transitional
sentences, brief rationale, and use-case examples.
Net: -/+19 lines across 5 files; CLAUDE.md committed for the first time.
Assisted-by: Claude Opus 4.7
Break pages/database.mdx (395 lines, single page) into a focused landing plus four sub-pages — matching the cadence of the admin section. Landing (pages/database.mdx, ~130 lines): - Intro + service overview + beta callout - Installation - Quick start - Dialects & connection strings - Migrations - Matchmaking driver - Next steps (links to sub-pages) Sub-pages: - pages/database/authentication.mdx — built-in @colyseus/auth integration, admin/moderation helpers, customizing callbacks. - pages/database/services.mdx — cloud saves, leaderboards, live configs, analytics/moderation/notes, plus the matching room plugins folded in (CloudSavesPlugin, LeaderboardsPlugin, AnalyticsPlugin). - pages/database/schemas.mdx — customizing built-in table schemas, with the 10-row built-in tables reference. - pages/database/bring-your-own.mdx — ORMs, query builders, Firebase, and the onAuth/onLeave integration patterns for BYO setups. - pages/database/_meta.tsx — sidebar order. Cross-references updated across 7 pages: /database#authentication-built-in- colyseusauth-integration → /database/authentication; /database#customizing-callbacks → /database/authentication#customizing-callbacks. Assisted-by: Claude Opus 4.7
Covers the three database delivery modes (bring-your-own MMDB, MaxMind auto-download, bundled DB-IP Lite), licensing terms for each, and worked examples for region-locked matchmaking, locale defaults, GDPR-aware analytics routing, and manual lookup via `this.plugins.geoip.lookup(ip)` for reconnect-time re-resolution. Assisted-by: Claude Opus 4.7
Replace the Cards grid with an early table of all five plugins (now including GeoIPPlugin) with one-line descriptions; drop unused Cards import. Assisted-by: Claude Opus 4.7
- matchmaker: add Batch Lookup by Room Id section for matchMaker.findRoomsByIds — single wire op for K known roomIds. - room/plugins/track-user-sessions: document the new static listUserSessions(userId, options?), the UserSessionInfo shape, and the reconcile / removeStale options. Replace the stale matchMaker.query reconcile caveat. - room/plugins/unique-session: update conflictsWith for its new (existing, currentRoom) signature with full IRoomCache exposure. Drop the misleading "scope by game mode metadata" example (it couldn't actually work before) and add three realistic ones: mode-based scoping, per-process exemption, capacity-aware filtering. Add a Performance section noting the 2 wire-op cap. Assisted-by: Claude Opus 4.7
Assisted-by: Claude Opus 4.7
Server (room.mdx): new "Responding to a message" section — a message handler returns a value (awaited) to answer the client; throwing settles the request as an error; the "*" fallback can't answer and unknown types reject with no_handler. Client (sdk.mdx): new "Request/Response" section — room.request() and room.send(type, payload, callback), timeout/rejection behavior, flagged as JS/TS-only for now. roadmap.mdx: point the #331 entry at the new section. Also folds in the previously-staged restructure into a "Shipped in v0.18" section. Assisted-by: Claude Opus 4.7
Add a Server-section page for the Colyseus Vite plugin (colyseus/vite), covering setup, options, dev HMR (tied to devMode), production build, and middleware mode. Cross-link from the Development Mode page and the server devMode option. Assisted-by: Claude Opus 4.7
# Conflicts: # style.css
New pages/netcode/ section (client-prediction, lag-compensation, determinism, recipes) synced to the 0.18 observer-model predict API, with targeted fixes across auth, database, faq, migrating and the phaser tutorial surfaced by the full-site audit. Assisted-by: Claude Opus 4.8
- sim step examples flipped to (ctx, world, command) - room.clock section rewritten reader-first: always safe to call (no optional chaining), custom-clock swap note moved below the timelines - input.data: note that undeclared-field writes do nothing and warn once per key with the debug panel active - concepts.mdx removed — superseded by the netcode section Assisted-by: Claude Opus 4.8
…cessor bookkeeping as a list Assisted-by: Claude Opus 4.8
Migration guide gains: preview/next-tag install callout, schema 4→5 and SDK version bumps, request/response messaging section, client.id / fossil-delta-serializer removals, playground production lockdown. Banner + header badge flip from 0.17 to 0.18. Assisted-by: Claude Opus 4.8
…cipe The three matchmaking flags were listed without semantics, and the password recipe recommended setPrivate() — which excludes the room from joinOrCreate() matching, defeating its own filterBy(['password']) step (verified against the 0.18 test harness). - room#matchmaking-properties: flag × join-path table, per-flag guidance, no-built-in-password callout; restore the truncated lock()/unlock() sections and the individual-setters list; metadata is replaced, not merged - password recipe: filterBy + unlisted (not private) + onAuth() check to cover the joinById bypass and the missing-password-field hole - consistency: driver/matchmaker/lobby pages now agree on what each flag filters Thanks @jeffreyhugh for the heads-up! Assisted-by: Claude Opus 4.8
- Document `onAuth` as a plugin hook: ordering row, the returns-nothing contract, and how GeoIPPlugin uses it to populate `client.geoip`. - Switch examples to the array form of `definePlugins()`, the recommended shape; explain when the record form is worth it. - Note that `@colyseus/geoip` is the one plugin outside the core package. - Replace the misleading `onKick` note: arrows bind `this` to the room. - Repoint broken links (`/auth/room`, `/sdk#send-and-receive-messages`) and swap `this.log.warn` for `console.warn`. Assisted-by: Claude Opus 4.8
Tier 1 of TODO/sidebar-reorg.md — sidebar labels and ordering only, no URL or content changes. Root sidebar: - "API Reference" becomes "Building Your Game", reordered to the dev loop: Server, Rooms, State Sync, Client SDK, Matchmaking, Auth, Database. - Netcode moves out to its own "Advanced" separator — as the flagship 0.18 feature it was buried at 5th-of-9, and the split signals "after the basics". - "Matchmaker API" retitled "Matchmaking"; it was the lone "...API" entry. - Admin Panel moves under "Tools & Integrations" (ex-"Tools") — it's a product, not API reference. - "Infrastructure" renamed "Deploy & Scale". - The consecutive "More" and "Extra" junk drawers merge into "Resources". Server: group children under Setup / Development / Production instead of accretion order. Rooms: title the three untitled children and order by learning curve — messages, timing events, reconnection, exceptions, plugins, built-in. Assisted-by: Claude Opus 4.8
These anchors pointed at headings that no longer exist (or never did):
- /room#patchrate -> #configuration-properties (it's a table row)
- /room#set-simulation-interval -> #game-loop, and the link text had a typo
("setSimiulationInterval"); renamed to setTimestep(), the current name
- /room#client -> #client-instance
- /sdk#consume-seat-reservation -> #other-join-methods
- /sdk#join-or-create-a-room -> #join-or-create-recommended
- /sdk#join-existing-room -> #other-join-methods
Found by slugging every heading with github-slugger (what Nextra uses) and
resolving every `](/page#anchor)` link against it. The existing check-links.js
and find-broken-links.js both split on "#" and only validate the page path,
which is why BROKEN_LINKS.md came out empty.
Assisted-by: Claude Opus 4.8
The two existing checkers (check-links.js, find-broken-links.js) were dead: both used `require` under `"type": "module"`, so they crashed on startup. That's why BROKEN_LINKS.md was empty — it wasn't "no broken links found", the script never ran. Both are replaced by scripts/check-links.js. The new checker validates anchors, not just page paths. A link to a renamed heading still loads the page, so it never 404s and rots silently — that class of rot accounted for every one of the 33 fixes here. Headings are slugged with github-slugger (added as a devDependency), the same slugger Nextra uses, so results match what ships. It also: - checks same-page `#anchor` links and trailing-slash routes (`/sdk/#x`) - skips fenced code, JSX/HTML comments, and inline code, so commented-out <Cards.Card href> entries don't register as links - unwraps `[label](url)` in headings, so `## Self-hosting on [Vultr](…)` slugs as self-hosting-on-vultr - exits non-zero, so it can gate CI Run with `npm run check-links`. Notable fixes: 4 tutorials pointed at a Unity heading renamed to "Running the test server locally"; 9 links used an SDK page structure that no longer exists; migrating/0.15 had a case-mismatched anchor (#onLeave-… vs the lowercase id). Assisted-by: Claude Opus 4.8
Tier 2 (part 1) of TODO/sidebar-reorg.md. room.mdx drops 1,241 -> 801 lines: - pages/room/visibility.mdx — the locked/private/unlisted flags, setMatchmaking, lock/unlock, and the password callout. Titled "Room Visibility & Access: locked, private, unlisted" so the terms people actually search for are in the page title. This is the answer that was invisible at an anchor inside a 1,241-line page. - pages/room/lifecycle.mdx — the full onCreate/onAuth/onJoin/onDrop/onReconnect/ onLeave/onDispose reference plus the devMode and shutdown hooks. room.mdx keeps overview, state, messages, config, communication, reconnection, and Client Instance, with a short pointer where each extracted section was. Old anchors: the plan called for mapping these in pages/404.mdx, but that can't work — /room still exists, so Next serves it 200 and the 404 page never runs. Server-side redirects can't help either, since browsers don't send the fragment. Added <MovedAnchors> (components/moved-anchors.tsx), a small inline script on the source page that maps the 16 moved hashes to their new homes, so external links and bookmarks keep working. Headings were promoted a level (### -> ##), which leaves their slugs unchanged, so every moved anchor resolves on the new page. check-links.js now also validates bare "/path#anchor" string literals, so the redirect map itself is covered — verified with a negative test. Verified: 165/165 pages build, check-links clean, and a line-by-line diff of the original against the three resulting files shows no content lost (the only deltas are the 16 heading promotions and 8 deliberately rewritten links). Assisted-by: Claude Opus 4.8
The Matchmaking unification made "matchmaking/matchmaker" the canon (166 occurrences), but 29 hyphenated stragglers remained — "Match-maker API", "Standalone Match-maker", "match-making requests". Normalized everywhere in prose; code identifiers (matchMaker, isStandaloneMatchMaker) untouched. Renamed headings get new slugs: the /matchmaker shim now also maps match-maker-api (the page's long-lived former H1 slug) alongside match-making. The shim's own historical keys are deliberately left hyphenated — they ARE the old slugs. Also fixed a stale "Built-in Rooms → LobbyRoom" link label left from the section dissolution. Verified: check-links clean, 165/165 pages build. Assisted-by: Claude Opus 4.8
Batch 1 of the SEO pass: every page without frontmatter gets a title and a meta description written from what the page actually covers. Includes the highest-traffic section roots (server.mdx, room.mdx, auth.mdx) and the whole Server child set. Excluded: 404.mdx (script page), the _js_ts_header partial, and the hidden postgresql stub. Verified: check-links clean, 165/165 pages build. Assisted-by: Claude Opus 4.8
Batch 2 of the SEO pass: every page that had a frontmatter title but no description gets one, written from the page's actual content — cloud/*, the transports, state pages, auth children, tutorials, example indexes, and the moved matchmaking pages. Docs-wide coverage is now complete except the hidden postgresql stub and the _js_ts_header partial, both intentional. Verified: check-links clean, 165/165 pages build. Assisted-by: Claude Opus 4.8
room, sdk, server, state, and database all end by pointing onward; the Matchmaking root ended mid-list on exposedMethods values and auth on its scenario grid. Both now close with the established Next Steps pattern, following the build-a-game journey (matchmaking -> auth -> database). netcode intentionally left alone — its Prediction Playground closer is stronger than a generic link list. Verified: check-links clean, 165/165 pages build. Assisted-by: Claude Opus 4.8
The repo had no CI. Two checks: - `pnpm run check-links` — validates every internal link and anchor against real heading slugs, plus the 404.mdx redirect map (dead targets, never-fires entries, shadowed entries). This is the guard that keeps the 38 heading moves from this reorg — and future ones — from rotting. - `pnpm run build` with one retry: next build intermittently fails page-data collection on a random unrelated page and passes on rerun (observed 4x locally on this Next 13 setup). Assisted-by: Claude Opus 4.8
Sidebar shows human titles (Kick Idle, GeoIP, WebRTC, Unique Session, Track User Sessions) instead of class names; prose and page bodies keep referring to the classes (IdleKickPlugin, ...) by their real names. Assisted-by: Claude Opus 4.8
- TODO/sidebar-reorg.md — the completed IA-reorg plan, kept as a record of what moved where and why (all tiers shipped 2026-07-21/22). - TODO/talking-to-the-server.mdx — staged draft, parked until `predict.action` ships; see its header comment. - *.psd ignored (images/hero.psd is a 1.8 MB source file that doesn't belong in git history). Assisted-by: Claude Opus 4.8
First run passed but annotated: v4 actions target the deprecated Node 20 runner and are being forced onto Node 24. Assisted-by: Claude Opus 4.8
Assisted-by: Claude Opus 4.8
Verified against colyseus-0.18 packages/sdk (v0.18.1): - sendBytes examples passed plain number[] arrays. The SDK reads .byteLength from the payload (Room.ts sendBytes), so a plain array yields NaN and silently sends an EMPTY frame. Examples now wrap in Uint8Array, with a warning callout. - Reconnection options table was missing `enabled` (default true) — the switch that disables automatic reconnection entirely. - `enqueuedMessages` status property documented as a number; it is the array of buffered messages (Reconnection.ts). - "Removing Listeners" section had a heading and no body. Documented room.removeAllListeners(), what it clears, and that it runs automatically on leave. Assisted-by: Claude Opus 4.8
Verified against colyseus-0.18 packages/core (v0.18.1):
- All five seat-reservation examples showed the old nested shape
({ sessionId, room: {...} }). 0.18's buildSeatReservation returns a flat
{ name, sessionId, roomId, processId } (ISeatReservation) — no nested
room object, no locked field.
- reserveSeatFor(room) missing its required options argument -> (room, {}).
- findOneRoomAvailable params: roomName is the room *type* (was described
as "id of a specific room instance"), the second parameter is filter
options (not onJoin/onAuth options), and the optional
additionalSortOptions parameter was undocumented.
- The filterBy(['maxClients']) example couldn't work as written: the cache
stores the room instance's real maxClients, not the client option. The
example room now applies the option in onCreate.
- Lobby filters require `name` — the name check runs unconditionally, so a
metadata-only filter matches nothing. Reworded feature bullet + section.
- Lobby JS tab used a default import (@colyseus/sdk has named exports only)
and a TS annotation in a .js sample.
- QueueRoom: maxWaitingCyclesForPriority is declared in QueueOptions but
onCreate never applies it in 0.18.1 — removed from the defineRoom example
and marked subclass-only in the options table.
- Visibility: exact lock-rejection error string is `room "<id>" is locked`.
- Standalone: documented the two fallbacks that can still create a room on
the matchmaker process (no healthy game servers; IPC timeout).
Assisted-by: Claude Opus 4.8
Verified against colyseus-0.18 packages/core (v0.18.1). Highlights: - Failed message validation does NOT silently ignore the message — it disconnects the client with 4002 (WITH_ERROR), or settles a request as an error. - Server-side onDrop semantics: it runs for EVERY non-consented close code (the docs' 1006/1001/1005/4010 list was the client-SDK trigger set); only CONSENTED or a denied in-progress reconnection bypasses it. onLeave additionally runs after a drop once reconnection fails or times out. - Custom close codes are 4011-4999 (4000-4010 are framework-reserved; the page's own table already said so). 4003 is not client-side-only. - onAuth sample used a (token, request) signature matching neither overload; metadata sample assigned a property on undefined; three samples were internally inconsistent (userData.reconnection vs reconnectionInterval, playerNumber vs team); clients.getById is deprecated for clients.get; client.sendBytes needs Uint8Array (plain arrays send an empty frame); 1000-range close-code names aligned with the exported CloseCode enum. - Exception handling: methods list gains onDrop/onReconnect and setTimestep/setFixedTimestep; OnLeaveException's property is `consented`, not `code`; SimulationIntervalException is a deprecated alias of TimestepException; documented OnDropException / OnReconnectException with a callout that 0.18.1 doesn't export them yet. - Reconnection page imported from "colyseus.js" (package is @colyseus/sdk). - RelayRoom: allowReconnectionTime is clamped to 40s (example used 120); the option is allowReconnectionTime, not allowReconnection: true; client snippets rewritten from the removed schema-v2 state.players.onAdd(...) style to Callbacks.get(relay). messages and timing-events pages verified fully clean. Assisted-by: Claude Opus 4.8
Verified against colyseus-0.18 (v0.18.1), including compiling type-level claims against the monorepo's TypeScript 6.0.3: - The "typed client-side use" claim for plugin messages was empirically false for `protected messages` — TS structural checks skip protected members, so they never reach the SDK's message type extraction. Now documents the tension with the protected-visibility guidance and the public escape hatch. - The <this> callout claimed a TS7022 cycle that no longer reproduces on TS 6.0.3 — softened to historical, keeping the type-alias recommendation. - idle-kick: custom close codes are 4011-4999; 4000-4003/4010 are framework-reserved, and 4010 specifically triggers the SDK's auto-reconnect — the opposite of a kick. - geoip: the EuropeRoom sample threw ServerError without importing it. - unique-session: the per-process conflictsWith example exempted the most common duplicate (second tab in the same room — existing.room is undefined for same-room conflicts): now `!existing.room || ...`. webrtc and track-user-sessions pages verified fully clean. Assisted-by: Claude Opus 4.8
Verified against colyseus-0.18 packages/core, transport, drivers, presence (v0.18.1). Highlights: - uWS transport install pinned old majors (@^2.0.1/@^1.4.1) that peer-conflict with core 0.18 — the Express v4/v5 split belongs to the optional uwebsockets-express layer, which the express: callback also silently requires. Now installs @^0.18.0 + documents the extra package. - H3Transport (WebTransport): the express: server option is silently ignored — the Express app must be passed as the required `app` transport option. Example rewritten; warning added. - BunWebSockets options are Bun's WebSocketHandler options, not Bun.serve. - Both selectProcessIdToCreateRoom samples used matchMaker without importing it; defaultOptions merge into onCreate only (not onAuth/onJoin); shutdown also triggers on SIGUSR2/uncaughtException; lifecycle-events list gains visibility-change, metadata-change, and leave's willDispose. - Driver: the class is MongooseDriver (no MongoDriver exists) and takes a connection URI, not an options object. - Presence: removed the hincrbyex section — source marks it "DO NOT USE, internal only". - HTTP routes: get/setSignedCookie require a `secret` argument; "server" scope endpoints ARE routed — they're only hidden from the typed RPC client. - Logging: no logger.log method exists (the Logger adaptor is trace/debug/info/warn/error — .log only worked via the console default); pino's level option takes a string, not 50. - Debugging: three undocumented categories (driver, presence, devmode). transport.mdx, ws, devmode, vite pages verified fully clean. Assisted-by: Claude Opus 4.8
Verified against colyseus-0.18 packages/sdk + core (v0.18.1), including
the last 50 commits on the 0.18 branch. Highlights:
- Predict.get is NOT idempotent — each call constructs a fresh Predict
(unlike Rewind.get, which caches per room). Reworded to "create one and
share it".
- valueAt is offset-free only for reckon-tracked entities; for
controller-bound instances it returns the smoothed pose. Dropped the
wrong parenthetical.
- Lag-comp auto-record fires on each broadcast, not each tick (fixed in
the overview diagram and the server-input summary; the lag-compensation
page already had it right).
- MoveInput sample: `type as t` yields the decorator, not the fluent
builder (t.int8 would be undefined at runtime) — import `t` directly;
and Room<{ input: MoveInput }> needs `SchemaType<typeof MoveInput>`
since schema() returns a value.
- Idle-callback comment implied returning true skips the seat — it
synthesizes a defaults frame; clients.getById -> clients.get.
- determinism: `if (!ctx.isReplay)` IS the idiom for fire-and-forget
presentation (source jsdoc is explicit; the page contradicted its own
client-prediction sibling); snap-absorbed corrections are excluded from
drift telemetry, not zeroed (only me.reset() zeroes).
- lag-compensation: per-attach maxRewindMs sizes that group's history
ring only — the anti-spoof clamp always uses the room-level default.
recipes.mdx verified fully clean.
Assisted-by: Claude Opus 4.8
…audit
Verified against colyseus-0.18 packages/auth + database + core (v0.18.1).
The big three are architectural:
- tokenVersion revocation is enforced by the default static Room.onAuth
ONLY — auth.middleware() never consults revocationCheck, so a revoked
but unexpired JWT still passes every protected HTTP route. The http page
claimed the opposite ("no per-route check needed"); now a warning with
the actual boundary, and the "force-logout" phrasing is qualified to
"next room join" everywhere it appears.
- Static onAuth short-circuits instance onAuth: with the colyseus bundle
installed, the patched static hook decodes the token at matchmake time
and its payload becomes client.auth — the instance hook never runs for
token-bearing clients (and client.auth is undefined when it does run).
Both example overrides (auth/room, database quick-start) were dead code
as written; rewritten as a static onAuth with JWT.verify + isBanned, and
the precedence is now documented.
- db.auth.settings does NOT wire email delivery: onForgotPassword /
onSendEmailConfirmation / onEmailConfirmed remain the user's job (unset,
forgot-password silently no-ops). Also, assigning onto db.auth.settings
mutates a throwaway object (the getter builds a fresh one per access)
and boot-time copying clobbers earlier singleton overrides — the
"customizing callbacks" section now shows the working after-listen()
wrap pattern.
Also: onHashPassword is declared but never invoked in 0.18 (use
Hash.algorithm; noted as non-functional); SESSION_SECRET is preferred,
not required (falls back to JWT_SECRET); three broken samples fixed
(htmlContents -> html, undefined `name` in User.insert, missing async on
an awaiting onJoin).
services and schemas pages verified fully clean.
Assisted-by: Claude Opus 4.8
Verified against colyseus-0.18 packages/monitor, loadtest, testing, admin, database (v0.18.1). Highlights: Tools: - Monitor express-middleware mode: the docs claimed prefix is ignored; the monitor actually dispatches on originalUrl, so the mount path must match the prefix or everything silently 404s. - Loadtest: default endpoint is ws:// not http://; onError's signature is (code, message), so err.message was always undefined. - Unit-testing: samples used assert without importing it, and told readers to run Mocha/Jest tabs with vitest. Admin (the serious ones): - `roles: []` on a custom action was documented as "deny entirely" — it actually skips the role check and allows ANY authenticated identity. And a non-empty roles list does NOT implicitly include admins. Both now a warning; the security inversion is gone. - The mod-role model was wrong in three places: mods have NO access outside assigned scopes (not "read everywhere"), never create/delete; user-role accounts can't use the panel UI at all. Policies REPLACE the default RBAC rule, not refine it. - SessionConfig field names (ttlSeconds/cookieDomain/cookieSecure/ cookieSameSite — docs showed maxAge/domain/sameSite/secure, and the cookie name is a fixed constant); only JWT_SECRET rotation invalidates admin sessions; reset emails ride onForgotPassword (not onResetPassword); reset links expire in 15 minutes, not 1 hour. - Dashboard: health preset is a DB-latency ping (not process metrics), segments renders as KPI, spans are a 24-column antd grid, and half the suggested icon names don't exist in ADMIN_ICON_NAMES. - Rooms: listing has no `unlisted` column; metadata lives on the detail page; state edits audit path+value (no before/after diff). playground and tools index verified fully clean. Assisted-by: Claude Opus 4.8
Verified against @colyseus/schema 5.0.8 (the version shipped in
colyseus-0.18), with the worst offenders runtime-confirmed. Highlights:
- Every JavaScript `schema()` tab used raw definitions ("string",
[ "string" ], { map: Player }) — schema 5 accepts only t.* builders /
Schema subclasses and THROWS on all documented forms, runtime-confirmed.
All 10 JS tabs across state.mdx + schema.mdx rewritten to t.string(),
t.array(...), t.map(...), t.set(...), t.collection(...); intro callout
now states the builder requirement.
- defineTypes() is not "will be removed" — it IS removed; the legacy tab
is now labeled as non-running historical reference.
- Type names are bigint64/biguint64 (the documented bigInt64 casing
silently fails to encode); "number" limits are ±1.798e+308, not 5e±324.
- SetSchema sample deleted/checked string values on a set of numbers.
- Two TS samples used MapSchema without importing it; "cstring" is not a
built-in string encoding.
- view.mdx: has() is a pure membership check (a copy-pasted callback
sentence claimed otherwise); view.add(collection) brings existing
children along — only later additions need individual adds.
- callbacks: codegen --help refreshed (adds --lua/--bundle/--decorator,
fixes upstream "fhe" typo); Haxe unbind var-name mismatch; stray quote
breaking the Unity codegen command.
- react: hooks ship today as @colyseus/react, not "being integrated".
- custom: refIds/refCounts don't exist in 5.0.8 — it's instance[$refId]
and root.refCount, and getRawChangesCallback is now a built-in export
instead of something to hand-roll.
- advanced-usage: $track sample was a syntax error; $encoder/$decoder
samples read unbound variables and misnamed the class; imports fixed.
Assisted-by: Claude Opus 4.8
Twelve candidate framework fixes surfaced while verifying docs claims against colyseus-0.18 v0.18.1 — behavior bugs (ignored QueueRoom option, lobby metadata-only filters, non-revocation-aware HTTP middleware, the admin roles:[] inversion), export/typing gaps, and cosmetics. Each is a candidate upstream issue; the docs describe actual behavior meanwhile. Assisted-by: Claude Opus 4.8
Accuracy edits left scar tissue; this pass restores read flow: - auth/room: the instance-onAuth tab still verified a token — dead code by the page's own new precedence warning. Rewritten as what the hook is actually for (room-specific gates on token-less clients); also fixed a duplicated word in the static tab's callout. - room.mdx / idle-kick: un-nested the double-parenthetical close-code sentences into plain prose. - queue: shortened the in-cell option warning to one clause. - unique-session: compressed the new guard comment to a single line, per inline-comment conventions. - database/authentication: folded the trailing "(Note: ...)" parenthetical into the sentence. - admin/resources: em-dashes in the empty Notes cells so the table doesn't read as half-finished. Verified: check-links clean, 165/165 pages build. Assisted-by: Claude Opus 4.8
…ment Successor plan to sidebar-reorg.md. Tier 1: split the four collection types (70% of state/schema.mdx, zero inbound anchors — cheapest split yet) into state/schema/collections.mdx, de-nesting the Tabs-in-Tabs type intros in the process. Tier 2: a reverse index from each source-bugs-0.18.md item to the doc qualifiers that get DELETED when the fix ships upstream. Tier 3 (parked): verify the non-JS SDK tabs against the local Unity/Defold/Haxe checkouts. Assisted-by: Claude Opus 4.8
The homepage feature list was four bullets of pre-0.16 messaging, two of them generic infrastructure claims — while the differentiators the source audit just verified went unmentioned. Now seven bullets: - Prediction-Ready Netcode (the flagship 0.18 feature — built-in prediction, rollback, interpolation, lag compensation) - Full-Stack Type Safety (Client<typeof server>: typed messages/state) - Batteries Included (auth, database services, plugins, admin, dev tools) - Any Engine (SDK breadth was only implied before) - Rooms & Matchmaking now also points at the unified Matchmaking section; the two infra bullets merged into one Scale & Deploy entry. Also: quickstart's onLeave showed `options` as the second parameter (it's the close code — the audit fixed this everywhere but here, since the homepage sat outside every audit cluster); room import aligned to the `colyseus` package like the rest of the docs; "How does it look like?" -> "What does it look like?"; meta description now mentions prediction. Assisted-by: Claude Opus 4.8
Seven bold-link bullets rendered as a wall of underlined blue text. Now a ScenarioGrid — the same card component the auth, matchmaking, and rooms pages use — with icon + title per card and muted wrapping descriptions. The inline links inside descriptions (database services, self-host, ...) became plain text: ScenarioCard wraps the whole card in an anchor, so nested links would be invalid HTML — and each card's own destination already covers the section. Assisted-by: Claude Opus 4.8
…onnection The page said everything twice and owned content that belongs to the SDK section. 432 -> ~320 lines: - The entire client half (three event sections + Complete Client Example + Reconnection Options + Option Details + Message Buffering) duplicated sdk/connection.mdx — and had already drifted from it once (the options table needed the same audit fix in both places). Now one compact Client-Side snippet showing the three events, with a pointer to Connection Lifecycle & Reconnection for options, backoff, buffering, and manual reconnection. MovedAnchors shim covers the removed anchors. - Server sections reordered to lifecycle order: onDrop -> allowReconnection (which onDrop calls) -> onReconnect -> onLeave. Previously allowReconnection was explained last, after onLeave. - The blockquote Note became a Callout like the rest of the page; the close-codes table links to the full range table on /room; the buffering best-practice bullet links to where buffering now lives. Zero inbound anchor links existed (verified), so the shim is external-link insurance only. Content-preservation diff confirms every removal came from the deduplicated client half. check-links clean, 165/165 build. Assisted-by: Claude Opus 4.8
…uence diagram The hand-drawn box diagram had drifted (emoji-width misalignment, two boxes with different right-edge offsets) and was opaque to screen readers. Nextra 3 bundles @theguild/remark-mermaid + mermaid 11, so a ```mermaid fence renders natively — first use in these docs. A sequence diagram is the correct form for this flow: two participants, self-calls for the hooks, a loop for the backoff retries, and an alt block for the success/failure fork — the same branch structure the numbered overview above it describes. Renders theme-aware in dark mode and scales instead of overflowing. Verified the remark transform ran: the page chunk carries chart:"sequenceDiagram..." into the Mermaid component (SSR emits a client-rendered placeholder, so the static HTML intentionally shows no trace). check-links clean, 165/165 build. Assisted-by: Claude Opus 4.8
progression, not a message exchange The sequence diagram was the wrong form: nearly every step is the framework invoking a hook (a self-call), so the render degenerated into six loopback arrows on two sparse lifelines with a single real cross-arrow — tall, mostly whitespace, still confusing. Now a five-node flowchart: connection lost -> onDrop on both sides (with what each side does) -> the SDK retry loop as the one decision diamond -> onReconnect or onLeave outcomes, stroke-colored green/red. Each node pairs the client and server hooks that fire together, mirroring the numbered overview's "on both sides" framing one-to-one. Assisted-by: Claude Opus 4.8
…style Decorators remain fully supported but move to their own child page (/state/schema/decorators) with the tsconfig setup, @entity edge case, and the defineTypes() legacy note. Schema snippets across the state section, homepage and tutorials now show a single builder code block — the TS/JS tab layer is gone, since builder code is identical in both. Assisted-by: Claude Opus 4.8
Decorators are a big part of legacy apps, so instead of builder-only snippets, every schema definition now has ["Schema Builder", "Decorators"] tabs — builder first. A shared storageKey="schema-style" remembers the selection across pages, same mechanism the old ts-or-js tabs used. Builder-specific sections (SchemaType idiom, field modifiers) and the versioning bodies stay single-snippet with decorator pointers. Assisted-by: Claude Opus 4.8
Upstream revived it (schema-5.0 2a27125) with runtime and codegen deprecation warnings — the removal only shipped in 5.0.0–5.0.8. Assisted-by: Claude Opus 4.8
input() and clock are public members of the SDK Room class, but the /sdk path never mentioned them — only the netcode pages did. Add a pointer-style Sending Input section (matching the messages section shape) and a clock row in the Room Reference table; the full reference stays in /netcode/client-prediction. JS-SDK-only note included. Assisted-by: Claude Opus 4.8
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.