@varta-health/client 0.1.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.
@@ -0,0 +1,92 @@
1
+ // BeatOutcome tagged union, DropReason enum, BeatError, and the
2
+ // `classifySendError` function — mirrors Rust `BeatOutcome`,
3
+ // Python `BeatOutcome`/`DropReason`, and Go `BeatOutcome`/`DropReason`.
4
+ import { EAGAIN, ECONNREFUSED, ECONNRESET, ENOBUFS, ENOENT, ENOSPC, ENOTCONN, EPIPE, EWOULDBLOCK, errnoName, } from "./errno.js";
5
+ // String-valued enum so the wire-side metrics label matches the Rust
6
+ // `Display` impl directly. The string values MUST stay byte-equal to
7
+ // the labels Prometheus sees from the observer (`varta_*_total{reason=…}`).
8
+ export var DropReason;
9
+ (function (DropReason) {
10
+ DropReason["KernelQueueFull"] = "kernel queue full";
11
+ DropReason["NoObserver"] = "no observer";
12
+ DropReason["PeerGone"] = "peer gone";
13
+ DropReason["StorageFull"] = "storage full";
14
+ })(DropReason || (DropReason = {}));
15
+ // Payload of `{ kind: "failed" }`. Extends `Error` so it can be thrown
16
+ // or logged like any other Node error, but carries structured `errno`
17
+ // and `kind` fields so callers don't have to parse `.message`.
18
+ export class BeatError extends Error {
19
+ errno;
20
+ kind;
21
+ constructor(errno, kind, message) {
22
+ super(message ?? `${kind} (errno=${errno})`);
23
+ this.name = "BeatError";
24
+ this.errno = errno;
25
+ this.kind = kind;
26
+ }
27
+ static fromNodeError(err) {
28
+ const code = typeof err.errno === "number" ? err.errno : 0;
29
+ return new BeatError(code, code ? errnoName(code) : err.name || "Other", err.message);
30
+ }
31
+ }
32
+ export const BeatOutcomes = Object.freeze({
33
+ sent() {
34
+ return { kind: "sent" };
35
+ },
36
+ dropped(reason) {
37
+ return { kind: "dropped", reason };
38
+ },
39
+ failed(error) {
40
+ return { kind: "failed", error };
41
+ },
42
+ });
43
+ export function isSent(o) {
44
+ return o.kind === "sent";
45
+ }
46
+ export function isDropped(o) {
47
+ return o.kind === "dropped";
48
+ }
49
+ export function isFailed(o) {
50
+ return o.kind === "failed";
51
+ }
52
+ // Translate a Node `send`-time error into a `BeatOutcome`.
53
+ //
54
+ // Mirrors `crates/varta-client/src/client.rs::classify_send_error` and
55
+ // the Python and Go equivalents. Exported because authors of custom
56
+ // `BeatTransport` implementations are likely to want the same bucketing.
57
+ export function classifySendError(err) {
58
+ // Node's `ErrnoException.errno` is the negative POSIX value on some
59
+ // calls (libuv convention) and the positive value on others. Take
60
+ // the absolute value so the comparisons below work uniformly.
61
+ const rawErrno = typeof err.errno === "number" ? err.errno : 0;
62
+ const code = rawErrno < 0 ? -rawErrno : rawErrno;
63
+ const sym = err.code ?? "";
64
+ if (code === ENOBUFS || sym === "ENOBUFS") {
65
+ return BeatOutcomes.dropped(DropReason.KernelQueueFull);
66
+ }
67
+ if (code === EAGAIN ||
68
+ code === EWOULDBLOCK ||
69
+ sym === "EAGAIN" ||
70
+ sym === "EWOULDBLOCK") {
71
+ return BeatOutcomes.dropped(DropReason.KernelQueueFull);
72
+ }
73
+ if (code === ECONNREFUSED ||
74
+ code === ENOENT ||
75
+ sym === "ECONNREFUSED" ||
76
+ sym === "ENOENT") {
77
+ return BeatOutcomes.dropped(DropReason.NoObserver);
78
+ }
79
+ if (code === ECONNRESET ||
80
+ code === ENOTCONN ||
81
+ code === EPIPE ||
82
+ sym === "ECONNRESET" ||
83
+ sym === "ENOTCONN" ||
84
+ sym === "EPIPE") {
85
+ return BeatOutcomes.dropped(DropReason.PeerGone);
86
+ }
87
+ if (code === ENOSPC || sym === "ENOSPC") {
88
+ return BeatOutcomes.dropped(DropReason.StorageFull);
89
+ }
90
+ return BeatOutcomes.failed(BeatError.fromNodeError(err));
91
+ }
92
+ //# sourceMappingURL=outcome.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outcome.js","sourceRoot":"","sources":["../src/outcome.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export declare class PanicInstallError extends Error {
2
+ readonly kind: string;
3
+ constructor(kind: string, message: string);
4
+ }
5
+ export declare function installSignalHandlerUdp(host: string, port: number): void;
6
+ export declare function installSignalHandlerSecureUdp(host: string, port: number, key: Buffer): void;
7
+ export declare function run(fn: () => void | Promise<void>): Promise<void>;
8
+ //# sourceMappingURL=panic.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"panic.d.ts","sourceRoot":"","sources":["../src/panic.ts"],"names":[],"mappings":"AA8BA,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBACV,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAK1C;AAwED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAexE;AAOD,wBAAgB,6BAA6B,CAC3C,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,GACV,IAAI,CAkDN;AAMD,wBAAsB,GAAG,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CASvE"}
package/dist/panic.js ADDED
@@ -0,0 +1,172 @@
1
+ // Panic-style emitters — Node's analogue of Rust's `install_panic_handler`.
2
+ //
3
+ // Node has no `excepthook` in the Python sense, but it does have:
4
+ // * `process.on('uncaughtException')` — synchronous throws.
5
+ // * `process.on('unhandledRejection')` — async promise rejections.
6
+ // * `process.on('SIGTERM' | 'SIGINT' | 'SIGQUIT' | 'SIGHUP')` —
7
+ // terminating signals.
8
+ //
9
+ // Each installer wires all three into a single critical-beat emitter
10
+ // for the chosen transport. The socket and frame buffer are
11
+ // pre-allocated at install time so the hot path is alloc-free and
12
+ // async-signal-safe (cerebrum 2026-05-14).
13
+ import { randomBytes } from "node:crypto";
14
+ import { createSocket } from "node:dgram";
15
+ import { encodeShared, KEY_BYTES, deriveIvPrefix, IV_RANDOM_BYTES, SESSION_SALT_BYTES, } from "./vlp_secure.js";
16
+ import { encodeInto, FRAME_BYTES, NONCE_TERMINAL, Status, } from "./vlp.js";
17
+ export class PanicInstallError extends Error {
18
+ kind;
19
+ constructor(kind, message) {
20
+ super(`${kind}: ${message}`);
21
+ this.name = "PanicInstallError";
22
+ this.kind = kind;
23
+ }
24
+ }
25
+ const FATAL_SIGNALS = ["SIGTERM", "SIGINT", "SIGQUIT", "SIGHUP"];
26
+ function buildCriticalFrame(payload = 0) {
27
+ const buf = Buffer.alloc(FRAME_BYTES);
28
+ encodeInto(buf, Status.Critical, process.pid >>> 0, process.hrtime.bigint(), NONCE_TERMINAL, payload >>> 0);
29
+ return buf;
30
+ }
31
+ // Wire emit() into the three terminating event sources. Each callback
32
+ // is one-shot: after the first invocation we tear down the listeners
33
+ // so process exit isn't blocked by lingering handlers.
34
+ function arm(emit) {
35
+ let fired = false;
36
+ const trigger = () => {
37
+ if (fired)
38
+ return;
39
+ fired = true;
40
+ try {
41
+ emit();
42
+ }
43
+ catch {
44
+ // Hook must never propagate.
45
+ }
46
+ };
47
+ process.on("uncaughtException", (err) => {
48
+ trigger();
49
+ // Re-throw so Node's default crash printer still runs and the
50
+ // process exits with code 1 — preserves Node's standard behaviour.
51
+ setImmediate(() => {
52
+ throw err;
53
+ });
54
+ });
55
+ process.on("unhandledRejection", (reason) => {
56
+ trigger();
57
+ setImmediate(() => {
58
+ throw reason instanceof Error ? reason : new Error(String(reason));
59
+ });
60
+ });
61
+ for (const sig of FATAL_SIGNALS) {
62
+ process.on(sig, () => {
63
+ trigger();
64
+ // Restore default handler and re-raise so the process exits with
65
+ // the canonical signal-derived code (128 + signum on POSIX).
66
+ process.removeAllListeners(sig);
67
+ process.kill(process.pid, sig);
68
+ });
69
+ }
70
+ }
71
+ function createConnectedSocket(host, port) {
72
+ const family = host.includes(":") ? "udp6" : "udp4";
73
+ const s = createSocket(family);
74
+ s.on("error", () => {
75
+ // Drop libuv async errors silently — emission is best-effort.
76
+ });
77
+ s.unref();
78
+ s.connect(port, host);
79
+ return s;
80
+ }
81
+ // Install a panic emitter that publishes a Critical+NONCE_TERMINAL
82
+ // frame over plaintext UDP on any terminating event.
83
+ export function installSignalHandlerUdp(host, port) {
84
+ let sock;
85
+ try {
86
+ sock = createConnectedSocket(host, port);
87
+ }
88
+ catch (err) {
89
+ throw new PanicInstallError("SocketBind", err.message);
90
+ }
91
+ const frame = buildCriticalFrame();
92
+ arm(() => {
93
+ try {
94
+ sock.send(frame);
95
+ }
96
+ catch {
97
+ // Best effort.
98
+ }
99
+ });
100
+ }
101
+ // Install a panic emitter that publishes a Critical+NONCE_TERMINAL
102
+ // frame over ChaCha20-Poly1305 AEAD UDP. Fail-closed entropy posture:
103
+ // `crypto.randomBytes(16)` is invoked once at install time; if it
104
+ // throws, `PanicInstallError(kind="EntropyUnavailable")` propagates
105
+ // and no hook is registered.
106
+ export function installSignalHandlerSecureUdp(host, port, key) {
107
+ if (key.length !== KEY_BYTES) {
108
+ throw new RangeError(`key must be ${KEY_BYTES} bytes`);
109
+ }
110
+ let salt;
111
+ try {
112
+ salt = randomBytes(SESSION_SALT_BYTES);
113
+ }
114
+ catch (err) {
115
+ throw new PanicInstallError("EntropyUnavailable", err.message);
116
+ }
117
+ let sock;
118
+ try {
119
+ sock = createConnectedSocket(host, port);
120
+ }
121
+ catch (err) {
122
+ throw new PanicInstallError("SocketBind", err.message);
123
+ }
124
+ // Capture state by reference inside the closure. `installPid` lets
125
+ // the hook detect post-`fork(2)` execution and re-read entropy
126
+ // before the IV is reused.
127
+ const state = {
128
+ salt,
129
+ installPid: process.pid,
130
+ counter: 0,
131
+ };
132
+ const keyCopy = Buffer.from(key);
133
+ arm(() => {
134
+ try {
135
+ if (process.pid !== state.installPid) {
136
+ try {
137
+ state.salt = randomBytes(SESSION_SALT_BYTES);
138
+ }
139
+ catch {
140
+ return; // fail-closed: skip emission rather than reuse stale IV
141
+ }
142
+ state.installPid = process.pid;
143
+ state.counter = 0;
144
+ }
145
+ const ivPrefix = deriveIvPrefix(state.salt, 0).subarray(0, IV_RANDOM_BYTES);
146
+ const counter = state.counter;
147
+ state.counter = (state.counter + 1) >>> 0;
148
+ const plaintext = buildCriticalFrame();
149
+ const wire = encodeShared(keyCopy, ivPrefix, counter, plaintext);
150
+ sock.send(wire);
151
+ }
152
+ catch {
153
+ // Hook must never propagate.
154
+ }
155
+ });
156
+ }
157
+ // Defer/recover-style wrapper. Any throw inside `fn` (sync or async)
158
+ // causes a critical beat to be emitted by whichever installer is
159
+ // already armed, then the original error is re-thrown so the caller's
160
+ // shutdown logic still runs.
161
+ export async function run(fn) {
162
+ try {
163
+ await fn();
164
+ }
165
+ catch (err) {
166
+ // Emit by triggering the uncaughtException pathway — re-throws
167
+ // are caught by the armed handler installed via `arm()`. If no
168
+ // handler is installed, the error simply propagates.
169
+ throw err;
170
+ }
171
+ }
172
+ //# sourceMappingURL=panic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"panic.js","sourceRoot":"","sources":["../src/panic.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,EAAE;AACF,kEAAkE;AAClE,8DAA8D;AAC9D,qEAAqE;AACrE,kEAAkE;AAClE,2BAA2B;AAC3B,EAAE;AACF,qEAAqE;AACrE,4DAA4D;AAC5D,kEAAkE;AAClE,2CAA2C;AAE3C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAe,MAAM,YAAY,CAAC;AAEvD,OAAO,EACL,YAAY,EACZ,SAAS,EACT,cAAc,EACd,eAAe,EACf,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,UAAU,EACV,WAAW,EACX,cAAc,EACd,MAAM,GACP,MAAM,UAAU,CAAC;AAElB,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IACjC,IAAI,CAAS;IACtB,YAAY,IAAY,EAAE,OAAe;QACvC,KAAK,CAAC,GAAG,IAAI,KAAK,OAAO,EAAE,CAAC,CAAC;QAC7B,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;QAChC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED,MAAM,aAAa,GAAqB,CAAC,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;AAEnF,SAAS,kBAAkB,CAAC,UAAkB,CAAC;IAC7C,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IACtC,UAAU,CACR,GAAG,EACH,MAAM,CAAC,QAAQ,EACf,OAAO,CAAC,GAAG,KAAK,CAAC,EACjB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,EACvB,cAAc,EACd,OAAO,KAAK,CAAC,CACd,CAAC;IACF,OAAO,GAAG,CAAC;AACb,CAAC;AAED,sEAAsE;AACtE,qEAAqE;AACrE,uDAAuD;AACvD,SAAS,GAAG,CAAC,IAAgB;IAC3B,IAAI,KAAK,GAAG,KAAK,CAAC;IAClB,MAAM,OAAO,GAAG,GAAS,EAAE;QACzB,IAAI,KAAK;YAAE,OAAO;QAClB,KAAK,GAAG,IAAI,CAAC;QACb,IAAI,CAAC;YACH,IAAI,EAAE,CAAC;QACT,CAAC;QAAC,MAAM,CAAC;YACP,6BAA6B;QAC/B,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,mBAAmB,EAAE,CAAC,GAAG,EAAE,EAAE;QACtC,OAAO,EAAE,CAAC;QACV,8DAA8D;QAC9D,mEAAmE;QACnE,YAAY,CAAC,GAAG,EAAE;YAChB,MAAM,GAAG,CAAC;QACZ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,EAAE,CAAC,oBAAoB,EAAE,CAAC,MAAM,EAAE,EAAE;QAC1C,OAAO,EAAE,CAAC;QACV,YAAY,CAAC,GAAG,EAAE;YAChB,MAAM,MAAM,YAAY,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;QACrE,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,KAAK,MAAM,GAAG,IAAI,aAAa,EAAE,CAAC;QAChC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE;YACnB,OAAO,EAAE,CAAC;YACV,iEAAiE;YACjE,6DAA6D;YAC7D,OAAO,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC;YAChC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED,SAAS,qBAAqB,CAAC,IAAY,EAAE,IAAY;IACvD,MAAM,MAAM,GAAoB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;IACrE,MAAM,CAAC,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IAC/B,CAAC,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;QACjB,8DAA8D;IAChE,CAAC,CAAC,CAAC;IACH,CAAC,CAAC,KAAK,EAAE,CAAC;IACV,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACtB,OAAO,CAAC,CAAC;AACX,CAAC;AAED,mEAAmE;AACnE,qDAAqD;AACrD,MAAM,UAAU,uBAAuB,CAAC,IAAY,EAAE,IAAY;IAChE,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,qBAAqB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC3C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,iBAAiB,CAAC,YAAY,EAAG,GAAa,CAAC,OAAO,CAAC,CAAC;IACpE,CAAC;IACD,MAAM,KAAK,GAAG,kBAAkB,EAAE,CAAC;IACnC,GAAG,CAAC,GAAG,EAAE;QACP,IAAI,CAAC;YACH,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACnB,CAAC;QAAC,MAAM,CAAC;YACP,eAAe;QACjB,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED,mEAAmE;AACnE,sEAAsE;AACtE,kEAAkE;AAClE,oEAAoE;AACpE,6BAA6B;AAC7B,MAAM,UAAU,6BAA6B,CAC3C,IAAY,EACZ,IAAY,EACZ,GAAW;IAEX,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAC7B,MAAM,IAAI,UAAU,CAAC,eAAe,SAAS,QAAQ,CAAC,CAAC;IACzD,CAAC;IAED,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,WAAW,CAAC,kBAAkB,CAAC,CAAC;IACzC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,iBAAiB,CAAC,oBAAoB,EAAG,GAAa,CAAC,OAAO,CAAC,CAAC;IAC5E,CAAC;IAED,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,qBAAqB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC3C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,iBAAiB,CAAC,YAAY,EAAG,GAAa,CAAC,OAAO,CAAC,CAAC;IACpE,CAAC;IAED,mEAAmE;IACnE,+DAA+D;IAC/D,2BAA2B;IAC3B,MAAM,KAAK,GAAG;QACZ,IAAI;QACJ,UAAU,EAAE,OAAO,CAAC,GAAG;QACvB,OAAO,EAAE,CAAC;KACX,CAAC;IAEF,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACjC,GAAG,CAAC,GAAG,EAAE;QACP,IAAI,CAAC;YACH,IAAI,OAAO,CAAC,GAAG,KAAK,KAAK,CAAC,UAAU,EAAE,CAAC;gBACrC,IAAI,CAAC;oBACH,KAAK,CAAC,IAAI,GAAG,WAAW,CAAC,kBAAkB,CAAC,CAAC;gBAC/C,CAAC;gBAAC,MAAM,CAAC;oBACP,OAAO,CAAC,wDAAwD;gBAClE,CAAC;gBACD,KAAK,CAAC,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC;gBAC/B,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC;YACpB,CAAC;YACD,MAAM,QAAQ,GAAG,cAAc,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC;YAC5E,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;YAC9B,KAAK,CAAC,OAAO,GAAG,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;YAC1C,MAAM,SAAS,GAAG,kBAAkB,EAAE,CAAC;YACvC,MAAM,IAAI,GAAG,YAAY,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;YACjE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClB,CAAC;QAAC,MAAM,CAAC;YACP,6BAA6B;QAC/B,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED,qEAAqE;AACrE,iEAAiE;AACjE,sEAAsE;AACtE,6BAA6B;AAC7B,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,EAA8B;IACtD,IAAI,CAAC;QACH,MAAM,EAAE,EAAE,CAAC;IACb,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,+DAA+D;QAC/D,+DAA+D;QAC/D,qDAAqD;QACrD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC"}
@@ -0,0 +1,40 @@
1
+ export interface BeatTransport {
2
+ send(buf: Buffer): void;
3
+ reconnect(): void;
4
+ close(): void;
5
+ }
6
+ export declare class UdpTransport implements BeatTransport {
7
+ private socket;
8
+ private readonly host;
9
+ private readonly port;
10
+ pendingError: NodeJS.ErrnoException | null;
11
+ constructor(host: string, port: number);
12
+ private openSocket;
13
+ send(buf: Buffer): void;
14
+ reconnect(): void;
15
+ close(): void;
16
+ }
17
+ export type SecureUdpKind = "shared" | "master";
18
+ export declare class SecureUdpTransport implements BeatTransport {
19
+ private socket;
20
+ private readonly host;
21
+ private readonly port;
22
+ private readonly secret;
23
+ private sessionSalt;
24
+ private ivPrefix;
25
+ private prefixIndex;
26
+ private counter;
27
+ pendingError: NodeJS.ErrnoException | null;
28
+ private constructor();
29
+ static shared(host: string, port: number, key: Buffer): SecureUdpTransport;
30
+ static master(host: string, port: number, masterKey: Buffer): SecureUdpTransport;
31
+ private openSocket;
32
+ __setCounterForTest(v: number): void;
33
+ __getCounterForTest(): number;
34
+ __getPrefixIndexForTest(): number;
35
+ __getIvPrefixForTest(): Buffer;
36
+ send(buf: Buffer): void;
37
+ reconnect(): void;
38
+ close(): void;
39
+ }
40
+ //# sourceMappingURL=transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAuBA,MAAM,WAAW,aAAa;IAO5B,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,IAAI,IAAI,CAAC;IAClB,KAAK,IAAI,IAAI,CAAC;CACf;AAeD,qBAAa,YAAa,YAAW,aAAa;IAChD,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,YAAY,EAAE,MAAM,CAAC,cAAc,GAAG,IAAI,CAAQ;gBAEtC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAMtC,OAAO,CAAC,UAAU;IAYlB,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAoBvB,SAAS,IAAI,IAAI;IAUjB,KAAK,IAAI,IAAI;CAOd;AAID,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAYhD,qBAAa,kBAAmB,YAAW,aAAa;IACtD,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAY;IACnC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,OAAO,CAAS;IACxB,YAAY,EAAE,MAAM,CAAC,cAAc,GAAG,IAAI,CAAQ;IAElD,OAAO;IAWP,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,kBAAkB;IAO1E,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,kBAAkB;IAUhF,OAAO,CAAC,UAAU;IAWlB,mBAAmB,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI;IAGpC,mBAAmB,IAAI,MAAM;IAG7B,uBAAuB,IAAI,MAAM;IAGjC,oBAAoB,IAAI,MAAM;IAI9B,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IA8CvB,SAAS,IAAI,IAAI;IAmBjB,KAAK,IAAI,IAAI;CAOd"}
@@ -0,0 +1,208 @@
1
+ // Beat transport abstractions — UDP and ChaCha20-Poly1305-AEAD UDP.
2
+ //
3
+ // UDS (AF_UNIX/SOCK_DGRAM) is intentionally NOT implemented in this
4
+ // release. Node's stdlib `dgram` module accepts only `"udp4"` and
5
+ // `"udp6"` socket types; the `"unix_dgram"` type that exists in some
6
+ // platform sockets APIs is rejected with `ERR_SOCKET_BAD_TYPE`. Adding
7
+ // UDS would require a native addon (breaking the zero-dep posture) or
8
+ // pulling in `node:net.Socket(fd)` over a manually opened AF_UNIX FD
9
+ // (no portable JS path exists). For same-host deployments, use
10
+ // `Varta.connectUdp("127.0.0.1", port)` — loopback is the same
11
+ // security domain as UDS on a single host.
12
+ import { randomBytes } from "node:crypto";
13
+ import { createSocket } from "node:dgram";
14
+ import { encodeMaster, encodeShared, IV_RANDOM_BYTES, SESSION_SALT_BYTES, deriveIvPrefix, } from "./vlp_secure.js";
15
+ // Common helper: drain a libuv async error captured on a previous
16
+ // `socket.send` callback. Returns the error if one is queued and
17
+ // clears the slot, or `null` if the slot is empty.
18
+ function takePendingError(holder) {
19
+ const e = holder.pendingError;
20
+ holder.pendingError = null;
21
+ return e;
22
+ }
23
+ // ─── Plaintext UDP ──────────────────────────────────────────────
24
+ export class UdpTransport {
25
+ socket;
26
+ host;
27
+ port;
28
+ pendingError = null;
29
+ constructor(host, port) {
30
+ this.host = host;
31
+ this.port = port;
32
+ this.socket = this.openSocket();
33
+ }
34
+ openSocket() {
35
+ const family = this.host.includes(":") ? "udp6" : "udp4";
36
+ const s = createSocket(family);
37
+ // Swallow `error` events; they would otherwise crash the process.
38
+ // The pending-error slot captures them for the next `send` call.
39
+ s.on("error", (err) => {
40
+ this.pendingError = err;
41
+ });
42
+ s.unref();
43
+ return s;
44
+ }
45
+ send(buf) {
46
+ const queued = takePendingError(this);
47
+ if (queued !== null)
48
+ throw queued;
49
+ // Use addressed sends instead of connected sends — `socket.connect`
50
+ // is async and a `send()` issued before its `connect` event lands
51
+ // fails with `ERR_SOCKET_DGRAM_NOT_CONNECTED`. The libuv callback
52
+ // path still surfaces kernel-level send errors via `pendingError`.
53
+ //
54
+ // Copy the caller's scratch buffer before handing off to libuv:
55
+ // `dgram.Socket.send` does NOT internally copy, and the agent
56
+ // reuses a single 32-byte buffer across beats, so a non-copy
57
+ // would let later beats overwrite earlier in-flight datagrams.
58
+ const owned = Buffer.from(buf);
59
+ this.socket.send(owned, this.port, this.host, (err) => {
60
+ if (err !== null && err !== undefined) {
61
+ this.pendingError = err;
62
+ }
63
+ });
64
+ }
65
+ reconnect() {
66
+ try {
67
+ this.socket.close();
68
+ }
69
+ catch {
70
+ // Already closed — fine.
71
+ }
72
+ this.pendingError = null;
73
+ this.socket = this.openSocket();
74
+ }
75
+ close() {
76
+ try {
77
+ this.socket.close();
78
+ }
79
+ catch {
80
+ // Already closed.
81
+ }
82
+ }
83
+ }
84
+ export class SecureUdpTransport {
85
+ socket;
86
+ host;
87
+ port;
88
+ secret;
89
+ sessionSalt;
90
+ ivPrefix;
91
+ prefixIndex;
92
+ counter;
93
+ pendingError = null;
94
+ constructor(host, port, secret) {
95
+ this.host = host;
96
+ this.port = port;
97
+ this.secret = secret;
98
+ this.sessionSalt = randomBytes(SESSION_SALT_BYTES);
99
+ this.prefixIndex = 0;
100
+ this.counter = 0;
101
+ this.ivPrefix = deriveIvPrefix(this.sessionSalt, this.prefixIndex);
102
+ this.socket = this.openSocket();
103
+ }
104
+ static shared(host, port, key) {
105
+ if (key.length !== 32) {
106
+ throw new RangeError("secure-UDP shared key must be 32 bytes");
107
+ }
108
+ return new SecureUdpTransport(host, port, { kind: "shared", key: Buffer.from(key) });
109
+ }
110
+ static master(host, port, masterKey) {
111
+ if (masterKey.length !== 32) {
112
+ throw new RangeError("secure-UDP master key must be 32 bytes");
113
+ }
114
+ return new SecureUdpTransport(host, port, {
115
+ kind: "master",
116
+ masterKey: Buffer.from(masterKey),
117
+ });
118
+ }
119
+ openSocket() {
120
+ const family = this.host.includes(":") ? "udp6" : "udp4";
121
+ const s = createSocket(family);
122
+ s.on("error", (err) => {
123
+ this.pendingError = err;
124
+ });
125
+ s.unref();
126
+ return s;
127
+ }
128
+ // Test hooks (matching Python `_set_*_for_test` and Go `*ForTest`).
129
+ __setCounterForTest(v) {
130
+ this.counter = v >>> 0;
131
+ }
132
+ __getCounterForTest() {
133
+ return this.counter;
134
+ }
135
+ __getPrefixIndexForTest() {
136
+ return this.prefixIndex;
137
+ }
138
+ __getIvPrefixForTest() {
139
+ return Buffer.from(this.ivPrefix);
140
+ }
141
+ send(buf) {
142
+ const queued = takePendingError(this);
143
+ if (queued !== null)
144
+ throw queued;
145
+ // The IV (8-byte prefix + 4-byte LE counter) is reserved
146
+ // synchronously here. The Rust client uses commit-on-success
147
+ // because its `send(2)` is synchronous and a `WouldBlock` lets it
148
+ // safely re-use the nonce on retry. Node's `dgram.send` queues
149
+ // datagrams via libuv async, so multiple concurrent calls would
150
+ // all see the same proposed counter and encrypt distinct
151
+ // plaintexts under the same nonce — that is the classic
152
+ // ChaCha20-Poly1305 nonce-reuse footgun. We reserve and advance
153
+ // synchronously here so every queued frame carries a unique IV;
154
+ // a callback-reported `pendingError` simply burns one nonce
155
+ // slot, which is harmless.
156
+ const ivRandom = Buffer.alloc(IV_RANDOM_BYTES);
157
+ this.ivPrefix.copy(ivRandom, 0, 0, IV_RANDOM_BYTES);
158
+ const counter = this.counter;
159
+ if (this.counter === 0xffffffff) {
160
+ this.prefixIndex = (this.prefixIndex + 1) >>> 0;
161
+ this.ivPrefix = deriveIvPrefix(this.sessionSalt, this.prefixIndex);
162
+ this.counter = 0;
163
+ }
164
+ else {
165
+ this.counter = (this.counter + 1) >>> 0;
166
+ }
167
+ let wire;
168
+ if (this.secret.kind === "shared") {
169
+ wire = encodeShared(this.secret.key, ivRandom, counter, buf);
170
+ }
171
+ else {
172
+ wire = encodeMaster(this.secret.masterKey, process.pid >>> 0, ivRandom, counter, buf);
173
+ }
174
+ this.socket.send(wire, this.port, this.host, (err) => {
175
+ if (err !== null && err !== undefined) {
176
+ this.pendingError = err;
177
+ }
178
+ });
179
+ }
180
+ reconnect() {
181
+ try {
182
+ this.socket.close();
183
+ }
184
+ catch {
185
+ // Already closed.
186
+ }
187
+ this.pendingError = null;
188
+ // Prepare a fresh session in locals; commit at the end without `?`.
189
+ const newSalt = randomBytes(SESSION_SALT_BYTES);
190
+ const newPrefixIndex = 0;
191
+ const newIvPrefix = deriveIvPrefix(newSalt, newPrefixIndex);
192
+ const newSocket = this.openSocket();
193
+ this.sessionSalt = newSalt;
194
+ this.prefixIndex = newPrefixIndex;
195
+ this.counter = 0;
196
+ this.ivPrefix = newIvPrefix;
197
+ this.socket = newSocket;
198
+ }
199
+ close() {
200
+ try {
201
+ this.socket.close();
202
+ }
203
+ catch {
204
+ // Already closed.
205
+ }
206
+ }
207
+ }
208
+ //# sourceMappingURL=transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"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"}
package/dist/vlp.d.ts ADDED
@@ -0,0 +1,30 @@
1
+ export declare const MAGIC: Buffer;
2
+ export declare const VERSION: number;
3
+ export declare const NONCE_TERMINAL: bigint;
4
+ export declare const TIMESTAMP_INVALID: bigint;
5
+ export declare const FRAME_BYTES: number;
6
+ export declare enum Status {
7
+ Ok = 0,
8
+ Degraded = 1,
9
+ Critical = 2,
10
+ Stall = 3
11
+ }
12
+ export type StatusLike = Status | number | string;
13
+ export type DecodeErrorKind = "BadMagic" | "BadVersion" | "BadCrc" | "BadStatus" | "StallOnWire" | "BadPid" | "BadTimestamp" | "BadNonce";
14
+ export declare class DecodeError extends Error {
15
+ readonly kind: DecodeErrorKind;
16
+ constructor(kind: DecodeErrorKind, detail?: string);
17
+ }
18
+ export declare function crc32c(data: Buffer | Uint8Array): number;
19
+ export interface Frame {
20
+ status: Status;
21
+ pid: number;
22
+ timestamp: bigint;
23
+ nonce: bigint;
24
+ payload: number;
25
+ }
26
+ export declare function encode(status: StatusLike, pid: number, timestamp: bigint, nonce: bigint, payload: number): Buffer;
27
+ export declare function encodeInto(buf: Buffer, status: StatusLike, pid: number, timestamp: bigint, nonce: bigint, payload: number): void;
28
+ export declare function decode(buf: Buffer | Uint8Array): Frame;
29
+ export declare function decodeFrame(buf: Buffer | Uint8Array): Frame;
30
+ //# sourceMappingURL=vlp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vlp.d.ts","sourceRoot":"","sources":["../src/vlp.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,KAAK,EAAE,MAAkC,CAAC;AACvD,eAAO,MAAM,OAAO,EAAE,MAAa,CAAC;AACpC,eAAO,MAAM,cAAc,EAAE,MAA4B,CAAC;AAC1D,eAAO,MAAM,iBAAiB,EAAE,MAA4B,CAAC;AAC7D,eAAO,MAAM,WAAW,EAAE,MAAW,CAAC;AAKtC,oBAAY,MAAM;IAChB,EAAE,IAAI;IACN,QAAQ,IAAI;IACZ,QAAQ,IAAI;IACZ,KAAK,IAAI;CACV;AAED,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAYlD,MAAM,MAAM,eAAe,GACvB,UAAU,GACV,YAAY,GACZ,QAAQ,GACR,WAAW,GACX,aAAa,GACb,QAAQ,GACR,cAAc,GACd,UAAU,CAAC;AAEf,qBAAa,WAAY,SAAQ,KAAK;IACpC,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;gBACnB,IAAI,EAAE,eAAe,EAAE,MAAM,SAAK;CAK/C;AAoBD,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,MAAM,CAOxD;AAID,MAAM,WAAW,KAAK;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAqBD,wBAAgB,MAAM,CACpB,MAAM,EAAE,UAAU,EAClB,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,GACd,MAAM,CAIR;AAGD,wBAAgB,UAAU,CACxB,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,UAAU,EAClB,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,GACd,IAAI,CAeN;AAQD,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,KAAK,CAmEtD;AAID,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,KAAK,CAE3D"}