fix: régler l'identité ne demande pas de session, se connecter oui

init() de @ng-org/web redirige vers le broker en première instruction, dès qu'on
est en tête. L'application appelait donc init() au chargement du module, la page
partait, et ensureIdentity() ne s'exécutait jamais : la barrière n'apparaissait
pas, ?ng-id= restait absent de l'URL remise au broker, et un primo-arrivant se
retrouvait devant la page de connexion sans portefeuille et sans moyen d'en
obtenir un — sans la moindre erreur.

Appeler ensureIdentity() avant init() ne marchait pas non plus : il attend la
session, que seul le callback d'init() résout. Cycle vérifié empiriquement.

La cause n'était ni l'ordre ni la redirection, mais une confusion dans
ensureIdentity() entre deux actes de nature différente — régler qui est
l'utilisateur (barrière, URL, stockage : aucune session) et se connecter
(session requise). settleIdentity() porte le premier ; le wrapper init() du
polyfill l'attend avant de déléguer. L'invariant d'ordre est ainsi porté par la
composition, pas par une consigne d'ordre d'appel que personne ne lit.

Piège trouvé et épinglé en écrivant les tests : init() et ensureIdentity() dans
le même tick montaient deux barrières, l'utilisateur répondait à l'une et
l'autre ne se résolvait jamais. Le règlement en vol est désormais partagé.
This commit is contained in:
Sylvain Duchesne
2026-08-11 12:52:49 +02:00
parent fc3c129bd3
commit 3547de202c
5 changed files with 392 additions and 39 deletions
+15 -10
View File
@@ -33,6 +33,7 @@ import {
docs,
ensureIdentity,
inbox,
init,
readUnion,
storeRegistry,
subscribeDoc,
@@ -60,16 +61,6 @@ interface Note {
// 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) => {
realInit((event: { status: string; session?: { session_id: string } }) => {
if (event.status === "loggedin" && event.session) {
session = event.session;
resolve(event.session);
}
}, true, []);
});
configure({
ng: realNg,
useShape: (() => {}) as never, // this example reads through `readUnion`, not the ORM
@@ -90,6 +81,20 @@ configure({
normalizeId: (id) => id.trim().replace(/^@/, "").toLowerCase(),
});
// The library's `init`, not the injected one — and this line is SDK-shaped, kept at
// migration. It settles the identity before handing the page to the broker, so the
// round-trip leaves with the identifier in the URL it carries. `realInit` called here
// would navigate away first, and the barrier would never show.
let session: { session_id: string } | null = null;
const sessionReady = new Promise<{ session_id: string }>((resolve) => {
init((event: { status: string; session?: { session_id: string } }) => {
if (event.status === "loggedin" && event.session) {
session = event.session;
resolve(event.session);
}
}, true, []);
});
// --- the acts ---------------------------------------------------------------
/** Write a new note in `scope`. The document is created, then filled. */