This is the client SDK for EnSync engine - a high-performance message-driven integration engine that enables you to integrate with third-party apps as though they were native to your system and in realtime.
See Documentation on EnSync Engine.
See Documentation on Our SDKs.
npm install ensync-client-sdk// CommonJS
const { EnSyncEngine } = require("ensync-client-sdk");
// ES Modules
import { EnSyncEngine } from "ensync-client-sdk";The main class that manages connections and client creation for the EnSync system.
const engine = new EnSyncEngine(url, options);url(string): The URL of the EnSync serveroptions(object, optional):disableTls(boolean): Set to true to disable TLS (default: false)reconnectInterval(number): Reconnection interval in ms (default: 5000)maxReconnectAttempts(number): Maximum reconnection attempts (default: 10)enableLogging(boolean): Enable/disable SDK console logs (default: false)
error: Emitted when an error occursconnect: Emitted when connection is establisheddisconnect: Emitted when connection is closed
- Initialize the engine with your server URL
- Create a client with your app key
const engine = new EnSyncEngine("grpcs://node.gms.ensync.cloud");
const client = await engine.createClient("your-app-key");appKey(string): Your EnSync application key (formerly accessKey)options(object, optional):appSecretKey(string): Application secret key for enhanced securityclientId(string): Custom client ID (default: auto-generated UUID)
Returns a new EnSyncClient instance
await client.publish(
"orders/created", // Message name
["recipient-public-key"], // Recipients
{ orderId: "123", amount: 99.99 }, // Message payload (JSON)
{ persist: true } // Metadata
);messageName(string): Name of the message to publishrecipients(array): Array of recipient public keys (base64)payload(object): Message data payload (must be valid JSON)options(object, optional):appSecretKey(string): Application secret keyttl(number): Time-to-live in seconds (default: 3600)
const subscription = await client.subscribe(messageName, options);messageName(string): Name of the message to subscribe tooptions(object, optional):appSecretKey(string): Application secret keyautoAck(boolean): Automatically acknowledge events (default: true)fromTimestamp(number): Subscribe from specific timestamp
Returns a subscription object with the following methods:
{
on: (callback: (message: EnSyncMessage) => Promise<void>) => void;
ack: (messageIdem: string, block: string) => Promise<string>;
defer: (messageIdem: string, delayMs: number, reason: string) => Promise<object>;
discard: (messageIdem: string, reason: string) => Promise<object>;
replay: (messageIdem: string) => Promise<object>;
pause: (reason: string) => Promise<object>;
resume: () => Promise<object>;
unsubscribe: () => Promise<void>;
}{
messageName: "orders/created", // Message name
idem: "msg-123", // Unique message ID
block: "456", // Block ID for acknowledgment
timestamp: 1634567890123, // Message timestamp
payload: { /* your data */ }, // Decrypted JSON payload
metadata: { /* metadata */ }, // Message metadata
sender: "base64-public-key" // Sender's public key
}await client.destroy(stopEngine);stopEngine(boolean, optional): If true, also closes the underlying engine connection. Set to false to keep the engine running for other clients. (default: false)
The SDK throws EnSyncError for various error conditions. Always wrap your code in try-catch blocks to handle potential errors gracefully.
try {
// Your EnSync code
} catch (e) {
if (e instanceof EnSyncError) {
console.error("EnSync Error:", e.message);
// Handle specific error types
if (e.name === "EnSyncConnectionError") {
// Handle connection errors
} else if (e.name === "EnSyncPublishError") {
// Handle publishing errors
} else if (e.name === "EnSyncSubscriptionError") {
// Handle subscription errors
}
} else {
console.error("Unexpected error:", e);
}
}Common error types:
EnSyncConnectionError: Connection or authentication issuesEnSyncPublishError: Problems publishing eventsEnSyncSubscriptionError: Subscription-related errorsEnSyncGenericError: Other errors
const { EnSyncEngine } = require("ensync-client-sdk");
const response = async () => {
try {
const messageName = "yourcompany/payment/POS/PAYMENT_SUCCESSFUL";
const engine = new EnSyncEngine("grpc://localhost:50051");
const client = await engine.createClient(appKey, {
appSecretKey: secretKey
});
// Payload must be valid JSON
await client.publish(
messageName,
[recipientPublicKey],
{
transactionId: "123",
amount: 100,
terminal: "pos-1",
timestamp: Date.now(),
},
{ persist: true }
);
await client.destroy();
} catch (e) {
console.error("Error:", e?.message);
}
};const { EnSyncEngine } = require("ensync-client-sdk");
const response = async () => {
try {
const messageName = "yourcompany/payment/POS/PAYMENT_SUCCESSFUL";
const engine = new EnSyncEngine("grpc://localhost:50051");
const client = await engine.createClient(appKey, {
appSecretKey: secretKey
});
const subscription = await client.subscribe(messageName);
subscription.on(async (message) => {
try {
// message is an EnSyncMessage
console.log("Message Name:", message.messageName);
console.log("Message ID:", message.idem);
console.log("Message Block:", message.block);
console.log("Message Payload:", message.payload); // Decrypted JSON payload
console.log("Message Timestamp:", message.timestamp);
await subscription.ack(message.idem, message.block);
await subscription.unsubscribe();
} catch (e) {
console.error("Processing error:", e);
}
});
} catch (e) {
console.error("Error:", e?.message);
}
};- Store connection credentials securely using environment variables
- Implement proper reconnection logic for production environments
- Always close connections when they're no longer needed
// Using environment variables for sensitive keys
require("dotenv").config();
const engine = new EnSyncEngine(process.env.ENSYNC_URL);
const client = await engine.createClient(process.env.ENSYNC_APP_KEY, {
appSecretKey: process.env.APP_SECRET_KEY
});
// Implement proper error handling and reconnection
engine.on("disconnect", () => {
console.log("Connection lost, will reconnect automatically");
});
// Close connections when done
process.on("SIGINT", async () => {
await client.destroy(true);
process.exit(0);
});- Use hierarchical message names (e.g.,
domain/entity/action) - Keep payloads concise and well-structured as valid JSON
- Consider versioning your message schemas
- Use JSON schema validation for critical messages
// Good message naming pattern
await client.publish(
"inventory/product/created",
[recipientPublicKey],
{
productId: "prod-123",
name: "Ergonomic Chair",
sku: "ERG-CH-BLK",
price: 299.99,
createdAt: Date.now(),
},
{ persist: true },
{
schema: {
productId: "string",
name: "string",
sku: "string",
price: "double",
createdAt: "long"
}
}
);- Never hardcode app keys or secret keys
- Use environment variables or secure key management solutions
- All messages are end-to-end encrypted using Ed25519
- Hybrid encryption (AES + Ed25519) is used automatically for multi-recipient messages
- Use
appSecretKeyfor message decryption
- Batch messages when possible instead of sending many small messages
- Hybrid encryption is enabled by default for multi-recipient messages (improves performance 2-5x)
- Consider message size and frequency in high-volume scenarios
- Use message persistence (
persist: true) for critical messages - Implement proper error handling and retry logic with defer/replay