feat!: useShapeQuery lit par la requete de forme du SDK

This commit is contained in:
Sylvain Duchesne
2026-09-21 11:41:31 +02:00
parent a5e553e65b
commit 77e78ec81d
29 changed files with 1190 additions and 971 deletions
@@ -43,7 +43,7 @@
* code. Making it async would push the wait onto the app, which is exactly the
* obligation this removes. So the work runs in the background and announces itself
* through the registry's change signal (`CapRegistry.onChange`), which is what
* `watchShape` already listens to — a view that was empty for want of a cap
* `useShapeQuery` already listens to - a view that was empty for want of a cap
* re-reads when the cap lands. {@link connectedUser} is there for a caller that
* genuinely needs to await it (tests, an app that wants a deterministic start).
*
@@ -36,7 +36,7 @@
* - the REGISTER — an inbox opened mid-session appends an `AddInboxCap` record to the
* User branch of the private store (`branch-registers.openDocumentInbox`), so a push on
* that document re-enumerates `myInboxes()`;
* - WHAT THIS IDENTITY HOLDS (`CapRegistry.onChange`) — the same signal `watchShape`
* - WHAT THIS IDENTITY HOLDS (`CapRegistry.onChange`) - the same signal `useShapeQuery`
* re-reads on. It answers the case the register cannot: an identity that connects
* before it has an account at all. Provisioning is lazy here, so a person's FIRST visit
* connects with no stores, no private store to follow and no inbox to watch; the
@@ -137,8 +137,8 @@ export function resetOpenedRepos(): void {
syncState.clear();
boundSessionId = null;
OPEN_TIMEOUT_MS = 8000;
// Whatever ELSE was still subscribed to a document — a `watchShape` following a scope,
// an inbox observation — belongs to the session that just went away too. One real
// Whatever ELSE was still subscribed to a document - an inbox observation, an
// application's own `subscribeDoc` - belongs to the session that just went away too. One real
// subscription now serves all of them (`surface/subscribe.ts`), so dropping the bootstrap
// ones above no longer closes those channels; they are re-opened against the new session,
// with their barrier forgotten. Without this a bootstrap open would join a surviving
@@ -16,12 +16,15 @@
* ── What this filter cannot do, and where that shows ──────────────────────
* It is SYNCHRONOUS and decides from what the holder holds at that instant. A document
* in a PUBLIC store hands its cap to whoever asks (`public-store.ts`), but asking is a
* round-trip — so this view drops such a document until some read path has asked.
* Every path this library owns does ask (`readUnion`, `docs.sparqlQuery`,
* `ensureRepoOpen`, `documentInboxAddress`), which covers `watchShape`; what it does
* not cover is `useShape`, whose signature is the real ORM's and has no await to
* spend. An application reaching a public document through `useShape` alone, having
* read it nowhere first, sees nothing. A polyfill-era limit, removed with the module.
* round-trip - so this filter drops such a document until some read path has asked.
* The paths that DO ask are the ones this library still reads with (`readUnion`,
* `docs.sparqlQuery`, `ensureRepoOpen`, `documentInboxAddress`). The two SHAPE reads
* ask nothing: `useShape` because its signature is the real ORM's and has no await to
* spend, and `useShapeQuery` since `1.0.0-dev.6`, because it reads through the SDK's
* own shape query and no longer opens a document of its own. An application reaching a
* public document through either of them alone, having read it nowhere first, sees
* nothing until it does - and a cap that lands later makes both re-publish, since each
* follows `CapRegistry.onChange`. A polyfill-era limit, removed with the module.
*
* Note there is no `user` parameter anywhere below, and that is the point: reading
* is key possession, so the only question askable is "do I hold this document's