Server actions are defined inDocumentation Index
Fetch the complete documentation index at: https://docs.deep.space/llms.txt
Use this file to discover all available pages before exploring further.
src/actions/index.ts and exposed at POST /api/actions/:name. They run as the app - RBAC checks are bypassed via the X-App-Action header - and are the right tool for cross-collection orchestration or owner-gated operations.
ActionHandler<TEnv>
src/actions/index.ts:
/api/actions/inviteAttendee.
ActionContext<TEnv>
userId is the caller - not the app owner. Use it for audit logs and per-caller logic. For owner-only actions, gate on userId === env.OWNER_USER_ID.
callerJwt is the raw, already-verified Bearer token the action was invoked with. Forward it on outbound platform requests that need to act as the caller rather than as the app owner - for example, deploy-worker /api/apps ownership checks, or any apiWorkerFetch / platformWorkerFetch call where the upstream bills or authorizes the JWT subject. See Forwarding caller identity in the guide.
ActionTools
| Method | Returns (under .data) |
|---|---|
tools.get(coll, id) | { record } - full envelope with data typed as T |
tools.query(coll, opts?) | { records, count } |
tools.create(coll, data, recordId?) | { recordId } - pass recordId to upsert against a known key (see Upsert by known id) |
tools.update(coll, id, patch) | { recordId } |
tools.remove(coll, id) | { recordId } |
tools.integration(endpoint, body) | The integration’s response body directly (typed as T) |
tools.integration does not wrap the response in { response } - on success, result.data IS the integration’s body. An OpenAI chat call yields result.data.choices; a Freepik image call yields result.data.images.
All operations bypass caller RBAC. tools.query sees every record in the collection regardless of the caller’s role - pass a where clause to scope.
ActionResult<T>
if (result.success) before reading result.data:
Integration billing
tools.integration(endpoint, body) proxies through the api-worker. Billing follows src/integrations.ts:
billing setting | Who pays |
|---|---|
'developer' | The app owner via APP_OWNER_JWT |
'user' | The signed-in caller |
X-Billing-User-Id is ignored).
Owner-only pattern
Gate actions that spend owner resources:OWNER_USER_ID is set on every deployed app and is the canonical trust anchor for owner-only operations.
Calling from the client
success / data / error shape is forwarded verbatim in the HTTP response body. HTTP status is 200 on success, 401 if unauthenticated, 404 if the action name doesn’t exist, 500 on uncaught throws.
Type tip - fetching the post-write envelope
tools.create / update / remove resolve to ActionResult<MutateActionData> - only { recordId } is returned, never the full envelope. To inspect the row after a mutation, re-fetch it:
See also
- Server actions guide - patterns and worked examples
- Permissions concepts - what RBAC bypass means
- External APIs guide - billing routing for
tools.integration