Functions
Admin-defined server-side JavaScript with grpcSdk access.
The functions module runs admin-defined JavaScript in-process with full grpcSdk access. Operators upload function definitions through the Admin API; HTTP and socket handlers register on the Client API (via router), while function CRUD and execution history live on the Admin API. Treat function code like server configuration — admin-trusted, not user-supplied.
Use cases
Webhooks
Receive Stripe/GitHub callbacks at /hook/{name} and call grpcSdk.database or grpcSdk.email
Custom Client API routes
Authenticated request handlers at /{name} with declared params and returns
Event automation
React to Redis bus events — send notifications when records change
Scheduled jobs
Cron functions run on a BullMQ schedule (Redis-backed)
Socket handlers
Custom Socket.io event handlers on a dedicated namespace path
Cross-module orchestration
Chain database writes, chat system messages, and email in one handler
Capabilities
- Six function types (request, webhook, middleware, socket, event, cron)
- Client API route registration via router
- node:vm sandbox (timeout + require allowlist)
- grpcSdk access
- BullMQ cron scheduler
- Execution logging & metrics
- GitOps export/import
Example: Webhook handler
Walkthrough
- Admin uploads a webhook function via POST /functions/upload (Admin API)
- Router registers POST /hook/stripeWebhook on CLIENT_BASE_URL
- External provider POSTs to the hook URL
- Function validates signature in JS, calls grpcSdk.database to update Order
- grpcSdk.email sends receipt; res({ ok: true }) returns the response shape
curl -X POST http://localhost:3000/hook/stripeWebhook \
-H "Content-Type: application/json" \
-d '{"type":"payment_intent.succeeded","data":{...}}'curl -X POST http://localhost:3030/functions/upload \
-H "masterkey: YOUR_MASTERKEY" \
-H "Content-Type: application/json" \
-d '{
"name": "stripeWebhook",
"functionType": "webhook",
"functionCode": "const sig = req.headers[\"stripe-signature\"]; /* verify + handle */ res({ received: true });",
"inputs": { "method": "POST" },
"returns": { "received": "Boolean" }
}'How it works
Trust boundary
Function code is admin-trusted — equivalent to deploying code to the server. It runs in the same Node.js process with full grpcSdk privileges. The VM layer applies a per-invocation timeout and limits require to lodash and axios only. These are guardrails against accidents, not a security boundary for malicious code. Do not use this module for tenant-submitted scripts.
For user-facing filtered queries, use database custom endpoints at /database/function/{name} on the Client API instead.
Handler shape
Stored functionCode is the body of:
function (grpcSdk, req, res) {
// your code
}
| Parameter | Meaning |
|---|---|
grpcSdk | Conduit gRPC SDK — database, auth, storage, chat, communications, … |
req | Parsed request: HTTP params/body/query for routes; event payload for bus/cron |
res | Callback (data) => void — return value mapped through returns schema |
console.log output is captured in execution logs.
Function types
functionType | Trigger | Client API surface |
|---|---|---|
request | HTTP route | /{name} (+ optional /:urlParams) |
webhook | HTTP route (no auth middleware by default) | /hook/{name} |
middleware | Global middleware | Registered as named middleware on / |
socket | Socket.io event | Namespace path /{name}, event from inputs.event |
event | Redis bus subscription | inputs.event = bus channel name |
cron | BullMQ repeatable job | inputs.event = cron expression |
The module waits for router to be serving before registering routes (watch: router rising).
HTTP methods and PUT mapping
inputs.method accepts GET, POST, PUT, PATCH, or DELETE. PUT maps to ConduitRouteActions.UPDATE — the same route action Hermes uses for update verbs (not GET). This matters when declaring returns and when matching routes in middleware patches.
Optional inputs.auth: true on request functions adds authMiddleware.
Declare inputs.bodyParams, inputs.queryParams, and inputs.urlParams to validate incoming data; urlParams append /:key segments to the route path.
VM sandbox
Each invocation runs inside node:vm:
- Timeout — per-function
timeoutin milliseconds (default 180000 / 3 minutes) - require allowlist — only
lodash(lodash-es) andaxios; anything else throws at runtime - Single run — compile + invoke share one timeout budget
Syntax is validated on upload (POST /functions/upload) and update (PATCH /functions/:id).
Event functions
functionType: event subscribes to grpcSdk.bus on channel inputs.event. Payloads are passed as req (JSON-parsed when the bus message is a JSON string). Handler errors are logged; they do not block the publisher.
Cron functions (BullMQ)
functionType: cron stores a cron expression in inputs.event (for example 0 */6 * * *). The functions module registers a BullMQ repeatable job on Redis — the same job-queue infrastructure used by database and communications modules. On each tick the handler runs with an empty or minimal req payload.
Cron requires the platform Redis connection used by other BullMQ workers (grpcSdk.redisManager) — there is no separate FUNCTIONS_REDIS_* configuration. Execution history is recorded like other function types.
Returns mapping
If returns is omitted, the handler result is wrapped as { result: data }. When returns is a schema object, only declared keys are forwarded from the res(...) payload. Set returns: "String" for a plain string result.
When to use Functions vs alternatives
| Need | Use |
|---|---|
| Filtered Client API query | Database custom endpoint |
| Long-running domain service | Custom ManagedModule |
| Webhook, cron, bus automation | Functions |
| System chat message from backend | grpcSdk.chat from Function or custom module |
Configure
| Key | Default | Meaning |
|---|---|---|
active | true | Module serves and registers routes when router is up |
Define functions via Admin panel or Admin API when the functions module is enabled. Each document stores name, functionType, functionCode, inputs, optional returns, and timeout.
On create/update/delete the module publishes to the functions bus channel and refreshes router registrations.
Client API
Functions register routes on the router (not Admin API):
| Type | Example path | Notes |
|---|---|---|
request | PUT /myHandler | When inputs.method is PUT → UPDATE action |
webhook | POST /hook/stripeWebhook | Typically unauthenticated |
socket | Namespace /{name} | Event from inputs.event |
App runtime code calls these URLs on CLIENT_BASE_URL like any other Client API route. request functions with inputs.auth: true require a bearer token.
Functions do not replace /database/function/{name} — those are database custom endpoints.
Admin API
Function management on ADMIN_BASE_URL/functions/...:
| Method | Path | Purpose |
|---|---|---|
| POST | /functions/upload | Create function |
| GET | /functions/ | List (search, skip, limit, sort) |
| GET | /functions/:id | Get function |
| PATCH | /functions/:id | Update code, inputs, returns, timeout |
| DELETE | /functions/:id | Delete function |
| DELETE | /functions/ | Bulk delete (ids[] query) |
| GET | /functions/list/executions | All execution logs |
| GET | /functions/executions/:functionId | Per-function executions (success filter) |
MCP
Enable with ?modules=functions in your MCP server URL. Admin tools manage function CRUD; uploaded functions appear on the Client API after router refresh.