FeaturesTemplatesShowcaseTownie
AI
BlogDocsPricing
Log inSign up
panphora

panphora

hyperclay

a single-tenant version of hyperclay
Public
Like
hyperclay
Home
Code
5
ARCHITECTURE.md
DEBUG_GUIDE.md
DEV_GUIDE.md
README.md
H
index.ts
Branches
1
Pull requests
Remixes
1
History
Environment variables
3
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.
Sign up now
Code
/
ARCHITECTURE.md
Code
/
ARCHITECTURE.md
Search
9/5/2025
ARCHITECTURE.md

Hyperclay App Architecture

Overview

This is a Hyperclay-compatible HTML editor application that provides secure email-based authentication for editing HTML documents with version control. The app serves both as a public viewer and an authenticated editor interface.

Core Functionality

1. HTML Document Management

  • Storage: Uses Val.town blob storage for persistence
  • Versioning: Automatic version history with incremental numbering
  • Default Content: Falls back to a Hyperclay starter template when no content exists
  • Reset Capability: Admin can reset to default state (dangerous operation)

2. Authentication System

  • Magic Link Auth: Email-based passwordless authentication
  • Admin-Only Access: Only the configured admin email can authenticate
  • Session Management: 30-day sessions with automatic extension
  • Token Security: 15-minute expiring one-time-use tokens

3. Hyperclay Integration

  • Edit Mode Cookies: Sets currentResource and isAdminOfCurrentResource cookies for authenticated admins
  • Security: Server-side cookie setting with proper security attributes
  • View Mode: Cookie clearing for public viewing

Technical Architecture

Framework: Hono.js

The application uses the Hono.js web framework for:

  • Declarative routing (app.get(), app.post())
  • Built-in cookie management (setCookie, getCookie, deleteCookie)
  • Middleware support for authentication
  • Consistent error handling

Storage Schema

Blob Keys:
- `${APP_NAMESPACE}_app` - Current HTML document
- `${APP_NAMESPACE}_app_version_${n}` - Versioned HTML documents
- `${APP_NAMESPACE}_app_version_count` - Version counter
- `${APP_NAMESPACE}_auth_token_${token}` - Magic link tokens (15min TTL)
- `${APP_NAMESPACE}_session_${sessionId}` - User sessions (30day TTL)

Environment Variables

  • ADMIN_EMAIL - Email address allowed to authenticate (required)
  • APP_NAMESPACE - Storage namespace prefix (default: 'default')
  • DEBUG - Enable debug logging (default: false)

Cookie Strategy

  • Session Cookie: session=${sessionId} - HttpOnly, Secure, 30-day expiry
  • Hyperclay Cookies (admin only):
    • currentResource=app - Identifies the resource being edited
    • isAdminOfCurrentResource=true - Enables Hyperclay edit mode

Code Structure

server.js (654 lines)
├── Configuration (lines 1-43)
│   ├── Imports (Hono, Val.town services)
│   ├── Environment variables
│   └── STORAGE_KEYS object
│
├── Core Services (lines 45-162)
│   ├── readBlob() - Unified blob reading
│   └── auth object - All authentication logic
│
├── Templates & Helpers (lines 164-358)
│   ├── TEMPLATES - HTML templates
│   ├── respond - Response helpers
│   └── handleAsync - Error wrapper
│
├── Application Logic (lines 380-443)
│   ├── sendMagicLink()
│   ├── getCurrentHTML()
│   ├── saveHTML()
│   └── getVersionHistory()
│
├── Middleware (lines 459-486)
│   └── requireAdmin - Protected routes
│
└── Routes (lines 490-651)
    ├── GET / - Main application
    ├── Auth endpoints (/auth/*)
    ├── POST /save/app - Save content
    ├── GET /versions - History
    └── GET /reset-dangerous - Reset

Request Flow

Public Routes

  1. GET / - Serve HTML document

    • Check admin status from session cookie
    • Set Hyperclay cookies if admin
    • Return HTML content with no-cache headers
  2. GET /auth/edit - Show email login form

  3. POST /auth/edit - Process email submission

    • Validate admin email
    • Generate magic link token
    • Send email with magic link
    • Show confirmation page
  4. GET /auth/verify?token=xxx - Verify magic link

    • Validate and consume token
    • Create session
    • Set session cookie
    • Redirect to main page
  5. GET /auth/logout - Logout/view mode

    • Clear all cookies
    • Redirect to main page

Admin-Only Routes

  1. POST /save/app - Save HTML document

    • Verify admin session
    • Validate HTML content
    • Save with versioning
    • Return success response
  2. GET /versions - View version history

    • Verify admin session
    • Display all versions with HTML preview
  3. GET /reset-dangerous - Reset to default

    • Verify admin session
    • Clear all versions and content
    • Reset to default HTML
    • Set message cookie and redirect

Security Model

Authentication Flow

User enters email → Generate token → Send magic link → User clicks link
                                                         ↓
Session cookie set ← Create session ← Verify token ← Token consumed

Authorization

  • Public Access: View HTML document, access auth forms
  • Admin Access: Save content, view versions, reset state
  • Session Validation: Every admin operation checks session validity

Cookie Security

  • HttpOnly: Session cookies not accessible to JavaScript
  • Secure: Only transmitted over HTTPS
  • SameSite=Lax: CSRF protection
  • Cache-Control: no-cache, no-store, must-revalidate

Key Design Patterns

1. Centralized Storage Keys

const STORAGE_KEYS = { app: `${APP_NAMESPACE}_app`, version: (n) => `${APP_NAMESPACE}_app_version_${n}`, versionCount: `${APP_NAMESPACE}_app_version_count`, token: (token) => `${APP_NAMESPACE}_auth_token_${token}`, session: (id) => `${APP_NAMESPACE}_session_${id}`, };

2. Unified Blob Reading

const readBlob = async (key) => { const response = await blob.get(key); if (!response) return null; if (response instanceof Response) return await response.text(); if (typeof response === "string") return response; return null; };

3. Auth Namespace

const auth = { generateToken: () => crypto.randomUUID(), storeToken: async (token, email) => {/* ... */}, verifyToken: async (token) => {/* ... */}, createSession: async (email) => {/* ... */}, verifySession: async (sessionId) => {/* ... */}, };

4. Template System

const TEMPLATES = { loginForm: (error?) => `/* HTML */`, checkEmail: (email) => `/* HTML */`, invalidToken: () => `/* HTML */`, versionHistory: (versions) => `/* HTML */`, };

5. Response Helpers

const respond = { error: (c, msg, status) => c.json({ msg, msgType: "error" }, status), success: (c, msg) => c.json({ msg, msgType: "success" }), unauthorized: (c) => c.json({ msg: "Unauthorized", msgType: "error" }, 401), setSessionCookie: (c, sessionId) => {/* ... */}, setAdminCookies: (c) => {/* ... */}, };

6. Error Handling Wrapper

const handleAsync = (handler) => async (c, next) => { try { return await handler(c, next); } catch (error) { // Centralized error handling } };

Performance Considerations

  • Blob Storage: Efficient key-value store for HTML content
  • Session Extension: Automatic extension reduces re-authentication
  • Version Limit: No built-in limit (consider implementing cleanup)
  • Cache Headers: Prevents stale content with no-cache, no-store

Deployment on Val.town

  • Runtime: Deno with TypeScript support
  • Hosting: Serverless with automatic scaling
  • Storage: Built-in blob storage (10MB free, 1GB pro)
  • Email: Integrated email service for magic links
  • URL Pattern: https://[username]-[valname].web.val.run

Future Considerations

  1. Multi-tenancy: Support multiple admin users
  2. Version Cleanup: Automatic old version deletion
  3. Backup/Export: Download HTML and version history
  4. Rate Limiting: Prevent abuse of auth endpoints
  5. Audit Logging: Track all admin actions
FeaturesVersion controlCode intelligenceCLI
Use cases
TeamsAI agentsSlackGTM
ExploreDocsShowcaseTemplatesNewestTrendingAPI examplesNPM packages
PricingNewsletterBlogAboutCareersBrandhi@val.townStatus
X (Twitter)
Discord community
GitHub discussions
YouTube channel
Bluesky
Terms of usePrivacy policyAbuse contact
© 2025 Val Town, Inc.