Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.enfinitos.com/llms.txt

Use this file to discover all available pages before exploring further.

The hosted sandbox is built in three layers:
packages/sandbox-core/        edge-runtime TypeScript library

apps/web/app/api/sandbox/     Cloudflare Pages edge routes

apps/web/app/sandbox/         React UI + in-browser verifier
Each layer is independently testable, independently substitutable. The library has no environment assumptions; the HTTP API is the only place cookies + storage live; the UI doesn’t trust the API’s “verified” claim — it re-verifies locally.

sandbox-core

The foundational TypeScript library. Edge-runtime-compatible: uses only Web APIs (TextEncoder, btoa/atob, crypto.subtle via @noble/hashes, crypto.randomUUID, crypto.getRandomValues). No node:fs, no node:crypto, no Buffer.
ModuleResponsibility
canonical.tsField-ordered + sort-keys canonical JSON. Byte-exact with platform + auditor SDK.
crypto.tsEd25519 (via @noble/ed25519), SHA-256 (via @noble/hashes), base64url, sandbox keypair derivation.
proofPack.tssignProofRecord, issueProofPack, buildReceiptPayload. Produces envelope.v1 packs.
metering.tsPer-substrate projection rules — DOOH dwell seconds, CTV impressions, etc.
settlement.tsBanker’s-rounded reconciliation across TENANT / VENUE / PLATFORM splits.
tenantState.tsThe full rights bounded context: basis, right (issue/suspend/resume/revoke), offer (propose/accept/reject/counter/withdraw), challenge (open/resolve/withdraw), expiry sweeps, provenance walks.
constraints.tsPre-render gate: messaging opt-out + quiet hours, automotive speed, drone Remote ID + BVLOS waiver, audio attention.
syntheticFactory.tsGenerates plausible delivery events with substrate-realistic dwell.
types.tsAll wire shapes. Mirrors platform shapes exactly.
Conformance is enforced by __tests__/conformance.test.ts — every sandbox-issued pack is fed through @enfinitos/sdk-auditor’s verifyAll. A drift in any encoder, signature, chain, metering, or settlement primitive will fail the suite. CI gates the sandbox release on it.

HTTP API

Each route under apps/web/app/api/sandbox/ is a tiny adapter between the HTTP boundary and the sandbox-core state machines. Common scaffolding lives in _lib/wrapHandler.ts:
  • Parses cookies + HMAC validation
  • Per-IP rate limiting
  • JSON body parsing
  • Persists the mutated tenant state back to the store
  • Wraps errors into the standard envelope
Adding a new state-machine API endpoint is typically 10 lines of glue plus the route file.

Storage

The tenant store is a Map<tenantId, TenantState> keyed under a global Symbol so all routes share one view per Worker isolate. The interface (apps/web/app/sandbox/_lib/store.ts) is intentionally small — get, set, delete — so a future swap to Cloudflare KV / D1 / Durable Objects requires no route-handler changes.

Why module-level memory works for sandbox

Sandbox traffic is single-visitor, short-session, low-stakes. A typical visitor finishes the seven-step flow in 5–20 minutes. Cloudflare Workers keep their isolates warm for tens of minutes under continuous traffic; the eviction case is detectable and recoverable (the API returns 410 TENANT_EVICTED; the UI prompts the user to hit Reset).

Upgrading to persistent storage

When sandbox traffic is high enough that eviction is common, the upgrade is:
  1. Create a Cloudflare KV namespace bound to the Pages project.
  2. Replace memoryStore in _lib/store.ts with a KV-backed implementation matching the same interface.
  3. KV reads are eventually consistent (~60s globally) — sandbox tenants are per-visitor so consistency isn’t a concern.
  4. Set an explicit TTL (24h matches the cookie max-age).
No route handler changes. No type changes. No UI changes.

In-browser verifier

apps/web/app/sandbox/_components/SandboxConsole.tsx runs the seven-step audit roundtrip client-side using sandbox-core primitives:
  1. Envelope version is envelope.v1.
  2. canonicaliseProofPayload re-encodes each record byte-identically.
  3. sha256HexOfString(payloadCanonical) reproduces afterHash.
  4. The hash chain is intact end-to-end.
  5. Every Ed25519 signature verifies against the published key.
  6. Metering records re-project from receipts.
  7. Settlement lines reconcile per-meter to gross.
When all seven pass, the UI shows a green panel and the visual proof-chain SVG colours every node green. A single failure flips the relevant node red and the panel says exactly which invariant broke.

Cross-environment story

A sandbox-issued pack verifies under any auditor pointed at the sandbox key directory. A production-issued pack verifies under any auditor pointed at the production key directory. Cross-pointing fails as UNKNOWN_KEY_ID — there is no environment-conditional code path on the auditor side. The same library handles both. This is the property that makes the sandbox useful for compliance review: anything that verifies under sandbox will verify under production once a real tenant exists.

Trust model summary

QuestionAnswer
Are sandbox signatures real?Yes — Ed25519 over canonical JSON, identical algorithm to production.
Is the sandbox key kept secret?No, deliberately — derived from a published seed string so anyone can re-derive. The keyId is unambiguously labelled as a sandbox key.
Can a sandbox pack impersonate a production pack?No. Sandbox packs carry a sandbox keyId; production auditors don’t know this key. Verification fails as UNKNOWN_KEY_ID.
Can a malicious user forge sandbox packs?Yes — by design. The sandbox is a demonstration environment, not a trust boundary. Forging packs that pass sandbox verification is the same as running the demo.
Where does tenant data live?Module-level Map in the Worker isolate. Per-visitor, ephemeral, no cross-visitor leakage.
Is the cookie tamper-resistant?HMAC-SHA256 over the tenantId with a server secret. Tampering breaks the HMAC.
What about rate limiting?10 req/10s burst + 200 req/hour sustained per IP. Cloudflare’s bind-time rate-limit primitive is the production upgrade path.