@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.
- package/CHANGELOG.md +41 -0
- package/LICENSE +25 -0
- package/README.md +140 -0
- package/dist/client.d.ts +32 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +187 -0
- package/dist/client.js.map +1 -0
- package/dist/errno.d.ts +11 -0
- package/dist/errno.d.ts.map +1 -0
- package/dist/errno.js +52 -0
- package/dist/errno.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/outcome.d.ts +31 -0
- package/dist/outcome.d.ts.map +1 -0
- package/dist/outcome.js +92 -0
- package/dist/outcome.js.map +1 -0
- package/dist/panic.d.ts +8 -0
- package/dist/panic.d.ts.map +1 -0
- package/dist/panic.js +172 -0
- package/dist/panic.js.map +1 -0
- package/dist/transport.d.ts +40 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +208 -0
- package/dist/transport.js.map +1 -0
- package/dist/vlp.d.ts +30 -0
- package/dist/vlp.d.ts.map +1 -0
- package/dist/vlp.js +159 -0
- package/dist/vlp.js.map +1 -0
- package/dist/vlp_secure.d.ts +17 -0
- package/dist/vlp_secure.d.ts.map +1 -0
- package/dist/vlp_secure.js +158 -0
- package/dist/vlp_secure.js.map +1 -0
- package/package.json +72 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Changelog — Varta Node.js client
|
|
2
|
+
|
|
3
|
+
All notable changes to the Node.js client live here. Versions follow
|
|
4
|
+
[Semantic Versioning](https://semver.org). The wire protocol version is
|
|
5
|
+
governed independently — see `book/src/spec/vlp.md` in the workspace.
|
|
6
|
+
|
|
7
|
+
## [0.1.0] — 2026-05-17
|
|
8
|
+
|
|
9
|
+
Initial release. Production client for the Varta health protocol.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `Varta` agent with `Varta.connectUdp()` and
|
|
14
|
+
`Varta.connectSecureUdp()` / `Varta.connectSecureUdpWithMaster()`
|
|
15
|
+
constructors. UDS transport is intentionally deferred to a future
|
|
16
|
+
release — see "Non-goals" in `README.md`.
|
|
17
|
+
- `beat(status, payload)` returning a `BeatOutcome` tagged union
|
|
18
|
+
(`sent` / `dropped` / `failed`) with the four-way `DropReason`
|
|
19
|
+
taxonomy mirroring the Rust, Python, and Go clients.
|
|
20
|
+
- `classifySendError(err)` exported for custom transport authors.
|
|
21
|
+
- Saturating counters `clockRegressions()` and `forkRecoveries()`
|
|
22
|
+
(returned as `bigint`).
|
|
23
|
+
- Fork auto-detection: a PID change between connect and the next
|
|
24
|
+
`beat()` triggers a transparent `reconnect()` so secure-UDP IV
|
|
25
|
+
state is rotated before any frame leaves the child process.
|
|
26
|
+
- `panic.installSignalHandlerUdp` / `installSignalHandlerSecureUdp`
|
|
27
|
+
— emit a `Status.Critical` frame with `nonce=NONCE_TERMINAL` on
|
|
28
|
+
uncaught exceptions, unhandled rejections, or terminating signals.
|
|
29
|
+
- `panic.run(fn)` defer/recover-style wrapper.
|
|
30
|
+
- Wire-format conformance against `tools/vlp-test-vectors.json`
|
|
31
|
+
(CRC-32C, base frames, HKDF derivations, AEAD seal/open).
|
|
32
|
+
- Full TypeScript types shipped (`.d.ts`); zero npm runtime
|
|
33
|
+
dependencies — ChaCha20-Poly1305 and HKDF-SHA256 come from
|
|
34
|
+
Node's built-in `node:crypto`.
|
|
35
|
+
|
|
36
|
+
### Stability
|
|
37
|
+
|
|
38
|
+
- Wire format: VLP v0.2, governed by `book/src/spec/vlp.md`.
|
|
39
|
+
- Node.js API: 0.x — refinements may land without deprecation cycles
|
|
40
|
+
until 1.0.
|
|
41
|
+
- Minimum Node.js version: 18 LTS.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
This Node.js client is part of the Varta project and is distributed under
|
|
2
|
+
the same terms as the workspace: MIT OR Apache-2.0, at the user's option.
|
|
3
|
+
|
|
4
|
+
----------------------------------------------------------------------
|
|
5
|
+
MIT License
|
|
6
|
+
----------------------------------------------------------------------
|
|
7
|
+
|
|
8
|
+
Permission is hereby granted, free of charge, to any person obtaining a
|
|
9
|
+
copy of this software and associated documentation files (the
|
|
10
|
+
"Software"), to deal in the Software without restriction, including
|
|
11
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
12
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
13
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
14
|
+
the following conditions:
|
|
15
|
+
|
|
16
|
+
The above copyright notice and this permission notice shall be included
|
|
17
|
+
in all copies or substantial portions of the Software.
|
|
18
|
+
|
|
19
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
20
|
+
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
21
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
22
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
23
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
24
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
25
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# Varta — Node.js client
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@varta/client)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
|
|
6
|
+
Production Node.js client for the [Varta](https://github.com/aramirez087/Varta)
|
|
7
|
+
health protocol. Emits 32-byte VLP heartbeats to a `varta-watch` observer
|
|
8
|
+
over plaintext UDP or ChaCha20-Poly1305-encrypted UDP. Written in
|
|
9
|
+
TypeScript; ships compiled `.js` + `.d.ts`. Zero npm runtime
|
|
10
|
+
dependencies — the AEAD primitives come from Node's built-in
|
|
11
|
+
`node:crypto`.
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install @varta/client
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quickstart
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import { Varta, Status } from "@varta/client";
|
|
21
|
+
|
|
22
|
+
const agent = await Varta.connectUdp("127.0.0.1", 5876);
|
|
23
|
+
setInterval(() => {
|
|
24
|
+
const outcome = agent.beat(Status.Ok);
|
|
25
|
+
if (outcome.kind === "dropped") {
|
|
26
|
+
// Observer absent, kernel queue full, peer gone, or disk full.
|
|
27
|
+
// Treat as a no-op; the next beat will retry.
|
|
28
|
+
}
|
|
29
|
+
}, 500);
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## API parity with `varta-client` (Rust)
|
|
33
|
+
|
|
34
|
+
| Rust | Node.js |
|
|
35
|
+
| --------------------------------------------------- | --------------------------------------------------------------------------- |
|
|
36
|
+
| `Varta::connect(path)` (UDS) | _Not supported in 0.1.0_ — see "Non-goals" below |
|
|
37
|
+
| `Varta::connect_udp(addr)` | `Varta.connectUdp(host, port)` |
|
|
38
|
+
| `Varta::connect_secure_udp(addr, key)` | `Varta.connectSecureUdp(host, port, key)` |
|
|
39
|
+
| `Varta::connect_secure_udp_with_master(addr, mkey)` | `Varta.connectSecureUdpWithMaster(host, port, masterKey)` |
|
|
40
|
+
| `Varta::beat(status, payload) -> BeatOutcome` | `Varta.beat(status, payload) -> BeatOutcome` |
|
|
41
|
+
| `BeatOutcome::{Sent, Dropped, Failed}` | `BeatOutcome` (discriminated union: `{ kind: "sent" \| "dropped" \| "failed" }`) |
|
|
42
|
+
| `DropReason::{KernelQueueFull, NoObserver, PeerGone, StorageFull}` | `DropReason` enum — same four variants |
|
|
43
|
+
| `BeatError { errno, kind }` | `BeatError extends Error` with `errno` and `kind` fields |
|
|
44
|
+
| `classify_send_error` | `classifySendError(err)` |
|
|
45
|
+
| `Varta::reconnect`, `set_reconnect_after` | `reconnect()`, `setReconnectAfter(n)` |
|
|
46
|
+
| `Varta::clock_regressions()`, `fork_recoveries()` | `clockRegressions()`, `forkRecoveries()` — return `bigint` |
|
|
47
|
+
| `install_panic_handler*` | `panic.installSignalHandlerUdp` / `installSignalHandlerSecureUdp` |
|
|
48
|
+
| `panic::run` (defer/recover) | `panic.run(fn)` |
|
|
49
|
+
|
|
50
|
+
## Hard invariants
|
|
51
|
+
|
|
52
|
+
The Node.js client preserves the Rust client's wire-level contract:
|
|
53
|
+
|
|
54
|
+
1. **Non-blocking I/O.** Every socket is non-blocking. A
|
|
55
|
+
kernel-queue-full send surfaces as
|
|
56
|
+
`{ kind: "dropped", reason: DropReason.KernelQueueFull }`, never a
|
|
57
|
+
block.
|
|
58
|
+
2. **Per-emission `process.pid`.** No PID caching — forked children
|
|
59
|
+
report their own identity on the next beat. Fork auto-recovery
|
|
60
|
+
refreshes the transport (and, for secure-UDP, re-reads OS entropy
|
|
61
|
+
via `crypto.randomBytes`) before the frame leaves the child.
|
|
62
|
+
3. **Commit-on-success nonces.** Secure-UDP's per-emission IV counter
|
|
63
|
+
advances only after `socket.send` resolves successfully. A
|
|
64
|
+
dropped beat does NOT consume a nonce, eliminating cross-fork
|
|
65
|
+
nonce reuse.
|
|
66
|
+
4. **Wire-format conformance.** The package ships a test that loads
|
|
67
|
+
`tools/vlp-test-vectors.json` (the same fixture the Rust crate
|
|
68
|
+
verifies against) and asserts byte-equality for every CRC, frame,
|
|
69
|
+
and AEAD vector. Drift between languages is impossible without
|
|
70
|
+
breaking both tests in the same PR.
|
|
71
|
+
|
|
72
|
+
## Non-goals (0.1.0)
|
|
73
|
+
|
|
74
|
+
- **Unix Domain Sockets.** Node's stdlib does not expose `AF_UNIX` /
|
|
75
|
+
`SOCK_DGRAM`; only stream-mode `unix:` sockets are reachable from
|
|
76
|
+
`node:net`. Shipping UDS support would require a native addon and
|
|
77
|
+
break the zero-dep posture. For same-host deployments use
|
|
78
|
+
`Varta.connectUdp("127.0.0.1", port)` — loopback is the same
|
|
79
|
+
security domain. If you need authenticated same-host transport,
|
|
80
|
+
use `Varta.connectSecureUdp` against `127.0.0.1` with a key
|
|
81
|
+
configured on the observer.
|
|
82
|
+
- **`accept-degraded-entropy` secure-UDP variant.** Reserved for
|
|
83
|
+
embedded targets that lack `/dev/urandom`; Node itself does not
|
|
84
|
+
run on such targets.
|
|
85
|
+
- **Browser support.** This package targets Node.js ≥ 18 LTS only.
|
|
86
|
+
It uses `node:dgram`, `node:crypto`, `node:os`, and `node:process`.
|
|
87
|
+
|
|
88
|
+
## Latency note
|
|
89
|
+
|
|
90
|
+
Node cannot match the ~1 µs-per-beat budget of the Rust client.
|
|
91
|
+
Measured cost on a modern x86_64 host is **~5–15 µs per `beat()`**
|
|
92
|
+
including frame allocation, UDP `send`, and outcome dispatch. The
|
|
93
|
+
Node client is intended for tooling, batch jobs, Express/Fastify
|
|
94
|
+
sidecars, and process supervisors — not for tight inner loops
|
|
95
|
+
emitting kilo-beats per second.
|
|
96
|
+
|
|
97
|
+
## Secure UDP
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
import { Varta, Status } from "@varta/client";
|
|
101
|
+
import { readFileSync } from "node:fs";
|
|
102
|
+
|
|
103
|
+
const key = readFileSync("/etc/varta/secure.key"); // 32 raw bytes
|
|
104
|
+
const agent = await Varta.connectSecureUdp("127.0.0.1", 5876, key);
|
|
105
|
+
agent.beat(Status.Ok);
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
ChaCha20-Poly1305 and HKDF-SHA256 are stdlib in Node ≥ 15.0; no
|
|
109
|
+
extra install is required.
|
|
110
|
+
|
|
111
|
+
## Panic hook
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
import { panic } from "@varta/client";
|
|
115
|
+
|
|
116
|
+
panic.installSignalHandlerUdp("127.0.0.1", 5876);
|
|
117
|
+
// any uncaught exception, unhandled rejection, or terminating
|
|
118
|
+
// signal (SIGTERM/SIGINT/SIGQUIT/SIGHUP) now emits a Critical beat
|
|
119
|
+
// with nonce=NONCE_TERMINAL before the process exits.
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
For deferred panic emission inside an async pipeline:
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
await panic.run(async () => {
|
|
126
|
+
await mainLoop(); // any throw inside emits Critical, then re-throws
|
|
127
|
+
});
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The handler pre-binds its socket at install time so emission is
|
|
131
|
+
async-signal-safe — no allocation or DNS in the hot path.
|
|
132
|
+
|
|
133
|
+
## Stability
|
|
134
|
+
|
|
135
|
+
- **Wire format:** VLP v0.2, governed by `book/src/spec/vlp.md` in
|
|
136
|
+
the workspace. Cross-language byte-equality is enforced by the
|
|
137
|
+
conformance test suite.
|
|
138
|
+
- **Node API:** 0.x — refinements may land without deprecation
|
|
139
|
+
cycles until 1.0.
|
|
140
|
+
- **Node version:** 18 LTS minimum. CI runs against Node 18, 20, 22.
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { DropReason, type BeatOutcome } from "./outcome.js";
|
|
2
|
+
import { type BeatTransport } from "./transport.js";
|
|
3
|
+
import { Status, type StatusLike } from "./vlp.js";
|
|
4
|
+
export declare function __setMonotonicForTest(fn: (() => bigint) | null): void;
|
|
5
|
+
export declare class Varta {
|
|
6
|
+
private transport;
|
|
7
|
+
private readonly buf;
|
|
8
|
+
private startNs;
|
|
9
|
+
private nonce;
|
|
10
|
+
private consecutiveDropped;
|
|
11
|
+
private reconnectAfter;
|
|
12
|
+
private lastTimestamp;
|
|
13
|
+
private clockRegressionsCount;
|
|
14
|
+
private connectPid;
|
|
15
|
+
private forkRecoveriesCount;
|
|
16
|
+
private constructor();
|
|
17
|
+
static connectUdp(host: string, port: number): Varta;
|
|
18
|
+
static connectSecureUdp(host: string, port: number, key: Buffer): Varta;
|
|
19
|
+
static connectSecureUdpWithMaster(host: string, port: number, masterKey: Buffer): Varta;
|
|
20
|
+
static fromTransport(transport: BeatTransport): Varta;
|
|
21
|
+
beat(status: StatusLike, payload?: number): BeatOutcome;
|
|
22
|
+
reconnect(): void;
|
|
23
|
+
setReconnectAfter(n: number | null): void;
|
|
24
|
+
clockRegressions(): bigint;
|
|
25
|
+
forkRecoveries(): bigint;
|
|
26
|
+
close(): void;
|
|
27
|
+
private sendFrame;
|
|
28
|
+
__setConnectPidForTest(pid: number): void;
|
|
29
|
+
__setNonceForTest(value: bigint): void;
|
|
30
|
+
}
|
|
31
|
+
export { Status, DropReason };
|
|
32
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAqBA,OAAO,EAIL,UAAU,EACV,KAAK,WAAW,EACjB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,KAAK,aAAa,EAGnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAIL,MAAM,EACN,KAAK,UAAU,EAChB,MAAM,UAAU,CAAC;AAyBlB,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,CAAC,MAAM,MAAM,CAAC,GAAG,IAAI,GAAG,IAAI,CAErE;AAED,qBAAa,KAAK;IAChB,OAAO,CAAC,SAAS,CAAgB;IACjC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,kBAAkB,CAAS;IACnC,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,qBAAqB,CAAS;IACtC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,mBAAmB,CAAS;IAEpC,OAAO;IAeP,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,KAAK;IAIpD,MAAM,CAAC,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,KAAK;IAIvE,MAAM,CAAC,0BAA0B,CAC/B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,GAChB,KAAK;IAMR,MAAM,CAAC,aAAa,CAAC,SAAS,EAAE,aAAa,GAAG,KAAK;IAMrD,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,GAAE,MAAU,GAAG,WAAW;IAgE1D,SAAS,IAAI,IAAI;IAKjB,iBAAiB,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAOzC,gBAAgB,IAAI,MAAM;IAM1B,cAAc,IAAI,MAAM;IAIxB,KAAK,IAAI,IAAI;IAMb,OAAO,CAAC,SAAS;IAWjB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIzC,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;CAGvC;AAGD,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
// Agent surface — `Varta` connects to the observer and emits
|
|
2
|
+
// fire-and-forget 32-byte VLP frames.
|
|
3
|
+
//
|
|
4
|
+
// Mirrors the Rust reference at `crates/varta-client/src/client.rs`
|
|
5
|
+
// and the Python/Go ports under `clients/{python,go}/`. Hot-path
|
|
6
|
+
// invariants preserved:
|
|
7
|
+
//
|
|
8
|
+
// * Non-blocking I/O. Node's libuv enqueues to the kernel; any
|
|
9
|
+
// `ENOBUFS` / `EAGAIN` surfaces on the next beat through the
|
|
10
|
+
// transport's `pendingError` slot.
|
|
11
|
+
// * Per-emission `process.pid`. No PID caching — forked children
|
|
12
|
+
// report their own identity on the next beat.
|
|
13
|
+
// * Fork auto-detection. On PID mismatch we call
|
|
14
|
+
// `transport.reconnect()` BEFORE encoding the frame; for
|
|
15
|
+
// secure-UDP that re-reads `crypto.randomBytes` so IV state is
|
|
16
|
+
// rotated before any frame leaves the child.
|
|
17
|
+
// * Clock-regression detection runs BEFORE the monotonic clamp so
|
|
18
|
+
// wire-format monotonicity is preserved while the underlying
|
|
19
|
+
// event is observable.
|
|
20
|
+
// * Nonce wraps with a single-shot stderr warning, never silently.
|
|
21
|
+
import { BeatError, BeatOutcomes, classifySendError, DropReason, } from "./outcome.js";
|
|
22
|
+
import { SecureUdpTransport, UdpTransport, } from "./transport.js";
|
|
23
|
+
import { encodeInto, FRAME_BYTES, NONCE_TERMINAL, Status, } from "./vlp.js";
|
|
24
|
+
const U64_MAX = 0xffffffffffffffffn;
|
|
25
|
+
function satAddBig(value, delta) {
|
|
26
|
+
const next = value + delta;
|
|
27
|
+
return next > U64_MAX ? U64_MAX : next;
|
|
28
|
+
}
|
|
29
|
+
let nonceWrapWarned = false;
|
|
30
|
+
function warnNonceWrapping() {
|
|
31
|
+
if (nonceWrapWarned)
|
|
32
|
+
return;
|
|
33
|
+
nonceWrapWarned = true;
|
|
34
|
+
try {
|
|
35
|
+
process.stderr.write("[varta] nonce exhausted; wrapping to 0\n");
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// stderr unavailable — give up silently.
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// `process.hrtime.bigint()` is monotonic and unaffected by NTP slew.
|
|
42
|
+
// We expose this through a tiny indirection so unit tests can clamp the
|
|
43
|
+
// clock without touching the global.
|
|
44
|
+
let monotonicNs = () => process.hrtime.bigint();
|
|
45
|
+
export function __setMonotonicForTest(fn) {
|
|
46
|
+
monotonicNs = fn ?? (() => process.hrtime.bigint());
|
|
47
|
+
}
|
|
48
|
+
export class Varta {
|
|
49
|
+
transport;
|
|
50
|
+
buf;
|
|
51
|
+
startNs;
|
|
52
|
+
nonce;
|
|
53
|
+
consecutiveDropped;
|
|
54
|
+
reconnectAfter;
|
|
55
|
+
lastTimestamp;
|
|
56
|
+
clockRegressionsCount;
|
|
57
|
+
connectPid;
|
|
58
|
+
forkRecoveriesCount;
|
|
59
|
+
constructor(transport) {
|
|
60
|
+
this.transport = transport;
|
|
61
|
+
this.buf = Buffer.alloc(FRAME_BYTES);
|
|
62
|
+
this.startNs = monotonicNs();
|
|
63
|
+
this.nonce = 0n;
|
|
64
|
+
this.consecutiveDropped = 0;
|
|
65
|
+
this.reconnectAfter = 0;
|
|
66
|
+
this.lastTimestamp = 0n;
|
|
67
|
+
this.clockRegressionsCount = 0n;
|
|
68
|
+
this.connectPid = process.pid;
|
|
69
|
+
this.forkRecoveriesCount = 0n;
|
|
70
|
+
}
|
|
71
|
+
// ─── constructors ─────────────────────────────────────────────
|
|
72
|
+
static connectUdp(host, port) {
|
|
73
|
+
return new Varta(new UdpTransport(host, port));
|
|
74
|
+
}
|
|
75
|
+
static connectSecureUdp(host, port, key) {
|
|
76
|
+
return new Varta(SecureUdpTransport.shared(host, port, key));
|
|
77
|
+
}
|
|
78
|
+
static connectSecureUdpWithMaster(host, port, masterKey) {
|
|
79
|
+
return new Varta(SecureUdpTransport.master(host, port, masterKey));
|
|
80
|
+
}
|
|
81
|
+
// Lower-level escape hatch for users with a custom `BeatTransport`.
|
|
82
|
+
// Stays unstable in 0.x.
|
|
83
|
+
static fromTransport(transport) {
|
|
84
|
+
return new Varta(transport);
|
|
85
|
+
}
|
|
86
|
+
// ─── public API ───────────────────────────────────────────────
|
|
87
|
+
beat(status, payload = 0) {
|
|
88
|
+
const pid = process.pid;
|
|
89
|
+
if (pid !== this.connectPid) {
|
|
90
|
+
try {
|
|
91
|
+
this.transport.reconnect();
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
return BeatOutcomes.failed(BeatError.fromNodeError(err));
|
|
95
|
+
}
|
|
96
|
+
this.connectPid = pid;
|
|
97
|
+
this.forkRecoveriesCount = satAddBig(this.forkRecoveriesCount, 1n);
|
|
98
|
+
this.nonce = 0n;
|
|
99
|
+
this.startNs = monotonicNs();
|
|
100
|
+
this.lastTimestamp = 0n;
|
|
101
|
+
this.consecutiveDropped = 0;
|
|
102
|
+
}
|
|
103
|
+
if (this.nonce < NONCE_TERMINAL - 1n) {
|
|
104
|
+
this.nonce = this.nonce + 1n;
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
warnNonceWrapping();
|
|
108
|
+
this.nonce = 0n;
|
|
109
|
+
}
|
|
110
|
+
let rawElapsed = monotonicNs() - this.startNs;
|
|
111
|
+
if (rawElapsed < 0n)
|
|
112
|
+
rawElapsed = 0n;
|
|
113
|
+
if (rawElapsed > U64_MAX)
|
|
114
|
+
rawElapsed = U64_MAX;
|
|
115
|
+
if (rawElapsed < this.lastTimestamp) {
|
|
116
|
+
this.clockRegressionsCount = satAddBig(this.clockRegressionsCount, 1n);
|
|
117
|
+
}
|
|
118
|
+
const ts = rawElapsed > this.lastTimestamp ? rawElapsed : this.lastTimestamp;
|
|
119
|
+
this.lastTimestamp = ts;
|
|
120
|
+
encodeInto(this.buf, status, pid, ts, this.nonce, payload);
|
|
121
|
+
const outcome = this.sendFrame();
|
|
122
|
+
if (outcome.kind === "dropped") {
|
|
123
|
+
this.consecutiveDropped = Math.min(this.consecutiveDropped + 1, Number.MAX_SAFE_INTEGER);
|
|
124
|
+
if (this.reconnectAfter > 0 &&
|
|
125
|
+
this.consecutiveDropped >= this.reconnectAfter) {
|
|
126
|
+
try {
|
|
127
|
+
this.transport.reconnect();
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
return outcome;
|
|
131
|
+
}
|
|
132
|
+
const retry = this.sendFrame();
|
|
133
|
+
if (retry.kind === "dropped") {
|
|
134
|
+
this.consecutiveDropped = this.reconnectAfter;
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
this.consecutiveDropped = 0;
|
|
138
|
+
}
|
|
139
|
+
return retry;
|
|
140
|
+
}
|
|
141
|
+
return outcome;
|
|
142
|
+
}
|
|
143
|
+
this.consecutiveDropped = 0;
|
|
144
|
+
return outcome;
|
|
145
|
+
}
|
|
146
|
+
reconnect() {
|
|
147
|
+
this.transport.reconnect();
|
|
148
|
+
this.connectPid = process.pid;
|
|
149
|
+
}
|
|
150
|
+
setReconnectAfter(n) {
|
|
151
|
+
this.reconnectAfter = n && n > 0 ? Math.trunc(n) : 0;
|
|
152
|
+
this.consecutiveDropped = 0;
|
|
153
|
+
}
|
|
154
|
+
// Saturating count of platform-clock regressions observed.
|
|
155
|
+
// Suggested Prometheus label: `varta_client_clock_regression_total`.
|
|
156
|
+
clockRegressions() {
|
|
157
|
+
return this.clockRegressionsCount;
|
|
158
|
+
}
|
|
159
|
+
// Saturating count of fork auto-recovery events.
|
|
160
|
+
// Suggested Prometheus label: `varta_client_fork_recoveries_total`.
|
|
161
|
+
forkRecoveries() {
|
|
162
|
+
return this.forkRecoveriesCount;
|
|
163
|
+
}
|
|
164
|
+
close() {
|
|
165
|
+
this.transport.close();
|
|
166
|
+
}
|
|
167
|
+
// ─── internal ─────────────────────────────────────────────────
|
|
168
|
+
sendFrame() {
|
|
169
|
+
try {
|
|
170
|
+
this.transport.send(this.buf);
|
|
171
|
+
return BeatOutcomes.sent();
|
|
172
|
+
}
|
|
173
|
+
catch (err) {
|
|
174
|
+
return classifySendError(err);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
// ─── test hooks (underscore-prefixed; not part of the public surface) ─
|
|
178
|
+
__setConnectPidForTest(pid) {
|
|
179
|
+
this.connectPid = pid >>> 0;
|
|
180
|
+
}
|
|
181
|
+
__setNonceForTest(value) {
|
|
182
|
+
this.nonce = value;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// Re-export Status for ergonomic call sites: `agent.beat(Status.Ok)`.
|
|
186
|
+
export { Status, DropReason };
|
|
187
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/errno.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare const ENOBUFS: number;
|
|
2
|
+
export declare const ENOSPC: number | undefined;
|
|
3
|
+
export declare const EAGAIN: number | undefined;
|
|
4
|
+
export declare const EWOULDBLOCK: number | undefined;
|
|
5
|
+
export declare const ECONNREFUSED: number | undefined;
|
|
6
|
+
export declare const ECONNRESET: number | undefined;
|
|
7
|
+
export declare const ENOTCONN: number | undefined;
|
|
8
|
+
export declare const EPIPE: number | undefined;
|
|
9
|
+
export declare const ENOENT: number | undefined;
|
|
10
|
+
export declare function errnoName(code: number | null | undefined): string;
|
|
11
|
+
//# sourceMappingURL=errno.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errno.d.ts","sourceRoot":"","sources":["../src/errno.ts"],"names":[],"mappings":"AA6BA,eAAO,MAAM,OAAO,QAAkB,CAAC;AACvC,eAAO,MAAM,MAAM,oBAAe,CAAC;AACnC,eAAO,MAAM,MAAM,oBAAe,CAAC;AACnC,eAAO,MAAM,WAAW,oBAAoC,CAAC;AAC7D,eAAO,MAAM,YAAY,oBAAqB,CAAC;AAC/C,eAAO,MAAM,UAAU,oBAAmB,CAAC;AAC3C,eAAO,MAAM,QAAQ,oBAAiB,CAAC;AACvC,eAAO,MAAM,KAAK,oBAAc,CAAC;AACjC,eAAO,MAAM,MAAM,oBAAe,CAAC;AAanC,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAGjE"}
|
package/dist/errno.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Platform-specific errno constants for parity with the Rust
|
|
2
|
+
// `varta-client::classify_send_error`. Mirrors Python's `_errno.py`.
|
|
3
|
+
//
|
|
4
|
+
// Node exposes runtime errno values via `os.constants.errno`, but the
|
|
5
|
+
// `ENOBUFS` symbol is not present on every platform's constant table
|
|
6
|
+
// (Linux=105, BSD/macOS=55, illumos/Solaris=132). We hard-code per
|
|
7
|
+
// `process.platform` to match the Rust constants exactly.
|
|
8
|
+
import { constants as osConstants } from "node:os";
|
|
9
|
+
const LINUX_ENOBUFS = 105;
|
|
10
|
+
const BSD_ENOBUFS = 55; // macOS / iOS / FreeBSD / NetBSD / OpenBSD / DragonFly
|
|
11
|
+
const SOLARIS_ENOBUFS = 132;
|
|
12
|
+
function selectEnobufs() {
|
|
13
|
+
const p = process.platform;
|
|
14
|
+
if (p === "linux")
|
|
15
|
+
return LINUX_ENOBUFS;
|
|
16
|
+
if (p === "darwin" || p === "freebsd" || p === "openbsd") {
|
|
17
|
+
return BSD_ENOBUFS;
|
|
18
|
+
}
|
|
19
|
+
if (p === "sunos")
|
|
20
|
+
return SOLARIS_ENOBUFS;
|
|
21
|
+
// Fall back to whatever the running platform exposes — better than
|
|
22
|
+
// silently using the Linux value on an unknown OS.
|
|
23
|
+
const fromOs = osConstants.errno;
|
|
24
|
+
return fromOs.ENOBUFS ?? LINUX_ENOBUFS;
|
|
25
|
+
}
|
|
26
|
+
const errno = osConstants.errno;
|
|
27
|
+
export const ENOBUFS = selectEnobufs();
|
|
28
|
+
export const ENOSPC = errno.ENOSPC;
|
|
29
|
+
export const EAGAIN = errno.EAGAIN;
|
|
30
|
+
export const EWOULDBLOCK = errno.EWOULDBLOCK ?? errno.EAGAIN;
|
|
31
|
+
export const ECONNREFUSED = errno.ECONNREFUSED;
|
|
32
|
+
export const ECONNRESET = errno.ECONNRESET;
|
|
33
|
+
export const ENOTCONN = errno.ENOTCONN;
|
|
34
|
+
export const EPIPE = errno.EPIPE;
|
|
35
|
+
export const ENOENT = errno.ENOENT;
|
|
36
|
+
// Reverse-lookup table for symbolic errno names. Used when surfacing
|
|
37
|
+
// unexpected `BeatOutcome.failed` results so the caller's log line has
|
|
38
|
+
// "ENOENT" instead of just "errno=2".
|
|
39
|
+
const NAME_BY_CODE = (() => {
|
|
40
|
+
const m = new Map();
|
|
41
|
+
for (const [name, code] of Object.entries(errno)) {
|
|
42
|
+
if (!m.has(code))
|
|
43
|
+
m.set(code, name);
|
|
44
|
+
}
|
|
45
|
+
return m;
|
|
46
|
+
})();
|
|
47
|
+
export function errnoName(code) {
|
|
48
|
+
if (code === null || code === undefined || code === 0)
|
|
49
|
+
return "Unknown";
|
|
50
|
+
return NAME_BY_CODE.get(code) ?? `errno_${code}`;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=errno.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errno.js","sourceRoot":"","sources":["../src/errno.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,qEAAqE;AACrE,EAAE;AACF,sEAAsE;AACtE,qEAAqE;AACrE,mEAAmE;AACnE,0DAA0D;AAE1D,OAAO,EAAE,SAAS,IAAI,WAAW,EAAE,MAAM,SAAS,CAAC;AAEnD,MAAM,aAAa,GAAG,GAAG,CAAC;AAC1B,MAAM,WAAW,GAAG,EAAE,CAAC,CAAC,uDAAuD;AAC/E,MAAM,eAAe,GAAG,GAAG,CAAC;AAE5B,SAAS,aAAa;IACpB,MAAM,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC;IAC3B,IAAI,CAAC,KAAK,OAAO;QAAE,OAAO,aAAa,CAAC;IACxC,IAAI,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,SAAS,EAAE,CAAC;QACzD,OAAO,WAAW,CAAC;IACrB,CAAC;IACD,IAAI,CAAC,KAAK,OAAO;QAAE,OAAO,eAAe,CAAC;IAC1C,mEAAmE;IACnE,mDAAmD;IACnD,MAAM,MAAM,GAAG,WAAW,CAAC,KAA+B,CAAC;IAC3D,OAAO,MAAM,CAAC,OAAO,IAAI,aAAa,CAAC;AACzC,CAAC;AAED,MAAM,KAAK,GAAG,WAAW,CAAC,KAA+B,CAAC;AAE1D,MAAM,CAAC,MAAM,OAAO,GAAG,aAAa,EAAE,CAAC;AACvC,MAAM,CAAC,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;AACnC,MAAM,CAAC,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;AACnC,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC,MAAM,CAAC;AAC7D,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,CAAC,YAAY,CAAC;AAC/C,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;AAC3C,MAAM,CAAC,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;AACvC,MAAM,CAAC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;AACjC,MAAM,CAAC,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;AAEnC,qEAAqE;AACrE,uEAAuE;AACvE,sCAAsC;AACtC,MAAM,YAAY,GAAwB,CAAC,GAAG,EAAE;IAC9C,MAAM,CAAC,GAAG,IAAI,GAAG,EAAkB,CAAC;IACpC,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACjD,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,IAAc,CAAC;YAAE,CAAC,CAAC,GAAG,CAAC,IAAc,EAAE,IAAI,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC,CAAC,EAAE,CAAC;AAEL,MAAM,UAAU,SAAS,CAAC,IAA+B;IACvD,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IACxE,OAAO,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,SAAS,IAAI,EAAE,CAAC;AACnD,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { Varta } from "./client.js";
|
|
2
|
+
export { Status, NONCE_TERMINAL, FRAME_BYTES, MAGIC, VERSION, DecodeError, decode, decodeFrame, encode, encodeInto, crc32c, type Frame, type StatusLike, type DecodeErrorKind, } from "./vlp.js";
|
|
3
|
+
export { BeatOutcomes, BeatError, DropReason, classifySendError, isSent, isDropped, isFailed, type BeatOutcome, } from "./outcome.js";
|
|
4
|
+
export { UdpTransport, SecureUdpTransport, type BeatTransport, } from "./transport.js";
|
|
5
|
+
export * as panic from "./panic.js";
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EACL,MAAM,EACN,cAAc,EACd,WAAW,EACX,KAAK,EACL,OAAO,EACP,WAAW,EACX,MAAM,EACN,WAAW,EACX,MAAM,EACN,UAAU,EACV,MAAM,EACN,KAAK,KAAK,EACV,KAAK,UAAU,EACf,KAAK,eAAe,GACrB,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,YAAY,EACZ,SAAS,EACT,UAAU,EACV,iBAAiB,EACjB,MAAM,EACN,SAAS,EACT,QAAQ,EACR,KAAK,WAAW,GACjB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,KAAK,aAAa,GACnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Public surface of `@varta/client`. See `README.md` for the parity
|
|
2
|
+
// table against the Rust, Python, and Go clients.
|
|
3
|
+
export { Varta } from "./client.js";
|
|
4
|
+
export { Status, NONCE_TERMINAL, FRAME_BYTES, MAGIC, VERSION, DecodeError, decode, decodeFrame, encode, encodeInto, crc32c, } from "./vlp.js";
|
|
5
|
+
export { BeatOutcomes, BeatError, DropReason, classifySendError, isSent, isDropped, isFailed, } from "./outcome.js";
|
|
6
|
+
export { UdpTransport, SecureUdpTransport, } from "./transport.js";
|
|
7
|
+
export * as panic from "./panic.js";
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,kDAAkD;AAElD,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EACL,MAAM,EACN,cAAc,EACd,WAAW,EACX,KAAK,EACL,OAAO,EACP,WAAW,EACX,MAAM,EACN,WAAW,EACX,MAAM,EACN,UAAU,EACV,MAAM,GAIP,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,YAAY,EACZ,SAAS,EACT,UAAU,EACV,iBAAiB,EACjB,MAAM,EACN,SAAS,EACT,QAAQ,GAET,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,YAAY,EACZ,kBAAkB,GAEnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export declare enum DropReason {
|
|
2
|
+
KernelQueueFull = "kernel queue full",
|
|
3
|
+
NoObserver = "no observer",
|
|
4
|
+
PeerGone = "peer gone",
|
|
5
|
+
StorageFull = "storage full"
|
|
6
|
+
}
|
|
7
|
+
export declare class BeatError extends Error {
|
|
8
|
+
readonly errno: number;
|
|
9
|
+
readonly kind: string;
|
|
10
|
+
constructor(errno: number, kind: string, message?: string);
|
|
11
|
+
static fromNodeError(err: NodeJS.ErrnoException): BeatError;
|
|
12
|
+
}
|
|
13
|
+
export type BeatOutcome = {
|
|
14
|
+
readonly kind: "sent";
|
|
15
|
+
} | {
|
|
16
|
+
readonly kind: "dropped";
|
|
17
|
+
readonly reason: DropReason;
|
|
18
|
+
} | {
|
|
19
|
+
readonly kind: "failed";
|
|
20
|
+
readonly error: BeatError;
|
|
21
|
+
};
|
|
22
|
+
export declare const BeatOutcomes: Readonly<{
|
|
23
|
+
sent(): BeatOutcome;
|
|
24
|
+
dropped(reason: DropReason): BeatOutcome;
|
|
25
|
+
failed(error: BeatError): BeatOutcome;
|
|
26
|
+
}>;
|
|
27
|
+
export declare function isSent(o: BeatOutcome): boolean;
|
|
28
|
+
export declare function isDropped(o: BeatOutcome): boolean;
|
|
29
|
+
export declare function isFailed(o: BeatOutcome): boolean;
|
|
30
|
+
export declare function classifySendError(err: NodeJS.ErrnoException): BeatOutcome;
|
|
31
|
+
//# sourceMappingURL=outcome.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outcome.d.ts","sourceRoot":"","sources":["../src/outcome.ts"],"names":[],"mappings":"AAoBA,oBAAY,UAAU;IACpB,eAAe,sBAAsB;IACrC,UAAU,gBAAgB;IAC1B,QAAQ,cAAc;IACtB,WAAW,iBAAiB;CAC7B;AAKD,qBAAa,SAAU,SAAQ,KAAK;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBACV,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM;IAOzD,MAAM,CAAC,aAAa,CAAC,GAAG,EAAE,MAAM,CAAC,cAAc,GAAG,SAAS;CAI5D;AAID,MAAM,MAAM,WAAW,GACnB;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACzB;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAA;CAAE,GACzD;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAA;CAAE,CAAC;AAE3D,eAAO,MAAM,YAAY;YACf,WAAW;oBAGH,UAAU,GAAG,WAAW;kBAG1B,SAAS,GAAG,WAAW;EAGrC,CAAC;AAEH,wBAAgB,MAAM,CAAC,CAAC,EAAE,WAAW,GAAG,OAAO,CAE9C;AACD,wBAAgB,SAAS,CAAC,CAAC,EAAE,WAAW,GAAG,OAAO,CAEjD;AACD,wBAAgB,QAAQ,CAAC,CAAC,EAAE,WAAW,GAAG,OAAO,CAEhD;AAOD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,CAAC,cAAc,GAAG,WAAW,CAyCzE"}
|