tabletcommand-backend-heartbeat
v3.3.0
Published
Tablet Command Heartbeat
Readme
tabletcommand-backend-heartbeat
A shared library for logging and retrieving heartbeat events from CAD system integrations. It is not a server — consuming backend services import it, inject a Redis client, and call its functions.
How it works
Consuming service (HTTP handler / queue consumer)
└─ calls log() or logInterfaceVersion()
└─ domain.ts: calculates delay, builds StoredHeartbeat
└─ store.ts: LPUSH to Redis list (capped at 25 items via LTRIM)Usage
import indexModule from "tabletcommand-backend-heartbeat";
const heartbeat = indexModule({ client: redisClient });
// Record a heartbeat from an incoming CAD message
await heartbeat.log(department, message, "incident");
// Record the CAD interface version
await heartbeat.logInterfaceVersion(department, message, "incident");
// Read back heartbeat state for a department
const state = await heartbeat.checkDepartment(department);
// state: { incident: EnhancedHeartbeat[], status: EnhancedHeartbeat[], location: EnhancedHeartbeat[], version: string }Public API
| Function | Description |
|---|---|
| log(department?, message?, type?) | Record a heartbeat event |
| conditionalLog(shouldLog, department?, message?, type?) | Conditionally record |
| logInterfaceVersion(department, message, type) | Record CAD interface version string |
| checkDepartment(dept) | Read heartbeat state for one department |
| checkDepartments(depts) | Read heartbeat state for multiple departments |
| defaultMessage(atDate?) | Create a blank HeartbeatMessage |
type is one of "incident", "status", or "location".
Input message types
HeartbeatMessage — periodic health check from a CAD interface:
{
Time: string; // ISO datetime of the heartbeat
Status: string; // e.g. "OK", "Green"
Message: string; // Human-readable description
Interface?: string; // Version string, e.g. "Interface_Two_Way 1.7.5"
}IncidentMessage — data push from a CAD system:
{
IncidentNumber: string;
EntryDateTime?: string;
ClosedDateTime?: string;
Interface?: string;
Unit?: Array<{
TimeDispatched?: string; TimeEnroute?: string; TimeArrived?: string;
TimeCleared?: string; TimeAtHospital?: string; TimePatient?: string;
TimeStaged?: string; TimeTransport?: string; TimeTransporting?: string;
}>;
Comment?: Array<{ CommentDateTime?: string }>;
}Timestamp resolution order (highest valid timestamp wins):
Time → EntryDateTime → ClosedDateTime → unit timestamps → CommentDateTime → fallback (-7200, marked invalid)
Redis schema
No MongoDB is used. All state lives in Redis.
Heartbeat lists — hb:{t}:{departmentId}
| Key | Type description |
|---|---|
| hb:i:{departmentId} | Incident heartbeats |
| hb:s:{departmentId} | Status heartbeats |
| hb:l:{departmentId} | Location heartbeats |
Redis type: List. Max 25 entries per key (enforced via LTRIM on every write). Each entry is a JSON-serialised StoredHeartbeat:
{
"RcvTime": 1693355267,
"Delay": 33,
"H": 1,
"src": "hb",
"v": true
}| Field | Description |
|---|---|
| RcvTime | Unix timestamp (seconds) when the message was received |
| Delay | Seconds between the message's own timestamp and receive time |
| H | 1 = heartbeat message, 0 = incident message |
| src | Source tag, e.g. "hb", "FC-1234-entry", "FC-1234-commentDate" |
| v | true if the resolved timestamp was valid |
Interface version — cad:v:{departmentId}
Redis type: String. Stores the cleaned CAD interface version extracted from Interface field, e.g. "Interface_Two_Way 1.7.5".
Development
npm run build # compile TypeScript
npm run lint # ESLint
npm run test # node:test suite