feat(client): watchShape — lecture réactive à la forme TanStack useQuery
Phase A du refactor des lectures. Surface la barrière de sync interne
(open-repo `getSyncState`) dans une API useQuery-shaped, en anticipation de la
mise à jour prévue de useShape par NextGraph — distingue nativement « sync en
cours » de « synchronisé mais vide ».
`watchShape<T>(shapeType, scope): { getSnapshot(): ShapeQuery<T>, subscribe(cb),
refetch() }` avec `ShapeQuery = { data, isPending, isSuccess, isError, error }`.
OBSERVABLE (pas de dépendance React — l'app câblera useSyncExternalStore en
phase B) ; getSnapshot rend une référence stable.
- Scope LOGIQUE (public/protected/private) résolu au wallet virtuel :
listMyEntityDocs(getCurrentUser, scope) + découverte foldée pour public.
- isPending tant que la barrière n'est pas atteinte / 1er readUnion non rendu ;
isSuccess après ; timed-out → isSuccess (best-effort, pas isError).
- Réactif SANS polling : subscribeDoc sur les docs + le doc d'index de scope
(+ index découverte) → re-read/re-résolution au push ; souscriptions idempotentes.
- Générique : aucune logique domaine Festipod dans le lib ; filtre par la shape
SHEX (rdf:type). Pas de double filtre cap.
gate : tsc 0 ; bun test 120 (+4 : pending→success, synced-vide, réactif, timed-out) ;
test:e2e 42 passed (+scénario broker réel : isPending au 1er snapshot → isSuccess
avec données, scope vide → isSuccess data:[]).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -495,6 +495,20 @@ export async function listEntityDocs(scope: Scope): Promise<Nuri[]> {
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* The scope-INDEX document NURI of ONE account (`id`) for `scope` — the
|
||||
* store-container document that LISTS the account's per-entity document NURIs
|
||||
* (what {@link listMyEntityDocs} reads). Exposed so a reactive reader
|
||||
* ({@link watchShape}) can SUBSCRIBE to this index document and re-resolve the
|
||||
* entity-doc set when the index changes (a new entity created appends a NURI
|
||||
* here). Idempotent via `ensureAccount`'s cache. At migration this becomes the
|
||||
* user's real per-scope store NURI (the container the store itself provides).
|
||||
*/
|
||||
export async function scopeIndexDoc(id: string, scope: Scope): Promise<Nuri> {
|
||||
const record = await ensureAccount(id);
|
||||
return indexDocOf(record, scope);
|
||||
}
|
||||
|
||||
/**
|
||||
* The entity-document NURIs of `scope` belonging to ONE account (`id`) —
|
||||
* the read-by-need path for one account's own entities. Bounded to a SINGLE
|
||||
|
||||
Reference in New Issue
Block a user