diff --git a/CLAUDE.md b/CLAUDE.md index d8a0451..7cfdb23 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -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. 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`** — 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 `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 | 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` | | `WidgetErrorBoundary` | `RoomWidgetsView` umbrella | | 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 | |---|---| @@ -283,3 +316,10 @@ Fix shapes documented; both are reasonable PRs on their own. `useMessageEventState`): `src/hooks/events/` - Wired-tools split (types/constants/helpers + 3 tab views): `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')`) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 658bf95..7b4d277 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -565,6 +565,53 @@ Status after this round of work: session start. Captures the layout convention, the patterns to use, 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 @@ -709,3 +756,10 @@ data-corrupting. `roomSession.userDataManager.getPetData(parser.petId)` could throw if `roomSession` was null at the moment the event arrived (between rooms). 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.