Emit exactly one close, and read the socket through a PduTransport

Ending a session while the link was down emitted nothing: the retried
drop had already torn it down, so close() found nothing left to do. The
terminal event is now guarded by its own flag rather than by `closed`.

The socket, the framer and the parse move to PduTransport, which is what
takes session.ts back under its line cap; `session.sock` reads through a
getter. The backoff also refuses an inverted pair and an unknown key.
This commit is contained in:
2026-08-31 21:53:11 +02:00
parent 880454b4f4
commit b2d121b4f3
7 changed files with 179 additions and 85 deletions
+16 -5
View File
@@ -143,6 +143,8 @@ function checkLimits(limits: [string, number, number][]): VoidResult {
return {};
}
const backoffDelays: readonly string[] = ['maxDelay', 'minDelay'];
function checkReconnect(reconnect: unknown): VoidResult {
if (reconnect === undefined || reconnect === false) return {};
@@ -150,11 +152,20 @@ function checkReconnect(reconnect: unknown): VoidResult {
return { err: new Error('reconnect takes { maxDelay, minDelay }, or false to turn it off') };
}
// A minDelay of 0 never doubles, so the backoff never starts and every retry lands at once.
return checkLimits([
['maxDelay', delayOr(reconnect.maxDelay, defaults.maxDelay), 1],
['minDelay', delayOr(reconnect.minDelay, defaults.minDelay), 1],
]);
for (const key of Object.keys(reconnect)) {
if (!backoffDelays.includes(key)) {
return { err: new Error(`reconnect has no ${key}, name ${backoffDelays.join(' or ')}`) };
}
}
const maxDelay = delayOr(reconnect.maxDelay, defaults.maxDelay);
const minDelay = delayOr(reconnect.minDelay, defaults.minDelay);
// A delay of 0 never doubles, so the backoff never starts and every retry lands at once.
const checked = checkLimits([['maxDelay', maxDelay, 1], ['minDelay', minDelay, 1]]);
if (checked.err || maxDelay >= minDelay) return checked;
return { err: new Error(`maxDelay must be minDelay or more, got ${String(maxDelay)}`) };
}
function isRecord(value: unknown): value is Record<string, unknown> {