Polyfill capabilities landed for Festipod's T02 features (all generic,
zero-domain — the consumer injects the domain).
- inbox: implement the previously-stubbed namespace. post(target,{from?,
payload,ts?}) deposits {from,payload,ts} as RDF via docs.sparqlUpdate (the
real injected ng, never makeNg); read/materialize + watch emulate the curator
in-lib (deposits read via docs.sparqlQuery). `from` optional = anonymity.
- write-guard: caps.hasWritePolicy() + ng-proxy.sparql_update rejects when the
target doc is under a write policy and the current user lacks its write cap;
passthrough otherwise (no regression). Read-cap registry unchanged.
- sparql.ts (new): escapeLiteral / escapeIri / assertNuri, exported from index.
store-registry now escapes every literal and validates/encodes every IRI-
position value — closes a SPARQL-injection hole where an untrusted username
could inject triples into the shim (the account→doc-NURI trust root).
Tests: inbox, sparql (incl. injection), ng-proxy write-guard, isolation-active.
68 tests pass; tsc --noEmit rc=0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Model the read filter on NextGraph's real ReadCap mechanism instead of an
invented per-item grant. Verified in nextgraph-rs: there is no Document type
(document = repo); a store is a container repo referencing other repos by RDF
overlay; holding a store's cap does NOT grant the repos it contains (each repo
needs its own cap; no read-cap inheritance). So the access unit is the
DOCUMENT = an item's `@graph`, never the item.
- caps.ts: CapRegistry (read/write caps per document NURI + public docs;
open/grantRead/grantWrite/makePublic/canRead/canWrite/governsRead/
hasReadPolicy). Replaces access.ts (Grant).
- read-filter.ts: filter keeps an item iff its `@graph` document is readable
(held cap or public); items with no `@graph` or in an ungoverned document are
kept. No injected grantOf — the filter reads `@graph` and consults the
registry (automatic, domain-agnostic).
- polyfill.ts: getCaps()/resetCaps() replace setGrantOf/getGrantOf; useShape
filters only when caps.hasReadPolicy() (else passthrough, no regression).
- tests: caps.test.ts (6) + read-filter.test.ts (4), incl. no-inheritance
between documents. 10 pass; tsc rc=0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>