Architecture
One Worker, one deploy. The Worker entrypoint is packages/api/src/index.ts;
the build output of packages/webapp is mounted as the ASSETS binding.
Browser / MCP client
|
v
Cloudflare Worker (packages/api/src/index.ts)
├── Static assets: Preact SPA (packages/webapp/dist/client)
├── /api/v1/*: Hono REST API
├── /mcp: MCP Streamable HTTP endpoint
├── /media/*: authenticated R2 read proxy
└── Bindings: D1 (DB), R2 (MEDIA), AI Gateway / Workers AI (AI), ASSETS
Request flow
logger,requestContext, andsessionMiddlewarerun for every request./api/v1/*gets CORS;/api/v1/health,/api/v1/authare public; the rest require a session (cookie or bearer) and CSRF for cookie mutations./mcpauthenticates, builds anMcpServicescontainer for the user, and delegates to@caly/mcp./media/:idchecks ownership and streams the R2 object.- Anything else falls through to
ASSETS.fetch, giving SPA deep links.
Layers
routes/— thin HTTP handlers; parse with shared schemas.services/— business logic, authorization, and orchestration.repositories/— D1 access, snake_case rows → camelCase schemas (lib/map.ts).lib/— crypto, validation, errors, cursor, mapping.services/ai/— the only place AI Gateway / Workers AI is called.