@rhizomatics/signalk-einklabel-plugin 0.7.0 → 0.7.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 CHANGED
@@ -1,3 +1,7 @@
1
+ # 0.7.1
2
+
3
+ - Fix path value retrieved for Image Fields when running in live plugin
4
+
1
5
  # 0.7.0
2
6
 
3
7
  ## Logging
@@ -8,6 +8,7 @@ exports.assembleExampleContext = assembleExampleContext;
8
8
  const promises_1 = require("fs/promises");
9
9
  const path_1 = __importDefault(require("path"));
10
10
  const formatters_1 = require("../render/formatters");
11
+ const unwrapSignalkTree_1 = require("../render/unwrapSignalkTree");
11
12
  const httpJson_1 = require("../httpJson");
12
13
  const unitCategories_1 = require("../unitCategories");
13
14
  const pathMeta_1 = require("../pathMeta");
@@ -18,29 +19,6 @@ const RESOURCES_API_PATH = "/signalk/v2/api/resources";
18
19
  function contextPath(context) {
19
20
  return context === "self" ? "vessels/self" : context.replace(/\./g, "/");
20
21
  }
21
- /**
22
- * `GET .../vessels/self` (or any other subtree) returns SignalK's full delta-tree shape, where every
23
- * leaf is wrapped as `{ value, $source, timestamp, ... }` rather than the bare value - unlike
24
- * `app.getSelfPath`/`getPath` in the live plugin (repaintScheduler.ts), which already return bare
25
- * values. Recursively unwraps every such leaf so `path=` bindings resolve the same way over HTTP as
26
- * they do live. Only applied to `signalk` fetches - `resources` responses have no such wrapper.
27
- *
28
- * Keys off `value` alone, not also requiring `timestamp`/`$source` - not every server includes both on
29
- * every leaf, and a `value` key is otherwise meaningless on a SignalK data-model node (it isn't a
30
- * regular vessel property name), so there's no real risk of unwrapping something that isn't this
31
- * wrapper.
32
- */
33
- function unwrapSignalkTree(node) {
34
- if (node === null || typeof node !== "object")
35
- return node;
36
- if (Array.isArray(node))
37
- return node.map(unwrapSignalkTree);
38
- const obj = node;
39
- if ("value" in obj) {
40
- return obj.value;
41
- }
42
- return Object.fromEntries(Object.entries(obj).map(([key, value]) => [key, unwrapSignalkTree(value)]));
43
- }
44
22
  /**
45
23
  * CLI counterpart to `assembleRawContext` + `considerRepaint`'s `meta` injection in
46
24
  * repaintScheduler.ts - same `{ signalk, resources, pathMeta, categories, meta }` shape, but fetched
@@ -56,7 +34,7 @@ async function assembleLiveContext(signalkUrl, bindings) {
56
34
  for (const context of contexts) {
57
35
  const url = `${signalkUrl}/signalk/v1/api/${contextPath(context)}`;
58
36
  (0, log_1.logDebug)(`GET ${url}`);
59
- signalk[context] = unwrapSignalkTree(await (0, httpJson_1.fetchJson)(url));
37
+ signalk[context] = (0, unwrapSignalkTree_1.unwrapSignalkTree)(await (0, httpJson_1.fetchJson)(url));
60
38
  }
61
39
  const pathMeta = {};
62
40
  for (const context of contexts) {
@@ -130,7 +108,7 @@ async function assembleExampleContext(examplesDir, bindings) {
130
108
  if (node === undefined) {
131
109
  throw new Error(`example data file ${vesselsPath} has no "${segments.join(".")}" subtree for context "${context}"`);
132
110
  }
133
- signalk[context] = unwrapSignalkTree(node);
111
+ signalk[context] = (0, unwrapSignalkTree_1.unwrapSignalkTree)(node);
134
112
  }
135
113
  }
136
114
  const resources = {};
@@ -0,0 +1,15 @@
1
+ /**
2
+ * SignalK's full data-model shape wraps every leaf as `{ value, $source, timestamp, ... }` rather
3
+ * than the bare value - true both over HTTP (`GET .../vessels/self`) and in-process
4
+ * (`app.getSelfPath`/`getPath` in the live plugin, see `repaintScheduler.ts` - despite that module's
5
+ * name, these do NOT already return bare values for a regular published path; only a handful of
6
+ * vessel-identity fields like `uuid` do). Recursively unwraps every such leaf so a `path=` binding
7
+ * resolves the same way regardless of which of the two ways the render context was assembled. Only
8
+ * applied to `signalk` fetches - `resources` responses have no such wrapper.
9
+ *
10
+ * Keys off `value` alone, not also requiring `timestamp`/`$source` - not every server includes both
11
+ * on every leaf, and a `value` key is otherwise meaningless on a SignalK data-model node (it isn't a
12
+ * regular vessel property name), so there's no real risk of unwrapping something that isn't this
13
+ * wrapper.
14
+ */
15
+ export declare function unwrapSignalkTree(node: unknown): unknown;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.unwrapSignalkTree = unwrapSignalkTree;
4
+ /**
5
+ * SignalK's full data-model shape wraps every leaf as `{ value, $source, timestamp, ... }` rather
6
+ * than the bare value - true both over HTTP (`GET .../vessels/self`) and in-process
7
+ * (`app.getSelfPath`/`getPath` in the live plugin, see `repaintScheduler.ts` - despite that module's
8
+ * name, these do NOT already return bare values for a regular published path; only a handful of
9
+ * vessel-identity fields like `uuid` do). Recursively unwraps every such leaf so a `path=` binding
10
+ * resolves the same way regardless of which of the two ways the render context was assembled. Only
11
+ * applied to `signalk` fetches - `resources` responses have no such wrapper.
12
+ *
13
+ * Keys off `value` alone, not also requiring `timestamp`/`$source` - not every server includes both
14
+ * on every leaf, and a `value` key is otherwise meaningless on a SignalK data-model node (it isn't a
15
+ * regular vessel property name), so there's no real risk of unwrapping something that isn't this
16
+ * wrapper.
17
+ */
18
+ function unwrapSignalkTree(node) {
19
+ if (node === null || typeof node !== "object")
20
+ return node;
21
+ if (Array.isArray(node))
22
+ return node.map(unwrapSignalkTree);
23
+ const obj = node;
24
+ if ("value" in obj) {
25
+ return obj.value;
26
+ }
27
+ return Object.fromEntries(Object.entries(obj).map(([key, value]) => [key, unwrapSignalkTree(value)]));
28
+ }
@@ -10,6 +10,7 @@ const registry_1 = require("./devices/registry");
10
10
  const svgRenderer_1 = require("./render/svgRenderer");
11
11
  const binding_1 = require("./render/binding");
12
12
  const formatters_1 = require("./render/formatters");
13
+ const unwrapSignalkTree_1 = require("./render/unwrapSignalkTree");
13
14
  const unitCategories_1 = require("./unitCategories");
14
15
  const pathMeta_1 = require("./pathMeta");
15
16
  const resolveApiUrl_1 = require("./resolveApiUrl");
@@ -58,13 +59,20 @@ function setAtPath(target, path, value) {
58
59
  /**
59
60
  * Reads live data for exactly what a template's own bindings ask for - no separate config declaring it.
60
61
  * `signalk`-sourced bindings are read directly (`self` via `getSelfPath`, anything else via `getPath`
61
- * against that literal SignalK context) - in-process, no URL needed. `resources`-sourced bindings go
62
- * through `app.resourcesApi`, in-process too. Per-path unit-conversion metadata (`pathMeta`, for
63
- * automatic conversion - see `renderBinding`) and an explicit `category=` binding's resolved
64
- * conversion both have no in-process equivalent (confirmed against the signalk-server source - that
65
- * resolution only happens in its REST layer), so both need `apiUrl` - fetching `pathMeta` is
66
- * best-effort (a missing/unreachable server just means no automatic conversion), but a `category=`
67
- * binding is a declared dependency, so a missing `apiUrl` is a hard error there.
62
+ * against that literal SignalK context) - in-process, no URL needed. Despite their names, neither
63
+ * already returns a bare value for a regular published path - both return the full data-model node
64
+ * (`{ path, value, context, source, $source, timestamp }`); only a handful of vessel-identity fields
65
+ * like `uuid` come back bare. `unwrapSignalkTree` strips that wrapper the same way it does for the
66
+ * CLI's HTTP-fetched equivalent (`assembleLiveContext` in `cli/liveContext.ts`), so a `path=` binding
67
+ * resolves to the same value either way - without it, `resolveBinding` would hand back the whole
68
+ * wrapper object instead of e.g. a plain string, breaking any binding that expects one (a `<image>`'s
69
+ * `assets=`, a `format=` formatter, etc). `resources`-sourced bindings go through `app.resourcesApi`,
70
+ * in-process too, with no such wrapper. Per-path unit-conversion metadata (`pathMeta`, for automatic
71
+ * conversion - see `renderBinding`) and an explicit `category=` binding's resolved conversion both
72
+ * have no in-process equivalent (confirmed against the signalk-server source - that resolution only
73
+ * happens in its REST layer), so both need `apiUrl` - fetching `pathMeta` is best-effort (a
74
+ * missing/unreachable server just means no automatic conversion), but a `category=` binding is a
75
+ * declared dependency, so a missing `apiUrl` is a hard error there.
68
76
  */
69
77
  async function assembleRawContext(app, apiUrl, bindings) {
70
78
  var _a;
@@ -77,7 +85,8 @@ async function assembleRawContext(app, apiUrl, bindings) {
77
85
  if (seenSignalk.has(key))
78
86
  continue;
79
87
  seenSignalk.add(key);
80
- const value = binding.context === "self" ? app.getSelfPath(binding.path) : app.getPath(`${binding.context}.${binding.path}`);
88
+ const rawValue = binding.context === "self" ? app.getSelfPath(binding.path) : app.getPath(`${binding.context}.${binding.path}`);
89
+ const value = (0, unwrapSignalkTree_1.unwrapSignalkTree)(rawValue);
81
90
  const namespace = (signalk[_a = binding.context] ?? (signalk[_a] = {}));
82
91
  setAtPath(namespace, binding.path, value);
83
92
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rhizomatics/signalk-einklabel-plugin",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
4
4
  "description": "Display SignalK data on eInk Electronic Shelf Labels",
5
5
  "keywords": [
6
6
  "ble",