fix: trois coûts qui revenaient à l'appelant reviennent au paquet
Le contrat faisait porter à l'application trois choses qui sont des artefacts de notre implémentation, pas de la cible. Le rechargement de page. Au retour depuis le cache du navigateur, la barrière se rechargeait pour rejouer init() — et détruisait au passage l'état de l'application, qui ne pouvait ni s'y opposer ni nettoyer avant. Le paquet détenait pourtant ce qu'il fallait : la fonction init injectée et le callback de l'appelant. Il enregistre désormais sa délégation, ranime sa barrière au retour — champ conservé, bouton réactivé — et redélègue à la confirmation. Rien hors de la barrière n'est touché. Vérifié dans le bundle amont : en page de tête, init navigue à chaque appel, sa garde « une seule fois » ne portant que sur la branche iframe. L'ordre d'appel silencieux. ensureIdentity() attendu avant init() ne se résolvait jamais, sans erreur. Le paquet possédant la session, il distingue maintenant les deux cas sans délai ni heuristique : session pas encore arrivée → il attend ; init jamais appelé → elle n'arrivera pas, il lève en nommant l'appel à faire d'abord. Et la clause qui annonçait la barrière était rangée dans les exigences de déploiement, alors qu'une application n'y peut rien. Elle passe dans les garanties, avec ce qui la remplace : la page n'est jamais rechargée. Il reste deux lignes d'exigences : servir le fichier de portefeuille, et appeler init avant d'attendre l'identité — ce qui échoue désormais bruyamment.
This commit is contained in:
@@ -135,12 +135,33 @@ export interface EventuallyConfig {
|
||||
|
||||
let cfg: EventuallyConfig | null = null;
|
||||
let currentUser: PrincipalId | null = null;
|
||||
/**
|
||||
* What hands the page to the broker — the polyfill's `init()` reduced to a thunk, kept so a
|
||||
* page that comes BACK from the hand-over can run it AGAIN ({@link ./access-gate}).
|
||||
*
|
||||
* It lives here rather than in either module that uses it because it is made of the injected
|
||||
* `init` and the caller's arguments, and this is where the injection is: `init()` registers
|
||||
* it (`../surface/lifecycle.ts`), the barrier runs it when someone confirms a second time.
|
||||
* Kept for the life of the page — the return it exists for happens long after the call.
|
||||
*/
|
||||
let handOver: (() => void) | null = null;
|
||||
/** Required fields of StoreRegistryDeps after defaults are applied. `pointerGuard`
|
||||
* defaults to `{ attempts: 1 }` (single read) when the consumer leaves it unset. */
|
||||
type ResolvedRegistryDeps = Required<
|
||||
Pick<StoreRegistryDeps, "getSession" | "normalizeId" | "pointerGuard">
|
||||
>;
|
||||
let registryDeps: ResolvedRegistryDeps | null = null;
|
||||
/**
|
||||
* Does the registry reach the session through the package's OWN holder?
|
||||
*
|
||||
* {@link configure} points it there, and that is what every application gets. The library's
|
||||
* suites and the e2e harness substitute a route of their own
|
||||
* ({@link configureStoreRegistry}) and hold a session no `init()` of this package opened —
|
||||
* so "`init()` was never called, therefore no session can ever arrive" is a true statement
|
||||
* about the package's holder and about nothing else. Recorded at the wiring rather than
|
||||
* asked afterwards: the wiring WRAPS the injected thunk, so it can no longer be recognised.
|
||||
*/
|
||||
let ownSessionRoute = false;
|
||||
/**
|
||||
* The map key of the current identity — deliberately NOT the raw id.
|
||||
*
|
||||
@@ -196,9 +217,33 @@ export function getConfig(): EventuallyConfig {
|
||||
export function resetConfig(): void {
|
||||
cfg = null;
|
||||
currentUser = null;
|
||||
// The hand-over goes with it, for the same reason: it is made of the config's injected
|
||||
// `init`, so leaving it behind would let a revived barrier delegate to the PREVIOUS
|
||||
// application's SDK.
|
||||
handOver = null;
|
||||
resetSharedWalletSession();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remember how this page is handed to the broker. Called by the polyfill's `init()` on its
|
||||
* way through, before it delegates.
|
||||
*
|
||||
* @internal Never published: an application does not perform the hand-over, it calls `init`.
|
||||
*/
|
||||
export function rememberHandOver(delegate: () => void): void {
|
||||
handOver = delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* The registered hand-over, or `null` when `init()` has never been called — in which case
|
||||
* nothing ever navigated, so there is no return from a hand-over to serve.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export function getHandOver(): (() => void) | null {
|
||||
return handOver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wire the storeRegistry's dependencies. INTERNAL since 2026-08-07: an application
|
||||
* passes these to {@link configure}, which calls this. Still exported for the library's
|
||||
@@ -223,6 +268,7 @@ export function configureStoreRegistry(deps: StoreRegistryDeps): void {
|
||||
}
|
||||
return session;
|
||||
};
|
||||
ownSessionRoute = deps.getSession === sharedWalletSession;
|
||||
registryDeps = {
|
||||
getSession,
|
||||
normalizeId: deps.normalizeId ?? normalizeIdentityId,
|
||||
@@ -240,9 +286,15 @@ export function getStoreRegistryDeps(): ResolvedRegistryDeps {
|
||||
return registryDeps;
|
||||
}
|
||||
|
||||
/** @internal — see {@link ownSessionRoute}. */
|
||||
export function sessionRouteIsThePackages(): boolean {
|
||||
return ownSessionRoute;
|
||||
}
|
||||
|
||||
/** Reset storeRegistry deps (mainly for tests). */
|
||||
export function resetStoreRegistry(): void {
|
||||
registryDeps = null;
|
||||
ownSessionRoute = false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user