iobroker.eos-admin 7.10.0 → 7.10.2

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.
Files changed (65) hide show
  1. package/INSTALL_TEST_V7.10.2.md +22 -0
  2. package/MERGE_UPDATE_README_V7.10.2.md +11 -0
  3. package/NEXOWATT_EOS_BUILD_INFO.json +19 -21
  4. package/NEXOWATT_EOS_PREBUILT_MANIFEST.json +1410 -0
  5. package/PUBLISH_STABLE_V7.10.2.md +21 -0
  6. package/README.md +16 -6
  7. package/README_STABILITY_V7.10.2.md +20 -0
  8. package/RELEASE_ACCEPTANCE_V7.10.2.md +13 -0
  9. package/RELEASE_NOTES_V7.10.2.md +11 -0
  10. package/adminWww/assets/Intro-DkwRiz1n-v84.js +1 -1
  11. package/adminWww/assets/bootstrap-COulQZax-v84.js +2 -2
  12. package/adminWww/css/eos-ems-overview.css +5 -3
  13. package/adminWww/css/nexowatt-native-shell.css +85 -413
  14. package/adminWww/index.html +20 -21
  15. package/adminWww/js/eos-account-management.js +28 -19
  16. package/adminWww/js/eos-assistant.js +1 -1
  17. package/adminWww/js/eos-ems-overview.js +1 -1
  18. package/adminWww/js/eos-role-bootstrap.js +17 -80
  19. package/adminWww/js/eos-role-ui.js +28 -4
  20. package/adminWww/js/nexowatt-native-shell.js +1 -1
  21. package/adminWww/static/js/nexowatt-stable-login.js +43 -70
  22. package/adminWww/static/js/nexowatt-stable-v7101.js +27 -0
  23. package/build/lib/eosAutoUpdate.js +418 -20
  24. package/build/lib/eosAutoUpdate.js.map +1 -0
  25. package/build/lib/eosRequestSecurity.js +4 -1
  26. package/build/lib/eosRequestSecurity.js.map +1 -0
  27. package/build/lib/web.js +161 -254
  28. package/build/lib/web.js.map +1 -1
  29. package/build/main.js +39 -67
  30. package/io-package.json +72 -7
  31. package/package.json +24 -25
  32. package/tools/nexowatt-account-management-selftest.cjs +15 -19
  33. package/tools/nexowatt-account-password-flow-selftest.cjs +15 -0
  34. package/tools/nexowatt-apply-ems-overview.cjs +4 -2
  35. package/tools/nexowatt-auto-update-selftest.cjs +144 -32
  36. package/tools/nexowatt-backend-runtime-selftest.cjs +147 -0
  37. package/tools/nexowatt-clean-legacy-runtime.cjs +1 -1
  38. package/tools/nexowatt-ems-overview-selftest.cjs +1 -1
  39. package/tools/nexowatt-ensure-release-defaults.cjs +1 -1
  40. package/tools/nexowatt-login-layout-selftest.cjs +9 -13
  41. package/tools/nexowatt-merge-update-selftest.cjs +7 -1
  42. package/tools/nexowatt-modern-ui-selftest.cjs +10 -46
  43. package/tools/nexowatt-password-write-selftest.cjs +46 -16
  44. package/tools/nexowatt-prebuilt-release-selftest.cjs +292 -0
  45. package/tools/nexowatt-release-defaults-selftest.cjs +1 -1
  46. package/tools/nexowatt-runtime-cleanup-selftest.cjs +6 -8
  47. package/tools/nexowatt-stable-v7102-selftest.cjs +51 -0
  48. package/tools/nexowatt-sync-release-version.cjs +43 -5
  49. package/tools/nexowatt-ui-overview-runtime-selftest.cjs +2 -3
  50. package/tools/nexowatt-validate-package.cjs +54 -29
  51. package/tools/nexowatt-version-sync-selftest.cjs +18 -1
  52. package/INSTALL_TEST_V7.10.0.md +0 -11
  53. package/MERGE_UPDATE_README_V7.10.0.md +0 -5
  54. package/PUBLISH_STABLE_V7.10.0.md +0 -15
  55. package/README_STABILITY_V7.10.0.md +0 -3
  56. package/RELEASE_ACCEPTANCE_V7.10.0.md +0 -11
  57. package/RELEASE_NOTES_V7.10.0.md +0 -17
  58. package/adminWww/js/eos-release-watch.js +0 -77
  59. package/adminWww/static/js/nexowatt-stable-v7100.js +0 -111
  60. package/build/lib/eosPassword.js +0 -72
  61. package/build/lib/nexowattStableAuth.js +0 -74
  62. package/src/lib/eosAutoUpdate.ts +0 -320
  63. package/tools/nexowatt-cache-update-selftest.cjs +0 -12
  64. package/tools/nexowatt-request-security-selftest.cjs +0 -11
  65. package/tools/nexowatt-stable-v7100-selftest.cjs +0 -17
@@ -11,6 +11,8 @@ const fail = msg => {
11
11
  const read = file => fs.readFileSync(path.join(root, file), 'utf8');
12
12
  const readJson = file => JSON.parse(read(file));
13
13
  const exists = file => fs.existsSync(path.join(root, file));
14
+ const canonicalPrepublishOnly = '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';
15
+ const canonicalPrepack = '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';
14
16
 
15
17
  const pkg = readJson('package.json');
16
18
  const pkgLock = readJson('package-lock.json');
@@ -41,20 +43,34 @@ if (pkg.scripts['test:eos-version-sync'] !== 'node tools/nexowatt-version-sync-s
41
43
  if (pkg.scripts['verify:eos-merge'] !== 'node tools/nexowatt-merge-update-selftest.cjs') fail('merge update selftest script is missing or incorrect');
42
44
  if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-version-sync-selftest.cjs')) fail('version sync selftest is not part of check:eos-stability');
43
45
  if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-merge-update-selftest.cjs')) fail('merge update selftest is not part of check:eos-stability');
44
- if (pkg.scripts['check:eos-stable-v7100'] !== 'node tools/nexowatt-stable-v7100-selftest.cjs') fail('stable v7100 selftest script is missing or incorrect');
45
- if (pkg.scripts['test:eos-password-write'] !== 'node tools/nexowatt-password-write-selftest.cjs') fail('password write selftest script is missing');
46
- if (pkg.scripts['test:eos-request-security'] !== 'node tools/nexowatt-request-security-selftest.cjs') fail('request security selftest script is missing');
47
- if (pkg.scripts['test:eos-cache-update'] !== 'node tools/nexowatt-cache-update-selftest.cjs') fail('cache update selftest script is missing');
48
- for (const marker of ['nexowatt-password-write-selftest.cjs','nexowatt-request-security-selftest.cjs','nexowatt-cache-update-selftest.cjs']) if (!pkg.scripts['check:eos-stability']?.includes(marker)) fail(`stability check must execute ${marker}`);
49
- if (!pkg.scripts.prepublishOnly?.startsWith('npm run sync:eos-version && npm run prepare:eos-release-defaults && npm run check:eos-publish-channel')) fail('prepublishOnly must synchronize versions and normalize release defaults before the publish channel guard');
46
+ if (pkg.scripts['check:eos-stable-v7102'] !== 'node tools/nexowatt-stable-v7102-selftest.cjs') fail('stable v7102 selftest script is missing or incorrect');
47
+ if (pkg.scripts.prepublishOnly !== canonicalPrepublishOnly) fail('prepublishOnly must use the dependency-free direct-publish workflow');
48
+ if (/\b(?:tsc|tsx)\b|build:(?:backend|frontend)|\bnpx\b|npm\s+(?:i|install|ci)\b/i.test(pkg.scripts.prepublishOnly || '')) fail('prepublishOnly must not require local development dependencies');
49
+ if (pkg.scripts['check:eos-prebuilt-release'] !== 'node tools/nexowatt-prebuilt-release-selftest.cjs') fail('prebuilt release selftest script is missing or incorrect');
50
+ if (pkg.scripts['seal:eos-prebuilt-release'] !== 'node tools/nexowatt-prebuilt-release-selftest.cjs --write') fail('prebuilt release sealing script is missing or incorrect');
51
+ const backendRuntimeSelftest = read('tools/nexowatt-backend-runtime-selftest.cjs');
52
+ if (!backendRuntimeSelftest.includes('dependency-free on Windows')) fail('backend runtime selftest is missing the cross-platform publish marker');
53
+ if (/const\s+npm\s*=\s*process\.platform|spawnSync\(\s*npm\s*,|['"]npm\.cmd['"]/.test(backendRuntimeSelftest)) fail('backend runtime selftest must not spawn a nested npm process');
54
+ if (!(pkg.files || []).some(value => String(value).replace(/\\/g, '/').replace(/\/+$/, '') === 'build')) fail('package.json files must include the complete build directory');
55
+ if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-prebuilt-release-selftest.cjs')) fail('prebuilt release selftest is not part of check:eos-stability');
50
56
  if (pkg.scripts['precheck:eos-package'] !== 'npm run sync:eos-version && npm run prepare:eos-release-defaults && npm run clean:eos-runtime') fail('precheck:eos-package must synchronize versions, normalize release defaults and clean stale runtime files');
51
57
  if (pkg.scripts['precheck:eos-stability'] !== 'npm run sync:eos-version && npm run prepare:eos-release-defaults && npm run clean:eos-runtime') fail('precheck:eos-stability must synchronize versions, normalize release defaults and clean stale runtime files');
52
58
  if (pkg.scripts['test:eos-publish-channel'] !== 'node tools/nexowatt-publish-channel-selftest.cjs') fail('publish channel selftest script is missing');
53
59
  if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-publish-channel-selftest.cjs')) fail('stability check must execute the publish channel selftest');
54
60
  if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-release-defaults-selftest.cjs')) fail('stability check must execute the release-default selftest');
61
+ if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-password-write-selftest.cjs')) fail('password-write selftest is not part of check:eos-stability');
62
+ if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-account-password-flow-selftest.cjs')) fail('account-password flow selftest is not part of check:eos-stability');
55
63
  if (io.native?.auth !== true) fail('fresh sales installations must default to authenticated access');
56
64
  if (io.native?.eosHideLegacyBackupFromNonAdmins !== true) fail('internal BackItUp reserve must default to Admin/Service visibility');
57
65
  if (io.native?.nexowattHideLegacyBackupFromNonAdmins !== true) fail('NexoWatt backup visibility compatibility flag must default to true');
66
+ const instanceObjectIds = new Set((io.instanceObjects || []).map(object => object?._id));
67
+ if (!instanceObjectIds.has('info.nexowattStableUpdatesEnabled')) fail('restart-safe auto-update enabled state is missing');
68
+ if (!instanceObjectIds.has('info.nexowattStableUpdatesState')) fail('restart-safe auto-update runtime state is missing');
69
+ for (const key of ['description', 'files', 'scripts', 'nexowattReleasePolicy']) {
70
+ if (JSON.stringify(pkgLock.packages?.['']?.[key]) !== JSON.stringify(pkg[key])) {
71
+ fail(`package-lock root ${key} must match package.json`);
72
+ }
73
+ }
58
74
  for (const [label, value] of [
59
75
  ['io-package common.version', io.common?.version],
60
76
  ['io-package top-level version', io.version],
@@ -104,7 +120,6 @@ for (const file of [
104
120
  'adminWww/js/eos-basic-settings.js',
105
121
  'adminWww/js/eos-role-ui.js',
106
122
  'adminWww/js/eos-account-management.js',
107
- 'adminWww/js/eos-release-watch.js',
108
123
  'adminWww/js/eos-assistant.js',
109
124
  'adminWww/css/nexowatt-native-shell.css',
110
125
  'adminWww/img/eos/nexowatt-192.png',
@@ -112,30 +127,31 @@ for (const file of [
112
127
  'src-admin/src/components/Drawer.tsx',
113
128
  'src-admin/src/components/DrawerItem.tsx',
114
129
  'admin/admin.svg',
130
+ 'build/lib/eosRequestSecurity.js',
115
131
  'LICENSE',
116
132
  'NEXOWATT_PROPRIETARY_LICENSE.md',
117
133
  'THIRD_PARTY_NOTICES.md',
118
- 'README_STABILITY_V7.10.0.md',
119
- 'RELEASE_NOTES_V7.10.0.md',
120
- 'PUBLISH_STABLE_V7.10.0.md',
121
- 'INSTALL_TEST_V7.10.0.md',
122
- 'RELEASE_ACCEPTANCE_V7.10.0.md',
134
+ 'README_STABILITY_V7.10.2.md',
135
+ 'RELEASE_NOTES_V7.10.2.md',
136
+ 'PUBLISH_STABLE_V7.10.2.md',
137
+ 'INSTALL_TEST_V7.10.2.md',
138
+ 'RELEASE_ACCEPTANCE_V7.10.2.md',
123
139
  'MERGE_UPDATE.ps1',
124
140
  'MERGE_UPDATE.cmd',
125
- 'MERGE_UPDATE_README_V7.10.0.md',
141
+ 'MERGE_UPDATE_README_V7.10.2.md',
126
142
  'tools/nexowatt-patch-built-frontend.cjs',
127
143
  'tools/nexowatt-native-shell-selftest.cjs',
128
144
  'tools/nexowatt-clean-legacy-runtime.cjs',
129
145
  'tools/nexowatt-runtime-cleanup-selftest.cjs',
130
146
  'tools/nexowatt-esm-syntax-selftest.cjs',
131
147
  'tools/nexowatt-import-integrity-selftest.cjs',
148
+ 'tools/nexowatt-backend-runtime-selftest.cjs',
149
+ 'tools/nexowatt-prebuilt-release-selftest.cjs',
150
+ 'NEXOWATT_EOS_PREBUILT_MANIFEST.json',
132
151
  'tools/nexowatt-entrypoint-smoke-selftest.cjs',
133
152
  'tools/nexowatt-role-access-selftest.cjs',
134
153
  'tools/nexowatt-first-login-selftest.cjs',
135
154
  'tools/nexowatt-account-management-selftest.cjs',
136
- 'tools/nexowatt-password-write-selftest.cjs',
137
- 'tools/nexowatt-request-security-selftest.cjs',
138
- 'tools/nexowatt-cache-update-selftest.cjs',
139
155
  'tools/nexowatt-modern-ui-selftest.cjs',
140
156
  'tools/nexowatt-login-layout-selftest.cjs',
141
157
  'tools/nexowatt-internal-reserve-selftest.cjs',
@@ -143,12 +159,14 @@ for (const file of [
143
159
  'tools/nexowatt-sync-release-version.cjs',
144
160
  'tools/nexowatt-version-sync-selftest.cjs',
145
161
  'tools/nexowatt-merge-update-selftest.cjs',
146
- 'tools/nexowatt-stable-v7100-selftest.cjs',
162
+ 'tools/nexowatt-stable-v7102-selftest.cjs',
163
+ 'tools/nexowatt-password-write-selftest.cjs',
164
+ 'tools/nexowatt-account-password-flow-selftest.cjs',
147
165
  'tools/nexowatt-ems-overview-selftest.cjs',
148
166
  'tools/nexowatt-ui-overview-runtime-selftest.cjs',
149
167
  'adminWww/js/eos-ems-overview.js',
150
168
  'adminWww/css/eos-ems-overview.css',
151
- 'adminWww/static/js/nexowatt-stable-v7100.js',
169
+ 'adminWww/static/js/nexowatt-stable-v7101.js',
152
170
  'src-admin/src/components/Intro/NexoWattEmsOverview.tsx',
153
171
  'tools/nexowatt-publish-channel-guard.cjs',
154
172
  'tools/nexowatt-publish-channel-selftest.cjs',
@@ -176,8 +194,8 @@ const shellTag = String(buildInfo.shellCacheTag || shellCache);
176
194
  if (!runtime || !Number.isFinite(runtimeNumber)) fail(`invalid runtimeEntry ${runtime}`);
177
195
  if (!Number.isFinite(shellCache)) fail(`invalid shellCacheVersion ${buildInfo.shellCacheVersion}`);
178
196
  for (const marker of [
179
- `hostInit-${runtime}.js?v=${shellTag}`,
180
- `index-CQZugZ1z-${runtime}.js?v=${shellTag}`,
197
+ `hostInit-${runtime}.js?v=${runtimeNumber}`,
198
+ `index-CQZugZ1z-${runtime}.js?v=${runtimeNumber}`,
181
199
  `eos-manual-write-policy.js?v=${shellTag}`,
182
200
  `nexowatt-native-shell.css?v=${shellTag}`,
183
201
  `nexowatt-native-shell.js?v=${shellTag}`,
@@ -187,13 +205,13 @@ for (const marker of [
187
205
  if (!index.includes(`eos-role-bootstrap.js?v=${shellTag}`)) fail('role bootstrap cache key mismatch');
188
206
  if (!index.includes(`eos-branding-sanitizer.js?v=${shellTag}`)) fail('branding sanitizer cache key mismatch');
189
207
  if (!index.includes(`eos-role-ui.js?v=${shellTag}`)) fail('role UI cache key mismatch');
190
- if (!index.includes(`eos-account-management.js?v=${shellTag}`)) fail('account management cache key mismatch');
208
+ if (index.includes('eos-account-management.js')) fail('custom account-management runtime must not be loaded in standard password mode');
209
+ if (!index.includes(`eos-auto-update.js?v=${shellTag}`)) fail('auto-update cache key mismatch');
191
210
  if (!index.includes(`eos-assistant.js?v=${shellTag}`)) fail('EOS Assist cache key mismatch');
192
211
  if (!index.includes(`eos-ems-overview.js?v=${shellTag}`)) fail('EMS overview cache key mismatch');
193
212
  if (!index.includes(`eos-ems-overview.css?v=${shellTag}`)) fail('EMS overview CSS cache key mismatch');
194
- if (!index.includes(`nexowatt-stable-v7100.js?v=${shellTag}`)) fail('stable v7100 cache key mismatch');
195
- if (!index.includes(`eos-release-watch.js?v=${shellTag}`)) fail('release watcher cache key mismatch');
196
- if (index.indexOf(`eos-manual-write-policy.js?v=${shellTag}`) > index.indexOf(`hostInit-${runtime}.js?v=${shellTag}`)) fail('manual-write policy must load before the React runtime');
213
+ if (!index.includes(`nexowatt-stable-v7101.js?v=${shellTag}`)) fail('stable v98 cache key mismatch');
214
+ if (index.indexOf(`eos-manual-write-policy.js?v=${shellTag}`) > index.indexOf(`hostInit-${runtime}.js?v=${runtimeNumber}`)) fail('manual-write policy must load before the React runtime');
197
215
  if (!index.includes('class="eos-native-shell"')) fail('native NexoWatt shell class missing');
198
216
  for (const legacy of ['eos-branding.js', 'eos-security-ui.js', 'eos-console-quiet.js', 'eos-objects-state-tools.js']) {
199
217
  if (index.includes(legacy)) fail(`legacy browser overlay still loaded: ${legacy}`);
@@ -241,7 +259,7 @@ if (accountManagement.includes("launcher.className = 'eos-account-management-lau
241
259
  if (accountManagement.includes('new MutationObserver')) fail('account-management runtime adds a second broad DOM observer');
242
260
  if (read('src-admin/public/js/eos-account-management.js') !== accountManagement) fail('account-management source/build drift');
243
261
  const roleBootstrap = read('adminWww/js/eos-role-bootstrap.js');
244
- if (!roleBootstrap.includes('installIntegratedFirstLogin') || !roleBootstrap.includes('v7100 normal-login first activation')) fail('compact integrated first-login is incomplete');
262
+ if (roleBootstrap.includes('installIntegratedFirstLogin(base);') || roleBootstrap.includes('showFirstLoginPassword(resolved, base);')) fail('forced first-login UI must be disabled');
245
263
  if (/data-eos-account=|selector\.innerHTML/.test(roleBootstrap)) fail('login role buttons must not enlarge the normal login card');
246
264
  if (!roleBootstrap.includes('nexowatt/account/passwordless-status') || !roleBootstrap.includes('eligibility.allowed')) fail('server-checked first-login eligibility is incomplete');
247
265
  if (roleBootstrap.includes('installPasswordlessFirstLoginLauncher')) fail('old first-login launcher remains active');
@@ -254,22 +272,29 @@ if (!mf.includes(`remoteEntry-${runtime}.js`) || !mf.includes(`index-D2ymscJA-${
254
272
  const webBuild = read('build/lib/web.js');
255
273
  if (!webBuild.includes('refreshLifetime: 60 * 60 * 24 * 7')) fail('build/lib/web.js must keep upstream-compatible refresh lifetime');
256
274
  if (!webBuild.includes('Follow upstream admin semantics again')) fail('build/lib/web.js lacks session compatibility fix');
275
+ if (!exists('build/lib/eosRequestSecurity.js')) fail('build/lib/eosRequestSecurity.js is missing');
276
+ const autoUpdateSource = read('src/lib/eosAutoUpdate.ts');
277
+ if (autoUpdateSource.includes('extendForeignObjectAsync(this.instanceId')) fail('auto-update runtime must not write the running instance native configuration');
278
+ if (!autoUpdateSource.includes("const ENABLED_STATE_ID = 'info.nexowattStableUpdatesEnabled'")) fail('restart-safe auto-update state storage is missing');
257
279
  const mainBuild = read('build/main.js');
258
280
  if (!mainBuild.includes('v37 BackItUp/runtime-adapter compatibility')) fail('build/main.js lacks BackItUp compatibility guard');
259
281
 
260
282
  if (!pkg.scripts['nexowatt:patch-built-frontend']) fail('missing nexowatt:patch-built-frontend script');
261
283
  if (pkg.scripts['check:eos-esm'] !== 'node tools/nexowatt-esm-syntax-selftest.cjs') fail('check:eos-esm script is missing or incorrect');
262
284
  if (pkg.scripts['check:eos-imports'] !== 'node tools/nexowatt-import-integrity-selftest.cjs') fail('check:eos-imports script is missing or incorrect');
285
+ if (pkg.scripts['check:eos-backend-runtime'] !== 'node tools/nexowatt-backend-runtime-selftest.cjs') fail('check:eos-backend-runtime script is missing or incorrect');
263
286
  if (pkg.scripts['check:eos-entry'] !== 'node tools/nexowatt-entrypoint-smoke-selftest.cjs') fail('check:eos-entry script is missing or incorrect');
264
287
  if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-esm-syntax-selftest.cjs')) fail('ESM syntax selftest is not part of check:eos-stability');
265
288
  if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-import-integrity-selftest.cjs')) fail('import integrity selftest is not part of check:eos-stability');
289
+ if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-backend-runtime-selftest.cjs')) fail('backend runtime selftest is not part of check:eos-stability');
266
290
  if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-entrypoint-smoke-selftest.cjs')) fail('entrypoint smoke selftest is not part of check:eos-stability');
267
291
  if (pkg.scripts['clean:eos-runtime'] !== 'node tools/nexowatt-clean-legacy-runtime.cjs') fail('clean:eos-runtime script is missing or incorrect');
268
- if (pkg.scripts.prepack !== 'node tools/nexowatt-sync-release-version.cjs --quiet && node tools/nexowatt-clean-legacy-runtime.cjs --quiet') fail('prepack must silently synchronize versions and clean stale runtime files');
269
- if (!pkg.scripts.build?.includes('npm run clean:eos-runtime')) fail('build must finish with runtime cleanup');
292
+ if (pkg.scripts.prepack !== canonicalPrepack) fail('prepack must verify the sealed prebuilt artifact without tsc/tsx');
293
+ if (/\b(?:tsc|tsx)\b|build:(?:backend|frontend)|\bnpx\b|npm\s+(?:i|install|ci)\b/i.test(pkg.scripts.prepack || '')) fail('prepack must not require local development dependencies');
294
+ if (pkg.scripts.build !== 'npm run build:frontend && npm run build:backend && npm run clean:eos-runtime && npm run seal:eos-prebuilt-release') fail('build must clean and seal the prebuilt release after compilation');
270
295
  if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-role-access-selftest.cjs')) fail('role access selftest is not part of check:eos-stability');
271
- if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-first-login-selftest.cjs')) fail('first-login selftest is not part of check:eos-stability');
272
- if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-account-management-selftest.cjs')) fail('account-management selftest is not part of check:eos-stability');
296
+ if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-account-password-flow-selftest.cjs')) fail('standard account-password flow selftest is not part of check:eos-stability');
297
+ if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-account-password-flow-selftest.cjs')) fail('standard account-password management selftest is not part of check:eos-stability');
273
298
  if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-modern-ui-selftest.cjs')) fail('modern-UI selftest is not part of check:eos-stability');
274
299
  if (pkg.scripts['test:eos-login-layout'] !== 'node tools/nexowatt-login-layout-selftest.cjs') fail('login-layout selftest script is missing or incorrect');
275
300
  if (!pkg.scripts['check:eos-stability']?.includes('nexowatt-login-layout-selftest.cjs')) fail('login-layout selftest is not part of check:eos-stability');
@@ -24,7 +24,19 @@ try {
24
24
  const currentPkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
25
25
  const version = currentPkg.version;
26
26
  writeJson('package.json', currentPkg);
27
- writeJson('package-lock.json', { name: currentPkg.name, version: '7.9.92', packages: { '': { version: '7.9.92' } } });
27
+ writeJson('package-lock.json', {
28
+ name: currentPkg.name,
29
+ version: '7.9.92',
30
+ packages: {
31
+ '': {
32
+ version: '7.9.92',
33
+ description: 'stale description',
34
+ files: ['README_STABILITY_V7.9.92.md'],
35
+ scripts: { 'check:eos-stable-v92': 'node stale.js' },
36
+ nexowattReleasePolicy: { distTag: 'latest', purpose: 'stale 7.9.92 policy' },
37
+ },
38
+ },
39
+ });
28
40
  writeJson('io-package.json', {
29
41
  version: '7.9.92',
30
42
  common: {
@@ -75,6 +87,11 @@ try {
75
87
  ]) {
76
88
  if (actual !== version) fail(`${label} was not synchronized: ${actual}`);
77
89
  }
90
+ for (const key of ['description', 'files', 'scripts', 'nexowattReleasePolicy']) {
91
+ if (JSON.stringify(lock.packages[''][key]) !== JSON.stringify(currentPkg[key])) {
92
+ fail(`package-lock root ${key} was not synchronized`);
93
+ }
94
+ }
78
95
  if (io.common.meta !== `${expectedBase}/io-package.json`) fail('io-package URL was not synchronized');
79
96
  if (entry.meta !== `${expectedBase}/io-package.json`) fail('repository entry URL was not synchronized');
80
97
  if (!fs.existsSync(path.join(temp, build.repositoryEntry))) fail('current repository entry was not created');
@@ -1,11 +0,0 @@
1
- # Installationstest 7.10.0
2
-
3
- ```bash
4
- cd /opt/iobroker
5
- iobroker stop eos-admin.0
6
- npm install --no-save --omit=dev iobroker.eos-admin@7.10.0
7
- iobroker upload eos-admin
8
- iobroker restart eos-admin.0
9
- ```
10
-
11
- Danach Browser mit `Strg + F5` vollständig neu laden. Für EMS-Livedaten muss `iobroker.nexowatt-ui` mindestens `0.8.198` installiert und gestartet sein.
@@ -1,5 +0,0 @@
1
- # NexoWatt EOS Admin 7.10.0 – Merge-Update
2
-
3
- Die flache Merge-ZIP direkt in den vorhandenen Repository-Ordner entpacken und anschließend `MERGE_UPDATE.cmd` ausführen.
4
-
5
- Enthalten sind alle Änderungen aus 7.9.96 einschließlich nativer Rollenübersicht, persönlicher Erstkennwortvergabe und EMS-Diagnose sowie die Korrekturen für Login-Geometrie und produktive AdminConnection.
@@ -1,15 +0,0 @@
1
- # Stable-Veröffentlichung 7.10.0
2
-
3
- ```powershell
4
- npm login
5
- npm whoami
6
- npm run check:eos-release
7
- npm publish --dry-run --tag latest
8
- npm publish --tag latest
9
- ```
10
-
11
- Das geprüfte Tarball kann alternativ direkt veröffentlicht werden:
12
-
13
- ```powershell
14
- npm publish .\iobroker.eos-admin-7.10.0.tgz --tag latest
15
- ```
@@ -1,3 +0,0 @@
1
- # NexoWatt EOS Admin 7.10.0 – Stabilität
2
-
3
- Die native NexoWatt-Autoaktualisierung ist standardmäßig aktiv und kann im Admin-Cockpit deaktiviert werden. Sie setzt ausschließlich für installierte NexoWatt-Adapter aus dem erkannten Stable-Repository die ioBroker-Richtlinie `major`. Fremdadapter bleiben unverändert. Beim Abschalten werden vorherige Richtlinien wiederhergestellt.
@@ -1,11 +0,0 @@
1
- # Release-Abnahme 7.10.0
2
-
3
- - [ ] Login-Karte ist ordentlich proportioniert und nur moderat größer als vor 7.9.96.
4
- - [ ] Normale Anmeldung, falsches Passwort und persönliche Erstkennwortvergabe erzeugen keine innere Scrollleiste.
5
- - [ ] Erstkennwort `nexowatt` führt zur verpflichtenden persönlichen Kennwortvergabe.
6
- - [ ] Native Adapterkarten sind bei Admin, Installateur und Endkunde sichtbar, soweit die Rolle sie freigibt.
7
- - [ ] NexoWatt-UI-Karte ist in der Übersicht vorhanden.
8
- - [ ] EMS-Kachel zeigt nach Verbindungsaufbau Livewerte aus `nexowatt-ui.*.info.adminOverview.*`.
9
- - [ ] UI-Version unter `0.8.198` wird verständlich gemeldet.
10
- - [ ] Die EMS-Kachel enthält keinen Schreibpfad.
11
- - [ ] `npm run check:eos-release` und `npm publish --dry-run --tag latest` sind vollständig grün.
@@ -1,17 +0,0 @@
1
- # NexoWatt EOS Admin 7.10.0
2
-
3
- ## Korrekturen
4
-
5
- - Dauerhafter vertikaler Scrollbalken in der Cockpit-/Übersichtsfläche.
6
- - Login wieder kompakt und sauber ausgerichtet; keine überlappenden Feldbeschriftungen.
7
- - Erstpasswort und Passwort-Reset verwenden die native ioBroker-Passwortverwaltung mit kanonischer Benutzer-ID und Kompatibilitäts-Fallback.
8
- - Passwort-Metadaten werden erst nach Hash- und Credential-Prüfung freigegeben.
9
- - Präzise Fehlermeldungen für nicht gespeicherte oder nicht verifizierte Passwörter.
10
- - Cache-Tag 7100 und automatische Release-Überwachung gegen gemischte Browserstände.
11
- - Automatische Stable-Updates für installierte NexoWatt-Adapter bleiben standardmäßig aktiv und abschaltbar.
12
-
13
- ## Unverändert
14
-
15
- - EMS-Diagnose bleibt rein lesend.
16
- - Der nicht vorhandene Link zur vollständigen EMS-Diagnose bleibt entfernt.
17
- - Der Bearbeitungsstift bleibt im unteren Kartenbereich.
@@ -1,77 +0,0 @@
1
- (() => {
2
- 'use strict';
3
- const RELEASE = '7.10.0';
4
- const RELEASE_KEY = 'nexowatt.eos.loadedRelease';
5
- const RELOAD_KEY = 'nexowatt.eos.reloadTarget';
6
- const CHECK_MS = 15000;
7
- let refreshing = false;
8
-
9
- const normalize = value => String(value || '').trim().replace(/^v/i, '');
10
- const validRelease = value => /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(normalize(value));
11
- const reloadUrl = version => {
12
- const url = new URL(window.location.href);
13
- url.searchParams.set('_eosRelease', normalize(version) || RELEASE);
14
- url.searchParams.set('_eosReload', String(Date.now()));
15
- return url.toString();
16
- };
17
- const purgeBrowserCaches = async () => {
18
- const jobs = [];
19
- try {
20
- if ('caches' in window) {
21
- jobs.push(caches.keys().then(keys => Promise.all(keys.map(key => caches.delete(key)))));
22
- }
23
- } catch (_) { /* Cache API is optional */ }
24
- try {
25
- if (navigator.serviceWorker?.getRegistrations) {
26
- jobs.push(navigator.serviceWorker.getRegistrations().then(rows => Promise.all(rows.map(row => row.unregister()))));
27
- }
28
- } catch (_) { /* service workers may be unavailable */ }
29
- await Promise.allSettled(jobs);
30
- };
31
- const reloadFor = async version => {
32
- const target = normalize(version) || RELEASE;
33
- if (refreshing || sessionStorage.getItem(RELOAD_KEY) === target) return;
34
- refreshing = true;
35
- sessionStorage.setItem(RELOAD_KEY, target);
36
- document.documentElement.classList.add('eos-release-refreshing');
37
- await purgeBrowserCaches();
38
- window.location.replace(reloadUrl(target));
39
- };
40
- const checkServerVersion = async () => {
41
- try {
42
- const endpoint = new URL('./version', window.location.href);
43
- endpoint.searchParams.set('_eosTs', String(Date.now()));
44
- const response = await fetch(endpoint, {
45
- cache: 'no-store',
46
- credentials: 'same-origin',
47
- headers: { 'Cache-Control': 'no-cache' },
48
- });
49
- if (!response.ok) return;
50
- const serverVersion = normalize(await response.text());
51
- if (validRelease(serverVersion) && serverVersion !== RELEASE) {
52
- await reloadFor(serverVersion);
53
- }
54
- } catch (_) { /* adapter restart or temporary network interruption */ }
55
- };
56
-
57
- window.NEXOWATT_EOS_RELEASE = RELEASE;
58
- const previous = normalize(localStorage.getItem(RELEASE_KEY));
59
- localStorage.setItem(RELEASE_KEY, RELEASE);
60
- const loadedFor = normalize(new URL(window.location.href).searchParams.get('_eosRelease'));
61
- if (previous && previous !== RELEASE && loadedFor !== RELEASE) {
62
- void reloadFor(RELEASE);
63
- } else {
64
- sessionStorage.removeItem(RELOAD_KEY);
65
- }
66
-
67
- window.addEventListener('focus', () => void checkServerVersion());
68
- document.addEventListener('visibilitychange', () => {
69
- if (document.visibilityState === 'visible') void checkServerVersion();
70
- });
71
- window.setInterval(() => void checkServerVersion(), CHECK_MS);
72
- window.NEXOWATT_EOS_RELEASE_WATCH = Object.freeze({
73
- release: RELEASE,
74
- check: checkServerVersion,
75
- purge: purgeBrowserCaches,
76
- });
77
- })();
@@ -1,111 +0,0 @@
1
- (() => {
2
- 'use strict';
3
- const VERSION = 'v7100-scroll-login-auto-update';
4
- const MANAGED_USERS = new Set(['installer', 'guest', 'user']);
5
- const normalizeUser = value => String(value || '').trim().toLowerCase().replace(/^system\.user\./, '');
6
- const INTRO_STYLE_PROPERTIES = [
7
- 'position', 'top', 'right', 'bottom', 'left', 'width', 'height', 'min-height', 'max-height',
8
- 'margin', 'overflow-x', 'overflow-y', 'overscroll-behavior', 'scrollbar-gutter',
9
- ];
10
- const isIntroRoute = () => {
11
- const hash = decodeURIComponent(window.location.hash || '').toLowerCase();
12
- const explicitTab = hash.match(/(?:^|[#/])(tab-[a-z0-9_-]+)(?:[/?&]|$)/)?.[1] || '';
13
- if (explicitTab) return explicitTab === 'tab-intro';
14
- return document.documentElement.classList.contains('eos-route-intro')
15
- || !hash
16
- || hash === '#'
17
- || hash === '#/';
18
- };
19
- const bindScrollInput = paper => {
20
- if (paper.dataset.nexowattScrollBound === 'true') return;
21
- paper.dataset.nexowattScrollBound = 'true';
22
- paper.addEventListener('wheel', event => {
23
- if (!event.deltaY || paper.scrollHeight <= paper.clientHeight + 1) return;
24
- const before = paper.scrollTop;
25
- paper.scrollTop += event.deltaY;
26
- if (paper.scrollTop !== before) event.preventDefault();
27
- }, { passive: false });
28
- paper.addEventListener('keydown', event => {
29
- if (paper.scrollHeight <= paper.clientHeight + 1) return;
30
- const step = Math.max(120, Math.round(paper.clientHeight * .78));
31
- if (event.key === 'PageDown') paper.scrollTop += step;
32
- else if (event.key === 'PageUp') paper.scrollTop -= step;
33
- else if (event.key === 'Home' && event.ctrlKey) paper.scrollTop = 0;
34
- else if (event.key === 'End' && event.ctrlKey) paper.scrollTop = paper.scrollHeight;
35
- else return;
36
- event.preventDefault();
37
- });
38
- };
39
- const disableCockpitScroll = () => {
40
- const root = document.documentElement;
41
- root.classList.remove('eos-intro-scroll-enabled');
42
- const paper = document.getElementById('app-paper');
43
- if (!paper || paper.dataset.nexowattScrollable !== 'true') return;
44
- delete paper.dataset.nexowattScrollable;
45
- for (const property of INTRO_STYLE_PROPERTIES) paper.style.removeProperty(property);
46
- };
47
- const ensureCockpitScroll = () => {
48
- const root = document.documentElement;
49
- const paper = document.getElementById('app-paper');
50
- if (!paper || !root.classList.contains('eos-app')) return;
51
- if (!isIntroRoute()) {
52
- disableCockpitScroll();
53
- return;
54
- }
55
- // eos-route-* is owned by the native shell; only add our dedicated scroll flag.
56
- root.classList.add('eos-intro-scroll-enabled');
57
- paper.dataset.nexowattScrollable = 'true';
58
- if (paper.tabIndex < 0) paper.tabIndex = 0;
59
- const styles = {
60
- position: 'fixed',
61
- top: 'var(--nx-content-top, 154px)',
62
- right: 'var(--nx-page-x, 12px)',
63
- bottom: '8px',
64
- left: 'var(--nx-page-x, 12px)',
65
- width: 'auto',
66
- height: 'auto',
67
- minHeight: '0',
68
- maxHeight: 'none',
69
- margin: '0',
70
- overflowX: 'hidden',
71
- overflowY: 'scroll',
72
- overscrollBehavior: 'contain',
73
- scrollbarGutter: 'stable',
74
- };
75
- for (const [name, value] of Object.entries(styles)) {
76
- paper.style.setProperty(name.replace(/[A-Z]/g, char => `-${char.toLowerCase()}`), value, 'important');
77
- }
78
- bindScrollInput(paper);
79
- };
80
- const apply = () => {
81
- document.documentElement.classList.add('eos-assist-disabled');
82
- document.querySelectorAll('.eos-assist-root,.eos-assist-header-root,[data-eos-assist-root],.eos-passwordless-launcher')
83
- .forEach(element => element.remove());
84
- const username = document.querySelector('input#username,input[name="username"]');
85
- const password = document.querySelector('input#password,input[name="password"]');
86
- const submit = document.querySelector('button[type="submit"],input[type="submit"]');
87
- if (submit && MANAGED_USERS.has(normalizeUser(username?.value)) && !String(password?.value || '')) {
88
- submit.disabled = true;
89
- submit.classList.add('Mui-disabled');
90
- submit.setAttribute('aria-disabled', 'true');
91
- }
92
- ensureCockpitScroll();
93
- };
94
- let scheduled = false;
95
- const schedule = () => {
96
- if (scheduled) return;
97
- scheduled = true;
98
- requestAnimationFrame(() => { scheduled = false; apply(); });
99
- };
100
- const start = () => {
101
- apply();
102
- new MutationObserver(schedule).observe(document.documentElement, { subtree: true, childList: true });
103
- document.addEventListener('input', schedule, true);
104
- document.addEventListener('change', schedule, true);
105
- window.addEventListener('hashchange', schedule);
106
- window.addEventListener('resize', schedule, { passive: true });
107
- window.setInterval(ensureCockpitScroll, 750);
108
- };
109
- document.readyState === 'loading' ? document.addEventListener('DOMContentLoaded', start, { once: true }) : start();
110
- window.NEXOWATT_EOS_STABLE_V7100 = Object.freeze({ version: VERSION, refresh: apply, ensureCockpitScroll, disableCockpitScroll });
111
- })();
@@ -1,72 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.normalizeEosPasswordTarget = normalizeEosPasswordTarget;
4
- exports.setEosUserPasswordWithVerification = setEosUserPasswordWithVerification;
5
- exports.verifyEosUserPasswordCredential = verifyEosUserPasswordCredential;
6
- function normalizeEosPasswordTarget(value) {
7
- const raw = String(value || '').trim();
8
- const userId = raw.startsWith('system.user.') ? raw : `system.user.${raw}`;
9
- const userName = userId.replace(/^system\.user\./, '').trim();
10
- if (!userName || userName.includes('.') || !/^system\.user\.[^.]+$/.test(userId)) throw new Error('invalidPasswordTarget');
11
- return { userId, userName };
12
- }
13
- const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
14
- const accepted = result => result === true || (Array.isArray(result) && result[0] === true);
15
- async function readPasswordHash(adapter, userId) {
16
- if (typeof adapter.getForeignObjectAsync !== 'function') return '';
17
- try {
18
- const object = await adapter.getForeignObjectAsync(userId);
19
- return typeof object?.common?.password === 'string' ? object.common.password : '';
20
- }
21
- catch { return ''; }
22
- }
23
- async function callPasswordApi(adapter, target, password, serviceUser, withOptions) {
24
- const options = withOptions ? { user: serviceUser } : null;
25
- if (typeof adapter.setPasswordAsync === 'function') { await adapter.setPasswordAsync(target, password, options); return; }
26
- if (typeof adapter.setPassword === 'function') {
27
- await new Promise((resolve, reject) => adapter.setPassword?.(target, password, options, error => error ? reject(error) : resolve()));
28
- return;
29
- }
30
- throw new Error('passwordApiUnavailable');
31
- }
32
- async function verifyAfterWrite(adapter, normalized, password, serviceUser) {
33
- const hasCredentialCheck = typeof adapter.checkPasswordAsync === 'function';
34
- for (let attempt = 0; attempt < 12; attempt++) {
35
- if (hasCredentialCheck) {
36
- for (const candidate of [normalized.userId, normalized.userName]) {
37
- try {
38
- if (accepted(await adapter.checkPasswordAsync?.(candidate, password, { user: serviceUser }))) return;
39
- }
40
- catch { }
41
- }
42
- }
43
- else if (await readPasswordHash(adapter, normalized.userId)) return;
44
- if (attempt < 11) await delay(55 + attempt * 35);
45
- }
46
- throw new Error(hasCredentialCheck ? 'passwordVerificationFailed' : 'passwordNotPersisted');
47
- }
48
- async function verifyEosUserPasswordCredential(adapter, target, password, serviceUser = 'system.user.admin') {
49
- const normalized = normalizeEosPasswordTarget(target);
50
- await verifyAfterWrite(adapter, normalized, password, serviceUser);
51
- return normalized;
52
- }
53
- async function setEosUserPasswordWithVerification(adapter, target, password, serviceUser = 'system.user.admin') {
54
- const normalized = normalizeEosPasswordTarget(target);
55
- const attempts = [
56
- { apiTarget: normalized.userId, withOptions: true },
57
- { apiTarget: normalized.userName, withOptions: true },
58
- { apiTarget: normalized.userId, withOptions: false },
59
- { apiTarget: normalized.userName, withOptions: false },
60
- ];
61
- let lastError = null;
62
- for (const attempt of attempts) {
63
- try {
64
- await callPasswordApi(adapter, attempt.apiTarget, password, serviceUser, attempt.withOptions);
65
- await verifyAfterWrite(adapter, normalized, password, serviceUser);
66
- return { ...normalized, apiTarget: attempt.apiTarget };
67
- }
68
- catch (error) { lastError = error; }
69
- }
70
- if (lastError instanceof Error) throw lastError;
71
- throw new Error('passwordNotPersisted');
72
- }