Skip to content

0014. The canvas page is served over bearer by its own handlers, answering status and body

Context: ADR 0009 (d) moves pages to a client-only build that reads /api/v1 with a bearer token. Canvas ops (POST /api/v1/org/canvas) are the agent dialect: agent actor, no base merge, different connect and same-canvas rules. Routing the canvas page through them would change what a person’s gesture does.

Decision: the canvas page is served by GET|POST /api/v1/projects/[projectId]/canvases/[canvasId][?action=<name>], which runs the page’s own load and actions ($lib/server/canvas/canvas-page.ts) with a bearer locals. Page and API call the same function by construction, as the user: base/409 concurrency, canvas checks and connect rules stay as they are. Ops keep serving MCP and the CLI.

The answer follows the one convention of every /api/v1 client transport (canvas and editor):

Handler outcomeHTTPBody
returns a value200the value, unwrapped
fail(status, body)statusbody (carries error, or e.g. { conflict: true, keys })
throws error(status, message)status{ error: message }
throws redirect(_, location)200{ redirect: location }
no or invalid bearer401{ error: 'missing_bearer' | 'invalid_token' }

The client calls through the one bearer caller, $lib/api/client.ts.