feat(auth)+refactor(app): identifier at the access barrier; adopt the lib fidelity refactor
Consumer-side of the @ng-eventually/client fidelity pass, plus the identifier UX: - Identity: the user types an IDENTIFIER at the access barrier (AccessGateScreen), in the same act that opens the shared wallet — the separate 'pick a username' screen (ConnexionScreen) is removed. The identifier is a technical id (a pseudo in practice, not a Festipod username), normalized (trim, @-stripped, lowercased) and persisted before the broker redirect, then handed to the SDK as the identity. AccountContext keeps its API but its stored value is now this normalized id. - Relationship/connections are app-owned: new src/shared/utils/connections.ts holds the bilateral registry and maps each link to the SDK's directed grantRead(doc, grantee); the lib no longer carries a connection concept. Rewired FestipodData and the @data harness to it. - Login removed: accounts use the SDK's IdentityStore (set/clear/get); no faux login/logout framing in the SDK boundary. Doctrine reconciled: app-security (knowledge_authentication flow, knowledge_trust-model directed grants, decision_2026-07-06_identifier-at-access-barrier), data-layer (knowledge_context-internals: stable id principal + single-seed), app-architecture (knowledge_screens auth inventory), bdd-testing (caveat_wallet-bloat-hang). App gates: tsc no new errors, build OK. @data path unaffected (harness bypasses the gate and sets identity directly; login() is not on that path). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -14,7 +14,9 @@ import { AccountProvider, useAccount } from '../context/AccountContext';
|
||||
import { FestipodDataProvider, useFestipodData } from '../context/FestipodDataContext';
|
||||
// useShape routed through the lib (SDK-identical surface); caps from /polyfill.
|
||||
import { useShape, docs, inbox as docsInbox } from '@ng-eventually/client';
|
||||
import { getCaps, getCurrentUser, setCurrentUser, resetCaps, declareConnections } from '@ng-eventually/client/polyfill';
|
||||
import { getCaps, getCurrentUser, setCurrentUser, resetCaps } from '@ng-eventually/client/polyfill';
|
||||
// Relationship is an app concept: directed grants come from the app's own module.
|
||||
import { declareConnections, resetConnections } from '../utils/connections';
|
||||
import { hostInboxNuri as regInboxNuri } from '../data/registration';
|
||||
import type { DeepSignalSet } from '@ng-eventually/client';
|
||||
// doc_create goes through the lib's `docs` primitive (T01.a): it calls the REAL
|
||||
@@ -476,10 +478,11 @@ function ConnectedHarness() {
|
||||
// (storeRegistry.createEntityDoc) does; the protected participations
|
||||
// document is governed, and a separate makePublic'd doc models a public
|
||||
// entity. <FilterProbe> exposes the read-filtered VIEW over the protected
|
||||
// participations doc. `connect` calls the SDK's declareConnections — the
|
||||
// app's domain sharing act — never touches a doc NURI or the registry.
|
||||
// participations doc. `connect` calls the app's declareConnections — the
|
||||
// domain sharing act — which issues the SDK's directed read grants.
|
||||
governProtected(owner: string, reader: string) {
|
||||
resetCaps();
|
||||
resetConnections(); // clear the app's relationship registry too
|
||||
// The protected participations document (owner-only read at first).
|
||||
getCaps().open(protectedNuri!, 'protected', owner);
|
||||
// A public entity document — readable by anyone regardless of caps.
|
||||
@@ -487,9 +490,9 @@ function ConnectedHarness() {
|
||||
setCurrentUser(reader);
|
||||
setFilterActive(true);
|
||||
},
|
||||
/** Declare a BILATERAL owner↔reader connection to the SDK (domain sharing
|
||||
* act). Each side asserts the other (bound to that identity); only then
|
||||
* does the SDK issue the protected doc's read cap to the connection. */
|
||||
/** Declare a bilateral owner↔reader connection (domain sharing act). Each
|
||||
* side asserts the other; only a two-sided link makes the app issue the
|
||||
* protected doc's directed read grant to the reader. */
|
||||
connect(a: string, b: string) {
|
||||
declareConnections([b], a); // a asserts b
|
||||
declareConnections([a], b); // b asserts a → bilateral link materializes
|
||||
@@ -524,7 +527,7 @@ function ConnectedHarness() {
|
||||
const created = await reg.ensureAccount(username);
|
||||
reg.resetRegistryCache();
|
||||
const reloaded = (await reg.allAccounts()).find(
|
||||
a => a.username === username,
|
||||
a => a.id === username,
|
||||
) ?? null;
|
||||
return { created, reloaded };
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user