mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-15 00:01:10 +02:00
Modules mounted before the active-space bootstrap finished rendered
empty on first paint and stayed empty until some unrelated Dexie
write happened to wake the querier up. Reproducible in wardrobe:
open the module, the face-ref banner stays visible (even though
face-ref is set), the garment grid is empty; create a new garment
and suddenly the existing ones appear alongside it.
Root cause: Dexie's `liveQuery` only re-runs when a Dexie table it
read during evaluation is written to. `getInScopeSpaceIds()` reads
from plain Svelte `$state` (active-space.svelte.ts `active` +
current-user.ts `currentUserId`), which is invisible to Dexie's
change tracker. So:
1. User opens /wardrobe.
2. First querier runs. getActiveSpaceId() is still null (bootstrap
hasn't resolved yet). getInScopeSpaceIds() returns
[`_personal:guest`].
3. Existing rows are stamped `_personal:<userId>` or a real
space-id — no match. Filter emits [].
4. Bootstrap resolves, setActiveSpace fires, `active = realSpace`.
Svelte $state assignment: invisible to Dexie.
5. liveQuery never re-runs; user sees empty until a subsequent
Dexie write forces a re-evaluation.
Fix: add `_scopeCursor`, a single-row infra table, as a Dexie
proxy for the scope-state signal.
- `data/scope/cursor.ts`: new module with two exports.
`bumpScopeCursor()` writes `{id:'active', bumpedAt}` to the
cursor. `touchScopeCursor()` reads from it, fire-and-forget —
the Dexie read registers the liveQuery subscription during
querier execution.
- Dexie v45 registers `_scopeCursor: 'id'`. NOT in SYNC_APP_MAP:
it's a client-side liveness signal, not user data, so the
creating-hook loop ignores it and no pending-change rows are
generated.
- `scopedTable` / `scopedGet` / `scopedAnd` in `scoped-db.ts` call
`touchScopeCursor()` on every invocation. Since those run inside
each querier's body, liveQuery picks up the subscription for free.
- `setActiveSpace` (direct + both loadActiveSpace branches) calls
`bumpScopeCursor()` after the `$state` update.
- `setCurrentUserId` in current-user.ts calls `bumpScopeCursor()`
via dynamic import so the module stays leaf-level (no eager
Dexie dep in test envs that mock fake-indexeddb differently).
Net effect: every scope change triggers one Dexie write to an
infra table, every liveQuery that went through `scopedForModule`
sees the write and re-evaluates with the fresh
`getInScopeSpaceIds()`. The first-mount race that left wardrobe
stuck on an empty list is gone.
Existing 14 scope regression tests still pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|---|---|---|
| .. | ||
| api | ||
| calc/packages/shared | ||
| calendar | ||
| cards | ||
| chat | ||
| citycorners | ||
| contacts | ||
| context | ||
| docs | ||
| food | ||
| guides | ||
| inventory | ||
| mana | ||
| manavoxel | ||
| memoro | ||
| moodlit | ||
| mukke | ||
| news | ||
| photos | ||
| picture | ||
| plants | ||
| presi | ||
| questions | ||
| quotes/packages/content | ||
| skilltree | ||
| storage | ||
| times | ||
| todo | ||
| traces | ||
| uload | ||