iobroker.eos-admin 7.9.92 → 7.9.95

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 (33) hide show
  1. package/{INSTALL_TEST_V7.9.92.md → INSTALL_TEST_V7.9.95.md} +2 -5
  2. package/NEXOWATT_EOS_BUILD_INFO.json +18 -14
  3. package/NEXOWATT_EOS_STABLE_7.9.94.md +16 -0
  4. package/PUBLISH_STABLE_V7.9.95.md +16 -0
  5. package/README_STABILITY_V7.9.95.md +12 -0
  6. package/RELEASE_ACCEPTANCE_V7.9.95.md +11 -0
  7. package/RELEASE_NOTES_V7.9.95.md +12 -0
  8. package/adminWww/css/nexowatt-native-shell.css +2 -2
  9. package/adminWww/index.html +2 -0
  10. package/adminWww/js/eos-assistant.js +5 -124
  11. package/adminWww/static/js/nexowatt-stable-login.js +79 -0
  12. package/build/lib/nexowattStableAuth.js +74 -0
  13. package/build/lib/web.js +24 -7
  14. package/build/main.js +122 -1
  15. package/io-package.json +24 -15
  16. package/package.json +22 -31
  17. package/PUBLISH_STABLE_V7.9.92.md +0 -19
  18. package/README_STABILITY_V7.9.92.md +0 -14
  19. package/RELEASE_ACCEPTANCE_V7.9.92.md +0 -12
  20. package/RELEASE_NOTES_V7.9.92.md +0 -17
  21. package/tools/nexowatt-account-management-selftest.cjs +0 -61
  22. package/tools/nexowatt-clean-legacy-runtime.cjs +0 -147
  23. package/tools/nexowatt-ensure-release-defaults.cjs +0 -72
  24. package/tools/nexowatt-generate-eos-admin-repo-entry.cjs +0 -37
  25. package/tools/nexowatt-generate-repo-entry.cjs +0 -3
  26. package/tools/nexowatt-internal-reserve-selftest.cjs +0 -55
  27. package/tools/nexowatt-login-layout-selftest.cjs +0 -81
  28. package/tools/nexowatt-modern-ui-selftest.cjs +0 -50
  29. package/tools/nexowatt-patch-repo.cjs +0 -54
  30. package/tools/nexowatt-publish-channel-guard.cjs +0 -58
  31. package/tools/nexowatt-release-defaults-selftest.cjs +0 -29
  32. package/tools/nexowatt-runtime-cleanup-selftest.cjs +0 -47
  33. package/tools/nexowatt-validate-package.cjs +0 -246
@@ -1,72 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- const fs = require('node:fs');
5
- const path = require('node:path');
6
-
7
- const CANONICAL_NATIVE_DEFAULTS = Object.freeze({
8
- auth: true,
9
- port: 8081,
10
- eosLockLegacyAdmin: true,
11
- eosHideLegacyAdminFromNonAdmins: true,
12
- eosHideLegacyBackupFromNonAdmins: true,
13
- nexowattHideLegacyBackupFromNonAdmins: true,
14
- eosRequireFirstLoginPassword: true,
15
- });
16
-
17
- /**
18
- * Enforce mandatory source defaults for every NexoWatt EOS sales release.
19
- * This normalizes the repository io-package.json only. Existing installed
20
- * instance configuration is not overwritten during adapter startup.
21
- */
22
- function ensureReleaseDefaults(ioPackage) {
23
- if (!ioPackage || typeof ioPackage !== 'object' || Array.isArray(ioPackage)) {
24
- throw new TypeError('io-package.json must contain a JSON object');
25
- }
26
- const native = ioPackage.native && typeof ioPackage.native === 'object' && !Array.isArray(ioPackage.native)
27
- ? ioPackage.native
28
- : (ioPackage.native = {});
29
- const changes = [];
30
- for (const [key, value] of Object.entries(CANONICAL_NATIVE_DEFAULTS)) {
31
- if (native[key] !== value) {
32
- changes.push({ key, previous: native[key], value });
33
- native[key] = value;
34
- }
35
- }
36
- return {
37
- ioPackage,
38
- changed: changes.length > 0,
39
- fields: changes.map(change => `native.${change.key}`),
40
- changes,
41
- };
42
- }
43
-
44
- function ensureFile(filePath) {
45
- const absolute = path.resolve(filePath);
46
- const parsed = JSON.parse(fs.readFileSync(absolute, 'utf8'));
47
- const result = ensureReleaseDefaults(parsed);
48
- if (result.changed) {
49
- fs.writeFileSync(absolute, `${JSON.stringify(result.ioPackage, null, 2)}\n`, 'utf8');
50
- }
51
- return { file: absolute, ...result };
52
- }
53
-
54
- if (require.main === module) {
55
- const root = path.resolve(__dirname, '..');
56
- const target = process.argv[2] || path.join(root, 'io-package.json');
57
- try {
58
- const result = ensureFile(target);
59
- if (result.changed) {
60
- console.log(
61
- `[NexoWatt EOS release defaults] repaired ${result.changes.length} canonical value(s): ${result.changes.map(change => change.key).join(', ')}`,
62
- );
63
- } else {
64
- console.log('[NexoWatt EOS release defaults] OK (canonical sales defaults already present)');
65
- }
66
- } catch (error) {
67
- console.error(`[NexoWatt EOS release defaults] ${error instanceof Error ? error.message : String(error)}`);
68
- process.exit(1);
69
- }
70
- }
71
-
72
- module.exports = { CANONICAL_NATIVE_DEFAULTS, ensureReleaseDefaults, ensureFile };
@@ -1,37 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
- const pkg = require('../package.json');
4
- const io = require('../io-package.json');
5
- const version = io.common.version || pkg.version;
6
- const base = (process.argv[2] || `https://unpkg.com/iobroker.eos-admin@${version}`).replace(/\/$/, '');
7
- const entry = {
8
- 'eos-admin': {
9
- name: 'eos-admin',
10
- version,
11
- title: 'NexoWatt EOS Admin',
12
- titleLang: io.common.titleLang,
13
- desc: io.common.desc,
14
- news: io.common.news,
15
- meta: `${base}/io-package.json`,
16
- icon: `${base}/admin/admin.png`,
17
- extIcon: `${base}/admin/admin.svg`,
18
- type: io.common.type || 'general',
19
- mode: io.common.mode || 'daemon',
20
- platform: io.common.platform || 'Javascript/Node.js',
21
- connectionType: io.common.connectionType || 'local',
22
- dataSource: io.common.dataSource || 'push',
23
- adminUI: io.common.adminUI || { config: 'json' },
24
- license: io.common.license || 'NexoWatt Proprietary',
25
- licenseInformation: io.common.licenseInformation,
26
- dependencies: io.common.dependencies || [{ 'js-controller': '>=6.0.11' }],
27
- stopBeforeUpdate: false,
28
- dontDelete: false,
29
- nondeletable: false,
30
- readme: `${base}/README.md`,
31
- packetName: 'iobroker.eos-admin',
32
- npmPackage: 'iobroker.eos-admin',
33
- allowAdapterUpdate: true,
34
- allowAdapterDelete: false,
35
- }
36
- };
37
- console.log(JSON.stringify(entry, null, 2));
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
- require('./nexowatt-generate-eos-admin-repo-entry.cjs');
@@ -1,55 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
- const fs = require('fs');
4
- const path = require('path');
5
- const root = path.resolve(__dirname, '..');
6
- const read = rel => fs.readFileSync(path.join(root, rel), 'utf8');
7
- const json = rel => JSON.parse(read(rel));
8
- let bad = false;
9
- const fail = msg => { console.error(`[NexoWatt EOS internal reserve] ${msg}`); bad = true; };
10
-
11
- const mainSource = read('src/main.ts');
12
- const mainBuilt = read('build/main.js');
13
- const webSource = read('src/lib/web.ts');
14
- const webBuilt = read('build/lib/web.js');
15
- const role = read('adminWww/js/eos-role-ui.js');
16
- const boot = read('adminWww/js/eos-role-bootstrap.js');
17
- const drawer = read('src-admin/src/components/Drawer.tsx');
18
- const assist = read('adminWww/js/eos-assistant.js');
19
- const io = json('io-package.json');
20
-
21
- for (const code of [mainSource, mainBuilt]) {
22
- for (const marker of [
23
- "LEGACY_BACKUP_ADAPTER_NAME = 'backitup'", 'shouldHideLegacyBackupFromNonAdmins',
24
- 'getLegacyBackupAclObjectIds', 'ensureLegacyBackupVisibleOnlyToAdmins',
25
- 'EOS ACL guard restricted internal', '/^system\\.adapter\\.(?:admin|backitup)(?:\\.|$)/',
26
- '/^(?:admin|backitup)\\.\\d+(?:\\.|$)/', 'internal Service reserve is Admin/Service-only',
27
- ]) if (!code.includes(marker)) fail(`backend reserve marker missing: ${marker}`);
28
- }
29
- for (const code of [webSource, webBuilt]) {
30
- for (const marker of [
31
- "LEGACY_BACKUP_ADAPTER_NAME = 'backitup'", "CUSTOMER_BACKUP_ADAPTER_NAMES = ['nexowatt-backup', 'eos-backup']",
32
- 'nexowattBackup: true', "internalBackupReserve: role === 'admin'", 'hideLegacyBackupFromNonAdmins',
33
- 'legacyBackupAdapter', 'customerBackupAdapters',
34
- ]) if (!code.includes(marker)) fail(`web reserve marker missing: ${marker}`);
35
- }
36
- for (const marker of [
37
- 'isOfficialAdminTab', 'isOfficialBackupTab', 'isOfficialReserveTab', 'isCustomerBackupTab',
38
- 'system.adapter.backitup', 'tab-backitup', 'nexowatt-backup', 'eos-backup',
39
- 'exact visible instance ID', 'data-eos-official-reserve-hidden', 'Reused virtual rows must be unhidden',
40
- ]) if (!role.includes(marker)) fail(`role UI reserve marker missing: ${marker}`);
41
- for (const marker of ['isOfficialReserveTab', 'isCustomerBackupTab', 'backitup', 'nexowatt-backup']) {
42
- if (!boot.includes(marker)) fail(`bootstrap reserve marker missing: ${marker}`);
43
- }
44
- for (const marker of ['System-Notfallsicherung', 'NexoWatt Sicherung', '^tab-backitup', 'nexowatt-backup|eos-backup']) {
45
- if (!drawer.includes(marker)) fail(`Drawer reserve marker missing: ${marker}`);
46
- }
47
- if (!assist.includes('NexoWatt Sicherung') || !assist.includes('System-Notfallsicherung')) fail('EOS Assist backup explanation is incomplete');
48
- if (io.native?.eosHideLegacyBackupFromNonAdmins !== true) fail('eosHideLegacyBackupFromNonAdmins must default to true');
49
- if (io.native?.nexowattHideLegacyBackupFromNonAdmins !== true) fail('nexowattHideLegacyBackupFromNonAdmins must default to true');
50
- const reserve = (io.native?.eosProtectedAdapters || []).find(entry => entry.adapter === 'backitup');
51
- if (!reserve?.enabled || !/Notfallreserve/i.test(String(reserve.note))) fail('backitup reserve is not clearly marked in the protected adapter defaults');
52
- if (role.includes("/^tab-(?:admin|backitup|nexowatt-backup)/")) fail('customer backup must not be grouped with internal reserves');
53
-
54
- if (bad) process.exit(1);
55
- console.log('[NexoWatt EOS internal reserve] OK');
@@ -1,81 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- const fs = require('fs');
5
- const path = require('path');
6
-
7
- const root = path.resolve(__dirname, '..');
8
- const read = rel => fs.readFileSync(path.join(root, rel), 'utf8');
9
- let bad = false;
10
- const fail = message => {
11
- console.error(`[NexoWatt EOS login layout] ${message}`);
12
- bad = true;
13
- };
14
-
15
- const css = read('adminWww/css/nexowatt-native-shell.css');
16
- const sourceCss = read('src-admin/public/css/nexowatt-native-shell.css');
17
- const login = read('src-admin/src/login/Login.tsx');
18
- const bootstrap = read('adminWww/js/eos-role-bootstrap.js');
19
- const index = read('adminWww/index.html');
20
- const buildInfo = JSON.parse(read('NEXOWATT_EOS_BUILD_INFO.json'));
21
- const shellTag = String(buildInfo.shellCacheTag || buildInfo.shellCacheVersion || '');
22
-
23
- if (css !== sourceCss) fail('login CSS source/build drift');
24
- if (!css.includes('outer frame is decorative only')) fail('decorative compact-frame contract is missing');
25
- if (css.includes('html.eos-login .MuiPaper-root:has(#username)')) {
26
- fail('broad :has selector still styles the outer login Paper');
27
- }
28
-
29
- const outer = css.match(/html\.eos-login main\.MuiPaper-root\s*\{([\s\S]*?)\n\}/)?.[1] || '';
30
- for (const marker of [
31
- 'position: relative',
32
- 'width: 100%',
33
- 'min-height: 100vh',
34
- 'place-items: center',
35
- 'background: transparent !important',
36
- 'box-shadow: none !important',
37
- ]) {
38
- if (!outer.includes(marker)) fail(`transparent viewport host rule missing: ${marker}`);
39
- }
40
-
41
- const decorative = css.match(/html\.eos-login main\.MuiPaper-root::before\s*\{([\s\S]*?)\n\}/)?.[1] || '';
42
- for (const marker of [
43
- "content: ''",
44
- 'width: min(390px, calc(100vw - 24px))',
45
- 'height: min(480px, calc(100vh - 24px))',
46
- 'transform: translate(-50%, -50%)',
47
- 'pointer-events: none',
48
- ]) {
49
- if (!decorative.includes(marker)) fail(`decorative rear frame rule missing: ${marker}`);
50
- }
51
-
52
- for (const marker of [
53
- 'html.eos-login main.MuiPaper-root > .eos-login-card-modern',
54
- 'html.eos-login main.MuiPaper-root > .MuiPaper-root:has(#username)',
55
- 'html.eos-login main.MuiPaper-root > .MuiPaper-root:has(#password)',
56
- 'width: min(334px, calc(100vw - 56px)) !important',
57
- 'height: min(424px, calc(100vh - 56px)) !important',
58
- 'max-height: none !important',
59
- ]) {
60
- if (!css.includes(marker)) fail(`inner compact card rule missing: ${marker}`);
61
- }
62
- if (!css.includes('.eos-login-first-status:empty { display: none; min-height: 0; margin: 0; }')) {
63
- fail('empty first-login status still reserves vertical space');
64
- }
65
-
66
- if (!login.includes('Keep the familiar compact login page')) fail('native Login source lacks compact-page contract');
67
- if (login.includes('eos-login-role-selector-native') || login.includes('data-eos-account=')) {
68
- fail('native Login source still renders role-selector buttons');
69
- }
70
- if (!bootstrap.includes('compact normal-login first activation')) fail('runtime compact first-login contract missing');
71
- if (!bootstrap.includes("card.querySelectorAll('.eos-login-role-selector').forEach(element => element.remove())")) {
72
- fail('runtime does not remove stale role-selector surfaces');
73
- }
74
- if (/data-eos-account=|selector\.innerHTML/.test(bootstrap)) fail('runtime still injects a second role-selector panel');
75
-
76
- if (!shellTag || !index.includes(`nexowatt-native-shell.css?v=${shellTag}`)) {
77
- fail('login CSS cache key is not aligned with build information');
78
- }
79
-
80
- if (bad) process.exit(1);
81
- console.log('[NexoWatt EOS login layout] OK');
@@ -1,50 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
- const fs = require('fs');
4
- const path = require('path');
5
- const root = path.resolve(__dirname, '..');
6
- const read = rel => fs.readFileSync(path.join(root, rel), 'utf8');
7
- let bad = false;
8
- const fail = msg => { console.error(`[NexoWatt EOS modern UI] ${msg}`); bad = true; };
9
- const css = read('adminWww/css/nexowatt-native-shell.css');
10
- const sourceCss = read('src-admin/public/css/nexowatt-native-shell.css');
11
- const index = read('adminWww/index.html');
12
- const accountUi = read('adminWww/js/eos-account-management.js');
13
- const bootstrap = read('adminWww/js/eos-role-bootstrap.js');
14
- const shell = read('adminWww/js/nexowatt-native-shell.js');
15
- const role = read('adminWww/js/eos-role-ui.js');
16
- const assist = read('adminWww/js/eos-assistant.js');
17
-
18
- for (const marker of [
19
- '--nx-shadow-soft', '--nx-shadow-float', 'backdrop-filter: blur', '#app-paper', '.MuiDialog-paper',
20
- '.MuiButton-root', '.MuiTableRow-root', ':focus-visible', 'border-radius: 24px', 'linear-gradient',
21
- '@media (max-width: 720px)', '.eos-activation-steps', '.eos-account-row:hover',
22
- 'main.MuiPaper-root::before', 'width: min(334px, calc(100vw - 56px)) !important', '.eos-assist-header-root', '.eos-overview-hero', '.eos-overview-grid',
23
- '.eos-account-management-entry', 'pointer-events: auto !important', 'touch-action: manipulation', 'overflow: visible',
24
- ]) if (!css.includes(marker)) fail(`modern styling marker missing: ${marker}`);
25
- if (sourceCss !== css) fail('modern CSS source/build drift');
26
- for (const marker of ['eos-account-management.js','nexowatt-native-shell.css','eos-role-bootstrap.js','eos-assistant.js']) {
27
- if (!index.includes(marker)) fail(`modern UI asset not active: ${marker}`);
28
- }
29
- for (const marker of ['NexoWatt EOS', 'Zugänge & Rollen', 'Endkunden-Zugänge', 'ensureEntrySurface']) {
30
- if (!accountUi.includes(marker)) fail(`modern account surface missing label: ${marker}`);
31
- }
32
- for (const marker of ['installIntegratedFirstLogin','v91 compact normal-login first activation','eos-passwordless-card','Idempotent writes are essential here']) {
33
- if (!bootstrap.includes(marker)) fail(`integrated first-activation surface missing: ${marker}`);
34
- }
35
- if (/data-eos-account=|selector\.innerHTML/.test(bootstrap)) fail('compact login still injects role buttons or a second panel');
36
- if (bootstrap.includes("launcher.className = 'eos-passwordless-launcher'")) fail('old bottom first-login launcher is still rendered');
37
- if (!shell.includes('ensureModernOverview') || !shell.includes("currentTab() !== 'tab-intro'")) fail('current overview is not modernized');
38
- if (!role.includes('eos-role-safe-overview') || !role.includes("currentRoute() !== 'tab-intro'") || !role.includes('navigateToTab') || !role.includes("overview.querySelectorAll('a[data-eos-role-tab]')")) fail('role-safe current overview is missing or not directly clickable');
39
- if (!role.includes('ensureReserveObserver') || !role.includes('state.reserveObserver.observe(paper')) fail('scoped delayed-row reserve filter is missing');
40
- if (!assist.includes('eos-assist-header-root') || !assist.includes('insertBefore(root, userAnchor)')) fail('EOS Assist is not integrated in the header');
41
- if (assist.includes('position:fixed;bottom') || assist.includes('bottom:')) fail('EOS Assist still uses a bottom floating position');
42
-
43
- const observerCount = [
44
- 'eos-policy-client.js', 'eos-branding-sanitizer.js', 'nexowatt-native-shell.js', 'eos-native-security.js',
45
- 'eos-basic-settings.js', 'eos-role-ui.js', 'eos-account-management.js', 'eos-assistant.js',
46
- ].reduce((count, file) => count + (read(`adminWww/js/${file}`).match(/new MutationObserver/g) || []).length, 0);
47
- if (observerCount !== 2) fail(`expected one shared observer plus one scoped reserve-row observer, found ${observerCount}`);
48
-
49
- if (bad) process.exit(1);
50
- console.log('[NexoWatt EOS modern UI] OK');
@@ -1,54 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
- const fs = require('fs');
4
- const path = require('path');
5
- const input = process.argv[2];
6
- const output = process.argv[3] || input;
7
- const version = process.argv[4] || require('../package.json').version;
8
- const baseUrl = (process.argv[5] || `https://unpkg.com/iobroker.eos-admin@${version}`).replace(/\/$/, '');
9
- if (!input) {
10
- console.error('Usage: node tools/nexowatt-patch-repo.cjs <repo-nexowatt.json> [output.json] [version] [base-url]');
11
- process.exit(2);
12
- }
13
- const repo = JSON.parse(fs.readFileSync(input, 'utf8'));
14
- const ioPath = path.join(__dirname, '..', 'io-package.json');
15
- const io = JSON.parse(fs.readFileSync(ioPath, 'utf8'));
16
- repo['eos-admin'] = {
17
- ...(repo['eos-admin'] || {}),
18
- name: 'eos-admin',
19
- version,
20
- title: 'NexoWatt EOS Admin',
21
- titleLang: io.common.titleLang,
22
- desc: {
23
- de: 'Eigenständige NexoWatt EOS Administrationsoberfläche mit zuverlässigem In-App-Updatepfad für Energy Operation System Installationen.',
24
- en: 'Standalone NexoWatt EOS administration interface with reliable in-app update flow for Energy Operation System installations.',
25
- },
26
- news: io.common.news,
27
- meta: `${baseUrl}/io-package.json`,
28
- icon: `${baseUrl}/admin/admin.png`,
29
- extIcon: `${baseUrl}/admin/admin.svg`,
30
- type: 'general',
31
- mode: 'daemon',
32
- platform: 'Javascript/Node.js',
33
- connectionType: 'local',
34
- dataSource: 'push',
35
- adminUI: { config: 'json' },
36
- license: 'NexoWatt Proprietary',
37
- licenseInformation: io.common.licenseInformation,
38
- dependencies: [{ 'js-controller': '>=6.0.11' }],
39
- stopBeforeUpdate: false,
40
- dontDelete: false,
41
- nondeletable: false,
42
- readme: `${baseUrl}/README.md`,
43
- packetName: 'iobroker.eos-admin',
44
- npmPackage: 'iobroker.eos-admin',
45
- allowAdapterUpdate: true,
46
- allowAdapterDelete: false,
47
- };
48
- fs.writeFileSync(output, JSON.stringify(repo, null, 2) + '\n');
49
- console.log(`Patched ${input} -> ${output}`);
50
- console.log(`repo["eos-admin"].version=${version}`);
51
- console.log(`repo["eos-admin"].meta=${repo['eos-admin'].meta}`);
52
- console.log('repo["eos-admin"].stopBeforeUpdate=false');
53
- console.log('repo["eos-admin"].dontDelete=false');
54
- console.log('repo["eos-admin"].nondeletable=false');
@@ -1,58 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- const fs = require('fs');
5
- const path = require('path');
6
-
7
- function validatePublishChannel(pkg, env = process.env) {
8
- const version = String(pkg?.version || '').trim();
9
- const configuredTag = String(pkg?.publishConfig?.tag || '').trim();
10
- const requestedTag = String(env.npm_config_tag || env.NPM_CONFIG_TAG || configuredTag || 'latest').trim();
11
- const isPrerelease = version.includes('-');
12
- const policy = pkg?.nexowattReleasePolicy || {};
13
-
14
- if (!version) {
15
- return { ok: false, message: 'package.json version is missing' };
16
- }
17
- if (configuredTag !== 'latest' || requestedTag !== 'latest') {
18
- return {
19
- ok: false,
20
- message: `${version} is approved only for npm dist-tag latest, got configured=${configuredTag || '<unset>'}, requested=${requestedTag || '<unset>'}`,
21
- };
22
- }
23
-
24
- if (isPrerelease) {
25
- if (policy.distTag !== 'latest' || policy.acceptedPrerelease !== version) {
26
- return {
27
- ok: false,
28
- message: `Prerelease ${version} may move latest only when nexowattReleasePolicy explicitly accepts this exact version`,
29
- };
30
- }
31
- return { ok: true, version, tag: 'latest', prerelease: true, explicitlyAccepted: true };
32
- }
33
-
34
- if (policy.acceptedPrerelease) {
35
- return {
36
- ok: false,
37
- message: `Stable version ${version} must remove stale acceptedPrerelease policy ${policy.acceptedPrerelease}`,
38
- };
39
- }
40
- return { ok: true, version, tag: 'latest', prerelease: false, explicitlyAccepted: false };
41
- }
42
-
43
- if (require.main === module) {
44
- const root = path.resolve(__dirname, '..');
45
- const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
46
- const result = validatePublishChannel(pkg, process.env);
47
-
48
- if (!result.ok) {
49
- console.error(`[NexoWatt EOS publish guard] ${result.message}`);
50
- process.exit(1);
51
- }
52
-
53
- console.log(
54
- `[NexoWatt EOS publish guard] OK (${result.version}, npm dist-tag latest${result.explicitlyAccepted ? '; exact prerelease acceptance recorded' : ''})`,
55
- );
56
- }
57
-
58
- module.exports = { validatePublishChannel };
@@ -1,29 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- const assert = require('node:assert/strict');
5
- const { CANONICAL_NATIVE_DEFAULTS, ensureReleaseDefaults } = require('./nexowatt-ensure-release-defaults.cjs');
6
-
7
- const unsafe = {
8
- common: { name: 'eos-admin' },
9
- native: {
10
- auth: false,
11
- port: 8091,
12
- eosLockLegacyAdmin: false,
13
- eosHideLegacyAdminFromNonAdmins: false,
14
- eosHideLegacyBackupFromNonAdmins: false,
15
- nexowattHideLegacyBackupFromNonAdmins: false,
16
- eosRequireFirstLoginPassword: false,
17
- },
18
- };
19
- const repaired = ensureReleaseDefaults(unsafe);
20
- assert.ok(repaired.changes.length >= 7, 'unsafe defaults must be repaired');
21
- for (const [key, expected] of Object.entries(CANONICAL_NATIVE_DEFAULTS)) {
22
- assert.equal(repaired.ioPackage.native[key], expected, `${key} must be normalized`);
23
- }
24
-
25
- const canonical = { native: { ...CANONICAL_NATIVE_DEFAULTS } };
26
- const unchanged = ensureReleaseDefaults(canonical);
27
- assert.equal(unchanged.changes.length, 0, 'canonical defaults must remain unchanged');
28
-
29
- console.log('[NexoWatt EOS release defaults selftest] OK');
@@ -1,47 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- const assert = require('assert');
5
- const fs = require('fs');
6
- const os = require('os');
7
- const path = require('path');
8
- const { cleanLegacyRuntime } = require('./nexowatt-clean-legacy-runtime.cjs');
9
-
10
- const temp = fs.mkdtempSync(path.join(os.tmpdir(), 'nexowatt-runtime-cleanup-'));
11
- try {
12
- fs.mkdirSync(path.join(temp, 'adminWww', 'assets'), { recursive: true });
13
- fs.mkdirSync(path.join(temp, 'adminWww', 'js'), { recursive: true });
14
- fs.mkdirSync(path.join(temp, 'adminWww', 'css'), { recursive: true });
15
- fs.mkdirSync(path.join(temp, 'src-admin', 'public', 'js'), { recursive: true });
16
- fs.writeFileSync(path.join(temp, 'NEXOWATT_EOS_BUILD_INFO.json'), JSON.stringify({ runtimeEntry: 'v82' }));
17
-
18
- const keep = [
19
- 'adminWww/assets/bootstrap-current-v82.js',
20
- 'adminWww/assets/Objects-current-v82.js',
21
- 'adminWww/remoteEntry-v82.js',
22
- 'adminWww/remoteEntry.js',
23
- ];
24
- const remove = [
25
- 'adminWww/assets/bootstrap-old-v54.js',
26
- 'adminWww/assets/Objects-old-v79.js',
27
- 'adminWww/assets/index-DPWrite53.js',
28
- 'adminWww/remoteEntry-v61.js',
29
- 'adminWww/js/eos-branding.js',
30
- 'adminWww/css/eos-branding.css',
31
- 'src-admin/public/js/eos-security-ui.js',
32
- ];
33
- for (const rel of [...keep, ...remove]) {
34
- const file = path.join(temp, rel);
35
- fs.mkdirSync(path.dirname(file), { recursive: true });
36
- fs.writeFileSync(file, '// fixture');
37
- }
38
-
39
- const result = cleanLegacyRuntime({ root: temp, quiet: true, silent: true });
40
- assert.strictEqual(result.activeRuntime, 82);
41
- assert.strictEqual(result.removed.length, remove.length);
42
- for (const rel of keep) assert.ok(fs.existsSync(path.join(temp, rel)), `current runtime removed: ${rel}`);
43
- for (const rel of remove) assert.ok(!fs.existsSync(path.join(temp, rel)), `legacy file remained: ${rel}`);
44
- console.log('[NexoWatt EOS runtime cleanup selftest] OK');
45
- } finally {
46
- fs.rmSync(temp, { recursive: true, force: true });
47
- }