Serves ENS websites (*.eth.casa) entirely in the browser. A service worker resolves the ENS contenthash, verifies it twice (DNS + blockchain), and fetches content from IPFS with cryptographic verification. No server-side resolution.
graph LR
subgraph Browser
L[Loader page<br>index.html] --> SW[Service Worker<br>sw/]
SW --> H[Helia node<br>helia.ts]
H --> OPFS[(OPFS blocks)]
H --> MFS[(MFS cache)]
H --> IDB[(IndexedDB<br>metadata)]
end
subgraph Edge
W[Cloudflare Worker<br>worker.ts] --> A[Static assets<br>dist/]
end
L -->|registers| SW
SW -->|DoH query| DOH[eth.limo DoH]
SW -->|eth_call + CCIP| RPC[ENS Universal<br>Resolver RPC]
H -->|gateways / bitswap| IPFS[(IPFS network)]
sequenceDiagram
participant B as Browser
participant W as Worker (edge)
participant L as Loader page
participant SW as Service Worker
participant H as Helia
B->>W: GET name.eth.casa/path
W->>B: index.html (loader)
B->>L: run inline JS
L->>SW: register /eth_casa/sw.js
L->>SW: fetch(location.href)
SW->>SW: resolve ENS contenthash (DoH + RPC)
SW->>H: verifiedFetch(ipfs://CID/path)
H-->>SW: verified bytes
SW->>SW: write to MFS + OPFS
SW-->>B: 200 content
L->>B: reload → SW serves from MFS
flowchart TD
Q[ENS name] --> D[DoH query<br>DNSLink TXT]
D -->|ok| R[RPC eth_call<br>Universal Resolver V2]
D -->|fail| X1[BLOCK]
R -->|CCIP revert| G[CCIP-read gateway<br>HTTPS public only]
G --> R
R --> M{scheme + root<br>match DoH?}
M -->|yes| S[Serve content]
M -->|no / empty / unsupported| X2[BLOCK]
DoH-only mode (?eth-casa-doh-only=true) skips the RPC step as an explicit opt-out.
flowchart TD
Req[GET /path] --> MFS{MFS hit?}
MFS -->|yes| Serve1[Serve from MFS]
MFS -->|no| Stale{Stale CID<br>MFS hit?}
Stale -->|yes| Serve2[Serve previous version<br>mfs-stale-reuse]
Stale -->|no| VF[verifiedFetch<br>OPFS → gateways → bitswap]
VF -->|200| W[Write MFS + pin depth 0<br>Serve]
VF -->|404| SPA{SPA fallback<br>/index.html}
SPA -->|200| W
SPA -->|fail| Err[Error page<br>+ IPNI diagnostics]
VF -->|timeout / error| Err
| Layer | Storage | TTL | Scope |
|---|---|---|---|
| Session cache | memory | 30 s | sub-requests of one page load |
| Resolve cache | memory | 5 min | verified DoH+RPC matches |
| DNSLink cache | memory + CacheStorage | 5 min / 7-day stale | DoH results |
| IPNS resolve cache | memory + CacheStorage | 120 s / 7-day stale | IPNS → IPFS CID |
| MFS | OPFS via Helia | until contenthash changes | verified file bytes, keyed by CID |
| Stale CID grace | memory | 3 days | previous CID's MFS data after an update |
| OPFS blockstore | OPFS (IDB fallback) | until evicted (storage limit) | raw IPFS blocks |
vitalik.eth.casa→vitalik.ethaero_dome.eth.casa→aero.dome.ethvitalik.localhost:PORTworks in dev
| File | Role |
|---|---|
src/worker.ts |
Edge: static assets, SPA fallback, dynamic headers |
src/index.html |
Loader page: apex lander + wildcard bootstrap |
src/eth_casa/eth-casa.ts |
Loader logic: SW registration, config, message UI, reset |
src/eth_casa/sw/index.ts |
SW entry: lifecycle, fetch routing, message handling |
src/eth_casa/sw/content.ts |
Content pipeline: MFS lookup, verified fetch, SPA fallback |
src/eth_casa/sw/resolve.ts |
DoH + RPC cross-compare, caches, stale CID registry |
src/eth_casa/sw/ens-rpc.ts |
RPC calls, CCIP-read, gateway URL validation |
src/eth_casa/helia.ts |
Helia node, verified fetch, MFS, pinning |
src/eth_casa/opfs.ts |
OPFS blockstore with IDB fallback |
src/eth_casa/config.ts |
All constants and types |
bun run typecheck # tsc --noEmit
bun run build # esbuild → dist/
bun run dev # build + wrangler dev :8787
bun run deploy # build + wrangler deploy
bun run test # Playwright E2E (auto-starts dev server)ETH_CASA_RPC_URL sets the primary RPC at build time. Keep the key out of source.
| Param | Effect |
|---|---|
?eth-casa-debug=true |
Verbose logging |
?eth-casa-doh-only=true |
Skip RPC verification |
?eth-casa-auto-reload=false |
Disable 7s auto-continue |
?eth-casa-max-storage=N |
Storage limit in MB (10–10000) |
?eth-casa-full-reset=true |
Clear SW, caches, OPFS, IndexedDB |
?eth-casa-sw-unregister=true |
Unregister SW only |
?eth-casa-options=true |
Options panel without loading content |
?eth-casa-dash=true |
Internal state dashboard |
All params are stripped from the URL after processing.