@signalk/tracks-plugin 3.0.0-beta.1 → 3.0.0-beta.2

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/README.md CHANGED
@@ -2,21 +2,17 @@
2
2
 
3
3
  Signal K server plugin that accumulates vessel positions into tracks and implements the track API.
4
4
 
5
- Positions are accumulated into a per-vessel sliding window using a configured time resolution. The
6
- **Where tracks come from after a restart** setting chooses what happens to them:
5
+ Positions are recorded to a SQLite file in the plugin's data directory, at a configured time
6
+ resolution, so tracks survive a restart with no other plugin required. The plugin is enabled on
7
+ install and needs no configuration to start recording.
7
8
 
8
- | Setting | Behaviour |
9
- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
10
- | `history` | _(default)_ Held in memory, and the own vessel's track is refilled on startup from a history provider such as `signalk-to-influxdb2` or `signalk-questdb`. |
11
- | `sqlite` | Recorded to a database file in the plugin's data directory, so every vessel's track survives a restart with no other plugin required. |
12
- | `memory` | Held in memory only; tracks start empty after a restart. |
9
+ | Setting | Behaviour |
10
+ | ---------------------------------------------- | ------------------------------------------------------------------------------ |
11
+ | Track resolution | Minimum spacing between recorded positions. |
12
+ | Days of the own vessel's track to keep | Trims only the own vessel. 0 keeps everything; it is never dropped for idling. |
13
+ | Days to keep another vessel after its last fix | Drops a vessel that has gone quiet. 0 keeps every vessel indefinitely. |
13
14
 
14
- All three work with no other plugin installed — with `history` and no provider present, tracks simply
15
- build up from live data. `sqlite` also takes a retention setting, in days, for how long to keep
16
- positions.
17
-
18
- This replaces the earlier `bootstrapFromHistory` checkbox. Existing configurations keep working:
19
- the setting is still read, with `false` mapping to `memory` and anything else to `history`.
15
+ The plugin's configuration page shows the current defaults, and is the authority on them.
20
16
 
21
17
  The package also exports a client side `TrackAccumulator` class that manages the track for a single
22
18
  vessel, exposing the result as `Observable<LatLngTuple[]>`.
@@ -28,9 +24,13 @@ With a history provider installed — [signalk-questdb](https://www.npmjs.com/pa
28
24
  both it and the plugin's own store: the provider is the finer record for as long as its retention
29
25
  reaches, and the store is what remains of everything older or of any period the provider missed.
30
26
 
31
- Nothing needs configuring for this, and the plugin works exactly as before with no provider
32
- installed. See [docs/history-and-storage.md](docs/history-and-storage.md) for what that means in
33
- practice.
27
+ Nothing needs configuring for this, and the plugin works fully with no provider installed. Its own
28
+ store is a SQLite file in the plugin's data directory, so tracks survive a restart on their own.
29
+ See [docs/history-and-storage.md](docs/history-and-storage.md) for what that means in practice.
30
+
31
+ The own vessel is kept indefinitely by default. Other vessels are kept for 30 days after their last
32
+ fix — a harbour puts hundreds of AIS targets past a receiver in a day, and keeping every one of them
33
+ forever is rarely what anybody wants. Both are settings.
34
34
 
35
35
  ## Glitch filtering
36
36
 
@@ -45,17 +45,18 @@ vessel, and glitches usually miss it by orders of magnitude rather than by a lit
45
45
  speed rather than distance, so a track resuming after a long gap — a passage with the plugin
46
46
  stopped, or an AIS target reappearing — is not filtered. Set it to 0 to record everything.
47
47
 
48
- The same check runs over positions loaded from a history provider at startup, since those carry
49
- the same glitches.
48
+ Positions a history provider supplies are not filtered here — they are that provider's record, and
49
+ it is the one that decides what to keep.
50
50
 
51
51
  ## Pausing while not under way
52
52
 
53
53
  A boat on a mooring for the winter emits a position every second and travels nowhere. Setting
54
54
  **Pause recording while navigation.state is one of** stops those months costing any rows.
55
55
 
56
- Off by default, and it needs `navigation.state` to be set — by
57
- [signalk-autostate](https://github.com/meri-imperiumi/signalk-autostate) or by hand. A vessel
58
- that reports no state is always recorded, so nothing changes for an install that has not opted in.
56
+ On by default for `moored`, `not-under-way` and `aground`. It needs `navigation.state` to be set —
57
+ by [signalk-autostate](https://github.com/meri-imperiumi/signalk-autostate) or by hand — and a
58
+ vessel that reports no state is always recorded, so an install with no state source behaves as
59
+ though this were off. Clear the list to record regardless of state.
59
60
 
60
61
  Two limits are deliberate. **`anchored` is offered but rarely wanted**: an anchor alarm watches
61
62
  exactly the track a vessel makes while swinging on its rode, so pausing there would break it.
@@ -151,7 +152,7 @@ the own vessel. Asking for `self` resolves the alias, so the response tells you
151
152
 
152
153
  `/signalk/v1/api/tracks`
153
154
 
154
- _If `maxRadius` is specified only vessels with last track position within this distance are returned._
155
+ _Every vessel the plugin holds a track for. Add `?radius=` to narrow it to vessels near your own._
155
156
 
156
157
  _Each entry carries `isSelf`, so the own vessel can be told from an AIS target without
157
158
  string-matching the context against the server's self identity._
@@ -166,7 +167,7 @@ without `times` each vessel keeps its single unsegmented line._
166
167
 
167
168
  `/signalk/v1/api/tracks?radius=50000`
168
169
 
169
- _Note: This value overrides the `maxRadius` value specified in plugin configuration._
170
+ _Distance from the own vessel's current position, matched against each track's **last** position — "which vessels are near me now". The v2 Track API asks a different question and matches any position in the window._
170
171
 
171
172
  ---
172
173
 
@@ -203,10 +204,10 @@ npm run format # prettier --write
203
204
  Signal K server against it and feeds positions as deltas — so it covers plugin loading, route
204
205
  mounting and the delta path, none of which the unit suite can. It needs a built server checkout;
205
206
  set `SIGNALK_SERVER_DIR` if yours is not at `~/dev/xxx_signalk-server`. A second tier installs a
206
- real history provider (signalk-questdb) into that server and exercises the startup bootstrap
207
- through it; it skips itself if no QuestDB is reachable at `QUESTDB_URL`. Neither tier runs in CI.
207
+ real history provider (signalk-questdb) into that server and exercises the reconciliation through
208
+ it; it skips itself if no QuestDB is reachable at `QUESTDB_URL`. Neither tier runs in CI.
208
209
 
209
210
  The package is ESM only and targets Node >= 22.5.0, the release that added `node:sqlite`. ESM alone
210
211
  would only need 20.19, the first release in which the Signal K server's `require()`-based plugin
211
- loader can load an ES module, but the sqlite track source raises the floor. The server itself
212
+ loader can load an ES module, but recording to SQLite raises the floor. The server itself
212
213
  requires Node >= 22, so this rules out nothing that could have run the plugin anyway.
@@ -30,9 +30,9 @@ export interface E2EOptions {
30
30
  * Other plugins to install and enable alongside this one, as
31
31
  * `{ 'npm-package-name': pluginConfiguration }`.
32
32
  *
33
- * Used to stand up a real history provider so the bootstrap can be exercised
34
- * through `getHistoryApi()` — the interface this plugin actually depends on —
35
- * rather than against a provider's private storage.
33
+ * Used to stand up a real history provider so the reconciliation can be
34
+ * exercised through `getHistoryApi()` — the interface this plugin actually
35
+ * depends on — rather than against a provider's private storage.
36
36
  */
37
37
  plugins?: Record<string, Record<string, unknown>>;
38
38
  /** Port to boot on, when a test needs its own server. */
@@ -26,7 +26,7 @@ export interface TestHarness {
26
26
  statuses: string[];
27
27
  /**
28
28
  * Install a track with explicit timestamps, bypassing the throttled bus. This
29
- * is the entry point the History API bootstrap uses.
29
+ * bypasses the throttle, which is what makes a back-dated track testable.
30
30
  */
31
31
  seedTrack: (context: string, positions: LatLngTuple[], timestamps: number[]) => void;
32
32
  /** Self position as reported by `getSelfPath`, used for radius filtering. */
@@ -34,6 +34,13 @@ export interface TestHarness {
34
34
  /** The own vessel's navigation.state, as reported by `getSelfPath`. */
35
35
  setSelfState: (state: string | undefined) => void;
36
36
  stop: () => void;
37
+ /**
38
+ * How many positions the plugin's bus subscription has accepted.
39
+ *
40
+ * Observable after stop(), when the store itself is closed and unreadable —
41
+ * which is how a test can still tell that the subscription was torn down.
42
+ */
43
+ emitted: () => number;
37
44
  errors: unknown[][];
38
45
  /**
39
46
  * The v2 Track API provider the plugin registered, or undefined when the
package/dist/index.d.ts CHANGED
@@ -74,6 +74,8 @@ interface App {
74
74
  }
75
75
  interface Plugin {
76
76
  start: (c: TracksPluginConfig) => void;
77
+ /** Enable on install, without waiting for a visit to the plugin config page. */
78
+ enabledByDefault: boolean;
77
79
  stop: () => void;
78
80
  signalKApiRoutes: (r: Router) => Router;
79
81
  id: string;
@@ -89,28 +91,12 @@ interface Plugin {
89
91
  */
90
92
  getTracks: () => TrackStore | undefined;
91
93
  }
92
- /**
93
- * Where tracks come from when the server starts.
94
- *
95
- * - `memory`: start empty, accumulate from the position bus only.
96
- * - `history`: refill from a History provider at startup, then accumulate.
97
- * - `sqlite`: persist to disk, so a restart resumes from what was recorded.
98
- *
99
- * One setting rather than a boolean per source: they are alternatives, and as
100
- * independent booleans a user could enable two and have the same positions
101
- * loaded twice.
102
- */
103
- export type TrackSource = 'memory' | 'history' | 'sqlite';
104
94
  interface TracksPluginConfig {
105
95
  resolution?: number;
106
- pointsToKeep?: number;
107
- maxAge?: number;
108
- maxRadius?: number;
109
- source?: TrackSource;
110
- /** @deprecated superseded by `source`; still honoured for existing configs. */
111
- bootstrapFromHistory?: boolean;
112
- /** Days of history to keep when `source` is `sqlite`. 0 keeps everything. */
96
+ /** Days of the own vessel's track to keep. 0 keeps everything. */
113
97
  retentionDays?: number;
98
+ /** Days another vessel is kept after its last fix. 0 keeps every vessel. */
99
+ aisRetentionDays?: number;
114
100
  /** Minutes without a fix that start a new track segment. 0 disables. */
115
101
  segmentGapMinutes?: number;
116
102
  /** Speed above which a position is treated as a glitch. 0 disables. */
@@ -118,16 +104,6 @@ interface TracksPluginConfig {
118
104
  /** navigation.state values that pause recording of the own vessel. */
119
105
  pauseWhenState?: string[];
120
106
  }
121
- /**
122
- * Resolve the effective source, honouring the setting this replaced.
123
- *
124
- * `bootstrapFromHistory` shipped as a boolean defaulting to true, so an
125
- * installed plugin has it saved in its config either way. Reading `source`
126
- * first and only then falling back keeps those installs working: an explicit
127
- * `false` still means "do not touch the History API", and everything else
128
- * lands on the old default of `history`.
129
- */
130
- export declare const resolveSource: (config: TracksPluginConfig) => TrackSource;
131
107
  export default function ThePlugin(app: App): Plugin;
132
108
  export { Tracks, TrackAccumulator } from './tracks.js';
133
109
  export type { TracksConfig } from './tracks.js';