Initial scaffold: @ng-eventually/client — SDK-shaped polyfill over NextGraph

Generic polyfill layer that makes a single NextGraph broker behave like the
not-yet-shipped multi-user NextGraph (emulated capabilities + inbox). Zero app domain.

@ng-eventually/client exposes an SDK-identical surface (ng, useShape, inbox); the
polyfill bootstrap (configure + capability helpers) is isolated under /polyfill, so
the main entry stays a drop-in for @ng-org/web|orm. The real SDK is injected at
configure() (no hard import → build-alias safe + testable).

Scaffold: NextGraph wiring stubbed with TODO; capability helpers implemented and
unit-tested (4 tests, typecheck clean). The global-index curator is deferred — in
NextGraph apps/services are mono-user with no global data.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sylvain Duchesne
2026-06-22 16:35:40 +02:00
commit bb2d9c3e59
16 changed files with 448 additions and 0 deletions
+30
View File
@@ -0,0 +1,30 @@
import { test, expect } from "bun:test";
import { canRead, canWrite, defaultGrant, grantRead } from "../src/access";
test("public docs are readable by anyone, even anonymous", () => {
const g = defaultGrant("public", "alice");
expect(canRead(g, null)).toBe(true);
expect(canRead(g, "bob")).toBe(true);
});
test("protected docs: owner + explicitly granted principals only", () => {
let g = defaultGrant("protected", "alice");
expect(canRead(g, "alice")).toBe(true);
expect(canRead(g, "bob")).toBe(false);
g = grantRead(g, "bob"); // e.g. bob becomes a connection of alice
expect(canRead(g, "bob")).toBe(true);
});
test("private docs: owner only", () => {
const g = defaultGrant("private", "alice");
expect(canRead(g, "alice")).toBe(true);
expect(canRead(g, "bob")).toBe(false);
expect(canRead(g, null)).toBe(false);
});
test("write is restricted to the write grant", () => {
const g = defaultGrant("public", "alice");
expect(canWrite(g, "alice")).toBe(true);
expect(canWrite(g, "bob")).toBe(false);
expect(canWrite(g, null)).toBe(false);
});