docs: reflect PR #126 cherry-pick + boot/asset infrastructure

CLAUDE.md
- TL;DR mentions the duckietm PR #126 cherry-pick (UserAccountSettings,
  wear-badge popup fix) and the sirv-based dev asset serving so a fresh
  session knows what's living on top of upstream main.
- New patterns section for the bootstrap.ts configuration pre-init
  and the nitroAssetsServer Vite plugin, with a pointer to the
  .gitignore note explaining why public/{nitro-assets,swf} symlinks
  are a trap.
- "What's wired up" table gets two rows: Form Actions, and the PR #126
  pickup.
- "Where everything lives" gets entries for UserAccountSettingsView,
  the persistAccessTokenFromPayload helper, the asset middleware, and
  the bootstrap pre-init call.

docs/ARCHITECTURE.md
- Recently fixed: adds the useAvatarEditor PETS/MISC paletteID
  null-pointer that surfaced when the editor was opened.
- New Bonus subsections describing the boot-time orchestration in
  bootstrap.ts, the dev asset serving via sirv (and why symlinking
  under public/ is the wrong move on Windows), and the upstream
  feature catch-up via PR #126.

No code changes in this commit — pure documentation refresh.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
simoleo89
2026-05-13 21:19:34 +02:00
parent b01f09c8ea
commit 622d73c2f0
2 changed files with 94 additions and 0 deletions
+40
View File
@@ -12,6 +12,18 @@ infrastructure (TanStack Query, Zustand, Vitest, React Compiler, error
boundaries), split a few god-hooks, and audit logic bugs along the way. boundaries), split a few god-hooks, and audit logic bugs along the way.
PR is **#2** on `simoleo89/Nitro-V3`. PR is **#2** on `simoleo89/Nitro-V3`.
On top of the modernization work this branch also picks up a couple of
upstream feature commits that lived only on `duckietm/Nitro-V3` (PR #126):
reset password / email / change username under user settings, and the
wear-badge popup fix.
Local-dev game assets are served by a small Vite plugin (`sirv` middleware
mounted on `/nitro-assets` and `/swf`, reading from
`E:\Users\simol\Desktop\DEV\Nitro-Files`) — NOT by symlinking inside
`public/`. The symlink path triggers chokidar on ~177k files and the dev
server hangs for minutes on Windows. See `vite.config.mjs` and the
`.gitignore` note.
Detailed status, decisions, and next steps live in **`docs/ARCHITECTURE.md`** — Detailed status, decisions, and next steps live in **`docs/ARCHITECTURE.md`** —
read that before starting anything non-trivial. read that before starting anything non-trivial.
@@ -220,6 +232,25 @@ Login / Register / Forgot in `src/components/login/LoginView.tsx` use
`src/components/login/components/{Register,Forgot}Dialog.tsx` and `src/components/login/components/{Register,Forgot}Dialog.tsx` and
`shared.ts` have been **removed** (dead code). `shared.ts` have been **removed** (dead code).
### Configuration pre-init in bootstrap
`src/bootstrap.ts` calls `await GetConfiguration().init()` **before**
importing `./index`. Otherwise the first paint dumps a flood of
"Missing configuration key" warnings while components synchronously
read `asset.url`, `login.endpoint`, … against an empty store before
`prepare()`'s deferred init lands.
### Asset serving in dev
Game assets (`bundled/`, `c_images/`, `gamedata/`, `swf/...`) are NOT
copied or symlinked under `public/`. They're served by a custom Vite
plugin (`nitroAssetsServer` in `vite.config.mjs`) that mounts `sirv`
on `/nitro-assets` and `/swf`, reading from
`E:\Users\simol\Desktop\DEV\Nitro-Files\`. sirv is a connect-style
middleware that bypasses chokidar entirely, so the ~177k asset files
never enter the watch graph. The plugin also wires the same handler
into `configurePreviewServer` so `yarn preview` keeps working.
## What's wired up and what isn't ## What's wired up and what isn't
| Adopted | Pilot sites | | Adopted | Pilot sites |
@@ -231,6 +262,8 @@ Login / Register / Forgot in `src/components/login/LoginView.tsx` use
| God-hook split (`useBetween` singleton + state filter + actions filter + shim) | `wired-tools`, `translation`, `notification`, `friends` | | God-hook split (`useBetween` singleton + state filter + actions filter + shim) | `wired-tools`, `translation`, `notification`, `friends` |
| `WidgetErrorBoundary` | `RoomWidgetsView` umbrella | | `WidgetErrorBoundary` | `RoomWidgetsView` umbrella |
| Vitest | 113/113 cases on pure helpers + the Zustand store | | Vitest | 113/113 cases on pure helpers + the Zustand store |
| Form Actions | Login / Register / Forgot (LoginView.tsx) |
| Cherry-picked from `duckietm` PR #126 | `UserAccountSettingsView` (reset password / email / username under user settings), plus the wear-badge popup `canShowWearButton` gating |
| Not yet | Notes | | Not yet | Notes |
|---|---| |---|---|
@@ -283,3 +316,10 @@ Fix shapes documented; both are reasonable PRs on their own.
`useMessageEventState`): `src/hooks/events/` `useMessageEventState`): `src/hooks/events/`
- Wired-tools split (types/constants/helpers + 3 tab views): - Wired-tools split (types/constants/helpers + 3 tab views):
`src/components/wired-tools/` `src/components/wired-tools/`
- User account settings (cherry-picked from upstream PR #126):
`src/components/user-settings/UserAccountSettingsView.tsx`
- Access-token persistence helper (used by login + remember + rotate):
`src/api/auth/accessToken.ts` (`persistAccessTokenFromPayload`)
- Asset middleware: `nitroAssetsServer()` in `vite.config.mjs`
- Configuration pre-init: `src/bootstrap.ts` (`await GetConfiguration().init()`
before `import('./index')`)
+54
View File
@@ -565,6 +565,53 @@ Status after this round of work:
session start. Captures the layout convention, the patterns to use, session start. Captures the layout convention, the patterns to use,
what's wired up, what isn't, and the open logic bugs. what's wired up, what isn't, and the open logic bugs.
### Boot-time orchestration (`src/bootstrap.ts`)
- Mobile viewport meta tag inserted before anything else.
- `await loadClientMode()` — fetches `client-mode.json` into
`window.__nitroClientMode` so `getClientMode()` can pick up
`secureAssetsEnabled` / `secureApiEnabled` / `apiBaseUrl` for the
fetch interceptor.
- `installSecureFetch()` (no-op when both `secureAssetsEnabled` and
`secureApiEnabled` are off, which is the dev default).
- Populate `window.NitroConfig` with `config.urls`, `sso.ticket`,
forward parameters.
- **`await GetConfiguration().init()`** — eager configuration load
before React mounts. Eliminates the "Missing configuration key:
asset.url / login.endpoint / login.turnstile.* / …" warning flood
that happens when components synchronously read keys on the first
paint while `prepare()`'s deferred init is still in flight.
- `import('./index')` — dynamic, so we keep top-level await for the
steps above.
### Dev asset serving (`vite.config.mjs`)
- Game asset directories (`bundled/`, `c_images/`, `gamedata/`, `swf/`)
live OUTSIDE the repo. The historical "symlink them into `public/`
so Vite serves them via `publicDir`" trick is a trap on Windows:
chokidar tries to install a watcher on every file under `public/`
and the dev server hangs for minutes on ~177k assets.
- The current setup installs a tiny Vite plugin (`nitroAssetsServer`)
that mounts `sirv` on `/nitro-assets` and `/swf`, reading from
`../Nitro-Files/{nitro-assets,swf}`. `sirv` is connect-style
middleware; it bypasses chokidar entirely.
- The same plugin wires the same handler into
`configurePreviewServer` so `yarn preview` keeps working with the
production build.
- `.gitignore` has explicit entries for `/public/nitro-assets` and
`/public/swf` plus a comment explaining why those paths must not be
recreated as symlinks.
### Upstream feature catch-up
- `duckietm/Nitro-V3` PR #126 is cherry-picked: adds
`src/components/user-settings/UserAccountSettingsView.tsx`
(reset password / email / change username flows under the user
settings overlay) and a wear-badge popup fix in
`NotificationBadgeReceivedBubbleView` that gates the button on the
`canShowWearButton` derived predicate. The cherry-pick required
reconciling the LoginView fork to the Form Actions migration
(`useActionState` + `useFormStatus`) and restoring the
`useEffectEvent`-wrapped subscription pattern used elsewhere in
this branch.
--- ---
## How to pick the next refactor PR ## How to pick the next refactor PR
@@ -709,3 +756,10 @@ data-corrupting.
`roomSession.userDataManager.getPetData(parser.petId)` could throw if `roomSession.userDataManager.getPetData(parser.petId)` could throw if
`roomSession` was null at the moment the event arrived (between rooms). `roomSession` was null at the moment the event arrived (between rooms).
Fixed with `?.` chain. Fixed with `?.` chain.
- **`useAvatarEditor` `set.paletteID` null-pointer** —
`buildCategory` read `set.paletteID` on the line above its
`if(!set || !palette) return null` guard. For categories where
`getSetType()` legitimately returns null (PETS / MISC without
server-side figure data), this threw and the avatar editor crashed
on open, escalating to `WidgetErrorBoundary`. Split the guard so
`set` is checked before its property access.