Files
ng-eventually/packages/client/src/index.ts
T
Sylvain Duchesne d804a436d7 feat(client): inbox mechanism, write-guard, SPARQL injection hardening
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>
2026-07-03 15:51:00 +02:00

43 lines
2.0 KiB
TypeScript

/**
* @ng-eventually/client — **SDK-identical** surface.
*
* This entry exposes ONLY what `@ng-org/web` / `@ng-org/orm` expose (current +
* anticipated: `inbox`). Import `ng` / `useShape` from here instead of the SDK
* during the polyfill period; at migration the build alias is removed and these
* resolve to the real SDK with **no code change**.
*
* The one non-SDK piece — the polyfill bootstrap (`configure`, capability
* helpers, current user) — lives at `@ng-eventually/client/polyfill`, and is the
* only thing removed at migration.
*/
export * from "./types";
export { useShape } from "./use-shape";
export { init, initNg } from "./lifecycle";
export * as inbox from "./inbox";
export * as docs from "./docs";
export * as storeRegistry from "./store-registry";
export type { AccountRecord, RegistrySession } from "./store-registry";
export * as isolation from "./isolation";
export type { Connections, IsolationAccessors } from "./isolation";
export * as accounts from "./accounts";
export type { AccountStorage } from "./accounts";
// SPARQL injection-safety helpers — so the app can reuse the same escaping /
// validation when it builds SPARQL by interpolation. `escapeLiteral` for string
// literals, `escapeIri` to embed untrusted values in an IRI, `assertNuri` to
// validate trusted-shaped NURIs before embedding them in an IRI.
export { escapeLiteral, escapeIri, assertNuri } from "./sparql";
// SDK type re-exports — so the app imports these from @ng-eventually/client too,
// not from @ng-org. `export type` is ERASED at build, so this adds NO runtime
// @ng-org import to the lib (no risk of a duplicate SDK copy in the bundle).
export type { ShapeType, BaseType, Schema } from "@ng-org/shex-orm";
export type { DeepSignalSet } from "@ng-org/alien-deepsignals";
export type { NG } from "@ng-org/web";
import { makeNg } from "./ng-proxy";
/** SDK-identical `ng` (wrapped). Drop-in replacement for `@ng-org/web`'s `ng`. */
export const ng: Record<string, any> = makeNg();