@glion/mllp-client 0.16.0 → 0.19.0
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/README.md +370 -195
- package/dist/assertions.d.ts +10 -0
- package/dist/assertions.d.ts.map +1 -0
- package/dist/client.d.ts +108 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/constants.d.ts +23 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/errors/base.d.ts +31 -0
- package/dist/errors/base.d.ts.map +1 -0
- package/dist/errors/index.d.ts +15 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/mllp-already-sending-error.d.ts +14 -0
- package/dist/errors/mllp-already-sending-error.d.ts.map +1 -0
- package/dist/errors/mllp-client-closed-error.d.ts +13 -0
- package/dist/errors/mllp-client-closed-error.d.ts.map +1 -0
- package/dist/errors/mllp-connection-error.d.ts +9 -0
- package/dist/errors/mllp-connection-error.d.ts.map +1 -0
- package/dist/errors/mllp-connection-failed-error.d.ts +12 -0
- package/dist/errors/mllp-connection-failed-error.d.ts.map +1 -0
- package/dist/errors/mllp-connection-lost-error.d.ts +13 -0
- package/dist/errors/mllp-connection-lost-error.d.ts.map +1 -0
- package/dist/errors/mllp-connection-timeout-error.d.ts +13 -0
- package/dist/errors/mllp-connection-timeout-error.d.ts.map +1 -0
- package/dist/errors/mllp-invalid-message-error.d.ts +13 -0
- package/dist/errors/mllp-invalid-message-error.d.ts.map +1 -0
- package/dist/errors/mllp-invalid-option-error.d.ts +8 -0
- package/dist/errors/mllp-invalid-option-error.d.ts.map +1 -0
- package/dist/errors/mllp-invalid-response-error.d.ts +16 -0
- package/dist/errors/mllp-invalid-response-error.d.ts.map +1 -0
- package/dist/errors/mllp-send-aborted-error.d.ts +12 -0
- package/dist/errors/mllp-send-aborted-error.d.ts.map +1 -0
- package/dist/errors/mllp-send-timeout-error.d.ts +13 -0
- package/dist/errors/mllp-send-timeout-error.d.ts.map +1 -0
- package/dist/errors/nak-exception.d.ts +17 -0
- package/dist/errors/nak-exception.d.ts.map +1 -0
- package/dist/events.d.ts +35 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/index.d.ts +13 -20
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +805 -3
- package/dist/index.js.map +1 -0
- package/dist/messages.d.ts +55 -0
- package/dist/messages.d.ts.map +1 -0
- package/dist/reconnect.d.ts +18 -0
- package/dist/reconnect.d.ts.map +1 -0
- package/dist/runtime/node.d.ts +39 -0
- package/dist/runtime/node.d.ts.map +1 -0
- package/dist/runtime/node.js +100 -0
- package/dist/runtime/node.js.map +1 -0
- package/dist/session.d.ts +63 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/state.d.ts +39 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/types.d.ts +109 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils.d.ts +9 -0
- package/dist/utils.d.ts.map +1 -0
- package/package.json +22 -48
- package/dist/client.js +0 -549
- package/dist/client.js.map +0 -1
- package/dist/core/acknowledgment.d.ts +0 -103
- package/dist/core/acknowledgment.d.ts.map +0 -1
- package/dist/core/client.d.ts +0 -256
- package/dist/core/client.d.ts.map +0 -1
- package/dist/core/connect.d.ts +0 -101
- package/dist/core/connect.d.ts.map +0 -1
- package/dist/core/errors.d.ts +0 -81
- package/dist/core/errors.d.ts.map +0 -1
- package/dist/core/index.d.ts +0 -23
- package/dist/core/index.d.ts.map +0 -1
- package/dist/core/index.js +0 -2
- package/dist/core/internal/ack-parser-stream.d.ts +0 -22
- package/dist/core/internal/ack-parser-stream.d.ts.map +0 -1
- package/dist/core/internal/subscribe-abort.d.ts +0 -30
- package/dist/core/internal/subscribe-abort.d.ts.map +0 -1
- package/dist/node.js +0 -214
- package/dist/node.js.map +0 -1
- package/dist/runtimes/internal/node-error-mapping.d.ts +0 -68
- package/dist/runtimes/internal/node-error-mapping.d.ts.map +0 -1
- package/dist/runtimes/node.d.ts +0 -47
- package/dist/runtimes/node.d.ts.map +0 -1
- package/dist/runtimes/node.js +0 -3
- package/dist/runtimes/workers.d.ts +0 -64
- package/dist/runtimes/workers.d.ts.map +0 -1
- package/dist/runtimes/workers.js +0 -143
- package/dist/runtimes/workers.js.map +0 -1
package/dist/core/errors.d.ts
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import { MllpError } from "@glion/mllp-transport";
|
|
2
|
-
import type { MllpErrorOptions } from "@glion/mllp-transport";
|
|
3
|
-
/**
|
|
4
|
-
* Machine-readable codes for `MllpClient` transport failures.
|
|
5
|
-
*
|
|
6
|
-
* These cover everything that can go wrong between the moment
|
|
7
|
-
* `MllpClient.send()` is called and the moment a complete ACK frame
|
|
8
|
-
* has been decoded — i.e. everything that is not an HL7v2
|
|
9
|
-
* application-level NAK. NAK responses (MSA-1 ∈ {AE, AR, CE, CR})
|
|
10
|
-
* surface as `AckException` subclasses thrown directly from
|
|
11
|
-
* `@glion/ack`, not as transport errors.
|
|
12
|
-
*/
|
|
13
|
-
export declare const MllpClientErrorCode: {
|
|
14
|
-
/** No ACK arrived within the configured `timeout`. */
|
|
15
|
-
/** The peer closed the connection before a complete ACK arrived. */
|
|
16
|
-
readonly CONNECTION_CLOSED: "CONNECTION_CLOSED";
|
|
17
|
-
/** TCP connection could not be established (refused, DNS, routing). */
|
|
18
|
-
readonly CONNECTION_REFUSED: "CONNECTION_REFUSED";
|
|
19
|
-
/**
|
|
20
|
-
* The caller passed a payload that could not be MLLP-encoded —
|
|
21
|
-
* typically because it was not a `string` or `Uint8Array`. Also
|
|
22
|
-
* surfaced when constructor options fail validation (bad
|
|
23
|
-
* host/port/timeout/etc). Thrown before any socket is opened, so
|
|
24
|
-
* no connection is made and no resources need cleanup.
|
|
25
|
-
*/
|
|
26
|
-
readonly INVALID_INPUT: "INVALID_INPUT";
|
|
27
|
-
readonly MALFORMED_ACK: "MALFORMED_ACK";
|
|
28
|
-
/** The remote sent bytes that did not form a valid MLLP frame. */
|
|
29
|
-
readonly MALFORMED_FRAME: "MALFORMED_FRAME";
|
|
30
|
-
/** A frame was received but could not be parsed as a valid HL7v2 ACK. */
|
|
31
|
-
readonly TIMEOUT: "TIMEOUT";
|
|
32
|
-
/**
|
|
33
|
-
* TLS handshake failed — typically because of certificate
|
|
34
|
-
* verification, hostname mismatch, expired cert, untrusted CA, or
|
|
35
|
-
* a TLS protocol error. Distinct from `CONNECTION_REFUSED` (the
|
|
36
|
-
* TCP connection succeeded but the TLS upgrade failed) so
|
|
37
|
-
* operators can identify TLS misconfiguration quickly in
|
|
38
|
-
* healthcare deployments where it is a recurring incident class.
|
|
39
|
-
*/
|
|
40
|
-
readonly TLS_HANDSHAKE_FAILED: "TLS_HANDSHAKE_FAILED";
|
|
41
|
-
};
|
|
42
|
-
export type MllpClientErrorCode = (typeof MllpClientErrorCode)[keyof typeof MllpClientErrorCode];
|
|
43
|
-
/**
|
|
44
|
-
* Error thrown by `MllpClient.send()` for transport-level failures.
|
|
45
|
-
*
|
|
46
|
-
* Extends {@link MllpError} so callers can catch any MLLP error —
|
|
47
|
-
* server- or client-side — with a single `instanceof MllpError`
|
|
48
|
-
* check. The {@link MllpClientErrorCode | code} field discriminates
|
|
49
|
-
* the failure mode for typed handling.
|
|
50
|
-
*
|
|
51
|
-
* Application-level NAK responses are **not** thrown as
|
|
52
|
-
* `MllpClientError`; they are thrown as `AckException` subclasses
|
|
53
|
-
* from `@glion/ack`. A typical `catch` block handles both:
|
|
54
|
-
*
|
|
55
|
-
* ```ts
|
|
56
|
-
* import { AckException } from "@glion/ack";
|
|
57
|
-
* import { MllpClientError } from "@glion/mllp-client";
|
|
58
|
-
*
|
|
59
|
-
* try {
|
|
60
|
-
* await client.send(message);
|
|
61
|
-
* } catch (error) {
|
|
62
|
-
* if (error instanceof AckException) {
|
|
63
|
-
* // Application-level NAK.
|
|
64
|
-
* } else if (error instanceof MllpClientError) {
|
|
65
|
-
* // Transport-level failure.
|
|
66
|
-
* }
|
|
67
|
-
* }
|
|
68
|
-
* ```
|
|
69
|
-
*/
|
|
70
|
-
export declare class MllpClientError extends MllpError {
|
|
71
|
-
/**
|
|
72
|
-
* Narrowed view of the inherited `MllpError.code` field. `declare`
|
|
73
|
-
* keeps the runtime value (set by the base constructor) while
|
|
74
|
-
* exposing the discriminated {@link MllpClientErrorCode} union to
|
|
75
|
-
* TypeScript — callers can `switch` on `error.code` with full
|
|
76
|
-
* exhaustiveness checking.
|
|
77
|
-
*/
|
|
78
|
-
readonly code: MllpClientErrorCode;
|
|
79
|
-
constructor(code: MllpClientErrorCode, message: string, options?: MllpErrorOptions);
|
|
80
|
-
}
|
|
81
|
-
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE9D;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB;IAC9B,sDAAsD;IACtD,oEAAoE;;IAEpE,uEAAuE;;IAEvE;;;;;;OAMG;;;IAGH,kEAAkE;;IAElE,yEAAyE;;IAEzE;;;;;;;OAOG;;CAEK,CAAC;AAEX,MAAM,MAAM,mBAAmB,GAC7B,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,OAAO,mBAAmB,CAAC,CAAC;AAEjE;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAAa,eAAgB,SAAQ,SAAS;IAC5C;;;;;;OAMG;IACH,SAAiB,IAAI,EAAE,mBAAmB,CAAC;gBAGzC,IAAI,EAAE,mBAAmB,EACzB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,gBAAgB;CAK7B"}
|
package/dist/core/index.d.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Runtime-free entry point of `@glion/mllp-client`.
|
|
3
|
-
*
|
|
4
|
-
* Use this when you need to run the client in a non-standard runtime
|
|
5
|
-
* (for example, in a browser via a WebSocket-to-MLLP gateway, or
|
|
6
|
-
* with an in-memory pipe for tests). Construction requires you to
|
|
7
|
-
* supply your own {@link MllpConnect} function.
|
|
8
|
-
*
|
|
9
|
-
* For the common case (Node, Bun, Deno, Cloudflare Workers), prefer
|
|
10
|
-
* the per-runtime adapters which ship a pre-wired connector:
|
|
11
|
-
*
|
|
12
|
-
* - `@glion/mllp-client` — Node and Bun (default entry)
|
|
13
|
-
* - `@glion/mllp-client/deno` — Deno
|
|
14
|
-
* - `@glion/mllp-client/workers` — Cloudflare Workers
|
|
15
|
-
*
|
|
16
|
-
* @module
|
|
17
|
-
*/
|
|
18
|
-
export type { Acknowledgment } from "./acknowledgment";
|
|
19
|
-
export { MllpClient } from "./client";
|
|
20
|
-
export type { BoundMllpClientOptions, MllpClientOptions, MllpClientTlsOptions, SendMode, SendOptions, } from "./client";
|
|
21
|
-
export type { MllpConnect, MllpConnectParams, MllpDuplexStream, } from "./connect";
|
|
22
|
-
export { MllpClientError, MllpClientErrorCode } from "./errors";
|
|
23
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/core/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,YAAY,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,YAAY,EACV,sBAAsB,EACtB,iBAAiB,EACjB,oBAAoB,EACpB,QAAQ,EACR,WAAW,GACZ,MAAM,UAAU,CAAC;AAClB,YAAY,EACV,WAAW,EACX,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC"}
|
package/dist/core/index.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `TransformStream<DecodedMessage, Acknowledgment>` that parses each
|
|
3
|
-
* decoded MLLP frame as an HL7v2 acknowledgment. Internal to
|
|
4
|
-
* `@glion/mllp-client`.
|
|
5
|
-
*
|
|
6
|
-
* On a malformed ACK the transform errors the readable with the
|
|
7
|
-
* typed `MllpClientError(MALFORMED_ACK)` from {@link parseAck}.
|
|
8
|
-
* Downstream `for await ... of` consumers reject with that error;
|
|
9
|
-
* `MllpClient.send()` translates it at its single catch site.
|
|
10
|
-
*
|
|
11
|
-
* @module
|
|
12
|
-
*/
|
|
13
|
-
import type { DecodedMessage } from "@glion/mllp-transport";
|
|
14
|
-
import type { Acknowledgment } from "../acknowledgment";
|
|
15
|
-
/**
|
|
16
|
-
* Build a transform that consumes decoded MLLP frames and produces
|
|
17
|
-
* parsed `Acknowledgment` objects. A parse failure errors the
|
|
18
|
-
* readable side rather than enqueuing — the consumer's `for await`
|
|
19
|
-
* loop rejects with the typed error.
|
|
20
|
-
*/
|
|
21
|
-
export declare function createAckParserStream(): TransformStream<DecodedMessage, Acknowledgment>;
|
|
22
|
-
//# sourceMappingURL=ack-parser-stream.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ack-parser-stream.d.ts","sourceRoot":"","sources":["../../../src/core/internal/ack-parser-stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGxD;;;;;GAKG;AACH,wBAAgB,qBAAqB,IAAI,eAAe,CACtD,cAAc,EACd,cAAc,CACf,CAUA"}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Subscribe to an `AbortSignal` and run a callback once if it
|
|
3
|
-
* aborts. Returns a disposer that unsubscribes — call it from a
|
|
4
|
-
* `finally` block so we never leak listeners.
|
|
5
|
-
*
|
|
6
|
-
* If the signal is already aborted at subscription time, the
|
|
7
|
-
* callback fires synchronously and the returned disposer is a
|
|
8
|
-
* no-op. This collapses the "aborted vs aborting" branch every
|
|
9
|
-
* caller would otherwise need to write by hand.
|
|
10
|
-
*
|
|
11
|
-
* Internal to `@glion/mllp-client`.
|
|
12
|
-
*
|
|
13
|
-
* @module
|
|
14
|
-
*/
|
|
15
|
-
/**
|
|
16
|
-
* Subscribe `onAbort` to fire once when `signal` aborts. Returns a
|
|
17
|
-
* disposer that removes the listener.
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* ```ts
|
|
21
|
-
* const dispose = subscribeAbort(signal, () => socket.destroy());
|
|
22
|
-
* try {
|
|
23
|
-
* await waitForReady(socket);
|
|
24
|
-
* } finally {
|
|
25
|
-
* dispose();
|
|
26
|
-
* }
|
|
27
|
-
* ```;
|
|
28
|
-
*/
|
|
29
|
-
export declare function subscribeAbort(signal: AbortSignal, onAbort: () => void): () => void;
|
|
30
|
-
//# sourceMappingURL=subscribe-abort.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"subscribe-abort.d.ts","sourceRoot":"","sources":["../../../src/core/internal/subscribe-abort.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,WAAW,EACnB,OAAO,EAAE,MAAM,IAAI,GAClB,MAAM,IAAI,CAOZ"}
|
package/dist/node.js
DELETED
|
@@ -1,214 +0,0 @@
|
|
|
1
|
-
import { i as MllpClientErrorCode, n as subscribeAbort, r as MllpClientError, t as MllpClient$1 } from "./client.js";
|
|
2
|
-
import { connect } from "node:net";
|
|
3
|
-
import { Readable, Writable } from "node:stream";
|
|
4
|
-
import { connect as connect$1 } from "node:tls";
|
|
5
|
-
//#region src/runtimes/internal/node-error-mapping.ts
|
|
6
|
-
/**
|
|
7
|
-
* Translation layer between Node's socket error surface and
|
|
8
|
-
* `MllpClientError`. Lives in `runtimes/internal/` so it is unreachable
|
|
9
|
-
* via the package's `exports` map (and therefore safe to evolve without
|
|
10
|
-
* a major bump) while remaining importable from the per-runtime test
|
|
11
|
-
* suite.
|
|
12
|
-
*
|
|
13
|
-
* **Drift contract.** Node does not document `error.code` as a stable
|
|
14
|
-
* enum — values come from libuv (system errors) and OpenSSL (TLS
|
|
15
|
-
* verification errors), and new codes can appear when Node bumps
|
|
16
|
-
* either dependency. The mapping here is curated against:
|
|
17
|
-
*
|
|
18
|
-
* - System errors (`ECONN*`, `ENOTFOUND`, `ETIMEDOUT`, …) —
|
|
19
|
-
* {@link https://nodejs.org/api/errors.html#common-system-errors | Node — Common System Errors}.
|
|
20
|
-
* - TLS X.509 verification errors (`CERT_HAS_EXPIRED`,
|
|
21
|
-
* `DEPTH_ZERO_SELF_SIGNED_CERT`, `UNABLE_TO_VERIFY_LEAF_SIGNATURE`, …) —
|
|
22
|
-
* {@link https://nodejs.org/api/tls.html#x509-certificate-error-codes | Node — X.509 Certificate Error Codes}
|
|
23
|
-
* (Node surfaces the upstream OpenSSL `X509_V_ERR_*` names).
|
|
24
|
-
* - Node-specific TLS errors (`ERR_TLS_*`) —
|
|
25
|
-
* {@link https://nodejs.org/api/errors.html#nodejs-error-codes | Node — Node.js Error Codes}.
|
|
26
|
-
*
|
|
27
|
-
* **The list does not aim to be exhaustive.** Two fallbacks absorb
|
|
28
|
-
* the long tail without leaking native errors to callers:
|
|
29
|
-
*
|
|
30
|
-
* 1. Any unrecognised `error.code` whose `error.message` looks TLS-flavoured
|
|
31
|
-
* ({@link looksLikeTlsHandshakeError}) routes to `TLS_HANDSHAKE_FAILED`.
|
|
32
|
-
* This catches new OpenSSL X.509 codes, `ERR_SSL_*` codes that arrive
|
|
33
|
-
* without a stable name, and bare `Error("alert handshake failure")`-style
|
|
34
|
-
* throws from Node's TLS layer.
|
|
35
|
-
* 2. Anything else routes to `CONNECTION_CLOSED`. Caller still gets a typed
|
|
36
|
-
* `MllpClientError` with the original Node error chained as `cause`; the
|
|
37
|
-
* caller's `error.code` discriminator is just less specific than ideal.
|
|
38
|
-
*
|
|
39
|
-
* **When to expand the explicit list.** Add a `case` only when a
|
|
40
|
-
* real-world report (a user issue, a CI failure, a production
|
|
41
|
-
* incident) shows a code consistently misclassified by the
|
|
42
|
-
* fallbacks. Don't pre-emptively enumerate from upstream changelogs —
|
|
43
|
-
* the fallback layer is doing its job for unknowns.
|
|
44
|
-
*
|
|
45
|
-
* @module
|
|
46
|
-
*/
|
|
47
|
-
/**
|
|
48
|
-
* Translate a Node.js socket error into the matching
|
|
49
|
-
* {@link MllpClientError} so callers see one consistent error shape
|
|
50
|
-
* regardless of which native code path failed.
|
|
51
|
-
*
|
|
52
|
-
* See the module-level JSDoc for the full drift contract.
|
|
53
|
-
*/
|
|
54
|
-
function mapSocketError(error, host, port) {
|
|
55
|
-
if (error instanceof MllpClientError) return error;
|
|
56
|
-
const target = `${host}:${port}`;
|
|
57
|
-
switch (error.code) {
|
|
58
|
-
case "ECONNREFUSED":
|
|
59
|
-
case "ENOTFOUND":
|
|
60
|
-
case "EHOSTUNREACH":
|
|
61
|
-
case "ENETUNREACH": return new MllpClientError(MllpClientErrorCode.CONNECTION_REFUSED, `Could not connect to ${target}: ${error.message}`, { cause: error });
|
|
62
|
-
case "ETIMEDOUT": return new MllpClientError(MllpClientErrorCode.TIMEOUT, `Connection to ${target} timed out: ${error.message}`, { cause: error });
|
|
63
|
-
case "CERT_HAS_EXPIRED":
|
|
64
|
-
case "DEPTH_ZERO_SELF_SIGNED_CERT":
|
|
65
|
-
case "ERR_TLS_CERT_ALTNAME_INVALID":
|
|
66
|
-
case "ERR_TLS_HANDSHAKE_TIMEOUT":
|
|
67
|
-
case "SELF_SIGNED_CERT_IN_CHAIN":
|
|
68
|
-
case "UNABLE_TO_GET_ISSUER_CERT":
|
|
69
|
-
case "UNABLE_TO_GET_ISSUER_CERT_LOCALLY":
|
|
70
|
-
case "UNABLE_TO_VERIFY_LEAF_SIGNATURE": return new MllpClientError(MllpClientErrorCode.TLS_HANDSHAKE_FAILED, `TLS handshake to ${target} failed: ${error.message}`, { cause: error });
|
|
71
|
-
default:
|
|
72
|
-
if (looksLikeTlsHandshakeError(error)) return new MllpClientError(MllpClientErrorCode.TLS_HANDSHAKE_FAILED, `TLS handshake to ${target} failed: ${error.message}`, { cause: error });
|
|
73
|
-
return new MllpClientError(MllpClientErrorCode.CONNECTION_CLOSED, `Connection error: ${error.message}`, { cause: error });
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Best-effort detector for TLS handshake errors that don't carry a
|
|
78
|
-
* stable `error.code`. This is the drift-protection mechanism: when
|
|
79
|
-
* Node or OpenSSL adds a new TLS error code we haven't enumerated,
|
|
80
|
-
* a TLS-flavoured `error.message` keeps it routed to the typed
|
|
81
|
-
* {@link MllpClientErrorCode.TLS_HANDSHAKE_FAILED} bucket rather than
|
|
82
|
-
* falling through to `CONNECTION_CLOSED`.
|
|
83
|
-
*
|
|
84
|
-
* Triggers on: `ssl`, `tls`, `handshake`, `certificate` (case-insensitive).
|
|
85
|
-
* Tested in `test/node.test.ts` so a future change here cannot
|
|
86
|
-
* silently widen or narrow the routing.
|
|
87
|
-
*/
|
|
88
|
-
function looksLikeTlsHandshakeError(error) {
|
|
89
|
-
const msg = error.message.toLowerCase();
|
|
90
|
-
return msg.includes("ssl") || msg.includes("tls") || msg.includes("handshake") || msg.includes("certificate");
|
|
91
|
-
}
|
|
92
|
-
//#endregion
|
|
93
|
-
//#region src/runtimes/node.ts
|
|
94
|
-
/**
|
|
95
|
-
* Node.js (and Bun) runtime adapter for `@glion/mllp-client`.
|
|
96
|
-
*
|
|
97
|
-
* Re-exports the core `MllpClient` pre-wired with a `connect`
|
|
98
|
-
* implementation that uses Node's `node:net` and `node:tls` modules.
|
|
99
|
-
* Application code on Node or Bun imports from this entry and never
|
|
100
|
-
* has to think about transport plumbing:
|
|
101
|
-
*
|
|
102
|
-
* ```ts
|
|
103
|
-
* import { MllpClient } from "@glion/mllp-client/node";
|
|
104
|
-
*
|
|
105
|
-
* const client = new MllpClient({ host: "127.0.0.1", port: 2575 });
|
|
106
|
-
* const ack = await client.send(rawHl7Message);
|
|
107
|
-
* ```
|
|
108
|
-
*
|
|
109
|
-
* Bun ships a `node:net` shim that is API-compatible for our needs,
|
|
110
|
-
* so this same adapter covers both runtimes.
|
|
111
|
-
*
|
|
112
|
-
* @module
|
|
113
|
-
*/
|
|
114
|
-
/**
|
|
115
|
-
* MLLP client pre-wired with the Node/Bun connector. API-identical to
|
|
116
|
-
* the core class — the only difference is that callers do not need
|
|
117
|
-
* to supply `connect`.
|
|
118
|
-
*/
|
|
119
|
-
var MllpClient = class extends MllpClient$1 {
|
|
120
|
-
constructor(options) {
|
|
121
|
-
super({
|
|
122
|
-
...options,
|
|
123
|
-
connect: nodeConnect
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
};
|
|
127
|
-
/**
|
|
128
|
-
* `MllpConnect` implementation backed by `node:net` (TCP) or
|
|
129
|
-
* `node:tls` (TLS). Returns a {@link MllpDuplexStream} whose readable
|
|
130
|
-
* and writable sides are the Web-Streams views of the underlying
|
|
131
|
-
* Node socket.
|
|
132
|
-
*
|
|
133
|
-
* Exported alongside the class so advanced callers can compose it
|
|
134
|
-
* with the core `MllpClient` directly (e.g., to wrap it with logging
|
|
135
|
-
* or fault injection in tests).
|
|
136
|
-
*/
|
|
137
|
-
const nodeConnect = (params) => new Promise((resolve, reject) => {
|
|
138
|
-
const socket = openSocket(params);
|
|
139
|
-
const readyEvent = params.tls ? "secureConnect" : "connect";
|
|
140
|
-
const cleanupAbort = params.signal ? subscribeAbort(params.signal, () => {
|
|
141
|
-
socket.destroy();
|
|
142
|
-
reject(toAbortError(params.signal.reason, params.host, params.port));
|
|
143
|
-
}) : noop;
|
|
144
|
-
socket.once(readyEvent, () => {
|
|
145
|
-
cleanupAbort();
|
|
146
|
-
socket.setNoDelay(true);
|
|
147
|
-
resolve(toDuplex(socket));
|
|
148
|
-
});
|
|
149
|
-
socket.once("error", (error) => {
|
|
150
|
-
cleanupAbort();
|
|
151
|
-
socket.destroy();
|
|
152
|
-
reject(mapSocketError(error, params.host, params.port));
|
|
153
|
-
});
|
|
154
|
-
});
|
|
155
|
-
/** No-op disposer used when no abort signal was supplied. */
|
|
156
|
-
function noop() {}
|
|
157
|
-
/**
|
|
158
|
-
* Translate an abort `reason` from the connect-phase signal into a typed
|
|
159
|
-
* {@link MllpClientError}. Mirrors the precedence in `normaliseSendError` in
|
|
160
|
-
* `core/client.ts`: typed reasons pass through, anything else maps to TIMEOUT.
|
|
161
|
-
*/
|
|
162
|
-
function toAbortError(reason, host, port) {
|
|
163
|
-
if (reason instanceof MllpClientError) return reason;
|
|
164
|
-
return new MllpClientError(MllpClientErrorCode.TIMEOUT, `Connect to ${host}:${port} aborted`, { cause: reason instanceof Error ? reason : void 0 });
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* Open a raw TCP or TLS socket using Node's built-ins. Splits TLS
|
|
168
|
-
* material into the shape `tls.connect()` expects and drops the
|
|
169
|
-
* `insecure` flag into `rejectUnauthorized` (the only opt-out form).
|
|
170
|
-
*/
|
|
171
|
-
function openSocket(params) {
|
|
172
|
-
if (!params.tls) return connect({
|
|
173
|
-
host: params.host,
|
|
174
|
-
port: params.port
|
|
175
|
-
});
|
|
176
|
-
return connect$1({
|
|
177
|
-
ca: toBufferOrString(params.tls.ca),
|
|
178
|
-
cert: toBufferOrString(params.tls.cert),
|
|
179
|
-
host: params.host,
|
|
180
|
-
key: toBufferOrString(params.tls.key),
|
|
181
|
-
passphrase: params.tls.passphrase,
|
|
182
|
-
port: params.port,
|
|
183
|
-
rejectUnauthorized: params.tls.insecure !== true,
|
|
184
|
-
servername: params.tls.servername ?? params.host
|
|
185
|
-
});
|
|
186
|
-
}
|
|
187
|
-
/**
|
|
188
|
-
* Coerce TLS material from the cross-runtime `string | Uint8Array`
|
|
189
|
-
* shape into Node's expected `string | Buffer`. `Buffer.from(view)`
|
|
190
|
-
* is a zero-copy wrap when the input is already a `Buffer`.
|
|
191
|
-
*/
|
|
192
|
-
function toBufferOrString(input) {
|
|
193
|
-
if (input === void 0) return;
|
|
194
|
-
return typeof input === "string" ? input : Buffer.from(input);
|
|
195
|
-
}
|
|
196
|
-
/**
|
|
197
|
-
* Wrap a Node `Socket` in the {@link MllpDuplexStream} contract.
|
|
198
|
-
* Bridges Node's stream model into Web Streams via `Readable.toWeb`
|
|
199
|
-
* and `Writable.toWeb` (Node 18+).
|
|
200
|
-
*/
|
|
201
|
-
function toDuplex(socket) {
|
|
202
|
-
return {
|
|
203
|
-
close() {
|
|
204
|
-
if (!socket.destroyed) socket.destroy();
|
|
205
|
-
return Promise.resolve();
|
|
206
|
-
},
|
|
207
|
-
readable: Readable.toWeb(socket),
|
|
208
|
-
writable: Writable.toWeb(socket)
|
|
209
|
-
};
|
|
210
|
-
}
|
|
211
|
-
//#endregion
|
|
212
|
-
export { nodeConnect as n, MllpClient as t };
|
|
213
|
-
|
|
214
|
-
//# sourceMappingURL=node.js.map
|
package/dist/node.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"node.js","names":["CoreMllpClient","netConnect","tlsConnect"],"sources":["../src/runtimes/internal/node-error-mapping.ts","../src/runtimes/node.ts"],"sourcesContent":["/**\n * Translation layer between Node's socket error surface and\n * `MllpClientError`. Lives in `runtimes/internal/` so it is unreachable\n * via the package's `exports` map (and therefore safe to evolve without\n * a major bump) while remaining importable from the per-runtime test\n * suite.\n *\n * **Drift contract.** Node does not document `error.code` as a stable\n * enum — values come from libuv (system errors) and OpenSSL (TLS\n * verification errors), and new codes can appear when Node bumps\n * either dependency. The mapping here is curated against:\n *\n * - System errors (`ECONN*`, `ENOTFOUND`, `ETIMEDOUT`, …) —\n * {@link https://nodejs.org/api/errors.html#common-system-errors | Node — Common System Errors}.\n * - TLS X.509 verification errors (`CERT_HAS_EXPIRED`,\n * `DEPTH_ZERO_SELF_SIGNED_CERT`, `UNABLE_TO_VERIFY_LEAF_SIGNATURE`, …) —\n * {@link https://nodejs.org/api/tls.html#x509-certificate-error-codes | Node — X.509 Certificate Error Codes}\n * (Node surfaces the upstream OpenSSL `X509_V_ERR_*` names).\n * - Node-specific TLS errors (`ERR_TLS_*`) —\n * {@link https://nodejs.org/api/errors.html#nodejs-error-codes | Node — Node.js Error Codes}.\n *\n * **The list does not aim to be exhaustive.** Two fallbacks absorb\n * the long tail without leaking native errors to callers:\n *\n * 1. Any unrecognised `error.code` whose `error.message` looks TLS-flavoured\n * ({@link looksLikeTlsHandshakeError}) routes to `TLS_HANDSHAKE_FAILED`.\n * This catches new OpenSSL X.509 codes, `ERR_SSL_*` codes that arrive\n * without a stable name, and bare `Error(\"alert handshake failure\")`-style\n * throws from Node's TLS layer.\n * 2. Anything else routes to `CONNECTION_CLOSED`. Caller still gets a typed\n * `MllpClientError` with the original Node error chained as `cause`; the\n * caller's `error.code` discriminator is just less specific than ideal.\n *\n * **When to expand the explicit list.** Add a `case` only when a\n * real-world report (a user issue, a CI failure, a production\n * incident) shows a code consistently misclassified by the\n * fallbacks. Don't pre-emptively enumerate from upstream changelogs —\n * the fallback layer is doing its job for unknowns.\n *\n * @module\n */\n\nimport { MllpClientError, MllpClientErrorCode } from \"../../core/errors\";\n\n/** Node socket errors carry an optional system code (e.g. `ECONNREFUSED`). */\nexport type NodeError = Error & { code?: string };\n\n/**\n * Translate a Node.js socket error into the matching\n * {@link MllpClientError} so callers see one consistent error shape\n * regardless of which native code path failed.\n *\n * See the module-level JSDoc for the full drift contract.\n */\nexport function mapSocketError(\n error: NodeError,\n host: string,\n port: number\n): MllpClientError {\n if (error instanceof MllpClientError) {\n return error;\n }\n const target = `${host}:${port}`;\n switch (error.code) {\n case \"ECONNREFUSED\":\n case \"ENOTFOUND\":\n case \"EHOSTUNREACH\":\n case \"ENETUNREACH\": {\n return new MllpClientError(\n MllpClientErrorCode.CONNECTION_REFUSED,\n `Could not connect to ${target}: ${error.message}`,\n { cause: error }\n );\n }\n case \"ETIMEDOUT\": {\n return new MllpClientError(\n MllpClientErrorCode.TIMEOUT,\n `Connection to ${target} timed out: ${error.message}`,\n { cause: error }\n );\n }\n case \"CERT_HAS_EXPIRED\":\n case \"DEPTH_ZERO_SELF_SIGNED_CERT\":\n case \"ERR_TLS_CERT_ALTNAME_INVALID\":\n case \"ERR_TLS_HANDSHAKE_TIMEOUT\":\n case \"SELF_SIGNED_CERT_IN_CHAIN\":\n case \"UNABLE_TO_GET_ISSUER_CERT\":\n case \"UNABLE_TO_GET_ISSUER_CERT_LOCALLY\":\n case \"UNABLE_TO_VERIFY_LEAF_SIGNATURE\": {\n return new MllpClientError(\n MllpClientErrorCode.TLS_HANDSHAKE_FAILED,\n `TLS handshake to ${target} failed: ${error.message}`,\n { cause: error }\n );\n }\n default: {\n if (looksLikeTlsHandshakeError(error)) {\n return new MllpClientError(\n MllpClientErrorCode.TLS_HANDSHAKE_FAILED,\n `TLS handshake to ${target} failed: ${error.message}`,\n { cause: error }\n );\n }\n return new MllpClientError(\n MllpClientErrorCode.CONNECTION_CLOSED,\n `Connection error: ${error.message}`,\n { cause: error }\n );\n }\n }\n}\n\n/**\n * Best-effort detector for TLS handshake errors that don't carry a\n * stable `error.code`. This is the drift-protection mechanism: when\n * Node or OpenSSL adds a new TLS error code we haven't enumerated,\n * a TLS-flavoured `error.message` keeps it routed to the typed\n * {@link MllpClientErrorCode.TLS_HANDSHAKE_FAILED} bucket rather than\n * falling through to `CONNECTION_CLOSED`.\n *\n * Triggers on: `ssl`, `tls`, `handshake`, `certificate` (case-insensitive).\n * Tested in `test/node.test.ts` so a future change here cannot\n * silently widen or narrow the routing.\n */\nexport function looksLikeTlsHandshakeError(error: NodeError): boolean {\n const msg = error.message.toLowerCase();\n return (\n msg.includes(\"ssl\") ||\n msg.includes(\"tls\") ||\n msg.includes(\"handshake\") ||\n msg.includes(\"certificate\")\n );\n}\n","/**\n * Node.js (and Bun) runtime adapter for `@glion/mllp-client`.\n *\n * Re-exports the core `MllpClient` pre-wired with a `connect`\n * implementation that uses Node's `node:net` and `node:tls` modules.\n * Application code on Node or Bun imports from this entry and never\n * has to think about transport plumbing:\n *\n * ```ts\n * import { MllpClient } from \"@glion/mllp-client/node\";\n *\n * const client = new MllpClient({ host: \"127.0.0.1\", port: 2575 });\n * const ack = await client.send(rawHl7Message);\n * ```\n *\n * Bun ships a `node:net` shim that is API-compatible for our needs,\n * so this same adapter covers both runtimes.\n *\n * @module\n */\n\nimport { connect as netConnect } from \"node:net\";\nimport type { Socket } from \"node:net\";\nimport { Readable, Writable } from \"node:stream\";\nimport { connect as tlsConnect } from \"node:tls\";\n\nimport { MllpClient as CoreMllpClient } from \"../core/client\";\nimport type {\n BoundMllpClientOptions,\n MllpClientOptions,\n MllpClientTlsOptions,\n} from \"../core/client\";\nimport type {\n MllpConnect,\n MllpConnectParams,\n MllpDuplexStream,\n} from \"../core/connect\";\nimport { MllpClientError, MllpClientErrorCode } from \"../core/errors\";\nimport { subscribeAbort } from \"../core/internal/subscribe-abort\";\nimport type { NodeError } from \"./internal/node-error-mapping\";\nimport { mapSocketError } from \"./internal/node-error-mapping\";\n\n// ---------------------------------------------------------------------------\n// Public class\n// ---------------------------------------------------------------------------\n\n/**\n * MLLP client pre-wired with the Node/Bun connector. API-identical to\n * the core class — the only difference is that callers do not need\n * to supply `connect`.\n */\nexport class MllpClient extends CoreMllpClient {\n constructor(options: BoundMllpClientOptions) {\n super({ ...options, connect: nodeConnect });\n }\n}\n\n// ---------------------------------------------------------------------------\n// Re-exports\n// ---------------------------------------------------------------------------\n\nexport type { Acknowledgment } from \"../core/acknowledgment\";\nexport type {\n MllpConnect,\n MllpConnectParams,\n MllpDuplexStream,\n} from \"../core/connect\";\nexport type {\n BoundMllpClientOptions,\n MllpClientOptions,\n MllpClientTlsOptions,\n SendMode,\n SendOptions,\n} from \"../core/client\";\nexport { MllpClientError, MllpClientErrorCode } from \"../core/errors\";\n\n// ---------------------------------------------------------------------------\n// Node connector\n// ---------------------------------------------------------------------------\n\n/**\n * `MllpConnect` implementation backed by `node:net` (TCP) or\n * `node:tls` (TLS). Returns a {@link MllpDuplexStream} whose readable\n * and writable sides are the Web-Streams views of the underlying\n * Node socket.\n *\n * Exported alongside the class so advanced callers can compose it\n * with the core `MllpClient` directly (e.g., to wrap it with logging\n * or fault injection in tests).\n */\nexport const nodeConnect: MllpConnect = (params) =>\n // oxlint-disable-next-line promise/avoid-new\n new Promise<MllpDuplexStream>((resolve, reject) => {\n const socket = openSocket(params);\n const readyEvent = params.tls ? \"secureConnect\" : \"connect\";\n\n const cleanupAbort = params.signal\n ? subscribeAbort(params.signal, () => {\n socket.destroy();\n reject(toAbortError(params.signal!.reason, params.host, params.port));\n })\n : noop;\n\n socket.once(readyEvent, () => {\n cleanupAbort();\n // Disable Nagle so small MLLP frames flush immediately.\n socket.setNoDelay(true);\n resolve(toDuplex(socket));\n });\n\n socket.once(\"error\", (error: NodeError) => {\n cleanupAbort();\n socket.destroy();\n reject(mapSocketError(error, params.host, params.port));\n });\n });\n\n/** No-op disposer used when no abort signal was supplied. */\nfunction noop(): void {\n /* nothing to dispose */\n}\n\n/**\n * Translate an abort `reason` from the connect-phase signal into a typed\n * {@link MllpClientError}. Mirrors the precedence in `normaliseSendError` in\n * `core/client.ts`: typed reasons pass through, anything else maps to TIMEOUT.\n */\nfunction toAbortError(\n reason: unknown,\n host: string,\n port: number\n): MllpClientError {\n if (reason instanceof MllpClientError) {\n return reason;\n }\n return new MllpClientError(\n MllpClientErrorCode.TIMEOUT,\n `Connect to ${host}:${port} aborted`,\n { cause: reason instanceof Error ? reason : undefined }\n );\n}\n\n/**\n * Open a raw TCP or TLS socket using Node's built-ins. Splits TLS\n * material into the shape `tls.connect()` expects and drops the\n * `insecure` flag into `rejectUnauthorized` (the only opt-out form).\n */\nfunction openSocket(params: MllpConnectParams): Socket {\n if (!params.tls) {\n return netConnect({ host: params.host, port: params.port });\n }\n return tlsConnect({\n ca: toBufferOrString(params.tls.ca),\n cert: toBufferOrString(params.tls.cert),\n host: params.host,\n key: toBufferOrString(params.tls.key),\n passphrase: params.tls.passphrase,\n port: params.port,\n // Verification is on by default; the only opt-out is the\n // explicit `insecure: true`. Spelling the mapping out protects\n // against future Node default changes.\n rejectUnauthorized: params.tls.insecure !== true,\n servername: params.tls.servername ?? params.host,\n });\n}\n\n/**\n * Coerce TLS material from the cross-runtime `string | Uint8Array`\n * shape into Node's expected `string | Buffer`. `Buffer.from(view)`\n * is a zero-copy wrap when the input is already a `Buffer`.\n */\nfunction toBufferOrString(\n input: string | Uint8Array | undefined\n): string | Buffer | undefined {\n if (input === undefined) {\n return;\n }\n return typeof input === \"string\" ? input : Buffer.from(input);\n}\n\n/**\n * Wrap a Node `Socket` in the {@link MllpDuplexStream} contract.\n * Bridges Node's stream model into Web Streams via `Readable.toWeb`\n * and `Writable.toWeb` (Node 18+).\n */\nfunction toDuplex(socket: Socket): MllpDuplexStream {\n return {\n // `socket.destroy()` is sync and non-throwing — no work to await,\n // so we resolve immediately. The async signature is for the\n // contract (Workers' `socket.close()` is genuinely async).\n close() {\n if (!socket.destroyed) {\n socket.destroy();\n }\n return Promise.resolve();\n },\n readable: Readable.toWeb(socket) as ReadableStream<Uint8Array>,\n writable: Writable.toWeb(socket) as WritableStream<Uint8Array>,\n };\n}\n\n// Node socket-error translation lives in\n// `./internal/node-error-mapping` so the per-runtime test suite can\n// pin the drift-protection contract directly. See that module's\n// JSDoc for the curated list and fallback behaviour.\n"],"mappings":"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"}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Translation layer between Node's socket error surface and
|
|
3
|
-
* `MllpClientError`. Lives in `runtimes/internal/` so it is unreachable
|
|
4
|
-
* via the package's `exports` map (and therefore safe to evolve without
|
|
5
|
-
* a major bump) while remaining importable from the per-runtime test
|
|
6
|
-
* suite.
|
|
7
|
-
*
|
|
8
|
-
* **Drift contract.** Node does not document `error.code` as a stable
|
|
9
|
-
* enum — values come from libuv (system errors) and OpenSSL (TLS
|
|
10
|
-
* verification errors), and new codes can appear when Node bumps
|
|
11
|
-
* either dependency. The mapping here is curated against:
|
|
12
|
-
*
|
|
13
|
-
* - System errors (`ECONN*`, `ENOTFOUND`, `ETIMEDOUT`, …) —
|
|
14
|
-
* {@link https://nodejs.org/api/errors.html#common-system-errors | Node — Common System Errors}.
|
|
15
|
-
* - TLS X.509 verification errors (`CERT_HAS_EXPIRED`,
|
|
16
|
-
* `DEPTH_ZERO_SELF_SIGNED_CERT`, `UNABLE_TO_VERIFY_LEAF_SIGNATURE`, …) —
|
|
17
|
-
* {@link https://nodejs.org/api/tls.html#x509-certificate-error-codes | Node — X.509 Certificate Error Codes}
|
|
18
|
-
* (Node surfaces the upstream OpenSSL `X509_V_ERR_*` names).
|
|
19
|
-
* - Node-specific TLS errors (`ERR_TLS_*`) —
|
|
20
|
-
* {@link https://nodejs.org/api/errors.html#nodejs-error-codes | Node — Node.js Error Codes}.
|
|
21
|
-
*
|
|
22
|
-
* **The list does not aim to be exhaustive.** Two fallbacks absorb
|
|
23
|
-
* the long tail without leaking native errors to callers:
|
|
24
|
-
*
|
|
25
|
-
* 1. Any unrecognised `error.code` whose `error.message` looks TLS-flavoured
|
|
26
|
-
* ({@link looksLikeTlsHandshakeError}) routes to `TLS_HANDSHAKE_FAILED`.
|
|
27
|
-
* This catches new OpenSSL X.509 codes, `ERR_SSL_*` codes that arrive
|
|
28
|
-
* without a stable name, and bare `Error("alert handshake failure")`-style
|
|
29
|
-
* throws from Node's TLS layer.
|
|
30
|
-
* 2. Anything else routes to `CONNECTION_CLOSED`. Caller still gets a typed
|
|
31
|
-
* `MllpClientError` with the original Node error chained as `cause`; the
|
|
32
|
-
* caller's `error.code` discriminator is just less specific than ideal.
|
|
33
|
-
*
|
|
34
|
-
* **When to expand the explicit list.** Add a `case` only when a
|
|
35
|
-
* real-world report (a user issue, a CI failure, a production
|
|
36
|
-
* incident) shows a code consistently misclassified by the
|
|
37
|
-
* fallbacks. Don't pre-emptively enumerate from upstream changelogs —
|
|
38
|
-
* the fallback layer is doing its job for unknowns.
|
|
39
|
-
*
|
|
40
|
-
* @module
|
|
41
|
-
*/
|
|
42
|
-
import { MllpClientError } from "../../core/errors";
|
|
43
|
-
/** Node socket errors carry an optional system code (e.g. `ECONNREFUSED`). */
|
|
44
|
-
export type NodeError = Error & {
|
|
45
|
-
code?: string;
|
|
46
|
-
};
|
|
47
|
-
/**
|
|
48
|
-
* Translate a Node.js socket error into the matching
|
|
49
|
-
* {@link MllpClientError} so callers see one consistent error shape
|
|
50
|
-
* regardless of which native code path failed.
|
|
51
|
-
*
|
|
52
|
-
* See the module-level JSDoc for the full drift contract.
|
|
53
|
-
*/
|
|
54
|
-
export declare function mapSocketError(error: NodeError, host: string, port: number): MllpClientError;
|
|
55
|
-
/**
|
|
56
|
-
* Best-effort detector for TLS handshake errors that don't carry a
|
|
57
|
-
* stable `error.code`. This is the drift-protection mechanism: when
|
|
58
|
-
* Node or OpenSSL adds a new TLS error code we haven't enumerated,
|
|
59
|
-
* a TLS-flavoured `error.message` keeps it routed to the typed
|
|
60
|
-
* {@link MllpClientErrorCode.TLS_HANDSHAKE_FAILED} bucket rather than
|
|
61
|
-
* falling through to `CONNECTION_CLOSED`.
|
|
62
|
-
*
|
|
63
|
-
* Triggers on: `ssl`, `tls`, `handshake`, `certificate` (case-insensitive).
|
|
64
|
-
* Tested in `test/node.test.ts` so a future change here cannot
|
|
65
|
-
* silently widen or narrow the routing.
|
|
66
|
-
*/
|
|
67
|
-
export declare function looksLikeTlsHandshakeError(error: NodeError): boolean;
|
|
68
|
-
//# sourceMappingURL=node-error-mapping.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"node-error-mapping.d.ts","sourceRoot":"","sources":["../../../src/runtimes/internal/node-error-mapping.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAEH,OAAO,EAAE,eAAe,EAAuB,MAAM,mBAAmB,CAAC;AAEzE,8EAA8E;AAC9E,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAElD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,SAAS,EAChB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GACX,eAAe,CAoDjB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAQpE"}
|
package/dist/runtimes/node.d.ts
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Node.js (and Bun) runtime adapter for `@glion/mllp-client`.
|
|
3
|
-
*
|
|
4
|
-
* Re-exports the core `MllpClient` pre-wired with a `connect`
|
|
5
|
-
* implementation that uses Node's `node:net` and `node:tls` modules.
|
|
6
|
-
* Application code on Node or Bun imports from this entry and never
|
|
7
|
-
* has to think about transport plumbing:
|
|
8
|
-
*
|
|
9
|
-
* ```ts
|
|
10
|
-
* import { MllpClient } from "@glion/mllp-client/node";
|
|
11
|
-
*
|
|
12
|
-
* const client = new MllpClient({ host: "127.0.0.1", port: 2575 });
|
|
13
|
-
* const ack = await client.send(rawHl7Message);
|
|
14
|
-
* ```
|
|
15
|
-
*
|
|
16
|
-
* Bun ships a `node:net` shim that is API-compatible for our needs,
|
|
17
|
-
* so this same adapter covers both runtimes.
|
|
18
|
-
*
|
|
19
|
-
* @module
|
|
20
|
-
*/
|
|
21
|
-
import { MllpClient as CoreMllpClient } from "../core/client";
|
|
22
|
-
import type { BoundMllpClientOptions } from "../core/client";
|
|
23
|
-
import type { MllpConnect } from "../core/connect";
|
|
24
|
-
/**
|
|
25
|
-
* MLLP client pre-wired with the Node/Bun connector. API-identical to
|
|
26
|
-
* the core class — the only difference is that callers do not need
|
|
27
|
-
* to supply `connect`.
|
|
28
|
-
*/
|
|
29
|
-
export declare class MllpClient extends CoreMllpClient {
|
|
30
|
-
constructor(options: BoundMllpClientOptions);
|
|
31
|
-
}
|
|
32
|
-
export type { Acknowledgment } from "../core/acknowledgment";
|
|
33
|
-
export type { MllpConnect, MllpConnectParams, MllpDuplexStream, } from "../core/connect";
|
|
34
|
-
export type { BoundMllpClientOptions, MllpClientOptions, MllpClientTlsOptions, SendMode, SendOptions, } from "../core/client";
|
|
35
|
-
export { MllpClientError, MllpClientErrorCode } from "../core/errors";
|
|
36
|
-
/**
|
|
37
|
-
* `MllpConnect` implementation backed by `node:net` (TCP) or
|
|
38
|
-
* `node:tls` (TLS). Returns a {@link MllpDuplexStream} whose readable
|
|
39
|
-
* and writable sides are the Web-Streams views of the underlying
|
|
40
|
-
* Node socket.
|
|
41
|
-
*
|
|
42
|
-
* Exported alongside the class so advanced callers can compose it
|
|
43
|
-
* with the core `MllpClient` directly (e.g., to wrap it with logging
|
|
44
|
-
* or fault injection in tests).
|
|
45
|
-
*/
|
|
46
|
-
export declare const nodeConnect: MllpConnect;
|
|
47
|
-
//# sourceMappingURL=node.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../src/runtimes/node.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAOH,OAAO,EAAE,UAAU,IAAI,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,KAAK,EACV,sBAAsB,EAGvB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EACV,WAAW,EAGZ,MAAM,iBAAiB,CAAC;AAUzB;;;;GAIG;AACH,qBAAa,UAAW,SAAQ,cAAc;gBAChC,OAAO,EAAE,sBAAsB;CAG5C;AAMD,YAAY,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,YAAY,EACV,WAAW,EACX,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,sBAAsB,EACtB,iBAAiB,EACjB,oBAAoB,EACpB,QAAQ,EACR,WAAW,GACZ,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAMtE;;;;;;;;;GASG;AACH,eAAO,MAAM,WAAW,EAAE,WAyBtB,CAAC"}
|
package/dist/runtimes/node.js
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Cloudflare Workers runtime adapter for `@glion/mllp-client`.
|
|
3
|
-
*
|
|
4
|
-
* Re-exports the core `MllpClient` pre-wired with a `connect`
|
|
5
|
-
* implementation that uses the `cloudflare:sockets` API. Application
|
|
6
|
-
* code on Workers imports from this entry:
|
|
7
|
-
*
|
|
8
|
-
* ```ts
|
|
9
|
-
* import { MllpClient } from "@glion/mllp-client/workers";
|
|
10
|
-
*
|
|
11
|
-
* const client = new MllpClient({ host: "127.0.0.1", port: 2575 });
|
|
12
|
-
* const ack = await client.send(rawHl7Message);
|
|
13
|
-
* ```
|
|
14
|
-
*
|
|
15
|
-
* The `cloudflare:sockets` module is only available inside the
|
|
16
|
-
* Workers (`workerd`) runtime. Importing this entry from a Node or
|
|
17
|
-
* Deno build will fail at module-resolution time — that's the
|
|
18
|
-
* intended behaviour, since each runtime should pick its own
|
|
19
|
-
* adapter.
|
|
20
|
-
*
|
|
21
|
-
* @module
|
|
22
|
-
*/
|
|
23
|
-
import { MllpClient as CoreMllpClient } from "../core/client";
|
|
24
|
-
import type { BoundMllpClientOptions } from "../core/client";
|
|
25
|
-
import type { MllpConnect } from "../core/connect";
|
|
26
|
-
/**
|
|
27
|
-
* MLLP client pre-wired with the Cloudflare Workers connector.
|
|
28
|
-
* API-identical to the core class — the only difference is that
|
|
29
|
-
* callers do not need to supply `connect`.
|
|
30
|
-
*/
|
|
31
|
-
export declare class MllpClient extends CoreMllpClient {
|
|
32
|
-
constructor(options: BoundMllpClientOptions);
|
|
33
|
-
}
|
|
34
|
-
export type { Acknowledgment } from "../core/acknowledgment";
|
|
35
|
-
export type { MllpConnect, MllpConnectParams, MllpDuplexStream, } from "../core/connect";
|
|
36
|
-
export type { BoundMllpClientOptions, MllpClientOptions, MllpClientTlsOptions, SendMode, SendOptions, } from "../core/client";
|
|
37
|
-
export { MllpClientError, MllpClientErrorCode } from "../core/errors";
|
|
38
|
-
/**
|
|
39
|
-
* `MllpConnect` implementation backed by Cloudflare's
|
|
40
|
-
* `cloudflare:sockets` module. Returns a {@link MllpDuplexStream} that
|
|
41
|
-
* mirrors the Worker socket's already-Web-Streams shape.
|
|
42
|
-
*
|
|
43
|
-
* TLS is on iff `params.tls` is set (the core normalises `tls: true`
|
|
44
|
-
* to `tls: {}` before reaching the adapter). Workers exposes a small
|
|
45
|
-
* subset of TLS options compared to Node — `ca`, `cert`, `key`,
|
|
46
|
-
* `passphrase`, and `servername` cannot be supplied programmatically
|
|
47
|
-
* and are rejected with `INVALID_INPUT`. `insecure: true` is also
|
|
48
|
-
* rejected: on Node it means "TLS on, certificate verification off",
|
|
49
|
-
* but Workers does not expose a way to disable verification, so
|
|
50
|
-
* silently downgrading to plain TCP would be a security regression.
|
|
51
|
-
* Callers wanting plain TCP must pass `tls: false` (the constructor
|
|
52
|
-
* defaults `tls` to `true`).
|
|
53
|
-
*
|
|
54
|
-
* **Error-code divergence vs. the Node adapter.** `cloudflare:sockets`
|
|
55
|
-
* does not surface enough detail to distinguish a TLS handshake
|
|
56
|
-
* failure from a TCP connect failure. Both surface here as
|
|
57
|
-
* `CONNECTION_REFUSED`. The Node adapter, by contrast, sniffs the
|
|
58
|
-
* underlying error and routes handshake failures to
|
|
59
|
-
* `TLS_HANDSHAKE_FAILED`. Callers writing cross-runtime code that
|
|
60
|
-
* switches on `error.code` must accept this asymmetry, or treat
|
|
61
|
-
* `CONNECTION_REFUSED` as the supertype.
|
|
62
|
-
*/
|
|
63
|
-
export declare const workersConnect: MllpConnect;
|
|
64
|
-
//# sourceMappingURL=workers.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"workers.d.ts","sourceRoot":"","sources":["../../src/runtimes/workers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AASH,OAAO,EAAE,UAAU,IAAI,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,KAAK,EACV,sBAAsB,EAEvB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,WAAW,EAAoB,MAAM,iBAAiB,CAAC;AAQrE;;;;GAIG;AACH,qBAAa,UAAW,SAAQ,cAAc;gBAChC,OAAO,EAAE,sBAAsB;CAG5C;AAMD,YAAY,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,YAAY,EACV,WAAW,EACX,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,sBAAsB,EACtB,iBAAiB,EACjB,oBAAoB,EACpB,QAAQ,EACR,WAAW,GACZ,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAMtE;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,cAAc,EAAE,WAsD5B,CAAC"}
|