@meri-imperiumi/signalk-passage-briefing 0.8.0 → 0.8.1
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/CHANGELOG.md +8 -0
- package/package.json +1 -1
- package/plugin/index.js +0 -9
- package/plugin/logbook-source.js +12 -28
- package/public/index.html +2 -0
- package/tests/logbook-source.test.js +15 -6
- package/tests/plugin.test.js +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.8.1] - 2026-10-08
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- Branding on the webapp page (per the Signal K visuals spec): the plugin's app icon (`icon-256.png`) serves as favicon and the base canvas color ships as the `theme-color` meta, so browser chrome matches the console background in both day and night modes.
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- The per-minute source-status tick no longer touches the logbook — fixes "Server unreachable: Fetch is aborted" with an empty route picker on production since 0.8.0. The checklist's logbook probe went through the resources API, whose `logentries` provider answers even a `limit: 1` listing by reading and schema-validating every day file — on a multi-year log that meant overlapping full-store scans every 60 s starving the server so `/api/status` and `/api/routes` blew the webapp's 8 s abort timeout. The logbook is a once-used learning resource (backfill), not an ongoing ingest source, so it leaves the data source statuses entirely; with no provider installed, backfill now fails loudly with the reason instead of silently reporting zero events.
|
|
12
|
+
|
|
5
13
|
## [0.8.0] - 2026-10-06
|
|
6
14
|
|
|
7
15
|
### Added
|
package/package.json
CHANGED
package/plugin/index.js
CHANGED
|
@@ -25,7 +25,6 @@ const { mkdir, readFile, unlink, writeFile } = require("node:fs/promises");
|
|
|
25
25
|
const { PassageStateMachine } = require("./state-machine.js");
|
|
26
26
|
const { PassageDatabase } = require("./sqlite-db.js");
|
|
27
27
|
const {
|
|
28
|
-
logbookAvailable,
|
|
29
28
|
readLogbookEntries,
|
|
30
29
|
readLogbookSailEvents,
|
|
31
30
|
} = require("./logbook-source.js");
|
|
@@ -1997,14 +1996,6 @@ module.exports = (app) => {
|
|
|
1997
1996
|
now,
|
|
1998
1997
|
});
|
|
1999
1998
|
}
|
|
2000
|
-
sourceStatus.record({
|
|
2001
|
-
id: "sk-logbook",
|
|
2002
|
-
label: "Logbook (signalk-logbook)",
|
|
2003
|
-
kind: "signalk",
|
|
2004
|
-
url: "resources/logentries",
|
|
2005
|
-
...((await logbookAvailable(app)) ? {} : { absent: true }),
|
|
2006
|
-
now,
|
|
2007
|
-
});
|
|
2008
1999
|
}
|
|
2009
2000
|
|
|
2010
2001
|
/**
|
package/plugin/logbook-source.js
CHANGED
|
@@ -465,17 +465,20 @@ function normalizeLogEntry(entry) {
|
|
|
465
465
|
* explicit window, so "all history" is an explicit epoch-to-eternity
|
|
466
466
|
* range.
|
|
467
467
|
*
|
|
468
|
-
*
|
|
469
|
-
* logbook plugin not installed — no provider
|
|
470
|
-
*
|
|
471
|
-
*
|
|
468
|
+
* Loud on an unusable source: a missing resources API (old server)
|
|
469
|
+
* or a failed listing (the logbook plugin not installed — no provider
|
|
470
|
+
* for the type) throws with the reason, so the human-initiated runs
|
|
471
|
+
* that read the logbook (backfill, event diagnostics) can say why
|
|
472
|
+
* they found nothing instead of silently reporting zero events.
|
|
472
473
|
*
|
|
473
474
|
* @param {object} app - Signal K plugin `app`
|
|
474
475
|
* @returns {Promise<Array<object>>} Normalized entries, oldest first
|
|
476
|
+
* @throws {Error} When the resources API or the `logentries` provider
|
|
477
|
+
* is unavailable
|
|
475
478
|
*/
|
|
476
479
|
async function readLogbookEntries(app) {
|
|
477
480
|
if (typeof app?.resourcesApi?.listResources !== "function") {
|
|
478
|
-
|
|
481
|
+
throw new Error("Resources API not available on this server");
|
|
479
482
|
}
|
|
480
483
|
let resourceMap;
|
|
481
484
|
try {
|
|
@@ -483,8 +486,10 @@ async function readLogbookEntries(app) {
|
|
|
483
486
|
from: ALL_HISTORY_FROM,
|
|
484
487
|
to: ALL_HISTORY_TO,
|
|
485
488
|
});
|
|
486
|
-
} catch (
|
|
487
|
-
|
|
489
|
+
} catch (error) {
|
|
490
|
+
throw new Error(
|
|
491
|
+
`No logentries resource provider on this server — install signalk-logbook to backfill from the log (${error.message})`,
|
|
492
|
+
);
|
|
488
493
|
}
|
|
489
494
|
if (!resourceMap || typeof resourceMap !== "object") {
|
|
490
495
|
return [];
|
|
@@ -542,26 +547,6 @@ async function readLogbookEntriesRest({ baseUrl, token } = {}) {
|
|
|
542
547
|
);
|
|
543
548
|
}
|
|
544
549
|
|
|
545
|
-
/**
|
|
546
|
-
* Whether the `logentries` resource is being served on this server
|
|
547
|
-
* (the signalk-logbook provider is registered). Probed with a
|
|
548
|
-
* one-entry listing — cheap even on years of logs.
|
|
549
|
-
*
|
|
550
|
-
* @param {object} app - Signal K plugin `app`
|
|
551
|
-
* @returns {Promise<boolean>}
|
|
552
|
-
*/
|
|
553
|
-
async function logbookAvailable(app) {
|
|
554
|
-
if (typeof app?.resourcesApi?.listResources !== "function") {
|
|
555
|
-
return false;
|
|
556
|
-
}
|
|
557
|
-
try {
|
|
558
|
-
await app.resourcesApi.listResources(RESOURCE_TYPE, { limit: 1 });
|
|
559
|
-
return true;
|
|
560
|
-
} catch (_error) {
|
|
561
|
-
return false;
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
|
|
565
550
|
/**
|
|
566
551
|
* Reads the logbook through the resources API and extracts
|
|
567
552
|
* sail-change events, optionally bounded to a window (state tracking
|
|
@@ -609,7 +594,6 @@ module.exports = {
|
|
|
609
594
|
normalizeLogEntry,
|
|
610
595
|
readLogbookEntries,
|
|
611
596
|
readLogbookEntriesRest,
|
|
612
|
-
logbookAvailable,
|
|
613
597
|
readLogbookSailEvents,
|
|
614
598
|
foldTwaDegrees,
|
|
615
599
|
};
|
package/public/index.html
CHANGED
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<meta name="theme-color" content="#080a0c">
|
|
6
7
|
<title>Passage Briefing</title>
|
|
8
|
+
<link rel="icon" href="icon-256.png">
|
|
7
9
|
<link rel="stylesheet" href="css/visuals.css">
|
|
8
10
|
<script type="module" src="app.js"></script>
|
|
9
11
|
</head>
|
|
@@ -350,8 +350,8 @@ describe("readLogbookEntries", () => {
|
|
|
350
350
|
assert.ok(queries[0].from && queries[0].to);
|
|
351
351
|
});
|
|
352
352
|
|
|
353
|
-
test("no resources API or no provider
|
|
354
|
-
assert.
|
|
353
|
+
test("no resources API or no provider fails loudly with the reason", async () => {
|
|
354
|
+
await assert.rejects(readLogbookEntries({}), /Resources API not available/);
|
|
355
355
|
const failing = {
|
|
356
356
|
resourcesApi: {
|
|
357
357
|
async listResources() {
|
|
@@ -359,7 +359,10 @@ describe("readLogbookEntries", () => {
|
|
|
359
359
|
},
|
|
360
360
|
},
|
|
361
361
|
};
|
|
362
|
-
assert.
|
|
362
|
+
await assert.rejects(
|
|
363
|
+
readLogbookEntries(failing),
|
|
364
|
+
/logentries resource provider/,
|
|
365
|
+
);
|
|
363
366
|
});
|
|
364
367
|
});
|
|
365
368
|
|
|
@@ -453,7 +456,7 @@ describe("readLogbookSailEvents", () => {
|
|
|
453
456
|
assert.equal(windowed[0].eventType, "REEF_INCREASE");
|
|
454
457
|
});
|
|
455
458
|
|
|
456
|
-
test("missing provider
|
|
459
|
+
test("missing provider fails loudly with the reason", async () => {
|
|
457
460
|
const failing = {
|
|
458
461
|
resourcesApi: {
|
|
459
462
|
async listResources() {
|
|
@@ -461,7 +464,13 @@ describe("readLogbookSailEvents", () => {
|
|
|
461
464
|
},
|
|
462
465
|
},
|
|
463
466
|
};
|
|
464
|
-
assert.
|
|
465
|
-
|
|
467
|
+
await assert.rejects(
|
|
468
|
+
readLogbookSailEvents({ app: failing }),
|
|
469
|
+
/logentries resource provider/,
|
|
470
|
+
);
|
|
471
|
+
await assert.rejects(
|
|
472
|
+
readLogbookSailEvents({ app: {} }),
|
|
473
|
+
/Resources API not available/,
|
|
474
|
+
);
|
|
466
475
|
});
|
|
467
476
|
});
|
package/tests/plugin.test.js
CHANGED
|
@@ -2110,7 +2110,6 @@ test("source status: SK availability recorded and served at /sources", async ()
|
|
|
2110
2110
|
assert.equal(entries["sk-polar"].lastStatus, "ok");
|
|
2111
2111
|
assert.equal(entries["sk-ships-time"].lastStatus, "absent");
|
|
2112
2112
|
assert.equal(entries["sk-routes-resources"].lastStatus, "fail");
|
|
2113
|
-
assert.equal(entries["sk-logbook"].lastStatus, "absent");
|
|
2114
2113
|
|
|
2115
2114
|
// Configured sources have entries even before their first cycle
|
|
2116
2115
|
assert.equal(entries["weather-track"].lastStatus, null);
|