iobroker.eos-admin 7.10.1 → 7.10.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/INSTALL_TEST_V7.10.3.md +7 -0
- package/MERGE_UPDATE_README_V7.10.3.md +3 -0
- package/NEXOWATT_EOS_BUILD_INFO.json +16 -16
- package/NEXOWATT_EOS_PREBUILT_MANIFEST.json +1412 -0
- package/PUBLISH_STABLE_V7.10.3.md +10 -0
- package/README.md +4 -4
- package/README_STABILITY_V7.10.3.md +5 -0
- package/RELEASE_ACCEPTANCE_V7.10.3.md +3 -0
- package/RELEASE_NOTES_V7.10.3.md +7 -0
- package/adminWww/css/eos-auto-update.css +4 -3
- package/adminWww/index.html +2 -2
- package/adminWww/js/eos-auto-update.js +127 -33
- package/build/lib/eosAutoUpdate.js +418 -20
- package/build/lib/eosAutoUpdate.js.map +1 -0
- package/build/lib/eosRequestSecurity.js +4 -1
- package/build/lib/eosRequestSecurity.js.map +1 -0
- package/build/lib/web.js +40 -9
- package/build/lib/web.js.map +1 -1
- package/io-package.json +65 -5
- package/package.json +24 -16
- package/tools/nexowatt-auto-update-placement-selftest.cjs +46 -0
- package/tools/nexowatt-auto-update-selftest.cjs +144 -32
- package/tools/nexowatt-backend-runtime-selftest.cjs +147 -0
- package/tools/nexowatt-merge-update-selftest.cjs +7 -1
- package/tools/nexowatt-prebuilt-release-selftest.cjs +292 -0
- package/tools/nexowatt-stable-v7103-selftest.cjs +61 -0
- package/tools/nexowatt-validate-package.cjs +45 -12
- package/INSTALL_TEST_V7.10.1.md +0 -10
- package/MERGE_UPDATE_README_V7.10.1.md +0 -10
- package/PUBLISH_STABLE_V7.10.1.md +0 -10
- package/README_STABILITY_V7.10.1.md +0 -10
- package/RELEASE_ACCEPTANCE_V7.10.1.md +0 -10
- package/RELEASE_NOTES_V7.10.1.md +0 -10
- package/adminWww/js/eos-release-watch.js +0 -77
- package/build/lib/eosPassword.js +0 -72
- package/build/lib/nexowattStableAuth.js +0 -74
- package/tools/nexowatt-stable-v7101-selftest.cjs +0 -15
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.eos-admin",
|
|
3
|
-
"description": "NexoWatt EOS Admin – stable baseline with native account passwords
|
|
4
|
-
"version": "7.10.
|
|
3
|
+
"description": "NexoWatt EOS Admin – repaired stable baseline with restart-safe automatic updates, native account passwords and persistent cockpit scrolling.",
|
|
4
|
+
"version": "7.10.3",
|
|
5
5
|
"contributors": [
|
|
6
6
|
"bluefox <dogafox@gmail.com>",
|
|
7
7
|
"apollon77",
|
|
@@ -118,24 +118,28 @@
|
|
|
118
118
|
"tools/nexowatt-version-sync-selftest.cjs",
|
|
119
119
|
"tools/nexowatt-merge-update-selftest.cjs",
|
|
120
120
|
"tools/nexowatt-ems-overview-selftest.cjs",
|
|
121
|
-
"README_STABILITY_V7.10.1.md",
|
|
122
|
-
"RELEASE_NOTES_V7.10.1.md",
|
|
123
|
-
"PUBLISH_STABLE_V7.10.1.md",
|
|
124
|
-
"INSTALL_TEST_V7.10.1.md",
|
|
125
|
-
"RELEASE_ACCEPTANCE_V7.10.1.md",
|
|
126
|
-
"MERGE_UPDATE_README_V7.10.1.md",
|
|
127
121
|
"README_EMS_OVERVIEW_MERGE.md",
|
|
128
122
|
"RC73_EOS_ADMIN_MERGE_VALIDATION.md",
|
|
129
123
|
"VALIDATION_EMS_OVERVIEW_MERGE.md",
|
|
130
124
|
"NexoWatt_EOS_Admin_EMS_OVERVIEW_MERGE_VALIDATION.md",
|
|
131
125
|
"tools/nexowatt-apply-ems-overview.cjs",
|
|
132
126
|
"tools/nexowatt-ui-overview-runtime-selftest.cjs",
|
|
133
|
-
"tools/nexowatt-stable-v7101-selftest.cjs",
|
|
134
127
|
"tools/nexowatt-password-write-selftest.cjs",
|
|
135
128
|
"tools/nexowatt-account-password-flow-selftest.cjs",
|
|
136
129
|
"tools/nexowatt-auto-update-selftest.cjs",
|
|
137
130
|
"adminWww/css/eos-auto-update.css",
|
|
138
|
-
"adminWww/js/eos-auto-update.js"
|
|
131
|
+
"adminWww/js/eos-auto-update.js",
|
|
132
|
+
"tools/nexowatt-backend-runtime-selftest.cjs",
|
|
133
|
+
"NEXOWATT_EOS_PREBUILT_MANIFEST.json",
|
|
134
|
+
"tools/nexowatt-prebuilt-release-selftest.cjs",
|
|
135
|
+
"tools/nexowatt-stable-v7103-selftest.cjs",
|
|
136
|
+
"README_STABILITY_V7.10.3.md",
|
|
137
|
+
"RELEASE_NOTES_V7.10.3.md",
|
|
138
|
+
"PUBLISH_STABLE_V7.10.3.md",
|
|
139
|
+
"INSTALL_TEST_V7.10.3.md",
|
|
140
|
+
"RELEASE_ACCEPTANCE_V7.10.3.md",
|
|
141
|
+
"MERGE_UPDATE_README_V7.10.3.md",
|
|
142
|
+
"tools/nexowatt-auto-update-placement-selftest.cjs"
|
|
139
143
|
],
|
|
140
144
|
"scripts": {
|
|
141
145
|
"npm": "npm i -f && cd src-admin && npm i -f",
|
|
@@ -146,8 +150,8 @@
|
|
|
146
150
|
"test:integration": "mocha test/integration --exit && npm run test:gui && npm run test:rule && npm run test:unit",
|
|
147
151
|
"test:rule": "mocha test/rule --exit",
|
|
148
152
|
"test:gui": "mocha test/*.gui.js --exit",
|
|
149
|
-
"prepublishOnly": "npm run sync:eos-version && npm run prepare:eos-release-defaults && npm run check:eos-publish-channel && npm run check:eos-package && npm run check:eos-stability",
|
|
150
|
-
"build": "npm run build:frontend && npm run build:backend && npm run clean:eos-runtime",
|
|
153
|
+
"prepublishOnly": "npm run sync:eos-version && npm run prepare:eos-release-defaults && npm run clean:eos-runtime && npm run check:eos-publish-channel && npm run check:eos-package && npm run check:eos-stability",
|
|
154
|
+
"build": "npm run build:frontend && npm run build:backend && npm run clean:eos-runtime && npm run seal:eos-prebuilt-release",
|
|
151
155
|
"build:backend": "tsc -p tsconfig.build.json && tsx tasks.mts --backend-i18n",
|
|
152
156
|
"build:frontend": "tsx tasks.mts",
|
|
153
157
|
"clean": "rimraf src-admin/build",
|
|
@@ -170,12 +174,12 @@
|
|
|
170
174
|
"nexowatt:repo-entry": "node tools/nexowatt-generate-repo-entry.cjs",
|
|
171
175
|
"nexowatt:patch-repo": "node tools/nexowatt-patch-repo.cjs",
|
|
172
176
|
"nexowatt:repair-update": "node tools/nexowatt-repair-eos-admin-update.cjs",
|
|
173
|
-
"check:eos-stability": "node tools/nexowatt-stability-check.cjs && node tools/nexowatt-esm-syntax-selftest.cjs && node tools/nexowatt-import-integrity-selftest.cjs && node tools/nexowatt-entrypoint-smoke-selftest.cjs && node tools/nexowatt-frontend-graph-check.cjs && node tools/nexowatt-policy-selftest.cjs && node tools/nexowatt-publish-channel-selftest.cjs && node tools/nexowatt-release-defaults-selftest.cjs && node tools/nexowatt-role-access-selftest.cjs && node tools/nexowatt-internal-reserve-selftest.cjs && node tools/nexowatt-modern-ui-selftest.cjs && node tools/nexowatt-login-layout-selftest.cjs && node tools/nexowatt-branding-selftest.cjs && node tools/nexowatt-default-port-selftest.cjs && node tools/nexowatt-module-popup-selftest.cjs && node tools/nexowatt-datapoint-selftest.cjs && node tools/nexowatt-update-selftest.cjs && node tools/nexowatt-datapoint-interaction-selftest.cjs && node tools/nexowatt-manual-write-policy-selftest.cjs && node tools/nexowatt-value-column-selftest.cjs && node tools/nexowatt-native-shell-selftest.cjs && node tools/nexowatt-assistant-separation-selftest.cjs && node tools/nexowatt-runtime-cleanup-selftest.cjs && node tools/nexowatt-version-sync-selftest.cjs && node tools/nexowatt-merge-update-selftest.cjs && node tools/nexowatt-password-write-selftest.cjs && node tools/nexowatt-account-password-flow-selftest.cjs && npm run check:eos-stable-
|
|
177
|
+
"check:eos-stability": "node tools/nexowatt-stability-check.cjs && node tools/nexowatt-esm-syntax-selftest.cjs && node tools/nexowatt-backend-runtime-selftest.cjs && node tools/nexowatt-prebuilt-release-selftest.cjs && node tools/nexowatt-import-integrity-selftest.cjs && node tools/nexowatt-entrypoint-smoke-selftest.cjs && node tools/nexowatt-frontend-graph-check.cjs && node tools/nexowatt-policy-selftest.cjs && node tools/nexowatt-publish-channel-selftest.cjs && node tools/nexowatt-release-defaults-selftest.cjs && node tools/nexowatt-role-access-selftest.cjs && node tools/nexowatt-internal-reserve-selftest.cjs && node tools/nexowatt-modern-ui-selftest.cjs && node tools/nexowatt-login-layout-selftest.cjs && node tools/nexowatt-branding-selftest.cjs && node tools/nexowatt-default-port-selftest.cjs && node tools/nexowatt-module-popup-selftest.cjs && node tools/nexowatt-datapoint-selftest.cjs && node tools/nexowatt-update-selftest.cjs && node tools/nexowatt-datapoint-interaction-selftest.cjs && node tools/nexowatt-manual-write-policy-selftest.cjs && node tools/nexowatt-value-column-selftest.cjs && node tools/nexowatt-native-shell-selftest.cjs && node tools/nexowatt-assistant-separation-selftest.cjs && node tools/nexowatt-runtime-cleanup-selftest.cjs && node tools/nexowatt-version-sync-selftest.cjs && node tools/nexowatt-merge-update-selftest.cjs && node tools/nexowatt-password-write-selftest.cjs && node tools/nexowatt-account-password-flow-selftest.cjs && npm run check:eos-stable-v7103 && node tools/nexowatt-ems-overview-selftest.cjs && node tools/nexowatt-ui-overview-runtime-selftest.cjs && node tools/nexowatt-auto-update-selftest.cjs && node tools/nexowatt-auto-update-placement-selftest.cjs",
|
|
174
178
|
"nexowatt:patch-built-frontend": "node tools/nexowatt-patch-built-frontend.cjs",
|
|
175
179
|
"clean:eos-runtime": "node tools/nexowatt-clean-legacy-runtime.cjs",
|
|
176
180
|
"precheck:eos-package": "npm run sync:eos-version && npm run prepare:eos-release-defaults && npm run clean:eos-runtime",
|
|
177
181
|
"precheck:eos-stability": "npm run sync:eos-version && npm run prepare:eos-release-defaults && npm run clean:eos-runtime",
|
|
178
|
-
"prepack": "node tools/nexowatt-sync-release-version.cjs --quiet && node tools/nexowatt-clean-legacy-runtime.cjs --quiet",
|
|
182
|
+
"prepack": "node tools/nexowatt-sync-release-version.cjs --quiet && node tools/nexowatt-ensure-release-defaults.cjs && node tools/nexowatt-clean-legacy-runtime.cjs --quiet && node tools/nexowatt-prebuilt-release-selftest.cjs",
|
|
179
183
|
"check:eos-esm": "node tools/nexowatt-esm-syntax-selftest.cjs",
|
|
180
184
|
"check:eos-imports": "node tools/nexowatt-import-integrity-selftest.cjs",
|
|
181
185
|
"check:eos-release": "npm run check:eos-package && npm run check:eos-stability && npm pack --dry-run",
|
|
@@ -194,7 +198,11 @@
|
|
|
194
198
|
"sync:eos-version": "node tools/nexowatt-sync-release-version.cjs",
|
|
195
199
|
"test:eos-version-sync": "node tools/nexowatt-version-sync-selftest.cjs",
|
|
196
200
|
"verify:eos-merge": "node tools/nexowatt-merge-update-selftest.cjs",
|
|
197
|
-
"check:eos-
|
|
201
|
+
"check:eos-backend-runtime": "node tools/nexowatt-backend-runtime-selftest.cjs",
|
|
202
|
+
"check:eos-prebuilt-release": "node tools/nexowatt-prebuilt-release-selftest.cjs",
|
|
203
|
+
"seal:eos-prebuilt-release": "node tools/nexowatt-prebuilt-release-selftest.cjs --write",
|
|
204
|
+
"check:eos-stable-v7103": "node tools/nexowatt-stable-v7103-selftest.cjs",
|
|
205
|
+
"test:eos-auto-update-placement": "node tools/nexowatt-auto-update-placement-selftest.cjs"
|
|
198
206
|
},
|
|
199
207
|
"author": "NexoWatt",
|
|
200
208
|
"private": false,
|
|
@@ -205,7 +213,7 @@
|
|
|
205
213
|
},
|
|
206
214
|
"nexowattReleasePolicy": {
|
|
207
215
|
"distTag": "latest",
|
|
208
|
-
"purpose": "accepted stable NexoWatt EOS sales-product candidate 7.10.
|
|
216
|
+
"purpose": "accepted stable NexoWatt EOS sales-product candidate 7.10.3"
|
|
209
217
|
},
|
|
210
218
|
"publisher": "NexoWatt"
|
|
211
219
|
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const path = require('node:path');
|
|
6
|
+
const root = path.resolve(__dirname, '..');
|
|
7
|
+
const read = relative => fs.readFileSync(path.join(root, relative), 'utf8');
|
|
8
|
+
const json = relative => JSON.parse(read(relative));
|
|
9
|
+
const fail = message => {
|
|
10
|
+
console.error(`[NexoWatt EOS auto-update placement] ${message}`);
|
|
11
|
+
process.exit(1);
|
|
12
|
+
};
|
|
13
|
+
const must = (value, message) => value || fail(message);
|
|
14
|
+
|
|
15
|
+
const sourceJs = read('src-admin/public/js/eos-auto-update.js');
|
|
16
|
+
const builtJs = read('adminWww/js/eos-auto-update.js');
|
|
17
|
+
const sourceCss = read('src-admin/public/css/eos-auto-update.css');
|
|
18
|
+
const builtCss = read('adminWww/css/eos-auto-update.css');
|
|
19
|
+
const index = read('adminWww/index.html');
|
|
20
|
+
const info = json('NEXOWATT_EOS_BUILD_INFO.json');
|
|
21
|
+
const cacheTag = String(info.autoUpdateCacheTag || info.autoUpdateCacheVersion || info.shellCacheTag || info.shellCacheVersion);
|
|
22
|
+
|
|
23
|
+
must(sourceJs === builtJs, 'JavaScript source/build drift');
|
|
24
|
+
must(sourceCss === builtCss, 'CSS source/build drift');
|
|
25
|
+
must(sourceJs.includes("const VERSION = 'v7103-system-settings-only'"), 'v7103 placement marker missing');
|
|
26
|
+
must(sourceJs.includes('[role="dialog"][aria-labelledby="system-settings-dialog-title"]'), 'System Settings dialog selector missing');
|
|
27
|
+
must(sourceJs.includes("root.dataset.context = 'system-settings'"), 'System Settings context marker missing');
|
|
28
|
+
must(sourceJs.includes("root.setAttribute('data-eos-system-settings-only', 'true')"), 'system-settings-only marker missing');
|
|
29
|
+
must(sourceJs.includes('mount.content.insertBefore(root, mount.appBar.nextSibling)'), 'card is not inserted below the System Settings app bar');
|
|
30
|
+
must(sourceJs.includes("location: 'system-settings'"), 'public UI location contract missing');
|
|
31
|
+
|
|
32
|
+
for (const forbidden of [
|
|
33
|
+
'introActive',
|
|
34
|
+
'eos-native-overview-hero',
|
|
35
|
+
'eos-ems-overview-runtime',
|
|
36
|
+
"document.getElementById('app-paper')",
|
|
37
|
+
]) {
|
|
38
|
+
must(!sourceJs.includes(forbidden), `global page placement remains active: ${forbidden}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
must(index.includes(`eos-auto-update.js?v=${cacheTag}`), `auto-update JavaScript cache key ${cacheTag} missing`);
|
|
42
|
+
must(index.includes(`eos-auto-update.css?v=${cacheTag}`), `auto-update CSS cache key ${cacheTag} missing`);
|
|
43
|
+
must(sourceCss.includes('visible only inside the System Settings dialog'), 'CSS ownership comment missing');
|
|
44
|
+
must(sourceCss.includes('[data-context="system-settings"]'), 'System Settings CSS scope marker missing');
|
|
45
|
+
|
|
46
|
+
console.log('[NexoWatt EOS auto-update placement] OK (System Settings only; no Overview/Modules injection)');
|
|
@@ -1,34 +1,146 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
objects
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
})
|
|
3
|
+
|
|
4
|
+
const assert = require('node:assert/strict');
|
|
5
|
+
const { NexoWattStableUpdateManager, isNexoWattRepositoryEntry } = require('../build/lib/eosAutoUpdate.js');
|
|
6
|
+
|
|
7
|
+
const copy = value => JSON.parse(JSON.stringify(value));
|
|
8
|
+
|
|
9
|
+
function createFixture() {
|
|
10
|
+
const objects = new Map();
|
|
11
|
+
const states = new Map();
|
|
12
|
+
const objectWrites = [];
|
|
13
|
+
const stateWrites = [];
|
|
14
|
+
const refresh = [];
|
|
15
|
+
|
|
16
|
+
objects.set('system.adapter.eos-admin.0', {
|
|
17
|
+
_id: 'system.adapter.eos-admin.0',
|
|
18
|
+
common: { name: 'eos-admin', version: '7.10.2' },
|
|
19
|
+
native: {
|
|
20
|
+
eosNexoWattAutoUpdate: true,
|
|
21
|
+
eosNexoWattAutoUpdateState: {
|
|
22
|
+
previousPolicies: {},
|
|
23
|
+
lastSync: 1,
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
objects.set('system.config', {
|
|
28
|
+
_id: 'system.config',
|
|
29
|
+
common: {
|
|
30
|
+
activeRepo: ['stable'],
|
|
31
|
+
adapterAutoUpgrade: { repositories: { stable: false }, defaultPolicy: 'none' },
|
|
32
|
+
},
|
|
33
|
+
native: {},
|
|
34
|
+
});
|
|
35
|
+
objects.set('system.repositories', {
|
|
36
|
+
_id: 'system.repositories',
|
|
37
|
+
native: {
|
|
38
|
+
repositories: {
|
|
39
|
+
stable: {
|
|
40
|
+
json: {
|
|
41
|
+
'eos-admin': { name: 'eos-admin', version: '7.10.2', meta: 'https://github.com/NexoWatt/ioBroker.eos-admin' },
|
|
42
|
+
'nexowatt-ui': { name: 'nexowatt-ui', version: '0.8.202', publisher: 'NexoWatt' },
|
|
43
|
+
'nexowatt-beta': { name: 'nexowatt-beta', version: '1.0.0-beta.1', publisher: 'NexoWatt' },
|
|
44
|
+
admin: { name: 'admin', version: '7.7.0', publisher: 'ioBroker' },
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
objects.set('system.adapter.eos-admin', {
|
|
51
|
+
_id: 'system.adapter.eos-admin',
|
|
52
|
+
common: { name: 'eos-admin', version: '7.10.2', automaticUpgrade: 'patch' },
|
|
53
|
+
native: {},
|
|
54
|
+
});
|
|
55
|
+
objects.set('system.adapter.nexowatt-ui', {
|
|
56
|
+
_id: 'system.adapter.nexowatt-ui',
|
|
57
|
+
common: { name: 'nexowatt-ui', version: '0.8.202' },
|
|
58
|
+
native: {},
|
|
59
|
+
});
|
|
60
|
+
objects.set('system.adapter.admin', {
|
|
61
|
+
_id: 'system.adapter.admin',
|
|
62
|
+
common: { name: 'admin', version: '7.7.0', automaticUpgrade: 'minor' },
|
|
63
|
+
native: {},
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const adapter = {
|
|
67
|
+
namespace: 'eos-admin.0',
|
|
68
|
+
host: 'eos-host',
|
|
69
|
+
log: { debug() {}, info() {}, warn() {}, error() {} },
|
|
70
|
+
getForeignObjectAsync: async id => copy(objects.get(id) || null),
|
|
71
|
+
setForeignObjectAsync: async (id, object) => {
|
|
72
|
+
objectWrites.push(id);
|
|
73
|
+
objects.set(id, copy(object));
|
|
74
|
+
},
|
|
75
|
+
getObjectViewAsync: async () => ({
|
|
76
|
+
rows: [...objects.entries()]
|
|
77
|
+
.filter(([id]) => /^system\.adapter\.[^.]+$/.test(id))
|
|
78
|
+
.map(([id, value]) => ({ id, value: copy(value) })),
|
|
79
|
+
}),
|
|
80
|
+
getStateAsync: async id => copy(states.get(id) || null),
|
|
81
|
+
setStateAsync: async (id, value, ack) => {
|
|
82
|
+
const state = value && typeof value === 'object' && Object.prototype.hasOwnProperty.call(value, 'val')
|
|
83
|
+
? { ...value }
|
|
84
|
+
: { val: value, ack: Boolean(ack) };
|
|
85
|
+
stateWrites.push(id);
|
|
86
|
+
states.set(id, copy(state));
|
|
87
|
+
},
|
|
88
|
+
sendToHostAsync: async (...args) => { refresh.push(args); },
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
return { adapter, objects, states, objectWrites, stateWrites, refresh };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
(async () => {
|
|
95
|
+
assert.equal(isNexoWattRepositoryEntry('nexowatt-ui', { publisher: 'NexoWatt' }), true);
|
|
96
|
+
assert.equal(isNexoWattRepositoryEntry('admin', { publisher: 'ioBroker' }), false);
|
|
97
|
+
|
|
98
|
+
const fixture = createFixture();
|
|
99
|
+
const manager = new NexoWattStableUpdateManager(fixture.adapter);
|
|
100
|
+
|
|
101
|
+
const enabled = await manager.reconcile('test');
|
|
102
|
+
assert.equal(enabled.enabled, true);
|
|
103
|
+
assert.equal(enabled.repository, 'stable');
|
|
104
|
+
assert.deepEqual(enabled.managedAdapters, ['eos-admin', 'nexowatt-ui']);
|
|
105
|
+
assert.equal(fixture.objects.get('system.adapter.eos-admin').common.automaticUpgrade, 'major');
|
|
106
|
+
assert.equal(fixture.objects.get('system.adapter.nexowatt-ui').common.automaticUpgrade, 'major');
|
|
107
|
+
assert.equal(fixture.objects.get('system.adapter.admin').common.automaticUpgrade, 'minor');
|
|
108
|
+
assert.equal(fixture.objects.get('system.config').common.adapterAutoUpgrade.repositories.stable, true);
|
|
109
|
+
assert.equal(fixture.states.get('info.nexowattStableUpdatesEnabled').val, true);
|
|
110
|
+
assert.ok(JSON.parse(fixture.states.get('info.nexowattStableUpdatesState').val).lastSync > 1);
|
|
111
|
+
|
|
112
|
+
// Regression guard for 7.10.1: runtime status must never be persisted into
|
|
113
|
+
// system.adapter.eos-admin.0.native, because that restarts the running adapter.
|
|
114
|
+
assert.equal(fixture.objectWrites.includes('system.adapter.eos-admin.0'), false);
|
|
115
|
+
|
|
116
|
+
// A second reconciliation may refresh state timestamps, but must not rewrite
|
|
117
|
+
// unchanged adapter policies or system.config.
|
|
118
|
+
const objectWriteCount = fixture.objectWrites.length;
|
|
119
|
+
await manager.reconcile('repeat');
|
|
120
|
+
assert.equal(fixture.objectWrites.length, objectWriteCount);
|
|
121
|
+
|
|
122
|
+
// A manual user change while EOS management is active must not be overwritten on disable.
|
|
123
|
+
fixture.objects.get('system.adapter.nexowatt-ui').common.automaticUpgrade = 'minor';
|
|
124
|
+
const disabled = await manager.setEnabled(false);
|
|
125
|
+
assert.equal(disabled.enabled, false);
|
|
126
|
+
assert.equal(fixture.objects.get('system.adapter.eos-admin').common.automaticUpgrade, 'patch');
|
|
127
|
+
assert.equal(fixture.objects.get('system.adapter.nexowatt-ui').common.automaticUpgrade, 'minor');
|
|
128
|
+
assert.equal(fixture.objects.get('system.adapter.admin').common.automaticUpgrade, 'minor');
|
|
129
|
+
assert.equal(fixture.objects.get('system.config').common.adapterAutoUpgrade.repositories.stable, false);
|
|
130
|
+
assert.equal(fixture.states.get('info.nexowattStableUpdatesEnabled').val, false);
|
|
131
|
+
assert.equal(fixture.objectWrites.includes('system.adapter.eos-admin.0'), false);
|
|
132
|
+
manager.stop();
|
|
133
|
+
|
|
134
|
+
// Startup must only schedule reconciliation. It must not modify repository or
|
|
135
|
+
// adapter objects while the HTTP server is serving the first browser assets.
|
|
136
|
+
const startupFixture = createFixture();
|
|
137
|
+
const startupManager = new NexoWattStableUpdateManager(startupFixture.adapter);
|
|
138
|
+
await startupManager.start();
|
|
139
|
+
assert.deepEqual(startupFixture.objectWrites, []);
|
|
140
|
+
startupManager.stop();
|
|
141
|
+
|
|
142
|
+
console.log('[NexoWatt EOS auto update] OK (restart-safe state persistence, delayed startup, stable-only scope, third-party isolation and restore)');
|
|
143
|
+
})().catch(error => {
|
|
144
|
+
console.error(error.stack || error);
|
|
145
|
+
process.exit(1);
|
|
146
|
+
});
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const path = require('node:path');
|
|
6
|
+
const { spawnSync } = require('node:child_process');
|
|
7
|
+
|
|
8
|
+
const root = path.resolve(__dirname, '..');
|
|
9
|
+
const entry = path.join(root, 'build', 'main.js');
|
|
10
|
+
const packageFile = path.join(root, 'package.json');
|
|
11
|
+
const failures = [];
|
|
12
|
+
const visited = new Set();
|
|
13
|
+
const runtimeFiles = new Set();
|
|
14
|
+
|
|
15
|
+
function fail(message) {
|
|
16
|
+
failures.push(message);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function normalize(relative) {
|
|
20
|
+
return String(relative).replace(/\\/g, '/').replace(/^\.\//, '');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function resolveLocal(fromFile, specifier) {
|
|
24
|
+
const base = path.resolve(path.dirname(fromFile), specifier);
|
|
25
|
+
const candidates = [base, `${base}.js`, `${base}.json`, path.join(base, 'index.js')];
|
|
26
|
+
if (fs.existsSync(base) && fs.statSync(base).isDirectory()) {
|
|
27
|
+
const packageJsonFile = path.join(base, 'package.json');
|
|
28
|
+
if (fs.existsSync(packageJsonFile)) {
|
|
29
|
+
try {
|
|
30
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonFile, 'utf8'));
|
|
31
|
+
if (packageJson.main) candidates.unshift(path.resolve(base, packageJson.main));
|
|
32
|
+
} catch (error) {
|
|
33
|
+
fail(`${normalize(path.relative(root, packageJsonFile))} is invalid JSON: ${error.message}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return candidates.find(candidate => fs.existsSync(candidate) && fs.statSync(candidate).isFile()) || null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function inspect(file) {
|
|
41
|
+
const absolute = path.resolve(file);
|
|
42
|
+
if (visited.has(absolute)) return;
|
|
43
|
+
visited.add(absolute);
|
|
44
|
+
runtimeFiles.add(absolute);
|
|
45
|
+
|
|
46
|
+
if (!fs.existsSync(absolute)) {
|
|
47
|
+
fail(`missing runtime file ${normalize(path.relative(root, absolute))}`);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (!absolute.endsWith('.js')) return;
|
|
51
|
+
|
|
52
|
+
const text = fs.readFileSync(absolute, 'utf8');
|
|
53
|
+
const patterns = [
|
|
54
|
+
/\brequire\(\s*['"]([^'"]+)['"]\s*\)/g,
|
|
55
|
+
/\brequire\.resolve\(\s*['"]([^'"]+)['"]\s*\)/g,
|
|
56
|
+
/\bimport\(\s*['"]([^'"]+)['"]\s*\)/g,
|
|
57
|
+
];
|
|
58
|
+
for (const pattern of patterns) {
|
|
59
|
+
pattern.lastIndex = 0;
|
|
60
|
+
let match;
|
|
61
|
+
while ((match = pattern.exec(text))) {
|
|
62
|
+
const specifier = match[1];
|
|
63
|
+
if (!specifier.startsWith('.')) continue;
|
|
64
|
+
const target = resolveLocal(absolute, specifier);
|
|
65
|
+
if (!target) {
|
|
66
|
+
fail(`${normalize(path.relative(root, absolute))} -> ${specifier} cannot be resolved`);
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
inspect(target);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function packageRules() {
|
|
75
|
+
if (!fs.existsSync(packageFile)) {
|
|
76
|
+
fail('package.json is missing');
|
|
77
|
+
return [];
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
const pkg = JSON.parse(fs.readFileSync(packageFile, 'utf8'));
|
|
81
|
+
if (!Array.isArray(pkg.files) || pkg.files.length === 0) {
|
|
82
|
+
fail('package.json files whitelist is missing');
|
|
83
|
+
return [];
|
|
84
|
+
}
|
|
85
|
+
return pkg.files
|
|
86
|
+
.map(rule => normalize(rule).replace(/\/+$/, ''))
|
|
87
|
+
.filter(Boolean);
|
|
88
|
+
} catch (error) {
|
|
89
|
+
fail(`package.json is invalid JSON: ${error.message}`);
|
|
90
|
+
return [];
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function isDeclaredForPackage(relative, rules) {
|
|
95
|
+
const value = normalize(relative);
|
|
96
|
+
return rules.some(rule => value === rule || value.startsWith(`${rule}/`));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (!fs.existsSync(entry)) fail('build/main.js is missing');
|
|
100
|
+
else inspect(entry);
|
|
101
|
+
|
|
102
|
+
for (const file of runtimeFiles) {
|
|
103
|
+
if (!file.endsWith('.js')) continue;
|
|
104
|
+
const result = spawnSync(process.execPath, ['--check', file], {
|
|
105
|
+
encoding: 'utf8',
|
|
106
|
+
windowsHide: true,
|
|
107
|
+
});
|
|
108
|
+
if (result.error) {
|
|
109
|
+
fail(`${normalize(path.relative(root, file))} syntax check could not start: ${result.error.message}`);
|
|
110
|
+
} else if (result.status !== 0) {
|
|
111
|
+
fail(`${normalize(path.relative(root, file))} does not parse: ${(result.stderr || result.stdout || '').trim()}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Do not start a nested `npm pack` process here. This self-test runs from
|
|
116
|
+
// prepublishOnly, and spawning npm.cmd from a Node child process is unreliable
|
|
117
|
+
// on Windows and can also re-enter npm lifecycle hooks. The final npm artifact
|
|
118
|
+
// is still verified externally by `npm publish --dry-run`; this check proves
|
|
119
|
+
// that every reachable local backend dependency is covered by package.json's
|
|
120
|
+
// explicit files whitelist without requiring npm, tsc, tsx or node_modules.
|
|
121
|
+
const rules = packageRules();
|
|
122
|
+
for (const file of runtimeFiles) {
|
|
123
|
+
const relative = normalize(path.relative(root, file));
|
|
124
|
+
if (!isDeclaredForPackage(relative, rules)) {
|
|
125
|
+
fail(`runtime dependency is not declared for the npm package: ${relative}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
for (const required of [
|
|
130
|
+
'build/main.js',
|
|
131
|
+
'build/lib/web.js',
|
|
132
|
+
'build/lib/eosAutoUpdate.js',
|
|
133
|
+
'build/lib/eosRequestSecurity.js',
|
|
134
|
+
]) {
|
|
135
|
+
if (!runtimeFiles.has(path.join(root, required))) {
|
|
136
|
+
fail(`entrypoint closure does not include required module ${required}`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (failures.length) {
|
|
141
|
+
console.error(`[NexoWatt EOS backend runtime] ${failures.length} failure(s):\n${failures.join('\n')}`);
|
|
142
|
+
process.exit(1);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
console.log(
|
|
146
|
+
`[NexoWatt EOS backend runtime] OK (${runtimeFiles.size} local runtime files resolve, parse and are declared by the npm files whitelist; dependency-free on Windows)`,
|
|
147
|
+
);
|
|
@@ -16,7 +16,7 @@ for (const file of [
|
|
|
16
16
|
'MERGE_UPDATE.ps1',
|
|
17
17
|
'MERGE_UPDATE.cmd',
|
|
18
18
|
'MERGE_UPDATE.sh',
|
|
19
|
-
'MERGE_UPDATE_README_V7.10.
|
|
19
|
+
'MERGE_UPDATE_README_V7.10.3.md',
|
|
20
20
|
'tools/nexowatt-apply-ems-overview.cjs',
|
|
21
21
|
'tools/nexowatt-sync-release-version.cjs',
|
|
22
22
|
'tools/nexowatt-version-sync-selftest.cjs',
|
|
@@ -67,5 +67,11 @@ if (!pkg.scripts['precheck:eos-package']?.startsWith('npm run sync:eos-version')
|
|
|
67
67
|
if (!pkg.scripts.prepublishOnly?.startsWith('npm run sync:eos-version')) {
|
|
68
68
|
fail('npm publishing does not self-heal stale merged version files');
|
|
69
69
|
}
|
|
70
|
+
if (/\b(?:tsc|tsx)\b|build:(?:backend|frontend)|\bnpx\b|npm\s+(?:i|install|ci)\b/i.test(pkg.scripts.prepublishOnly || '')) {
|
|
71
|
+
fail('npm publishing must not require local development dependencies');
|
|
72
|
+
}
|
|
73
|
+
if (!pkg.scripts.prepack?.includes('nexowatt-prebuilt-release-selftest.cjs')) {
|
|
74
|
+
fail('npm packaging does not verify the sealed prebuilt release');
|
|
75
|
+
}
|
|
70
76
|
|
|
71
77
|
console.log('[NexoWatt EOS merge update selftest] OK (flat overwrite + EMS merge + version repair + guarded verification)');
|