smart-home-engine 1.48.1 → 1.48.3
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/dist/web/assets/{index-DvjjOawt.js → index-BMdhxdQq.js} +5 -5
- package/dist/web/assets/{tsMode-Bw4L07QT.js → tsMode-Daa0DLzL.js} +1 -1
- package/dist/web/index.html +1 -1
- package/package.json +1 -1
- package/service/she-servicectl +17 -2
- package/src/lib/npm-registry.js +9 -7
- package/src/lib/services-host.js +1 -1
- package/src/web/services-api.js +13 -7
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{m as O}from"./monaco-langs-DKJI_o9J.js";import{t as I}from"./index-
|
|
1
|
+
import{m as O}from"./monaco-langs-DKJI_o9J.js";import{t as I}from"./index-BMdhxdQq.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
|
@@ -175,7 +175,7 @@
|
|
|
175
175
|
}
|
|
176
176
|
})();
|
|
177
177
|
</script>
|
|
178
|
-
<script type="module" crossorigin src="/assets/index-
|
|
178
|
+
<script type="module" crossorigin src="/assets/index-BMdhxdQq.js"></script>
|
|
179
179
|
<link rel="modulepreload" crossorigin href="/assets/monaco-langs-DKJI_o9J.js">
|
|
180
180
|
<link rel="stylesheet" crossorigin href="/assets/monaco-langs-DyX1CsEw.css">
|
|
181
181
|
<link rel="stylesheet" crossorigin href="/assets/index-BTq9iige.css">
|
package/package.json
CHANGED
package/service/she-servicectl
CHANGED
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
|
|
46
46
|
set -eu
|
|
47
47
|
|
|
48
|
-
VERSION=
|
|
48
|
+
VERSION=14
|
|
49
49
|
BROKER_ENV=/etc/mqtt-interfaces/broker.env
|
|
50
50
|
UNIT_DIR=/etc/systemd/system
|
|
51
51
|
|
|
@@ -84,10 +84,25 @@ need_instance() {
|
|
|
84
84
|
valid_instance "$1" || die "invalid instance name: $1"
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
# the command behind <adapter> belongs to an npm package of that name — what tells an adapter
|
|
88
|
+
# apart from any other daemon that happens to keep its binary in /usr/local/bin
|
|
89
|
+
npm_adapter_pkg() {
|
|
90
|
+
dir=$(adapter_dir "$1" 2>/dev/null) || return 1
|
|
91
|
+
[ "$(basename "$dir")" = "$1" ] && return 0
|
|
92
|
+
grep -Eq "\"name\"[[:space:]]*:[[:space:]]*\"(@[^\"/]*/)?$1\"" "$dir/package.json" 2>/dev/null
|
|
93
|
+
}
|
|
94
|
+
|
|
87
95
|
# a plain <adapter>.service of an npm-installed adapter (pre-core layout)
|
|
88
96
|
legacy_unit() {
|
|
89
97
|
[ -f "$UNIT_DIR/$1.service" ] || return 1
|
|
90
|
-
|
|
98
|
+
# the unit naming the package directory is conclusive on its own
|
|
99
|
+
if grep -Eq "/node_modules/$1/" "$UNIT_DIR/$1.service" 2>/dev/null; then
|
|
100
|
+
return 0
|
|
101
|
+
fi
|
|
102
|
+
# ExecStart=/usr/local/bin/<name> alone is not: dnscrypt-proxy, dnsproxy and the like live
|
|
103
|
+
# there too. It counts only when that binary is an npm package called <adapter>.
|
|
104
|
+
grep -Eq "/usr/local/bin/$1( |$)" "$UNIT_DIR/$1.service" 2>/dev/null || return 1
|
|
105
|
+
npm_adapter_pkg "$1"
|
|
91
106
|
}
|
|
92
107
|
# the env file of a legacy unit: its EnvironmentFile= (leading - stripped), default /etc/default/<adapter>;
|
|
93
108
|
# only /etc/default/<adapter> or something inside /etc/<adapter>/ is accepted
|
package/src/lib/npm-registry.js
CHANGED
|
@@ -39,10 +39,10 @@ async function latestVersion(name, opts = {}) {
|
|
|
39
39
|
if (!validName(name)) return null;
|
|
40
40
|
const now = opts.now ?? Date.now();
|
|
41
41
|
const hit = _cache.get(name);
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
// a forced lookup ignores the cached answer, but not a forced one already on its way:
|
|
43
|
+
// the same adapter installed on five hosts is one request, not five
|
|
44
|
+
if (hit && hit.promise && (!opts.force || hit.forced)) return hit.promise;
|
|
45
|
+
if (hit && !opts.force && now - hit.ts < TTL) return hit.version;
|
|
46
46
|
const promise = (async () => {
|
|
47
47
|
try {
|
|
48
48
|
const res = await _fetch(`${REGISTRY}/${name}/latest`, { signal: AbortSignal.timeout(10000) });
|
|
@@ -53,7 +53,7 @@ async function latestVersion(name, opts = {}) {
|
|
|
53
53
|
return hit ? hit.version : null; // keep the last good answer
|
|
54
54
|
}
|
|
55
55
|
})();
|
|
56
|
-
_cache.set(name, { version: hit ? hit.version : null, ts: now, promise });
|
|
56
|
+
_cache.set(name, { version: hit ? hit.version : null, ts: now, promise, forced: Boolean(opts.force) });
|
|
57
57
|
const version = await promise;
|
|
58
58
|
_cache.set(name, { version, ts: now });
|
|
59
59
|
return version;
|
|
@@ -63,10 +63,12 @@ async function latestVersion(name, opts = {}) {
|
|
|
63
63
|
* Newer version available? null when unknown.
|
|
64
64
|
* @param {string} name
|
|
65
65
|
* @param {string|null} installed
|
|
66
|
+
* @param {{force?: boolean, now?: number}} [opts] `force` asks the registry again instead of
|
|
67
|
+
* answering from the 24 h cache — what the refresh button on a listing wants.
|
|
66
68
|
* @returns {Promise<{latest: string|null, updateAvailable: boolean|null}>}
|
|
67
69
|
*/
|
|
68
|
-
async function updateInfo(name, installed) {
|
|
69
|
-
const latest = await latestVersion(name);
|
|
70
|
+
async function updateInfo(name, installed, opts = {}) {
|
|
71
|
+
const latest = await latestVersion(name, opts);
|
|
70
72
|
if (!latest || !installed) return { latest, updateAvailable: null };
|
|
71
73
|
let updateAvailable = null;
|
|
72
74
|
try {
|
package/src/lib/services-host.js
CHANGED
|
@@ -26,7 +26,7 @@ const { execFile, spawn } = require('child_process');
|
|
|
26
26
|
const sshDeploy = require('./ssh-deploy');
|
|
27
27
|
|
|
28
28
|
const HELPER = '/usr/local/bin/she-servicectl';
|
|
29
|
-
const HELPER_VERSION =
|
|
29
|
+
const HELPER_VERSION = 14; // must match VERSION in service/she-servicectl (test/unit/helper-version.test.js)
|
|
30
30
|
/** Default identity for services.hosts[].ssh — one key for all managed hosts (I5). */
|
|
31
31
|
const DEFAULT_SERVICES_IDENTITY = '~/.she/ssh/services_id_ed25519';
|
|
32
32
|
/** The helper as shipped with this she version (copied to remote hosts by the deploy route). */
|
package/src/web/services-api.js
CHANGED
|
@@ -132,17 +132,18 @@ function publish(topic, payload) {
|
|
|
132
132
|
});
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
-
// GET /she/services/instances
|
|
135
|
+
// GET /she/services/instances[?refresh=1]
|
|
136
136
|
router.get('/instances', async (req, res) => {
|
|
137
137
|
if (!_store) return res.json({ enabled: false, instances: [], coreCount: 0, legacyCount: 0 });
|
|
138
138
|
const cfg = getServicesConfig(req);
|
|
139
139
|
const result = analyzeServices(_store.mqttEntries());
|
|
140
|
-
// update badge: one registry lookup per adapter (cached 24 h)
|
|
140
|
+
// update badge: one registry lookup per adapter (cached 24 h, asked again on a refresh)
|
|
141
141
|
const adapters = [...new Set(result.instances.filter((i) => i.adapter).map((i) => i.adapter))];
|
|
142
|
-
const latest = new Map(await Promise.all(adapters.map(async (a) => [a, await npmRegistry.latestVersion(a)])));
|
|
142
|
+
const latest = new Map(await Promise.all(adapters.map(async (a) => [a, await npmRegistry.latestVersion(a, { force: req.query.refresh === '1' })])));
|
|
143
143
|
const instances = await Promise.all(
|
|
144
144
|
result.instances.map(async (i) => {
|
|
145
145
|
if (!i.adapter) return { ...i, latestVersion: null, updateAvailable: null };
|
|
146
|
+
// unforced on purpose: the lookup above just put the fresh answer in the cache
|
|
146
147
|
const { updateAvailable } = await npmRegistry.updateInfo(i.adapter, i.version);
|
|
147
148
|
return { ...i, latestVersion: latest.get(i.adapter) ?? null, updateAvailable };
|
|
148
149
|
}),
|
|
@@ -556,7 +557,7 @@ router.get('/hosts', async (req, res) => {
|
|
|
556
557
|
if (!fresh && _hostsCache && _hostsCache.key === key && Date.now() - _hostsCache.ts < HOSTS_TTL) {
|
|
557
558
|
return res.json({ hosts: await _hostsCache.promise, cached: true });
|
|
558
559
|
}
|
|
559
|
-
const promise = listHosts(req);
|
|
560
|
+
const promise = listHosts(req, { force: fresh });
|
|
560
561
|
_hostsCache = { key, ts: Date.now(), promise };
|
|
561
562
|
res.json({ hosts: await promise, cached: false });
|
|
562
563
|
});
|
|
@@ -574,7 +575,12 @@ function withCpuShare(hostName, instances, now = Date.now()) {
|
|
|
574
575
|
});
|
|
575
576
|
}
|
|
576
577
|
|
|
577
|
-
|
|
578
|
+
/**
|
|
579
|
+
* @param {object} req
|
|
580
|
+
* @param {{force?: boolean}} [opts] `force`: ask npm again for the latest versions instead of
|
|
581
|
+
* taking the 24 h cached answer — a refresh on the listing means "is any of this outdated now?"
|
|
582
|
+
*/
|
|
583
|
+
async function listHosts(req, opts = {}) {
|
|
578
584
|
return Promise.all(
|
|
579
585
|
hostEntries(req).map(async ({ cfg, driver }) => {
|
|
580
586
|
const base = {
|
|
@@ -588,11 +594,11 @@ async function listHosts(req) {
|
|
|
588
594
|
const { stdout } = await driver.exec(['list']);
|
|
589
595
|
const list = parseList(stdout);
|
|
590
596
|
if (!cfg.hostname && list.hostname) saveHostname(req, cfg.name, list.hostname);
|
|
591
|
-
// update badge per installed adapter: one registry lookup each (cached 24 h)
|
|
597
|
+
// update badge per installed adapter: one registry lookup each (cached 24 h, asked again on a refresh)
|
|
592
598
|
const adapters = await Promise.all(
|
|
593
599
|
(list.adapters || []).map(async (a) => {
|
|
594
600
|
try {
|
|
595
|
-
const { latest, updateAvailable } = await npmRegistry.updateInfo(a.name, a.version);
|
|
601
|
+
const { latest, updateAvailable } = await npmRegistry.updateInfo(a.name, a.version, { force: opts.force });
|
|
596
602
|
return { ...a, latestVersion: latest || null, updateAvailable };
|
|
597
603
|
} catch {
|
|
598
604
|
return { ...a, latestVersion: null, updateAvailable: null };
|