refactor(api): le bootstrap redescend de quatre appels à un
L'objectif acté était deux appels spécifiques au polyfill, voire un. Il en publiait
quatre. Chacun des trois de trop était une raison que la BIBLIOTHÈQUE a, pas un besoin
qu'une application a :
- **`configureStoreRegistry`** existait parce qu'il y a deux internes à câbler — le SDK
injecté d'un côté, la session de l'autre. Vu de l'appelant, les deux disent « voici ce
qu'il te faut pour tourner ». Replié dans `configure`, qui prend désormais
`getSession` / `normalizeId` / `pointerGuard`.
- **`setCurrentUser`** n'a plus lieu d'être publié depuis que le portail d'accès est
passé dans le polyfill : c'est lui qui pose l'identité. Et une application qui nomme
sa propre identité est exactement le geste qui inverse le modèle — il ne doit pas
exister d'appel publié vers lequel se tourner. Le harnais e2e, lui, joue plusieurs
identités sur une même page ; il y accède par le chemin interne, ce qu'un harnais a
le droit de faire et une application non.
- **`connectedUser`** est maintenant attendu DANS `ensureIdentity`. Ce n'était pas une
commodité : la suite applicative avait montré qu'une app devait l'attendre elle-même,
sinon une note qu'on venait de lui partager se lisait comme illisible. J'avais traité
le symptôme dans l'app d'exemple ; le défaut était côté bibliothèque. En amont, ouvrir
la session EST la connexion — aucune application n'attend un second appel.
Reste donc `configure({ … })`, plus `await ensureIdentity()` dont le site d'appel
survit à la migration : une application attendra toujours une session avant de rendre.
Le test étendu hier a fait son travail : les deux contrôles de contrat sont passés au
rouge sur `configureStoreRegistry`, `connectedUser` et `StoreRegistryDeps` dès que la
surface a bougé.
180 tests unitaires, e2e 40/40 (3,4 min) et applicatif 10/10 (0,8 min).
This commit is contained in:
@@ -23,7 +23,7 @@ The four journeys the suite runs, and what each proves:
|
||||
| Bob leaves a message on Alice's note, and only Alice reads it | A depositor FINDS the address from the note itself; depositing grants no reading |
|
||||
| Each actor's list holds their own notes | The boundary, seen from the only place that matters: the screen |
|
||||
|
||||
It has also found three defects of its own, each an application-side one the harness could not see: `connectedUser()` had to be awaited at sign-in (a note just shared with you reads as unreadable otherwise), a stale answer stayed on screen beside a fresh question, and changing the scope did not refresh the list.
|
||||
It has also found three defects of its own, each one the harness could not see. The first turned out to be a LIBRARY defect rather than an application one: the connection work had to be awaited at sign-in, or a note just shared with you read as unreadable — so `ensureIdentity` now awaits it, and `connectedUser` left the published surface. The other two were the application's: a stale answer stayed on screen beside a fresh question, and changing the scope did not refresh the list.
|
||||
|
||||
## Running it
|
||||
|
||||
|
||||
+17
-20
@@ -36,13 +36,10 @@ import {
|
||||
readUnion,
|
||||
storeRegistry,
|
||||
subscribeDoc,
|
||||
connectedUser,
|
||||
type Nuri,
|
||||
type Scope,
|
||||
// Polyfill-era — these three go away, and they are the whole of what goes away.
|
||||
// Polyfill-era — ONE call, and it is the whole of what goes away.
|
||||
configure,
|
||||
configureStoreRegistry,
|
||||
setCurrentUser,
|
||||
} from "@ng-eventually/sdk";
|
||||
import { ng as realNg, init as realInit } from "@ng-org/web";
|
||||
|
||||
@@ -57,11 +54,11 @@ interface Note {
|
||||
body: string;
|
||||
}
|
||||
|
||||
// --- bootstrap: the two polyfill-era calls ---------------------------------
|
||||
// --- bootstrap: ONE polyfill-era call --------------------------------------
|
||||
//
|
||||
// Everything else an application calls is SDK surface, preserved at migration. These
|
||||
// two are the scaffolding: `configure` becomes inert (the app will import the real SDK)
|
||||
// and the identity will come from the wallet instead of a barrier.
|
||||
// Everything else an application calls is SDK surface, preserved at migration. This one
|
||||
// is the scaffolding, and at migration it goes: the app imports the real SDK, and the
|
||||
// identity comes from the wallet instead of a barrier.
|
||||
|
||||
let session: { session_id: string } | null = null;
|
||||
const sessionReady = new Promise<{ session_id: string }>((resolve) => {
|
||||
@@ -81,9 +78,6 @@ configure({
|
||||
fileUrl: "/shared-wallet.ngw",
|
||||
password: (globalThis as { __NOTEBOOK_WALLET_PASSWORD__?: string }).__NOTEBOOK_WALLET_PASSWORD__ ?? "",
|
||||
},
|
||||
});
|
||||
|
||||
configureStoreRegistry({
|
||||
getSession: async () => {
|
||||
const s = session ?? (await sessionReady);
|
||||
return {
|
||||
@@ -190,18 +184,18 @@ function currentIdentity(): string {
|
||||
* Sign in. The library shows its access barrier when it needs one; the day the wallet
|
||||
* supplies the identity, this resolves silently and nothing here changes.
|
||||
*
|
||||
* The `connectedUser()` await is not optional decoration, and the applicative e2e is
|
||||
* what found that out: setting an identity FIRES the connection work — restoring what
|
||||
* others shared with you, draining your inboxes — but does not wait for it. Render
|
||||
* before it lands and a note someone just shared reads as unreadable, which looks like
|
||||
* a permission problem and is a timing one. At migration this becomes the session
|
||||
* opening, and the await stays exactly where it is.
|
||||
* One await, and it covers everything: the gate resolves the identity AND waits for the
|
||||
* connection work it fires (restoring what others shared with you, draining your
|
||||
* inboxes). The application used to have to await that second part itself — the
|
||||
* applicative e2e is what found it out, because a note someone had just shared read as
|
||||
* unreadable, which looks like a permission problem and is a timing one. The library
|
||||
* absorbed it: upstream, opening the session IS the connection, and no application
|
||||
* awaits a second call.
|
||||
*/
|
||||
async function signIn(): Promise<void> {
|
||||
await ensureIdentity();
|
||||
await sessionReady;
|
||||
identity = readIdentityBack();
|
||||
await connectedUser();
|
||||
}
|
||||
|
||||
/** The library owns the identity; the app asks for it rather than remembering it. */
|
||||
@@ -280,5 +274,8 @@ async function main(): Promise<void> {
|
||||
void main();
|
||||
|
||||
// The e2e suite drives this app through the DOM. It exposes nothing else: a test that
|
||||
// needed a back door would be testing something an application cannot do.
|
||||
(globalThis as { __notebook?: unknown }).__notebook = { watchNote, setCurrentUser };
|
||||
// needed a back door would be testing something an application cannot do. `watchNote`
|
||||
// is here because reactivity has no visible surface in this UI yet — not as an escape
|
||||
// hatch, and it takes no identity: switching user means reloading with another `?ng-id=`,
|
||||
// exactly as switching upstream means opening another wallet.
|
||||
(globalThis as { __notebook?: unknown }).__notebook = { watchNote };
|
||||
|
||||
Reference in New Issue
Block a user