o
odinpkg.dev
packages / library / wasm_ui

wasm_ui

85a5706library

No description provided.

No license · updated 10 months ago

Odin WASM UI Chat Example

An Odin + WebAssembly UI example with a minimal virtual DOM, a small static server powered by odin-http, and JWT-backed endpoints. The UI runs in the browser (WASM), while the native server serves static files and a tiny JSON API.

Features

  • Chat UI rendered from Odin to the DOM via JS bridges
  • Fixed-height, scrollable message list with auto-scroll and focus preservation
  • Send messages from the UI; server stores them in memory (max 200)
  • JWT (HS256) demo endpoints with constant-time signature verification
  • “Who Am I” button to validate the JWT from the browser

Prerequisites

  • Odin toolchain (tested with odin version dev-2025-08)
  • just (optional but recommended): just --version

Quick Start

  • Build and run everything:
    • just serve
    • Open http://localhost:8080/

The serve recipe will:

  • Fetch vendor/odin-http if missing (just vendor)
  • Build the WASM UI (just buildui.wasm)
  • Build the native server (just build-server./server_bin)
  • Launch the server on port 8080

Useful Commands

  • Build WASM only: just build
  • Build server only: just build-server
  • Fetch/update vendor:
    • just vendor (clone odin-http)
    • just vendor-update (pull latest)

Without just:

  • WASM: odin build . -target:js_wasm32 -out:./ui.wasm
  • Server: odin build ./server -collection:local=./vendor -out:./server_bin && ./server_bin

Debug logs

  • One-off: LOG_LEVEL=debug just serve
  • Or use the recipe: just serve-debug
  • Levels: debug, info (default), warn, error via LOG_LEVEL.

Bluesky OAuth (optional)

Enable “Sign in with Bluesky” by setting these environment variables (e.g., in .env):

  • BSKY_OAUTH_REDIRECT_URI: Use http://127.0.0.1:8080/ (or your host) and ensure it’s registered.
  • BSKY_OAUTH_AUTHORIZATION_ENDPOINT: e.g. https://bsky.social/oauth/authorize.
  • BSKY_OAUTH_TOKEN_ENDPOINT: e.g. https://bsky.social/oauth/token.
  • BSKY_OAUTH_SCOPE (optional): Defaults to profile offline_access.

Click “Sign in with Bluesky” in the UI to run a PKCE flow. On success, the server exchanges the code and issues a local JWT; the UI stores it and updates the current user.

Endpoints

  • GET /api/messages[{ user, text, at }]
  • POST /api/messages → body { user, text }
  • GET /api/auth/token?sub=NAME{ token } (HS256 JWT)
  • GET /api/auth/whoami (requires Authorization: Bearer <token>) → { payload }
  • GET /api/health{ ok: true }
  • GET /api/time{ now: "YYYY-MM-DD HH:MM:SS" }

File Overview

  • index.html — Boots the WASM, provides DOM/JS bridge and loading spinner
  • odin.js — Odin’s JS runtime/loader required by index.html (tracked in repo)
  • main.odin — UI state + components; fetch handlers, JWT wiring
  • vdom.odin — Minimal virtual DOM node definitions
  • renderer.odin — DOM builder + JS foreign imports (events, fetch, focus)
  • events.odin — Event dispatch from JS → Odin and rerender
  • server/main.odin — Static server, JSON API, rate limiting, logging
  • server/jwt.odin — HS256 sign/verify and base64url helpers
  • justfile — Build/serve tasks; vendor management

Notes

  • Messages are stored in Turso (libSQL over HTTP). Set environment variables before starting the server:
    • TURSO_DATABASE_URL (or LIBSQL_URL)
    • TURSO_AUTH_TOKEN (or LIBSQL_AUTH_TOKEN) The server auto-creates the messages table if needed. Without these env vars, storage is disabled and message endpoints return 500.
  • JWT secret defaults to dev-secret-change-me (see server/main.odin). Swap for production.
  • The app shows a spinner until the first render; on failure, it replaces the spinner with a friendly error.

Troubleshooting

  • If the server can’t find odin-http, run just vendor.
  • If the browser fetches fail, check DevTools Network and the terminal logs. The UI logs status and up to 200 chars of body on parse failures.
  • If you see a 404 for odin.js, ensure it’s present in the project root (it’s tracked in this example); the page loads it before starting ui.wasm.

This is an educational example; harden and review before production use.