Skip to main content

State-channel HTML hosting

You spin up a state machine and you can host a webapp on it. The pitch is spin-up-as-webapp — no separate Vercel, no separate Netlify, no separate CDN. Your zsm_ key already authorizes uploads; the machine is already on the entangled state; the bytes you upload are hash-committed to your audit log on every change.

The framework runs the server. The framework enforces a strict CSP at serve time. The framework forces MIME from extension. The framework path-normalizes against your machine root. The framework writes an entangled state row on every serve. You get a fully-audited, sandboxed mini-webapp, billed against your tally.


What it is

  • A per-slug HTML hosting tier served at https://zeqsdk.com/s/:slug/*.
  • Bytes uploaded via authenticated POST to /api/chain/:slug/site/upload.
  • Bytes served under a sandbox CSP with isolated cookies — no zeq.dev credentials in scope.
  • Strict CSP with isolated cookies.
  • Hash commitment on the entangled state on every byte stream served.
  • Free tier: hash-only — the chain commits the hash of each upload and the serve path 302s to an external_url (no bytes stored). Paid tier: the bytes themselves are stored in a machine-isolated bucket and served directly. Throughput is rate-limited per slug.

What it is not

  • Not a CDN. Throughput is rate-limited. For high-volume static, use a CDN and beacon to your machine from the CDN edge.
  • Not a runtime. There's no server-side execution; this is static hosting + framework-controlled response headers.
  • Not a database. State should live in your audit entangled state, your contracts, your tally — not in the static bytes.

Routes

MethodPathAuthNotes
POST/api/chain/:slug/site/uploadBearer (operator+)Upload a byte stream (multipart or base64). Hash committed on the entangled state.
GET/api/chain/:slug/site/listBearer (viewer+)List the pages for the slug with their hashes.
GET/api/chain/:slug/site/file/:shaBearer (viewer+)Single-file metadata by content hash.
DELETE/api/chain/:slug/site/*Bearer (admin+)Soft-delete (archive). Records the change on the entangled state.
GET/s/:slug/*nonePublic serve. Sandbox CSP. MIME-forced.

Each upload writes:

  • A byte commitment to the audit entangled state (state_hash: sha256(bytes)).
  • (Paid tier) the bytes themselves to the machine's bucket.

Each public serve writes:

  • An audit row (state_hash: sha256(bytes)).
  • The egress counter against your tally.

CSP at serve time

Every served byte stream gets the same response headers, framework-set, NOT user-overridable:

Content-Type: <forced from extension>
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline';
style-src 'self' 'unsafe-inline'; img-src 'self' data:;
font-src 'self' data:; connect-src 'self';
frame-ancestors 'none'; form-action 'self';
base-uri 'none';
sandbox allow-scripts allow-forms allow-same-origin
allow-popups allow-popups-to-escape-sandbox;
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Referrer-Policy: no-referrer
X-Zsm-Content-Sha256: <hash of bytes>

The CSP allows 'unsafe-inline' for scripts and styles (so embedded apps work) but locks connect-src to 'self'. A hosted page reaches the kernel through the same-origin Site SDK proxy at /s/:slug/sdk/zeq/:op.

X-Zsm-Content-Sha256 lets external verifiers hash the bytes themselves and compare to the entangled state commitment — proof that the framework served what the entangled state claims.


The hash-commitment-only doctrine

Free-tier hosting commits the hash of every uploaded byte stream to the entangled state, and the entangled state remains the ground truth.

This is consistent with the framework's audit-log doctrine: bytes are off-chain; hashes are on-chain; the entangled state is the witness.

For paid-tier hosting, bytes are persisted in a machine-isolated bucket and the manifest tracks (path, hash, bucket_url, bytes). The entangled state row also points to the bucket, so a future verifier can fetch and re-hash without trusting the framework's serve.


Use cases this is built for

  • Marketing landing for a machine. Spin up my-launch, upload index.html + style.css, share https://zeqsdk.com/s/my-launch/. Every visitor's view is on your entangled state.
  • Client-side dashboard for an entangled state. Upload an HTML/JS dashboard that talks to /api/chain/:slug/explore/sse via the same-origin gate. Public dashboards for is_public machines work without auth.
  • Companion docs for a contract. Upload a static page describing your deployed contract; link from the contract definition's description field.
  • Static API stub. Upload a JSON file at /manifest.json, have a partner read it via GET /s/:slug/manifest.json. Hash on the entangled state proves what they read.

Use cases this is NOT built for

  • Real-time multiplayer apps (no server-side runtime).
  • High-volume CDN-style static (use a real CDN + beacon to your machine).
  • Anything that wants to read zeq.dev cookies (you can't — separate origin).
  • Anything that wants to call random external APIs (you can't — strict connect-src).

Next