Message utilities
Splitting, reassembly, and delivery-receipt parsing as standalone tools.
The client wires these in automatically; they're exported for server-side use, proxies, and anything custom.
splitMessage
Splits text into transmission-ready segments — encoding-aware (GSM escape pairs and UTF-16 surrogate pairs are never cut), with concat UDHs or SAR TLV values:
import { splitMessage } from "@better-smpp/core";
const split = splitMessage("a very long message…".repeat(30));
split.encoding; // "ASCII"
split.dataCoding; // 1
split.reference; // shared concat reference
split.segments; // [{ text, udh: <Buffer 05 00 03 ref total seq> }, …]
// SAR TLVs instead of UDH:
splitMessage(text, { method: "sar" });
// segments: [{ text, sar: { sarMsgRefNum, sarTotalSegments, sarSegmentSeqnum } }, …]
// 16-bit references, forced encoding, fixed reference:
splitMessage(text, { wideRef: true, encoding: "UCS2", reference: 0x1234 });Short text returns a single bare segment — safe to call unconditionally.
MessageReassembler
The inverse: feed it every inbound deliver_sm (or submit_sm on the server) and it
returns the complete message once all segments arrived. Handles 8-bit and 16-bit
concat UDHs and SAR TLVs, out-of-order and interleaved segments:
import { MessageReassembler } from "@better-smpp/core";
const reassembler = new MessageReassembler({ timeoutMs: 60_000 });
connection.on("deliver_sm", (pdu) => {
const message = reassembler.add(pdu);
if (!message) return; // waiting for more segments
message.message; // full text (or Buffer for binary)
message.parts; // segment count
message.reference; // concat reference (absent for singles)
message.pdus; // underlying PDUs in sequence order
});Stalled partial messages are evicted after timeoutMs (default 60 s);
reassembler.pendingCount reports how many are in flight.
parseDeliveryReceipt
Turns receipt deliver_sm PDUs into typed objects. Understands the appendix-B text
format and the receiptedMessageId / messageState TLVs (TLVs win):
import { parseDeliveryReceipt, isDeliveryReceipt } from "@better-smpp/core";
const receipt = parseDeliveryReceipt(pdu);
// undefined when the PDU isn't a receipt at all
if (receipt) {
receipt.messageId; // "abc123"
receipt.state; // "DELIVRD"
receipt.messageState; // 2 (MESSAGE_STATE.DELIVERED)
receipt.submitted; // 1
receipt.delivered; // 1
receipt.submitDate; // Date (UTC)
receipt.doneDate; // Date (UTC)
receipt.error; // "000"
receipt.text; // first chars of the original message
receipt.raw; // unparsed source text
}A PDU counts as a receipt when its esmClass has the receipt bits
(MC_DELIVERY_RECEIPT, DELIVERY_ACKNOWLEDGEMENT, INTERMEDIATE_DELIVERY) or when
receipt TLVs are present — isDeliveryReceipt(pdu) exposes the check.