@mcal/core-node-sdk
v0.0.0
Published
Production-grade SDK for consuming MCAL third-party outputs in Node.js.
Keywords
Readme
@mcal/core-node-sdk
Production-grade SDK for consuming MCAL third-party outputs in Node.js.
This SDK is built for engineering teams integrating event delivery through HTTP webhooks and MQTT over mutual TLS. It provides a consistent, secure, and operationally friendly integration surface for both models.
Introduction
@mcal/core-node-sdk standardizes how external systems consume MCAL outputs. Instead of dealing with transport-level details in every project, teams can use one SDK API for webhook validation, MQTT connection handling, and lifecycle events.
The same integration principles will be reused across SDKs in other languages (for example Java), so integration behavior remains predictable across ecosystems.
Installation
Install from npm:
npm install @mcal/core-node-sdkInstall from a local tarball:
npm install /absolute/path/core-node-sdk.tgzDelivery Channels
MCAL supports two transport channels:
- HTTP Webhook for server-to-server push
- MQTT over mTLS for topic-based event streaming
You can implement either transport independently, or both together.
HTTP Integration
The HTTP module is designed to verify webhook authenticity before your business logic executes.
Important behavior
Any non-2xx response from your webhook endpoint is treated as a failed relay by MCAL.
Initialize
const {SDKNodeIntegrations} = require('@mcal/core-node-sdk');
const sdk = new SDKNodeIntegrations();
const http = sdk.initialize.http({
webhookKey: 'wsc_...'
});Validate incoming requests
// Option A: explicit payload
const result = http.validate({
headers: req.headers,
body: req.body
});
// Option B: request object directly if shape is compatible
// const result = http.validate(req);
if (!result.ok) {
return res.status(401).json({error: 'invalid webhook signature'});
}
handleEvent(result.body);
return res.status(200).end();If you prefer fail-fast behavior, use http.assert(...) instead of http.validate(...). It throws when validation fails.
Security model
MCAL sends the per-channel webhook secret in the header:
x-mcal-webhook-key
The SDK validates this value using timing-safe comparison. Failed validation must be treated as unauthorized traffic.
MQTT Integration
The MQTT module is certificate-based and AWS IoT compatible.
Initialize
const session = await sdk.initialize.mqtt({
endpoint: 'provided in integration settings',
topic: 'provided in integration settings',
caPath: '/path/to/AmazonRootCA1.pem',
certPath: '/path/to/certificate.pem.crt',
keyPath: '/path/to/private.pem.key',
qos: 1
});Returned session:
clientId: effective MQTT client id used by the connectiontopics: topics subscribed by the SDKdisconnect(): graceful disconnect helper
Event listeners
sdk.on('mqtt:connect', () => console.log('[MQTT] connected'));
sdk.on('mqtt:message', (msg) => {
console.log('[MQTT] topic:', msg.topic);
console.log('[MQTT] payload:', msg.text);
});
sdk.on('mqtt:error', (err) => console.error('[MQTT] error:', err));MQTT event map
mqtt:connect
Fired when the MQTT client establishes a connection.mqtt:reconnect
Fired when the client starts a reconnect attempt after an interruption.mqtt:subscribed
Fired after topic subscription succeeds. Payload:{ topics: string[], qos: 0 | 1 }mqtt:message
Fired when a message is received on a subscribed topic. Payload:{ topic: string, payload: Buffer, text: string }mqtt:error
Fired on MQTT client errors. Payload is typically anError.mqtt:close
Fired when the MQTT connection closes.mqtt:disconnect
Fired when disconnection is explicitly triggered via SDK shutdown (disconnect()ordispose()).
Operational Recommendations
For production environments, keep webhook keys and certificate files in a secure secret manager, not in source control. Rotate credentials according to your policy and monitor integration logs with structured logging.
Webhook and MQTT consumers should be idempotent. Event-driven systems can deliver duplicates under retry/recovery scenarios.
Graceful shutdown
const shutdown = async () => {
await sdk.dispose();
process.exit(0);
};
process.on('SIGINT', shutdown);
process.on('SIGTERM', shutdown);