Sylvain Duchesne 7db5eef33f feat(client): activate ReadCap isolation via current identity + connections
Isolation was dormant (no current identity ever set). Now: setCurrentUser
records who is reading; declareConnections(neighborsOf) grants each protected
document's read cap to owner + connections. Reads discriminate through the
ReadCap filter: private→owner, protected→owner+connections, public→all. Generic
(the consumer injects identity + connections). Write-guard coverage limits
documented honestly in docs/simulation.md (real write paths bypass the JS proxy;
full enforcement awaits native caps). isolation-active.test.ts proves the
protected+connections path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-03 23:59:27 +02:00

ng-eventually

A generic polyfill layer over the NextGraph JS SDK.

NextGraph's JS SDK does not yet expose cross-wallet reads, capabilities, inboxes or group stores. ng-eventually lets an app behave as if those existed today, by emulating them on top of a single shared wallet / broker. It is generic: it contains no application domain — the consumer injects its shapes and the acts of granting access.

The name: eventually NextGraph will ship these features; until then this layer fills the gap (and nods at eventual consistency / events).

The boundary — mature face out, compensation in

The asymmetry is the whole point. Consumers write SDK-shaped code as if NextGraph were finished: per-entity documents in public/protected/private stores, capabilities, inboxes. This library owns all the current-state NextGraph knowledge and the simulation that fabricates that mature face — a shared-wallet emulation — so the application never sees it. When NextGraph matures, only this library changes; the consumer's code does not.

Docs (this library's own engineering doctrine, under docs/):

  • docs/nextgraph-current-state.md — the authoritative reference on what the CURRENT SDK/broker do and do NOT expose (the ground truth every polyfill compensates for).
  • docs/simulation.md — how this lib emulates the mature behaviour on ONE shared wallet (shim, per-document ReadCaps, emulated inbox+curator, write guard, faux login, the two axes, the double-proxy constraint).
  • docs/decisions/ — historical current-SDK ADRs (private-store scope, SPARQL delete, shared-wallet login, discovery mechanism).
  • docs/fork-inbox-fallback.md — the Rust-patch / self-host inbox path NOT taken (kept as fallback).
  • docs/migration-guide.md — the checklist for when real NextGraph matures.

Packages

Package Role At migration
@ng-eventually/client SDK-identical wrapper the app imports instead of @ng-org/web / @ng-org/orm. Adds the polyfills the broker/verifier will do natively (shared-wallet login, capability enforcement, anticipated cap/inbox methods). Disappears: the app points back at the real SDK (build alias removed).

A global-index curator package is deferred. NextGraph is mono-user with no global data (apps/services see only what the user shares; there is no multi-user backend). A global index would come from a singleton app (a global document administered by the developer) — not implemented and uncertain, and simpler paths may exist. So no second package for now; it will be (re)introduced once the global-index mechanism is decided. The curator must never be bundled in the client → it will be a separate package when it lands.

Design principle

The application code is written as if the target NextGraph existed. All compensation lives here, beside the app. Migration = remove this layer; the app code (SDK-shaped) is unchanged.

  • SDK-identical surface: the client wraps the real ng (a Proxy that forwards everything and overrides only what must be emulated) and useShape. The real SDK is injected via configure() (no hard import → build-alias safe + testable).
  • Authorization = emulated capabilities: documents carry grants; the client enforces them generically (read filter + write guard). The app attaches grants via cap operations — same as it will in the target. No policy is injected.
  • Inbox: the client inbox namespace deposits (post) and, in the shared-wallet emulation, also plays the curator inline (read / materialize / watch). At migration the read side moves to a separate curator package, deferred with the global-index mechanism — see the note above.
  • Tests of the polyfill (against a real broker) live in this repo, so the consuming app can test its features against a mocked, clean API.

Status

Implemented. The polyfill mechanisms are wired against a real broker, not stubbed:

  • Shared-wallet shimstore-registry.ts ((account, scope) → document NURI, createEntityDoc / listEntityDocs + per-scope index, cross-device via the RDF shim anchored in the private store).
  • Document / SPARQL primitivedocs.ts, calling the real injected ng directly (avoids the @ng-org double-proxy DataCloneError).
  • Emulated ReadCapscaps.ts (CapRegistry, per-document) + read filter read-filter.ts (reactive-set Proxy view), applied by use-shape.ts only when a policy is declared.
  • Write guardng-proxy.ts (sparql_update override, emulated write cap).
  • Inboxinbox.ts (post / read / materialize / watch, emulated curator inline).
  • Isolationisolation.ts (pure social-visibility matrix, distinct axis from ReadCaps).
  • Accountsaccounts.ts (faux username login, injected storage).
  • SPARQL hardeningsparql.ts (escapeLiteral / escapeIri / assertNuri).

Remaining TODO markers are narrow: the shared-wallet credential passthrough in the login/session_start proxy branch, and the anticipated cap/inbox SDK signatures to reconcile if the official API differs. See docs/simulation.md for what each piece does and docs/migration-guide.md for what is removed at migration.

S
Description
No description provided
Readme 375 KiB
Languages
TypeScript 100%