edge-ai-client-ts 1.0.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.
Files changed (57) hide show
  1. package/CHANGELOG.md +72 -0
  2. package/LICENSE +21 -0
  3. package/README.md +174 -0
  4. package/bin/ec-ts.js +18 -0
  5. package/dist/buffer/disk-queue.d.ts +140 -0
  6. package/dist/buffer/disk-queue.js +370 -0
  7. package/dist/cli/devices.d.ts +1 -0
  8. package/dist/cli/devices.js +61 -0
  9. package/dist/cli/enroll.d.ts +2 -0
  10. package/dist/cli/enroll.js +89 -0
  11. package/dist/cli/index.d.ts +10 -0
  12. package/dist/cli/index.js +116 -0
  13. package/dist/cli/messages.d.ts +1 -0
  14. package/dist/cli/messages.js +59 -0
  15. package/dist/cli/run.d.ts +5 -0
  16. package/dist/cli/run.js +112 -0
  17. package/dist/cli/status.d.ts +1 -0
  18. package/dist/cli/status.js +56 -0
  19. package/dist/cli/whoami.d.ts +2 -0
  20. package/dist/cli/whoami.js +41 -0
  21. package/dist/config/cmd-gate.d.ts +65 -0
  22. package/dist/config/cmd-gate.js +128 -0
  23. package/dist/config/settings.d.ts +209 -0
  24. package/dist/config/settings.js +627 -0
  25. package/dist/crypto/aes-gcm.d.ts +38 -0
  26. package/dist/crypto/aes-gcm.js +90 -0
  27. package/dist/crypto/hmac.d.ts +31 -0
  28. package/dist/crypto/hmac.js +52 -0
  29. package/dist/crypto/tls-guard.d.ts +36 -0
  30. package/dist/crypto/tls-guard.js +54 -0
  31. package/dist/daemon/manager.d.ts +82 -0
  32. package/dist/daemon/manager.js +461 -0
  33. package/dist/index.d.ts +39 -0
  34. package/dist/index.js +63 -0
  35. package/dist/logging/file-logger.d.ts +21 -0
  36. package/dist/logging/file-logger.js +71 -0
  37. package/dist/network/ws-client.d.ts +221 -0
  38. package/dist/network/ws-client.js +1134 -0
  39. package/dist/session/fail-fast.d.ts +70 -0
  40. package/dist/session/fail-fast.js +122 -0
  41. package/dist/session/manager.d.ts +136 -0
  42. package/dist/session/manager.js +291 -0
  43. package/dist/session/persistence.d.ts +103 -0
  44. package/dist/session/persistence.js +194 -0
  45. package/dist/session/pi-rpc.d.ts +164 -0
  46. package/dist/session/pi-rpc.js +412 -0
  47. package/dist/session/sftp.d.ts +64 -0
  48. package/dist/session/sftp.js +335 -0
  49. package/dist/session/shell-frame.d.ts +77 -0
  50. package/dist/session/shell-frame.js +199 -0
  51. package/dist/session/shell.d.ts +124 -0
  52. package/dist/session/shell.js +300 -0
  53. package/docs/CONFIGURATION.md +169 -0
  54. package/docs/INSTALLATION.md +164 -0
  55. package/docs/PROTOCOL.md +248 -0
  56. package/docs/TROUBLESHOOTING.md +177 -0
  57. package/package.json +79 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,72 @@
1
+ # Changelog
2
+
3
+ All notable changes to `edge-ai-client-ts` are documented here.
4
+ The format follows [Keep a Changelog](https://keepachangelog.com/) and the
5
+ project adheres to [Semantic Versioning](https://semver.org/).
6
+
7
+ ## [Unreleased]
8
+
9
+ ### Added
10
+ - (placeholder for next iteration)
11
+
12
+ ## [1.0.0] - 2026-07-13
13
+
14
+ **First public release** of `edge-ai-client-ts` on npm. The package
15
+ ships a complete, byte-compatible TypeScript re-implementation of the Rust
16
+ `ec` binary — same wire protocol, same security model, same CLI surface,
17
+ shipped via `npm install -g`.
18
+
19
+ ### Added
20
+ - Full TypeScript (Model 1) parallel client mirroring the Rust
21
+ `edge-client` byte-for-byte on the wire protocol. See
22
+ `docs/PROTOCOL.md` for the full spec and `e2e-smoke/README.md` for the
23
+ end-to-end smoke test.
24
+ - 17-byte binary shell frame codec (`session/shell-frame.ts`) — byte-exact
25
+ with Rust `ShellFrame::encode/decode`.
26
+ - AES-256-GCM disk-backed offline buffer queue (`buffer/disk-queue.ts`).
27
+ - AGT-02 fail-fast policy (`session/fail-fast.ts`).
28
+ - Disk-backed session persistence (`session/persistence.ts`).
29
+ - `EdgeWsClient` with register / heartbeat / ACK / `get_config` RPC /
30
+ reconnect supervisor.
31
+ - All six CLI subcommands (`run`, `enroll`, `whoami`, `status`, `devices`,
32
+ `messages`) with commander `exitOverride()` for embeddability.
33
+ - `ServiceManager` for per-OS service install: systemd --user (Linux),
34
+ LaunchAgent (macOS), schtasks / LeastPrivilege (Windows).
35
+ - TLS SPKI fingerprint pinning via the Node built-in `tls` module.
36
+ - Comprehensive documentation under `docs/`:
37
+ - `INSTALLATION.md`
38
+ - `CONFIGURATION.md`
39
+ - `TROUBLESHOOTING.md`
40
+ - `PROTOCOL.md`
41
+ - GitHub Actions workflow for CI + automated npm publish.
42
+
43
+ ### Fixed
44
+ - Subprotocol header is now a 2-element array `["edgeai-v2", "<token>"]`
45
+ (was a single comma-containing string that `ws@8` rejects).
46
+ - `socket.on('error')` defensive null-error handler (was propagating
47
+ `null` → `Error("null")`).
48
+ - `session/shell.ts` stub `FrameCodec` replaced with the byte-exact real
49
+ codec from `session/shell-frame.ts` (was producing DIFFERENT wire bytes
50
+ than the Rust side via a hex-string interpretation).
51
+
52
+ ### Changed
53
+ - Renamed the package version series from the pre-publish `7.0.0` line to
54
+ `1.0.0` to mark the first public npm release (no API/semantic break —
55
+ internal only).
56
+ - Removed duplicate `FrameType` / `FrameCodec` stub from
57
+ `session/shell.ts` in favor of `session/shell-frame.ts` as the single
58
+ source of truth.
59
+
60
+ ### Security
61
+ - `prepublishOnly` runs `typecheck`, `test`, and `build` to prevent
62
+ shipping a broken / unverified package.
63
+ - No secrets are stored in source. All credentials are loaded from
64
+ environment variables (`EDGE_AUTH_TOKEN`, `EDGE_BUFFER_KEY`,
65
+ `EDGE_RELAY_FINGERPRINT`, …) — see `docs/CONFIGURATION.md`.
66
+
67
+ ### Known issues
68
+ - See `docs/TROUBLESHOOTING.md` for a curated list of operator-facing
69
+ workarounds (no known critical issues at v1.0.0).
70
+
71
+ [Unreleased]: https://github.com/baphuongna/edge-ai-agent/compare/v1.0.0...HEAD
72
+ [1.0.0]: https://github.com/baphuongna/edge-ai-agent/releases/tag/v1.0.0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Edge AI Agent Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,174 @@
1
+ # edge-ai-client-ts
2
+
3
+ [![npm version](https://img.shields.io/npm/v/edge-ai-client-ts.svg)](https://www.npmjs.com/package/edge-ai-client-ts)
4
+ [![npm downloads](https://img.shields.io/npm/dm/edge-ai-client-ts.svg)](https://www.npmjs.com/package/edge-ai-client-ts)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
6
+ [![Node.js](https://img.shields.io/badge/node-%E2%89%A520-green.svg)](https://nodejs.org/)
7
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.5-blue.svg)](https://www.typescriptlang.org/)
8
+
9
+ **TypeScript edge-client** for the [Edge AI Agent](https://github.com/baphuongna/edge-ai-agent) fleet — a pure-npm re-implementation of the Rust `ec` binary with a **byte-compatible wire protocol**.
10
+
11
+ A TypeScript edge-client and a Rust edge-client can connect to the **same relay** interchangeably, making `ec-ts` the perfect choice when:
12
+
13
+ - You want a one-line `npm install -g` install (no Rust toolchain required).
14
+ - You are running the edge node on an architecture without a prebuilt `ec` binary.
15
+ - You need to embed the client into a Node.js application or a custom daemon.
16
+
17
+ ---
18
+
19
+ ## 🚀 Quick start
20
+
21
+ ```bash
22
+ # 1. Install (requires Node.js >= 20)
23
+ npm install -g edge-ai-client-ts
24
+
25
+ # 2. Enroll against your relay (uses the per-operator API key from your dashboard)
26
+ ec-ts enroll --key <your-operator-api-key>
27
+
28
+ # 3. Start the daemon (foreground)
29
+ ec-ts run
30
+
31
+ # Or install it as a system service (auto-start on boot)
32
+ ec-ts run --install-service
33
+ ```
34
+
35
+ That's it — the daemon will open a WebSocket to the relay, register, and start sending heartbeats.
36
+
37
+ ---
38
+
39
+ ## 📦 What you get
40
+
41
+ | Command | Purpose |
42
+ |---------|---------|
43
+ | `ec-ts run` | Start the daemon (foreground or `--install-service` for systemd/LaunchAgent/schtasks). |
44
+ | `ec-ts enroll --key <key>` | Persist a per-operator credential to the OS keychain. |
45
+ | `ec-ts whoami` | Print the current operator + relay identity. |
46
+ | `ec-ts status` | One-shot health snapshot (WS state, queue depth, last heartbeat). |
47
+ | `ec-ts devices` | List devices owned by the current operator. |
48
+ | `ec-ts messages` | Tail the message buffer. |
49
+
50
+ > **Binary name:** `ec-ts` (not `ec`) so you can run both the TypeScript and the Rust clients side-by-side if you want to compare them.
51
+
52
+ ---
53
+
54
+ ## ✅ Protocol parity with the Rust `ec`
55
+
56
+ The TypeScript client implements the **exact same wire formats** as the Rust client:
57
+
58
+ - **`/edge` JSON connection** — `register`, `stream`, `ack`, `heartbeat`, `get_config`, `list_agents`, `browser_fetch` message types with identical field names (`machine_id`, `agent_id`, `msg_id`, `type`, `payload`, `timestamp`).
59
+ - **`/shell-edge` binary frames** — 17-byte header = 16-byte `session_id` (UUID bytes) + 1-byte `FrameType` + payload. `FrameType` enum values are identical (`Data=0`, `Resize=1`, `Close=2`, …).
60
+ - **Buffer dump encryption** — `[KEY_VERSION=1][nonce:12][ciphertext+tag]` AES-256-GCM envelope with keyring rotation.
61
+ - **TLS SPKI pinning** — SHA-256 of the DER `SubjectPublicKeyInfo`.
62
+ - **`Sec-WebSocket-Protocol`** — `edgeai-v2, <token>[, device-secret=...]`.
63
+
64
+ A TS edge-client and a Rust edge-client produce **byte-compatible** frames and JSON.
65
+
66
+ ---
67
+
68
+ ## 📋 Requirements
69
+
70
+ - **Node.js >= 20** (uses `crypto.randomUUID`, native `fetch`, modern ESM).
71
+ - A C++ toolchain for `node-pty` — Microsoft `node-pty` ships **prebuilt `.node` binaries** for common platforms (Linux x64/arm64, macOS x64/arm64, Windows x64), so a toolchain is only needed on unusual architectures.
72
+ - The relay server must be reachable via WebSocket (`ws://` for dev, `wss://` for production).
73
+
74
+ ---
75
+
76
+ ## ⚙️ Configuration
77
+
78
+ Config lives at:
79
+
80
+ - **Linux:** `~/.config/edge-ai-agent/config.toml`
81
+ - **macOS:** `~/Library/Application Support/edge-ai-agent/config.toml`
82
+ - **Windows:** `%APPDATA%\edge-ai-agent\config.toml`
83
+
84
+ A JSON `config.json` is also accepted as a fallback. The schema is identical to the Rust `config.toml` — see [`docs/CONFIGURATION.md`](docs/CONFIGURATION.md) for the full reference.
85
+
86
+ ### Environment variables (preferred for secrets)
87
+
88
+ > **Never commit credentials to source.** Use environment variables for tokens, API keys, and encryption keys.
89
+
90
+ | Variable | Purpose |
91
+ |----------|---------|
92
+ | `EDGE_AUTH_TOKEN` | Fleet shared secret for WS auth (preferred over `config.toml`). |
93
+ | `EDGE_BUFFER_KEY` | Buffer-dump AES-256-GCM key (hex, 64 chars = 32 bytes). |
94
+ | `EDGE_BUFFER_KEY_PREVIOUS` | Previous key for rotation (hex, 64 chars). |
95
+ | `EDGE_RELAY_FINGERPRINT` | Pinned TLS SPKI fingerprint (overrides config). |
96
+ | `EDGE_OWNER_OPERATOR_ID` | Override the enrolled operator id. |
97
+ | `EDGEAI_REQUIRE_TLS` | `1` forces `wss://` even outside production. |
98
+ | `NODE_ENV=production` | Forces `wss://`. |
99
+ | `EDGE_CMD_GATE_MODE` | `off` / `warn` / `block`. |
100
+ | `EDGE_FAIL_FAST` | Fail-fast policy toggle. |
101
+
102
+ See [`docs/CONFIGURATION.md`](docs/CONFIGURATION.md) for the full env-var reference and precedence rules.
103
+
104
+ ---
105
+
106
+ ## 🛠️ Development
107
+
108
+ ```bash
109
+ git clone https://github.com/baphuongna/edge-ai-agent.git
110
+ cd edge-ai-agent/edge-client-ts
111
+ npm install
112
+ npm run typecheck # tsc --noEmit
113
+ npm test # vitest run
114
+ npm run build # compile to dist/
115
+ ```
116
+
117
+ Pre-publish sanity check (mirrors CI):
118
+
119
+ ```bash
120
+ npm run prepublishOnly # typecheck + test + build
121
+ ```
122
+
123
+ End-to-end smoke test against a live `ws-service`:
124
+
125
+ ```bash
126
+ npm run smoke
127
+ ```
128
+
129
+ See [`docs/TROUBLESHOOTING.md`](docs/TROUBLESHOOTING.md) for common install/run issues.
130
+
131
+ ---
132
+
133
+ ## 🧱 Architecture (module mapping)
134
+
135
+ Every module in this package corresponds 1:1 with a Rust module — see
136
+ [`docs/PROTOCOL.md`](docs/PROTOCOL.md) for the byte-exact wire spec.
137
+
138
+ | Rust file | TS file |
139
+ |------------------------------------|----------------------------------|
140
+ | `config/settings.rs` | `src/config/settings.ts` |
141
+ | `config/machine_id.rs` | `src/config/settings.ts` |
142
+ | `config/device_secret.rs` | `src/config/settings.ts` |
143
+ | `session/cmd_gate.rs` (config) | `src/config/cmd-gate.ts` |
144
+ | `network/tls_guard.rs` | `src/crypto/tls-guard.ts` |
145
+ | `crypto/aes_gcm.rs` | `src/crypto/aes-gcm.ts` |
146
+ | `logging/file_logger.rs` | `src/logging/file-logger.ts` |
147
+ | `network/ws_client.rs` | `src/network/ws-client.ts` |
148
+ | `session/manager.rs` | `src/session/manager.ts` |
149
+ | `session/shell.rs` | `src/session/shell.ts` |
150
+ | `session/shell_frame.rs` | `src/session/shell-frame.ts` |
151
+ | `session/fail_fast.rs` | `src/session/fail-fast.ts` |
152
+ | `session/pi_rpc.rs` | `src/session/pi-rpc.ts` |
153
+ | `session/persistence.rs` | `src/session/persistence.ts` |
154
+ | `session/sftp.rs` | `src/session/sftp.ts` |
155
+ | `buffer/disk_queue.rs` | `src/buffer/disk-queue.ts` |
156
+ | `cli/mod.rs` | `src/cli/index.ts` |
157
+ | `daemon/manager.rs` | `src/daemon/manager.ts` |
158
+
159
+ ---
160
+
161
+ ## 📚 Documentation
162
+
163
+ - [`docs/INSTALLATION.md`](docs/INSTALLATION.md) — Detailed install guide (Linux / macOS / Windows, dev / prod).
164
+ - [`docs/CONFIGURATION.md`](docs/CONFIGURATION.md) — Full config schema + env-var precedence.
165
+ - [`docs/TROUBLESHOOTING.md`](docs/TROUBLESHOOTING.md) — Common errors and fixes.
166
+ - [`docs/PROTOCOL.md`](docs/PROTOCOL.md) — Wire-protocol reference (frames, JSON messages, TLS pinning).
167
+
168
+ ---
169
+
170
+ ## 📄 License
171
+
172
+ MIT — see [`LICENSE`](LICENSE).
173
+
174
+ This package is part of the Edge AI Agent monorepo. The full system is documented at <https://github.com/baphuongna/edge-ai-agent>.
package/bin/ec-ts.js ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * ec-ts — TypeScript (Model 1) parallel edge-client binary shim.
4
+ *
5
+ * Loader that forwards argv to the CLI dispatch in the compiled dist/index.js.
6
+ * Install globally via `npm i -g edge-ai-client-ts` and run `ec-ts`.
7
+ *
8
+ * Requires Node.js >= 20.
9
+ */
10
+ import('../dist/cli/index.js')
11
+ .then(async ({ dispatch }) => {
12
+ const code = await dispatch(process.argv.slice(2));
13
+ process.exit(code);
14
+ })
15
+ .catch((err) => {
16
+ console.error('ec-ts: failed to load CLI dispatch:', err);
17
+ process.exit(1);
18
+ });
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Disk-backed offline buffer queue — TypeScript parallel of
3
+ * `edge-client/src/buffer/queue.rs` (in-memory queue with the disk-persist
4
+ * half) and `edge-client/src/buffer/disk_dump.rs` (AES-256-GCM envelope).
5
+ *
6
+ * This is the OFFLINE RESILIENCE LAYER: when the WS connection is down,
7
+ * stream frames are durably written to disk; on reconnect they replay in
8
+ * order; no frames lost on crash.
9
+ *
10
+ * ## On-disk format (mirrors Rust `DiskDumper`)
11
+ *
12
+ * [KEY_VERSION: 1 byte][AES-256-GCM nonce: 12 bytes][ciphertext + auth tag: 16 bytes]
13
+ *
14
+ * The plaintext is a JSON-encoded array of {@link QueueEntry} objects
15
+ * (`{ msg_id, timestamp, bytes }`), where `bytes` is base64-encoded.
16
+ *
17
+ * ## Atomic-write invariant (the project's hardest-won guarantee)
18
+ *
19
+ * 1. Serialize entries → encrypt → write to `<dir>/.buffer.queue.enc.tmp`
20
+ * 2. `fsync` the temp file
21
+ * 3. `rename` tmp → `<dir>/buffer.queue.enc`
22
+ *
23
+ * Crash safety: a tmp file left on disk after a crash is half-written; we
24
+ * delete it on next lazy-load. The main file is either fully written or
25
+ * absent (the rename is atomic on POSIX and on Windows since Node 14+).
26
+ *
27
+ * ## Concurrency
28
+ *
29
+ * In-process serialization via a Promise-chain mutex. Cross-process locking
30
+ * is intentionally NOT implemented (would require `proper-lockfile` or
31
+ * similar; omitted to keep the dependency surface minimal — the in-process
32
+ * case is the common path).
33
+ *
34
+ * ## Dedup
35
+ *
36
+ * `append` silently skips when an entry with the same `msg_id` is already
37
+ * buffered. The Rust `BufferQueue::push` does not dedup, but the disk queue
38
+ * MUST dedup to avoid sending the same `msg_id` twice to the relay on
39
+ * reconnect (relay-side ACKs would otherwise race).
40
+ */
41
+ import { KEY_VERSION } from '../crypto/aes-gcm.js';
42
+ /** One queued message awaiting replay. */
43
+ export interface QueueEntry {
44
+ /** Stable identifier used for dedup. */
45
+ msg_id: string;
46
+ /** Unix epoch milliseconds (sender-side ordering hint). */
47
+ timestamp: number;
48
+ /** Wire payload — encrypted at rest in the on-disk file. */
49
+ bytes: Uint8Array;
50
+ }
51
+ export interface DiskBufferQueueOptions {
52
+ /** Directory where the encrypted queue file lives. Created if missing. */
53
+ readonly dir: string;
54
+ /** 32-byte AES-256-GCM key (typically from `loadBufferKey(settings)`). */
55
+ readonly key: Uint8Array;
56
+ /**
57
+ * Soft cap on the serialized JSON envelope (plaintext bytes).
58
+ * Mirrors Rust `BufferConfig.max_memory_mb` (default 50 MiB).
59
+ */
60
+ readonly maxBytes?: number;
61
+ }
62
+ /** Default cap — 50 MiB. Matches Rust `BufferConfig::default().max_memory_mb`. */
63
+ export declare const DEFAULT_MAX_BYTES: number;
64
+ /** Filename of the encrypted queue blob (relative to `dir`). */
65
+ export declare const QUEUE_FILE_NAME = "buffer.queue.enc";
66
+ /** Filename of the atomic-write temp file (relative to `dir`). */
67
+ export declare const QUEUE_TMP_NAME = ".buffer.queue.enc.tmp";
68
+ /** Thrown by {@link DiskBufferQueue.append} when the cap would be exceeded. */
69
+ export declare class BufferFullError extends Error {
70
+ readonly currentBytes: number;
71
+ readonly maxBytes: number;
72
+ constructor(currentBytes: number, maxBytes: number);
73
+ }
74
+ /**
75
+ * Single-file, AES-256-GCM-encrypted, FIFO buffer queue.
76
+ *
77
+ * Append-only on the hot path. `drain()` consumes every entry in FIFO order,
78
+ * hands each to a handler, and deletes the on-disk file when the handler
79
+ * completes successfully. `peek()` and `size()` are non-mutating.
80
+ */
81
+ export declare class DiskBufferQueue {
82
+ private readonly dir;
83
+ private readonly filePath;
84
+ private readonly tmpPath;
85
+ private readonly key;
86
+ private readonly maxBytes;
87
+ /** In-memory cache. Loaded lazily on first op. */
88
+ private entries;
89
+ private loaded;
90
+ /** Promise-chain mutex for in-process serialization. */
91
+ private mutex;
92
+ constructor(opts: DiskBufferQueueOptions);
93
+ /**
94
+ * Append an entry to the queue. Skips silently when `entry.msg_id` is
95
+ * already buffered (dedup invariant). Throws {@link BufferFullError} when
96
+ * the serialized envelope would exceed `maxBytes`.
97
+ */
98
+ append(entry: QueueEntry): Promise<void>;
99
+ /**
100
+ * Return up to `limit` entries (FIFO order) without removing them.
101
+ * Defensive copy — callers may freely mutate the returned bytes.
102
+ */
103
+ peek(limit: number): Promise<QueueEntry[]>;
104
+ /** Return the number of entries currently buffered. */
105
+ size(): Promise<number>;
106
+ /**
107
+ * Delete all entries and the on-disk file. Idempotent — succeeds whether
108
+ * the file exists or not.
109
+ */
110
+ clear(): Promise<void>;
111
+ /**
112
+ * Invoke `handler(entry)` for every entry in FIFO order, then delete the
113
+ * on-disk file. Returns the number of entries processed. If the handler
114
+ * throws, the entries remain on disk for a future `drain()` retry
115
+ * (at-least-once semantics — matches the Rust offline-queue contract).
116
+ */
117
+ drain(handler: (entry: QueueEntry) => Promise<void> | void): Promise<number>;
118
+ /**
119
+ * Lazily create the dir, recover from a prior crash (delete tmp), and
120
+ * load existing entries. Runs at most once per queue instance.
121
+ */
122
+ private ensureLoaded;
123
+ /**
124
+ * Encrypt + atomic-write the in-memory entry list to disk.
125
+ *
126
+ * Sequence (mirrors Rust `atomic_write` in `disk_dump.rs:159-186`):
127
+ * 1. encrypt(plaintext) → `[version][nonce][ciphertext][tag]`
128
+ * 2. open tmp with mode 0600 (defense in depth — encryption protects
129
+ * contents either way)
130
+ * 3. write blob + fsync the file (force kernel buffers to disk)
131
+ * 4. rename tmp → final path (atomic on POSIX, atomic on Win since Node 14+)
132
+ */
133
+ private persist;
134
+ private projectedBytesAfterAppend;
135
+ /** Serialize operations via a Promise chain (in-process mutex). */
136
+ private withLock;
137
+ private assertValidEntry;
138
+ private unlinkIfExists;
139
+ }
140
+ export { KEY_VERSION };