docs+refactor(client): fidelity pass — id identity, drop connections, no faux-login, accurate NextGraph framing
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>
This commit is contained in:
+38
-33
@@ -1,25 +1,29 @@
|
||||
/**
|
||||
* Capability emulation — generic, no domain rules. Models NextGraph **ReadCaps**
|
||||
* (and write caps) as faithfully as a data layer can.
|
||||
* Capability emulation — generic, with no domain rules. It models NextGraph
|
||||
* ReadCaps (and write caps) as a data layer can.
|
||||
*
|
||||
* In NextGraph a ReadCap is possession of a *document's* (repo's) read key: the
|
||||
* broker only ever delivers documents the wallet holds a cap for. The access
|
||||
* UNIT is therefore the **document = repo**, identified here by its NURI — the
|
||||
* `@graph` an item lives in — **never the item**. (Verified in nextgraph-rs:
|
||||
* a store is just a container repo; holding a store's cap does NOT grant the
|
||||
* repos it references — each document needs its own cap. So this registry is
|
||||
* purely per-document, with NO store-level inheritance.)
|
||||
* In NextGraph a ReadCap is possession of a document's (repo's) read key: the
|
||||
* broker only delivers documents the wallet holds a cap for. The access unit is
|
||||
* therefore the document = repo, identified here by its NURI — the `@graph` an
|
||||
* item lives in, rather than the item. (A store is just a container repo, and
|
||||
* holding a store's cap does not grant the repos it references — each document
|
||||
* carries its own cap — so this registry is purely per-document, with no
|
||||
* store-level inheritance.)
|
||||
*
|
||||
* At migration this whole layer disappears: the broker/verifier enforces the
|
||||
* real caps and `useShape` already returns only authorized documents.
|
||||
* Sharing here is DIRECTED: a grant issues one grantee the read cap of one
|
||||
* document (`grantRead(doc, granteeId)`). Whether two identities are "connected"
|
||||
* — and therefore whether such a grant should be issued — is an application
|
||||
* concept the consumer owns; this layer only records the resulting per-document
|
||||
* grants. At migration this whole layer disappears: the broker/verifier enforces
|
||||
* the real caps and `useShape` returns only authorized documents.
|
||||
*/
|
||||
|
||||
import type { Nuri, PrincipalId, Scope } from "./types";
|
||||
|
||||
/**
|
||||
* Who holds the read/write cap of each document. The consumer populates it via
|
||||
* cap operations (create-public, grant-to-a-connection…) exactly as it will in
|
||||
* the target; this layer enforces possession generically — it knows no policy.
|
||||
* cap operations (make-public, directed grant…) exactly as it will in the
|
||||
* target; this layer enforces possession generically, with no policy of its own.
|
||||
*/
|
||||
export class CapRegistry {
|
||||
/** doc NURI → principals holding its READ cap. */
|
||||
@@ -29,14 +33,14 @@ export class CapRegistry {
|
||||
/** doc NURIs readable by everyone (public_store repos — no cap needed). */
|
||||
private publicDocs = new Set<Nuri>();
|
||||
/** doc NURI → its declared (scope, owner), as recorded at {@link open}. Lets
|
||||
* a later, connection-aware sharing act (see {@link grantReadToConnections})
|
||||
* re-derive which documents are `protected` and who owns them, without the
|
||||
* consumer re-supplying that per-document — it already declared it at open. */
|
||||
* the consumer re-derive which documents are `protected` and who owns them
|
||||
* (see {@link protectedDocsOf}) so it can issue directed grants, without
|
||||
* re-supplying that per-document — it already declared it at open. */
|
||||
private policy = new Map<Nuri, { scope: Scope; owner: PrincipalId }>();
|
||||
|
||||
/** Grant `principal` the READ cap of document `doc`. */
|
||||
grantRead(doc: Nuri, principal: PrincipalId): void {
|
||||
add(this.readers, doc, principal);
|
||||
/** Grant `grantee` the READ cap of document `doc` — a directed grant. */
|
||||
grantRead(doc: Nuri, grantee: PrincipalId): void {
|
||||
add(this.readers, doc, grantee);
|
||||
}
|
||||
|
||||
/** Grant `principal` the WRITE cap of document `doc`. */
|
||||
@@ -62,23 +66,24 @@ export class CapRegistry {
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend the read caps of every `protected` document so its owner's direct
|
||||
* connections may read it — the sharing act "protected = owner + connections".
|
||||
* `neighborsOf(owner)` yields the principals connected to `owner` (the consumer
|
||||
* supplies its social graph; this layer invents no relationship). Public docs
|
||||
* are already world-readable; private docs are untouched (owner only). Additive
|
||||
* and idempotent: re-running after the connection graph changes only ever adds
|
||||
* read caps for the current connections.
|
||||
* The `protected` documents owned by `owner`, as recorded at {@link open}. The
|
||||
* consumer uses this to issue directed read grants: it decides who may read an
|
||||
* owner's protected documents (its own relationship concept) and calls
|
||||
* {@link grantRead} on each of these documents for each such reader. Public
|
||||
* documents are already world-readable and private documents stay owner-only,
|
||||
* so only the protected ones are surfaced here.
|
||||
*
|
||||
* This is the per-document ReadCap image of a native cap operation: in the
|
||||
* target, sharing a protected repo with a connection issues that connection the
|
||||
* repo's ReadCap. Here it grants the emulated read cap on the same unit.
|
||||
* This mirrors a native cap operation: in the target, sharing a protected repo
|
||||
* with another identity issues that identity the repo's ReadCap. Here the
|
||||
* consumer selects the documents via this accessor and grants the emulated read
|
||||
* cap on the same unit.
|
||||
*/
|
||||
grantReadToConnections(neighborsOf: (owner: PrincipalId) => Iterable<PrincipalId>): void {
|
||||
for (const [doc, { scope, owner }] of this.policy) {
|
||||
if (scope !== "protected") continue;
|
||||
for (const connection of neighborsOf(owner)) this.grantRead(doc, connection);
|
||||
protectedDocsOf(owner: PrincipalId): Nuri[] {
|
||||
const out: Nuri[] = [];
|
||||
for (const [doc, { scope, owner: o }] of this.policy) {
|
||||
if (scope === "protected" && o === owner) out.push(doc);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/** Is `doc` under any READ-cap policy? (Undeclared docs are not enforced.) */
|
||||
|
||||
Reference in New Issue
Block a user