feat(client): SDK-shaped scope resolvers (resolveScopeGraph/resolveInboxAnchor)

Expose a clean scope-based surface so consumers work by scope (public/protected/
private) and never see a physical store id — the library resolves placement and
performs the shared-wallet simulation internally. RegistrySession gains optional
protected/public store ids, supplied at the single injection point
(configureStoreRegistry). Zero domain knowledge. docs/simulation.md updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sylvain Duchesne
2026-07-03 23:41:34 +02:00
parent bea9f51d91
commit e0d88b5076
3 changed files with 110 additions and 0 deletions
@@ -5,6 +5,8 @@ import {
loadShim,
resolveWriteGraph,
resolveReadGraphs,
resolveScopeGraph,
resolveInboxAnchor,
createEntityDoc,
listEntityDocs,
resetRegistryCache,
@@ -177,6 +179,33 @@ test("resolveWriteGraph returns the per-scope index doc; resolveReadGraphs fans
expect(await resolveReadGraphs("public")).toEqual([rec.docPublic]);
});
test("resolveScopeGraph maps scopes to native store NURIs (no store-id leaks to the caller)", async () => {
// Session with all three store ids: private → private store; public+protected
// co-locate on the protected native store (the polyfill's Axis-A placement).
const ng = makeFakeNg();
configure({ ng: ng as any, useShape: (() => {}) as any });
configureStoreRegistry({
getSession: async () => ({
sessionId: "sid-2",
privateStoreId: "PRIV",
protectedStoreId: "PROT",
publicStoreId: "PUB",
}),
});
resetRegistryCache();
expect(await resolveScopeGraph("private")).toBe("did:ng:PRIV");
expect(await resolveScopeGraph("protected")).toBe("did:ng:PROT");
expect(await resolveScopeGraph("public")).toBe("did:ng:PROT"); // co-located
expect(await resolveInboxAnchor()).toBe("did:ng:PRIV");
});
test("resolveScopeGraph falls back to the private store when no protected id is injected", async () => {
// The default SESSION carries only privateStoreId — non-private scopes fall
// back to the private store rather than emitting a broken NURI.
expect(await resolveScopeGraph("protected")).toBe("did:ng:PRIV");
expect(await resolveScopeGraph("public")).toBe("did:ng:PRIV");
});
test("createEntityDoc + listEntityDocs round-trip via the per-scope index", async () => {
const rec = await ensureAccount("Dave");
const e1 = await createEntityDoc("dave", "public");