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.
currentResource
and isAdminOfCurrentResource
cookies for authenticated adminsThe application uses the Hono.js web framework for:
app.get()
, app.post()
)setCookie
, getCookie
, deleteCookie
)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=${sessionId}
- HttpOnly, Secure, 30-day expirycurrentResource=app
- Identifies the resource being editedisAdminOfCurrentResource=true
- Enables Hyperclay edit modeserver.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
GET /auth/edit
- Show email login form
POST /auth/edit
- Process email submission
GET /auth/verify?token=xxx
- Verify magic link
GET /auth/logout
- Logout/view mode
POST /save/app
- Save HTML document
GET /versions
- View version history
GET /reset-dangerous
- Reset to default
User enters email → Generate token → Send magic link → User clicks link
↓
Session cookie set ← Create session ← Verify token ← Token consumed
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
}
};
no-cache, no-store
https://[username]-[valname].web.val.run