63ecfeeff8
Align the polyfill's surface and docs with the verified NextGraph reality and
remove application-level concepts:
- Identity is an ID, not a username: AccountRecord.id, shim predicate shim:id,
normalizeId; accounts core becomes IdentityStore (set/clear/get) — the faux
login/logout framing is gone (identity is set at wallet-import time).
- Relationship/connection is an application concept, not a platform primitive
(NextGraph has no bilateral-connection primitive: grantee is unpersisted
scaffolding, cap-send is unimplemented). Remove connections.ts; caps exposes
only a directed grantRead(doc, granteeId) + a read-only protectedDocsOf(owner).
Delete the now-dead isolation.ts social-visibility axis.
- Inbox docs: NextGraph has no separate curator — the recipient's own verifier
unseals and applies each queued sealed message inline (process_inbox);
inbox_post_link is a proposed/future API. Stop attributing the emulated
curator to the platform.
- Read isolation reframed around the outcome: no cap -> empty union read;
targeted read of an unheld repo -> RepoNotFound; cap introspection
(canRead/governsRead) is emulation-only with no NextGraph API behind it.
- read-model.md corrected: the listing path is per-doc ANCHORED default-graph
queries, never the anchorless GRAPH ?g union (that is O(wallet)); the probe
section no longer claims the opposite.
- README recap table restructured (target | current NextGraph status | current
emulation); INDEX_ACCOUNT documented as reservedAccount("index") in the
sentinel namespace; de-domained generic-layer comments; softened tone.
Consumer application (Festipod) rewired separately to own the relationship
concept and feed the lib an id. Lib gates: bun test 83 pass / 0 fail, tsc clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
76 lines
2.4 KiB
TypeScript
76 lines
2.4 KiB
TypeScript
import { test, expect } from "bun:test";
|
|
import {
|
|
IdentityStore,
|
|
browserIdentityStore,
|
|
ACCOUNT_STORAGE_KEY,
|
|
type AccountStorage,
|
|
} from "../src/accounts";
|
|
|
|
// In-memory fake of the Storage subset — keeps this framework/DOM-agnostic.
|
|
function fakeStorage(): AccountStorage & { map: Map<string, string> } {
|
|
const map = new Map<string, string>();
|
|
return {
|
|
map,
|
|
getItem: (k) => (map.has(k) ? (map.get(k) as string) : null),
|
|
setItem: (k, v) => void map.set(k, v),
|
|
removeItem: (k) => void map.delete(k),
|
|
};
|
|
}
|
|
|
|
test("IdentityStore: set persists a trimmed id, get reads it back", () => {
|
|
const s = fakeStorage();
|
|
const store = new IdentityStore(s);
|
|
expect(store.get()).toBeNull();
|
|
|
|
expect(store.set(" marie ")).toBe("marie"); // trimmed
|
|
expect(store.get()).toBe("marie");
|
|
expect(s.map.get(ACCOUNT_STORAGE_KEY)).toBe("marie");
|
|
});
|
|
|
|
test("IdentityStore: a blank id is ignored, keeps the previous value", () => {
|
|
const store = new IdentityStore(fakeStorage());
|
|
store.set("bob");
|
|
expect(store.set(" ")).toBe("bob");
|
|
expect(store.get()).toBe("bob");
|
|
});
|
|
|
|
test("IdentityStore: clear removes the id (no throw)", () => {
|
|
const store = new IdentityStore(fakeStorage());
|
|
store.set("bob");
|
|
store.clear();
|
|
expect(store.get()).toBeNull();
|
|
});
|
|
|
|
test("IdentityStore: null storage degrades to non-persisting (SSR-safe)", () => {
|
|
const store = new IdentityStore(null);
|
|
expect(store.get()).toBeNull();
|
|
expect(store.set("bob")).toBe("bob"); // returns the value, just doesn't persist
|
|
expect(store.get()).toBeNull();
|
|
store.clear(); // no throw
|
|
});
|
|
|
|
test("IdentityStore: swallows storage errors on read and write", () => {
|
|
const throwing: AccountStorage = {
|
|
getItem: () => {
|
|
throw new Error("boom");
|
|
},
|
|
setItem: () => {
|
|
throw new Error("boom");
|
|
},
|
|
removeItem: () => {
|
|
throw new Error("boom");
|
|
},
|
|
};
|
|
const store = new IdentityStore(throwing);
|
|
expect(store.get()).toBeNull(); // read error swallowed → null
|
|
expect(() => store.set("bob")).not.toThrow();
|
|
expect(() => store.clear()).not.toThrow();
|
|
});
|
|
|
|
test("browserIdentityStore returns a working store (uses global localStorage if present)", () => {
|
|
const store = browserIdentityStore("ng-eventually.test.account");
|
|
expect(store).toBeInstanceOf(IdentityStore);
|
|
// Behaves regardless of environment: set returns the value.
|
|
expect(store.set("zoe")).toBe("zoe");
|
|
});
|