[data-reveal]{opacity:1!important;transform:none!important}
Extending
Automation

Extending

Declare your own triggers, actions and data nodes from any module with @antelopejs/interface-dms-automation, ship procedures as code, and start them from code.

Any module can add nodes to the automation builder. The contract lives in a separate package, @antelopejs/interface-dms-automation, which @antelopejs/dms-automation implements. A module that declares nodes depends on the interface only, never on this module.

Add the interface

Choose the dependency type according to whether your module needs automation:

Dependency typeUse whenWithout the automation module
optionalDependenciesYour nodes are a bonus.Registrations wait for attachment.
dependenciesYour module needs automation to work.Automation is required.

For optional nodes, add the interface to optionalDependencies:

package.json
{
  "optionalDependencies": {
    "@antelopejs/interface-dms-automation": ">=0.3.0 <1.0.0"
  }
}

Interface 0.3 adds DeclareProcedure and RunProcedure; its complete contract requires Automation 0.5 or newer. This consumer range stays wide for deduplication. Automation itself implements the interface and uses the narrower >=0.3.0 <0.4.0 range.

Declare an action

Register in start(), unregister in stop(). This example adds a trace marker; it does not call an external service or log its input:

src/automation.ts
import { RegisterActionType, UnregisterActionType } from "@antelopejs/interface-dms-automation";

const ACTION_ID = "example.trace-marker";

export function registerAutomationNodes(): void {
  RegisterActionType({
    id: ACTION_ID,
    name: "Record trace marker",
    description: "Record that this step was reached",
    icon: "i-lucide-file-text",
    inputSchema: { type: "object" },
    outputSchema: { type: "object", properties: { recorded: { type: "boolean" } } },
    async execute(_input, ctx) {
      ctx.log("info", "Trace marker reached");
      return { recorded: true };
    },
  });
}

export function unregisterAutomationNodes(): void {
  UnregisterActionType(ACTION_ID);
}

The builder lists the node in its palette under your module's name (as named in antelope.config.ts), with a settings panel generated from inputSchema and one output port per outputSchema property.

Node kinds

Choose a node according to its role:

  • A trigger starts a run.
  • An action performs asynchronous I/O.
  • A data node computes values synchronously and purely.

The consumer reference defines the required members, schemas, lifecycle and execution context for each kind.

Trigger clustering

Choose the trigger's cluster mode based on where it should fire:

  • singleton activates on the leader only.
  • replicated activates on every instance.

Run a procedure from code

import { InvokeProcedure } from "@antelopejs/interface-dms-automation";

const runId = await InvokeProcedure(procedureId, { orderId: "10477" });

The saved procedure needs a manual trigger. Inspect the run's recorded outcome rather than treating its ID as proof of success.

RunProcedure runs any procedure now, whatever starts it (a schedule, a webhook, a trigger your module registers), as Run now does in the builder, and says how the run ended:

import { RunProcedure } from "@antelopejs/interface-dms-automation";

const { runId, status, errorMessage } = await RunProcedure("reports.weekly", {
  payload: { firedAt: new Date().toISOString() },
});

Without payload, the trigger receives its last stored payload, or {}. triggerNodeId picks the trigger to start from. See the invocation contract for return values, failures and authorization responsibilities.

Ship procedures as code

A project or a module can ship its own procedures, such as the automations a template provides, with DeclareProcedure. Call it on every boot from start():

src/automation.ts
import { DeclareProcedure } from "@antelopejs/interface-dms-automation";
import followUpQuotes from "./procedures/quote-follow-up.json";

export async function start(): Promise<void> {
  await DeclareProcedure({
    id: "bakery.quote-follow-up",
    name: followUpQuotes.name,
    description: followUpQuotes.description,
    graph: followUpQuotes.graph,
    enabled: true,
  });
}

Design the procedure in the builder, export it with Export JSON, and keep the file in your project. The id is yours and stays the procedure's ID: the call creates the procedure once, refreshes it when your declaration changes, and leaves it alone once someone edits, pauses or resumes it in the builder. The module reconciles eligible triggers after storage, respecting singleton leadership and replicated triggers. The declaration contract gives the validation, exact update rule and retry behavior after a storage or synchronization failure.

Do not insert rows in the module's tables yourself: a procedure written behind the module's back is not armed until the next restart, and it ties your project to an internal schema.

Fire on changes to your own tables

The Table watch trigger of @antelopejs/dms-database (database.table-watch) starts a procedure on each insert, update or delete in any registered table, your project's included. Set schema to the ID you pass to RegisterSchema and table to the table name.

It reads the database change feed. MongoDB only has one on a replica set: on a standalone server the procedure shows as Failing with "$changeStream is only supported on replica sets". In development, start MongoDB as a single-node replica set (mongod --replSet rs0, then rs.initiate() once) and add replicaSet=rs0 to the connection string, or use a hosted cluster, which is always a replica set.

The trigger's output carries the row before and after the change, so the procedure can read your columns, a tenantId included. To act on tenant data from your own action, declare tenantId as an input and wire it from that output: the execution context of an action has no tenant.

Nodes from other modules

ModuleNodes
@antelopejs/dmsTriggers: member added and removed, invite created, user registered, record created, updated and deleted. Actions: send email, send notification, invite user.
@antelopejs/dms-databaseTrigger: table watch.
@antelopejs/dms-apiTrigger: route unhealthy. Actions: get API health, query request logs.

Role permissions

The module's pages are DMS blocks around a few module components (DmsAutomation prefix), each named for the roles screen with .meta(). The pages and the module's API (/api/automation) belong to the platform owner.