signalk-edge-link 1.0.1 → 2.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.
Files changed (62) hide show
  1. package/README.md +212 -468
  2. package/lib/CircularBuffer.js +33 -35
  3. package/lib/bin/edge-link-cli.js +373 -0
  4. package/lib/bonding.js +740 -0
  5. package/lib/config-io.js +141 -0
  6. package/lib/config-watcher.js +251 -0
  7. package/lib/congestion.js +223 -0
  8. package/lib/connection-config.js +357 -0
  9. package/lib/constants.js +85 -65
  10. package/lib/crypto.js +271 -98
  11. package/lib/index.js +699 -0
  12. package/lib/instance.js +911 -0
  13. package/lib/metrics-publisher.js +264 -0
  14. package/lib/metrics.js +311 -229
  15. package/lib/monitoring.js +572 -0
  16. package/lib/packet-capture.js +290 -0
  17. package/lib/packet.js +467 -0
  18. package/lib/pathDictionary.js +456 -483
  19. package/lib/pipeline-factory.js +36 -0
  20. package/lib/pipeline-utils.js +134 -0
  21. package/lib/pipeline-v2-client.js +799 -0
  22. package/lib/pipeline-v2-server.js +803 -0
  23. package/lib/pipeline.js +268 -285
  24. package/lib/prometheus.js +197 -0
  25. package/lib/retransmit-queue.js +246 -0
  26. package/lib/routes/config-validation.js +40 -0
  27. package/lib/routes/config.js +280 -0
  28. package/lib/routes/connections.js +467 -0
  29. package/lib/routes/control.js +179 -0
  30. package/lib/routes/metrics.js +126 -0
  31. package/lib/routes/monitoring.js +353 -0
  32. package/lib/routes/types.js +2 -0
  33. package/lib/routes.js +538 -393
  34. package/lib/scripts/migrate-config.js +74 -0
  35. package/lib/sequence.js +227 -0
  36. package/lib/types.js +2 -0
  37. package/package.json +98 -12
  38. package/public/11.413e152fbef6e7dfd2f8.js +2 -0
  39. package/public/11.413e152fbef6e7dfd2f8.js.map +1 -0
  40. package/public/{277.e4828e082563595def51.js → 277.509a7bfc11fac344f433.js} +4 -4
  41. package/public/{277.e4828e082563595def51.js.map → 277.509a7bfc11fac344f433.js.map} +1 -1
  42. package/public/index.html +1 -1
  43. package/public/main.3576323fe7e587bd7c5e.js +2 -0
  44. package/public/main.3576323fe7e587bd7c5e.js.map +1 -0
  45. package/public/{main.5d54244033b773c1441a.css → main.e2b9c98749816ac2e285.css} +478 -1
  46. package/public/main.e2b9c98749816ac2e285.css.map +1 -0
  47. package/public/remoteEntry.js +1 -1
  48. package/public/remoteEntry.js.map +1 -1
  49. package/schemas/config.schema.json +104 -0
  50. package/.github/dependabot.yml +0 -11
  51. package/.prettierignore +0 -13
  52. package/doc/dataconnectorconcept.jpg +0 -0
  53. package/doc/datarate.jpg +0 -0
  54. package/index.js +0 -642
  55. package/public/831.a2124774e19d544043f1.js +0 -3
  56. package/public/831.a2124774e19d544043f1.js.LICENSE.txt +0 -1
  57. package/public/831.a2124774e19d544043f1.js.map +0 -1
  58. package/public/main.00c54d4228814ed344dc.js +0 -3
  59. package/public/main.00c54d4228814ed344dc.js.LICENSE.txt +0 -1
  60. package/public/main.00c54d4228814ed344dc.js.map +0 -1
  61. package/public/main.5d54244033b773c1441a.css.map +0 -1
  62. /package/public/{277.e4828e082563595def51.js.LICENSE.txt → 277.509a7bfc11fac344f433.js.LICENSE.txt} +0 -0
package/README.md CHANGED
@@ -1,538 +1,282 @@
1
1
  # Signal K Edge Link
2
2
 
3
- Secure, encrypted UDP data transmission between Signal K servers with advanced bandwidth optimization.
4
-
5
- [![Tests](https://img.shields.io/badge/tests-209%20passed-brightgreen)](https://github.com/KEGustafsson/signalk-edge-link)
6
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
- [![Node.js](https://img.shields.io/badge/node-%3E%3D14.0.0-brightgreen)](https://nodejs.org/)
8
-
9
- ![Data Connector Concept](https://raw.githubusercontent.com/KEGustafsson/signalk-edge-link/refs/heads/main/doc/dataconnectorconcept.jpg)
10
-
11
- **Create a digital twin of your vessel in the cloud.** Signal K Edge Link sends vessel data from an onboard Signal K server to a remote cloud server using UDP — designed for challenging network conditions where TCP struggles, such as cellular network edge areas with intermittent connectivity. Data is queued and transmitted when the network allows, keeping latency low and bandwidth usage minimal. All traffic is encrypted and outbound-only, requiring no open inbound ports on the vessel. Simple to configure, efficient to run.
12
-
13
- ---
14
-
15
- ## Table of Contents
16
-
17
- - [Overview](#overview)
18
- - [Getting Started](#getting-started)
19
- - [Installation](#installation)
20
- - [Quick Start](#quick-start)
21
- - [Configuration](#configuration)
22
- - [Server Mode](#server-mode-receiver)
23
- - [Client Mode](#client-mode-sender)
24
- - [Web Dashboard](#web-dashboard)
25
- - [Configuration Files](#configuration-files)
26
- - [Network Monitoring](#network-monitoring)
27
- - [Performance](#performance)
28
- - [Bandwidth Comparison](#bandwidth-comparison)
29
- - [Smart Batching](#smart-batching)
30
- - [Optimization Tips](#optimization-tips)
31
- - [Security](#security)
32
- - [Encryption](#encryption)
33
- - [Secret Key Requirements](#secret-key-requirements)
34
- - [Best Practices](#best-practices)
35
- - [Troubleshooting](#troubleshooting)
36
- - [Development](#development)
37
- - [Architecture](#architecture)
38
- - [Project Structure](#project-structure)
39
- - [Build Commands](#build-commands)
40
- - [Testing](#testing)
41
- - [Technical Reference](#technical-reference)
42
- - [Contributing](#contributing)
43
- - [License](#license)
44
-
45
- ---
46
-
47
- ## Overview
48
-
49
- Signal K Edge Link is a Signal K Node Server plugin that enables real-time data sharing between vessels or shore stations over UDP. It combines AES-256-GCM authenticated encryption with Brotli compression to deliver secure, bandwidth-efficient transmission — achieving up to **97% bandwidth reduction** compared to raw data.
50
-
51
- **Key capabilities:**
52
-
53
- | Feature | Description |
54
- |---------|-------------|
55
- | Encrypted transport | AES-256-GCM authenticated encryption with per-message unique IV |
56
- | Brotli compression | Quality-10 compression with 85–97% reduction on typical data |
57
- | Binary protocol | Zero JSON overhead in the wire format |
58
- | Path dictionary | 170+ Signal K paths mapped to numeric IDs (10–20% savings) |
59
- | MessagePack | Optional binary serialization (15–25% additional savings) |
60
- | Smart batching | Adaptive packet sizing that prevents UDP fragmentation |
61
- | Sentence filtering | Exclude NMEA sentences (GSV, GSA, etc.) to reduce bandwidth |
62
- | Network monitoring | TCP ping with RTT measurement published to Signal K |
63
- | Web dashboard | Real-time bandwidth, compression, and path analytics |
64
- | Hot-reload config | Configuration files reload automatically on change |
65
-
66
- ---
67
-
68
- ## Getting Started
69
-
70
- ### Installation
71
-
72
- ```bash
73
- cd ~/.signalk/node_modules/
74
- git clone https://github.com/KEGustafsson/signalk-edge-link.git
75
- cd signalk-edge-link
76
- npm install
77
- npm run build
78
- ```
79
-
80
- Restart your Signal K server after installation.
81
-
82
- ### Quick Start
83
-
84
- 1. Open **Admin UI → Plugin Config → Signal K Edge Link**
85
- 2. Choose an operation mode:
86
- - **Server** — receives data from remote clients
87
- - **Client** — sends data to a remote server
88
- 3. Set the **UDP port** (must match between client and server)
89
- 4. Enter a **32-character encryption key** (must be identical on both ends)
90
- 5. For client mode, enter the **server IP address**
91
- 6. Enable the plugin and verify data flow in the web dashboard
92
-
93
- > **Tip:** Start with the default settings. Enable path dictionary and MessagePack later for additional bandwidth savings.
94
-
95
- ---
96
-
97
- ## Configuration
98
-
99
- The plugin provides a custom React-based configuration UI that dynamically adapts to the selected operation mode, showing only relevant settings.
100
-
101
- **Access:** Admin UI → Plugin Config → Signal K Edge Link
102
-
103
- ### Server Mode (Receiver)
104
-
105
- | Setting | Description |
106
- |---------|-------------|
107
- | Operation Mode | Server/Client selector |
108
- | UDP Port | Port to listen on (1024–65535) |
109
- | Encryption Key | 32-character secret key |
110
- | MessagePack | Enable binary serialization |
111
- | Path Dictionary | Enable path encoding |
112
-
113
- ### Client Mode (Sender)
114
-
115
- | Setting | Description |
116
- |---------|-------------|
117
- | Operation Mode | Server/Client selector |
118
- | UDP Port | Port to send to |
119
- | Encryption Key | 32-character secret key (must match server) |
120
- | Destination Address | Server IP or hostname |
121
- | Heartbeat Interval | Keep-alive message frequency (seconds) |
122
- | Connectivity Test Target | Address to ping for network monitoring |
123
- | Connectivity Test Port | Port to test (80, 443, etc.) |
124
- | Check Interval | How often to test connectivity (minutes) |
125
- | MessagePack | Enable binary serialization |
126
- | Path Dictionary | Enable path encoding |
127
-
128
- Additional client settings are available in the web dashboard:
129
- - **Delta timer** — collection interval (100–10000 ms)
130
- - **Subscription paths** — Signal K paths to transmit
131
- - **Sentence filter** — NMEA sentences to exclude (e.g., `GSV, GSA, VTG`)
132
-
133
- ### Web Dashboard
134
-
135
- **Access:** `http://[signalk-server]:3000/plugins/signalk-edge-link`
136
-
137
- The dashboard provides real-time monitoring and configuration controls.
138
-
139
- **Client mode:**
140
- - Delta timer and subscription management
141
- - Sentence filter configuration
142
- - Upload/download bandwidth with compression ratio
143
- - Bandwidth savings display (actual bytes saved)
144
- - Path analytics with per-path data volume breakdown
145
- - Performance metrics (errors, uptime, deltas sent)
146
- - Rate history chart (last 150 seconds)
147
-
148
- **Server mode:**
149
- - Download bandwidth and packet rate
150
- - Bandwidth savings display
151
- - Incoming path analytics
152
- - Performance metrics (deltas received, errors)
153
- - Compression effectiveness tracking
154
-
155
- ### Configuration Files
156
-
157
- These JSON files are stored in the plugin data directory and support hot-reload — changes take effect automatically without restarting.
158
-
159
- | File | Purpose | Default |
160
- |------|---------|---------|
161
- | `delta_timer.json` | Collection interval in ms | `{"deltaTimer": 1000}` |
162
- | `subscription.json` | Signal K paths to subscribe | `{"context": "*", "subscribe": [...]}` |
163
- | `sentence_filter.json` | NMEA sentences to exclude | `{"sentences": []}` |
164
-
165
- ### API Endpoints
166
-
167
- All endpoints are rate-limited to 20 requests per minute per IP.
168
-
169
- | Method | Endpoint | Description |
170
- |--------|----------|-------------|
171
- | GET | `/plugins/signalk-edge-link/config/:filename` | Read a configuration file |
172
- | POST | `/plugins/signalk-edge-link/config/:filename` | Update a configuration file |
173
- | GET | `/plugins/signalk-edge-link/metrics` | Real-time statistics and performance data |
174
- | GET | `/plugins/signalk-edge-link/paths` | Path dictionary information |
175
- | GET | `/plugins/signalk-edge-link/plugin-config` | Current plugin configuration |
176
- | POST | `/plugins/signalk-edge-link/plugin-config` | Update plugin configuration |
177
- | GET | `/plugins/signalk-edge-link/plugin-schema` | Plugin schema definition |
178
-
179
- ---
180
-
181
- ## Network Monitoring
182
-
183
- In client mode, the plugin measures **Round Trip Time (RTT)** using TCP ping to monitor connectivity and latency.
184
-
185
- **How it works:**
186
- 1. TCP ping is sent to the configured test address and port at the configured interval
187
- 2. RTT is published to local Signal K at `networking.modem.rtt` (value in seconds)
188
- 3. If subscribed, RTT data is transmitted to the remote server with other data
189
-
190
- **To enable RTT transmission:** Add `networking.modem.rtt` to your subscription paths.
191
-
192
- **Use cases:**
193
- - Monitor cellular or satellite modem latency
194
- - Track connection quality over time
195
- - Trigger alerts on high latency
196
- - Analyze network performance trends
197
-
198
- ---
199
-
200
- ## Performance
201
-
202
- ### Bandwidth Comparison
203
-
204
- ![Data Rate Comparison](https://raw.githubusercontent.com/KEGustafsson/signalk-edge-link/refs/heads/main/doc/datarate.jpg)
205
-
206
- | Mode | Bandwidth | Reduction vs. WebSocket |
207
- |------|-----------|------------------------|
208
- | 1000 ms collection | ~44.1 kb/s | ~70% |
209
- | 100 ms collection | ~107.7 kb/s | ~28% |
210
- | WebSocket real-time | ~149.5 kb/s | — |
211
-
212
- Typical compression results on Signal K data:
213
-
3
+ [![npm version](https://img.shields.io/npm/v/signalk-edge-link)](https://www.npmjs.com/package/signalk-edge-link)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
5
+ [![Node.js](https://img.shields.io/badge/node-%3E%3D16-brightgreen)](https://nodejs.org)
6
+
7
+ Signal K Edge Link is a Signal K plugin that transfers vessel deltas between Signal K servers over encrypted UDP.
8
+
9
+ It is designed for links where latency, packet loss, and bandwidth usage matter (cellular, satellite, and other unstable WAN paths).
10
+
11
+ ![Data Connector Concept](docs/assets/dataconnectorconcept.jpg)
12
+
13
+ ## Why use it?
14
+
15
+ - **Secure transport** using AES-256-GCM
16
+ - **Bandwidth optimization** with Brotli compression (plus optional MessagePack and path dictionary)
17
+ - **Two operating modes**:
18
+ - **Client**: subscribes to local deltas and sends packets
19
+ - **Server**: receives packets, decrypts, and forwards to local Signal K
20
+ - **Protocol v2/v3 features** for difficult links:
21
+ - ACK/NAK-based reliability
22
+ - congestion control
23
+ - optional primary/backup bonding
24
+ - monitoring and alerting endpoints
25
+ - **Multi-connection support** on one Signal K instance
26
+
27
+ ## How data flows
28
+
29
+ ```text
30
+ Client Signal K
31
+ -> subscribe + batch deltas
32
+ -> optional path dictionary + MessagePack
33
+ -> Brotli compress
34
+ -> AES-256-GCM encrypt
35
+ -> UDP send
36
+
37
+ Server Signal K
38
+ <- UDP receive
39
+ <- AES-256-GCM decrypt
40
+ <- Brotli decompress
41
+ <- optional MessagePack + path decode
42
+ <- inject into local Signal K
214
43
  ```
215
- Original: 19,293 bytes → Encrypted + Compressed: 622 bytes (96.78% reduction)
216
- ```
217
-
218
- ### Smart Batching
219
-
220
- The plugin uses adaptive smart batching to keep UDP packets under the MTU limit (1400 bytes), preventing fragmentation that can cause data loss.
221
-
222
- 1. **Rolling average** — tracks bytes-per-delta using exponential smoothing
223
- 2. **Dynamic batch sizing** — calculates optimal deltas per packet based on recent sizes
224
- 3. **Early send trigger** — sends immediately when a batch reaches the predicted size limit
225
- 4. **Self-learning** — continuously adapts as data patterns change
226
-
227
- ```
228
- Example: Initial estimate 5 deltas/batch → After learning: 11 deltas/batch
229
- All packets stay well under 1400 bytes
230
- ```
231
-
232
- ### Optimization Tips
233
44
 
234
- For the best bandwidth efficiency:
45
+ ## Requirements
235
46
 
236
- 1. **Increase delta timer** 1000 ms gives optimal compression; lower values increase bandwidth
237
- 2. **Enable path dictionary** saves 10–20% by replacing path strings with numeric IDs
238
- 3. **Enable MessagePack** saves 15–25% with binary serialization
239
- 4. **Filter NMEA sentences** exclude GSV, GSA, VTG to remove unnecessary data
240
- 5. **Review subscriptions** — subscribe only to paths you need
47
+ - Two Signal K instances (source and destination)
48
+ - UDP reachability from client to server on your chosen port
49
+ - Shared encryption key on both ends (32-character ASCII, 64-character hex, or 44-character base64)
50
+ - Node.js 16+ (if installing from source: dev dependencies including TypeScript are installed automatically via `npm install`)
241
51
 
242
- ---
52
+ ## Installation
243
53
 
244
- ## Security
54
+ ### Option A: Signal K Plugin Manager
245
55
 
246
- ### Encryption
56
+ Install **Signal K Edge Link** from your Signal K plugin catalog.
247
57
 
248
- All data is encrypted with **AES-256-GCM**, providing authenticated encryption in a single operation.
249
-
250
- | Property | Detail |
251
- |----------|--------|
252
- | Algorithm | AES-256-GCM |
253
- | IV | 12 bytes, unique per message |
254
- | Auth tag | 16 bytes, tamper detection |
255
- | Wire format | `[IV (12 bytes)][Encrypted Data][Auth Tag (16 bytes)]` |
256
- | Overhead | 28 bytes per packet |
257
-
258
- **Security features:**
259
- - Tamper detection — any modification causes decryption failure
260
- - Rate-limited API endpoints (20 req/min/IP)
261
- - Input validation on all parameters
262
- - Key entropy checking — rejects weak keys
263
- - XSS protection in the web UI
264
- - Stateless UDP — no session state to compromise
265
-
266
- ### Secret Key Requirements
267
-
268
- - Exactly **32 characters** (256 bits)
269
- - Minimum **8 unique characters**
270
- - Must match on both client and server
271
-
272
- Generate a secure key:
58
+ ### Option B: Manual install from source
273
59
 
274
60
  ```bash
275
- openssl rand -base64 32 | cut -c1-32
61
+ cd ~/.signalk/node_modules
62
+ git clone https://github.com/KEGustafsson/signalk-edge-link.git
63
+ cd signalk-edge-link
64
+ npm install
65
+ npm run build
276
66
  ```
277
67
 
278
- **Valid examples:**
279
- ```
280
- Abc123!@#XYZ456$%^uvw789&*()pqr0
281
- K9#mP2$nQ7@rS4%tU6^vW8*xY3!zA5&
282
- abcdefgh12345678901234567890abcd
283
- ```
68
+ Restart Signal K after installation.
284
69
 
285
- **Invalid examples:**
286
- ```
287
- aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa # All same character
288
- abababababababababababababababab # Insufficient diversity
289
- MySecretKey123 # Too short
290
- ```
70
+ ## Quick start
291
71
 
292
- ### Best Practices
72
+ ### 1) Configure the destination (Server mode)
293
73
 
294
- 1. Use strong, randomly generated keys (`openssl rand` recommended)
295
- 2. Never commit keys to version control
296
- 3. Rotate keys periodically (every 6–12 months)
297
- 4. Monitor logs for decryption failures (may indicate attacks or key mismatch)
298
- 5. Restrict UDP access with firewall rules to known IP addresses
299
- 6. Test configuration in a safe environment before production deployment
74
+ In Signal K Admin UI:
300
75
 
301
- ---
76
+ 1. Open `Server -> Plugin Config -> Signal K Edge Link`
77
+ 2. Click **Add Server**
78
+ 3. Set:
79
+ - `Connection Name` (for example `shore-server`)
80
+ - `UDP Port` (default `4446`)
81
+ - `Encryption Key` (same shared secret used by client)
82
+ - `Protocol Version` (`3` recommended for new deployments; use `2` only for compatibility with an existing v2 peer)
83
+ 4. Save
302
84
 
303
- ## Troubleshooting
85
+ ### 2) Configure the source (Client mode)
304
86
 
305
- ### Plugin Not Loading
87
+ On the sending Signal K instance:
306
88
 
307
- - Verify `npm install` completed successfully
308
- - Check Signal K server logs for errors
309
- - Ensure plugin directory is `~/.signalk/node_modules/signalk-edge-link`
310
- - Verify Node.js version 14.0.0
89
+ 1. Open `Server -> Plugin Config -> Signal K Edge Link`
90
+ 2. Click **Add Client**
91
+ 3. Set:
92
+ - `Connection Name` (for example `vessel-client`)
93
+ - `Server Address` (destination host/IP)
94
+ - `UDP Port` (must match server)
95
+ - `Encryption Key` (must match server)
96
+ - `Protocol Version` (`3` recommended for new deployments; use `2` only for compatibility with an existing v2 peer)
97
+ 4. Save
311
98
 
312
- ### Web UI Not Accessible
99
+ ### 3) Verify traffic
313
100
 
314
- - Run `npm run build` to generate UI files
315
- - Verify `public/` directory exists with built files
316
- - Clear browser cache and refresh
101
+ Open the runtime UI:
317
102
 
318
- ### No Data Transmission
103
+ `http://<signalk-host>:3000/plugins/signalk-edge-link/`
319
104
 
320
- **Client side:**
321
- 1. Confirm encryption keys match on both ends
322
- 2. Verify UDP port and destination address
323
- 3. Check firewall allows UDP traffic on the configured port
324
- 4. Confirm subscription paths are valid Signal K paths
325
- 5. Verify delta timer is running (check metrics in web dashboard)
105
+ Check that:
326
106
 
327
- **Server side:**
328
- 1. Verify UDP port is not blocked by firewall
329
- 2. Confirm encryption key matches the client
330
- 3. Check Signal K logs for decryption errors
331
- 4. Verify client is sending data (check client metrics)
107
+ - client `Deltas Sent` increases
108
+ - server `Deltas Received` increases
109
+ - encryption/decryption errors remain stable at zero
332
110
 
333
- **Common error messages:**
111
+ ## Protocol version guidance
334
112
 
335
- | Message | Cause |
336
- |---------|-------|
337
- | `Unsupported state or unable to authenticate data` | Mismatched encryption keys |
338
- | `Invalid packet size` | Corrupted data or network issues |
339
- | `Secret key must be exactly 32 characters` | Invalid key length |
113
+ | Version | Use when | Notes |
114
+ | ------- | --------------------------------------------------------- | --------------------------------------------------------------------------- |
115
+ | v1 | stable local links, simplest setup | lower overhead, no ACK/NAK reliability layer |
116
+ | v2 | packet loss, variable latency, WAN links | adds retransmission, congestion control, bonding, richer monitoring |
117
+ | v3 | same use cases as v2 when both peers can upgrade together | keeps v2 features and authenticates ACK/NAK/HEARTBEAT/HELLO control packets |
340
118
 
341
- ### Poor Performance
119
+ For unstable links, start with **v3** when both peers support it; fall back to **v2** only when you need compatibility with an already deployed v2 peer.
342
120
 
343
- - Increase delta timer for better compression (1000 ms recommended)
344
- - Enable path dictionary and MessagePack
345
- - Filter unnecessary NMEA sentences
346
- - Check network latency with the ping monitor
347
- - Monitor CPU usage (Brotli compression at quality 10 is CPU-intensive)
121
+ ## Runtime UI and API
348
122
 
349
- ### Debug Logging
123
+ - Runtime UI: `/plugins/signalk-edge-link/`
124
+ - API base path: `/plugins/signalk-edge-link`
125
+ - Default API rate limit: **120 requests/minute/IP**
350
126
 
351
- Enable in Signal K plugin settings to see:
352
- - Connection monitor status and ping results
353
- - Configuration file changes (automatic reload)
354
- - Delta transmission statistics
355
- - Compression ratios and packet sizes
356
- - Error messages with full context
127
+ Most used endpoints:
357
128
 
358
- ---
129
+ - `GET /metrics`
130
+ - `GET /network-metrics`
131
+ - `GET /monitoring/alerts`
132
+ - `GET /connections`
133
+ - `GET /instances`
134
+ - `GET /instances/:id`
135
+ - `GET /connections/:id/metrics`
136
+ - `GET /connections/:id/network-metrics`
137
+ - `GET /bonding`
138
+ - `POST /bonding`
359
139
 
360
- ## Development
140
+ For full endpoint details, use `docs/api-reference.md
361
141
 
362
- ### Architecture
142
+ ## Configuration model (summary)
363
143
 
364
- **Data pipeline:**
144
+ Configuration is an array of independent connections:
365
145
 
146
+ ```json
147
+ {
148
+ "connections": [
149
+ {
150
+ "name": "shore-server",
151
+ "serverType": "server",
152
+ "udpPort": 4446,
153
+ "secretKey": "<32-byte key>",
154
+ "protocolVersion": 3
155
+ },
156
+ {
157
+ "name": "sat-client",
158
+ "serverType": "client",
159
+ "udpPort": 4447,
160
+ "udpAddress": "10.0.0.1",
161
+ "secretKey": "<32-byte key>",
162
+ "protocolVersion": 3
163
+ }
164
+ ]
165
+ }
366
166
  ```
367
- Client (Sender):
368
- Signal K Deltas → Filter → [Path Encode] → [MessagePack] → Brotli → AES-256-GCM → UDP
369
167
 
370
- Server (Receiver):
371
- UDP AES-256-GCM Brotli [MessagePack] [Path Decode] → Signal K
372
- ```
168
+ - Each connection runs independently.
169
+ - Legacy single-object config is auto-normalized to one connection.
170
+ - Client runtime JSON files (`delta_timer.json`, `subscription.json`, `sentence_filter.json`) are stored per connection and can be edited via API.
373
171
 
374
- The plugin core is decomposed into focused modules:
172
+ For complete setting definitions and ranges, use `docs/configuration-reference.md`.
375
173
 
376
- | Module | Responsibility |
377
- |--------|---------------|
378
- | `index.js` | Plugin entry point, shared state, file watchers, lifecycle |
379
- | `lib/constants.js` | Shared constants and batch size calculation |
380
- | `lib/CircularBuffer.js` | Fixed-size circular buffer for O(1) metrics history |
381
- | `lib/crypto.js` | AES-256-GCM encryption and decryption |
382
- | `lib/metrics.js` | Bandwidth tracking, path analytics, error recording |
383
- | `lib/pathDictionary.js` | Signal K path encoding (170+ paths) |
384
- | `lib/pipeline.js` | Compress → encrypt → send / receive → decrypt → decompress |
385
- | `lib/routes.js` | HTTP route handlers, rate limiting, config file I/O |
174
+ Schema and migration helpers:
386
175
 
387
- Modules are wired together via factory functions that receive a shared `state` object by reference, enabling cross-module state access without globals.
176
+ - `schemas/config.schema.json` (machine-readable config schema)
177
+ - `src/scripts/migrate-config.ts` (convert legacy flat config to `connections[]`)
178
+ - `npm run migrate:config -- <input.json> [output.json]`
388
179
 
389
- ### Project Structure
180
+ ## Security notes
390
181
 
391
- ```
392
- signalk-edge-link/
393
- ├── index.js # Plugin entry, state, watchers, lifecycle
394
- ├── lib/
395
- │ ├── CircularBuffer.js # Fixed-size circular buffer
396
- │ ├── constants.js # Shared constants and utilities
397
- │ ├── crypto.js # AES-256-GCM encryption module
398
- │ ├── metrics.js # Metrics, bandwidth, path analytics
399
- │ ├── pathDictionary.js # Signal K path encoding (170+ paths)
400
- │ ├── pipeline.js # Pack/unpack pipeline (compress, encrypt, UDP)
401
- │ └── routes.js # HTTP routes and rate limiting
402
- ├── src/
403
- │ ├── webapp/
404
- │ │ ├── index.js # Web dashboard (vanilla JS)
405
- │ │ └── styles.css
406
- │ └── components/
407
- │ └── PluginConfigurationPanel.jsx # React config panel
408
- ├── __tests__/ # 209 tests across 9 files
409
- │ ├── crypto.test.js
410
- │ ├── pathDictionary.test.js
411
- │ ├── compression.test.js
412
- │ ├── full-pipeline.test.js
413
- │ ├── smartBatching.test.js
414
- │ ├── config.test.js
415
- │ ├── index.test.js
416
- │ ├── webapp.test.js
417
- │ └── integration-pipe.test.js
418
- └── public/ # Built UI files (generated)
419
- ```
182
+ - Uses AES-256-GCM authenticated encryption.
183
+ - Keys must match exactly and can be entered as 32-character ASCII, 64-character hex, or 44-character base64.
184
+ - Restrict UDP ingress to trusted source addresses whenever possible.
420
185
 
421
- ### Build Commands
186
+ Example key generation:
422
187
 
423
188
  ```bash
424
- npm run dev # Development build with watch mode
425
- npm run build # Production build
426
- npm test # Run all 209 tests
427
- npm run test:watch # Run tests in watch mode
428
- npm run test:coverage # Generate coverage report
429
- npm run lint # Check code style
430
- npm run lint:fix # Auto-fix linting issues
431
- npm run format # Format code with Prettier
189
+ openssl rand -hex 32
432
190
  ```
433
191
 
434
- ### Testing
435
-
436
- The test suite covers all critical paths with 209 tests across 9 files:
437
-
438
- | Test file | Scope |
439
- |-----------|-------|
440
- | `crypto.test.js` | Encryption, decryption, key validation |
441
- | `pathDictionary.test.js` | Path encoding and decoding |
442
- | `compression.test.js` | Brotli compression effectiveness |
443
- | `full-pipeline.test.js` | End-to-end compression + encryption round-trip |
444
- | `smartBatching.test.js` | Rolling average, batch limits, size verification |
445
- | `config.test.js` | Configuration file creation, loading, hot-reload |
446
- | `index.test.js` | Plugin lifecycle, schema validation |
447
- | `webapp.test.js` | Web UI metrics and API endpoints |
448
- | `integration-pipe.test.js` | Full input → backend → frontend data flow |
192
+ ## Troubleshooting
449
193
 
450
- Run a specific test suite:
194
+ Common checks:
451
195
 
452
- ```bash
453
- npm test -- crypto.test.js
454
- npm test -- full-pipeline.test.js
455
- npm test -- --coverage
456
- ```
196
+ - Verify `udpAddress`, `udpPort`, and `secretKey` match both ends.
197
+ - Confirm server UDP port is reachable and not already in use.
198
+ - If link quality is poor, switch to `protocolVersion: 3` when both peers can upgrade together, or `2` if you must stay compatible with an existing v2 peer.
457
199
 
458
- ### Technical Reference
200
+ For issue-oriented diagnostics, use `docs/troubleshooting.md`.
459
201
 
460
- **Packet format:**
202
+ ## Developer commands
461
203
 
462
- ```
463
- [IV (12 bytes)][Encrypted Data][Auth Tag (16 bytes)]
464
- Total overhead: 28 bytes per packet
204
+ ```bash
205
+ npm run build
206
+ npm run dev
207
+ npm test
208
+ npm run test:v2
209
+ npm run test:integration
210
+ npm run lint
211
+ npm run lint:fix
212
+ npm run cli -- help
213
+ npm run cli -- instances list --token=$EDGE_LINK_TOKEN --state=running --limit=10 --page=1 --format=table
214
+ npm run cli -- instances show alpha --token=$EDGE_LINK_TOKEN --format=table
215
+ npm run cli -- instances create --config ./new-instance.json --token=$EDGE_LINK_TOKEN
216
+ npm run cli -- instances update alpha --patch '{"udpAddress":"10.0.0.2"}' --token=$EDGE_LINK_TOKEN
217
+ npm run cli -- instances delete alpha --token=$EDGE_LINK_TOKEN
218
+ npm run cli -- bonding status --token=$EDGE_LINK_TOKEN --format=table
219
+ npm run cli -- bonding update --patch '{"failoverThreshold":300}' --token=$EDGE_LINK_TOKEN
220
+ npm run cli -- status --token=$EDGE_LINK_TOKEN --format=table
465
221
  ```
466
222
 
467
- **Compression pipeline (detailed):**
223
+ ## Management API security
468
224
 
469
- ```
470
- Client side:
471
- JSON.stringify(delta) → Serialization
472
- → [pathDictionary.encode()] → Optional: numeric path IDs
473
- → [msgpack.encode()] → Optional: binary format
474
- → brotli.compress(quality=10) → Maximum compression
475
- → encryptBinary(key) → AES-256-GCM
476
- → UDP send
477
-
478
- Server side:
479
- UDP receive
480
- → decryptBinary(key) → Verify + decrypt
481
- → brotli.decompress()
482
- → [msgpack.decode()]
483
- → [pathDictionary.decode()]
484
- → JSON.parse()
485
- → Signal K handleMessage()
486
- ```
225
+ Set `managementApiToken` in plugin options (or the environment variable `SIGNALK_EDGE_LINK_MANAGEMENT_TOKEN`). Protected routes include:
487
226
 
488
- **Smart batching constants:**
227
+ - `/instances`, `/bonding`, `/status`, `/plugin-config`
228
+ - `/config/*`, `/connections/:id/config/*`
229
+ - `/connections/:id/metrics`, `/connections/:id/network-metrics`
230
+ - `/connections/:id/bonding`, `/connections/:id/congestion`
231
+ - `/connections/:id/monitoring/*`, `/monitoring/alerts`
232
+ - `/capture/*`, `/delta-timer`
489
233
 
490
- | Constant | Value | Purpose |
491
- |----------|-------|---------|
492
- | Safety margin | 85% | Target 85% of MTU (1190 bytes effective) |
493
- | Smoothing factor | 0.2 | Rolling average weight (20% new, 80% old) |
494
- | Initial estimate | 200 bytes | Starting bytes-per-delta assumption |
495
- | Min deltas | 1 | Always send at least 1 delta |
496
- | Max deltas | 50 | Cap to prevent excessive batching latency |
234
+ Send the token as either:
497
235
 
498
- **Performance characteristics:**
236
+ - `X-Edge-Link-Token: <token>`
237
+ - `Authorization: Bearer <token>`
499
238
 
500
- | Metric | Value |
501
- |--------|-------|
502
- | Compression ratio | 85–97% on typical Signal K data |
503
- | Packet latency | 20–30 ms (serialize → compress → encrypt) |
504
- | Throughput | 10–100 Hz update rates |
505
- | Memory | Constant O(1) with circular buffers |
239
+ CLI commands support `--token=<token>` or the `SIGNALK_EDGE_LINK_MANAGEMENT_TOKEN` environment variable.
506
240
 
507
- ### Contributing
241
+ ## Web UI token injection
508
242
 
509
- 1. Fork the repository
510
- 2. Create a feature branch: `git checkout -b feature/name`
511
- 3. Make changes and add tests
512
- 4. Run `npm test` and `npm run lint` (all must pass)
513
- 5. Run `npm run build` (must succeed)
514
- 6. Commit with clear messages using conventional format
515
- 7. Submit a pull request
243
+ Management pages automatically attach auth headers when a token is available. Token sources are checked in this order:
516
244
 
517
- **Requirements for all contributions:**
518
- - All 209 tests pass
519
- - No ESLint errors or warnings
520
- - Code formatted with Prettier
521
- - Test coverage for new features
522
- - README updated if adding features
245
+ 1. `window.__EDGE_LINK_AUTH__.token` — injected global (preferred for server-side injection)
246
+ 2. URL query parameter `?edgeLinkToken=<token>`
247
+ 3. `localStorage.setItem("signalkEdgeLinkManagementToken", "<token>")`
523
248
 
524
- **Commit message format:**
249
+ The UI sends both `X-Edge-Link-Token` and `Authorization: Bearer <token>` by default. Override with:
525
250
 
251
+ ```javascript
252
+ window.__EDGE_LINK_AUTH__ = {
253
+ token: "<token>",
254
+ queryParam: "edgeLinkToken",
255
+ localStorageKey: "signalkEdgeLinkManagementToken",
256
+ headerMode: "both" // "both" | "authorization" | "x-edge-link-token"
257
+ };
526
258
  ```
527
- type: description
528
259
 
529
- Types: feat, fix, docs, style, refactor, perf, test, chore
530
- ```
531
-
532
- ---
260
+ ## Documentation map
261
+
262
+ - `docs/README.md` (documentation index)
263
+ - `docs/architecture-overview.md` (system architecture and lifecycle)
264
+ - `docs/configuration-reference.md` (settings and defaults)
265
+ - `docs/api-reference.md
266
+ - `docs/protocol-v2.md` (reliable protocol operational overview)
267
+ - `docs/protocol-v3-spec.md` (authenticated control-plane details)
268
+ - `docs/bonding.md` (bonding concepts and API usage)
269
+ - `docs/congestion-control.md` (congestion-control behavior and tuning)
270
+ - `docs/metrics.md` (metrics and monitoring reference)
271
+ - `docs/management-tools.md` (instance/bonding API + CLI operations)
272
+ - `docs/security.md` (security guidance and deployment hardening)
273
+ - `docs/performance-tuning.md` (deployment tuning recommendations by hardware profile)
274
+ - `samples/` (example JSON configurations for minimal/dev/v2-bonding setups)
275
+ - `grafana/dashboards/edge-link.json` (starter Grafana dashboard)
276
+ - `schemas/config.schema.json` (unified plugin config schema)
277
+ - `src/scripts/migrate-config.ts` (legacy config migration utility)
278
+ - `src/bin/edge-link-cli.ts` (CLI wrapper for migration and instance/bonding management)
533
279
 
534
280
  ## License
535
281
 
536
- MIT License — Copyright (c) 2024 Karl-Erik Gustafsson
537
-
538
- See [LICENSE](LICENSE) file for details.
282
+ MIT. See `LICENSE`.