smart-home-engine 1.20.7 → 1.20.9
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-
|
|
1
|
+
import{m as O}from"./monaco-langs-Dt8a9eeo.js";import{t as I}from"./index-C6zGQcmq.js";/*!-----------------------------------------------------------------------------
|
|
2
2
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
3
|
* Version: 0.52.2(404545bded1df6ffa41ea0af4e8ddb219018c6c1)
|
|
4
4
|
* Released under the MIT license
|
package/dist/web/index.html
CHANGED
|
@@ -172,7 +172,7 @@
|
|
|
172
172
|
}
|
|
173
173
|
})();
|
|
174
174
|
</script>
|
|
175
|
-
<script type="module" crossorigin src="/assets/index-
|
|
175
|
+
<script type="module" crossorigin src="/assets/index-C6zGQcmq.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-C3njyEHY.css">
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -303,9 +303,32 @@ let _sentinelValue = null; // unique value for this boot's sentinel
|
|
|
303
303
|
const _STARTUP_TIMEOUT_MS = 10000; // ms to wait for broker before starting anyway
|
|
304
304
|
const _SENTINEL_TIMEOUT_MS = config.sentinelTimeout; // ms to wait for sentinel after connecting
|
|
305
305
|
|
|
306
|
-
|
|
307
|
-
|
|
306
|
+
// Script start waits on two gates: MQTT retained state (sentinel) and — when
|
|
307
|
+
// the Matter controller is enabled — controller startup, so scripts using
|
|
308
|
+
// she.matter.* at top level don't fail with "Matter controller not started".
|
|
309
|
+
let _mqttGate = false;
|
|
310
|
+
let _matterGate = !config.matterStorage; // pre-open when matter is disabled
|
|
311
|
+
|
|
312
|
+
function _maybeStart() {
|
|
313
|
+
if (_started || !_mqttGate || !_matterGate) {
|
|
314
|
+
if (!_started && _mqttGate && !_matterGate) {
|
|
315
|
+
log.info('waiting for matter controller before starting scripts');
|
|
316
|
+
}
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
308
319
|
_started = true;
|
|
320
|
+
start();
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function matterGateOpen() {
|
|
324
|
+
if (_matterGate) return;
|
|
325
|
+
_matterGate = true;
|
|
326
|
+
_maybeStart();
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function startOnce(reason) {
|
|
330
|
+
if (_started || _mqttGate) return;
|
|
331
|
+
_mqttGate = true;
|
|
309
332
|
if (_startupTimeout) {
|
|
310
333
|
clearTimeout(_startupTimeout);
|
|
311
334
|
_startupTimeout = null;
|
|
@@ -316,7 +339,7 @@ function startOnce(reason) {
|
|
|
316
339
|
}
|
|
317
340
|
if (reason) log.info(reason);
|
|
318
341
|
broadcast({ type: 'mqtt:status', ready: true, connected });
|
|
319
|
-
|
|
342
|
+
_maybeStart();
|
|
320
343
|
}
|
|
321
344
|
|
|
322
345
|
// Wire up the MQTT API: pass the state store and a getter for the live MQTT client.
|
|
@@ -605,9 +628,21 @@ if (config.matterStorage) {
|
|
|
605
628
|
matterStoragePath = ensureStorageDir('matter');
|
|
606
629
|
}
|
|
607
630
|
log.info('matter controller starting, storage:', matterStoragePath);
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
631
|
+
// Scripts wait for the controller (see _maybeStart) — but never forever:
|
|
632
|
+
// a hanging start must not block the whole script engine.
|
|
633
|
+
const _matterStartTimeout = setTimeout(() => {
|
|
634
|
+
if (!_started) log.warn('matter controller not ready after 30s — starting scripts anyway');
|
|
635
|
+
matterGateOpen();
|
|
636
|
+
}, 30000);
|
|
637
|
+
matterController
|
|
638
|
+
.init(matterStoragePath, log, broadcast)
|
|
639
|
+
.catch((err) => {
|
|
640
|
+
log.error('matter controller init failed:', err.message, err.stack);
|
|
641
|
+
})
|
|
642
|
+
.finally(() => {
|
|
643
|
+
clearTimeout(_matterStartTimeout);
|
|
644
|
+
matterGateOpen();
|
|
645
|
+
});
|
|
611
646
|
} else {
|
|
612
647
|
log.warn('matter controller disabled — set matterStorage in config.json to enable');
|
|
613
648
|
}
|
|
@@ -626,7 +661,10 @@ if (config.url) {
|
|
|
626
661
|
startOnce();
|
|
627
662
|
}, _STARTUP_TIMEOUT_MS);
|
|
628
663
|
} else {
|
|
629
|
-
|
|
664
|
+
// No broker configured — open the MQTT gate directly (scripts may still
|
|
665
|
+
// wait for the Matter controller, see _maybeStart).
|
|
666
|
+
_mqttGate = true;
|
|
667
|
+
_maybeStart();
|
|
630
668
|
}
|
|
631
669
|
|
|
632
670
|
function stateChange(topic, state, oldState, msg) {
|
|
@@ -1084,42 +1122,33 @@ function runScript(script, name, _origin) {
|
|
|
1084
1122
|
if (modules[md]) {
|
|
1085
1123
|
return modules[md];
|
|
1086
1124
|
}
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1125
|
+
// Failures throw (Cannot find module, syntax errors in the required
|
|
1126
|
+
// file, …) and thereby stop the requiring script — a script must not
|
|
1127
|
+
// silently continue with an undefined module.
|
|
1128
|
+
let result;
|
|
1129
|
+
if (md.match(/^\.\//) || md.match(/^\.\.\//)) {
|
|
1130
|
+
// Relative import — resolve from the script's own directory
|
|
1131
|
+
she.debug('require', md);
|
|
1132
|
+
result = require(path.resolve(scriptDir, md));
|
|
1133
|
+
} else {
|
|
1134
|
+
// Absolute import — try ~/.she/node_modules/ first (user-installed),
|
|
1135
|
+
// then fall back to engine's own require (builtins + engine deps).
|
|
1136
|
+
try {
|
|
1137
|
+
result = _userRequire(md);
|
|
1138
|
+
she.debug('require (user)', md);
|
|
1139
|
+
} catch {
|
|
1140
|
+
const localMod = path.join(scriptDir, 'node_modules', md, 'package.json');
|
|
1141
|
+
if (fs.existsSync(localMod)) {
|
|
1142
|
+
result = require(path.join(scriptDir, 'node_modules', md));
|
|
1143
|
+
she.debug('require (local)', md);
|
|
1144
|
+
} else {
|
|
1145
|
+
result = require(md);
|
|
1146
|
+
she.debug('require', md);
|
|
1109
1147
|
}
|
|
1110
1148
|
}
|
|
1111
|
-
modules[md] = result;
|
|
1112
|
-
return result;
|
|
1113
|
-
} catch (err) {
|
|
1114
|
-
const lines = err.stack.split('\n');
|
|
1115
|
-
const stack = [];
|
|
1116
|
-
lines.forEach((line) => {
|
|
1117
|
-
if (!line.match(/module\.js:/)) {
|
|
1118
|
-
stack.push(line);
|
|
1119
|
-
}
|
|
1120
|
-
});
|
|
1121
|
-
log.error(name + ': ' + stack);
|
|
1122
1149
|
}
|
|
1150
|
+
modules[md] = result;
|
|
1151
|
+
return result;
|
|
1123
1152
|
},
|
|
1124
1153
|
|
|
1125
1154
|
console: {
|
|
@@ -1174,7 +1203,15 @@ function runScript(script, name, _origin) {
|
|
|
1174
1203
|
|
|
1175
1204
|
scriptDomain.run(() => {
|
|
1176
1205
|
log.debug(logLabel, 'running');
|
|
1177
|
-
|
|
1206
|
+
try {
|
|
1207
|
+
script.runInContext(context);
|
|
1208
|
+
} catch (e) {
|
|
1209
|
+
// Contain top-level script errors: without this, the exception
|
|
1210
|
+
// unwinds through the caller (e.g. the watcher batch loading many
|
|
1211
|
+
// scripts in one tick) and aborts loading of subsequent scripts.
|
|
1212
|
+
// Route through the domain handler for the usual attributed log.
|
|
1213
|
+
scriptDomain.emit('error', e);
|
|
1214
|
+
}
|
|
1178
1215
|
});
|
|
1179
1216
|
|
|
1180
1217
|
// Log a summary of what was registered — symmetric with the unload summary
|
package/src/matter/controller.js
CHANGED
|
@@ -159,9 +159,30 @@ async function init(storagePath, log, broadcastFn) {
|
|
|
159
159
|
// matter.js's default unhandled-error reporter logs the bare value, which
|
|
160
160
|
// renders as "{}" for non-Error throwables and drops cause / AggregateError
|
|
161
161
|
// details. The hook is explicitly replaceable — report full detail (B6).
|
|
162
|
+
//
|
|
163
|
+
// matter.js wires this to process.uncaughtExceptionMonitor, which fires for
|
|
164
|
+
// EVERY uncaught exception in the process — matter internals, sandbox
|
|
165
|
+
// script errors, and she's own code alike. Attribute by stack:
|
|
166
|
+
// - sandbox script errors are skipped entirely (she's per-script domain
|
|
167
|
+
// handles and logs them with correct script attribution);
|
|
168
|
+
// - only stacks that actually contain matter.js frames get the
|
|
169
|
+
// "matter.js:" label — everything else is reported neutrally, since it
|
|
170
|
+
// may just as well be a bug in she itself.
|
|
162
171
|
Logger.reportUnhandledError = (error) => {
|
|
163
172
|
try {
|
|
164
|
-
|
|
173
|
+
const stack = typeof error?.stack === 'string' ? error.stack : '';
|
|
174
|
+
if (stack) {
|
|
175
|
+
if (stack.includes('Script.runInContext') || stack.includes('node:vm')) return;
|
|
176
|
+
try {
|
|
177
|
+
const config = require('../config');
|
|
178
|
+
const dirs = config.dir ? (Array.isArray(config.dir) ? config.dir : [config.dir]) : [];
|
|
179
|
+
if (dirs.some((d) => d && stack.includes(d))) return;
|
|
180
|
+
} catch {
|
|
181
|
+
/* config unavailable — fall through to logging */
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
const fromMatter = stack.includes('/@matter/') || stack.includes('\\@matter\\') || stack.includes('@project-chip');
|
|
185
|
+
_log.error(fromMatter ? 'matter.js: unhandled error:' : 'unhandled error:', _inspect(error));
|
|
165
186
|
} catch {
|
|
166
187
|
/* never throw from the error reporter */
|
|
167
188
|
}
|
|
@@ -701,13 +722,18 @@ function subscribeAttribute(scriptFile, nodeId, endpointId, clusterName, attrNam
|
|
|
701
722
|
if (!changeEvent) throw new Error(`Attribute "${attrName}" on cluster "${clusterName}" has no change event`);
|
|
702
723
|
|
|
703
724
|
const listenerId = _nextListenerId++;
|
|
704
|
-
const
|
|
725
|
+
const observer = (value, oldValue) => {
|
|
705
726
|
try {
|
|
706
727
|
callback(value, oldValue);
|
|
707
728
|
} catch (err) {
|
|
708
729
|
_log?.error(`matter subscriber error in ${scriptFile}:`, err.message);
|
|
709
730
|
}
|
|
710
|
-
}
|
|
731
|
+
};
|
|
732
|
+
// Observable.on() returns void — detaching needs off() with the same
|
|
733
|
+
// observer reference. (A cancel based on on()'s return value silently did
|
|
734
|
+
// nothing, leaking one listener per hot-reload.)
|
|
735
|
+
changeEvent.on(observer);
|
|
736
|
+
const cancel = () => changeEvent.off(observer);
|
|
711
737
|
|
|
712
738
|
if (!_listeners.has(scriptFile)) _listeners.set(scriptFile, new Map());
|
|
713
739
|
_listeners.get(scriptFile).set(listenerId, { cancel });
|
|
@@ -735,13 +761,18 @@ function unsubscribe(scriptFile, listenerId) {
|
|
|
735
761
|
function cleanup(scriptFile) {
|
|
736
762
|
const scriptListeners = _listeners.get(scriptFile);
|
|
737
763
|
if (!scriptListeners) return;
|
|
764
|
+
let cancelled = 0;
|
|
738
765
|
for (const { cancel } of scriptListeners.values()) {
|
|
739
766
|
try {
|
|
740
767
|
cancel();
|
|
741
|
-
|
|
742
|
-
|
|
768
|
+
cancelled++;
|
|
769
|
+
} catch (err) {
|
|
770
|
+
// Don't swallow silently — a broken cancel means a leaked listener
|
|
771
|
+
// (this hid the on()-returns-void bug above for a long time).
|
|
772
|
+
_log?.warn(`matter: failed to cancel a subscription of ${scriptFile}: ${err.message}`);
|
|
743
773
|
}
|
|
744
774
|
}
|
|
775
|
+
if (cancelled > 0) _log?.debug(`matter: cancelled ${cancelled} subscription(s) of ${scriptFile}`);
|
|
745
776
|
_listeners.delete(scriptFile);
|
|
746
777
|
}
|
|
747
778
|
|