smart-home-engine 1.20.4 → 1.20.6

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.
@@ -1,4 +1,4 @@
1
- import{m as O}from"./monaco-langs-Dt8a9eeo.js";import{t as I}from"./index-xX-8bkDA.js";/*!-----------------------------------------------------------------------------
1
+ import{m as O}from"./monaco-langs-Dt8a9eeo.js";import{t as I}from"./index-D-DESdgj.js";/*!-----------------------------------------------------------------------------
2
2
  * Copyright (c) Microsoft Corporation. All rights reserved.
3
3
  * Version: 0.52.2(404545bded1df6ffa41ea0af4e8ddb219018c6c1)
4
4
  * Released under the MIT license
@@ -172,7 +172,7 @@
172
172
  }
173
173
  })();
174
174
  </script>
175
- <script type="module" crossorigin src="/assets/index-xX-8bkDA.js"></script>
175
+ <script type="module" crossorigin src="/assets/index-D-DESdgj.js"></script>
176
176
  <link rel="modulepreload" crossorigin href="/assets/monaco-langs-Dt8a9eeo.js">
177
177
  <link rel="stylesheet" crossorigin href="/assets/monaco-langs-DyX1CsEw.css">
178
178
  <link rel="stylesheet" crossorigin href="/assets/index-B4M4MeEk.css">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "smart-home-engine",
3
- "version": "1.20.4",
3
+ "version": "1.20.6",
4
4
  "description": "Node.js based script runner for use in MQTT based Smart Home environments",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
package/src/index.js CHANGED
@@ -547,8 +547,13 @@ if (config.url) {
547
547
  state.ts = new Date().getTime();
548
548
  }
549
549
  oldState = store.getObject('mqtt::' + topic) || {};
550
- if (oldState.val !== state.val) {
551
- state.lc = state.ts;
550
+ // lc (last change): prefer a payload-provided value; otherwise set it
551
+ // on value change and carry the previous lc over when the value is
552
+ // unchanged. Previously the old lc was simply lost on repeated
553
+ // identical values, so she.mqtt.age() returned NaN for topics whose
554
+ // payloads don't carry their own lc (B5).
555
+ if (state.lc === undefined) {
556
+ state.lc = oldState.val !== state.val ? state.ts : (oldState.lc ?? state.ts);
552
557
  }
553
558
  store.setObject('mqtt::' + topic, state);
554
559
  stateChange(topic, state, oldState, msg);
@@ -588,6 +588,13 @@ function _broadcastNodeAttributes(node, nodeId) {
588
588
  value: _jsonSafe(value),
589
589
  ts: Date.now(),
590
590
  });
591
+ // Device/endpoint labels feed the device list — rebroadcast it
592
+ // when they change. This is also what completes a rename():
593
+ // the local mirror only learns the new nodeLabel when the
594
+ // device's subscription report arrives, i.e. exactly now.
595
+ if (attrName === 'nodeLabel' || attrName === 'productName') {
596
+ _broadcast?.({ type: 'matter:deviceList', devices: listPaired() });
597
+ }
591
598
  });
592
599
  count++;
593
600
  }
@@ -52,9 +52,15 @@ module.exports = function (she, ctx = {}) {
52
52
  she.setValue(target, val);
53
53
  });
54
54
  },
55
- /** Seconds since the topic's value last changed. */
56
- age: function Sandbox_mqtt_age(topic) {
57
- return Math.round((new Date().getTime() - she.getProp(topic, 'lc')) / 1000);
55
+ /**
56
+ * Seconds since the topic's value last changed.
57
+ * Pass 'message' (or 'ts') as second argument to get the seconds since
58
+ * the last received message instead — repeated identical values reset
59
+ * that clock, useful for sensor heartbeat checks.
60
+ */
61
+ age: function Sandbox_mqtt_age(topic, mode) {
62
+ const prop = mode === 'message' || mode === 'ts' ? 'ts' : 'lc';
63
+ return Math.round((new Date().getTime() - she.getProp(topic, prop)) / 1000);
58
64
  },
59
65
  /**
60
66
  * Publish 1 to target when any source is truthy, 0 otherwise.
@@ -148,7 +154,8 @@ module.exports = function (she, ctx = {}) {
148
154
  she.http = {
149
155
  /**
150
156
  * Fetch a URL and return a Promise that resolves to the response body.
151
- * Resolves to parsed JSON when the Content-Type is application/json, plain text otherwise.
157
+ * Resolves to parsed JSON when the Content-Type is application/json and
158
+ * the body parses; falls back to the raw text body when parsing fails.
152
159
  * Rejects on non-2xx responses.
153
160
  * @param {string} url
154
161
  * @param {RequestInit} [options]
@@ -171,7 +178,15 @@ module.exports = function (she, ctx = {}) {
171
178
  const promise = fetch(url, { ...options, signal })
172
179
  .then(async (r) => {
173
180
  const ct = r.headers.get('content-type') || '';
174
- const body = ct.includes('json') ? await r.json() : await r.text();
181
+ const text = await r.text();
182
+ let body = text;
183
+ if (ct.includes('json')) {
184
+ try {
185
+ body = JSON.parse(text);
186
+ } catch {
187
+ // Content-Type lied — deliver the raw body instead of throwing
188
+ }
189
+ }
175
190
  const headers = {};
176
191
  r.headers.forEach((v, k) => {
177
192
  headers[k] = v;