@transitive-sdk/utils-web 0.13.0 → 0.14.0

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/client/client.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // It is OK to use paths outside of this package because webpack will bundle them
2
2
  export * from '../../common/common.js';
3
- export * from '../../common/DataCache';
3
+ export * from '../../common/datacache';
4
4
  import MS from '../../common/MqttSync.js';
5
5
  export const MqttSync = MS;
6
6
 
package/client/hooks.jsx CHANGED
@@ -10,6 +10,8 @@ const MqttSync = require('../../common/MqttSync');
10
10
  const log = getLogger('utils-web/hooks');
11
11
  log.setLevel('info');
12
12
 
13
+ const RECONNECT_PERIOD_DEFAULT = 1000; // default time until mqtt retries connecting
14
+ const RECONNECT_PERIOD_MAX = 20000; // max retry time (after dynamic backoff)
13
15
 
14
16
  /** Hook for using MqttSync in React.
15
17
  * @returns {object} An object `{data, mqttSync, ready, StatusComponent, status}`
@@ -31,14 +33,43 @@ export const useMqttSync = ({jwt, id, mqttUrl, appReact}) => {
31
33
 
32
34
  useEffect(() => {
33
35
  const payload = decodeJWT(jwt);
34
- log.debug('re-create mqtt client');
36
+
37
+ // pre-check validity of JWT, don't use if expired
38
+ const { validity, iat } = payload;
39
+ if (!validity || !iat || (iat + validity) * 1e3 < Date.now()) {
40
+ const error = 'The provided JWT is invalid or expired.';
41
+ log.warn(error, payload);
42
+ setStatus(`error: ${error}`);
43
+ return;
44
+ }
45
+
46
+ /** Implement dynamic backoff when we fail to connect. */
47
+ let reconnectPeriod = RECONNECT_PERIOD_DEFAULT; // default to start with
48
+ const transformWsUrl = (url, options, client) => {
49
+ options.reconnectPeriod = reconnectPeriod;
50
+ log.info(`reconnect in ${options.reconnectPeriod} s`);
51
+ return url;
52
+ }
53
+
54
+ log.debug('(re-)create mqtt client');
35
55
  const client = mqtt.connect(mqttUrl, {
36
56
  username: JSON.stringify({id, payload}),
37
- password: jwt
57
+ password: jwt,
58
+ transformWsUrl
38
59
  });
39
60
 
61
+ // Increase backoff with each close (since we can't actually detect auth
62
+ // errors)
63
+ client.on('close', () =>
64
+ reconnectPeriod = Math.min(reconnectPeriod * 2, RECONNECT_PERIOD_MAX)
65
+ );
66
+
67
+ // reset to default after a successful connection
68
+ client.on('connect', () => reconnectPeriod = RECONNECT_PERIOD_DEFAULT);
69
+
40
70
  client.once('connect', () => {
41
71
  log.debug('MQTT connected');
72
+
42
73
  const mqttSyncClient = new MqttSync({
43
74
  mqttClient: client,
44
75
  ignoreRetain: true,
package/dist/utils-web.js CHANGED
@@ -143,97 +143,26 @@ var require_react_web_component = __commonJS({
143
143
  }
144
144
  });
145
145
 
146
- // ../common/constants.js
147
- var require_constants = __commonJS({
148
- "../common/constants.js"(exports, module2) {
149
- module2.exports = {
150
- rosReleases: {
151
- kinetic: { rosVersion: 1, ubuntuCodename: "xenial" },
152
- melodic: { rosVersion: 1, ubuntuCodename: "bionic" },
153
- noetic: { rosVersion: 1, ubuntuCodename: "focal" },
154
- dashing: { rosVersion: 2 },
155
- eloquent: { rosVersion: 2 },
156
- foxy: { rosVersion: 2 },
157
- galactic: { rosVersion: 2 },
158
- humble: { rosVersion: 2 },
159
- iron: { rosVersion: 2 },
160
- jazzy: { rosVersion: 2 },
161
- kilted: { rosVersion: 2 },
162
- rolling: { rosVersion: 2 }
163
- }
164
- };
165
- }
166
- });
167
-
168
- // ../common/common.js
169
- var require_common = __commonJS({
170
- "../common/common.js"(exports, module2) {
171
- var semverCompare = require("semver/functions/compare");
172
- var semverMinVersion = require("semver/ranges/min-version");
146
+ // ../common/datacache/tools.js
147
+ var require_tools = __commonJS({
148
+ "../common/datacache/tools.js"(exports, module2) {
173
149
  var _2 = {
174
150
  get: require("lodash/get"),
175
151
  set: require("lodash/set"),
176
- unset: require("lodash/unset"),
177
152
  forEach: require("lodash/forEach"),
178
153
  map: require("lodash/map"),
179
- isEmpty: require("lodash/isEmpty"),
180
- eq: require("lodash/isEqual"),
181
- isPlainObject: require("lodash/isPlainObject"),
182
- merge: require("lodash/merge")
183
- };
184
- var loglevel = require("loglevel");
185
- var chalk = require("chalk");
186
- var constants = require_constants();
187
- loglevel.setAll = (level) => Object.values(loglevel.getLoggers()).forEach((l) => l.setLevel(level));
188
- var methodColors = {
189
- warn: chalk.yellow,
190
- error: chalk.red,
191
- info: chalk.green,
192
- debug: chalk.gray
193
- };
194
- var coloredMethod = (method) => methodColors[method] ? methodColors[method](method) : method;
195
- var originalFactory = loglevel.methodFactory;
196
- loglevel.methodFactory = (methodName, level, loggerName) => {
197
- const rawMethod = originalFactory(methodName, level, loggerName);
198
- if (typeof window != "undefined") {
199
- const context2 = `${loggerName} ${methodName}`;
200
- return (...args) => rawMethod(`[${context2}]`, ...args);
201
- }
202
- const context = `${loggerName} ${coloredMethod(methodName)}`;
203
- return (...args) => rawMethod(
204
- `[${chalk.blue((/* @__PURE__ */ new Date()).toISOString())} ${context}]`,
205
- ...args
206
- );
207
- };
208
- var getLogger2 = loglevel.getLogger;
209
- var clone2 = (obj) => JSON.parse(JSON.stringify(obj));
210
- var decodeJWT3 = (jwt) => JSON.parse(atob(jwt.split(".")[1]));
211
- var tryJSONParse = (string) => {
212
- try {
213
- return JSON.parse(string);
214
- } catch (e) {
215
- return null;
216
- }
154
+ isPlainObject: require("lodash/isPlainObject")
217
155
  };
218
- var visit = (object, childField, visitor) => {
219
- if (!object)
220
- return;
221
- visitor(object);
222
- object[childField]?.forEach((child) => visit(child, childField, visitor));
156
+ var topicToPath2 = (topic) => {
157
+ const path = topic.split("/").map(decodeTopicElement);
158
+ path.length > 0 && path[0].length == 0 && path.shift();
159
+ path.length > 0 && path.at(-1).length == 0 && path.pop();
160
+ return path;
223
161
  };
224
- var visitAncestor = (object, path, visitor, prefix = []) => {
225
- visitor(object, prefix);
226
- const next = path[0];
227
- if (next) {
228
- const sub = object[next];
229
- if (sub) {
230
- visitAncestor(sub, path.slice(1), visitor, prefix.concat(next));
231
- }
232
- }
162
+ var pathToTopic2 = (pathArray) => {
163
+ const dropWildcardIds = (x) => x.startsWith("+") ? "+" : x;
164
+ return `/${pathArray.map(dropWildcardIds).map(encodeTopicElement).join("/")}`;
233
165
  };
234
- var wait = (delay) => new Promise((resolve) => {
235
- setTimeout(resolve, delay);
236
- });
237
166
  var toFlatObject = (obj, prefix = [], rtv = {}) => {
238
167
  _2.forEach(obj, (value, key) => {
239
168
  const newPrefix = prefix.concat(String(key));
@@ -280,16 +209,6 @@ var require_common = __commonJS({
280
209
  };
281
210
  var encodeTopicElement = (x) => x.replace(/%/g, "%25").replace(/\//g, "%2F");
282
211
  var decodeTopicElement = (x) => x.replace(/%25/g, "%").replace(/%2F/g, "/");
283
- var pathToTopic2 = (pathArray) => {
284
- const dropWildcardIds = (x) => x.startsWith("+") ? "+" : x;
285
- return `/${pathArray.map(dropWildcardIds).map(encodeTopicElement).join("/")}`;
286
- };
287
- var topicToPath2 = (topic) => {
288
- const path = topic.split("/").map(decodeTopicElement);
289
- path.length > 0 && path[0].length == 0 && path.shift();
290
- path.length > 0 && path.at(-1).length == 0 && path.pop();
291
- return path;
292
- };
293
212
  var topicMatch = (selector, topic) => {
294
213
  const byArray = (s, p) => {
295
214
  if (s.length == 0)
@@ -306,8 +225,8 @@ var require_common = __commonJS({
306
225
  }
307
226
  return false;
308
227
  };
309
- const selectorArray = topicToPath2(selector);
310
- const pathArray = topicToPath2(topic);
228
+ const selectorArray = Array.isArray(selector) ? selector : topicToPath2(selector);
229
+ const pathArray = Array.isArray(topic) ? topic : topicToPath2(topic);
311
230
  return byArray(selectorArray, pathArray);
312
231
  };
313
232
  var isSubTopicOf = (sub, parent) => {
@@ -320,6 +239,122 @@ var require_common = __commonJS({
320
239
  return true;
321
240
  return prefixArray[0] == array[0] && isPrefixOf(prefixArray.slice(1), array.slice(1));
322
241
  };
242
+ module2.exports = {
243
+ topicToPath: topicToPath2,
244
+ pathToTopic: pathToTopic2,
245
+ toFlatObject,
246
+ forMatchIterator,
247
+ setFromPath,
248
+ encodeTopicElement,
249
+ decodeTopicElement,
250
+ topicMatch,
251
+ isSubTopicOf
252
+ };
253
+ }
254
+ });
255
+
256
+ // ../common/constants.js
257
+ var require_constants = __commonJS({
258
+ "../common/constants.js"(exports, module2) {
259
+ module2.exports = {
260
+ rosReleases: {
261
+ kinetic: { rosVersion: 1, ubuntuCodename: "xenial" },
262
+ melodic: { rosVersion: 1, ubuntuCodename: "bionic" },
263
+ noetic: { rosVersion: 1, ubuntuCodename: "focal" },
264
+ dashing: { rosVersion: 2 },
265
+ eloquent: { rosVersion: 2 },
266
+ foxy: { rosVersion: 2 },
267
+ galactic: { rosVersion: 2 },
268
+ humble: { rosVersion: 2 },
269
+ iron: { rosVersion: 2 },
270
+ jazzy: { rosVersion: 2 },
271
+ kilted: { rosVersion: 2 },
272
+ rolling: { rosVersion: 2 }
273
+ }
274
+ };
275
+ }
276
+ });
277
+
278
+ // ../common/common.js
279
+ var require_common = __commonJS({
280
+ "../common/common.js"(exports, module2) {
281
+ var semverCompare = require("semver/functions/compare");
282
+ var semverMinVersion = require("semver/ranges/min-version");
283
+ var _2 = {
284
+ get: require("lodash/get"),
285
+ set: require("lodash/set"),
286
+ unset: require("lodash/unset"),
287
+ forEach: require("lodash/forEach"),
288
+ map: require("lodash/map"),
289
+ isEmpty: require("lodash/isEmpty"),
290
+ eq: require("lodash/isEqual"),
291
+ isPlainObject: require("lodash/isPlainObject"),
292
+ merge: require("lodash/merge")
293
+ };
294
+ var loglevel = require("loglevel");
295
+ var prefix = require("loglevel-plugin-prefix");
296
+ var chalk = require("chalk");
297
+ var {
298
+ topicToPath: topicToPath2,
299
+ pathToTopic: pathToTopic2,
300
+ toFlatObject,
301
+ setFromPath,
302
+ forMatchIterator,
303
+ topicMatch,
304
+ isSubTopicOf,
305
+ encodeTopicElement,
306
+ decodeTopicElement
307
+ } = require_tools();
308
+ var constants = require_constants();
309
+ loglevel.setAll = (level) => Object.values(loglevel.getLoggers()).forEach((l) => l.setLevel(level));
310
+ var logColors = {
311
+ warn: chalk.yellow,
312
+ error: chalk.red,
313
+ info: chalk.green,
314
+ debug: chalk.gray
315
+ };
316
+ var levelFormatter = (level) => logColors[level] ? logColors[level](level) : level;
317
+ prefix.reg(loglevel);
318
+ if (typeof window != "undefined") {
319
+ prefix.apply(loglevel, {
320
+ template: "[%n %l]"
321
+ });
322
+ } else {
323
+ prefix.apply(loglevel, {
324
+ template: "[%t %n %l]",
325
+ levelFormatter,
326
+ timestampFormatter: (date) => chalk.blue(date.toISOString())
327
+ });
328
+ }
329
+ var getLogger2 = loglevel.getLogger;
330
+ var clone2 = (obj) => JSON.parse(JSON.stringify(obj));
331
+ var decodeJWT3 = (jwt) => JSON.parse(atob(jwt.split(".")[1]));
332
+ var tryJSONParse = (string) => {
333
+ try {
334
+ return JSON.parse(string);
335
+ } catch (e) {
336
+ return null;
337
+ }
338
+ };
339
+ var visit = (object, childField, visitor) => {
340
+ if (!object)
341
+ return;
342
+ visitor(object);
343
+ object[childField]?.forEach((child) => visit(child, childField, visitor));
344
+ };
345
+ var visitAncestor = (object, path, visitor, prefix2 = []) => {
346
+ visitor(object, prefix2);
347
+ const next = path[0];
348
+ if (next) {
349
+ const sub = object[next];
350
+ if (sub) {
351
+ visitAncestor(sub, path.slice(1), visitor, prefix2.concat(next));
352
+ }
353
+ }
354
+ };
355
+ var wait = (delay) => new Promise((resolve) => {
356
+ setTimeout(resolve, delay);
357
+ });
323
358
  var parseMQTTUsername = (username) => {
324
359
  const parts = username.split(":");
325
360
  return {
@@ -345,24 +380,24 @@ var require_common = __commonJS({
345
380
  const toDelete = [];
346
381
  const collectToDelete = (topic) => {
347
382
  prefixes.forEach(
348
- (prefix) => (
383
+ (prefix2) => (
349
384
  // mqttTopicMatch(topic, `${prefix}/#`) && toDelete.push(topic)
350
- topicMatch(`${prefix}/#`, topic) && toDelete.push(topic)
385
+ topicMatch(`${prefix2}/#`, topic) && toDelete.push(topic)
351
386
  )
352
387
  );
353
388
  };
354
389
  mqttClient.on("message", collectToDelete);
355
- prefixes.forEach((prefix) => {
356
- if (typeof prefix == "string") {
357
- mqttClient.subscribe(`${prefix}/#`);
390
+ prefixes.forEach((prefix2) => {
391
+ if (typeof prefix2 == "string") {
392
+ mqttClient.subscribe(`${prefix2}/#`);
358
393
  } else {
359
- console.warn("Ignoring", prefix, "since it is not a string.");
394
+ console.warn("Ignoring", prefix2, "since it is not a string.");
360
395
  }
361
396
  });
362
397
  const nullValue = typeof Buffer != "undefined" ? Buffer.alloc(0) : null;
363
398
  setTimeout(() => {
364
399
  mqttClient.removeListener("message", collectToDelete);
365
- prefixes.forEach((prefix) => mqttClient.unsubscribe(`${prefix}/#`));
400
+ prefixes.forEach((prefix2) => mqttClient.unsubscribe(`${prefix2}/#`));
366
401
  const count = toDelete.length;
367
402
  console.log(`clearing ${count} retained messages from ${prefixes}`);
368
403
  toDelete.forEach((topic) => {
@@ -464,9 +499,9 @@ var require_common = __commonJS({
464
499
  }
465
500
  });
466
501
 
467
- // ../common/DataCache.js
502
+ // ../common/datacache/DataCache.js
468
503
  var require_DataCache = __commonJS({
469
- "../common/DataCache.js"(exports, module2) {
504
+ "../common/datacache/DataCache.js"(exports, module2) {
470
505
  var _2 = {
471
506
  get: require("lodash/get"),
472
507
  set: require("lodash/set"),
@@ -478,7 +513,7 @@ var require_DataCache = __commonJS({
478
513
  isPlainObject: require("lodash/isPlainObject"),
479
514
  merge: require("lodash/merge")
480
515
  };
481
- var { topicToPath: topicToPath2, pathToTopic: pathToTopic2, toFlatObject, topicMatch, forMatchIterator } = require_common();
516
+ var { topicToPath: topicToPath2, pathToTopic: pathToTopic2, toFlatObject, topicMatch, forMatchIterator } = require_tools();
482
517
  var unset = (obj, path) => {
483
518
  if (!path || path.length == 0)
484
519
  return;
@@ -522,6 +557,7 @@ var require_DataCache = __commonJS({
522
557
  #flatListeners = [];
523
558
  constructor(data = {}) {
524
559
  this.#data = data;
560
+ this.subscribeTopic = this.subscribePath;
525
561
  }
526
562
  /** Update the object with the given value at the given path, remove empty;
527
563
  return the flat changes (see toFlatObject). Add `tags` to updates to mark
@@ -585,16 +621,21 @@ var require_DataCache = __commonJS({
585
621
  console.warn("DataCache.subscribe expects a function as argument. Did you mean to use subscribePath?");
586
622
  }
587
623
  }
588
- /** Subscribe to a specific topic only. Callback receives
589
- `value, key, matched, tags`. TODO: rename to subscribeTopic. */
590
- subscribePath(topic, callback) {
624
+ /** Subscribe to a specific path (array) only. Callback receives
625
+ `value, key, matched, tags`. */
626
+ subscribePath(path, callback) {
591
627
  this.#listeners.push((changes, tags) => {
592
628
  _2.forEach(changes, (value, key) => {
593
- const matched = topicMatch(topic, key);
629
+ const matched = topicMatch(path, key);
594
630
  matched && callback(value, key, matched, tags);
595
631
  });
596
632
  });
597
633
  }
634
+ /** Subscribe to a specific topic only. Callback receives
635
+ `value, key, matched, tags`. */
636
+ subscribeTopic(topic, callback) {
637
+ this.subscribePath(topic, callback);
638
+ }
598
639
  /** Same as subscribePath but always get all changes in flat form */
599
640
  subscribePathFlat(topic, callback) {
600
641
  this.#flatListeners.push((changes, tags) => {
@@ -645,6 +686,15 @@ var require_DataCache = __commonJS({
645
686
  }
646
687
  });
647
688
 
689
+ // ../common/datacache/index.js
690
+ var require_datacache = __commonJS({
691
+ "../common/datacache/index.js"(exports, module2) {
692
+ var dataCache = require_DataCache();
693
+ var tools = require_tools();
694
+ module2.exports = { ...dataCache, ...tools };
695
+ }
696
+ });
697
+
648
698
  // ../common/MqttSync.js
649
699
  var require_MqttSync = __commonJS({
650
700
  "../common/MqttSync.js"(exports, module2) {
@@ -1261,7 +1311,7 @@ __export(client_exports, {
1261
1311
  parseCookie: () => parseCookie
1262
1312
  });
1263
1313
  __reExport(client_exports, __toESM(require_common()));
1264
- __reExport(client_exports, __toESM(require_DataCache()));
1314
+ __reExport(client_exports, __toESM(require_datacache()));
1265
1315
  var import_MqttSync = __toESM(require_MqttSync());
1266
1316
  var MqttSync = import_MqttSync.default;
1267
1317
  var parseCookie = (str) => str.split(";").map((v) => v.split("=")).reduce((acc, v) => {
@@ -1297,6 +1347,8 @@ var import_mqtt = __toESM(require("mqtt/dist/mqtt.esm"));
1297
1347
  var MqttSync2 = require_MqttSync();
1298
1348
  var log = (0, client_exports.getLogger)("utils-web/hooks");
1299
1349
  log.setLevel("info");
1350
+ var RECONNECT_PERIOD_DEFAULT = 1e3;
1351
+ var RECONNECT_PERIOD_MAX = 2e4;
1300
1352
  var useMqttSync = ({ jwt, id, mqttUrl, appReact }) => {
1301
1353
  const { useState: useState3, useRef: useRef2, useEffect: useEffect3 } = appReact || import_react.default;
1302
1354
  const [status, setStatus] = useState3("connecting");
@@ -1305,11 +1357,30 @@ var useMqttSync = ({ jwt, id, mqttUrl, appReact }) => {
1305
1357
  const [heartbeatGranted, setHeartbeatGranted] = useState3(false);
1306
1358
  useEffect3(() => {
1307
1359
  const payload = (0, client_exports.decodeJWT)(jwt);
1308
- log.debug("re-create mqtt client");
1360
+ const { validity, iat } = payload;
1361
+ if (!validity || !iat || (iat + validity) * 1e3 < Date.now()) {
1362
+ const error = "The provided JWT is invalid or expired.";
1363
+ log.warn(error, payload);
1364
+ setStatus(`error: ${error}`);
1365
+ return;
1366
+ }
1367
+ let reconnectPeriod = RECONNECT_PERIOD_DEFAULT;
1368
+ const transformWsUrl = (url, options, client2) => {
1369
+ options.reconnectPeriod = reconnectPeriod;
1370
+ log.info(`reconnect in ${options.reconnectPeriod} s`);
1371
+ return url;
1372
+ };
1373
+ log.debug("(re-)create mqtt client");
1309
1374
  const client = import_mqtt.default.connect(mqttUrl, {
1310
1375
  username: JSON.stringify({ id, payload }),
1311
- password: jwt
1376
+ password: jwt,
1377
+ transformWsUrl
1312
1378
  });
1379
+ client.on(
1380
+ "close",
1381
+ () => reconnectPeriod = Math.min(reconnectPeriod * 2, RECONNECT_PERIOD_MAX)
1382
+ );
1383
+ client.on("connect", () => reconnectPeriod = RECONNECT_PERIOD_DEFAULT);
1313
1384
  client.once("connect", () => {
1314
1385
  log.debug("MQTT connected");
1315
1386
  const mqttSyncClient = new MqttSync2({
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../client/react-web-component/getStyleElementsFromReactWebComponentStyleLoader.js", "../client/react-web-component/extractAttributes.js", "../client/react-web-component/index.js", "../../common/constants.js", "../../common/common.js", "../../common/DataCache.js", "../../common/MqttSync.js", "../index.js", "../client/shared.jsx", "../client/client.js", "../client/hooks.jsx"],
4
- "sourcesContent": ["/*\n * An optional library which is conditionally added\n * @returns {[]}\n */\nmodule.exports = () => {\n try {\n return require('react-web-component-style-loader/exports').styleElements;\n } catch (e) {\n return [];\n }\n};\n", "/*\n * Takes in a node attributes map and returns an object with camelCased\n * properties and values\n * @param nodeMap\n * @returns {{}}\n */\nmodule.exports = function extractAttributes(nodeMap) {\n if (!nodeMap.attributes) {\n return {};\n }\n\n let obj = {};\n let attribute;\n const attributesAsNodeMap = [...nodeMap.attributes];\n const attributes = attributesAsNodeMap.map((attribute) =>\n ({ [attribute.name]: attribute.value }));\n\n for (attribute of attributes) {\n const key = Object.keys(attribute)[0];\n const camelCasedKey = key.replace(/-([a-z])/g, (g) => g[1].toUpperCase());\n obj[camelCasedKey] = attribute[key];\n }\n\n return obj;\n};\n", "const React = require('react');\nconst ReactDOM = require('react-dom');\nconst { createRoot } = require('react-dom/client');\n\n// const { createRoot } = require('react-dom/client'); // react 18; wip\nconst retargetEvents = require('react-shadow-dom-retarget-events');\nconst getStyleElementsFromReactWebComponentStyleLoader = require('./getStyleElementsFromReactWebComponentStyleLoader');\nconst extractAttributes = require('./extractAttributes');\n\n// require('@webcomponents/shadydom');\n// require('@webcomponents/custom-elements');\n\nconst lifeCycleHooks = {\n attachedCallback: 'webComponentAttached',\n connectedCallback: 'webComponentConnected',\n disconnectedCallback: 'webComponentDisconnected',\n adoptedCallback: 'webComponentAdopted'\n};\n\nmodule.exports = {\n /*\n * @param {JSX.Element} wrapper: the wrapper component class to be instantiated and wrapped\n * @param {string} tagName - The name of the web component. Has to be minus \"-\" delimited.\n * @param {boolean} useShadowDom - If the value is set to \"true\" the web component will use the `shadowDom`. The default value is true.\n */\n create: (wrapper, tagName, useShadowDom = true, compRef = undefined) => {\n\n const proto = class extends HTMLElement {\n instance = null; // the instance we create of the wrapper\n\n callConstructorHook() {\n if (this.instance['webComponentConstructed']) {\n this.instance['webComponentConstructed'].apply(this.instance, [this])\n }\n }\n\n callLifeCycleHook(hook, params = []) {\n const method = lifeCycleHooks[hook];\n if (method && this.instance && this.instance[method]) {\n this.instance[method].apply(this.instance, params);\n }\n }\n\n connectedCallback() {\n const self = this;\n let mountPoint = self;\n\n if (useShadowDom) {\n // Re-assign the self (this) to the newly created shadowRoot\n const shadowRoot = self.attachShadow({ mode: 'open' });\n\n // Re-assign the mountPoint to the newly created \"div\" element\n mountPoint = document.createElement('div');\n\n // Move all of the styles assigned to the react component inside of\n // the shadowRoot. By default this is not used, only if the library is\n // explicitly installed\n const styles = getStyleElementsFromReactWebComponentStyleLoader();\n styles.forEach((style) => {\n shadowRoot.appendChild(style.cloneNode(shadowRoot));\n });\n\n shadowRoot.appendChild(mountPoint);\n retargetEvents(shadowRoot);\n }\n\n createRoot(mountPoint).render(\n // This is where we instantiate the actual component (in its wrapper)\n React.createElement(wrapper, {_element: self, ...extractAttributes(self)})\n );\n }\n\n disconnectedCallback() {\n this.callLifeCycleHook('disconnectedCallback');\n }\n\n adoptedCallback(oldDocument, newDocument) {\n this.callLifeCycleHook('adoptedCallback', [oldDocument, newDocument]);\n }\n\n /* call a function defined in the component, either as a class method, or\n * via useImperativeHandle */\n call(functionName, args) {\n return compRef?.current?.[functionName]?.call(compRef?.current, args);\n }\n\n /* predefined function to retrieve the pre-defined config object of the\n * state, populated via the pre-defined `setConfig` method given as prop\n * to the wrapped component. */\n getConfig() {\n return this.instance.state.config;\n }\n }\n\n customElements.define(tagName, proto);\n\n return proto;\n },\n};\n", "module.exports = {\n rosReleases: {\n kinetic: { rosVersion: 1, ubuntuCodename: 'xenial' },\n melodic: { rosVersion: 1, ubuntuCodename: 'bionic' },\n noetic: { rosVersion: 1, ubuntuCodename: 'focal' },\n dashing: { rosVersion: 2 },\n eloquent: { rosVersion: 2 },\n foxy: { rosVersion: 2 },\n galactic: { rosVersion: 2 },\n humble: { rosVersion: 2 },\n iron: { rosVersion: 2 },\n jazzy: { rosVersion: 2 },\n kilted: { rosVersion: 2 },\n rolling: { rosVersion: 2 },\n }\n};\n", "const semverCompare = require('semver/functions/compare');\nconst semverMinVersion = require('semver/ranges/min-version');\n\nconst _ = {\n get: require('lodash/get'),\n set: require('lodash/set'),\n unset: require('lodash/unset'),\n forEach: require('lodash/forEach'),\n map: require('lodash/map'),\n isEmpty: require('lodash/isEmpty'),\n eq: require('lodash/isEqual'),\n isPlainObject: require('lodash/isPlainObject'),\n merge: require('lodash/merge'),\n};\n\nconst loglevel = require('loglevel');\nconst chalk = require('chalk');\n\nconst constants = require('./constants');\n\n/* Convenience function to set all loggers to the given level. */\nloglevel.setAll = (level) =>\n Object.values(loglevel.getLoggers()).forEach(l => l.setLevel(level));\n\nconst methodColors = {\n warn: chalk.yellow,\n error: chalk.red,\n info: chalk.green,\n debug: chalk.gray,\n};\nconst coloredMethod = (method) =>\n methodColors[method] ? methodColors[method](method) : method;\n\n// patch the methodFactory to prefix logs with name and level\nconst originalFactory = loglevel.methodFactory;\nloglevel.methodFactory = (methodName, level, loggerName) => {\n const rawMethod = originalFactory(methodName, level, loggerName);\n\n if (typeof window != 'undefined') {\n // browser: keep it simple\n const context = `${loggerName} ${methodName}`;\n return (...args) => rawMethod(`[${context}]`, ...args);\n }\n\n const context = `${loggerName} ${coloredMethod(methodName)}`;\n return (...args) => rawMethod(\n `[${chalk.blue((new Date()).toISOString())} ${context}]`, ...args);\n};\n\n/** Get a new loglevel logger; call with a name, e.g., `module.id`. The returned\n* logger has methods trace, debug, info, warn, error. See\n* https://www.npmjs.com/package/loglevel for details.\n*/\nconst getLogger = loglevel.getLogger;\n\n/** Deep-clone the given object. All functionality is lost, just data is kept. */\nconst clone = (obj) => JSON.parse(JSON.stringify(obj));\n\n/** Parse JWT and return the decoded payload (JSON). */\nconst decodeJWT = (jwt) => JSON.parse(atob(jwt.split('.')[1]));\n// TODO: make this robust against bad JWTs (throw a more readable error)\n\n/** Try parsing JSON, return null if unsuccessful */\nconst tryJSONParse = (string) => {\n try {\n return JSON.parse(string);\n } catch (e) {\n return null;\n }\n};\n\n/** Reusable visitor pattern: iteratively visits all nodes in the tree\n described by `object`, where `childField` indicates the child-of predicate.\n*/\nconst visit = (object, childField, visitor) => {\n if (!object) return;\n visitor(object);\n object[childField]?.forEach(child => visit(child, childField, visitor));\n};\n\n/** Given an object and a path, visit each ancestor of the path */\nconst visitAncestor = (object, path, visitor, prefix = []) => {\n visitor(object, prefix);\n const next = path[0];\n if (next) {\n const sub = object[next];\n if (sub) {\n visitAncestor(sub, path.slice(1), visitor, prefix.concat(next));\n }\n }\n};\n\n/** Wait for delay ms, for use in async functions. */\nconst wait = (delay) => new Promise((resolve) => { setTimeout(resolve, delay); });\n\n// -------------------------------------------------------------------------\n// DataCache tools\n\n/**\n * Given an object, return a new flat object of topic+value pairs, e.g.:\n```js\n{a: {b: 1, c: 2}, d: 3} \u2192 {'/a/b': 1, '/a/c': 2, '/d': 3}\n```\nNote: not idempotent!\n```js\n{'/a/b': 1, '/a/c': 2, d: 3} \u2192 {'%2Fa%2Fb': 1, '%2Fa%2Fc': 2, '/d': 3}\n```\n*/\nconst toFlatObject = (obj, prefix = [], rtv = {}) => {\n _.forEach(obj, (value, key) => {\n // const newPrefix = prefix.concat(topicToPath(String(key)));\n const newPrefix = prefix.concat(String(key));\n\n // TODO: using isPlainObject also means custom objects (classes) do not get\n // broken down.\n if ((_.isPlainObject(value) || value instanceof Array) && value !== null) {\n // it's an object or array\n toFlatObject(value, newPrefix, rtv);\n } else {\n // it's a primitive\n rtv[pathToTopic(newPrefix)] = value;\n }\n });\n return rtv;\n};\n\n/** Iterate through the object and invoke callback for each match of path (with\nnamed wildcards) */\nconst forMatchIterator = (obj, path, callback, pathSoFar = [], matchSoFar = {}) => {\n\n if (path.length == 0 || path[0] == '#') {\n callback(obj, pathSoFar, matchSoFar);\n return;\n }\n\n const next = path[0]; // don't use shift, we don't want to modify path\n if (next) {\n for (let key in obj) {\n if (key == next || next == '*' || next.startsWith('+')) {\n const match = next.startsWith('+') && next.length > 1 ?\n Object.assign({}, matchSoFar, {[next.slice(1)]: key}) :\n matchSoFar;\n forMatchIterator(obj[key], path.slice(1), callback,\n pathSoFar.concat([key]), match);\n }\n }\n }\n};\n\n/** Like _.set but without arrays. This allows using numbers as keys. */\nconst setFromPath = (obj, path, value) => {\n if (path.length == 0) return obj;\n const next = path.shift();\n if (path.length == 0) {\n obj[next] = value;\n } else {\n if (!obj[next]) obj[next] = {};\n setFromPath(obj[next], path, value);\n }\n};\n\nconst encodeTopicElement = x => x.replace(/%/g, '%25').replace(/\\//g, '%2F');\nconst decodeTopicElement = x => x.replace(/%25/g, '%').replace(/%2F/g, '/');\n\n/** convert a path array to mqtt topic; reduces +id identifiers to + */\nconst pathToTopic = (pathArray) => {\n /** reduce wildcards with Ids, such as `+sessionId`, to just + */\n const dropWildcardIds = (x) => x.startsWith('+') ? '+' : x;\n return `/${pathArray.map(dropWildcardIds).map(encodeTopicElement).join('/')}`;\n};\n\n/** convert topic to path array */\nconst topicToPath = (topic) => {\n // split topic by slashes, but not if they are escaped\n // const path = topic.match(/(\\\\.|[^/])+/g) || [];\n // split topic by slashes and unescape slashes in each item\n const path = topic.split('/').map(decodeTopicElement);\n // handle leading slash\n path.length > 0 && path[0].length == 0 && path.shift();\n // handle trailing slash\n path.length > 0 && path.at(-1).length == 0 && path.pop();\n return path;\n};\n\n/** match a slash-separated topic with a selector using +XYZ for (named)\n wildcards. Return the matching result.\n*/\nconst topicMatch = (selector, topic) => {\n const byArray = (s, p) => {\n if (s.length == 0) return true; // we are done: prefix matched\n if (s[0][0] == '#') return true; // explicit tail-wildcard\n // if (p.length < s.length) return false;\n if (p.length == 0) return true; // we are done, matched all\n // simple match:\n if (s[0] == p[0]) return byArray(s.slice(1), p.slice(1));\n // wild card match:\n if (s[0][0] == '+') {\n const sub = byArray(s.slice(1), p.slice(1));\n return sub && Object.assign({[s[0].slice(1)]: p[0]}, sub);\n }\n // else: failure!\n return false;\n };\n\n const selectorArray = topicToPath(selector);\n const pathArray = topicToPath(topic);\n // const selectorArray = selector.split('/');\n // const pathArray = topic.split('/');\n return byArray(selectorArray, pathArray);\n};\n\n/** sub is a strict sub-topic of parent, and in particular not equal */\nconst isSubTopicOf = (sub, parent) => {\n const pPath = topicToPath(parent);\n const sPath = topicToPath(sub);\n return isPrefixOf(pPath, sPath) && pPath.length < sPath.length;\n};\n\n/** prefixArray is a prefix of the array */\nconst isPrefixOf = (prefixArray, array) => {\n if (prefixArray.length == 0) return true;\n return (prefixArray[0] == array[0] &&\n isPrefixOf(prefixArray.slice(1), array.slice(1))\n );\n}\n\n\n// -------------------------------------------------------------------------\n// MQTT Tools\n\n/** parse usernames used in MQTT */\nconst parseMQTTUsername = (username) => {\n const parts = username.split(':');\n return {\n organization: parts[0],\n client: parts[1],\n sub: parts.slice(2)\n }\n};\n\n/** parse an MQTT topic according to our topic schema */\nconst parseMQTTTopic = (topic) => {\n const parts = topicToPath(topic);\n return {\n organization: parts[0],\n device: parts[1],\n capabilityScope: parts[2],\n capabilityName: parts[3],\n capability: `${parts[2]}/${parts[3]}`,\n version: parts[4],\n sub: parts.slice(5)\n }\n};\n\nconst mqttParsePayload = (payload) =>\n payload.length == 0 ? null : JSON.parse(payload.toString('utf-8'));\n// TODO: ^ This can probably now just become tryJSONParse\n\n/** delete all retained messages in a certain topic prefix, waiting for\n a given delay to collect existing retained. Use with care, never delete topics\n not owned by us. Harmless within capabilities, which are namespaced already.\n*/\nconst mqttClearRetained = (mqttClient, prefixes, callback, delay = 1000) => {\n\n const toDelete = [];\n const collectToDelete = (topic) => {\n // there may be other mqtt subscriptions running, filter by topic\n prefixes.forEach(prefix =>\n // mqttTopicMatch(topic, `${prefix}/#`) && toDelete.push(topic)\n topicMatch(`${prefix}/#`, topic) && toDelete.push(topic)\n );\n }\n mqttClient.on('message', collectToDelete);\n\n // subscribe to all\n prefixes.forEach(prefix => {\n if (typeof prefix == 'string') {\n mqttClient.subscribe(`${prefix}/#`);\n } else {\n console.warn('Ignoring', prefix, 'since it is not a string.');\n }\n });\n\n // value to use to clear, depending on node.js vs. browser\n const nullValue = (typeof Buffer != 'undefined' ? Buffer.alloc(0) : null);\n\n setTimeout(() => {\n mqttClient.removeListener('message', collectToDelete);\n prefixes.forEach(prefix => mqttClient.unsubscribe(`${prefix}/#`));\n\n const count = toDelete.length;\n console.log(`clearing ${count} retained messages from ${prefixes}`);\n toDelete.forEach(topic => {\n mqttClient.publish(topic, nullValue, {retain: true});\n });\n\n callback && callback(count);\n }, delay);\n};\n\n\n// WIP: a cleaner, more explicit way to serialize/deserialize mqtt payloads\n// /** Serialize a message for transport via MQTT */\n// const mqttSerialize = (message) => {\n// return value == null ? null : JSON.stringify(message);\n// };\n\n// /** Deserialize a message from MQTT */\n// const mqttDeserialize = (payload) => {\n// return payload.length == 0 ? null : JSON.parse(payload.toString('utf-8'));\n// };\n\n\n// -------------------------------------------------------------------------\n\n/** Generate a random id (base36) */\nconst getRandomId = (bytes = 6) => {\n const buffer = new Uint8Array(bytes);\n crypto.getRandomValues(buffer);\n return buffer.reduce((memo, i) => memo + i.toString(36), '');\n};\n\n/** Convert number to base52 [a-zA-Z] */\nconst toBase52 = (num) => {\n const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';\n const list = [];\n do {\n list.unshift(characters[num % 52]);\n num = Math.floor(num / 52);\n } while (num > 0);\n return list.join('');\n}\n\n/** Get a base52 representation [a-zA-Z] of the current date (ms since epoch) */\nconst getDateBase52 = () => toBase52(Date.now());\n\n// -------------------------------------------------------------------------\n\n/** Compare to version strings. Return -1 if a is lower than b,\n0 if they are equal, and 1 otherwise. If either is not a complete version,\ne.g., 2.0, interpret it as a range and use its minimum version for the\ncomparison. Hence, 2.0 < 2.0.1. */\nconst versionCompare = (a, b) =>\n semverCompare(semverMinVersion(a), semverMinVersion(b));\n\n// -------------------------------------------------------------------------\n\n/** given an object where the keys are versions, merge this into one object\n where the latest version of each subfield overwrites any previous */\nconst mergeVersions = (versionsObject, subTopic = undefined, options = {}) => {\n if (!versionsObject) {\n return subTopic ? _.set({}, subTopic, versionsObject) : versionsObject;\n }\n\n const versions = Object.keys(versionsObject).filter(ver =>\n (!options.maxVersion || versionCompare(ver, options.maxVersion) <= 0) &&\n (!options.minVersion || versionCompare(options.minVersion, ver) <= 0))\n .sort(versionCompare);\n\n const merged = {};\n const subPath = subTopic && topicToPath(subTopic);\n versions.forEach(nextVersion => {\n const newValue = subPath ? _.get(versionsObject[nextVersion], subPath) :\n versionsObject[nextVersion];\n // Object.assign(merged, newValue);\n _.merge(merged, newValue);\n });\n return subPath ? _.set({}, subPath, merged) : merged;\n};\n\n// -------------------------------------------------------------------------\n// Formatting tools\n\nconst units = ['B', 'KB', 'MB', 'GB', 'TB'];\nconst formatBytes = (bytes) => {\n if (!bytes) return '--';\n let i = 0;\n while (bytes > 1024) {\n bytes /= 1024;\n i++;\n }\n return `${bytes.toFixed(2)} ${units[i]}`;\n}\n\nconst formatDuration = (seconds) => {\n if (!seconds) return '--';\n const parts = {};\n if (seconds > 3600) {\n parts.h = Math.floor(seconds / 3600);\n seconds = seconds % 3600;\n }\n if (seconds > 60) {\n parts.m = Math.floor(seconds / 60);\n seconds = seconds % 60;\n }\n parts.s = Math.floor(seconds);\n\n let rtv = '';\n parts.h > 0 && (rtv += `${parts.h}h `);\n parts.m > 0 && (rtv += `${parts.m}m `);\n !parts.h && (rtv += `${parts.s}s`);\n return rtv.trim();\n};\n\n// -------------------------------------------------------------------------\n\nmodule.exports = { parseMQTTUsername, parseMQTTTopic,\n pathToTopic, topicToPath, toFlatObject, topicMatch,\n mqttParsePayload, getRandomId, toBase52, getDateBase52, versionCompare,\n loglevel, getLogger,\n mergeVersions, mqttClearRetained, isSubTopicOf, clone, setFromPath,\n forMatchIterator, encodeTopicElement, decodeTopicElement, constants, visit,\n wait, formatBytes, formatDuration, tryJSONParse,\n decodeJWT, visitAncestor\n};\n", "\nconst _ = {\n get: require('lodash/get'),\n set: require('lodash/set'),\n unset: require('lodash/unset'),\n forEach: require('lodash/forEach'),\n map: require('lodash/map'),\n isEmpty: require('lodash/isEmpty'),\n eq: require('lodash/isEqual'),\n isPlainObject: require('lodash/isPlainObject'),\n merge: require('lodash/merge'),\n};\n\nconst {topicToPath, pathToTopic, toFlatObject, topicMatch, forMatchIterator}\n = require('./common');\n\n/** Unset the topic in that obj, and clean up parent if empty, recursively.\nReturn the path to the removed node.\n*/\nconst unset = (obj, path) => {\n if (!path || path.length == 0) return;\n _.unset(obj, path);\n const parentPath = path.slice(0, -1);\n // _.get doesn't do the intuitive thing for the empty path, handle it ourselves\n const parent = parentPath.length == 0 ? obj : _.get(obj, parentPath);\n if (_.isEmpty(parent)) {\n return unset(obj, parentPath);\n } else {\n return path;\n }\n};\n\n/** Given a modifier `{\"a/b/c\": \"xyz\"}` update the object `obj` such that\n`obj.a.b.c = \"xyz\"`. */\nconst updateObject = (obj, modifier) => {\n _.forEach( modifier, (value, topic) => {\n const path = topicToPath(topic);\n if (value == null) {\n unset(obj, path);\n } else {\n _.set(obj, path, value);\n }\n });\n return obj;\n};\n\n/** Given an object and a path with wildcards (`*` and `+`), *modify* the object\nto only contain elements matched by the path, e.g.,\n`{a: {b: 1, c: 2}, d: 2}` and `['a','+']` would give `{a: {b: 1, c: 2}}`\n\n@param {object} obj - The object to select from\n@param {array} path - An array specifying the path to select, potentially\ncontaining mqtt wildcards ('+').\n*/\nconst selectFromObject = (obj, path) => {\n if (path.length == 0) return;\n const next = path[0];\n if (next) {\n for (let key in obj) {\n if (key != next && next != '*' && !next.startsWith('+')) {\n delete obj[key];\n } else {\n selectFromObject(obj[key], path.slice(1));\n }\n }\n }\n};\n\n\n/**\n* A class implementing a local data cache, used as a local data store with\n* deduplication detection and update events. While this class is very handy\n* you probably won't need to create instances of it directly. Instead use\n* the mqttSync.data instance which holds the locally stored data\n* subscribed/published from/to MQTTSync.\n* For example on the robot:\n* ```js\n* // update/publish our status:\n* mqttSync.data.update('status', {changed: Date.now(), msg: 'OK'});\n* // subscribe to new user requests (e.g., from UI):\n* mqttSync.data.subscribePath('+user/request', (request, key, {user}) => {\n* log.debug(`user ${user} made request`, request);\n* });\n* ```\n* In the cloud or in a web component you would need to use the full topic including\n* org, device, scope, cap-name, and version.\n*/\nclass DataCache {\n\n #data = {};\n #listeners = [];\n #flatListeners = [];\n\n constructor(data = {}) {\n this.#data = data;\n }\n\n /** Update the object with the given value at the given path, remove empty;\n return the flat changes (see toFlatObject). Add `tags` to updates to mark\n them somehow based on the context, e.g., so that some subscriptions can choose\n to ignore updates with a certain tag.\n */\n updateFromArray(path, value, tags = {}) {\n // const empty = Object.keys(this.#data).length == 0; // object already empty\n const current = _.get(this.#data, path);\n if (value == null) {\n if (current === undefined || current === null) {\n return {}; // no change, do not call listeners\n } else {\n unset(this.#data, path);\n }\n } else {\n if (_.eq(current, value)) {\n // note: this is just a shallow equal, so replacing a sub-document\n // with an atomic copy of it should still trigger listeners.\n // TODO: Note also that when value is an object, we will set it by\n // reference here, so any changes made to that object will *not* trigger\n // listeners because `current` will already be changed -- which is\n // probably wrong. May want to always clone value first.\n return {}; // nothing to do, do not bother listeners\n }\n // console.log('setting', path, value);\n _.set(this.#data, path, value);\n // TODO: implement this ourselves so we can do better change-checking\n }\n\n const topic = pathToTopic(path);\n const obj = {[topic]: value};\n\n // flatten the value and combine eith topic (without reflattening the topic):\n let flatChanges;\n if (value instanceof Object) {\n const flatValue = toFlatObject(value);\n flatChanges = {};\n _.forEach(flatValue, (atomic, flatKey) => {\n flatChanges[`${topic}${flatKey}`] = atomic;\n });\n } else {\n flatChanges = obj;\n }\n\n // option 1. using flat changes (sub-documents are never atomic)\n // this.#listeners.forEach(fn => fn(flatChanges));\n\n // option 2. allow atomic sub-document changes\n this.#listeners.forEach(fn => fn(obj, tags));\n\n this.#flatListeners.forEach(fn => fn(flatChanges, tags));\n\n return flatChanges;\n }\n\n /** Update the value at the given path (array or dot separated string) */\n update(path, value, tags) {\n if (typeof path == 'string') {\n return this.updateFromTopic(path, value, tags);\n } else if (path instanceof Array) {\n return this.updateFromArray(path, value, tags);\n } else {\n throw new Error('unrecognized path expression');\n }\n }\n\n /** Set value from the given topic (with or without leading or trailing slash) */\n updateFromTopic(topic, value, tags) {\n return this.updateFromArray(topicToPath(topic), value, tags);\n }\n\n /** Update data from a modifier object where keys are topic names to be\n interpreted as paths, and values are the values to set */\n updateFromModifier(modifier, tags) {\n return _.map(modifier, (value, topic) =>\n this.updateFromTopic(topic, value, tags));\n }\n\n /** Add a callback for all change events. */\n subscribe(callback) {\n if (callback instanceof Function) {\n this.#listeners.push(callback);\n } else {\n console.warn('DataCache.subscribe expects a function as argument. Did you mean to use subscribePath?');\n }\n }\n\n /** Subscribe to a specific topic only. Callback receives\n `value, key, matched, tags`. TODO: rename to subscribeTopic. */\n subscribePath(topic, callback) {\n this.#listeners.push((changes, tags) => {\n _.forEach(changes, (value, key) => {\n const matched = topicMatch(topic, key);\n matched && callback(value, key, matched, tags);\n });\n });\n }\n\n /** Same as subscribePath but always get all changes in flat form */\n subscribePathFlat(topic, callback) {\n this.#flatListeners.push((changes, tags) => {\n _.forEach(changes, (value, key) => {\n const matched = topicMatch(topic, key);\n matched && callback(value, key, matched, tags);\n });\n });\n }\n\n /** Remove a callback previously registered using `subscribe`. */\n unsubscribe(callback) {\n this.#listeners = this.#listeners.filter(f => f != callback);\n }\n\n /** Get sub-value at path, or entire object if none given */\n get(path = []) {\n return path.length == 0 ? this.#data : _.get(this.#data, path);\n }\n\n /** Get sub-value specified by topic */\n getByTopic(topic) {\n return this.get(topicToPath(topic));\n }\n\n /** Filter the object using path with wildcards */\n filter(path) {\n const rtv = JSON.parse(JSON.stringify(this.get()));\n selectFromObject(rtv, path);\n return rtv;\n }\n\n /** Filter the object using topic with wildcards */\n filterByTopic(topic) {\n return this.filter(topicToPath(topic));\n }\n\n /** For each topic match, invoke the callback with the value, path, and match\n just like subscribePath, but on the current data rather than future changes. */\n forMatch(topic, callback) {\n const path = topicToPath(topic);\n this.forPathMatch(path, callback);\n }\n\n /** For each path match, invoke the callback with the value, path, and match\n just like subscribePath */\n forPathMatch(path, callback) {\n forMatchIterator(this.get(), path, callback);\n }\n};\n\nmodule.exports = {\n DataCache, updateObject\n}", "'use strict';\n\nconst _ = require('lodash');\n\nconst { mqttParsePayload, topicMatch, topicToPath, pathToTopic,\ntoFlatObject, getLogger, mergeVersions, parseMQTTTopic, isSubTopicOf,\nversionCompare, encodeTopicElement, visitAncestor, getRandomId }\n = require('./common');\nconst { DataCache } = require('./DataCache');\n\n\nconst log = getLogger('MqttSync');\nlog.setLevel('info');\n\nconst HEARTBEAT_TOPIC = '$SYS/broker/uptime';\nconst specialKey = '$_'; // special key to reify \"value\" in publishedMessages\n\nconst noop = () => {};\n\n/* clone a mqtt payload, if necessary */\nconst clone = (payload) => {\n if (typeof payload == 'object') {\n return JSON.parse(JSON.stringify(payload));\n } else {\n return payload;\n }\n};\n\n/* return new string that ends in /# for sure */\nconst ensureHashSuffix = (topic) =>\n topic.endsWith('/#') ? topic :\n ( topic.endsWith('/') ? topic.concat('#') :\n topic.concat('/#') );\n\n/* given a path, replace any double slashes, '//', with single ones */\nconst resolveDoubleSlashes = (path) => path.replace(/\\/\\//g, '/');\n\n\n/** A class that combines DataCache and MQTT to implement a data synchronization\nfeature over the latter. Relies on retained messages in mqtt for persistence.\n* @param {object} options\n* @param {object} options.mqttClient - An already connected mqtt.js client.\n* @param {boolean} [options.ignoreRetain] - retain all messages, ignorant of the retain\n* flag.\n* @param {number} [options.sliceTopic] - a number indicating at what level to\n* slice the topic, i.e., only use a suffix. Used in robot-capabilities to slice\noff the topic prefix (namespaces).\n* @param {array} [options.migrate] - an array of objects of the form\n* `{topic, newVersion, level}`. Only meaningful in the cloud. Instructs MQTTSync\nto first migrate existing topics to a new version namespace, publishing at the\ndesignated level down from the version level. For example:\n```js\n[{ topic: `/myorg/mydevice/@local/my-cap/+/config`,\n newVersion: this.version,\n level: 1\n}]\n```\nWould migrate any existing data in the capability's `config` namespace to the\ncurrent version of the package, publishing at the `config/+` level (rather than\natomically at the config level itself).\n* @param {function} [options.onReady] - A function that is called when the MQTTSync\nclient is ready and has completed any requested migrations.\n* @param {function} [options.onChange] - A function that is called any time there\nis a change to the shared data. This is not usually used. It's usually better to\nuse the finer grained `MqttSync.data.subscribePath` instead, that allows you to\nsubscribe to changes just on a specific sun-object instead, see DataCache.\n*/\nclass MqttSync {\n\n data = new DataCache();\n\n /* Directory of paths we've subscribed to in this class; this matters\n because the same mqtt client may have subscriptions to paths that we don't\n care to store (sync). */\n subscribedPaths = {};\n\n publishedPaths = {}; // not used in atomic mode\n\n /* Store messages retained on mqtt so we can publish what is necessary to\n achieve the \"should-be\" state. Note that we cannot use a structured document\n for storing these publishedMessages since we need to be able to store separate\n values at non-leaf nodes in the object (just like mqtt, where you can have\n /a/b = 1 and /a/b/c = 1 at the same time). Note: not used in atomic mode.\n Note: we use specialKey in this DataCache to allow overlapping\n topics (e.g., `/a/b/$_ = 1` and `/a/$_ = {b: 2}`)\n */\n publishedMessages = new DataCache();\n\n /* The order in which we send retained messages matters, which is why we use\n a queue for sending things. Note that we here use the property of Map that it\n remembers insertion order of keys. */\n publishQueue = new Map();\n\n /* We need to keep a record of all received topics (not messages) so far in\n case we want to clear any of them. */\n receivedTopics = new Set();\n\n /* List of callbacks waiting for next heartbeat, gets purged with each\n heartbeat */\n heartbeatWaitersOnce = [];\n\n heartbeats = 0;\n\n beforeDisconnectHooks = [];\n\n rpcHandlers = {}; // handlers for incoming RPC requests\n rpcCallbacks = {}; // callback for RPC requests we've sent\n\n constructor({mqttClient, onChange, ignoreRetain, migrate, onReady,\n sliceTopic, onHeartbeatGranted }) {\n\n this.mqtt = mqttClient;\n this.sliceTopic = sliceTopic;\n\n this.mqtt.on('message', (topic, payload, packet) => {\n const payloadString = payload && payload.toString()\n // log.debug('got message', topic, payloadString.slice(0, 180),\n // payloadString.length > 180 ? `... (${payloadString.length} bytes)` : '',\n // packet.retain);\n\n if (topic == HEARTBEAT_TOPIC) {\n if (this.heartbeats > 0) { // ignore initial heartbeat (retained)\n this.heartbeatWaitersOnce.forEach(cb => cb());\n this.heartbeatWaitersOnce = [];\n }\n if (this.heartbeats == 1 && !migrate && onReady) onReady();\n this.heartbeats++;\n\n } else {\n this.receivedTopics.add(topic);\n // Do NOT parse payload just yet, since it may be binary and ignored by us\n\n let path = topicToPath(topic);\n log.debug('processing message', topic, path);\n if (sliceTopic) {\n path = path.slice(sliceTopic);\n topic = pathToTopic(path);\n }\n\n if (this.rpcHandlers[topic]) {\n const json = mqttParsePayload(payload);\n this.handleRPCRequest(topic, json);\n\n } else if (this.rpcCallbacks[topic]) {\n const json = mqttParsePayload(payload);\n this.handleRPCResponse(topic, json);\n\n } else if (packet.retain || ignoreRetain) {\n\n if (this.isPublished(topic)) {\n const json = mqttParsePayload(payload);\n // store plain messages, still stored in a structure, but values are\n // not interpreted; we just store them to undo them if necessary, e.g.,\n // for switching between atomic and non-atomic subdocuments\n // log.trace('setting publishedMessages', topic);\n this.publishedMessages.updateFromArray([...path, specialKey], json);\n\n // this.pubData.update(topic, json);\n // Still need to update the data so that we can detect changes we make\n // and publish them. But we need to break the reaction-chain to avoid\n // loops, so tag this update with 'published' and then ignore those\n // updates in this.publish.\n this.data.update(topic, json, {external: true});\n\n } else if (this.isSubscribed(topic)) {\n const json = mqttParsePayload(payload);\n\n log.debug('applying received update', topic);\n const changes = this.data.update(topic, json);\n onChange && Object.keys(changes).length > 0 && onChange(changes);\n }\n }\n // else: do not try to parse it, it might be a binary message sent\n // directly using the client (with or without retain)\n }\n });\n\n this.mqtt.subscribe(HEARTBEAT_TOPIC, {rap: true}, (err, granted) => {\n log.debug(HEARTBEAT_TOPIC, {granted});\n granted && granted.length > 0 && onHeartbeatGranted?.();\n });\n\n migrate?.length > 0 && this.migrate(migrate, () => {\n log.debug('done migrating');\n onReady && this.waitForHeartbeatOnce(onReady);\n });\n }\n\n /**\n * Publish all values at the given level of the given object under the given\n * topic (plus sub-key, of course).\n * TODO: Is this OK, or do we need to go through this.publish?\n */\n publishAtLevel(topic, value, level) {\n log.debug(`publishingAtLevel ${level}`, topic, value);\n\n if (level > 0) {\n _.forEach(value, (subValue, subKey) => {\n const subTopic = `${topic}/${encodeTopicElement(subKey)}`;\n log.debug(`publishing ${subTopic}`);\n this.publishAtLevel(subTopic, subValue, level - 1);\n });\n } else {\n this.mqtt.publish(topic, JSON.stringify(value), {retain: true}, (err) => {\n err && log.warn('Error when publishing migration result', err);\n });\n }\n }\n\n /** Migrate a list of `{topic, newVersion, transform}`. The version number in\n * topic will be ignored, and all versions' values will be merged, applied in\n * order, such that the latest version is applied last. `topic` may include\n * wildcards in the part before the version number but not after.\n *\n * Example:\n * ```js\n * mqttSync.migrate([{topic: '/+/dId/@scope/capname/+/b', newVersion: '1.2.0'}]\n * ```\n */\n migrate(list, onReady = undefined) {\n\n let toGo = list.length;\n if (toGo == 0) {\n onReady && onReady(); // in case an empty list was given\n return;\n }\n\n /* called each time one item is done */\n const oneDown = () => --toGo == 0 && onReady && onReady();\n\n list.forEach(({topic, newVersion, transform = undefined, flat = false,\n level = 0}) => {\n log.debug('migrating', topic, newVersion);\n const {organization, device, capability, sub} = parseMQTTTopic(topic);\n const prefix = `/${organization}/${device}/${capability}`;\n\n const suffix = sub.length == 0 ? '/#' : pathToTopic(sub);\n // suffix will have a leading slash\n const subTopic = `${prefix}/+${suffix}`;\n\n this.subscribe(subTopic, (err) => {\n if (err) {\n log.warn('Error during migration', err);\n oneDown();\n return;\n }\n\n const all = {};\n this.waitForHeartbeatOnce(() => {\n\n // for each match (prefix can include wildcards) merge everything\n this.data.forMatch(prefix, (value, path, match) => {\n // an actual (ground, aka. no wildcard) prefix\n const groundPrefix = pathToTopic(path);\n\n log.debug('got heartbeat', {prefix, topic, subTopic, suffix}, groundPrefix, value);\n if (!value) {\n // no data to migrate\n return;\n }\n // collect for cleanup\n Object.assign(all, value);\n\n const merged = mergeVersions(value, suffix, {maxVersion: newVersion});\n // get suffix in merged\n const suffixMergedValue = _.get(merged, topicToPath(suffix));\n log.debug({value, suffix, merged, suffixMergedValue});\n // ^ this will need to change to support wild-cards in suffix\n const transformed = transform ? transform(suffixMergedValue) :\n suffixMergedValue;\n\n // Publish the transformed value under the ground prefix as\n // `newVersion/suffix`\n const newTopic =\n resolveDoubleSlashes(`${groundPrefix}/${newVersion}/${suffix}`);\n log.debug('publishing merged', newTopic);\n\n if (flat) {\n const flatObj = toFlatObject(transformed);\n const newPath = topicToPath(newTopic);\n _.forEach(flatObj, (value, key) => {\n const keyTopic = pathToTopic(newPath.concat(topicToPath(key)));\n // TODO: Is this OK, or do we need to go through this.publish?\n this.mqtt.publish(keyTopic, JSON.stringify(value),\n {retain: true}, (err) => {\n err && log.warn(\n `Error when publishing migration result for ${key}`, err);\n });\n });\n\n } else {\n this.publishAtLevel(newTopic, transformed, level);\n }\n });\n\n this.unsubscribe(subTopic);\n\n if (Object.keys(all).length == 0) {\n // no data to migrate\n oneDown();\n return;\n }\n\n this.waitForHeartbeatOnce(() => {\n // now clear this suffix in the old version space\n const oldVersions = Object.keys(all).filter(v =>\n versionCompare(v, newVersion) < 0);\n // log.debug({oldVersions});\n\n const prefixesToClear = oldVersions.map(oldV =>\n resolveDoubleSlashes(`${prefix}/${oldV}/${suffix}`));\n\n this.clear(prefixesToClear);\n oneDown();\n });\n });\n });\n });\n }\n\n /** Delete all retained messages in a certain topic prefix, waiting for\n a mqtt broker heartbeat to collect existing retained. Use with care, never\n delete topics not owned by us. Harmless within capabilities, which are\n namespaced already.\n\n `options.filter(topic)`: a function that can be provided to further,\n programmatically filter the set of topics to clear, e.g., to onlt clear\n topics of old versions.\n\n Note: This may not yet work in robot-capabilities, since the subscription\n prefix and received topic prefix don't match (the device prefix is added to\n subscription by localMQTT.\n */\n clear(prefixes, callback = undefined, options = {}) {\n\n const toDelete = [];\n const collectToDelete = (topic) => {\n // there may be other mqtt subscriptions running, filter by topic\n prefixes.forEach(prefix =>\n topicMatch(`${prefix}/#`, topic)\n && (!options.filter || options.filter(topic))\n && toDelete.push(topic)\n );\n }\n this.mqtt.on('message', collectToDelete);\n // this only collects new topics, not those we've already received\n\n // subscribe to all\n prefixes.forEach(prefix => {\n if (typeof prefix == 'string') {\n this.mqtt.subscribe(`${prefix}/#`);\n } else {\n log.warn('Ignoring', prefix, 'since it is not a string.');\n }\n // add the topics we already know off:\n this.receivedTopics.forEach(topic => {\n if (topic.startsWith(prefix)) {\n log.debug('marking for deletion', `${prefix}${topic}`);\n toDelete.push(topic);\n }\n });\n });\n\n // value to use to clear, depending on node.js vs. browser\n const nullValue = (typeof Buffer != 'undefined' ? Buffer.alloc(0) : null);\n\n this.waitForHeartbeatOnce(() => {\n this.mqtt.removeListener('message', collectToDelete);\n prefixes.forEach(prefix => this.mqtt.unsubscribe(prefix));\n\n const count = toDelete.length;\n log.info(`clearing ${count} retained messages from ${prefixes}`);\n toDelete.forEach(topic => {\n this.mqtt.publish(topic, nullValue, {retain: true});\n });\n\n callback && callback(count);\n });\n };\n\n\n /** register a callback for the next heartbeat from the broker */\n waitForHeartbeatOnce(callback) {\n // need to wait a tick, in case we are still in the callback tree\n // of a previous heartbeat waiter\n setTimeout(() => this.heartbeatWaitersOnce.push(callback), 1);\n }\n\n /** check whether we are subscribed to the given topic */\n isSubscribed(topic) {\n return Object.keys(this.subscribedPaths).some(subscribedTopic =>\n topicMatch(subscribedTopic, topic));\n }\n\n /** Check whether we are publishing the given topic in a non-atomic way.\n This is used to determine whether to store the published value or not. */\n isPublished(topic) {\n return Object.keys(this.publishedPaths).some(subscribedTopic =>\n topicMatch(subscribedTopic, topic) &&\n !this.publishedPaths[subscribedTopic].atomic\n );\n }\n\n /** Subscribe to the given topic (and all sub-topics). The callback will\n indicate success/failure, *not* a message on the topic. */\n subscribe(topic, callback = noop) {\n topic = ensureHashSuffix(topic);\n log.debug('subscribing to', topic);\n if (this.subscribedPaths[topic]) {\n log.debug('already subscribed to', topic);\n callback();\n return;\n }\n\n this.mqtt.subscribe(topic, {rap: true}, (err, granted) => {\n log.debug('subscribe', topic, 'granted:', granted);\n if (granted && granted.some(grant => grant.topic == topic && grant.qos < 128)) {\n // granted\n this.subscribedPaths[topic] = 1;\n callback(null);\n } else {\n // let user know (somehow) when we don't get permission\n callback(`not permitted to subscribe to topic ${topic}, ${JSON.stringify(granted)}`);\n }\n });\n }\n\n unsubscribe(topic) {\n topic = ensureHashSuffix(topic);\n if (this.subscribedPaths[topic]) {\n this.mqtt.unsubscribe(topic);\n delete this.subscribedPaths[topic];\n }\n }\n\n /** Publish retained to MQTT, store as published, and return a promise */\n _actuallyPublish(topic, value) {\n // return new Promise((resolve, reject) =>\n // this.mqtt.publish(topic,\n // value == null ? null : JSON.stringify(value), // aka \"unparse payload\"\n // {retain: true},\n // (err) => {\n // // Note that this returns optimistically at QoS 0, and no error occurs\n // // even when we are not allowed to publish this topic/message, see\n // // https://github.com/mqttjs/MQTT.js/#publish. Only when the client\n // // disconnects it seems.\n // if (err) {\n // log.warn('error in _actuallyPublish:', err);\n // reject(err);\n // // TODO: if this happens, we may need to force a full-sync\n // } else {\n // resolve();\n // }\n // }));\n\n if (!this.mqtt.connected) {\n log.warn('not connected, not publishing', topic);\n return false;\n }\n log.debug('actually publishing', topic);\n this.mqtt.publish(topic,\n value == null ? null : JSON.stringify(value), // aka \"unparse payload\"\n {retain: true});\n return true;\n }\n\n /** Send all items in the queue in sequence, if any and if not already\n running. */\n // async _processQueue() {\n // if (this._processing) return; // already running (and probably waiting)\n //\n // this._processing = true;\n // while (this.publishQueue.length > 0) {\n // const {topic, value} = this.publishQueue.shift();\n // await this._actuallyPublish(topic, value);\n // }\n // this._processing = false;\n // }\n\n // when using Map\n _processQueue_rec(cb) {\n if (this.publishQueue.size > 0) {\n const [topic, value] = this.publishQueue.entries().next().value;\n // this.publishQueue.delete(topic);\n // this._actuallyPublish(topic, value).then(\n // () => this._processQueue_rec(cb),\n // cb); // always call cb, even in rejection case\n if (this._actuallyPublish(topic, value)) {\n this.publishQueue.delete(topic);\n this._processQueue_rec(cb);\n } else {\n // try again soon\n setTimeout(() => this._processQueue_rec(cb), 5000);\n }\n } else {\n cb();\n }\n }\n\n _processQueue() {\n if (this._processing) return; // already running (and probably waiting)\n\n this._processing = true; // semaphore\n this._processQueue_rec(() => this._processing = false);\n }\n\n /** Set delay between processing of publishing queue in milliseconds. This\n allows you to effectively throttle the rate at which this instance will\n publish changes. Note that updates to a topic already in the queue will not\n cause multiple publications. Only the latest value will be published.\n @param {number} [delay] - Number of milliseconds to wait between processing\n of publish queue.\n */\n setThrottle(delay) {\n this._processQueueThrottled =\n _.throttle(this._processQueue.bind(this), delay);\n }\n\n /** Clear the set throttling delay. */\n clearThrottle() {\n delete this._processQueueThrottled;\n }\n\n addToQueue(topic, value) {\n // this.publishQueue.push({topic, value});\n this.publishQueue.set(topic, value);\n }\n\n /** Add to publication queue */\n _enqueue(topic, value) {\n log.debug('enqueuing', topic);\n this.addToQueue(topic, value);\n if (this._processQueueThrottled) {\n this._processQueueThrottled();\n } else {\n this._processQueue();\n }\n // yes, this is optimistic, but if we don't, then upcoming changes\n // may not work as expected (e.g., when switching from flat to atomic to flat)\n const path = topicToPath(topic);\n this.publishedMessages.updateFromArray([...path, specialKey],\n value == null ? null : clone(value));\n }\n\n /** Register a listener for path in data. Make sure to populate the data\n before calling this or set the data all at once afterwards.\n\n With option \"atomic\" this will always send the whole sub-document,\n not flat changes. Useful, e.g., for desiredPackages, see\n https://github.com/chfritz/transitive/issues/85.\n\n @return true if publication added (false, e.g., when already present)\n */\n publish(topic, options = {atomic: false}) {\n topic = ensureHashSuffix(topic);\n\n if (_.isEqual(this.publishedPaths[topic], options)) {\n return false;\n // avoid double subscription\n }\n this.publishedPaths[topic] = options;\n\n if (options.atomic) {\n // this case is quite simple\n this.data.subscribePath(topic, (value, key, matched, tags) => {\n // do not re-publish changes received from external:\n if (tags?.external) return;\n\n log.debug('processing change (atomic)', key, topic);\n // instantiate topic according to key (topic may have wildcards)\n const topicWithoutHash = topic.slice(0, topic.length - 2);\n const groundedTopic = pathToTopic(\n // get length of topic (how many levels of selectors), get that many\n // levels from key prefix\n topicToPath(key).slice(0, topicToPath(topicWithoutHash).length)\n );\n this._enqueue(groundedTopic, this.data.getByTopic(groundedTopic));\n });\n return true;\n }\n\n this.mqtt.subscribe(topic);\n\n // second: keep them up to date by publishing updates as changes happen\n this.data.subscribePath(topic, (value, key, matched, tags) => {\n if (tags?.external) return;\n\n log.debug('processing change', key);\n\n /* First: establish clarity by ensuring that the object defined by the\n currently present retained messages under this path accurately reflect\n the current value of this.data (and if not, publish what is necessary to\n create consistency). */\n // first, clear/replace all messages below or above this sub-path (if any)\n const path = topicToPath(key);\n\n // Check flat to atomic\n const publishedSub = this.publishedMessages.get(path);\n _.each(publishedSub, (oldSubVal, oldSubKey) => {\n if (oldSubKey == specialKey) return true;\n // We are going from flat to atomic, i.e., we are publishing at a\n // higher level than before: clear out old sub-keys.\n\n // Find all sub-sub-keys that end in `specialKey`:\n const toClear = Object.keys(toFlatObject(oldSubVal))\n .filter(subkey => subkey.endsWith(specialKey));\n\n log.debug('flat->atomic: ', {toClear}, oldSubKey);\n // Clear them all:\n toClear.forEach(oldSubSubKey => {\n const oldKey = oldSubSubKey.slice(0, -(specialKey.length + 1));\n const clearKey = `${key}/${oldSubKey}/${oldKey}`\n // log.debug('flat->atomic: clear', clearKey);\n this._enqueue(clearKey, null);\n });\n });\n\n // Check atomic to flat\n const published = this.publishedMessages.get();\n visitAncestor(published, path.slice(0, -1), (subObj, prefix) => {\n const oldVal = subObj[specialKey];\n if (oldVal && _.isObject(oldVal)) {\n log.debug('atomic->flat', {oldVal});\n // A parent topic has been published. We are going from atomic to\n // separate values: need to transform existing sub-document to flat\n // values.\n\n // Remove the old published (atomic) message:\n const prefixTopic = pathToTopic(prefix);\n this._enqueue(prefixTopic, null);\n\n // Now re-add as separate flat messages\n const flat = toFlatObject(oldVal);\n _.each(flat, (flatValue, flatKey) => {\n const oldFlatKey = `${prefixTopic}${flatKey}`;\n this._enqueue(oldFlatKey, flatValue);\n })\n }\n });\n\n /* We need to first wait until all of the above messages are out;\n otherwise replacing an atomic `/a = {c: 1}` with `/a/c = 2` would create\n a race condition where it is not clear which message, the replacement\n c = 1 or the new c = 2, would be sent last (and hence retained). That's\n why we use a publishing queue in this class.\n */\n this._enqueue(key, value);\n return true;\n });\n }\n\n /** Run all registered hooks before disconnecting */\n beforeDisconnect() {\n this.beforeDisconnectHooks.forEach(fn => fn(this));\n }\n\n /** Register a new hook to be called before disconnecting */\n onBeforeDisconnect(fn) {\n this.beforeDisconnectHooks.push(fn);\n }\n\n /* --------------------------------------------------------------------------\n * Remote Procedure Calls (RPC)\n */\n\n /* Handle RPC requests */\n async handleRPCRequest(topic, json) {\n log.debug('handling RPC request for', topic, json);\n const handler = this.rpcHandlers[topic];\n const result = handler(json.args);\n\n const responseTopic = `${topic.replace('/request', '/response')}/${json.id}`;\n\n if (result instanceof Promise) {\n result.then( resultValue => this.mqtt.publish(responseTopic,\n JSON.stringify({ id: json.id, result: resultValue }),\n {retain: false, qos: 2}));\n } else {\n this.mqtt.publish(responseTopic,\n JSON.stringify({ id: json.id, result }),\n {retain: false, qos: 2});\n }\n }\n\n /* Handle RPC response */\n handleRPCResponse(topic, json) {\n log.debug('handle RPC response', topic, json);\n this.rpcCallbacks[topic](json.result);\n delete this.rpcCallbacks[topic];\n this.mqtt.unsubscribe(topic);\n }\n\n /** Register an RPC request handler. Example:\n * ```js\n * mqttSync.register('/mySquare', arg => {\n * log.debug('running /mySquare with args', arg);\n * return arg * arg;\n * });\n * ```\n * Note that the command topic needs to be in the capabilities namespace like\n * any other topic. In robot capabilities, as usual, these can start in `/`\n * because the local mqtt bridge operated by the robot agent will place all\n * topics in their respective namespace. In the cloud and on the web you will\n * need to use the respective namespace, i.e.,\n * `/orgId/deviceId/@scope/capName/capVersion/`.\n *\n * #### Async/Await\n * Yes, you can make the handler `async` and use `await` inside of it. This\n * will be handled correctly, i.e., MqttSync will await the result of the\n * handler before responding to the RPC request client.\n */\n register(command, handler) {\n log.debug('registering RPC handler for', command);\n const requestTopic = `${command}/request`;\n\n this.rpcHandlers[requestTopic] = handler;\n this.mqtt.subscribe(requestTopic, {rap: true, qos: 2}, (err, granted) => {\n if (err) {\n log.warn(`Error subscribing to RPC topic ${requestTopic}`, err);\n } else if (granted && granted.length == 0) {\n log.warn(`Not allowed to subscribe to RPC topic ${requestTopic}`);\n }\n });\n }\n\n /** Make an RPC request. Example:\n * ```js\n * mqttSync.call('/mySquare', 11, result => {\n * log.debug(`Called /mySquare with arg 11 and got ${result}`);\n * });\n * ```\n * Alternative you can omit the callback and use async/await:\n * ```js\n * const result = await mqttSync.call('/mySquare', 11);\n * log.debug(`Called /mySquare with arg 11 and got ${result}`);\n * ```\n * See the note about namespaces in `register`.\n *\n * Note: It is your responsibility to only call methods that exist (have been\n * registered). Calling a non-existent command just hangs.\n */\n call(command, args, callback = undefined) {\n const id = getRandomId();\n\n const responseTopic = `${command}/response/${id}`;\n this.mqtt.subscribe(responseTopic, {rap: true, qos: 2}, (err, granted) => {\n if (err) {\n log.warn(`Error subscribing to RPC response topic ${responseTopic}`, err);\n } else if (granted && granted.length == 0) {\n log.warn(`Not allowed to subscribe to RPC response topic ${responseTopic}`);\n }\n });\n\n const requestTopic = `${command}/request`\n log.debug('calling RPC', requestTopic);\n this.mqtt.publish(requestTopic, JSON.stringify({ id, args }),\n {retain: false, qos: 2});\n\n if (callback) {\n this.rpcCallbacks[responseTopic] = callback;\n } else {\n return new Promise((resolve, reject) => {\n this.rpcCallbacks[responseTopic] = resolve;\n });\n }\n }\n}\n\nmodule.exports = MqttSync;\n", "export * from './client/shared.jsx';\nexport * from './client/hooks.jsx';\nexport * from './client/client';\n", "import React, { useState, useEffect, useMemo, useRef } from 'react';\nimport { Button, Accordion, AccordionContext, Card, Badge }\n from 'react-bootstrap';\nimport ReactWebComponent from './react-web-component';\n\nimport { parseCookie, decodeJWT } from './client';\nimport { useCapability } from './hooks';\n\nconst styles = {\n badge: {\n width: '4em'\n },\n code: {\n color: '#700',\n borderLeft: '3px solid #aaa',\n padding: '0.5em 0px 0.5em 2em',\n backgroundColor: '#f0f0f0',\n borderRadius: '4px',\n marginTop: '0.5em',\n },\n inlineCode: {\n color: '#700',\n margin: '0px 0.5em 0px 0.5em',\n }\n};\n\nconst levelBadges = [\n <Badge bg=\"success\" style={styles.badge}>OK</Badge>,\n <Badge bg=\"warning\" style={styles.badge}>Warn</Badge>,\n <Badge bg=\"danger\" style={styles.badge}>Error</Badge>,\n <Badge bg=\"secondary\" style={styles.badge}>Stale</Badge>,\n];\n\n/* The right badge for the level */\nexport const LevelBadge = ({level}) => levelBadges[level] || <span>{level}</span>;\n\n/** Reusable component for showing code */\nexport const Code = ({children}) => <pre style={styles.code}>\n {children}\n</pre>;\n\nexport const InlineCode = ({children}) => <tt style={styles.inlineCode}>\n {children}\n</tt>;\n\n\nconst intervals = {};\n\nexport const TimerContext = React.createContext({});\nexport const Timer = ({duration, onTimeout, onStart, setOnDisconnect, children}) => {\n duration = duration || 60;\n const [timer, setTimer] = useState(duration);\n const [running, setRunning] = useState(false);\n const id = useMemo(() => Math.random().toString(36).slice(2), []);\n\n const stop = () => {\n console.log('stopping timer for', id);\n onTimeout && setTimeout(onTimeout, 1);\n clearInterval(intervals[id]);\n intervals[id] = null;\n setRunning(false);\n };\n\n const startTimer = () => {\n const interval = intervals[id];\n console.log(interval, intervals, timer);\n if (!interval && timer > 0) {\n setRunning(true);\n intervals[id] = setInterval(() =>\n setTimer(t => {\n if (--t > 0) {\n return t;\n } else {\n stop();\n }\n }), 1000);\n onStart && setTimeout(onStart, 1);\n }\n\n return stop;\n };\n\n useEffect(() => { timer > 0 && !running && startTimer() }, [timer]);\n\n useEffect(() => stop, []);\n\n setOnDisconnect && setOnDisconnect(() => {\n // call on disconnect of the web component\n stop()\n });\n\n const reset = () => setTimer(duration);\n\n return <TimerContext.Provider value={{reset, duration, timer}}>\n {timer > 0 ? <div>\n {children}\n {timer < 60 && <div>Timeout in: {timer} seconds</div>}\n </div> :\n <div>Timed out. <Button onClick={reset}>\n Resume\n </Button>\n </div>}\n </TimerContext.Provider>;\n};\n\n\n/** Dynamically load and use the Transitive web component specified in the JWT.\n* Embedding Transitive components this way also enables the use of functional\n* and object properties, which get lost when using the custom element (Web\n* Component) because HTML attributes are strings.\n* Example:\n* ```jsx\n* <TransitiveCapability jwt={jwt}\n* myconfig={{a: 1, b: 2}}\n* onData={(data) => setData(data)}\n* onclick={() => { console.log('custom click handler'); }}\n* />\n* ```\n*\n* Always loads the capability specified in the JWT and will default to the\n* main component for that JWT (`-device` or `-fleet`). To specify a secondary\n* component offered by the capability specify `component`, e.g., to load\n* `webrtc-video-supervisor` instead of `webrtc-video-device`, provide a device\n* JWT for webrtc-video and use:\n* ```jsx\n* <TransitiveCapability jwt={jwt}\n* component='webrtc-video-supervisor'\n* auto=\"true\"\n* />\n* ```\n*/\nexport const TransitiveCapability = ({\n jwt, host = 'transitiverobotics.com', ssl = true, ...config\n }) => {\n\n const assertPresent = (value, name) => {\n if (!value) throw new Error(`JWT is missing ${name}`);\n };\n\n const {id, device, capability} = decodeJWT(jwt);\n // Throw an error when any of the above payload is missing\n assertPresent(id, 'id');\n assertPresent(device, 'device');\n assertPresent(capability, 'capability');\n\n const type = device == '_fleet' ? 'fleet' : 'device';\n const capName = capability.split('/')[1];\n const name = `${capName}-${type}`;\n const component = config.component || name;\n\n const { loaded } = useCapability({\n capability,\n name,\n userId: id || config.userId, // accept both id and userId, see #492\n deviceId: device,\n host,\n ssl\n });\n\n const ref = useRef();\n // Attach functional and object properties to the component when ready and\n // on change\n useEffect(() => {\n ref.current?.instance?.setState(s =>\n ({ ...s, id, jwt, host, ssl, ...config }));\n }, [ref.current, loaded, id, jwt, host, ssl, ...Object.values(config)]);\n\n // Disrupt the reactive chain of the MutationObserver to the customElement,\n // so we are not competing with it for updating the props.\n const propClone = useMemo(() => ({id, jwt, host, ssl, ...config}), []);\n\n if (!loaded) return <div>Loading {name}</div>;\n return React.createElement(component, {...propClone, ref});\n };\n\n\n/** A simple error boundary. Usage:\n* ```jsx\n* <ErrorBoundary message=\"Something went wrong\">\n* <SomeFlakyComponent />\n* </ErrorBoundary>\n* ```\n*/\nexport class ErrorBoundary extends React.Component {\n constructor(props) {\n super(props);\n this.state = {\n hasError: false,\n messages: [],\n };\n }\n\n static getDerivedStateFromError(error) {\n return { hasError: true };\n }\n\n componentDidCatch(error, errorInfo) {\n console.warn('ErrorBoundary caught:', error, errorInfo);\n this.setState(({messages}) => ({messages: [...messages, error.message]}));\n }\n\n render() {\n return (this.state.hasError ? <div>\n Error: {this.props.message || this.state.messages?.join(', ')\n || 'Something went wrong here.'}\n </div>\n : this.props.children);\n }\n};\n\n\nexport const CapabilityContext = React.createContext({});\n\n/* Only used internally: the actual context provider, given the loaded module */\nconst LoadedCapabilityContextProvider = (props) => {\n const {children, jwt, id, host, ssl, loadedModule} = props;\n\n const context = loadedModule.provideContext?.({\n jwt, id, host, ssl, appReact: React\n });\n\n return <CapabilityContext.Provider value={{ ...context }}>\n {children}\n </CapabilityContext.Provider>;\n};\n\n/**\n* Context provider for capabilities. Use this to access the front-end API\n* provided by some capabilities. Example:\n* ```jsx\n* <CapabilityContextProvider jwt={jwt}>\n* <MyROSComponent />\n* </CapabilityContextProvider>\n* ```\n* where `jwt` is a JWT for a capability that exposes a front-end API. Then use\n* `useContext` in `MyROSComponent` to get the exposed data and functions, e.g.:\n* ```jsx\n* const MyROSComponent = () => {\n* const { ready, subscribe, data } = useContext(CapabilityContext);\n* // When ready, subscribe to the `/odom` topic in ROS1\n* useEffect(() => { ready && subscribe(1, '/odom'); }, [ready]);\n* return <pre>{JSON.stringify(data, true, 2)}</pre>;\n* }\n* ```\n* Where `ready`, `subscribe`, and `data` are reactive variables and functions\n* exposed by the capability of the provided JWT. In this example, the latest\n* message from the subscribed ROS topics will be available in the capabilities\n* namespace in `data`.\n* @param {object} props\n*/\nexport const CapabilityContextProvider =\n ({children, jwt, host = undefined, ssl = undefined}) => {\n\n const {id, device, capability} = decodeJWT(jwt);\n const type = device == '_fleet' ? 'fleet' : 'device';\n const capName = capability.split('/')[1];\n const name = `${capName}-${type}`;\n\n const {loaded, loadedModule} = useCapability({\n capability,\n name,\n userId: id,\n deviceId: device,\n appReact: React,\n host,\n ssl\n });\n\n if (!loadedModule) return <div>Loading {capability}</div>;\n return <LoadedCapabilityContextProvider {...{jwt, id, host, ssl, loadedModule}}>\n {children}\n </LoadedCapabilityContextProvider>;\n };\n\n\n/* whether or not the given react component allows refs, i.e., is either\n * a functional component wrapped with forwardRef or a class component */\nconst componentPermitsRefs = (Component) =>\n (Component.$$typeof == Symbol.for('react.forward_ref'))\n || Component.prototype?.render;\n\n\n/** Create a WebComponent from the given react component and name that is\n* reactive to all attributes. Used in web capabilities. Example:\n* ```js\n* createWebComponent(Diagnostics, 'health-monitoring-device', TR_PKG_VERSION);\n* ```\n*/\nexport const createWebComponent = (Component, name, version = '0.0.0',\n options = {}) => {\n\n // Only create a ref if the component accepts it. This avoids an ugly\n // error in the console when trying to give a ref to a non-forwardRef-wrapped\n // functional component.\n const compRef = componentPermitsRefs(Component) ? React.createRef() : null;\n\n class Wrapper extends React.Component {\n\n onDisconnect = null;\n state = {};\n\n componentDidMount() {\n this.props._element.instance = this;\n this.webComponentConstructed(this.props._element);\n this.props._element.callLifeCycleHook('connectedCallback');\n }\n\n /* function used by `Component` to register a onDisconnect handler */\n setOnDisconnect(fn) {\n this.onDisconnect = fn;\n }\n\n webComponentConstructed(instance) {\n // Observe all changes to attributes and update React state from it\n const observer = new MutationObserver((mutationRecords) => {\n const update = {};\n mutationRecords.forEach(({attributeName}) => {\n update[attributeName] = instance.getAttribute(attributeName);\n });\n this.setState(old => ({...old, ...update}));\n }).observe(instance, { attributes: true });\n }\n\n webComponentDisconnected() {\n // This ensures that the react component unmounts and all useEffect\n // cleanups are called.\n this.setState({_disconnected: true});\n try {\n this.onDisconnect && this.onDisconnect();\n } catch (e) {\n console.log('Error during onDisconnect of web-component', e);\n }\n }\n\n /* method exposed to the wrapped component via prop that allows setting\n * the \"config\" state variable inside the wrapper (not the component\n * itself). This config is retrieved by the portal for inclusion in the\n * embedding instructions. */\n setConfig(config) {\n this.setState({config});\n }\n\n render() {\n const stylesheets = options.stylesheets || [\n // 'https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css'\n // Bootstrap 5.3.2 css scoped to `.transitive-bs-root`:\n 'https://cdn.jsdelivr.net/gh/transitiverobotics/transitive-utils@0.8.3/web/css/bootstrap_transitive-bs-root.min.css'\n ];\n\n return <div id={`cap-${name}-${version}`}\n className={options.className || 'transitive-bs-root'}>\n <style>\n {stylesheets.map(url => `@import url(${url});`)}\n </style>\n\n {!this.state._disconnected &&\n <Component ref={compRef}\n {...this.props}\n // Important to keep state *after* props for reactivity to work\n {...this.state}\n setOnDisconnect={this.setOnDisconnect.bind(this)}\n setConfig={this.setConfig.bind(this)}\n />}\n </div>;\n }\n };\n\n return ReactWebComponent.create(Wrapper, name, options.shadowDOM || false,\n compRef);\n };\n", "// It is OK to use paths outside of this package because webpack will bundle them\nexport * from '../../common/common.js';\nexport * from '../../common/DataCache';\nimport MS from '../../common/MqttSync.js';\nexport const MqttSync = MS;\n\n// moved to common\n// export const decodeJWT = (jwt) => JSON.parse(atob(jwt.split('.')[1]));\n\n/** parse document cookies */\nexport const parseCookie = str =>\n str.split(';')\n .map(v => v.split('='))\n .reduce((acc, v) => {\n acc[decodeURIComponent(v[0].trim())] =\n v[1] && decodeURIComponent(v[1].trim());\n return acc;\n }, {});\n\n/** get or post (if body given) json */\nexport const fetchJson = (url, callback, options = {}) => {\n fetch(url, {\n method: options.method || (options.body ? 'post' : 'get'),\n mode: 'cors',\n cache: 'no-cache',\n // Maybe we'll need this (when embedding)?\n // credentials: 'same-origin', // include, *same-origin, omit\n headers: {\n 'Content-Type': 'application/json',\n ...options.headers\n },\n redirect: 'follow',\n referrerPolicy: 'no-referrer',\n body: options.body ? JSON.stringify(options.body) : undefined\n }).then(res => {\n const error = !res.ok &&\n `fetching ${url} failed: ${res.status} ${res.statusText}`;\n res.json()\n .then(data => callback(error, data))\n .catch(err => {\n throw new Error(err);\n });\n }).catch((error) => callback(`error: ${error}`));\n};\n", "import React, { useState, useEffect, useMemo } from 'react';\nimport _ from 'lodash';\n// import mqtt1 from 'mqtt';\nimport mqtt from 'mqtt/dist/mqtt.esm';\n\nimport { decodeJWT, getLogger, clone, pathToTopic, mergeVersions, topicToPath }\n from './client';\nconst MqttSync = require('../../common/MqttSync');\n\nconst log = getLogger('utils-web/hooks');\nlog.setLevel('info');\n\n\n/** Hook for using MqttSync in React.\n* @returns {object} An object `{data, mqttSync, ready, StatusComponent, status}`\n* where:\n* `data` is a reactive data source in React containing all the data received by\n* mqttsync,\n* `mqttSync` is the MqttSync object itself,\n* `ready` indicates when mqttSync is ready to be used (connected and received\n* successfully subscribed to mqtt system heartbeats)\n*/\nexport const useMqttSync = ({jwt, id, mqttUrl, appReact}) => {\n const { useState, useRef, useEffect } = appReact || React;\n\n const [status, setStatus] = useState('connecting');\n const [mqttSync, setMqttSync] = useState();\n const [data, setData] = useState({});\n // True once the subscription to the system heartbeat has been granted.\n const [heartbeatGranted, setHeartbeatGranted] = useState(false);\n\n useEffect(() => {\n const payload = decodeJWT(jwt);\n log.debug('re-create mqtt client');\n const client = mqtt.connect(mqttUrl, {\n username: JSON.stringify({id, payload}),\n password: jwt\n });\n\n client.once('connect', () => {\n log.debug('MQTT connected');\n const mqttSyncClient = new MqttSync({\n mqttClient: client,\n ignoreRetain: true,\n onHeartbeatGranted: () => setHeartbeatGranted(true)\n });\n setMqttSync(mqttSyncClient);\n setStatus('connected');\n\n // Update data on change. Note: need to clone object to force reaction\n mqttSyncClient.data.subscribe(_.throttle(() =>\n setData(clone(mqttSyncClient.data.get())), 50));\n });\n\n client.on('error', (error) => {\n log.error(error);\n setStatus(`error: ${error}`);\n });\n\n return () => {\n log.info('cleaning up useMQTTSync');\n if (mqttSync && mqttSync.beforeDisconnect) {\n mqttSync.beforeDisconnect();\n mqttSync.waitForHeartbeatOnce(() => client.end());\n } else {\n client.end();\n }\n };\n }, [jwt, id]);\n\n return {\n status,\n // ready: status == 'connected',\n ready: heartbeatGranted,\n StatusComponent: () => <div>{status}</div>,\n mqttSync, // Note: mqttSync.data is not reactive.\n data, // This is a reactive data-source (to use meteor terminology).\n };\n};\n\n/** Hook for using Transitive in React. Connects to MQTT, establishes sync, and\n* exposes reactive `data` state variable. */\nexport const useTransitive =\n ({jwt, id, capability, versionNS, appReact,\n host = 'transitiverobotics.com', ssl = true }) => {\n\n const [scope, capabilityName] = capability.split('/');\n\n const { device } = decodeJWT(jwt);\n const prefixPath = [id, device, scope, capabilityName];\n const prefix = pathToTopic(prefixPath);\n const prefixPathVersion = [...prefixPath, versionNS];\n const prefixVersion = pathToTopic(prefixPathVersion);\n\n const mqttUrl = `${ssl && JSON.parse(ssl) ? 'wss' : 'ws'}://mqtt.${host}`;\n const fromMqttSync = useMqttSync({ jwt, id, mqttUrl, appReact });\n\n return {...fromMqttSync, device, prefixPath, prefix, prefixPathVersion,\n prefixVersion};\n };\n\n\n/** Subscribe to MqttSync topics using the provided JWT. This will\n* automatically find which version of the capability named in the JWT is running\n* on the device of the JWT and get the data for that version.\n*\n* Example usage (with webrtc-video):\n*\n* ```js\n* const { agentStatus, topicData } = useTopics({ jwt, topics: [\n* '/options/videoSource',\n* '/stats/+/log/'\n* ]});\n* ```\n*\n* @param {object} options An object containing:\n* `JWT`: A list of subtopics of the capability named in the JWT.\n* `topics`: A list of subtopics of the capability named in the JWT.\n* @returns {object} An object `{data, mqttSync, ready, agentStatus, topicData}`\n* where:\n* `agentStatus` is the `status` field of the running robot agent, including\n* heartbeat and runningPackages, and\n* `topicData` is the data for the selected topics of the capability\n*/\nexport const useTopics = ({jwt, host = 'transitiverobotics.com', ssl = true,\n topics = [], appReact}) => {\n\n const { useState, useEffect } = appReact || React;\n\n // We need to make sure we don't resubscribe (below) when this function\n // is called with the same content of `topics` but a different object.\n const [topicList, setTopicList] = useState();\n !_.isEqual(topicList, topics) && setTopicList(topics);\n\n const {device, id, capability} = decodeJWT(jwt);\n if (device == '_fleet') {\n log.warn('useTopics only works for device JWTs, not _fleet ones');\n return;\n }\n\n const agentPrefix = `/${id}/${device}/@transitive-robotics/_robot-agent/+/status`;\n\n const {mqttSync, data, status, ready, StatusComponent} =\n useMqttSync({jwt, id, mqttUrl: `ws${ssl ? 's' : ''}://mqtt.${host}`, appReact});\n\n useEffect(() => {\n if (ready) {\n mqttSync.subscribe(agentPrefix, (err) => err && console.warn(err));\n }\n }, [mqttSync, ready]);\n\n const agentStatus = mergeVersions(\n data[id]?.[device]['@transitive-robotics']['_robot-agent'], 'status').status;\n const runningPackages = agentStatus?.runningPackages;\n\n const [scope, capName] = capability.split('/');\n const versions = runningPackages?.[scope]?.[capName];\n const runningVersion = versions && Object.values(versions).filter(Boolean)[0];\n const prefix = `/${id}/${device}/${capability}/${runningVersion}`;\n\n useEffect(() => {\n log.debug('topics', topics);\n if (runningVersion) {\n topics.forEach(topic => {\n log.debug(`subscribing to ${prefix}${topic}`);\n mqttSync.subscribe(`${prefix}${topic}`,\n (err) => err && log.warn(err));\n });\n }\n }, [topicList, runningVersion, mqttSync]);\n\n const topicData = _.get(data, topicToPath(prefix));\n // log.debug(data, agentStatus, topicData);\n\n return {data: data?.[id]?.[device], mqttSync, agentStatus, topicData};\n };\n\n\nconst listeners = {};\nconst loadedModules = {};\n/** Hook to load a Transitive capability. Besides loading the custom element,\n* this hook also returns any functions and objects the component exports in\n* `loadedModule`. Example:\n* ```js\n* const {loaded, loadedModule} = useCapability({\n* capability: '@transitive-robotics/terminal',\n* name: 'mock-device',\n* userId: 'user123',\n* deviceId: 'd_mydevice123',\n* });\n* ```\n*/\nexport const useCapability = ({ capability, name, userId, deviceId,\n host = 'transitiverobotics.com', ssl = true, appReact\n }) => {\n const { useState, useEffect } = appReact || React;\n\n const [returns, setReturns] = useState({ loaded: false });\n\n // called when loaded\n const done = (message, theModule) => {\n log.debug(`custom component ${name}: ${message}`);\n loadedModules[name] = theModule;\n setReturns(x => ({...x, loadedModule: theModule, loaded: !!theModule}));\n };\n\n /** set the returns for all listeners */\n const notifyListeners = (...args) => listeners[name].forEach(l => l(...args));\n\n useEffect(() => {\n log.debug(`loading custom component ${name}`);\n\n if (loadedModules[name]) {\n return done('already loaded', loadedModules[name]);\n }\n if (listeners[name]) {\n log.debug('already loading');\n // get notified when loading completes\n listeners[name].push(done);\n return;\n }\n listeners[name] = [done];\n\n const baseUrl = `http${ssl ? 's' : ''}://portal.${host}`;\n const params = new URLSearchParams({ userId, deviceId });\n // filename without extension as we'll try multiple\n const fileBasename = `${baseUrl}/running/${capability}/dist/${name}`;\n\n /* Since some users use webpack and webpack is stupid, we need to use\n this magic comment for it to ignore these (remote) requests, see:\n https://webpack.js.org/api/module-methods/#webpackignore. */\n import(/* webpackIgnore: true */\n `${fileBasename}.esm.js?${params.toString()}`).then(\n esm => notifyListeners('loaded esm', esm),\n error => {\n log.warn(`No ESM module found for ${name}, loading iife`, error);\n import(/* webpackIgnore: true */\n `${fileBasename}.js?${params.toString()}`).then(\n iife => notifyListeners('loaded iife', iife),\n error => log.error(`Failed to load ${name} iife`, error));\n });\n }, [capability, name, userId, deviceId]);\n\n return returns;\n };\n\n\n"],
5
- "mappings": "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",
6
- "names": ["module", "module", "attribute", "module", "React", "styles", "module", "module", "_", "context", "getLogger", "clone", "decodeJWT", "pathToTopic", "topicToPath", "mergeVersions", "module", "_", "topicToPath", "pathToTopic", "module", "_", "topicToPath", "pathToTopic", "getLogger", "mergeVersions", "log", "clone", "MqttSync", "value", "err", "import_react", "MS", "MqttSync", "useState", "useRef", "useEffect", "React", "mqtt", "_", "error", "React", "name", "React", "ReactWebComponent"]
3
+ "sources": ["../client/react-web-component/getStyleElementsFromReactWebComponentStyleLoader.js", "../client/react-web-component/extractAttributes.js", "../client/react-web-component/index.js", "../../common/datacache/tools.js", "../../common/constants.js", "../../common/common.js", "../../common/datacache/DataCache.js", "../../common/datacache/index.js", "../../common/MqttSync.js", "../index.js", "../client/shared.jsx", "../client/client.js", "../client/hooks.jsx"],
4
+ "sourcesContent": ["/*\n * An optional library which is conditionally added\n * @returns {[]}\n */\nmodule.exports = () => {\n try {\n return require('react-web-component-style-loader/exports').styleElements;\n } catch (e) {\n return [];\n }\n};\n", "/*\n * Takes in a node attributes map and returns an object with camelCased\n * properties and values\n * @param nodeMap\n * @returns {{}}\n */\nmodule.exports = function extractAttributes(nodeMap) {\n if (!nodeMap.attributes) {\n return {};\n }\n\n let obj = {};\n let attribute;\n const attributesAsNodeMap = [...nodeMap.attributes];\n const attributes = attributesAsNodeMap.map((attribute) =>\n ({ [attribute.name]: attribute.value }));\n\n for (attribute of attributes) {\n const key = Object.keys(attribute)[0];\n const camelCasedKey = key.replace(/-([a-z])/g, (g) => g[1].toUpperCase());\n obj[camelCasedKey] = attribute[key];\n }\n\n return obj;\n};\n", "const React = require('react');\nconst ReactDOM = require('react-dom');\nconst { createRoot } = require('react-dom/client');\n\n// const { createRoot } = require('react-dom/client'); // react 18; wip\nconst retargetEvents = require('react-shadow-dom-retarget-events');\nconst getStyleElementsFromReactWebComponentStyleLoader = require('./getStyleElementsFromReactWebComponentStyleLoader');\nconst extractAttributes = require('./extractAttributes');\n\n// require('@webcomponents/shadydom');\n// require('@webcomponents/custom-elements');\n\nconst lifeCycleHooks = {\n attachedCallback: 'webComponentAttached',\n connectedCallback: 'webComponentConnected',\n disconnectedCallback: 'webComponentDisconnected',\n adoptedCallback: 'webComponentAdopted'\n};\n\nmodule.exports = {\n /*\n * @param {JSX.Element} wrapper: the wrapper component class to be instantiated and wrapped\n * @param {string} tagName - The name of the web component. Has to be minus \"-\" delimited.\n * @param {boolean} useShadowDom - If the value is set to \"true\" the web component will use the `shadowDom`. The default value is true.\n */\n create: (wrapper, tagName, useShadowDom = true, compRef = undefined) => {\n\n const proto = class extends HTMLElement {\n instance = null; // the instance we create of the wrapper\n\n callConstructorHook() {\n if (this.instance['webComponentConstructed']) {\n this.instance['webComponentConstructed'].apply(this.instance, [this])\n }\n }\n\n callLifeCycleHook(hook, params = []) {\n const method = lifeCycleHooks[hook];\n if (method && this.instance && this.instance[method]) {\n this.instance[method].apply(this.instance, params);\n }\n }\n\n connectedCallback() {\n const self = this;\n let mountPoint = self;\n\n if (useShadowDom) {\n // Re-assign the self (this) to the newly created shadowRoot\n const shadowRoot = self.attachShadow({ mode: 'open' });\n\n // Re-assign the mountPoint to the newly created \"div\" element\n mountPoint = document.createElement('div');\n\n // Move all of the styles assigned to the react component inside of\n // the shadowRoot. By default this is not used, only if the library is\n // explicitly installed\n const styles = getStyleElementsFromReactWebComponentStyleLoader();\n styles.forEach((style) => {\n shadowRoot.appendChild(style.cloneNode(shadowRoot));\n });\n\n shadowRoot.appendChild(mountPoint);\n retargetEvents(shadowRoot);\n }\n\n createRoot(mountPoint).render(\n // This is where we instantiate the actual component (in its wrapper)\n React.createElement(wrapper, {_element: self, ...extractAttributes(self)})\n );\n }\n\n disconnectedCallback() {\n this.callLifeCycleHook('disconnectedCallback');\n }\n\n adoptedCallback(oldDocument, newDocument) {\n this.callLifeCycleHook('adoptedCallback', [oldDocument, newDocument]);\n }\n\n /* call a function defined in the component, either as a class method, or\n * via useImperativeHandle */\n call(functionName, args) {\n return compRef?.current?.[functionName]?.call(compRef?.current, args);\n }\n\n /* predefined function to retrieve the pre-defined config object of the\n * state, populated via the pre-defined `setConfig` method given as prop\n * to the wrapped component. */\n getConfig() {\n return this.instance.state.config;\n }\n }\n\n customElements.define(tagName, proto);\n\n return proto;\n },\n};\n", "\nconst _ = {\n get: require('lodash/get'),\n set: require('lodash/set'),\n forEach: require('lodash/forEach'),\n map: require('lodash/map'),\n isPlainObject: require('lodash/isPlainObject'),\n};\n\n\n// -------------------------------------------------------------------------\n// DataCache tools\n\n/** convert topic to path array */\nconst topicToPath = (topic) => {\n // split topic by slashes, but not if they are escaped\n // const path = topic.match(/(\\\\.|[^/])+/g) || [];\n // split topic by slashes and unescape slashes in each item\n const path = topic.split('/').map(decodeTopicElement);\n // handle leading slash\n path.length > 0 && path[0].length == 0 && path.shift();\n // handle trailing slash\n path.length > 0 && path.at(-1).length == 0 && path.pop();\n return path;\n};\n\n\n/** convert a path array to mqtt topic; reduces +id identifiers to + */\nconst pathToTopic = (pathArray) => {\n /** reduce wildcards with Ids, such as `+sessionId`, to just + */\n const dropWildcardIds = (x) => x.startsWith('+') ? '+' : x;\n return `/${pathArray.map(dropWildcardIds).map(encodeTopicElement).join('/')}`;\n};\n\n/**\n * Given an object, return a new flat object of topic+value pairs, e.g.:\n```js\n{a: {b: 1, c: 2}, d: 3} \u2192 {'/a/b': 1, '/a/c': 2, '/d': 3}\n```\nNote: not idempotent!\n```js\n{'/a/b': 1, '/a/c': 2, d: 3} \u2192 {'%2Fa%2Fb': 1, '%2Fa%2Fc': 2, '/d': 3}\n```\n*/\nconst toFlatObject = (obj, prefix = [], rtv = {}) => {\n _.forEach(obj, (value, key) => {\n // const newPrefix = prefix.concat(topicToPath(String(key)));\n const newPrefix = prefix.concat(String(key));\n\n // TODO: using isPlainObject also means custom objects (classes) do not get\n // broken down.\n if ((_.isPlainObject(value) || value instanceof Array) && value !== null) {\n // it's an object or array\n toFlatObject(value, newPrefix, rtv);\n } else {\n // it's a primitive\n rtv[pathToTopic(newPrefix)] = value;\n }\n });\n return rtv;\n};\n\n/** Iterate through the object and invoke callback for each match of path (with\nnamed wildcards) */\nconst forMatchIterator = (obj, path, callback, pathSoFar = [], matchSoFar = {}) => {\n\n if (path.length == 0 || path[0] == '#') {\n callback(obj, pathSoFar, matchSoFar);\n return;\n }\n\n const next = path[0]; // don't use shift, we don't want to modify path\n if (next) {\n for (let key in obj) {\n if (key == next || next == '*' || next.startsWith('+')) {\n const match = next.startsWith('+') && next.length > 1 ?\n Object.assign({}, matchSoFar, {[next.slice(1)]: key}) :\n matchSoFar;\n forMatchIterator(obj[key], path.slice(1), callback,\n pathSoFar.concat([key]), match);\n }\n }\n }\n};\n\n/** Like _.set but without arrays. This allows using numbers as keys. */\nconst setFromPath = (obj, path, value) => {\n if (path.length == 0) return obj;\n const next = path.shift();\n if (path.length == 0) {\n obj[next] = value;\n } else {\n if (!obj[next]) obj[next] = {};\n setFromPath(obj[next], path, value);\n }\n};\n\nconst encodeTopicElement = x => x.replace(/%/g, '%25').replace(/\\//g, '%2F');\nconst decodeTopicElement = x => x.replace(/%25/g, '%').replace(/%2F/g, '/');\n\n\n/** Match a slash-separated topic or path array with a selector using +XYZ for\n* (named) wildcards. Return the matching result.\n*/\nconst topicMatch = (selector, topic) => {\n const byArray = (s, p) => {\n if (s.length == 0) return true; // we are done: prefix matched\n if (s[0][0] == '#') return true; // explicit tail-wildcard\n // if (p.length < s.length) return false;\n if (p.length == 0) return true; // we are done, matched all\n // simple match:\n if (s[0] == p[0]) return byArray(s.slice(1), p.slice(1));\n // wild card match:\n if (s[0][0] == '+') {\n const sub = byArray(s.slice(1), p.slice(1));\n return sub && Object.assign({[s[0].slice(1)]: p[0]}, sub);\n }\n // else: failure!\n return false;\n };\n\n const selectorArray = Array.isArray(selector) ? selector : topicToPath(selector);\n const pathArray = Array.isArray(topic) ? topic : topicToPath(topic);\n return byArray(selectorArray, pathArray);\n};\n\n/** sub is a strict sub-topic of parent, and in particular not equal */\nconst isSubTopicOf = (sub, parent) => {\n const pPath = topicToPath(parent);\n const sPath = topicToPath(sub);\n return isPrefixOf(pPath, sPath) && pPath.length < sPath.length;\n};\n\n/** prefixArray is a prefix of the array */\nconst isPrefixOf = (prefixArray, array) => {\n if (prefixArray.length == 0) return true;\n return (prefixArray[0] == array[0] &&\n isPrefixOf(prefixArray.slice(1), array.slice(1))\n );\n}\n\n\nmodule.exports = {\n topicToPath,\n pathToTopic,\n toFlatObject,\n forMatchIterator,\n setFromPath,\n encodeTopicElement,\n decodeTopicElement,\n topicMatch,\n isSubTopicOf,\n};", "module.exports = {\n rosReleases: {\n kinetic: { rosVersion: 1, ubuntuCodename: 'xenial' },\n melodic: { rosVersion: 1, ubuntuCodename: 'bionic' },\n noetic: { rosVersion: 1, ubuntuCodename: 'focal' },\n dashing: { rosVersion: 2 },\n eloquent: { rosVersion: 2 },\n foxy: { rosVersion: 2 },\n galactic: { rosVersion: 2 },\n humble: { rosVersion: 2 },\n iron: { rosVersion: 2 },\n jazzy: { rosVersion: 2 },\n kilted: { rosVersion: 2 },\n rolling: { rosVersion: 2 },\n }\n};\n", "const semverCompare = require('semver/functions/compare');\nconst semverMinVersion = require('semver/ranges/min-version');\n\nconst _ = {\n get: require('lodash/get'),\n set: require('lodash/set'),\n unset: require('lodash/unset'),\n forEach: require('lodash/forEach'),\n map: require('lodash/map'),\n isEmpty: require('lodash/isEmpty'),\n eq: require('lodash/isEqual'),\n isPlainObject: require('lodash/isPlainObject'),\n merge: require('lodash/merge'),\n};\n\nconst loglevel = require('loglevel');\nconst prefix = require('loglevel-plugin-prefix');\nconst chalk = require('chalk');\n\nconst { topicToPath, pathToTopic, toFlatObject, setFromPath, forMatchIterator,\n topicMatch, isSubTopicOf, encodeTopicElement, decodeTopicElement }\n = require('./datacache/tools');\n\nconst constants = require('./constants');\n\n// ----------------------------------------------------------------------------\n// Logging, incl. logger prefix\n\n/* Convenience function to set all loggers to the given level. */\nloglevel.setAll = (level) =>\n Object.values(loglevel.getLoggers()).forEach(l => l.setLevel(level));\n\nconst logColors = {\n warn: chalk.yellow,\n error: chalk.red,\n info: chalk.green,\n debug: chalk.gray,\n};\n\nconst levelFormatter =\n (level) => logColors[level] ? logColors[level](level) : level;\n\nprefix.reg(loglevel);\n\nif (typeof window != 'undefined') {\n // browser: keep it simple\n prefix.apply(loglevel, {\n template: '[%n %l]',\n });\n} else {\n // back-end + robot: include timestamp and use colors\n prefix.apply(loglevel, {\n template: '[%t %n %l]',\n levelFormatter,\n timestampFormatter: date => chalk.blue(date.toISOString()),\n });\n}\n\n/** Get a new loglevel logger; call with a name, e.g., `module.id`. The returned\n* logger has methods trace, debug, info, warn, error. See\n* https://www.npmjs.com/package/loglevel for details.\n*/\nconst getLogger = loglevel.getLogger;\n\n// ----------------------------------------------------------------------------\n\n/** Deep-clone the given object. All functionality is lost, just data is kept. */\nconst clone = (obj) => JSON.parse(JSON.stringify(obj));\n\n/** Parse JWT and return the decoded payload (JSON). */\nconst decodeJWT = (jwt) => JSON.parse(atob(jwt.split('.')[1]));\n// TODO: make this robust against bad JWTs (throw a more readable error)\n\n/** Try parsing JSON, return null if unsuccessful */\nconst tryJSONParse = (string) => {\n try {\n return JSON.parse(string);\n } catch (e) {\n return null;\n }\n};\n\n/** Reusable visitor pattern: iteratively visits all nodes in the tree\n described by `object`, where `childField` indicates the child-of predicate.\n*/\nconst visit = (object, childField, visitor) => {\n if (!object) return;\n visitor(object);\n object[childField]?.forEach(child => visit(child, childField, visitor));\n};\n\n/** Given an object and a path, visit each ancestor of the path */\nconst visitAncestor = (object, path, visitor, prefix = []) => {\n visitor(object, prefix);\n const next = path[0];\n if (next) {\n const sub = object[next];\n if (sub) {\n visitAncestor(sub, path.slice(1), visitor, prefix.concat(next));\n }\n }\n};\n\n/** Wait for delay ms, for use in async functions. */\nconst wait = (delay) => new Promise((resolve) => { setTimeout(resolve, delay); });\n\n\n\n\n// -------------------------------------------------------------------------\n// MQTT Tools\n\n/** parse usernames used in MQTT */\nconst parseMQTTUsername = (username) => {\n const parts = username.split(':');\n return {\n organization: parts[0],\n client: parts[1],\n sub: parts.slice(2)\n }\n};\n\n/** parse an MQTT topic according to our topic schema */\nconst parseMQTTTopic = (topic) => {\n const parts = topicToPath(topic);\n return {\n organization: parts[0],\n device: parts[1],\n capabilityScope: parts[2],\n capabilityName: parts[3],\n capability: `${parts[2]}/${parts[3]}`,\n version: parts[4],\n sub: parts.slice(5)\n }\n};\n\nconst mqttParsePayload = (payload) =>\n payload.length == 0 ? null : JSON.parse(payload.toString('utf-8'));\n// TODO: ^ This can probably now just become tryJSONParse\n\n/** delete all retained messages in a certain topic prefix, waiting for\n a given delay to collect existing retained. Use with care, never delete topics\n not owned by us. Harmless within capabilities, which are namespaced already.\n*/\nconst mqttClearRetained = (mqttClient, prefixes, callback, delay = 1000) => {\n\n const toDelete = [];\n const collectToDelete = (topic) => {\n // there may be other mqtt subscriptions running, filter by topic\n prefixes.forEach(prefix =>\n // mqttTopicMatch(topic, `${prefix}/#`) && toDelete.push(topic)\n topicMatch(`${prefix}/#`, topic) && toDelete.push(topic)\n );\n }\n mqttClient.on('message', collectToDelete);\n\n // subscribe to all\n prefixes.forEach(prefix => {\n if (typeof prefix == 'string') {\n mqttClient.subscribe(`${prefix}/#`);\n } else {\n console.warn('Ignoring', prefix, 'since it is not a string.');\n }\n });\n\n // value to use to clear, depending on node.js vs. browser\n const nullValue = (typeof Buffer != 'undefined' ? Buffer.alloc(0) : null);\n\n setTimeout(() => {\n mqttClient.removeListener('message', collectToDelete);\n prefixes.forEach(prefix => mqttClient.unsubscribe(`${prefix}/#`));\n\n const count = toDelete.length;\n console.log(`clearing ${count} retained messages from ${prefixes}`);\n toDelete.forEach(topic => {\n mqttClient.publish(topic, nullValue, {retain: true});\n });\n\n callback && callback(count);\n }, delay);\n};\n\n\n// WIP: a cleaner, more explicit way to serialize/deserialize mqtt payloads\n// /** Serialize a message for transport via MQTT */\n// const mqttSerialize = (message) => {\n// return value == null ? null : JSON.stringify(message);\n// };\n\n// /** Deserialize a message from MQTT */\n// const mqttDeserialize = (payload) => {\n// return payload.length == 0 ? null : JSON.parse(payload.toString('utf-8'));\n// };\n\n\n// -------------------------------------------------------------------------\n\n/** Generate a random id (base36) */\nconst getRandomId = (bytes = 6) => {\n const buffer = new Uint8Array(bytes);\n crypto.getRandomValues(buffer);\n return buffer.reduce((memo, i) => memo + i.toString(36), '');\n};\n\n/** Convert number to base52 [a-zA-Z] */\nconst toBase52 = (num) => {\n const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';\n const list = [];\n do {\n list.unshift(characters[num % 52]);\n num = Math.floor(num / 52);\n } while (num > 0);\n return list.join('');\n}\n\n/** Get a base52 representation [a-zA-Z] of the current date (ms since epoch) */\nconst getDateBase52 = () => toBase52(Date.now());\n\n// -------------------------------------------------------------------------\n\n/** Compare to version strings. Return -1 if a is lower than b,\n0 if they are equal, and 1 otherwise. If either is not a complete version,\ne.g., 2.0, interpret it as a range and use its minimum version for the\ncomparison. Hence, 2.0 < 2.0.1. */\nconst versionCompare = (a, b) =>\n semverCompare(semverMinVersion(a), semverMinVersion(b));\n\n// -------------------------------------------------------------------------\n\n/** given an object where the keys are versions, merge this into one object\n where the latest version of each subfield overwrites any previous */\nconst mergeVersions = (versionsObject, subTopic = undefined, options = {}) => {\n if (!versionsObject) {\n return subTopic ? _.set({}, subTopic, versionsObject) : versionsObject;\n }\n\n const versions = Object.keys(versionsObject).filter(ver =>\n (!options.maxVersion || versionCompare(ver, options.maxVersion) <= 0) &&\n (!options.minVersion || versionCompare(options.minVersion, ver) <= 0))\n .sort(versionCompare);\n\n const merged = {};\n const subPath = subTopic && topicToPath(subTopic);\n versions.forEach(nextVersion => {\n const newValue = subPath ? _.get(versionsObject[nextVersion], subPath) :\n versionsObject[nextVersion];\n // Object.assign(merged, newValue);\n _.merge(merged, newValue);\n });\n return subPath ? _.set({}, subPath, merged) : merged;\n};\n\n// -------------------------------------------------------------------------\n// Formatting tools\n\nconst units = ['B', 'KB', 'MB', 'GB', 'TB'];\nconst formatBytes = (bytes) => {\n if (!bytes) return '--';\n let i = 0;\n while (bytes > 1024) {\n bytes /= 1024;\n i++;\n }\n return `${bytes.toFixed(2)} ${units[i]}`;\n}\n\nconst formatDuration = (seconds) => {\n if (!seconds) return '--';\n const parts = {};\n if (seconds > 3600) {\n parts.h = Math.floor(seconds / 3600);\n seconds = seconds % 3600;\n }\n if (seconds > 60) {\n parts.m = Math.floor(seconds / 60);\n seconds = seconds % 60;\n }\n parts.s = Math.floor(seconds);\n\n let rtv = '';\n parts.h > 0 && (rtv += `${parts.h}h `);\n parts.m > 0 && (rtv += `${parts.m}m `);\n !parts.h && (rtv += `${parts.s}s`);\n return rtv.trim();\n};\n\n// -------------------------------------------------------------------------\n\nmodule.exports = { parseMQTTUsername, parseMQTTTopic,\n pathToTopic, topicToPath, toFlatObject, topicMatch,\n mqttParsePayload, getRandomId, toBase52, getDateBase52, versionCompare,\n loglevel, getLogger,\n mergeVersions, mqttClearRetained, isSubTopicOf, clone, setFromPath,\n forMatchIterator, encodeTopicElement, decodeTopicElement, constants, visit,\n wait, formatBytes, formatDuration, tryJSONParse,\n decodeJWT, visitAncestor\n};\n", "\nconst _ = {\n get: require('lodash/get'),\n set: require('lodash/set'),\n unset: require('lodash/unset'),\n forEach: require('lodash/forEach'),\n map: require('lodash/map'),\n isEmpty: require('lodash/isEmpty'),\n eq: require('lodash/isEqual'),\n isPlainObject: require('lodash/isPlainObject'),\n merge: require('lodash/merge'),\n};\n\nconst {topicToPath, pathToTopic, toFlatObject, topicMatch, forMatchIterator}\n = require('./tools');\n\n/** Unset the topic in that obj, and clean up parent if empty, recursively.\nReturn the path to the removed node.\n*/\nconst unset = (obj, path) => {\n if (!path || path.length == 0) return;\n _.unset(obj, path);\n const parentPath = path.slice(0, -1);\n // _.get doesn't do the intuitive thing for the empty path, handle it ourselves\n const parent = parentPath.length == 0 ? obj : _.get(obj, parentPath);\n if (_.isEmpty(parent)) {\n return unset(obj, parentPath);\n } else {\n return path;\n }\n};\n\n/** Given a modifier `{\"a/b/c\": \"xyz\"}` update the object `obj` such that\n`obj.a.b.c = \"xyz\"`. */\nconst updateObject = (obj, modifier) => {\n _.forEach( modifier, (value, topic) => {\n const path = topicToPath(topic);\n if (value == null) {\n unset(obj, path);\n } else {\n _.set(obj, path, value);\n }\n });\n return obj;\n};\n\n/** Given an object and a path with wildcards (`*` and `+`), *modify* the object\nto only contain elements matched by the path, e.g.,\n`{a: {b: 1, c: 2}, d: 2}` and `['a','+']` would give `{a: {b: 1, c: 2}}`\n\n@param {object} obj - The object to select from\n@param {array} path - An array specifying the path to select, potentially\ncontaining mqtt wildcards ('+').\n*/\nconst selectFromObject = (obj, path) => {\n if (path.length == 0) return;\n const next = path[0];\n if (next) {\n for (let key in obj) {\n if (key != next && next != '*' && !next.startsWith('+')) {\n delete obj[key];\n } else {\n selectFromObject(obj[key], path.slice(1));\n }\n }\n }\n};\n\n\n/**\n* A class implementing a local data cache, used as a local data store with\n* deduplication detection and update events. While this class is very handy\n* you probably won't need to create instances of it directly. Instead use\n* the mqttSync.data instance which holds the locally stored data\n* subscribed/published from/to MQTTSync.\n* For example on the robot:\n* ```js\n* // update/publish our status:\n* mqttSync.data.update('status', {changed: Date.now(), msg: 'OK'});\n* // subscribe to new user requests (e.g., from UI):\n* mqttSync.data.subscribePath('+user/request', (request, key, {user}) => {\n* log.debug(`user ${user} made request`, request);\n* });\n* ```\n* In the cloud or in a web component you would need to use the full topic including\n* org, device, scope, cap-name, and version.\n*/\nclass DataCache {\n\n #data = {};\n #listeners = [];\n #flatListeners = [];\n\n constructor(data = {}) {\n this.#data = data;\n\n // for now add an alias\n this.subscribeTopic = this.subscribePath;\n }\n\n /** Update the object with the given value at the given path, remove empty;\n return the flat changes (see toFlatObject). Add `tags` to updates to mark\n them somehow based on the context, e.g., so that some subscriptions can choose\n to ignore updates with a certain tag.\n */\n updateFromArray(path, value, tags = {}) {\n // const empty = Object.keys(this.#data).length == 0; // object already empty\n const current = _.get(this.#data, path);\n if (value == null) {\n if (current === undefined || current === null) {\n return {}; // no change, do not call listeners\n } else {\n unset(this.#data, path);\n }\n } else {\n if (_.eq(current, value)) {\n // note: this is just a shallow equal, so replacing a sub-document\n // with an atomic copy of it should still trigger listeners.\n // TODO: Note also that when value is an object, we will set it by\n // reference here, so any changes made to that object will *not* trigger\n // listeners because `current` will already be changed -- which is\n // probably wrong. May want to always clone value first.\n return {}; // nothing to do, do not bother listeners\n }\n // console.log('setting', path, value);\n _.set(this.#data, path, value);\n // TODO: implement this ourselves so we can do better change-checking\n }\n\n const topic = pathToTopic(path);\n const obj = {[topic]: value};\n\n // flatten the value and combine eith topic (without reflattening the topic):\n let flatChanges;\n if (value instanceof Object) {\n const flatValue = toFlatObject(value);\n flatChanges = {};\n _.forEach(flatValue, (atomic, flatKey) => {\n flatChanges[`${topic}${flatKey}`] = atomic;\n });\n } else {\n flatChanges = obj;\n }\n\n // option 1. using flat changes (sub-documents are never atomic)\n // this.#listeners.forEach(fn => fn(flatChanges));\n\n // option 2. allow atomic sub-document changes\n this.#listeners.forEach(fn => fn(obj, tags));\n\n this.#flatListeners.forEach(fn => fn(flatChanges, tags));\n\n return flatChanges;\n }\n\n /** Update the value at the given path (array or dot separated string) */\n update(path, value, tags) {\n if (typeof path == 'string') {\n return this.updateFromTopic(path, value, tags);\n } else if (path instanceof Array) {\n return this.updateFromArray(path, value, tags);\n } else {\n throw new Error('unrecognized path expression');\n }\n }\n\n /** Set value from the given topic (with or without leading or trailing slash) */\n updateFromTopic(topic, value, tags) {\n return this.updateFromArray(topicToPath(topic), value, tags);\n }\n\n /** Update data from a modifier object where keys are topic names to be\n interpreted as paths, and values are the values to set */\n updateFromModifier(modifier, tags) {\n return _.map(modifier, (value, topic) =>\n this.updateFromTopic(topic, value, tags));\n }\n\n /** Add a callback for all change events. */\n subscribe(callback) {\n if (callback instanceof Function) {\n this.#listeners.push(callback);\n } else {\n console.warn('DataCache.subscribe expects a function as argument. Did you mean to use subscribePath?');\n }\n }\n\n /** Subscribe to a specific path (array) only. Callback receives\n `value, key, matched, tags`. */\n subscribePath(path, callback) {\n this.#listeners.push((changes, tags) => {\n _.forEach(changes, (value, key) => {\n const matched = topicMatch(path, key);\n matched && callback(value, key, matched, tags);\n });\n });\n }\n\n /** Subscribe to a specific topic only. Callback receives\n `value, key, matched, tags`. */\n subscribeTopic(topic, callback) {\n this.subscribePath(topic, callback);\n }\n\n /** Same as subscribePath but always get all changes in flat form */\n subscribePathFlat(topic, callback) {\n this.#flatListeners.push((changes, tags) => {\n _.forEach(changes, (value, key) => {\n const matched = topicMatch(topic, key);\n matched && callback(value, key, matched, tags);\n });\n });\n }\n\n /** Remove a callback previously registered using `subscribe`. */\n unsubscribe(callback) {\n this.#listeners = this.#listeners.filter(f => f != callback);\n }\n\n /** Get sub-value at path, or entire object if none given */\n get(path = []) {\n return path.length == 0 ? this.#data : _.get(this.#data, path);\n }\n\n /** Get sub-value specified by topic */\n getByTopic(topic) {\n return this.get(topicToPath(topic));\n }\n\n /** Filter the object using path with wildcards */\n filter(path) {\n const rtv = JSON.parse(JSON.stringify(this.get()));\n selectFromObject(rtv, path);\n return rtv;\n }\n\n /** Filter the object using topic with wildcards */\n filterByTopic(topic) {\n return this.filter(topicToPath(topic));\n }\n\n /** For each topic match, invoke the callback with the value, path, and match\n just like subscribePath, but on the current data rather than future changes. */\n forMatch(topic, callback) {\n const path = topicToPath(topic);\n this.forPathMatch(path, callback);\n }\n\n /** For each path match, invoke the callback with the value, path, and match\n just like subscribePath */\n forPathMatch(path, callback) {\n forMatchIterator(this.get(), path, callback);\n }\n};\n\nmodule.exports = {\n DataCache, updateObject\n}", "const dataCache = require('./DataCache');\nconst tools = require('./tools');\n\nmodule.exports = { ...dataCache, ...tools };", "'use strict';\n\nconst _ = require('lodash');\n\nconst { mqttParsePayload, topicMatch, topicToPath, pathToTopic,\ntoFlatObject, getLogger, mergeVersions, parseMQTTTopic, isSubTopicOf,\nversionCompare, encodeTopicElement, visitAncestor, getRandomId }\n = require('./common');\nconst { DataCache } = require('./datacache/DataCache');\n\n\nconst log = getLogger('MqttSync');\nlog.setLevel('info');\n\nconst HEARTBEAT_TOPIC = '$SYS/broker/uptime';\nconst specialKey = '$_'; // special key to reify \"value\" in publishedMessages\n\nconst noop = () => {};\n\n/* clone a mqtt payload, if necessary */\nconst clone = (payload) => {\n if (typeof payload == 'object') {\n return JSON.parse(JSON.stringify(payload));\n } else {\n return payload;\n }\n};\n\n/* return new string that ends in /# for sure */\nconst ensureHashSuffix = (topic) =>\n topic.endsWith('/#') ? topic :\n ( topic.endsWith('/') ? topic.concat('#') :\n topic.concat('/#') );\n\n/* given a path, replace any double slashes, '//', with single ones */\nconst resolveDoubleSlashes = (path) => path.replace(/\\/\\//g, '/');\n\n\n/** A class that combines DataCache and MQTT to implement a data synchronization\nfeature over the latter. Relies on retained messages in mqtt for persistence.\n* @param {object} options\n* @param {object} options.mqttClient - An already connected mqtt.js client.\n* @param {boolean} [options.ignoreRetain] - retain all messages, ignorant of the retain\n* flag.\n* @param {number} [options.sliceTopic] - a number indicating at what level to\n* slice the topic, i.e., only use a suffix. Used in robot-capabilities to slice\noff the topic prefix (namespaces).\n* @param {array} [options.migrate] - an array of objects of the form\n* `{topic, newVersion, level}`. Only meaningful in the cloud. Instructs MQTTSync\nto first migrate existing topics to a new version namespace, publishing at the\ndesignated level down from the version level. For example:\n```js\n[{ topic: `/myorg/mydevice/@local/my-cap/+/config`,\n newVersion: this.version,\n level: 1\n}]\n```\nWould migrate any existing data in the capability's `config` namespace to the\ncurrent version of the package, publishing at the `config/+` level (rather than\natomically at the config level itself).\n* @param {function} [options.onReady] - A function that is called when the MQTTSync\nclient is ready and has completed any requested migrations.\n* @param {function} [options.onChange] - A function that is called any time there\nis a change to the shared data. This is not usually used. It's usually better to\nuse the finer grained `MqttSync.data.subscribePath` instead, that allows you to\nsubscribe to changes just on a specific sun-object instead, see DataCache.\n*/\nclass MqttSync {\n\n data = new DataCache();\n\n /* Directory of paths we've subscribed to in this class; this matters\n because the same mqtt client may have subscriptions to paths that we don't\n care to store (sync). */\n subscribedPaths = {};\n\n publishedPaths = {}; // not used in atomic mode\n\n /* Store messages retained on mqtt so we can publish what is necessary to\n achieve the \"should-be\" state. Note that we cannot use a structured document\n for storing these publishedMessages since we need to be able to store separate\n values at non-leaf nodes in the object (just like mqtt, where you can have\n /a/b = 1 and /a/b/c = 1 at the same time). Note: not used in atomic mode.\n Note: we use specialKey in this DataCache to allow overlapping\n topics (e.g., `/a/b/$_ = 1` and `/a/$_ = {b: 2}`)\n */\n publishedMessages = new DataCache();\n\n /* The order in which we send retained messages matters, which is why we use\n a queue for sending things. Note that we here use the property of Map that it\n remembers insertion order of keys. */\n publishQueue = new Map();\n\n /* We need to keep a record of all received topics (not messages) so far in\n case we want to clear any of them. */\n receivedTopics = new Set();\n\n /* List of callbacks waiting for next heartbeat, gets purged with each\n heartbeat */\n heartbeatWaitersOnce = [];\n\n heartbeats = 0;\n\n beforeDisconnectHooks = [];\n\n rpcHandlers = {}; // handlers for incoming RPC requests\n rpcCallbacks = {}; // callback for RPC requests we've sent\n\n constructor({mqttClient, onChange, ignoreRetain, migrate, onReady,\n sliceTopic, onHeartbeatGranted }) {\n\n this.mqtt = mqttClient;\n this.sliceTopic = sliceTopic;\n\n this.mqtt.on('message', (topic, payload, packet) => {\n const payloadString = payload && payload.toString()\n // log.debug('got message', topic, payloadString.slice(0, 180),\n // payloadString.length > 180 ? `... (${payloadString.length} bytes)` : '',\n // packet.retain);\n\n if (topic == HEARTBEAT_TOPIC) {\n if (this.heartbeats > 0) { // ignore initial heartbeat (retained)\n this.heartbeatWaitersOnce.forEach(cb => cb());\n this.heartbeatWaitersOnce = [];\n }\n if (this.heartbeats == 1 && !migrate && onReady) onReady();\n this.heartbeats++;\n\n } else {\n this.receivedTopics.add(topic);\n // Do NOT parse payload just yet, since it may be binary and ignored by us\n\n let path = topicToPath(topic);\n log.debug('processing message', topic, path);\n if (sliceTopic) {\n path = path.slice(sliceTopic);\n topic = pathToTopic(path);\n }\n\n if (this.rpcHandlers[topic]) {\n const json = mqttParsePayload(payload);\n this.handleRPCRequest(topic, json);\n\n } else if (this.rpcCallbacks[topic]) {\n const json = mqttParsePayload(payload);\n this.handleRPCResponse(topic, json);\n\n } else if (packet.retain || ignoreRetain) {\n\n if (this.isPublished(topic)) {\n const json = mqttParsePayload(payload);\n // store plain messages, still stored in a structure, but values are\n // not interpreted; we just store them to undo them if necessary, e.g.,\n // for switching between atomic and non-atomic subdocuments\n // log.trace('setting publishedMessages', topic);\n this.publishedMessages.updateFromArray([...path, specialKey], json);\n\n // this.pubData.update(topic, json);\n // Still need to update the data so that we can detect changes we make\n // and publish them. But we need to break the reaction-chain to avoid\n // loops, so tag this update with 'published' and then ignore those\n // updates in this.publish.\n this.data.update(topic, json, {external: true});\n\n } else if (this.isSubscribed(topic)) {\n const json = mqttParsePayload(payload);\n\n log.debug('applying received update', topic);\n const changes = this.data.update(topic, json);\n onChange && Object.keys(changes).length > 0 && onChange(changes);\n }\n }\n // else: do not try to parse it, it might be a binary message sent\n // directly using the client (with or without retain)\n }\n });\n\n this.mqtt.subscribe(HEARTBEAT_TOPIC, {rap: true}, (err, granted) => {\n log.debug(HEARTBEAT_TOPIC, {granted});\n granted && granted.length > 0 && onHeartbeatGranted?.();\n });\n\n migrate?.length > 0 && this.migrate(migrate, () => {\n log.debug('done migrating');\n onReady && this.waitForHeartbeatOnce(onReady);\n });\n }\n\n /**\n * Publish all values at the given level of the given object under the given\n * topic (plus sub-key, of course).\n * TODO: Is this OK, or do we need to go through this.publish?\n */\n publishAtLevel(topic, value, level) {\n log.debug(`publishingAtLevel ${level}`, topic, value);\n\n if (level > 0) {\n _.forEach(value, (subValue, subKey) => {\n const subTopic = `${topic}/${encodeTopicElement(subKey)}`;\n log.debug(`publishing ${subTopic}`);\n this.publishAtLevel(subTopic, subValue, level - 1);\n });\n } else {\n this.mqtt.publish(topic, JSON.stringify(value), {retain: true}, (err) => {\n err && log.warn('Error when publishing migration result', err);\n });\n }\n }\n\n /** Migrate a list of `{topic, newVersion, transform}`. The version number in\n * topic will be ignored, and all versions' values will be merged, applied in\n * order, such that the latest version is applied last. `topic` may include\n * wildcards in the part before the version number but not after.\n *\n * Example:\n * ```js\n * mqttSync.migrate([{topic: '/+/dId/@scope/capname/+/b', newVersion: '1.2.0'}]\n * ```\n */\n migrate(list, onReady = undefined) {\n\n let toGo = list.length;\n if (toGo == 0) {\n onReady && onReady(); // in case an empty list was given\n return;\n }\n\n /* called each time one item is done */\n const oneDown = () => --toGo == 0 && onReady && onReady();\n\n list.forEach(({topic, newVersion, transform = undefined, flat = false,\n level = 0}) => {\n log.debug('migrating', topic, newVersion);\n const {organization, device, capability, sub} = parseMQTTTopic(topic);\n const prefix = `/${organization}/${device}/${capability}`;\n\n const suffix = sub.length == 0 ? '/#' : pathToTopic(sub);\n // suffix will have a leading slash\n const subTopic = `${prefix}/+${suffix}`;\n\n this.subscribe(subTopic, (err) => {\n if (err) {\n log.warn('Error during migration', err);\n oneDown();\n return;\n }\n\n const all = {};\n this.waitForHeartbeatOnce(() => {\n\n // for each match (prefix can include wildcards) merge everything\n this.data.forMatch(prefix, (value, path, match) => {\n // an actual (ground, aka. no wildcard) prefix\n const groundPrefix = pathToTopic(path);\n\n log.debug('got heartbeat', {prefix, topic, subTopic, suffix}, groundPrefix, value);\n if (!value) {\n // no data to migrate\n return;\n }\n // collect for cleanup\n Object.assign(all, value);\n\n const merged = mergeVersions(value, suffix, {maxVersion: newVersion});\n // get suffix in merged\n const suffixMergedValue = _.get(merged, topicToPath(suffix));\n log.debug({value, suffix, merged, suffixMergedValue});\n // ^ this will need to change to support wild-cards in suffix\n const transformed = transform ? transform(suffixMergedValue) :\n suffixMergedValue;\n\n // Publish the transformed value under the ground prefix as\n // `newVersion/suffix`\n const newTopic =\n resolveDoubleSlashes(`${groundPrefix}/${newVersion}/${suffix}`);\n log.debug('publishing merged', newTopic);\n\n if (flat) {\n const flatObj = toFlatObject(transformed);\n const newPath = topicToPath(newTopic);\n _.forEach(flatObj, (value, key) => {\n const keyTopic = pathToTopic(newPath.concat(topicToPath(key)));\n // TODO: Is this OK, or do we need to go through this.publish?\n this.mqtt.publish(keyTopic, JSON.stringify(value),\n {retain: true}, (err) => {\n err && log.warn(\n `Error when publishing migration result for ${key}`, err);\n });\n });\n\n } else {\n this.publishAtLevel(newTopic, transformed, level);\n }\n });\n\n this.unsubscribe(subTopic);\n\n if (Object.keys(all).length == 0) {\n // no data to migrate\n oneDown();\n return;\n }\n\n this.waitForHeartbeatOnce(() => {\n // now clear this suffix in the old version space\n const oldVersions = Object.keys(all).filter(v =>\n versionCompare(v, newVersion) < 0);\n // log.debug({oldVersions});\n\n const prefixesToClear = oldVersions.map(oldV =>\n resolveDoubleSlashes(`${prefix}/${oldV}/${suffix}`));\n\n this.clear(prefixesToClear);\n oneDown();\n });\n });\n });\n });\n }\n\n /** Delete all retained messages in a certain topic prefix, waiting for\n a mqtt broker heartbeat to collect existing retained. Use with care, never\n delete topics not owned by us. Harmless within capabilities, which are\n namespaced already.\n\n `options.filter(topic)`: a function that can be provided to further,\n programmatically filter the set of topics to clear, e.g., to onlt clear\n topics of old versions.\n\n Note: This may not yet work in robot-capabilities, since the subscription\n prefix and received topic prefix don't match (the device prefix is added to\n subscription by localMQTT.\n */\n clear(prefixes, callback = undefined, options = {}) {\n\n const toDelete = [];\n const collectToDelete = (topic) => {\n // there may be other mqtt subscriptions running, filter by topic\n prefixes.forEach(prefix =>\n topicMatch(`${prefix}/#`, topic)\n && (!options.filter || options.filter(topic))\n && toDelete.push(topic)\n );\n }\n this.mqtt.on('message', collectToDelete);\n // this only collects new topics, not those we've already received\n\n // subscribe to all\n prefixes.forEach(prefix => {\n if (typeof prefix == 'string') {\n this.mqtt.subscribe(`${prefix}/#`);\n } else {\n log.warn('Ignoring', prefix, 'since it is not a string.');\n }\n // add the topics we already know off:\n this.receivedTopics.forEach(topic => {\n if (topic.startsWith(prefix)) {\n log.debug('marking for deletion', `${prefix}${topic}`);\n toDelete.push(topic);\n }\n });\n });\n\n // value to use to clear, depending on node.js vs. browser\n const nullValue = (typeof Buffer != 'undefined' ? Buffer.alloc(0) : null);\n\n this.waitForHeartbeatOnce(() => {\n this.mqtt.removeListener('message', collectToDelete);\n prefixes.forEach(prefix => this.mqtt.unsubscribe(prefix));\n\n const count = toDelete.length;\n log.info(`clearing ${count} retained messages from ${prefixes}`);\n toDelete.forEach(topic => {\n this.mqtt.publish(topic, nullValue, {retain: true});\n });\n\n callback && callback(count);\n });\n };\n\n\n /** register a callback for the next heartbeat from the broker */\n waitForHeartbeatOnce(callback) {\n // need to wait a tick, in case we are still in the callback tree\n // of a previous heartbeat waiter\n setTimeout(() => this.heartbeatWaitersOnce.push(callback), 1);\n }\n\n /** check whether we are subscribed to the given topic */\n isSubscribed(topic) {\n return Object.keys(this.subscribedPaths).some(subscribedTopic =>\n topicMatch(subscribedTopic, topic));\n }\n\n /** Check whether we are publishing the given topic in a non-atomic way.\n This is used to determine whether to store the published value or not. */\n isPublished(topic) {\n return Object.keys(this.publishedPaths).some(subscribedTopic =>\n topicMatch(subscribedTopic, topic) &&\n !this.publishedPaths[subscribedTopic].atomic\n );\n }\n\n /** Subscribe to the given topic (and all sub-topics). The callback will\n indicate success/failure, *not* a message on the topic. */\n subscribe(topic, callback = noop) {\n topic = ensureHashSuffix(topic);\n log.debug('subscribing to', topic);\n if (this.subscribedPaths[topic]) {\n log.debug('already subscribed to', topic);\n callback();\n return;\n }\n\n this.mqtt.subscribe(topic, {rap: true}, (err, granted) => {\n log.debug('subscribe', topic, 'granted:', granted);\n if (granted && granted.some(grant => grant.topic == topic && grant.qos < 128)) {\n // granted\n this.subscribedPaths[topic] = 1;\n callback(null);\n } else {\n // let user know (somehow) when we don't get permission\n callback(`not permitted to subscribe to topic ${topic}, ${JSON.stringify(granted)}`);\n }\n });\n }\n\n unsubscribe(topic) {\n topic = ensureHashSuffix(topic);\n if (this.subscribedPaths[topic]) {\n this.mqtt.unsubscribe(topic);\n delete this.subscribedPaths[topic];\n }\n }\n\n /** Publish retained to MQTT, store as published, and return a promise */\n _actuallyPublish(topic, value) {\n // return new Promise((resolve, reject) =>\n // this.mqtt.publish(topic,\n // value == null ? null : JSON.stringify(value), // aka \"unparse payload\"\n // {retain: true},\n // (err) => {\n // // Note that this returns optimistically at QoS 0, and no error occurs\n // // even when we are not allowed to publish this topic/message, see\n // // https://github.com/mqttjs/MQTT.js/#publish. Only when the client\n // // disconnects it seems.\n // if (err) {\n // log.warn('error in _actuallyPublish:', err);\n // reject(err);\n // // TODO: if this happens, we may need to force a full-sync\n // } else {\n // resolve();\n // }\n // }));\n\n if (!this.mqtt.connected) {\n log.warn('not connected, not publishing', topic);\n return false;\n }\n log.debug('actually publishing', topic);\n this.mqtt.publish(topic,\n value == null ? null : JSON.stringify(value), // aka \"unparse payload\"\n {retain: true});\n return true;\n }\n\n /** Send all items in the queue in sequence, if any and if not already\n running. */\n // async _processQueue() {\n // if (this._processing) return; // already running (and probably waiting)\n //\n // this._processing = true;\n // while (this.publishQueue.length > 0) {\n // const {topic, value} = this.publishQueue.shift();\n // await this._actuallyPublish(topic, value);\n // }\n // this._processing = false;\n // }\n\n // when using Map\n _processQueue_rec(cb) {\n if (this.publishQueue.size > 0) {\n const [topic, value] = this.publishQueue.entries().next().value;\n // this.publishQueue.delete(topic);\n // this._actuallyPublish(topic, value).then(\n // () => this._processQueue_rec(cb),\n // cb); // always call cb, even in rejection case\n if (this._actuallyPublish(topic, value)) {\n this.publishQueue.delete(topic);\n this._processQueue_rec(cb);\n } else {\n // try again soon\n setTimeout(() => this._processQueue_rec(cb), 5000);\n }\n } else {\n cb();\n }\n }\n\n _processQueue() {\n if (this._processing) return; // already running (and probably waiting)\n\n this._processing = true; // semaphore\n this._processQueue_rec(() => this._processing = false);\n }\n\n /** Set delay between processing of publishing queue in milliseconds. This\n allows you to effectively throttle the rate at which this instance will\n publish changes. Note that updates to a topic already in the queue will not\n cause multiple publications. Only the latest value will be published.\n @param {number} [delay] - Number of milliseconds to wait between processing\n of publish queue.\n */\n setThrottle(delay) {\n this._processQueueThrottled =\n _.throttle(this._processQueue.bind(this), delay);\n }\n\n /** Clear the set throttling delay. */\n clearThrottle() {\n delete this._processQueueThrottled;\n }\n\n addToQueue(topic, value) {\n // this.publishQueue.push({topic, value});\n this.publishQueue.set(topic, value);\n }\n\n /** Add to publication queue */\n _enqueue(topic, value) {\n log.debug('enqueuing', topic);\n this.addToQueue(topic, value);\n if (this._processQueueThrottled) {\n this._processQueueThrottled();\n } else {\n this._processQueue();\n }\n // yes, this is optimistic, but if we don't, then upcoming changes\n // may not work as expected (e.g., when switching from flat to atomic to flat)\n const path = topicToPath(topic);\n this.publishedMessages.updateFromArray([...path, specialKey],\n value == null ? null : clone(value));\n }\n\n /** Register a listener for path in data. Make sure to populate the data\n before calling this or set the data all at once afterwards.\n\n With option \"atomic\" this will always send the whole sub-document,\n not flat changes. Useful, e.g., for desiredPackages, see\n https://github.com/chfritz/transitive/issues/85.\n\n @return true if publication added (false, e.g., when already present)\n */\n publish(topic, options = {atomic: false}) {\n topic = ensureHashSuffix(topic);\n\n if (_.isEqual(this.publishedPaths[topic], options)) {\n return false;\n // avoid double subscription\n }\n this.publishedPaths[topic] = options;\n\n if (options.atomic) {\n // this case is quite simple\n this.data.subscribePath(topic, (value, key, matched, tags) => {\n // do not re-publish changes received from external:\n if (tags?.external) return;\n\n log.debug('processing change (atomic)', key, topic);\n // instantiate topic according to key (topic may have wildcards)\n const topicWithoutHash = topic.slice(0, topic.length - 2);\n const groundedTopic = pathToTopic(\n // get length of topic (how many levels of selectors), get that many\n // levels from key prefix\n topicToPath(key).slice(0, topicToPath(topicWithoutHash).length)\n );\n this._enqueue(groundedTopic, this.data.getByTopic(groundedTopic));\n });\n return true;\n }\n\n this.mqtt.subscribe(topic);\n\n // second: keep them up to date by publishing updates as changes happen\n this.data.subscribePath(topic, (value, key, matched, tags) => {\n if (tags?.external) return;\n\n log.debug('processing change', key);\n\n /* First: establish clarity by ensuring that the object defined by the\n currently present retained messages under this path accurately reflect\n the current value of this.data (and if not, publish what is necessary to\n create consistency). */\n // first, clear/replace all messages below or above this sub-path (if any)\n const path = topicToPath(key);\n\n // Check flat to atomic\n const publishedSub = this.publishedMessages.get(path);\n _.each(publishedSub, (oldSubVal, oldSubKey) => {\n if (oldSubKey == specialKey) return true;\n // We are going from flat to atomic, i.e., we are publishing at a\n // higher level than before: clear out old sub-keys.\n\n // Find all sub-sub-keys that end in `specialKey`:\n const toClear = Object.keys(toFlatObject(oldSubVal))\n .filter(subkey => subkey.endsWith(specialKey));\n\n log.debug('flat->atomic: ', {toClear}, oldSubKey);\n // Clear them all:\n toClear.forEach(oldSubSubKey => {\n const oldKey = oldSubSubKey.slice(0, -(specialKey.length + 1));\n const clearKey = `${key}/${oldSubKey}/${oldKey}`\n // log.debug('flat->atomic: clear', clearKey);\n this._enqueue(clearKey, null);\n });\n });\n\n // Check atomic to flat\n const published = this.publishedMessages.get();\n visitAncestor(published, path.slice(0, -1), (subObj, prefix) => {\n const oldVal = subObj[specialKey];\n if (oldVal && _.isObject(oldVal)) {\n log.debug('atomic->flat', {oldVal});\n // A parent topic has been published. We are going from atomic to\n // separate values: need to transform existing sub-document to flat\n // values.\n\n // Remove the old published (atomic) message:\n const prefixTopic = pathToTopic(prefix);\n this._enqueue(prefixTopic, null);\n\n // Now re-add as separate flat messages\n const flat = toFlatObject(oldVal);\n _.each(flat, (flatValue, flatKey) => {\n const oldFlatKey = `${prefixTopic}${flatKey}`;\n this._enqueue(oldFlatKey, flatValue);\n })\n }\n });\n\n /* We need to first wait until all of the above messages are out;\n otherwise replacing an atomic `/a = {c: 1}` with `/a/c = 2` would create\n a race condition where it is not clear which message, the replacement\n c = 1 or the new c = 2, would be sent last (and hence retained). That's\n why we use a publishing queue in this class.\n */\n this._enqueue(key, value);\n return true;\n });\n }\n\n /** Run all registered hooks before disconnecting */\n beforeDisconnect() {\n this.beforeDisconnectHooks.forEach(fn => fn(this));\n }\n\n /** Register a new hook to be called before disconnecting */\n onBeforeDisconnect(fn) {\n this.beforeDisconnectHooks.push(fn);\n }\n\n /* --------------------------------------------------------------------------\n * Remote Procedure Calls (RPC)\n */\n\n /* Handle RPC requests */\n async handleRPCRequest(topic, json) {\n log.debug('handling RPC request for', topic, json);\n const handler = this.rpcHandlers[topic];\n const result = handler(json.args);\n\n const responseTopic = `${topic.replace('/request', '/response')}/${json.id}`;\n\n if (result instanceof Promise) {\n result.then( resultValue => this.mqtt.publish(responseTopic,\n JSON.stringify({ id: json.id, result: resultValue }),\n {retain: false, qos: 2}));\n } else {\n this.mqtt.publish(responseTopic,\n JSON.stringify({ id: json.id, result }),\n {retain: false, qos: 2});\n }\n }\n\n /* Handle RPC response */\n handleRPCResponse(topic, json) {\n log.debug('handle RPC response', topic, json);\n this.rpcCallbacks[topic](json.result);\n delete this.rpcCallbacks[topic];\n this.mqtt.unsubscribe(topic);\n }\n\n /** Register an RPC request handler. Example:\n * ```js\n * mqttSync.register('/mySquare', arg => {\n * log.debug('running /mySquare with args', arg);\n * return arg * arg;\n * });\n * ```\n * Note that the command topic needs to be in the capabilities namespace like\n * any other topic. In robot capabilities, as usual, these can start in `/`\n * because the local mqtt bridge operated by the robot agent will place all\n * topics in their respective namespace. In the cloud and on the web you will\n * need to use the respective namespace, i.e.,\n * `/orgId/deviceId/@scope/capName/capVersion/`.\n *\n * #### Async/Await\n * Yes, you can make the handler `async` and use `await` inside of it. This\n * will be handled correctly, i.e., MqttSync will await the result of the\n * handler before responding to the RPC request client.\n */\n register(command, handler) {\n log.debug('registering RPC handler for', command);\n const requestTopic = `${command}/request`;\n\n this.rpcHandlers[requestTopic] = handler;\n this.mqtt.subscribe(requestTopic, {rap: true, qos: 2}, (err, granted) => {\n if (err) {\n log.warn(`Error subscribing to RPC topic ${requestTopic}`, err);\n } else if (granted && granted.length == 0) {\n log.warn(`Not allowed to subscribe to RPC topic ${requestTopic}`);\n }\n });\n }\n\n /** Make an RPC request. Example:\n * ```js\n * mqttSync.call('/mySquare', 11, result => {\n * log.debug(`Called /mySquare with arg 11 and got ${result}`);\n * });\n * ```\n * Alternative you can omit the callback and use async/await:\n * ```js\n * const result = await mqttSync.call('/mySquare', 11);\n * log.debug(`Called /mySquare with arg 11 and got ${result}`);\n * ```\n * See the note about namespaces in `register`.\n *\n * Note: It is your responsibility to only call methods that exist (have been\n * registered). Calling a non-existent command just hangs.\n */\n call(command, args, callback = undefined) {\n const id = getRandomId();\n\n const responseTopic = `${command}/response/${id}`;\n this.mqtt.subscribe(responseTopic, {rap: true, qos: 2}, (err, granted) => {\n if (err) {\n log.warn(`Error subscribing to RPC response topic ${responseTopic}`, err);\n } else if (granted && granted.length == 0) {\n log.warn(`Not allowed to subscribe to RPC response topic ${responseTopic}`);\n }\n });\n\n const requestTopic = `${command}/request`\n log.debug('calling RPC', requestTopic);\n this.mqtt.publish(requestTopic, JSON.stringify({ id, args }),\n {retain: false, qos: 2});\n\n if (callback) {\n this.rpcCallbacks[responseTopic] = callback;\n } else {\n return new Promise((resolve, reject) => {\n this.rpcCallbacks[responseTopic] = resolve;\n });\n }\n }\n}\n\nmodule.exports = MqttSync;\n", "export * from './client/shared.jsx';\nexport * from './client/hooks.jsx';\nexport * from './client/client';\n", "import React, { useState, useEffect, useMemo, useRef } from 'react';\nimport { Button, Accordion, AccordionContext, Card, Badge }\n from 'react-bootstrap';\nimport ReactWebComponent from './react-web-component';\n\nimport { parseCookie, decodeJWT } from './client';\nimport { useCapability } from './hooks';\n\nconst styles = {\n badge: {\n width: '4em'\n },\n code: {\n color: '#700',\n borderLeft: '3px solid #aaa',\n padding: '0.5em 0px 0.5em 2em',\n backgroundColor: '#f0f0f0',\n borderRadius: '4px',\n marginTop: '0.5em',\n },\n inlineCode: {\n color: '#700',\n margin: '0px 0.5em 0px 0.5em',\n }\n};\n\nconst levelBadges = [\n <Badge bg=\"success\" style={styles.badge}>OK</Badge>,\n <Badge bg=\"warning\" style={styles.badge}>Warn</Badge>,\n <Badge bg=\"danger\" style={styles.badge}>Error</Badge>,\n <Badge bg=\"secondary\" style={styles.badge}>Stale</Badge>,\n];\n\n/* The right badge for the level */\nexport const LevelBadge = ({level}) => levelBadges[level] || <span>{level}</span>;\n\n/** Reusable component for showing code */\nexport const Code = ({children}) => <pre style={styles.code}>\n {children}\n</pre>;\n\nexport const InlineCode = ({children}) => <tt style={styles.inlineCode}>\n {children}\n</tt>;\n\n\nconst intervals = {};\n\nexport const TimerContext = React.createContext({});\nexport const Timer = ({duration, onTimeout, onStart, setOnDisconnect, children}) => {\n duration = duration || 60;\n const [timer, setTimer] = useState(duration);\n const [running, setRunning] = useState(false);\n const id = useMemo(() => Math.random().toString(36).slice(2), []);\n\n const stop = () => {\n console.log('stopping timer for', id);\n onTimeout && setTimeout(onTimeout, 1);\n clearInterval(intervals[id]);\n intervals[id] = null;\n setRunning(false);\n };\n\n const startTimer = () => {\n const interval = intervals[id];\n console.log(interval, intervals, timer);\n if (!interval && timer > 0) {\n setRunning(true);\n intervals[id] = setInterval(() =>\n setTimer(t => {\n if (--t > 0) {\n return t;\n } else {\n stop();\n }\n }), 1000);\n onStart && setTimeout(onStart, 1);\n }\n\n return stop;\n };\n\n useEffect(() => { timer > 0 && !running && startTimer() }, [timer]);\n\n useEffect(() => stop, []);\n\n setOnDisconnect && setOnDisconnect(() => {\n // call on disconnect of the web component\n stop()\n });\n\n const reset = () => setTimer(duration);\n\n return <TimerContext.Provider value={{reset, duration, timer}}>\n {timer > 0 ? <div>\n {children}\n {timer < 60 && <div>Timeout in: {timer} seconds</div>}\n </div> :\n <div>Timed out. <Button onClick={reset}>\n Resume\n </Button>\n </div>}\n </TimerContext.Provider>;\n};\n\n\n/** Dynamically load and use the Transitive web component specified in the JWT.\n* Embedding Transitive components this way also enables the use of functional\n* and object properties, which get lost when using the custom element (Web\n* Component) because HTML attributes are strings.\n* Example:\n* ```jsx\n* <TransitiveCapability jwt={jwt}\n* myconfig={{a: 1, b: 2}}\n* onData={(data) => setData(data)}\n* onclick={() => { console.log('custom click handler'); }}\n* />\n* ```\n*\n* Always loads the capability specified in the JWT and will default to the\n* main component for that JWT (`-device` or `-fleet`). To specify a secondary\n* component offered by the capability specify `component`, e.g., to load\n* `webrtc-video-supervisor` instead of `webrtc-video-device`, provide a device\n* JWT for webrtc-video and use:\n* ```jsx\n* <TransitiveCapability jwt={jwt}\n* component='webrtc-video-supervisor'\n* auto=\"true\"\n* />\n* ```\n*/\nexport const TransitiveCapability = ({\n jwt, host = 'transitiverobotics.com', ssl = true, ...config\n }) => {\n\n const assertPresent = (value, name) => {\n if (!value) throw new Error(`JWT is missing ${name}`);\n };\n\n const {id, device, capability} = decodeJWT(jwt);\n // Throw an error when any of the above payload is missing\n assertPresent(id, 'id');\n assertPresent(device, 'device');\n assertPresent(capability, 'capability');\n\n const type = device == '_fleet' ? 'fleet' : 'device';\n const capName = capability.split('/')[1];\n const name = `${capName}-${type}`;\n const component = config.component || name;\n\n const { loaded } = useCapability({\n capability,\n name,\n userId: id || config.userId, // accept both id and userId, see #492\n deviceId: device,\n host,\n ssl\n });\n\n const ref = useRef();\n // Attach functional and object properties to the component when ready and\n // on change\n useEffect(() => {\n ref.current?.instance?.setState(s =>\n ({ ...s, id, jwt, host, ssl, ...config }));\n }, [ref.current, loaded, id, jwt, host, ssl, ...Object.values(config)]);\n\n // Disrupt the reactive chain of the MutationObserver to the customElement,\n // so we are not competing with it for updating the props.\n const propClone = useMemo(() => ({id, jwt, host, ssl, ...config}), []);\n\n if (!loaded) return <div>Loading {name}</div>;\n return React.createElement(component, {...propClone, ref});\n };\n\n\n/** A simple error boundary. Usage:\n* ```jsx\n* <ErrorBoundary message=\"Something went wrong\">\n* <SomeFlakyComponent />\n* </ErrorBoundary>\n* ```\n*/\nexport class ErrorBoundary extends React.Component {\n constructor(props) {\n super(props);\n this.state = {\n hasError: false,\n messages: [],\n };\n }\n\n static getDerivedStateFromError(error) {\n return { hasError: true };\n }\n\n componentDidCatch(error, errorInfo) {\n console.warn('ErrorBoundary caught:', error, errorInfo);\n this.setState(({messages}) => ({messages: [...messages, error.message]}));\n }\n\n render() {\n return (this.state.hasError ? <div>\n Error: {this.props.message || this.state.messages?.join(', ')\n || 'Something went wrong here.'}\n </div>\n : this.props.children);\n }\n};\n\n\nexport const CapabilityContext = React.createContext({});\n\n/* Only used internally: the actual context provider, given the loaded module */\nconst LoadedCapabilityContextProvider = (props) => {\n const {children, jwt, id, host, ssl, loadedModule} = props;\n\n const context = loadedModule.provideContext?.({\n jwt, id, host, ssl, appReact: React\n });\n\n return <CapabilityContext.Provider value={{ ...context }}>\n {children}\n </CapabilityContext.Provider>;\n};\n\n/**\n* Context provider for capabilities. Use this to access the front-end API\n* provided by some capabilities. Example:\n* ```jsx\n* <CapabilityContextProvider jwt={jwt}>\n* <MyROSComponent />\n* </CapabilityContextProvider>\n* ```\n* where `jwt` is a JWT for a capability that exposes a front-end API. Then use\n* `useContext` in `MyROSComponent` to get the exposed data and functions, e.g.:\n* ```jsx\n* const MyROSComponent = () => {\n* const { ready, subscribe, data } = useContext(CapabilityContext);\n* // When ready, subscribe to the `/odom` topic in ROS1\n* useEffect(() => { ready && subscribe(1, '/odom'); }, [ready]);\n* return <pre>{JSON.stringify(data, true, 2)}</pre>;\n* }\n* ```\n* Where `ready`, `subscribe`, and `data` are reactive variables and functions\n* exposed by the capability of the provided JWT. In this example, the latest\n* message from the subscribed ROS topics will be available in the capabilities\n* namespace in `data`.\n* @param {object} props\n*/\nexport const CapabilityContextProvider =\n ({children, jwt, host = undefined, ssl = undefined}) => {\n\n const {id, device, capability} = decodeJWT(jwt);\n const type = device == '_fleet' ? 'fleet' : 'device';\n const capName = capability.split('/')[1];\n const name = `${capName}-${type}`;\n\n const {loaded, loadedModule} = useCapability({\n capability,\n name,\n userId: id,\n deviceId: device,\n appReact: React,\n host,\n ssl\n });\n\n if (!loadedModule) return <div>Loading {capability}</div>;\n return <LoadedCapabilityContextProvider {...{jwt, id, host, ssl, loadedModule}}>\n {children}\n </LoadedCapabilityContextProvider>;\n };\n\n\n/* whether or not the given react component allows refs, i.e., is either\n * a functional component wrapped with forwardRef or a class component */\nconst componentPermitsRefs = (Component) =>\n (Component.$$typeof == Symbol.for('react.forward_ref'))\n || Component.prototype?.render;\n\n\n/** Create a WebComponent from the given react component and name that is\n* reactive to all attributes. Used in web capabilities. Example:\n* ```js\n* createWebComponent(Diagnostics, 'health-monitoring-device', TR_PKG_VERSION);\n* ```\n*/\nexport const createWebComponent = (Component, name, version = '0.0.0',\n options = {}) => {\n\n // Only create a ref if the component accepts it. This avoids an ugly\n // error in the console when trying to give a ref to a non-forwardRef-wrapped\n // functional component.\n const compRef = componentPermitsRefs(Component) ? React.createRef() : null;\n\n class Wrapper extends React.Component {\n\n onDisconnect = null;\n state = {};\n\n componentDidMount() {\n this.props._element.instance = this;\n this.webComponentConstructed(this.props._element);\n this.props._element.callLifeCycleHook('connectedCallback');\n }\n\n /* function used by `Component` to register a onDisconnect handler */\n setOnDisconnect(fn) {\n this.onDisconnect = fn;\n }\n\n webComponentConstructed(instance) {\n // Observe all changes to attributes and update React state from it\n const observer = new MutationObserver((mutationRecords) => {\n const update = {};\n mutationRecords.forEach(({attributeName}) => {\n update[attributeName] = instance.getAttribute(attributeName);\n });\n this.setState(old => ({...old, ...update}));\n }).observe(instance, { attributes: true });\n }\n\n webComponentDisconnected() {\n // This ensures that the react component unmounts and all useEffect\n // cleanups are called.\n this.setState({_disconnected: true});\n try {\n this.onDisconnect && this.onDisconnect();\n } catch (e) {\n console.log('Error during onDisconnect of web-component', e);\n }\n }\n\n /* method exposed to the wrapped component via prop that allows setting\n * the \"config\" state variable inside the wrapper (not the component\n * itself). This config is retrieved by the portal for inclusion in the\n * embedding instructions. */\n setConfig(config) {\n this.setState({config});\n }\n\n render() {\n const stylesheets = options.stylesheets || [\n // 'https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css'\n // Bootstrap 5.3.2 css scoped to `.transitive-bs-root`:\n 'https://cdn.jsdelivr.net/gh/transitiverobotics/transitive-utils@0.8.3/web/css/bootstrap_transitive-bs-root.min.css'\n ];\n\n return <div id={`cap-${name}-${version}`}\n className={options.className || 'transitive-bs-root'}>\n <style>\n {stylesheets.map(url => `@import url(${url});`)}\n </style>\n\n {!this.state._disconnected &&\n <Component ref={compRef}\n {...this.props}\n // Important to keep state *after* props for reactivity to work\n {...this.state}\n setOnDisconnect={this.setOnDisconnect.bind(this)}\n setConfig={this.setConfig.bind(this)}\n />}\n </div>;\n }\n };\n\n return ReactWebComponent.create(Wrapper, name, options.shadowDOM || false,\n compRef);\n };\n", "// It is OK to use paths outside of this package because webpack will bundle them\nexport * from '../../common/common.js';\nexport * from '../../common/datacache';\nimport MS from '../../common/MqttSync.js';\nexport const MqttSync = MS;\n\n// moved to common\n// export const decodeJWT = (jwt) => JSON.parse(atob(jwt.split('.')[1]));\n\n/** parse document cookies */\nexport const parseCookie = str =>\n str.split(';')\n .map(v => v.split('='))\n .reduce((acc, v) => {\n acc[decodeURIComponent(v[0].trim())] =\n v[1] && decodeURIComponent(v[1].trim());\n return acc;\n }, {});\n\n/** get or post (if body given) json */\nexport const fetchJson = (url, callback, options = {}) => {\n fetch(url, {\n method: options.method || (options.body ? 'post' : 'get'),\n mode: 'cors',\n cache: 'no-cache',\n // Maybe we'll need this (when embedding)?\n // credentials: 'same-origin', // include, *same-origin, omit\n headers: {\n 'Content-Type': 'application/json',\n ...options.headers\n },\n redirect: 'follow',\n referrerPolicy: 'no-referrer',\n body: options.body ? JSON.stringify(options.body) : undefined\n }).then(res => {\n const error = !res.ok &&\n `fetching ${url} failed: ${res.status} ${res.statusText}`;\n res.json()\n .then(data => callback(error, data))\n .catch(err => {\n throw new Error(err);\n });\n }).catch((error) => callback(`error: ${error}`));\n};\n", "import React, { useState, useEffect, useMemo } from 'react';\nimport _ from 'lodash';\n// import mqtt1 from 'mqtt';\nimport mqtt from 'mqtt/dist/mqtt.esm';\n\nimport { decodeJWT, getLogger, clone, pathToTopic, mergeVersions, topicToPath }\n from './client';\nconst MqttSync = require('../../common/MqttSync');\n\nconst log = getLogger('utils-web/hooks');\nlog.setLevel('info');\n\nconst RECONNECT_PERIOD_DEFAULT = 1000; // default time until mqtt retries connecting\nconst RECONNECT_PERIOD_MAX = 20000; // max retry time (after dynamic backoff)\n\n/** Hook for using MqttSync in React.\n* @returns {object} An object `{data, mqttSync, ready, StatusComponent, status}`\n* where:\n* `data` is a reactive data source in React containing all the data received by\n* mqttsync,\n* `mqttSync` is the MqttSync object itself,\n* `ready` indicates when mqttSync is ready to be used (connected and received\n* successfully subscribed to mqtt system heartbeats)\n*/\nexport const useMqttSync = ({jwt, id, mqttUrl, appReact}) => {\n const { useState, useRef, useEffect } = appReact || React;\n\n const [status, setStatus] = useState('connecting');\n const [mqttSync, setMqttSync] = useState();\n const [data, setData] = useState({});\n // True once the subscription to the system heartbeat has been granted.\n const [heartbeatGranted, setHeartbeatGranted] = useState(false);\n\n useEffect(() => {\n const payload = decodeJWT(jwt);\n\n // pre-check validity of JWT, don't use if expired\n const { validity, iat } = payload;\n if (!validity || !iat || (iat + validity) * 1e3 < Date.now()) {\n const error = 'The provided JWT is invalid or expired.';\n log.warn(error, payload);\n setStatus(`error: ${error}`);\n return;\n }\n\n /** Implement dynamic backoff when we fail to connect. */\n let reconnectPeriod = RECONNECT_PERIOD_DEFAULT; // default to start with\n const transformWsUrl = (url, options, client) => {\n options.reconnectPeriod = reconnectPeriod;\n log.info(`reconnect in ${options.reconnectPeriod} s`);\n return url;\n }\n\n log.debug('(re-)create mqtt client');\n const client = mqtt.connect(mqttUrl, {\n username: JSON.stringify({id, payload}),\n password: jwt,\n transformWsUrl\n });\n\n // Increase backoff with each close (since we can't actually detect auth\n // errors)\n client.on('close', () =>\n reconnectPeriod = Math.min(reconnectPeriod * 2, RECONNECT_PERIOD_MAX)\n );\n\n // reset to default after a successful connection\n client.on('connect', () => reconnectPeriod = RECONNECT_PERIOD_DEFAULT);\n\n client.once('connect', () => {\n log.debug('MQTT connected');\n\n const mqttSyncClient = new MqttSync({\n mqttClient: client,\n ignoreRetain: true,\n onHeartbeatGranted: () => setHeartbeatGranted(true)\n });\n setMqttSync(mqttSyncClient);\n setStatus('connected');\n\n // Update data on change. Note: need to clone object to force reaction\n mqttSyncClient.data.subscribe(_.throttle(() =>\n setData(clone(mqttSyncClient.data.get())), 50));\n });\n\n client.on('error', (error) => {\n log.error(error);\n setStatus(`error: ${error}`);\n });\n\n return () => {\n log.info('cleaning up useMQTTSync');\n if (mqttSync && mqttSync.beforeDisconnect) {\n mqttSync.beforeDisconnect();\n mqttSync.waitForHeartbeatOnce(() => client.end());\n } else {\n client.end();\n }\n };\n }, [jwt, id]);\n\n return {\n status,\n // ready: status == 'connected',\n ready: heartbeatGranted,\n StatusComponent: () => <div>{status}</div>,\n mqttSync, // Note: mqttSync.data is not reactive.\n data, // This is a reactive data-source (to use meteor terminology).\n };\n};\n\n/** Hook for using Transitive in React. Connects to MQTT, establishes sync, and\n* exposes reactive `data` state variable. */\nexport const useTransitive =\n ({jwt, id, capability, versionNS, appReact,\n host = 'transitiverobotics.com', ssl = true }) => {\n\n const [scope, capabilityName] = capability.split('/');\n\n const { device } = decodeJWT(jwt);\n const prefixPath = [id, device, scope, capabilityName];\n const prefix = pathToTopic(prefixPath);\n const prefixPathVersion = [...prefixPath, versionNS];\n const prefixVersion = pathToTopic(prefixPathVersion);\n\n const mqttUrl = `${ssl && JSON.parse(ssl) ? 'wss' : 'ws'}://mqtt.${host}`;\n const fromMqttSync = useMqttSync({ jwt, id, mqttUrl, appReact });\n\n return {...fromMqttSync, device, prefixPath, prefix, prefixPathVersion,\n prefixVersion};\n };\n\n\n/** Subscribe to MqttSync topics using the provided JWT. This will\n* automatically find which version of the capability named in the JWT is running\n* on the device of the JWT and get the data for that version.\n*\n* Example usage (with webrtc-video):\n*\n* ```js\n* const { agentStatus, topicData } = useTopics({ jwt, topics: [\n* '/options/videoSource',\n* '/stats/+/log/'\n* ]});\n* ```\n*\n* @param {object} options An object containing:\n* `JWT`: A list of subtopics of the capability named in the JWT.\n* `topics`: A list of subtopics of the capability named in the JWT.\n* @returns {object} An object `{data, mqttSync, ready, agentStatus, topicData}`\n* where:\n* `agentStatus` is the `status` field of the running robot agent, including\n* heartbeat and runningPackages, and\n* `topicData` is the data for the selected topics of the capability\n*/\nexport const useTopics = ({jwt, host = 'transitiverobotics.com', ssl = true,\n topics = [], appReact}) => {\n\n const { useState, useEffect } = appReact || React;\n\n // We need to make sure we don't resubscribe (below) when this function\n // is called with the same content of `topics` but a different object.\n const [topicList, setTopicList] = useState();\n !_.isEqual(topicList, topics) && setTopicList(topics);\n\n const {device, id, capability} = decodeJWT(jwt);\n if (device == '_fleet') {\n log.warn('useTopics only works for device JWTs, not _fleet ones');\n return;\n }\n\n const agentPrefix = `/${id}/${device}/@transitive-robotics/_robot-agent/+/status`;\n\n const {mqttSync, data, status, ready, StatusComponent} =\n useMqttSync({jwt, id, mqttUrl: `ws${ssl ? 's' : ''}://mqtt.${host}`, appReact});\n\n useEffect(() => {\n if (ready) {\n mqttSync.subscribe(agentPrefix, (err) => err && console.warn(err));\n }\n }, [mqttSync, ready]);\n\n const agentStatus = mergeVersions(\n data[id]?.[device]['@transitive-robotics']['_robot-agent'], 'status').status;\n const runningPackages = agentStatus?.runningPackages;\n\n const [scope, capName] = capability.split('/');\n const versions = runningPackages?.[scope]?.[capName];\n const runningVersion = versions && Object.values(versions).filter(Boolean)[0];\n const prefix = `/${id}/${device}/${capability}/${runningVersion}`;\n\n useEffect(() => {\n log.debug('topics', topics);\n if (runningVersion) {\n topics.forEach(topic => {\n log.debug(`subscribing to ${prefix}${topic}`);\n mqttSync.subscribe(`${prefix}${topic}`,\n (err) => err && log.warn(err));\n });\n }\n }, [topicList, runningVersion, mqttSync]);\n\n const topicData = _.get(data, topicToPath(prefix));\n // log.debug(data, agentStatus, topicData);\n\n return {data: data?.[id]?.[device], mqttSync, agentStatus, topicData};\n };\n\n\nconst listeners = {};\nconst loadedModules = {};\n/** Hook to load a Transitive capability. Besides loading the custom element,\n* this hook also returns any functions and objects the component exports in\n* `loadedModule`. Example:\n* ```js\n* const {loaded, loadedModule} = useCapability({\n* capability: '@transitive-robotics/terminal',\n* name: 'mock-device',\n* userId: 'user123',\n* deviceId: 'd_mydevice123',\n* });\n* ```\n*/\nexport const useCapability = ({ capability, name, userId, deviceId,\n host = 'transitiverobotics.com', ssl = true, appReact\n }) => {\n const { useState, useEffect } = appReact || React;\n\n const [returns, setReturns] = useState({ loaded: false });\n\n // called when loaded\n const done = (message, theModule) => {\n log.debug(`custom component ${name}: ${message}`);\n loadedModules[name] = theModule;\n setReturns(x => ({...x, loadedModule: theModule, loaded: !!theModule}));\n };\n\n /** set the returns for all listeners */\n const notifyListeners = (...args) => listeners[name].forEach(l => l(...args));\n\n useEffect(() => {\n log.debug(`loading custom component ${name}`);\n\n if (loadedModules[name]) {\n return done('already loaded', loadedModules[name]);\n }\n if (listeners[name]) {\n log.debug('already loading');\n // get notified when loading completes\n listeners[name].push(done);\n return;\n }\n listeners[name] = [done];\n\n const baseUrl = `http${ssl ? 's' : ''}://portal.${host}`;\n const params = new URLSearchParams({ userId, deviceId });\n // filename without extension as we'll try multiple\n const fileBasename = `${baseUrl}/running/${capability}/dist/${name}`;\n\n /* Since some users use webpack and webpack is stupid, we need to use\n this magic comment for it to ignore these (remote) requests, see:\n https://webpack.js.org/api/module-methods/#webpackignore. */\n import(/* webpackIgnore: true */\n `${fileBasename}.esm.js?${params.toString()}`).then(\n esm => notifyListeners('loaded esm', esm),\n error => {\n log.warn(`No ESM module found for ${name}, loading iife`, error);\n import(/* webpackIgnore: true */\n `${fileBasename}.js?${params.toString()}`).then(\n iife => notifyListeners('loaded iife', iife),\n error => log.error(`Failed to load ${name} iife`, error));\n });\n }, [capability, name, userId, deviceId]);\n\n return returns;\n };\n\n\n"],
5
+ "mappings": "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",
6
+ "names": ["module", "module", "attribute", "module", "React", "styles", "module", "_", "topicToPath", "pathToTopic", "module", "module", "_", "topicToPath", "pathToTopic", "getLogger", "clone", "decodeJWT", "prefix", "mergeVersions", "module", "_", "topicToPath", "pathToTopic", "module", "module", "_", "topicToPath", "pathToTopic", "getLogger", "mergeVersions", "log", "clone", "MqttSync", "value", "err", "import_react", "MS", "MqttSync", "useState", "useRef", "useEffect", "React", "client", "mqtt", "_", "error", "React", "name", "React", "ReactWebComponent"]
7
7
  }
package/docs/client.md CHANGED
@@ -49,6 +49,10 @@ createWebComponent(Device, `${capabilityName}-device`, ['jwt']);
49
49
 
50
50
  <!-- Generated by documentation.js. Update this documentation by updating the source code. -->
51
51
 
52
+ ## reconnectPeriod
53
+
54
+ Implement dynamic backoff when we fail to connect.
55
+
52
56
  ## ErrorBoundary
53
57
 
54
58
  **Extends React.Component**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@transitive-sdk/utils-web",
3
- "version": "0.13.0",
3
+ "version": "0.14.0",
4
4
  "description": "Web utils for the Transitive framework",
5
5
  "homepage": "https://transitiverobotics.com",
6
6
  "repository": {