Systems
System plugins allow Automation to exchange data with external platforms such as EMRs, national surveillance systems, DHIS2, and other databases that need structured lab data.
Each system plugin must export a start
function that receives a context
object. The plugin does not manage queues or routing β Automation handles this and delivers the correct resources based on your declared capabilities
.
π° Typing the Contextβ
Always type your context with your pluginβs automation definition:
import type { Context } from "automation/types/context";
import automation from "../path/to/automation.json";
export async function start(context: Context<typeof automation>) {
// plugin logic
}
βοΈ Accessing Configurationβ
System plugins can define configFields
such as:
configFields: [
{ key: "baseUrl", label: "API URL", type: "string", required: true },
{ key: "token", label: "Access Token", type: "password", required: true }
]
At runtime, values are available at:
context.connection.system.config
Example:
const { baseUrl, token } = context.connection.system.config;
π₯ Receiving Resources to Syncβ
When your plugin declares a receive
capability for a resource like DiagnosticReport
, Automation will deliver those resources to your code via:
context.on("DiagnosticReport", async report => {
// sync logic
report.status("synced", "external-id-123");
});
Automation handles matching, delivery, tracking, and retries automatically.
π Example: EMR or FHIR Serverβ
import axios from "axios";
export async function start(context) {
const { baseUrl, token } = context.connection.system.config;
context.on("DiagnosticReport", async report => {
try {
const { data } = await axios.post(`${baseUrl}/DiagnosticReport`, report, {
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/fhir+json"
}
});
report.status("synced", data.id ?? `report-${Date.now()}`);
} catch (err: any) {
if (err.response?.status === 400 || err.response?.status === 403) {
report.status("failed", err.message); // permanent failure
} else {
report.status("error", err.message); // retryable
}
}
});
context.status("connected");
}
π Example: DHIS2 (Aggregate Reporting)β
import axios from "axios";
export async function start(context) {
const { baseUrl, username, password } = context.connection.system.config;
const auth = { auth: { username, password } };
context.on("Observation", async observation => {
try {
const payload = {
dataValues: [
{
dataElement: "MAL_POS",
value: 1,
period: "202405",
orgUnit: "XYZ001"
}
]
};
await axios.post(`${baseUrl}/api/dataValueSets`, payload, auth);
observation.status("synced", "XYZ001-MAL_POS-202405");
} catch (err: any) {
if (err.response?.status === 400) {
observation.status("failed", err.message);
} else {
observation.status("error", err.message);
}
}
});
context.status("connected");
}
π Example: Custom Surveillance APIβ
import axios from "axios";
export async function start(context) {
const { baseUrl, token } = context.connection.system.config;
context.on("DiagnosticReport", async report => {
try {
const { data } = await axios.post(`${baseUrl}/api/results`, {
patientId: report.subject?.reference,
test: report.code?.text,
result: report.result,
issued: report.issued
}, {
headers: { Authorization: `Bearer ${token}` }
});
report.status("synced", data.id ?? `surv-${Date.now()}`);
} catch (err: any) {
if (err.response?.status === 422) {
report.status("failed", err.message);
} else {
report.status("error", err.message);
}
}
});
context.status("connected");
}
π Handling Authβ
Supported authMethod
values include:
"none"
"basic"
"token"
"custom"
(useconfigFields
manually)
Automation doesnβt enforce auth. Your plugin uses the values directly.
π¦ Understanding .status(...)
β
Every received resource includes a .status()
method:
βοΈ synced
β
Used when delivery is successful. Requires a secondaryId
:
resource.status("synced", "external-uuid-123");
β failed
β
Use this for unrecoverable issues β bad config, missing fields, 400 errors. Requires a human-readable error message:
resource.status("failed", "Missing patient ID");
Automation will not retry.
β οΈ error
β
Use for temporary issues β timeouts, 5xx errors, etc. This tells Automation to retry later.
resource.status("error", "DHIS2 server unavailable");
Automation tracks this and will try again automatically.
β Recapβ
You Write | Automation Handles |
---|---|
context.on("X", ...) | Delivers matched resources |
resource.status(...) | Tracks sync outcome and retries |
context.status(...) | Monitors connection state |
Status | Tracked in UI | Retries? | Required info |
---|---|---|---|
synced | β | β | secondaryId |
failed | β | β | Error message |
error | β | β | Retryable error text |