hyperclay
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.
Viewing readonly version of main branch: v90View latest version
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.
- 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)
- 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
- Edit Mode Cookies: Sets
currentResource
andisAdminOfCurrentResource
cookies for authenticated admins - Security: Server-side cookie setting with proper security attributes
- View Mode: Cookie clearing for public viewing
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
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)
ADMIN_EMAIL
- Email address allowed to authenticate (required)APP_NAMESPACE
- Storage namespace prefix (default: 'default')DEBUG
- Enable debug logging (default: false)
- Session Cookie:
session=${sessionId}
- HttpOnly, Secure, 30-day expiry - Hyperclay Cookies (admin only):
currentResource=app
- Identifies the resource being editedisAdminOfCurrentResource=true
- Enables Hyperclay edit mode
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
-
GET /
- Serve HTML document- Check admin status from session cookie
- Set Hyperclay cookies if admin
- Return HTML content with no-cache headers
-
GET /auth/edit
- Show email login form -
POST /auth/edit
- Process email submission- Validate admin email
- Generate magic link token
- Send email with magic link
- Show confirmation page
-
GET /auth/verify?token=xxx
- Verify magic link- Validate and consume token
- Create session
- Set session cookie
- Redirect to main page
-
GET /auth/logout
- Logout/view mode- Clear all cookies
- Redirect to main page
-
POST /save/app
- Save HTML document- Verify admin session
- Validate HTML content
- Save with versioning
- Return success response
-
GET /versions
- View version history- Verify admin session
- Display all versions with HTML preview
-
GET /reset-dangerous
- Reset to default- Verify admin session
- Clear all versions and content
- Reset to default HTML
- Set message cookie and redirect
User enters email → Generate token → Send magic link → User clicks link
↓
Session cookie set ← Create session ← Verify token ← Token consumed
- Public Access: View HTML document, access auth forms
- Admin Access: Save content, view versions, reset state
- Session Validation: Every admin operation checks session validity
- HttpOnly: Session cookies not accessible to JavaScript
- Secure: Only transmitted over HTTPS
- SameSite=Lax: CSRF protection
- Cache-Control:
no-cache, no-store, must-revalidate
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}`,
};
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;
};
const auth = {
generateToken: () => crypto.randomUUID(),
storeToken: async (token, email) => {/* ... */},
verifyToken: async (token) => {/* ... */},
createSession: async (email) => {/* ... */},
verifySession: async (sessionId) => {/* ... */},
};
const TEMPLATES = {
loginForm: (error?) => `/* HTML */`,
checkEmail: (email) => `/* HTML */`,
invalidToken: () => `/* HTML */`,
versionHistory: (versions) => `/* HTML */`,
};
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) => {/* ... */},
};
const handleAsync = (handler) => async (c, next) => {
try {
return await handler(c, next);
} catch (error) {
// Centralized error handling
}
};
- 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
- 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
- Multi-tenancy: Support multiple admin users
- Version Cleanup: Automatic old version deletion
- Backup/Export: Download HTML and version history
- Rate Limiting: Prevent abuse of auth endpoints
- Audit Logging: Track all admin actions