feat!: useShapeQuery prend le Scope du SDK, et un store se nomme par sa reference

This commit is contained in:
Sylvain Duchesne
2026-09-16 16:47:09 +02:00
parent ee9319f89b
commit d0ca5c5d41
31 changed files with 812 additions and 291 deletions
+28 -12
View File
@@ -15,7 +15,11 @@ import {
resetStoreRegistry,
setCurrentUser,
} from "../src/shared-wallet/bootstrap";
import { createEntityDoc as registryCreateEntityDoc, resetRegistryCache } from "../src/shared-wallet/account-registry";
import {
createEntityDoc as registryCreateEntityDoc,
listMyEntityDocs as registryListMyEntityDocs,
resetRegistryCache,
} from "../src/shared-wallet/account-registry";
import { share } from "../src/surface/inbox";
const SHIM = "urn:ng-eventually:shim";
@@ -126,18 +130,30 @@ test("ensureIdentity returns the identity it settled", async () => {
test("a placement call before signing in names the mistake", async () => {
inject();
setCurrentUser(null);
await expect(storeRegistry.createEntityDoc("protected")).rejects.toThrow(/ensureIdentity/i);
await expect(storeRegistry.listMyEntityDocs("protected")).rejects.toThrow(/no identity/i);
await expect(storeRegistry.createEntityDoc()).rejects.toThrow(/ensureIdentity/i);
await expect(storeRegistry.protectedStore()).rejects.toThrow(/no identity/i);
});
test("placement acts as the connected user, with nothing passed", async () => {
inject();
setCurrentUser("alice");
const doc = await storeRegistry.createEntityDoc("protected");
expect(await storeRegistry.listMyEntityDocs("protected")).toContain(doc);
const doc = await storeRegistry.createEntityDoc(await storeRegistry.protectedStore());
expect(await registryListMyEntityDocs("alice", "protected")).toContain(doc);
setCurrentUser("bob");
expect(await storeRegistry.listMyEntityDocs("protected")).not.toContain(doc);
expect(await registryListMyEntityDocs("bob", "protected")).not.toContain(doc);
});
// A store reference that is not one of the connected identity's three is a caller error,
// and silence here would be the worst answer available: the document would be created,
// successfully, somewhere its author did not ask for — and only a later listing that comes
// back short would say so.
test("createEntityDoc refuses a store that is not one of this identity's", async () => {
inject();
setCurrentUser("alice");
const hers = await storeRegistry.protectedStore();
setCurrentUser("bob");
await expect(storeRegistry.createEntityDoc(hers)).rejects.toThrow(/not one of this identity/i);
});
// ── sharing names someone who exists ───────────────────────────────────────
@@ -145,7 +161,7 @@ test("placement acts as the connected user, with nothing passed", async () => {
test("share refuses a recipient nobody has signed in as, instead of creating them", async () => {
inject();
setCurrentUser("alice");
const doc = await storeRegistry.createEntityDoc("protected");
const doc = await storeRegistry.createEntityDoc(await storeRegistry.protectedStore());
// "bpb" is a typo for "bob". It used to mint that name's three stores and an inbox,
// and the cap landed where nobody will ever look — with no error at all.
await expect(share(doc, "bpb")).rejects.toThrow(/no such recipient/i);
@@ -157,7 +173,7 @@ test("share refuses a recipient nobody has signed in as, instead of creating the
test("a failed lookup surfaces as a failure, not as 'no such recipient'", async () => {
const { quads } = inject();
setCurrentUser("alice");
const doc = await storeRegistry.createEntityDoc("protected");
const doc = await storeRegistry.createEntityDoc(await storeRegistry.protectedStore());
setCurrentUser("bob");
await registryCreateEntityDoc("bob", "private"); // bob genuinely exists
setCurrentUser("alice");
@@ -178,7 +194,7 @@ test("a failed lookup surfaces as a failure, not as 'no such recipient'", async
test("createEntityDoc reports a half-written document instead of returning its reference", async () => {
inject(/shim:contains/); // the LISTING write fails
setCurrentUser("alice");
await expect(storeRegistry.createEntityDoc("protected")).rejects.toThrow(/not listed in its store/i);
await expect(storeRegistry.createEntityDoc(await storeRegistry.protectedStore())).rejects.toThrow(/not listed in its store/i);
});
// Both writes are attempted before the failure is raised — the cap must land even when
@@ -187,14 +203,14 @@ test("createEntityDoc reports a half-written document instead of returning its r
test("a failed listing does not cost the document its key", async () => {
const { quads } = inject(/shim:contains/);
setCurrentUser("alice");
await storeRegistry.createEntityDoc("protected").catch(() => {});
await storeRegistry.createEntityDoc(await storeRegistry.protectedStore()).catch(() => {});
expect(quads.some((q) => q.p === `${SHIM}:readCap`)).toBe(true);
});
test("a failed key write is reported too, and names that half", async () => {
inject(/shim:readCap/);
setCurrentUser("alice");
await expect(storeRegistry.createEntityDoc("protected")).rejects.toThrow(/key is not recorded/i);
await expect(storeRegistry.createEntityDoc(await storeRegistry.protectedStore())).rejects.toThrow(/key is not recorded/i);
});
// The third write a PUBLIC creation makes, and the one that was still silent: exposing the
@@ -206,6 +222,6 @@ test("a failed key write is reported too, and names that half", async () => {
test("a public document whose cap could not be exposed is reported, not returned", async () => {
inject(/shim:exposedReadCap/);
setCurrentUser("alice");
await expect(storeRegistry.createEntityDoc("public")).rejects.toThrow(/broker refused/i);
await expect(storeRegistry.createEntityDoc(await storeRegistry.publicStore())).rejects.toThrow(/broker refused/i);
});