API surface
Two mechanisms. Choose by shape, not habit.
- Server actions (
src/app/**/actions.ts) for mutations driven by the UI. Type-safe end to end, no serialization boilerplate, no route to keep in sync. - Route handlers (
src/app/api/**/route.ts) for anything needing a URL: file downloads, OAuth redirects,<form method="post">targets, andfetchfrom a client component.
Server actions
src/app/studio/actions.ts
Every mutation calls assertOwns(projectId) first — ownership check, admin override, throws otherwise.
| Action | Notes |
|---|---|
createProject | Also creates the Universe and Timeline. A project without a Universe is not a thing. |
saveScript | Every save is a new ScriptVersion |
promoteScriptToProduction | Parses Fountain → scenes, characters, locations, cues, notes, graph edges |
buildShotList / buildAllShotLists | Shot Engine coverage grammar |
generateStoryboardAction | Cheap still, Economy tier |
generateShotAction | Throws StoryboardGateError if the gate is unmet |
generateArenaAction / pickWinnerAction | Arena + win-rate training |
improveAction | Regenerates only weak scoring dimensions |
freeGenerate / tryStyle | Creator Studio surfaces |
applyStyleAction | Project / scene / shot scope |
approveCascadeAction / rejectCascadeAction | The confirmation gate |
addStateEventAction / changeWardrobeAction | Return a priced plan, not a mutation |
directorSend / directorApprove / directorReject | Vibe directing |
assembleTimeline / proposeRuntimeEditAction / applyEditProposalAction | NLE |
runAuditAction / fixAllAction | Film Audit |
submitToTheater | Creates the Publication, cast cards, runs Stage 0 |
src/app/admin/actions.ts
decideAction, assessQualityAction, publishAction — all behind requireRole('admin', 'moderator').
Route handlers
| Route | Purpose | |||
|---|---|---|---|---|
GET /api/style-preview/[styleId] | Canonical reference scene as SVG. ?w &h &seed &still &modifiers. Deterministic → immutable cache. | |||
GET /api/projects/[id]/export | `?format=edl \ | srt \ | edl-json \ | <delivery format>` |
GET /api/projects/[id]/script/export | `?format=fountain \ | fdx, ?annotations=1` | ||
POST /api/theater/[id]/progress | JSON. Called by the player every ~5s of watched time. | |||
| `POST /api/theater/[id]/rate \ | comment \ | mylist` | Form posts, 303 redirect back | |
POST /api/theater/follow/[userId] | Toggle | |||
POST /api/festival/vote/[entryId] | One vote per account per category | |||
GET /api/publishing/connect/[platform] | OAuth start; CSRF nonce in an httpOnly cookie | |||
POST /api/publishing/disconnect/[id] | Destroys the token | |||
POST /api/auth/signout |
Conventions
- Auth —
currentUser()returnsnull;requireUser()/requireRole()throwAuthErrorwith a status. - Errors — server actions return
{ ok, message }for expected failures (insufficient credits, storyboard gate) and throw only for programming errors. Expected failures are UI states, not exceptions. - Redirects — form-post handlers return 303 so a refresh does not resubmit.
- Revalidation —
revalidatePath(path, 'layout')after anything that changes project-wide state.
Not built
No public REST API for third parties. Part 7 lists an API for the Studio tier; when it exists it should wrap the same service functions rather than reimplementing them — the services are already the API, they just lack an HTTP surface and key auth.