signalk-questdb 1.5.3 → 1.5.5

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 (55) hide show
  1. package/README.md +54 -0
  2. package/dist/container-env.d.ts +3 -0
  3. package/dist/container-env.js +51 -0
  4. package/dist/container-env.js.map +1 -0
  5. package/dist/delta-routing.d.ts +1 -1
  6. package/dist/delta-routing.js +9 -0
  7. package/dist/delta-routing.js.map +1 -1
  8. package/dist/history-v1.js +158 -4
  9. package/dist/history-v1.js.map +1 -1
  10. package/dist/history-v2.js +105 -2
  11. package/dist/history-v2.js.map +1 -1
  12. package/dist/host-limits.d.ts +9 -0
  13. package/dist/host-limits.js +58 -0
  14. package/dist/host-limits.js.map +1 -0
  15. package/dist/ilp-writer.d.ts +1 -1
  16. package/dist/ilp-writer.js +8 -2
  17. package/dist/ilp-writer.js.map +1 -1
  18. package/dist/index.js +99 -64
  19. package/dist/index.js.map +1 -1
  20. package/dist/path-matcher.d.ts +16 -0
  21. package/dist/path-matcher.js +109 -0
  22. package/dist/path-matcher.js.map +1 -0
  23. package/dist/query-client.d.ts +1 -1
  24. package/dist/query-client.js +25 -6
  25. package/dist/query-client.js.map +1 -1
  26. package/dist/test/container-env.test.d.ts +1 -0
  27. package/dist/test/container-env.test.js +75 -0
  28. package/dist/test/container-env.test.js.map +1 -0
  29. package/dist/test/delta-routing.test.js +6 -0
  30. package/dist/test/delta-routing.test.js.map +1 -1
  31. package/dist/test/history-v1.test.d.ts +1 -0
  32. package/dist/test/history-v1.test.js +310 -0
  33. package/dist/test/history-v1.test.js.map +1 -0
  34. package/dist/test/history-v2.test.js +282 -0
  35. package/dist/test/history-v2.test.js.map +1 -1
  36. package/dist/test/host-limits.test.d.ts +1 -0
  37. package/dist/test/host-limits.test.js +71 -0
  38. package/dist/test/host-limits.test.js.map +1 -0
  39. package/dist/test/ilp-writer.test.js +24 -0
  40. package/dist/test/ilp-writer.test.js.map +1 -1
  41. package/dist/test/path-matcher.test.d.ts +1 -0
  42. package/dist/test/path-matcher.test.js +170 -0
  43. package/dist/test/path-matcher.test.js.map +1 -0
  44. package/dist/test/query-client.test.js +88 -0
  45. package/dist/test/query-client.test.js.map +1 -1
  46. package/dist/test/wal-monitor.test.js +77 -0
  47. package/dist/test/wal-monitor.test.js.map +1 -1
  48. package/dist/wal-monitor.d.ts +1 -0
  49. package/dist/wal-monitor.js +40 -0
  50. package/dist/wal-monitor.js.map +1 -1
  51. package/package.json +2 -2
  52. package/public/540.js +1 -1
  53. package/public/805.js +1 -1
  54. package/public/main.js +1 -1
  55. package/public/remoteEntry.js +1 -1
package/README.md CHANGED
@@ -158,6 +158,31 @@ whether Signal K runs on bare metal or is itself containerized:
158
158
  In **external mode** (`Managed container` off) the plugin connects to the
159
159
  QuestDB you point it at via `QuestDB host` + the HTTP/ILP ports.
160
160
 
161
+ ## Durability on power loss
162
+
163
+ The managed container runs QuestDB with `cairo.commit.mode=sync`.
164
+
165
+ QuestDB's default is `nosync`: nothing on the ingest path is ever fsynced, and
166
+ durability is left to the OS page cache. On a power cut an arbitrary subset of
167
+ recent writes survives — including the case where a commit record reaches disk
168
+ while the row data it describes does not. QuestDB then fails while _opening_
169
+ that table's partition, which suspends the table permanently: neither a
170
+ lossless `RESUME WAL` nor a bounded `RESUME WAL FROM TXN` skip can get past it,
171
+ because the failure happens before any transaction is read. Repair means
172
+ hand-patching the commit record.
173
+
174
+ With `sync`, partition columns are fsynced before the commit record is written
175
+ and WAL segments are fsynced on commit, so the stored state can never claim
176
+ data that isn't durable. The cost is a few fsyncs per commit interval — writes
177
+ are already batched (see `ilpFlushIntervalMs`), so at boat data rates it is
178
+ negligible against losing a table.
179
+
180
+ **Running an external QuestDB?** Set this yourself in `server.conf`:
181
+
182
+ ```
183
+ cairo.commit.mode=sync
184
+ ```
185
+
161
186
  ## QuestDB Web Console
162
187
 
163
188
  QuestDB ships a web console (SQL editor + import UI) on its HTTP port. See the
@@ -265,6 +290,35 @@ podman events --since 2h --stream=false --filter container=sk-signalk-questdb \
265
290
  --filter event=oom --filter event=died
266
291
  ```
267
292
 
293
+ ### History queries slow or timing out / "out-of-memory" errors with free RAM
294
+
295
+ QuestDB memory-maps every partition column file and every pending WAL segment
296
+ it touches. The Linux kernel caps how many memory mappings one process may
297
+ hold (`vm.max_map_count`), and the stock value on Debian, Ubuntu ≤ 22.04, and
298
+ RHEL (65530) is far below what QuestDB recommends (1048576). A fresh database
299
+ fits easily; months of daily partitions across the three tables — plus a
300
+ segment backlog if a table's WAL is suspended — can exhaust the limit. When
301
+ that happens `mmap` fails with out-of-memory errors (errno 12) **even though
302
+ plenty of RAM is free**: queries error out or crawl, and the WAL apply job can
303
+ suspend a table.
304
+
305
+ The QuestDB Web Console shows the same warning
306
+ (`vm.max_map_count limit is too low`), the plugin's config panel shows a
307
+ banner, and the server log gets a warning at plugin startup. Fix it in a
308
+ shell **on the host machine itself** — not inside the QuestDB container via
309
+ `podman exec`: the limit is kernel-global, a container cannot change it, and
310
+ the QuestDB image has neither `sudo` nor `/etc/sysctl.d`. Being kernel-global
311
+ also means this works no matter how Signal K itself is deployed:
312
+
313
+ ```bash
314
+ echo 'vm.max_map_count=1048576' | sudo tee /etc/sysctl.d/99-questdb.conf
315
+ sudo sysctl --system
316
+ ```
317
+
318
+ This takes effect immediately — no container or host restart needed. See
319
+ [QuestDB capacity planning](https://questdb.com/docs/getting-started/capacity-planning/#max-virtual-memory-areas-limit)
320
+ for background.
321
+
268
322
  ## History API Provider
269
323
 
270
324
  QuestDB automatically registers as the **default** Signal K v2 History API provider. Any app or Grafana plugin that queries `/signalk/v2/api/history/` uses QuestDB.
@@ -0,0 +1,3 @@
1
+ import { Config } from "./config/schema";
2
+ export declare const QUESTDB_COMMIT_MODE = "sync";
3
+ export declare function buildContainerEnv(config: Partial<Config>): Record<string, string>;
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ // The QuestDB container's environment, in ONE place.
3
+ //
4
+ // There are two call sites that create the container — plugin start and
5
+ // /api/update/apply — and they used to build this literal independently. They
6
+ // had already drifted: the update path silently dropped the low-power worker
7
+ // tuning, so an in-place version update quietly moved a Pi onto QuestDB's
8
+ // multi-worker defaults. Anything a future option adds here now reaches both
9
+ // paths by construction.
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.QUESTDB_COMMIT_MODE = void 0;
12
+ exports.buildContainerEnv = buildContainerEnv;
13
+ // QuestDB's ingest path does not fsync anything under its default
14
+ // `cairo.commit.mode=nosync`: durability is left to the OS page cache, and a
15
+ // power cut can land the `_txn` commit record while the partition data it
16
+ // describes is still dirty. The table then claims more rows than exist on
17
+ // disk, and TableWriter asserts while OPENING the partition — a state no
18
+ // RESUME WAL variant can repair (both remedies run after the open), so it
19
+ // costs the whole table. `sync` makes TableWriter.commit00() fsync partition
20
+ // columns BEFORE writing the commit record, and makes WalWriter fsync each
21
+ // segment on commit, so the on-disk state can never claim data it doesn't
22
+ // have.
23
+ //
24
+ // Boats lose power; that is the deployment, not an edge case. The cost is a
25
+ // handful of fsyncs per commit interval (ILP batches at `ilpFlushIntervalMs`,
26
+ // 5s by default), which at boat data rates is noise against losing a table.
27
+ exports.QUESTDB_COMMIT_MODE = "sync";
28
+ function buildContainerEnv(config) {
29
+ return {
30
+ QDB_TELEMETRY_ENABLED: "false",
31
+ QDB_HTTP_ENABLED: "true",
32
+ QDB_LINE_TCP_ENABLED: "true",
33
+ QDB_CAIRO_COMMIT_MODE: exports.QUESTDB_COMMIT_MODE,
34
+ // Reduce CPU usage on low-power devices (Pi, Cerbo)
35
+ QDB_CAIRO_WAL_APPLY_WORKER_COUNT: "1",
36
+ QDB_SHARED_WORKER_COUNT: "1",
37
+ QDB_LINE_TCP_WRITER_WORKER_COUNT: "1",
38
+ QDB_CAIRO_O3_COLUMN_MEMORY_SIZE: "262144",
39
+ ...(config.compression && config.compression !== "none"
40
+ ? {
41
+ QDB_CAIRO_WAL_SEGMENT_COMPRESSION_CODEC: config.compression === "zstd" ? "ZSTD" : "LZ4",
42
+ ...(config.compression === "zstd" && config.compressionLevel
43
+ ? {
44
+ QDB_CAIRO_WAL_SEGMENT_COMPRESSION_LEVEL: String(config.compressionLevel),
45
+ }
46
+ : {}),
47
+ }
48
+ : {}),
49
+ };
50
+ }
51
+ //# sourceMappingURL=container-env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"container-env.js","sourceRoot":"","sources":["../src/container-env.ts"],"names":[],"mappings":";AAAA,qDAAqD;AACrD,EAAE;AACF,wEAAwE;AACxE,8EAA8E;AAC9E,6EAA6E;AAC7E,0EAA0E;AAC1E,6EAA6E;AAC7E,yBAAyB;;;AAoBzB,8CA2BC;AA3CD,kEAAkE;AAClE,6EAA6E;AAC7E,0EAA0E;AAC1E,0EAA0E;AAC1E,yEAAyE;AACzE,0EAA0E;AAC1E,6EAA6E;AAC7E,2EAA2E;AAC3E,0EAA0E;AAC1E,QAAQ;AACR,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,4EAA4E;AAC/D,QAAA,mBAAmB,GAAG,MAAM,CAAC;AAE1C,SAAgB,iBAAiB,CAC/B,MAAuB;IAEvB,OAAO;QACL,qBAAqB,EAAE,OAAO;QAC9B,gBAAgB,EAAE,MAAM;QACxB,oBAAoB,EAAE,MAAM;QAC5B,qBAAqB,EAAE,2BAAmB;QAC1C,oDAAoD;QACpD,gCAAgC,EAAE,GAAG;QACrC,uBAAuB,EAAE,GAAG;QAC5B,gCAAgC,EAAE,GAAG;QACrC,+BAA+B,EAAE,QAAQ;QACzC,GAAG,CAAC,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,WAAW,KAAK,MAAM;YACrD,CAAC,CAAC;gBACE,uCAAuC,EACrC,MAAM,CAAC,WAAW,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK;gBAChD,GAAG,CAAC,MAAM,CAAC,WAAW,KAAK,MAAM,IAAI,MAAM,CAAC,gBAAgB;oBAC1D,CAAC,CAAC;wBACE,uCAAuC,EAAE,MAAM,CAC7C,MAAM,CAAC,gBAAgB,CACxB;qBACF;oBACH,CAAC,CAAC,EAAE,CAAC;aACR;YACH,CAAC,CAAC,EAAE,CAAC;KACR,CAAC;AACJ,CAAC"}
@@ -1,2 +1,2 @@
1
- export type DeltaRoute = "number" | "string" | "position" | null;
1
+ export type DeltaRoute = "number" | "string" | "boolean" | "position" | null;
2
2
  export declare function routeDeltaValue(path: string, value: unknown): DeltaRoute;
@@ -6,6 +6,15 @@ function routeDeltaValue(path, value) {
6
6
  return "number";
7
7
  if (typeof value === "string")
8
8
  return "string";
9
+ // Booleans are everywhere in Signal K — switch and relay states, pump and
10
+ // valve states, autopilot flags — and used to fall through to null, so a
11
+ // whole class of history was dropped without a trace. They go to
12
+ // signalk_str as "true"/"false" rather than 0/1 in the numeric table: the
13
+ // string round-trips unambiguously (a 1.0 double cannot be told apart from
14
+ // a real numeric channel), and it needs no schema change, so dedup keys,
15
+ // retention and the history API all apply unchanged.
16
+ if (typeof value === "boolean")
17
+ return "boolean";
9
18
  if (path === "navigation.position" &&
10
19
  value !== null &&
11
20
  typeof value === "object" &&
@@ -1 +1 @@
1
- {"version":3,"file":"delta-routing.js","sourceRoot":"","sources":["../src/delta-routing.ts"],"names":[],"mappings":";;AAUA,0CAcC;AAdD,SAAgB,eAAe,CAAC,IAAY,EAAE,KAAc;IAC1D,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC/C,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC/C,IACE,IAAI,KAAK,qBAAqB;QAC9B,KAAK,KAAK,IAAI;QACd,OAAO,KAAK,KAAK,QAAQ;QACzB,UAAU,IAAI,KAAK;QACnB,WAAW,IAAI,KAAK;QACpB,MAAM,CAAC,QAAQ,CAAE,KAA+B,CAAC,QAAQ,CAAC;QAC1D,MAAM,CAAC,QAAQ,CAAE,KAAgC,CAAC,SAAS,CAAC;QAE5D,OAAO,UAAU,CAAC;IACpB,OAAO,IAAI,CAAC;AACd,CAAC"}
1
+ {"version":3,"file":"delta-routing.js","sourceRoot":"","sources":["../src/delta-routing.ts"],"names":[],"mappings":";;AAUA,0CAsBC;AAtBD,SAAgB,eAAe,CAAC,IAAY,EAAE,KAAc;IAC1D,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC/C,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC/C,0EAA0E;IAC1E,yEAAyE;IACzE,iEAAiE;IACjE,0EAA0E;IAC1E,2EAA2E;IAC3E,yEAAyE;IACzE,qDAAqD;IACrD,IAAI,OAAO,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACjD,IACE,IAAI,KAAK,qBAAqB;QAC9B,KAAK,KAAK,IAAI;QACd,OAAO,KAAK,KAAK,QAAQ;QACzB,UAAU,IAAI,KAAK;QACnB,WAAW,IAAI,KAAK;QACpB,MAAM,CAAC,QAAQ,CAAE,KAA+B,CAAC,QAAQ,CAAC;QAC1D,MAAM,CAAC,QAAQ,CAAE,KAAgC,CAAC,SAAS,CAAC;QAE5D,OAAO,UAAU,CAAC;IACpB,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -2,13 +2,88 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createHistoryProviderV1 = createHistoryProviderV1;
4
4
  const query_client_1 = require("./query-client");
5
+ // v1 replays raw deltas rather than aggregating, so all three value tables can
6
+ // be read in one pass and interleaved by timestamp. Every branch below emits
7
+ // the same unified shape — ts, path, context, valuetext, kind — which
8
+ // decodeValue turns back into the real delta value; the CASTs exist to keep
9
+ // the union's column types compatible.
10
+ //
11
+ // One builder per table, shared by BOTH query shapes (windowed streaming and
12
+ // the LATEST ON snapshot). `tail` carries what the caller appends inside the
13
+ // branch — the snapshot's LATEST ON clause. Keeping every branch here is the
14
+ // point: the snapshot query used to re-implement these by hand and drifted,
15
+ // silently replaying booleans as text on that path only.
16
+ function numBranch(where, tail = "") {
17
+ return (`SELECT ts, path, context, CAST(value AS STRING) valuetext, ` +
18
+ `'number' kind FROM signalk WHERE ${where}${tail}`);
19
+ }
20
+ // `withKind: false` degrades to the pre-migration shape. ensureTables() adds
21
+ // value_kind at startup, but a read racing an unmigrated table (or an
22
+ // external QuestDB the plugin does not own) would otherwise fail the WHOLE
23
+ // union with "Invalid column: value_kind" — turning a missing type tag into
24
+ // no history at all. The NULL is cast so the union's column type is stated
25
+ // rather than inferred.
26
+ function strBranch(where, withKind, tail = "") {
27
+ const kind = withKind ? `CAST(value_kind AS STRING)` : `CAST(NULL AS STRING)`;
28
+ return (`SELECT ts, path, context, value_str valuetext, ${kind} kind ` +
29
+ `FROM signalk_str WHERE ${where}${tail}`);
30
+ }
31
+ // The track table has no path column, so the path is supplied as a literal.
32
+ function posBranch(where, tail = "") {
33
+ return (`SELECT ts, 'navigation.position' path, context, ` +
34
+ `concat(CAST(lat AS STRING), ',', CAST(lon AS STRING)) valuetext, ` +
35
+ `'position' kind FROM signalk_position WHERE ${where}${tail}`);
36
+ }
37
+ function unionValueRowsSQL(where, orderAndLimit, withKind = true) {
38
+ return (`${numBranch(where)} UNION ALL ` +
39
+ `${strBranch(where, withKind)} UNION ALL ` +
40
+ `${posBranch(where)} ${orderAndLimit}`);
41
+ }
42
+ // True for the error QuestDB returns when value_kind has not been added yet.
43
+ function isMissingKindColumn(err) {
44
+ return /Invalid column:\s*value_kind/i.test(err instanceof Error ? err.message : String(err));
45
+ }
46
+ // Turn a unified row back into the value a Signal K delta carries. Numbers
47
+ // must not stay strings (consumers do arithmetic on them), positions must be
48
+ // objects again, and a value recorded as a boolean must replay as a boolean.
49
+ //
50
+ // Only rows explicitly tagged 'boolean' are converted: the text is parsed
51
+ // from the stored value, never guessed. A path whose value genuinely is the
52
+ // word "true" carries no tag and stays a string — as do all rows written
53
+ // before the value_kind column existed, whose original type is not
54
+ // recoverable.
55
+ function decodeValue(row) {
56
+ const text = row.valuetext;
57
+ if (text === null || text === undefined)
58
+ return null;
59
+ switch (row.kind) {
60
+ case "number": {
61
+ const n = Number(text);
62
+ return Number.isFinite(n) ? n : null;
63
+ }
64
+ case "boolean":
65
+ return String(text) === "true";
66
+ case "position": {
67
+ const [lat, lon] = String(text).split(",");
68
+ const latitude = Number(lat);
69
+ const longitude = Number(lon);
70
+ return Number.isFinite(latitude) && Number.isFinite(longitude)
71
+ ? { latitude, longitude }
72
+ : null;
73
+ }
74
+ default:
75
+ return text;
76
+ }
77
+ }
5
78
  function groupRowsIntoDeltas(rows) {
6
79
  const byTimestamp = new Map();
7
80
  for (const row of rows) {
8
81
  const ts = row.ts;
9
82
  const context = row.context || "self";
10
83
  const path = row.path;
11
- const value = row.value;
84
+ // Both call sites query the unified shape, so every row carries
85
+ // `valuetext` + `kind` for decodeValue to reconstruct.
86
+ const value = decodeValue(row);
12
87
  if (!byTimestamp.has(ts)) {
13
88
  byTimestamp.set(ts, new Map());
14
89
  }
@@ -32,8 +107,17 @@ function groupRowsIntoDeltas(rows) {
32
107
  function createHistoryProviderV1(queryClient, selfContext, debug) {
33
108
  function hasAnyData(options, callback) {
34
109
  const startTime = (0, query_client_1.validateTimestamp)(options.startTime.toISOString());
110
+ // "Any data" must consider every value table: a vessel recording only
111
+ // string/boolean channels (or only a position track) has history to play
112
+ // back, and answering false here disables playback entirely.
35
113
  queryClient
36
- .exec(`SELECT count() as cnt FROM signalk WHERE ts >= '${startTime}' LIMIT 1`)
114
+ .exec(
115
+ // Summed via a UNION ALL subquery: QuestDB rejects adding scalar
116
+ // subqueries with `+` ("no matching operator").
117
+ `SELECT sum(c) as cnt FROM (` +
118
+ `SELECT count() c FROM signalk WHERE ts >= '${startTime}'` +
119
+ ` UNION ALL SELECT count() c FROM signalk_str WHERE ts >= '${startTime}'` +
120
+ ` UNION ALL SELECT count() c FROM signalk_position WHERE ts >= '${startTime}')`)
37
121
  .then((result) => {
38
122
  const count = result.dataset.length > 0 ? result.dataset[0][0] : 0;
39
123
  callback(count > 0);
@@ -49,6 +133,9 @@ function createHistoryProviderV1(queryClient, selfContext, debug) {
49
133
  const startTime = (0, query_client_1.validateTimestamp)(options.startTime.toISOString());
50
134
  const playbackRate = Math.max(1, options.playbackRate);
51
135
  const CHUNK_SECONDS = 60;
136
+ // Rows per read. A window holding more than this is drained across
137
+ // several reads rather than truncated (see the resume logic below).
138
+ const CHUNK_ROW_LIMIT = 10000;
52
139
  let currentTime = new Date(startTime);
53
140
  async function streamChunk() {
54
141
  if (stopped)
@@ -57,7 +144,15 @@ function createHistoryProviderV1(queryClient, selfContext, debug) {
57
144
  const chunkEnd = new Date(currentTime.getTime() + CHUNK_SECONDS * 1000);
58
145
  const to = (0, query_client_1.validateTimestamp)(chunkEnd.toISOString());
59
146
  try {
60
- const result = await queryClient.exec(`SELECT ts, path, context, value FROM signalk WHERE ts >= '${from}' AND ts < '${to}' ORDER BY ts LIMIT 10000`);
147
+ const window = `ts >= '${from}' AND ts < '${to}'`;
148
+ const order = `ORDER BY ts LIMIT ${CHUNK_ROW_LIMIT}`;
149
+ const result = await queryClient
150
+ .exec(unionValueRowsSQL(window, order))
151
+ .catch((err) => {
152
+ if (!isMissingKindColumn(err))
153
+ throw err;
154
+ return queryClient.exec(unionValueRowsSQL(window, order, false));
155
+ });
61
156
  if (result.dataset.length === 0) {
62
157
  currentTime = chunkEnd;
63
158
  if (!stopped) {
@@ -76,6 +171,37 @@ function createHistoryProviderV1(queryClient, selfContext, debug) {
76
171
  context: resolvedContext,
77
172
  });
78
173
  }
174
+ // A busy interval can hold more rows than one read returns — querying
175
+ // three tables instead of one makes that far likelier (a live install
176
+ // already reaches ~6k rows per 60s window). Advancing to chunkEnd
177
+ // after a truncated read would skip the remainder silently, so drain
178
+ // the window before moving on.
179
+ //
180
+ // Resume AT the last sent row's timestamp, not past it: QuestDB
181
+ // stamps at microsecond precision but JS Date truncates to
182
+ // milliseconds, and a single instrument update commonly stamps
183
+ // several paths within the same millisecond. Stepping past it would
184
+ // drop the siblings that did not fit in this page. Re-reading that
185
+ // millisecond can re-send rows already delivered, which is harmless
186
+ // on replay — losing them is not.
187
+ //
188
+ // Only when the whole page shared currentTime's millisecond (so
189
+ // resuming at it would repeat the identical read forever) does the
190
+ // cursor step forward by 1ms, trading that millisecond's tail for
191
+ // guaranteed progress.
192
+ // Guard on `rows`, not `dataset`: toObjects() returns [] when the
193
+ // response carries no column metadata, and indexing the last row of
194
+ // an empty array would throw into the catch below — turning a
195
+ // metadata hiccup into a permanent 1s retry loop on this window.
196
+ if (rows.length >= CHUNK_ROW_LIMIT) {
197
+ const lastTs = new Date(rows[rows.length - 1].ts).getTime();
198
+ const resumeAt = lastTs > currentTime.getTime() ? lastTs : currentTime.getTime() + 1;
199
+ currentTime = new Date(Math.min(resumeAt, chunkEnd.getTime()));
200
+ if (!stopped) {
201
+ setTimeout(streamChunk, 0);
202
+ }
203
+ return;
204
+ }
79
205
  currentTime = chunkEnd;
80
206
  const wallDelay = (CHUNK_SECONDS * 1000) / playbackRate;
81
207
  if (!stopped) {
@@ -97,10 +223,38 @@ function createHistoryProviderV1(queryClient, selfContext, debug) {
97
223
  stopped = true;
98
224
  };
99
225
  }
226
+ // Snapshot of every path at `date`, for the v1 snapshot API.
227
+ //
228
+ // `path` is deliberately unused and must NOT become a filter. Despite the
229
+ // name (and the `string` in the server's provider interface), the server
230
+ // passes the REQUEST URL SEGMENTS — e.g. ["vessels", "<selfId>",
231
+ // "navigation"], or [] for the root snapshot — then feeds every returned
232
+ // delta to buildFullFromDeltas() and walks into the assembled tree with
233
+ // those segments (signalk-server src/interfaces/rest.js). Filtering the
234
+ // query by it would both mismatch the type and starve the snapshot the
235
+ // caller is building.
100
236
  function getHistory(date, path, callback) {
101
237
  const ts = (0, query_client_1.validateTimestamp)(date.toISOString());
238
+ // LATEST ON is applied PER TABLE and the results unioned, not the other
239
+ // way round: running it over a materialized union makes QuestDB scan
240
+ // instead of using each table's index, which timed out (>30s) on a
241
+ // multi-hundred-million-row install. Position partitions by context only
242
+ // — the track table has no path column.
243
+ const at = `ts <= '${ts}'`;
244
+ const byPath = ` LATEST ON ts PARTITION BY path, context`;
245
+ const byContext = ` LATEST ON ts PARTITION BY context`;
246
+ const snapshotSQL = (withKind) => `(${numBranch(at, byPath)})` +
247
+ ` UNION ALL ` +
248
+ `(${strBranch(at, withKind, byPath)})` +
249
+ ` UNION ALL ` +
250
+ `(${posBranch(at, byContext)})`;
102
251
  queryClient
103
- .exec(`SELECT path, value, ts, context FROM signalk WHERE ts <= '${ts}' LATEST ON ts PARTITION BY path`)
252
+ .exec(snapshotSQL(true))
253
+ .catch((err) => {
254
+ if (!isMissingKindColumn(err))
255
+ throw err;
256
+ return queryClient.exec(snapshotSQL(false));
257
+ })
104
258
  .then((result) => {
105
259
  const rows = queryClient.toObjects(result);
106
260
  const deltas = groupRowsIntoDeltas(rows);
@@ -1 +1 @@
1
- {"version":3,"file":"history-v1.js","sourceRoot":"","sources":["../src/history-v1.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"history-v1.js","sourceRoot":"","sources":["../src/history-v1.ts"],"names":[],"mappings":";;AAiJA,0DA0MC;AA3VD,iDAAgE;AAgBhE,+EAA+E;AAC/E,6EAA6E;AAC7E,sEAAsE;AACtE,4EAA4E;AAC5E,uCAAuC;AACvC,EAAE;AACF,6EAA6E;AAC7E,6EAA6E;AAC7E,6EAA6E;AAC7E,4EAA4E;AAC5E,yDAAyD;AACzD,SAAS,SAAS,CAAC,KAAa,EAAE,IAAI,GAAG,EAAE;IACzC,OAAO,CACL,6DAA6D;QAC7D,oCAAoC,KAAK,GAAG,IAAI,EAAE,CACnD,CAAC;AACJ,CAAC;AAED,6EAA6E;AAC7E,sEAAsE;AACtE,2EAA2E;AAC3E,4EAA4E;AAC5E,2EAA2E;AAC3E,wBAAwB;AACxB,SAAS,SAAS,CAAC,KAAa,EAAE,QAAiB,EAAE,IAAI,GAAG,EAAE;IAC5D,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,4BAA4B,CAAC,CAAC,CAAC,sBAAsB,CAAC;IAC9E,OAAO,CACL,kDAAkD,IAAI,QAAQ;QAC9D,0BAA0B,KAAK,GAAG,IAAI,EAAE,CACzC,CAAC;AACJ,CAAC;AAED,4EAA4E;AAC5E,SAAS,SAAS,CAAC,KAAa,EAAE,IAAI,GAAG,EAAE;IACzC,OAAO,CACL,kDAAkD;QAClD,mEAAmE;QACnE,+CAA+C,KAAK,GAAG,IAAI,EAAE,CAC9D,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CACxB,KAAa,EACb,aAAqB,EACrB,QAAQ,GAAG,IAAI;IAEf,OAAO,CACL,GAAG,SAAS,CAAC,KAAK,CAAC,aAAa;QAChC,GAAG,SAAS,CAAC,KAAK,EAAE,QAAQ,CAAC,aAAa;QAC1C,GAAG,SAAS,CAAC,KAAK,CAAC,IAAI,aAAa,EAAE,CACvC,CAAC;AACJ,CAAC;AAED,6EAA6E;AAC7E,SAAS,mBAAmB,CAAC,GAAY;IACvC,OAAO,+BAA+B,CAAC,IAAI,CACzC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CACjD,CAAC;AACJ,CAAC;AAED,2EAA2E;AAC3E,6EAA6E;AAC7E,6EAA6E;AAC7E,EAAE;AACF,0EAA0E;AAC1E,4EAA4E;AAC5E,yEAAyE;AACzE,mEAAmE;AACnE,eAAe;AACf,SAAS,WAAW,CAAC,GAA4B;IAC/C,MAAM,IAAI,GAAG,GAAG,CAAC,SAAS,CAAC;IAC3B,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACrD,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;QACjB,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;YACvB,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACvC,CAAC;QACD,KAAK,SAAS;YACZ,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,MAAM,CAAC;QACjC,KAAK,UAAU,CAAC,CAAC,CAAC;YAChB,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC3C,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;YAC7B,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;YAC9B,OAAO,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC;gBAC5D,CAAC,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE;gBACzB,CAAC,CAAC,IAAI,CAAC;QACX,CAAC;QACD;YACE,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC;AAED,SAAS,mBAAmB,CAAC,IAA+B;IAC1D,MAAM,WAAW,GAAG,IAAI,GAAG,EAGxB,CAAC;IAEJ,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,EAAE,GAAG,GAAG,CAAC,EAAY,CAAC;QAC5B,MAAM,OAAO,GAAI,GAAG,CAAC,OAAkB,IAAI,MAAM,CAAC;QAClD,MAAM,IAAI,GAAG,GAAG,CAAC,IAAc,CAAC;QAChC,gEAAgE;QAChE,uDAAuD;QACvD,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;QAE/B,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YACzB,WAAW,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;QACjC,CAAC;QACD,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,CAAC,EAAE,CAAE,CAAC;QACvC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5B,SAAS,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC7B,CAAC;QACD,SAAS,CAAC,GAAG,CAAC,OAAO,CAAE,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAChD,CAAC;IAED,MAAM,MAAM,GAAY,EAAE,CAAC;IAC3B,KAAK,MAAM,CAAC,EAAE,EAAE,SAAS,CAAC,IAAI,WAAW,EAAE,CAAC;QAC1C,KAAK,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;YAC1C,MAAM,CAAC,IAAI,CAAC;gBACV,OAAO;gBACP,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC;aACrC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAgB,uBAAuB,CACrC,WAAwB,EACxB,WAAmB,EACnB,KAA4B;IAE5B,SAAS,UAAU,CACjB,OAAuB,EACvB,QAAuC;QAEvC,MAAM,SAAS,GAAG,IAAA,gCAAiB,EAAC,OAAO,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,CAAC;QACrE,sEAAsE;QACtE,yEAAyE;QACzE,6DAA6D;QAC7D,WAAW;aACR,IAAI;QACH,iEAAiE;QACjE,gDAAgD;QAChD,6BAA6B;YAC3B,8CAA8C,SAAS,GAAG;YAC1D,6DAA6D,SAAS,GAAG;YACzE,kEAAkE,SAAS,IAAI,CAClF;aACA,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;YACf,MAAM,KAAK,GACT,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAY,CAAC,CAAC,CAAC,CAAC,CAAC;YACnE,QAAQ,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QACtB,CAAC,CAAC;aACD,KAAK,CAAC,GAAG,EAAE;YACV,QAAQ,CAAC,KAAK,CAAC,CAAC;QAClB,CAAC,CAAC,CAAC;IACP,CAAC;IAED,SAAS,aAAa,CACpB,KAGC,EACD,OAAuB;IACvB,6DAA6D;IAC7D,QAAoB;QAEpB,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,MAAM,SAAS,GAAG,IAAA,gCAAiB,EAAC,OAAO,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,CAAC;QACrE,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;QAEvD,MAAM,aAAa,GAAG,EAAE,CAAC;QACzB,mEAAmE;QACnE,oEAAoE;QACpE,MAAM,eAAe,GAAG,KAAK,CAAC;QAC9B,IAAI,WAAW,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC;QAEtC,KAAK,UAAU,WAAW;YACxB,IAAI,OAAO;gBAAE,OAAO;YAEpB,MAAM,IAAI,GAAG,IAAA,gCAAiB,EAAC,WAAW,CAAC,WAAW,EAAE,CAAC,CAAC;YAC1D,MAAM,QAAQ,GAAG,IAAI,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,GAAG,aAAa,GAAG,IAAI,CAAC,CAAC;YACxE,MAAM,EAAE,GAAG,IAAA,gCAAiB,EAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;YAErD,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,UAAU,IAAI,eAAe,EAAE,GAAG,CAAC;gBAClD,MAAM,KAAK,GAAG,qBAAqB,eAAe,EAAE,CAAC;gBACrD,MAAM,MAAM,GAAG,MAAM,WAAW;qBAC7B,IAAI,CAAC,iBAAiB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;qBACtC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;oBACb,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC;wBAAE,MAAM,GAAG,CAAC;oBACzC,OAAO,WAAW,CAAC,IAAI,CAAC,iBAAiB,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;gBACnE,CAAC,CAAC,CAAC;gBAEL,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBAChC,WAAW,GAAG,QAAQ,CAAC;oBACvB,IAAI,CAAC,OAAO,EAAE,CAAC;wBACb,UAAU,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;oBAC/B,CAAC;oBACD,OAAO;gBACT,CAAC;gBAED,MAAM,IAAI,GAAG,WAAW,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;gBAC3C,MAAM,MAAM,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;gBAEzC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;oBAC3B,IAAI,OAAO;wBAAE,OAAO;oBAEpB,MAAM,eAAe,GACnB,KAAK,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC;oBACzD,KAAK,CAAC,KAAK,CAAC;wBACV,GAAG,KAAK;wBACR,OAAO,EAAE,eAAe;qBACzB,CAAC,CAAC;gBACL,CAAC;gBAED,sEAAsE;gBACtE,sEAAsE;gBACtE,kEAAkE;gBAClE,qEAAqE;gBACrE,+BAA+B;gBAC/B,EAAE;gBACF,gEAAgE;gBAChE,2DAA2D;gBAC3D,+DAA+D;gBAC/D,oEAAoE;gBACpE,mEAAmE;gBACnE,oEAAoE;gBACpE,kCAAkC;gBAClC,EAAE;gBACF,gEAAgE;gBAChE,mEAAmE;gBACnE,kEAAkE;gBAClE,uBAAuB;gBACvB,kEAAkE;gBAClE,oEAAoE;gBACpE,8DAA8D;gBAC9D,iEAAiE;gBACjE,IAAI,IAAI,CAAC,MAAM,IAAI,eAAe,EAAE,CAAC;oBACnC,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAY,CAAC,CAAC,OAAO,EAAE,CAAC;oBACtE,MAAM,QAAQ,GACZ,MAAM,GAAG,WAAW,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;oBACtE,WAAW,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;oBAC/D,IAAI,CAAC,OAAO,EAAE,CAAC;wBACb,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;oBAC7B,CAAC;oBACD,OAAO;gBACT,CAAC;gBAED,WAAW,GAAG,QAAQ,CAAC;gBACvB,MAAM,SAAS,GAAG,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG,YAAY,CAAC;gBACxD,IAAI,CAAC,OAAO,EAAE,CAAC;oBACb,UAAU,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;gBACrC,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,KAAK,CACH,wBAAwB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAC3E,CAAC;gBACF,IAAI,CAAC,OAAO,EAAE,CAAC;oBACb,UAAU,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;gBAChC,CAAC;YACH,CAAC;QACH,CAAC;QAED,WAAW,EAAE,CAAC;QAEd,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YACnB,OAAO,GAAG,IAAI,CAAC;QACjB,CAAC,CAAC,CAAC;QAEH,OAAO,GAAG,EAAE;YACV,OAAO,GAAG,IAAI,CAAC;QACjB,CAAC,CAAC;IACJ,CAAC;IAED,6DAA6D;IAC7D,EAAE;IACF,0EAA0E;IAC1E,yEAAyE;IACzE,iEAAiE;IACjE,yEAAyE;IACzE,wEAAwE;IACxE,wEAAwE;IACxE,uEAAuE;IACvE,sBAAsB;IACtB,SAAS,UAAU,CACjB,IAAU,EAEV,IAAY,EACZ,QAAmC;QAEnC,MAAM,EAAE,GAAG,IAAA,gCAAiB,EAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QAEjD,wEAAwE;QACxE,qEAAqE;QACrE,mEAAmE;QACnE,yEAAyE;QACzE,wCAAwC;QACxC,MAAM,EAAE,GAAG,UAAU,EAAE,GAAG,CAAC;QAC3B,MAAM,MAAM,GAAG,0CAA0C,CAAC;QAC1D,MAAM,SAAS,GAAG,oCAAoC,CAAC;QACvD,MAAM,WAAW,GAAG,CAAC,QAAiB,EAAE,EAAE,CACxC,IAAI,SAAS,CAAC,EAAE,EAAE,MAAM,CAAC,GAAG;YAC5B,aAAa;YACb,IAAI,SAAS,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG;YACtC,aAAa;YACb,IAAI,SAAS,CAAC,EAAE,EAAE,SAAS,CAAC,GAAG,CAAC;QAElC,WAAW;aACR,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;aACvB,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YACb,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC;gBAAE,MAAM,GAAG,CAAC;YACzC,OAAO,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC;QAC9C,CAAC,CAAC;aACD,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;YACf,MAAM,IAAI,GAAG,WAAW,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YAC3C,MAAM,MAAM,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;YACzC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACnB,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YACb,KAAK,CACH,qBAAqB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CACxE,CAAC;YACF,QAAQ,CAAC,EAAE,CAAC,CAAC;QACf,CAAC,CAAC,CAAC;IACP,CAAC;IAED,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,CAAC;AACnD,CAAC"}
@@ -82,9 +82,80 @@ function normalizeContext(context, selfContext) {
82
82
  }
83
83
  return context;
84
84
  }
85
+ // Upper bound on SAMPLE BY buckets a single request may generate. The
86
+ // SAMPLE BY queries use FILL(NULL), which fabricates a row for EVERY bucket
87
+ // in the range whether data exists or not — a caller asking for weeks at 1s
88
+ // resolution would stream millions of rows through QuestDB, Node's JSON
89
+ // parser, and the HTTP response, wedging Pi-class servers for minutes. The
90
+ // well-behaved clients budget ~2000 points per request; a million covers any
91
+ // sane chart while keeping the worst case bounded.
92
+ const MAX_SAMPLE_BUCKETS = 1_000_000;
93
+ // Effective SAMPLE BY period: QuestDB rejects `SAMPLE BY 0s`, so fractional
94
+ // resolutions (e.g. 0.5) must clamp up to 1s instead of flooring to zero.
95
+ function effectiveResolution(resolution) {
96
+ return Math.max(1, Math.floor(resolution));
97
+ }
85
98
  function createHistoryProviderV2(queryClient, selfContext) {
99
+ // Read a path's rows from signalk_str. Numeric aggregates do not apply to
100
+ // text, so a downsampled request takes one representative value per bucket
101
+ // (last = the state in force at the bucket's end, which is what a state
102
+ // channel means) instead of averaging. Values are returned verbatim:
103
+ // booleans were stored as "true"/"false", so a consumer can tell them apart
104
+ // from real numbers, and Grafana value mappings work directly.
105
+ async function readStringRows(where, resolution) {
106
+ // `value_kind` marks rows that were recorded as booleans, so v2 replays
107
+ // them as real booleans exactly like v1 — otherwise the same path would
108
+ // read `true` through one API and `"true"` through the other. Untagged
109
+ // rows (plain text, and everything written before the column existed)
110
+ // stay strings; the text is never guessed at.
111
+ const sql = (withKind) => {
112
+ const kind = withKind ? "value_kind" : "NULL";
113
+ return resolution && resolution > 0
114
+ ? `SELECT ts, last(value_str) as value_str, last(${kind}) as value_kind FROM signalk_str WHERE ${where} SAMPLE BY ${effectiveResolution(resolution)}s FILL(NULL) ORDER BY ts`
115
+ : `SELECT ts, value_str, ${kind} as value_kind FROM signalk_str WHERE ${where} ORDER BY ts LIMIT 10000`;
116
+ };
117
+ // A read racing ensureTables()'s migration — or an external QuestDB the
118
+ // plugin does not own — must degrade to text, not fail the request.
119
+ const result = await queryClient.exec(sql(true)).catch((err) => {
120
+ if (!/Invalid column:\s*value_kind/i.test(String(err)))
121
+ throw err;
122
+ return queryClient.exec(sql(false));
123
+ });
124
+ return result.dataset.map((row) => [
125
+ row[0],
126
+ row[2] === "boolean" ? row[1] === "true" : row[1],
127
+ ]);
128
+ }
86
129
  async function getValues(query) {
87
130
  const range = (0, time_range_1.resolveTimeRange)(query);
131
+ // Only specs that actually run a SAMPLE BY query fabricate buckets:
132
+ // client-side aggregates (sma/ema/middle_index) read raw rows under a
133
+ // LIMIT and must not trip the cap. Each qualifying spec issues its own
134
+ // SAMPLE BY, so the fabricated total scales with their count.
135
+ //
136
+ // A non-numeric path costs TWO such queries: the numeric one comes back
137
+ // empty and the string-table fallback repeats it against signalk_str.
138
+ // Which paths those are is only known after querying, so the budget
139
+ // assumes the worst case — every sampled spec falling back — rather than
140
+ // letting a request built entirely of boolean/string paths quietly run at
141
+ // twice the ceiling this cap exists to enforce on Pi-class hosts.
142
+ const sampledSpecs = query.pathSpecs.filter((spec) => spec.path === "navigation.position" ||
143
+ !needsClientSideAggregation(spec.aggregate)).length;
144
+ // navigation.position is served by its own table and never falls back.
145
+ const fallbackCapableSpecs = query.pathSpecs.filter((spec) => spec.path !== "navigation.position" &&
146
+ !needsClientSideAggregation(spec.aggregate)).length;
147
+ if (sampledSpecs > 0 && query.resolution && query.resolution > 0) {
148
+ const rangeSec = (Date.parse(range.to) - Date.parse(range.from)) / 1000;
149
+ const bucketsPerSeries = Math.ceil(rangeSec / effectiveResolution(query.resolution));
150
+ const worstCaseQueries = sampledSpecs + fallbackCapableSpecs;
151
+ const buckets = bucketsPerSeries * worstCaseQueries;
152
+ if (buckets > MAX_SAMPLE_BUCKETS) {
153
+ throw new Error(`resolution ${query.resolution}s over this range produces up to ` +
154
+ `${buckets} sample buckets across ${sampledSpecs} paths ` +
155
+ `(max ${MAX_SAMPLE_BUCKETS}) — use a coarser resolution or ` +
156
+ `a shorter range`);
157
+ }
158
+ }
88
159
  const requestedContext = query.context ?? "vessels.self";
89
160
  const storedContext = normalizeContext(requestedContext, selfContext);
90
161
  const safeContext = (0, query_client_1.validateIdentifier)(storedContext);
@@ -104,7 +175,7 @@ function createHistoryProviderV2(queryClient, selfContext) {
104
175
  const posAgg = spec.aggregate === "last" ? "last" : "first";
105
176
  let sql;
106
177
  if (query.resolution && query.resolution > 0) {
107
- sql = `SELECT ts, ${posAgg}(lat) as lat, ${posAgg}(lon) as lon FROM ${table} WHERE ${where} SAMPLE BY ${Math.floor(query.resolution)}s FILL(NULL) ORDER BY ts`;
178
+ sql = `SELECT ts, ${posAgg}(lat) as lat, ${posAgg}(lon) as lon FROM ${table} WHERE ${where} SAMPLE BY ${effectiveResolution(query.resolution)}s FILL(NULL) ORDER BY ts`;
108
179
  }
109
180
  else {
110
181
  sql = `SELECT ts, lat, lon FROM ${table} WHERE ${where} ORDER BY ts LIMIT 10000`;
@@ -148,7 +219,7 @@ function createHistoryProviderV2(queryClient, selfContext) {
148
219
  const aggExpr = aggregateToSql(spec.aggregate);
149
220
  let sql;
150
221
  if (query.resolution && query.resolution > 0) {
151
- sql = `SELECT ts, ${aggExpr} as agg_value FROM ${table} WHERE ${where} SAMPLE BY ${Math.floor(query.resolution)}s FILL(NULL) ORDER BY ts`;
222
+ sql = `SELECT ts, ${aggExpr} as agg_value FROM ${table} WHERE ${where} SAMPLE BY ${effectiveResolution(query.resolution)}s FILL(NULL) ORDER BY ts`;
152
223
  }
153
224
  else {
154
225
  sql = `SELECT ts, value FROM ${table} WHERE ${where} ORDER BY ts LIMIT 10000`;
@@ -158,6 +229,26 @@ function createHistoryProviderV2(queryClient, selfContext) {
158
229
  row[0],
159
230
  row[1],
160
231
  ]);
232
+ // Non-numeric paths (strings, and booleans stored as "true"/"false")
233
+ // live in signalk_str, which this query never touches — they used to
234
+ // come back empty even though getPaths lists them. Fall back to the
235
+ // string table when the numeric one held nothing for this path.
236
+ // Emptiness is judged on VALUES, not row count: a SAMPLE BY with
237
+ // FILL(NULL) fabricates a row per bucket, so an all-null result is
238
+ // still "no numeric data here".
239
+ if (!rows.some(([, value]) => value !== null)) {
240
+ // Report the aggregate that was actually applied. Downsampled string
241
+ // rows always use last() — averaging text is meaningless — so leaving
242
+ // the caller's requested method in the response would label the
243
+ // series with an aggregation that never ran.
244
+ if (query.resolution && query.resolution > 0) {
245
+ const reported = valuesList[valuesList.length - 1];
246
+ if (reported.path === spec.path)
247
+ reported.method = "last";
248
+ }
249
+ columnData.set(spec.path, await readStringRows(where, query.resolution));
250
+ continue;
251
+ }
161
252
  columnData.set(spec.path, rows);
162
253
  }
163
254
  const allTimestamps = new Set();
@@ -194,18 +285,30 @@ function createHistoryProviderV2(queryClient, selfContext) {
194
285
  async function getPaths(query) {
195
286
  const range = (0, time_range_1.resolveTimeRange)(query);
196
287
  const where = buildRangeWhere(range);
288
+ // signalk_position has no `path` column — the whole table IS
289
+ // navigation.position — so it contributes that name as a literal. Without
290
+ // this branch getValues happily serves the track while getPaths never
291
+ // advertised it, so a client enumerating paths could not discover the one
292
+ // series it most likely wants.
197
293
  const result = await queryClient.exec(`SELECT DISTINCT path FROM signalk WHERE ${where}
198
294
  UNION
199
295
  SELECT DISTINCT path FROM signalk_str WHERE ${where}
296
+ UNION
297
+ SELECT DISTINCT 'navigation.position' path FROM signalk_position WHERE ${where}
200
298
  ORDER BY path`);
201
299
  return result.dataset.map((row) => row[0]);
202
300
  }
203
301
  async function getContexts(query) {
204
302
  const range = (0, time_range_1.resolveTimeRange)(query);
205
303
  const where = buildRangeWhere(range);
304
+ // Include the track table: a vessel can be position-only (an AIS target
305
+ // whose other paths are filtered out, or a receiver sending nothing but
306
+ // fixes), and omitting it hides that context entirely.
206
307
  const result = await queryClient.exec(`SELECT DISTINCT context FROM signalk WHERE ${where}
207
308
  UNION
208
309
  SELECT DISTINCT context FROM signalk_str WHERE ${where}
310
+ UNION
311
+ SELECT DISTINCT context FROM signalk_position WHERE ${where}
209
312
  ORDER BY context`);
210
313
  // Translate stored "self" back to the spec-canonical "vessels.self"
211
314
  return result.dataset.map((row) => {
@@ -1 +1 @@
1
- {"version":3,"file":"history-v2.js","sourceRoot":"","sources":["../src/history-v2.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"history-v2.js","sourceRoot":"","sources":["../src/history-v2.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export declare const RECOMMENDED_MAX_MAP_COUNT = 1048576;
2
+ export interface MaxMapCountStatus {
3
+ current: number;
4
+ recommended: number;
5
+ tooLow: boolean;
6
+ }
7
+ export declare function parseMaxMapCount(content: string): number | null;
8
+ export declare function evaluateMaxMapCount(current: number): MaxMapCountStatus;
9
+ export declare function readMaxMapCount(path?: string): Promise<MaxMapCountStatus | null>;