Say undefined where the SMSC named no id for a segment it took (#101)

* Cover the ids a send gets back where the SMSC named only some of them

* Say undefined where the SMSC named no id for a segment it took

* Record why the merger takes the wider type, and de-duplicate the interop narrowing

* Guard the numbering hole the merger must refuse, and correct the phase record
This commit is contained in:
2026-09-12 22:37:55 +02:00
committed by GitHub
parent ca1a7473ed
commit 13e3ff8f1f
12 changed files with 121 additions and 34 deletions
+3 -3
View File
@@ -37,12 +37,12 @@ const severity: Record<MessageState, number> = {
};
/** The base and the part numbers one send's ids carry, or nothing when they do not spell out one message. */
function idNumbering(smsIds: string[]): { base: string; parts: Set<number> } | undefined {
function idNumbering(smsIds: (string | undefined)[]): { base: string; parts: Set<number> } | undefined {
const bases = new Set<string>();
const parts = new Set<number>();
for (const smsId of smsIds) {
const numbering = parseSegmentId(smsId);
const numbering = smsId === undefined ? undefined : parseSegmentId(smsId);
if (!numbering) return undefined;
@@ -93,7 +93,7 @@ export class DlrMerger {
}
/** Registers the ids one multipart send got back, so their receipts can be merged. */
expect(smsIds: string[]): void {
expect(smsIds: (string | undefined)[]): void {
if (smsIds.length < 2) return;
const numbering = idNumbering(smsIds);
+11 -3
View File
@@ -45,7 +45,8 @@ export type SendSmsInput =
export type SendSmsResult = {
err?: Error;
pduObjs: PduObject[];
smsIds: string[];
/** Positional with `pduObjs`, and undefined where the SMSC took the segment and named no id. */
smsIds: (string | undefined)[];
/** Segments that went out unanswered. The peer may have taken them, so sending again may duplicate. */
unanswered: number;
};
@@ -248,12 +249,19 @@ function checkSegments(allowed: number, segments: number): Error | undefined {
return undefined;
}
/** An absent message_id and one a peer wrote empty are the same octets, and neither names an id. */
function acceptedId(pduObj: PduObject, notation: SmsIdNotation | undefined): string | undefined {
const smsId = normaliseSmsId(paramText(pduObj.params.message_id), notation);
return smsId === '' ? undefined : smsId;
}
function collectSent(
sent: Result<{ pduObj: PduObject }>[],
notation: SmsIdNotation | undefined,
): SendSmsResult {
const pduObjs: PduObject[] = [];
const smsIds: string[] = [];
const smsIds: (string | undefined)[] = [];
let failure: Error | undefined;
let unanswered = 0;
@@ -264,7 +272,7 @@ function collectSent(
failure ??= one.err;
} else if (one.pduObj.cmdStatus === 'ESME_ROK') {
pduObjs.push(one.pduObj);
smsIds.push(normaliseSmsId(paramText(one.pduObj.params.message_id), notation));
smsIds.push(acceptedId(one.pduObj, notation));
} else {
const refusal = one.pduObj.cmdStatus ?? String(one.pduObj.cmdStatusId);