signalk-data-connector 1.0.0-beta.100

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,11 @@
1
+ # To get started with Dependabot version updates, you'll need to specify which
2
+ # package ecosystems to update and where the package manifests are located.
3
+ # Please see the documentation for all configuration options:
4
+ # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
5
+
6
+ version: 2
7
+ updates:
8
+ - package-ecosystem: "npm" # See documentation for possible values
9
+ directory: "/" # Location of package manifests
10
+ schedule:
11
+ interval: "weekly"
@@ -0,0 +1,13 @@
1
+ # Dependencies
2
+ node_modules/
3
+
4
+ # Build output
5
+ public/
6
+ dist/
7
+ coverage/
8
+
9
+ # Config files
10
+ package-lock.json
11
+
12
+ # Logs
13
+ *.log
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Karl-Erik Gustafsson
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,536 @@
1
+ # Signal K Data Connector
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-data-connector)
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-data-connector/refs/heads/main/doc/dataconnectorconcept.jpg)
10
+
11
+ ---
12
+
13
+ ## Table of Contents
14
+
15
+ - [Overview](#overview)
16
+ - [Getting Started](#getting-started)
17
+ - [Installation](#installation)
18
+ - [Quick Start](#quick-start)
19
+ - [Configuration](#configuration)
20
+ - [Server Mode](#server-mode-receiver)
21
+ - [Client Mode](#client-mode-sender)
22
+ - [Web Dashboard](#web-dashboard)
23
+ - [Configuration Files](#configuration-files)
24
+ - [Network Monitoring](#network-monitoring)
25
+ - [Performance](#performance)
26
+ - [Bandwidth Comparison](#bandwidth-comparison)
27
+ - [Smart Batching](#smart-batching)
28
+ - [Optimization Tips](#optimization-tips)
29
+ - [Security](#security)
30
+ - [Encryption](#encryption)
31
+ - [Secret Key Requirements](#secret-key-requirements)
32
+ - [Best Practices](#best-practices)
33
+ - [Troubleshooting](#troubleshooting)
34
+ - [Development](#development)
35
+ - [Architecture](#architecture)
36
+ - [Project Structure](#project-structure)
37
+ - [Build Commands](#build-commands)
38
+ - [Testing](#testing)
39
+ - [Technical Reference](#technical-reference)
40
+ - [Contributing](#contributing)
41
+ - [License](#license)
42
+
43
+ ---
44
+
45
+ ## Overview
46
+
47
+ Signal K Data Connector 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.
48
+
49
+ **Key capabilities:**
50
+
51
+ | Feature | Description |
52
+ |---------|-------------|
53
+ | Encrypted transport | AES-256-GCM authenticated encryption with per-message unique IV |
54
+ | Brotli compression | Quality-10 compression with 85–97% reduction on typical data |
55
+ | Binary protocol | Zero JSON overhead in the wire format |
56
+ | Path dictionary | 170+ Signal K paths mapped to numeric IDs (10–20% savings) |
57
+ | MessagePack | Optional binary serialization (15–25% additional savings) |
58
+ | Smart batching | Adaptive packet sizing that prevents UDP fragmentation |
59
+ | Sentence filtering | Exclude NMEA sentences (GSV, GSA, etc.) to reduce bandwidth |
60
+ | Network monitoring | TCP ping with RTT measurement published to Signal K |
61
+ | Web dashboard | Real-time bandwidth, compression, and path analytics |
62
+ | Hot-reload config | Configuration files reload automatically on change |
63
+
64
+ ---
65
+
66
+ ## Getting Started
67
+
68
+ ### Installation
69
+
70
+ ```bash
71
+ cd ~/.signalk/node_modules/
72
+ git clone https://github.com/KEGustafsson/signalk-data-connector.git
73
+ cd signalk-data-connector
74
+ npm install
75
+ npm run build
76
+ ```
77
+
78
+ Restart your Signal K server after installation.
79
+
80
+ ### Quick Start
81
+
82
+ 1. Open **Admin UI → Plugin Config → Signal K Data Connector**
83
+ 2. Choose an operation mode:
84
+ - **Server** — receives data from remote clients
85
+ - **Client** — sends data to a remote server
86
+ 3. Set the **UDP port** (must match between client and server)
87
+ 4. Enter a **32-character encryption key** (must be identical on both ends)
88
+ 5. For client mode, enter the **server IP address**
89
+ 6. Enable the plugin and verify data flow in the web dashboard
90
+
91
+ > **Tip:** Start with the default settings. Enable path dictionary and MessagePack later for additional bandwidth savings.
92
+
93
+ ---
94
+
95
+ ## Configuration
96
+
97
+ The plugin provides a custom React-based configuration UI that dynamically adapts to the selected operation mode, showing only relevant settings.
98
+
99
+ **Access:** Admin UI → Plugin Config → Signal K Data Connector
100
+
101
+ ### Server Mode (Receiver)
102
+
103
+ | Setting | Description |
104
+ |---------|-------------|
105
+ | Operation Mode | Server/Client selector |
106
+ | UDP Port | Port to listen on (1024–65535) |
107
+ | Encryption Key | 32-character secret key |
108
+ | MessagePack | Enable binary serialization |
109
+ | Path Dictionary | Enable path encoding |
110
+
111
+ ### Client Mode (Sender)
112
+
113
+ | Setting | Description |
114
+ |---------|-------------|
115
+ | Operation Mode | Server/Client selector |
116
+ | UDP Port | Port to send to |
117
+ | Encryption Key | 32-character secret key (must match server) |
118
+ | Destination Address | Server IP or hostname |
119
+ | Heartbeat Interval | Keep-alive message frequency (seconds) |
120
+ | Connectivity Test Target | Address to ping for network monitoring |
121
+ | Connectivity Test Port | Port to test (80, 443, etc.) |
122
+ | Check Interval | How often to test connectivity (minutes) |
123
+ | MessagePack | Enable binary serialization |
124
+ | Path Dictionary | Enable path encoding |
125
+
126
+ Additional client settings are available in the web dashboard:
127
+ - **Delta timer** — collection interval (100–10000 ms)
128
+ - **Subscription paths** — Signal K paths to transmit
129
+ - **Sentence filter** — NMEA sentences to exclude (e.g., `GSV, GSA, VTG`)
130
+
131
+ ### Web Dashboard
132
+
133
+ **Access:** `http://[signalk-server]:3000/plugins/signalk-data-connector`
134
+
135
+ The dashboard provides real-time monitoring and configuration controls.
136
+
137
+ **Client mode:**
138
+ - Delta timer and subscription management
139
+ - Sentence filter configuration
140
+ - Upload/download bandwidth with compression ratio
141
+ - Bandwidth savings display (actual bytes saved)
142
+ - Path analytics with per-path data volume breakdown
143
+ - Performance metrics (errors, uptime, deltas sent)
144
+ - Rate history chart (last 150 seconds)
145
+
146
+ **Server mode:**
147
+ - Download bandwidth and packet rate
148
+ - Bandwidth savings display
149
+ - Incoming path analytics
150
+ - Performance metrics (deltas received, errors)
151
+ - Compression effectiveness tracking
152
+
153
+ ### Configuration Files
154
+
155
+ These JSON files are stored in the plugin data directory and support hot-reload — changes take effect automatically without restarting.
156
+
157
+ | File | Purpose | Default |
158
+ |------|---------|---------|
159
+ | `delta_timer.json` | Collection interval in ms | `{"deltaTimer": 1000}` |
160
+ | `subscription.json` | Signal K paths to subscribe | `{"context": "*", "subscribe": [...]}` |
161
+ | `sentence_filter.json` | NMEA sentences to exclude | `{"sentences": []}` |
162
+
163
+ ### API Endpoints
164
+
165
+ All endpoints are rate-limited to 20 requests per minute per IP.
166
+
167
+ | Method | Endpoint | Description |
168
+ |--------|----------|-------------|
169
+ | GET | `/plugins/signalk-data-connector/config/:filename` | Read a configuration file |
170
+ | POST | `/plugins/signalk-data-connector/config/:filename` | Update a configuration file |
171
+ | GET | `/plugins/signalk-data-connector/metrics` | Real-time statistics and performance data |
172
+ | GET | `/plugins/signalk-data-connector/paths` | Path dictionary information |
173
+ | GET | `/plugins/signalk-data-connector/plugin-config` | Current plugin configuration |
174
+ | POST | `/plugins/signalk-data-connector/plugin-config` | Update plugin configuration |
175
+ | GET | `/plugins/signalk-data-connector/plugin-schema` | Plugin schema definition |
176
+
177
+ ---
178
+
179
+ ## Network Monitoring
180
+
181
+ In client mode, the plugin measures **Round Trip Time (RTT)** using TCP ping to monitor connectivity and latency.
182
+
183
+ **How it works:**
184
+ 1. TCP ping is sent to the configured test address and port at the configured interval
185
+ 2. RTT is published to local Signal K at `networking.modem.rtt` (value in seconds)
186
+ 3. If subscribed, RTT data is transmitted to the remote server with other data
187
+
188
+ **To enable RTT transmission:** Add `networking.modem.rtt` to your subscription paths.
189
+
190
+ **Use cases:**
191
+ - Monitor cellular or satellite modem latency
192
+ - Track connection quality over time
193
+ - Trigger alerts on high latency
194
+ - Analyze network performance trends
195
+
196
+ ---
197
+
198
+ ## Performance
199
+
200
+ ### Bandwidth Comparison
201
+
202
+ ![Data Rate Comparison](https://raw.githubusercontent.com/KEGustafsson/signalk-data-connector/refs/heads/main/doc/datarate.jpg)
203
+
204
+ | Mode | Bandwidth | Reduction vs. WebSocket |
205
+ |------|-----------|------------------------|
206
+ | 1000 ms collection | ~44.1 kb/s | ~70% |
207
+ | 100 ms collection | ~107.7 kb/s | ~28% |
208
+ | WebSocket real-time | ~149.5 kb/s | — |
209
+
210
+ Typical compression results on Signal K data:
211
+
212
+ ```
213
+ Original: 19,293 bytes → Encrypted + Compressed: 622 bytes (96.78% reduction)
214
+ ```
215
+
216
+ ### Smart Batching
217
+
218
+ The plugin uses adaptive smart batching to keep UDP packets under the MTU limit (1400 bytes), preventing fragmentation that can cause data loss.
219
+
220
+ 1. **Rolling average** — tracks bytes-per-delta using exponential smoothing
221
+ 2. **Dynamic batch sizing** — calculates optimal deltas per packet based on recent sizes
222
+ 3. **Early send trigger** — sends immediately when a batch reaches the predicted size limit
223
+ 4. **Self-learning** — continuously adapts as data patterns change
224
+
225
+ ```
226
+ Example: Initial estimate 5 deltas/batch → After learning: 11 deltas/batch
227
+ All packets stay well under 1400 bytes
228
+ ```
229
+
230
+ ### Optimization Tips
231
+
232
+ For the best bandwidth efficiency:
233
+
234
+ 1. **Increase delta timer** — 1000 ms gives optimal compression; lower values increase bandwidth
235
+ 2. **Enable path dictionary** — saves 10–20% by replacing path strings with numeric IDs
236
+ 3. **Enable MessagePack** — saves 15–25% with binary serialization
237
+ 4. **Filter NMEA sentences** — exclude GSV, GSA, VTG to remove unnecessary data
238
+ 5. **Review subscriptions** — subscribe only to paths you need
239
+
240
+ ---
241
+
242
+ ## Security
243
+
244
+ ### Encryption
245
+
246
+ All data is encrypted with **AES-256-GCM**, providing authenticated encryption in a single operation.
247
+
248
+ | Property | Detail |
249
+ |----------|--------|
250
+ | Algorithm | AES-256-GCM |
251
+ | IV | 12 bytes, unique per message |
252
+ | Auth tag | 16 bytes, tamper detection |
253
+ | Wire format | `[IV (12 bytes)][Encrypted Data][Auth Tag (16 bytes)]` |
254
+ | Overhead | 28 bytes per packet |
255
+
256
+ **Security features:**
257
+ - Tamper detection — any modification causes decryption failure
258
+ - Rate-limited API endpoints (20 req/min/IP)
259
+ - Input validation on all parameters
260
+ - Key entropy checking — rejects weak keys
261
+ - XSS protection in the web UI
262
+ - Stateless UDP — no session state to compromise
263
+
264
+ ### Secret Key Requirements
265
+
266
+ - Exactly **32 characters** (256 bits)
267
+ - Minimum **8 unique characters**
268
+ - Must match on both client and server
269
+
270
+ Generate a secure key:
271
+
272
+ ```bash
273
+ openssl rand -base64 32 | cut -c1-32
274
+ ```
275
+
276
+ **Valid examples:**
277
+ ```
278
+ Abc123!@#XYZ456$%^uvw789&*()pqr0
279
+ K9#mP2$nQ7@rS4%tU6^vW8*xY3!zA5&
280
+ abcdefgh12345678901234567890abcd
281
+ ```
282
+
283
+ **Invalid examples:**
284
+ ```
285
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa # All same character
286
+ abababababababababababababababab # Insufficient diversity
287
+ MySecretKey123 # Too short
288
+ ```
289
+
290
+ ### Best Practices
291
+
292
+ 1. Use strong, randomly generated keys (`openssl rand` recommended)
293
+ 2. Never commit keys to version control
294
+ 3. Rotate keys periodically (every 6–12 months)
295
+ 4. Monitor logs for decryption failures (may indicate attacks or key mismatch)
296
+ 5. Restrict UDP access with firewall rules to known IP addresses
297
+ 6. Test configuration in a safe environment before production deployment
298
+
299
+ ---
300
+
301
+ ## Troubleshooting
302
+
303
+ ### Plugin Not Loading
304
+
305
+ - Verify `npm install` completed successfully
306
+ - Check Signal K server logs for errors
307
+ - Ensure plugin directory is `~/.signalk/node_modules/signalk-data-connector`
308
+ - Verify Node.js version ≥ 14.0.0
309
+
310
+ ### Web UI Not Accessible
311
+
312
+ - Run `npm run build` to generate UI files
313
+ - Verify `public/` directory exists with built files
314
+ - Clear browser cache and refresh
315
+
316
+ ### No Data Transmission
317
+
318
+ **Client side:**
319
+ 1. Confirm encryption keys match on both ends
320
+ 2. Verify UDP port and destination address
321
+ 3. Check firewall allows UDP traffic on the configured port
322
+ 4. Confirm subscription paths are valid Signal K paths
323
+ 5. Verify delta timer is running (check metrics in web dashboard)
324
+
325
+ **Server side:**
326
+ 1. Verify UDP port is not blocked by firewall
327
+ 2. Confirm encryption key matches the client
328
+ 3. Check Signal K logs for decryption errors
329
+ 4. Verify client is sending data (check client metrics)
330
+
331
+ **Common error messages:**
332
+
333
+ | Message | Cause |
334
+ |---------|-------|
335
+ | `Unsupported state or unable to authenticate data` | Mismatched encryption keys |
336
+ | `Invalid packet size` | Corrupted data or network issues |
337
+ | `Secret key must be exactly 32 characters` | Invalid key length |
338
+
339
+ ### Poor Performance
340
+
341
+ - Increase delta timer for better compression (1000 ms recommended)
342
+ - Enable path dictionary and MessagePack
343
+ - Filter unnecessary NMEA sentences
344
+ - Check network latency with the ping monitor
345
+ - Monitor CPU usage (Brotli compression at quality 10 is CPU-intensive)
346
+
347
+ ### Debug Logging
348
+
349
+ Enable in Signal K plugin settings to see:
350
+ - Connection monitor status and ping results
351
+ - Configuration file changes (automatic reload)
352
+ - Delta transmission statistics
353
+ - Compression ratios and packet sizes
354
+ - Error messages with full context
355
+
356
+ ---
357
+
358
+ ## Development
359
+
360
+ ### Architecture
361
+
362
+ **Data pipeline:**
363
+
364
+ ```
365
+ Client (Sender):
366
+ Signal K Deltas → Filter → [Path Encode] → [MessagePack] → Brotli → AES-256-GCM → UDP
367
+
368
+ Server (Receiver):
369
+ UDP → AES-256-GCM → Brotli → [MessagePack] → [Path Decode] → Signal K
370
+ ```
371
+
372
+ The plugin core is decomposed into focused modules:
373
+
374
+ | Module | Responsibility |
375
+ |--------|---------------|
376
+ | `index.js` | Plugin entry point, shared state, file watchers, lifecycle |
377
+ | `lib/constants.js` | Shared constants and batch size calculation |
378
+ | `lib/CircularBuffer.js` | Fixed-size circular buffer for O(1) metrics history |
379
+ | `lib/crypto.js` | AES-256-GCM encryption and decryption |
380
+ | `lib/metrics.js` | Bandwidth tracking, path analytics, error recording |
381
+ | `lib/pathDictionary.js` | Signal K path encoding (170+ paths) |
382
+ | `lib/pipeline.js` | Compress → encrypt → send / receive → decrypt → decompress |
383
+ | `lib/routes.js` | HTTP route handlers, rate limiting, config file I/O |
384
+
385
+ Modules are wired together via factory functions that receive a shared `state` object by reference, enabling cross-module state access without globals.
386
+
387
+ ### Project Structure
388
+
389
+ ```
390
+ signalk-data-connector/
391
+ ├── index.js # Plugin entry, state, watchers, lifecycle
392
+ ├── lib/
393
+ │ ├── CircularBuffer.js # Fixed-size circular buffer
394
+ │ ├── constants.js # Shared constants and utilities
395
+ │ ├── crypto.js # AES-256-GCM encryption module
396
+ │ ├── metrics.js # Metrics, bandwidth, path analytics
397
+ │ ├── pathDictionary.js # Signal K path encoding (170+ paths)
398
+ │ ├── pipeline.js # Pack/unpack pipeline (compress, encrypt, UDP)
399
+ │ └── routes.js # HTTP routes and rate limiting
400
+ ├── src/
401
+ │ ├── webapp/
402
+ │ │ ├── index.js # Web dashboard (vanilla JS)
403
+ │ │ └── styles.css
404
+ │ └── components/
405
+ │ └── PluginConfigurationPanel.jsx # React config panel
406
+ ├── __tests__/ # 209 tests across 9 files
407
+ │ ├── crypto.test.js
408
+ │ ├── pathDictionary.test.js
409
+ │ ├── compression.test.js
410
+ │ ├── full-pipeline.test.js
411
+ │ ├── smartBatching.test.js
412
+ │ ├── config.test.js
413
+ │ ├── index.test.js
414
+ │ ├── webapp.test.js
415
+ │ └── integration-pipe.test.js
416
+ └── public/ # Built UI files (generated)
417
+ ```
418
+
419
+ ### Build Commands
420
+
421
+ ```bash
422
+ npm run dev # Development build with watch mode
423
+ npm run build # Production build
424
+ npm test # Run all 209 tests
425
+ npm run test:watch # Run tests in watch mode
426
+ npm run test:coverage # Generate coverage report
427
+ npm run lint # Check code style
428
+ npm run lint:fix # Auto-fix linting issues
429
+ npm run format # Format code with Prettier
430
+ ```
431
+
432
+ ### Testing
433
+
434
+ The test suite covers all critical paths with 209 tests across 9 files:
435
+
436
+ | Test file | Scope |
437
+ |-----------|-------|
438
+ | `crypto.test.js` | Encryption, decryption, key validation |
439
+ | `pathDictionary.test.js` | Path encoding and decoding |
440
+ | `compression.test.js` | Brotli compression effectiveness |
441
+ | `full-pipeline.test.js` | End-to-end compression + encryption round-trip |
442
+ | `smartBatching.test.js` | Rolling average, batch limits, size verification |
443
+ | `config.test.js` | Configuration file creation, loading, hot-reload |
444
+ | `index.test.js` | Plugin lifecycle, schema validation |
445
+ | `webapp.test.js` | Web UI metrics and API endpoints |
446
+ | `integration-pipe.test.js` | Full input → backend → frontend data flow |
447
+
448
+ Run a specific test suite:
449
+
450
+ ```bash
451
+ npm test -- crypto.test.js
452
+ npm test -- full-pipeline.test.js
453
+ npm test -- --coverage
454
+ ```
455
+
456
+ ### Technical Reference
457
+
458
+ **Packet format:**
459
+
460
+ ```
461
+ [IV (12 bytes)][Encrypted Data][Auth Tag (16 bytes)]
462
+ Total overhead: 28 bytes per packet
463
+ ```
464
+
465
+ **Compression pipeline (detailed):**
466
+
467
+ ```
468
+ Client side:
469
+ JSON.stringify(delta) → Serialization
470
+ → [pathDictionary.encode()] → Optional: numeric path IDs
471
+ → [msgpack.encode()] → Optional: binary format
472
+ → brotli.compress(quality=10) → Maximum compression
473
+ → encryptBinary(key) → AES-256-GCM
474
+ → UDP send
475
+
476
+ Server side:
477
+ UDP receive
478
+ → decryptBinary(key) → Verify + decrypt
479
+ → brotli.decompress()
480
+ → [msgpack.decode()]
481
+ → [pathDictionary.decode()]
482
+ → JSON.parse()
483
+ → Signal K handleMessage()
484
+ ```
485
+
486
+ **Smart batching constants:**
487
+
488
+ | Constant | Value | Purpose |
489
+ |----------|-------|---------|
490
+ | Safety margin | 85% | Target 85% of MTU (1190 bytes effective) |
491
+ | Smoothing factor | 0.2 | Rolling average weight (20% new, 80% old) |
492
+ | Initial estimate | 200 bytes | Starting bytes-per-delta assumption |
493
+ | Min deltas | 1 | Always send at least 1 delta |
494
+ | Max deltas | 50 | Cap to prevent excessive batching latency |
495
+
496
+ **Performance characteristics:**
497
+
498
+ | Metric | Value |
499
+ |--------|-------|
500
+ | Compression ratio | 85–97% on typical Signal K data |
501
+ | Packet latency | 20–30 ms (serialize → compress → encrypt) |
502
+ | Throughput | 10–100 Hz update rates |
503
+ | Memory | Constant O(1) with circular buffers |
504
+
505
+ ### Contributing
506
+
507
+ 1. Fork the repository
508
+ 2. Create a feature branch: `git checkout -b feature/name`
509
+ 3. Make changes and add tests
510
+ 4. Run `npm test` and `npm run lint` (all must pass)
511
+ 5. Run `npm run build` (must succeed)
512
+ 6. Commit with clear messages using conventional format
513
+ 7. Submit a pull request
514
+
515
+ **Requirements for all contributions:**
516
+ - All 209 tests pass
517
+ - No ESLint errors or warnings
518
+ - Code formatted with Prettier
519
+ - Test coverage for new features
520
+ - README updated if adding features
521
+
522
+ **Commit message format:**
523
+
524
+ ```
525
+ type: description
526
+
527
+ Types: feat, fix, docs, style, refactor, perf, test, chore
528
+ ```
529
+
530
+ ---
531
+
532
+ ## License
533
+
534
+ MIT License — Copyright (c) 2024 Karl-Erik Gustafsson
535
+
536
+ See [LICENSE](LICENSE) file for details.
Binary file
Binary file