Skip to content

Deploy

Build & deploy

sh
bun run build       # tsc -b && vite build
bun run deploy      # bun run build && wrangler deploy

vite build emits the SPA into dist/, then @cloudflare/vite-plugin bundles the Worker against worker/index.ts. wrangler deploy uploads both, wiring the SPA up via assets.not_found_handling: "single-page-application" in wrangler.jsonc.

Type checking

The project ships two TypeScript projects (tsconfig.app.json covers src/, tsconfig.worker.json covers worker/). Run them in sequence:

sh
tsc -p tsconfig.app.json && tsc -p tsconfig.worker.json

This is also wired up as bun run typecheck.

Migrating the schema separately

The InitPage runs SCHEMA_STATEMENTS against your D1 database. If you prefer migrations:

sh
bunx wrangler d1 migrations apply lumen-db --local
bunx wrangler d1 migrations apply lumen-db --remote

The migrations/ folder ships with 0001_init.sql, which mirrors SCHEMA_STATEMENTS. Add new migrations there as the schema evolves.

Custom domain

In wrangler.jsonc, add a routes block pointing at your domain:

jsonc
"routes": [
  { "pattern": "mail.example.com", "custom_domain": true }
]

The redirect URI in the Prism app must match the same hostname; update prism_redirect_uri via the InitPage or PUT /api/init/config if you move domains.

Operational tips

  • Use bunx wrangler tail to follow runtime logs, including failed inbound parse attempts and rejected recipients.
  • Treat init:configured in KV as the gate for first-boot setup. Delete it to re-run the InitPage; it doesn't drop the schema.
  • For heavier mailboxes, mirror raw .eml files to a backup R2 bucket and sync regularly — D1 holds metadata, but the source-of-truth message body is the R2 object.