better-smpp
Core

Connection layer

SmppConnection — the shared transport session under client and server.

SmppConnection wraps a connected socket (net.Socket or tls.TLSSocket) with everything SMPP needs above TCP. SmppClient and SmppServerSession are built on it; use it directly for proxies and custom roles.

import net from "node:net";
import { SmppConnection } from "@better-smpp/core";

const socket = net.connect(2775, "smsc.example.com");
await new Promise((resolve) => socket.once("connect", resolve));

const connection = new SmppConnection(socket, {
  requestTimeoutMs: 30_000,
  windowSize: 10,
  enquireLink: { intervalMs: 30_000 },
});

What it does

  • Framing — accumulates socket data, extracts complete PDUs (partial frames across reads and multiple frames per read both handled), decodes them through the codec.
  • Sequence numbers — auto-assigned, wrapping at 0x7FFFFFFF; caller-provided sequence numbers are respected (proxy use).
  • Correlationrequest() returns a Promise resolved by the matching response's sequence number, regardless of response order.
  • Keepalive — optional enquire_link timer with dead-link detection; inbound pings are answered automatically.
  • Hygiene — unknown commands get generic_nack (ESME_RINVCMDID); malformed bodies are nacked with the right status without killing the stream; an invalid frame header (the stream itself is corrupt) destroys the connection.

Requests and responses

// Request/response with timeout + cancellation:
const resp = await connection.request(
  { command: "submit_sm", destinationAddr: "…", shortMessage: "hi" },
  { timeoutMs: 5_000, signal: controller.signal },
);

// Answer an inbound request:
connection.on("deliver_sm", (pdu) => {
  void connection.sendResponse(pdu, { messageId: "" });
});

// Fire-and-forget (responses, outbind, alert_notification):
await connection.send({ command: "alert_notification", /* … */ });

request() rejects with SmppCommandError (non-zero status or generic_nack), SmppTimeoutError, SmppAbortError, or SmppClosedError — see Errors.

Events

Typed per-command events (deliver_sm, submit_sm, …) plus pdu (everything), unknownPdu, send, stateChange, error, close.

Flow control

  • windowSize / windowQueueLimit bound outstanding requests (enquire_link bypasses the window).
  • pause() / resume() hold inbound dispatch — this is what the server uses while the bind hook authenticates.
  • pendingCount reports awaiting responses.

State

The connection tracks sessionState (OPENBOUND_*UNBOUND/CLOSED) but does not enforce it — the client/server layers own transitions via setState(). Helpers canTransmit, canReceive and isBound are exported for your own checks.

On this page