@cosyte/mllp 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -2007,8 +2007,8 @@ var Correlator = class {
2007
2007
  * removed from live store. Caller calls `entry.resolve(ackPayload)`.
2008
2008
  * - controlId: keyed lookup by `controlIdFromAck`. Live-store hit returns
2009
2009
  * the entry; graveyard hit fires `MLLP_ACK_AFTER_TIMEOUT` warning
2010
- * and returns `null`; otherwise fires
2011
- * `onUnmatchedAck(controlIdFromAck)` and returns `null`.
2010
+ * and returns `null`; otherwise fires `onUnmatchedAck` with the id's
2011
+ * **byte length** and returns `null`.
2012
2012
  *
2013
2013
  * Triggers lazy graveyard eviction.
2014
2014
  *
@@ -2031,7 +2031,7 @@ var Correlator = class {
2031
2031
  }
2032
2032
  if (controlIdFromAck === null) {
2033
2033
  if (this._opts.onUnmatchedAck !== void 0) {
2034
- this._opts.onUnmatchedAck("");
2034
+ this._opts.onUnmatchedAck(null);
2035
2035
  }
2036
2036
  return null;
2037
2037
  }
@@ -2046,7 +2046,9 @@ var Correlator = class {
2046
2046
  if (grave !== void 0) {
2047
2047
  const elapsedSinceSendMs = this._opts.now() - grave.timedOutAt;
2048
2048
  this._opts.onWarning("MLLP_ACK_AFTER_TIMEOUT", {
2049
- controlId: grave.controlId,
2049
+ // The LENGTH, never the id. Control IDs are decoded `latin1`, a 1:1
2050
+ // byte to code-unit map, so `.length` is a byte count.
2051
+ controlIdBytes: grave.controlId === null ? null : grave.controlId.length,
2050
2052
  elapsedSinceSendMs,
2051
2053
  byteOffset: byteOffsetFromAck
2052
2054
  });
@@ -2054,7 +2056,7 @@ var Correlator = class {
2054
2056
  return null;
2055
2057
  }
2056
2058
  if (this._opts.onUnmatchedAck !== void 0) {
2057
- this._opts.onUnmatchedAck(controlIdFromAck);
2059
+ this._opts.onUnmatchedAck(controlIdFromAck.length);
2058
2060
  }
2059
2061
  return null;
2060
2062
  }
@@ -2129,11 +2131,32 @@ var Correlator = class {
2129
2131
  }
2130
2132
  };
2131
2133
 
2134
+ // src/client/ack-diagnostics.ts
2135
+ var ACK_DIAGNOSTIC_MESSAGES = Object.freeze({
2136
+ MLLP_ACK_UNMATCHED_CONTROL_ID: "Inbound ACK control ID matched no in-flight send and no timed-out send; the ACK was dropped. Field values are withheld: MSA-2 is inbound payload content and this diagnostic goes to a log. The inbound bytes are on the 'message' event; controlIdBytes gives the length.",
2137
+ MLLP_ACK_AFTER_TIMEOUT: "ACK arrived after its send had already timed out; the ACK was dropped. Field values are withheld: a control ID is payload content and this diagnostic goes to a log. The outbound bytes are the payload you passed to send(); controlIdBytes gives the length."
2138
+ });
2139
+ function ackDiagnosticMessage(code) {
2140
+ return ACK_DIAGNOSTIC_MESSAGES[code];
2141
+ }
2142
+
2132
2143
  // src/client/error.ts
2133
2144
  var MllpTimeoutError = class _MllpTimeoutError extends Error {
2134
2145
  name = "MllpTimeoutError";
2135
- /** MSH-10 control ID of the timed-out send (FIFO mode: `undefined`). */
2136
- messageControlId;
2146
+ /**
2147
+ * Byte length of the timed-out send's MSH-10 control ID, or `undefined` when
2148
+ * there was none to read (FIFO mode, or a payload with no MSH-10).
2149
+ *
2150
+ * **The control ID itself is deliberately not here.** An `Error` is a
2151
+ * diagnostic surface: it is logged, and its `stack` is what an error reporter
2152
+ * ships off the box. MSH-10 is payload content, and a scanner that returns
2153
+ * the wrong field returns payload content of some other kind, which is how a
2154
+ * patient identifier reaches a log line. Nothing is lost by withholding it,
2155
+ * because this error rejects the very `send()` whose payload the caller
2156
+ * passed in, so the caller already holds the bytes. Control IDs are decoded
2157
+ * `latin1`, a 1:1 byte to code-unit map, so this count is a byte count.
2158
+ */
2159
+ messageControlIdBytes;
2137
2160
  /** Milliseconds elapsed between write-flush and timeout fire. */
2138
2161
  elapsedMs;
2139
2162
  /** Epoch ms timestamp recorded at write-flush callback. */
@@ -2141,12 +2164,12 @@ var MllpTimeoutError = class _MllpTimeoutError extends Error {
2141
2164
  /**
2142
2165
  * Construct an MLLP timeout error.
2143
2166
  *
2144
- * @param message - Human-readable error message.
2145
- * @param opts - Timeout context (originating message control id, elapsed time, flush timestamp).
2167
+ * @param message - Human-readable error message. Structural facts only, never field content.
2168
+ * @param opts - Timeout context (control-id byte length, elapsed time, flush timestamp).
2146
2169
  */
2147
2170
  constructor(message, opts) {
2148
2171
  super(message);
2149
- this.messageControlId = opts.messageControlId;
2172
+ this.messageControlIdBytes = opts.messageControlIdBytes;
2150
2173
  this.elapsedMs = opts.elapsedMs;
2151
2174
  this.sentAt = opts.sentAt;
2152
2175
  if (Error.captureStackTrace) {
@@ -2589,31 +2612,34 @@ var MllpClient = class extends events.EventEmitter {
2589
2612
  maxInFlight: this._pipeline ? Number.POSITIVE_INFINITY : 1,
2590
2613
  onWarning: (code, ctx) => {
2591
2614
  this._aggregatedWarningsByCode[code] = (this._aggregatedWarningsByCode[code] ?? 0) + 1;
2592
- this._emitContained(
2593
- "warning",
2594
- Object.freeze({
2595
- code,
2596
- byteOffset: ctx.byteOffset,
2597
- message: `${code}: controlId=${ctx.controlId} elapsed=${ctx.elapsedSinceSendMs}ms`,
2598
- connectionId: this._connection?.connectionId ?? conn.connectionId,
2599
- timestamp: /* @__PURE__ */ new Date()
2600
- })
2601
- );
2615
+ const warning = Object.freeze({
2616
+ code,
2617
+ byteOffset: ctx.byteOffset,
2618
+ message: ackDiagnosticMessage(code),
2619
+ controlIdBytes: ctx.controlIdBytes,
2620
+ elapsedSinceSendMs: ctx.elapsedSinceSendMs,
2621
+ connectionId: this._connection?.connectionId ?? conn.connectionId,
2622
+ timestamp: /* @__PURE__ */ new Date()
2623
+ });
2624
+ this._emitContained("warning", warning);
2602
2625
  },
2603
- onUnmatchedAck: (controlId) => {
2626
+ onUnmatchedAck: (controlIdBytes) => {
2604
2627
  if (this.listenerCount("error") === 0) return;
2605
2628
  const err = new MllpFramingError(
2606
2629
  "MLLP_ACK_UNMATCHED_CONTROL_ID",
2607
2630
  0,
2608
2631
  Buffer.alloc(0),
2609
- `Unmatched ACK control ID${controlId === "" ? "" : `: ${controlId}`}`
2632
+ ackDiagnosticMessage("MLLP_ACK_UNMATCHED_CONTROL_ID")
2610
2633
  );
2611
2634
  safeEmitError(
2612
2635
  this,
2613
2636
  Object.freeze({
2614
2637
  connectionId: this._connection?.connectionId ?? conn.connectionId,
2615
2638
  error: err,
2616
- controlId
2639
+ // The peer's MSA-2 byte LENGTH. The bytes themselves used to be
2640
+ // here and on the message above; a peer sending a one-megabyte
2641
+ // MSA-2 produced a one-megabyte Error.message, straight into a log.
2642
+ controlIdBytes
2617
2643
  })
2618
2644
  );
2619
2645
  },
@@ -2621,7 +2647,7 @@ var MllpClient = class extends events.EventEmitter {
2621
2647
  this._timedOutTotal += 1;
2622
2648
  entry.reject(
2623
2649
  new MllpTimeoutError(`ACK timeout after ${elapsedMs}ms`, {
2624
- messageControlId: entry.controlId ?? void 0,
2650
+ messageControlIdBytes: entry.controlId?.length,
2625
2651
  elapsedMs,
2626
2652
  sentAt: entry.sentAt ?? 0
2627
2653
  })
@@ -3174,7 +3200,7 @@ var MllpClient = class extends events.EventEmitter {
3174
3200
  cleanup();
3175
3201
  reject(
3176
3202
  new MllpTimeoutError(`waiting for drain timed out after ${ackTimeoutMs}ms`, {
3177
- messageControlId: void 0,
3203
+ messageControlIdBytes: void 0,
3178
3204
  elapsedMs: ackTimeoutMs,
3179
3205
  sentAt: Date.now()
3180
3206
  })
@@ -3412,7 +3438,7 @@ async function createStarterClient(opts) {
3412
3438
  }
3413
3439
 
3414
3440
  // src/index.ts
3415
- var VERSION = "0.0.4";
3441
+ var VERSION = "0.0.5";
3416
3442
 
3417
3443
  exports.Connection = Connection;
3418
3444
  exports.FrameReader = FrameReader;
@@ -3428,6 +3454,7 @@ exports.MllpTimeoutError = MllpTimeoutError;
3428
3454
  exports.NetTransport = NetTransport;
3429
3455
  exports.TlsTransport = TlsTransport;
3430
3456
  exports.VERSION = VERSION;
3457
+ exports.ackDiagnosticMessage = ackDiagnosticMessage;
3431
3458
  exports.buildRawAck = buildRawAck;
3432
3459
  exports.createClient = createClient;
3433
3460
  exports.createServer = createServer;