Skip to content

Repository files navigation

eth.casa — Client-side ENS Gateway

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.

Architecture

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)]
Loading

Request flow

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
Loading

ENS resolution

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]
Loading

DoH-only mode (?eth-casa-doh-only=true) skips the RPC step as an explicit opt-out.

Content serving

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
Loading

Caching layers

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

Hostname rules

  • vitalik.eth.casavitalik.eth
  • aero_dome.eth.casaaero.dome.eth
  • vitalik.localhost:PORT works in dev

Code map

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

Build and deploy

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.

Query params

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.

See also

  • specs.md — full technical specification
  • review.md — latest code review
  • AGENT.md — AI assistant conventions
  • skills/workflows/ — per-component guides

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages