iobroker.eos-admin 7.9.89 → 7.9.92

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 (59) hide show
  1. package/INSTALL_TEST_V7.9.92.md +18 -0
  2. package/NEXOWATT_EOS_BUILD_INFO.json +19 -25
  3. package/PUBLISH_STABLE_V7.9.92.md +19 -0
  4. package/README_STABILITY_V7.9.92.md +14 -0
  5. package/RELEASE_ACCEPTANCE_V7.9.92.md +12 -0
  6. package/RELEASE_NOTES_V7.9.92.md +17 -0
  7. package/adminWww/assets/Instances-YdaGnS5a-v84.js +1 -1
  8. package/adminWww/css/nexowatt-native-shell.css +151 -12
  9. package/adminWww/index.html +11 -11
  10. package/adminWww/js/eos-account-management.js +1 -1
  11. package/adminWww/js/eos-assistant.js +1 -1
  12. package/adminWww/js/eos-basic-settings.js +1 -1
  13. package/adminWww/js/eos-branding-sanitizer.js +1 -1
  14. package/adminWww/js/eos-native-security.js +1 -1
  15. package/adminWww/js/eos-policy-client.js +1 -1
  16. package/adminWww/js/eos-role-bootstrap.js +180 -46
  17. package/adminWww/js/eos-role-ui.js +156 -23
  18. package/adminWww/js/nexowatt-native-shell.js +1 -1
  19. package/build/lib/web.js +39 -0
  20. package/io-package.json +15 -5
  21. package/package.json +21 -13
  22. package/tools/nexowatt-account-management-selftest.cjs +1 -1
  23. package/tools/nexowatt-ensure-release-defaults.cjs +72 -0
  24. package/tools/nexowatt-internal-reserve-selftest.cjs +1 -0
  25. package/tools/nexowatt-login-layout-selftest.cjs +81 -0
  26. package/tools/nexowatt-modern-ui-selftest.cjs +7 -5
  27. package/tools/nexowatt-release-defaults-selftest.cjs +29 -0
  28. package/tools/nexowatt-validate-package.cjs +18 -8
  29. package/INSTALL_TEST_V7.9.89.md +0 -73
  30. package/PUBLISH_STABLE_V7.9.89.md +0 -33
  31. package/README_STABILITY_V7.9.89.md +0 -26
  32. package/RELEASE_ACCEPTANCE_V7.9.89.md +0 -40
  33. package/admin/img/eos/nexowatt-192-maskable.png +0 -0
  34. package/admin/img/eos/nexowatt-24.png +0 -0
  35. package/admin/img/eos/nexowatt-512-maskable.png +0 -0
  36. package/admin/img/eos/nexowatt-eos-logo.png +0 -0
  37. package/adminWww/admin.png +0 -0
  38. package/adminWww/img/eos/nexowatt-24.png +0 -0
  39. package/adminWww/img/eos/nexowatt-eos-logo.png +0 -0
  40. package/adminWww/img/eos/nexowatt-header-128.png +0 -0
  41. package/adminWww/img/eos/nexowatt-header-192.png +0 -0
  42. package/adminWww/img/eos/nexowatt-header-256.png +0 -0
  43. package/adminWww/img/eos/nexowatt-header-512.png +0 -0
  44. package/adminWww/img/eos/nexowatt-header-64.png +0 -0
  45. package/adminWww/img/logo192.png +0 -0
  46. package/adminWww/js/eos-adapter-surface-cleanup.js +0 -141
  47. package/adminWww/js/eos-toolbar-ghost-cleanup.js +0 -102
  48. package/docs/NEXOWATT_EOS_BRANDING_DE.md +0 -29
  49. package/docs/NEXOWATT_EOS_UI_LOGO_LOGIN_V6_DE.md +0 -9
  50. package/docs/NEXOWATT_EOS_UI_PERFORMANCE_V5_DE.md +0 -25
  51. package/docs/NEXOWATT_EOS_UI_V12_HEADER_LOGO_NAV_CLEANUP_DE.md +0 -16
  52. package/docs/NEXOWATT_EOS_UI_V12_HEADER_NAV_LOGO_FIX_DE.md +0 -16
  53. package/docs/NEXOWATT_EOS_UI_V15_DE.md +0 -8
  54. package/docs/NEXOWATT_EOS_UI_V16_DE.md +0 -9
  55. package/docs/NEXOWATT_EOS_UI_V17_DE.md +0 -24
  56. package/docs/NEXOWATT_EOS_UI_V6_FIXES_DE.md +0 -13
  57. package/docs/NEXOWATT_EOS_UI_V6_LOGIN_LOGO_404_FIX_DE.md +0 -9
  58. package/docs/NEXOWATT_EOS_UI_V6_LOGO_LOGIN_FIX_DE.md +0 -10
  59. package/docs/NEXOWATT_EOS_UI_V7_RESTORE_LOGO_SCOPE_FIX_DE.md +0 -18
@@ -1,4 +1,4 @@
1
- /* NexoWatt EOS native shell v89
1
+ /* NexoWatt EOS native shell v91
2
2
  Clean presentation layer for the NexoWatt fork of ioBroker Admin.
3
3
  This stylesheet deliberately avoids broad pointer-event, visibility and DOM-structure overrides. */
4
4
 
@@ -55,23 +55,53 @@ html.eos-login #root {
55
55
  place-items: center;
56
56
  }
57
57
  html.eos-login main.MuiPaper-root {
58
+ position: relative;
59
+ isolation: isolate;
58
60
  width: 100%;
59
61
  min-height: 100vh;
60
62
  display: grid;
61
63
  place-items: center;
64
+ padding: 0 !important;
62
65
  background: transparent !important;
63
66
  border: 0 !important;
64
67
  box-shadow: none !important;
65
68
  }
66
- html.eos-login .MuiPaper-root:has(#username),
67
- html.eos-login .MuiPaper-root:has(#password) {
68
- width: min(430px, calc(100vw - 36px)) !important;
69
- padding: 30px !important;
70
- border-radius: 26px !important;
69
+ /* The outer frame is decorative only. Keeping it as a pseudo element prevents
70
+ the viewport-sized main Paper from being mistaken for a second form card. */
71
+ html.eos-login main.MuiPaper-root::before {
72
+ content: '';
73
+ position: absolute;
74
+ z-index: 0;
75
+ left: 50%;
76
+ top: 50%;
77
+ box-sizing: border-box;
78
+ width: min(390px, calc(100vw - 24px));
79
+ height: min(480px, calc(100vh - 24px));
80
+ transform: translate(-50%, -50%);
81
+ border: 1px solid rgba(0, 229, 138, .34);
82
+ border-radius: 26px;
83
+ background: linear-gradient(180deg, rgba(10, 34, 52, .82), rgba(3, 15, 27, .88));
84
+ box-shadow: 0 26px 70px rgba(0, 0, 0, .52), 0 0 42px rgba(0, 255, 136, .08);
85
+ pointer-events: none;
86
+ }
87
+ html.eos-login main.MuiPaper-root > .eos-login-card-modern,
88
+ html.eos-login main.MuiPaper-root > .MuiPaper-root:has(#username),
89
+ html.eos-login main.MuiPaper-root > .MuiPaper-root:has(#password) {
90
+ position: relative;
91
+ z-index: 1;
92
+ box-sizing: border-box !important;
93
+ width: min(334px, calc(100vw - 56px)) !important;
94
+ height: min(424px, calc(100vh - 56px)) !important;
95
+ min-height: 0 !important;
96
+ max-width: none !important;
97
+ max-height: none !important;
98
+ padding: 28px !important;
99
+ overflow: auto !important;
100
+ border-radius: 24px !important;
71
101
  color: var(--nx-text) !important;
72
- background: linear-gradient(180deg, rgba(14,36,56,.97), rgba(4,15,27,.96)) !important;
102
+ background: linear-gradient(180deg, rgba(14, 36, 56, .97), rgba(4, 15, 27, .96)) !important;
73
103
  border: 1px solid var(--nx-border-accent) !important;
74
- box-shadow: 0 26px 70px rgba(0,0,0,.52), 0 0 42px rgba(0,255,136,.12) !important;
104
+ box-shadow: 0 18px 44px rgba(0, 0, 0, .34), inset 0 1px 0 rgba(255, 255, 255, .035) !important;
75
105
  }
76
106
  html.eos-login img[src*="admin"],
77
107
  html.eos-login .MuiAvatar-img { object-fit: contain !important; filter: drop-shadow(0 0 18px rgba(0,255,136,.35)); }
@@ -511,7 +541,7 @@ html.eos-security-nonadmin [data-eos-admin-only-control="1"] { display: none !im
511
541
  .eos-basic-settings-actions button:disabled { opacity: .55; cursor: wait; }
512
542
  @media (max-width: 760px) { .eos-basic-settings-overlay { padding: 8px; } .eos-basic-settings-dialog { width: 100%; max-height: 96vh; } .eos-basic-settings-form { grid-template-columns: 1fr; } .eos-basic-settings-actions { flex-direction: column-reverse; } .eos-basic-settings-actions button { width: 100%; } }
513
543
 
514
- /* v89: blocking first-login password setup for installer/end-user accounts */
544
+ /* v91: server-checked first-login password setup for installer/end-user accounts */
515
545
  html.eos-first-login-active,html.eos-first-login-active body { min-height: 100%; overflow: hidden !important; background: #020914 !important; }
516
546
  .eos-first-login-overlay { position: fixed; inset: 0; z-index: 2147483647; display: grid; place-items: center; box-sizing: border-box; padding: 24px; color: #effbff; background: radial-gradient(circle at 20% 0%,rgba(0,229,138,.15),transparent 38%),linear-gradient(145deg,#020914,#061927); font-family: Inter,Roboto,Arial,sans-serif; }
517
547
  .eos-first-login-card { width: min(520px,100%); box-sizing: border-box; padding: 30px; border: 1px solid rgba(0,229,138,.34); border-radius: 22px; background: rgba(4,21,33,.96); box-shadow: 0 28px 90px rgba(0,0,0,.58),0 0 42px rgba(0,229,138,.08); }
@@ -826,7 +856,7 @@ html.eos-modern-login body::before {
826
856
 
827
857
 
828
858
  /* ==========================================================================
829
- NexoWatt EOS 7.9.89 – stable product layout
859
+ NexoWatt EOS 7.9.92 – stable product layout
830
860
  Integrated first login, header assistant, role-safe overview and account
831
861
  management exclusively below "Zugänge & Rechte".
832
862
  ========================================================================== */
@@ -853,10 +883,19 @@ html.eos-app .eos-top-toolbar {
853
883
  display: none !important;
854
884
  }
855
885
  html.eos-login .eos-login-card-modern {
856
- max-height: min(760px, calc(100vh - 30px)) !important;
886
+ /* Compact product login: the form remains the proven inner card while the
887
+ decorative rear frame keeps a fixed, restrained footprint. */
888
+ box-sizing: border-box !important;
889
+ width: min(334px, calc(100vw - 56px)) !important;
890
+ height: min(424px, calc(100vh - 56px)) !important;
891
+ min-height: 0 !important;
892
+ max-width: none !important;
893
+ max-height: none !important;
857
894
  overflow: auto !important;
858
895
  }
859
896
  .eos-login-role-selector {
897
+ display: none !important;
898
+
860
899
  width: 100%;
861
900
  margin: 14px 0 5px;
862
901
  padding: 13px;
@@ -934,8 +973,57 @@ html.eos-login .eos-login-card-modern {
934
973
  }
935
974
  .eos-login-first-status[data-kind="error"] { color: #ff8d98; }
936
975
  .eos-login-first-status[data-kind="success"] { color: #54f1aa; }
976
+ .eos-login-first-status:empty { display: none; min-height: 0; margin: 0; }
977
+
978
+ .eos-first-login-native-submit-hidden {
979
+ display: none !important;
980
+ }
981
+ .eos-first-login-submit-proxy {
982
+ box-sizing: border-box;
983
+ width: 100%;
984
+ min-height: 36px;
985
+ margin-top: 8px;
986
+ padding: 8px 18px;
987
+ color: #03161d;
988
+ font: inherit;
989
+ font-weight: 900;
990
+ letter-spacing: .035em;
991
+ text-transform: uppercase;
992
+ border: 1px solid rgba(82, 255, 190, .7);
993
+ border-radius: 5px;
994
+ background: linear-gradient(135deg, #00e58a, #45d5ff);
995
+ box-shadow: 0 10px 24px rgba(0, 229, 138, .18), inset 0 1px 0 rgba(255,255,255,.35);
996
+ cursor: pointer;
997
+ transition: transform .16s ease, filter .16s ease, box-shadow .16s ease;
998
+ }
999
+ .eos-first-login-submit-proxy:hover,
1000
+ .eos-first-login-submit-proxy:focus-visible {
1001
+ filter: brightness(1.08);
1002
+ transform: translateY(-1px);
1003
+ box-shadow: 0 14px 28px rgba(0, 229, 138, .24), 0 0 0 3px rgba(69, 213, 255, .16);
1004
+ }
1005
+ .eos-first-login-submit-proxy:disabled {
1006
+ cursor: progress;
1007
+ opacity: .62;
1008
+ transform: none;
1009
+ }
937
1010
  .eos-login-first-ready button[type="submit"] {
1011
+ color: #03151c !important;
1012
+ opacity: 1 !important;
1013
+ pointer-events: auto !important;
1014
+ background: linear-gradient(135deg, #00e58a, #45d5ff) !important;
938
1015
  box-shadow: 0 0 0 1px rgba(0, 229, 138, .28), 0 12px 28px rgba(0, 229, 138, .14) !important;
1016
+ cursor: pointer !important;
1017
+ }
1018
+ .eos-login-first-ready button[type="submit"].Mui-disabled { pointer-events: auto !important; }
1019
+ .eos-first-login-password-optional .MuiInputLabel-asterisk { display: none !important; }
1020
+ .eos-login-first-checking button[type="submit"],
1021
+ .eos-login-first-blocked button[type="submit"] {
1022
+ color: rgba(218, 235, 242, .55) !important;
1023
+ opacity: .72 !important;
1024
+ background: #314050 !important;
1025
+ box-shadow: none !important;
1026
+ cursor: not-allowed !important;
939
1027
  }
940
1028
 
941
1029
  /* EOS Assist lives in the fixed header and opens below it. */
@@ -1029,7 +1117,9 @@ html.eos-login .eos-login-card-modern {
1029
1117
  .eos-role-safe-overview {
1030
1118
  position: absolute;
1031
1119
  inset: 0;
1032
- z-index: 25;
1120
+ z-index: 1000;
1121
+ isolation: isolate;
1122
+ pointer-events: auto !important;
1033
1123
  overflow: auto;
1034
1124
  padding: 0 0 24px;
1035
1125
  background:
@@ -1038,12 +1128,19 @@ html.eos-login .eos-login-card-modern {
1038
1128
  }
1039
1129
  .eos-overview-grid {
1040
1130
  display: grid;
1131
+ position: relative;
1132
+ z-index: 2;
1133
+ pointer-events: auto !important;
1041
1134
  grid-template-columns: repeat(auto-fit, minmax(245px, 1fr));
1042
1135
  gap: 13px;
1043
1136
  padding: 0 16px 20px;
1044
1137
  }
1045
1138
  .eos-overview-action {
1046
1139
  min-height: 105px;
1140
+ position: relative;
1141
+ z-index: 3;
1142
+ pointer-events: auto !important;
1143
+ touch-action: manipulation;
1047
1144
  display: grid;
1048
1145
  grid-template-columns: 52px minmax(0, 1fr) 22px;
1049
1146
  align-items: center;
@@ -1051,6 +1148,7 @@ html.eos-login .eos-login-card-modern {
1051
1148
  padding: 17px;
1052
1149
  color: #eafaff;
1053
1150
  text-align: left;
1151
+ text-decoration: none;
1054
1152
  border: 1px solid rgba(133, 193, 218, .14);
1055
1153
  border-radius: 18px;
1056
1154
  background: linear-gradient(145deg, rgba(10, 35, 50, .84), rgba(3, 16, 28, .92));
@@ -1058,6 +1156,7 @@ html.eos-login .eos-login-card-modern {
1058
1156
  cursor: pointer;
1059
1157
  transition: transform .16s ease, border-color .16s ease, background .16s ease, box-shadow .16s ease;
1060
1158
  }
1159
+ .eos-overview-action > * { pointer-events: none !important; }
1061
1160
  .eos-overview-action:hover {
1062
1161
  transform: translateY(-2px);
1063
1162
  border-color: rgba(0, 229, 138, .35);
@@ -1082,6 +1181,33 @@ html.eos-login .eos-login-card-modern {
1082
1181
  .eos-overview-action i { color: #59e5bd; font-size: 29px; font-style: normal; }
1083
1182
  .eos-official-reserve-hidden { display: none !important; }
1084
1183
 
1184
+ /* Internal fallback services are never exposed outside Admin / Service. */
1185
+ html.eos-role-installer [data-instance^="admin."],
1186
+ html.eos-role-installer [data-instance^="backitup."],
1187
+ html.eos-role-enduser [data-instance^="admin."],
1188
+ html.eos-role-enduser [data-instance^="backitup."],
1189
+ html.eos-role-installer [data-instance-id^="admin."],
1190
+ html.eos-role-installer [data-instance-id^="backitup."],
1191
+ html.eos-role-enduser [data-instance-id^="admin."],
1192
+ html.eos-role-enduser [data-instance-id^="backitup."] { display: none !important; }
1193
+
1194
+
1195
+
1196
+ /* Final 7.9.92 interaction guards. */
1197
+ html.eos-safe-overview-active #app-paper { position: relative !important; }
1198
+ html.eos-safe-overview-active #app-paper > :not(#eos-role-safe-overview):not(.MuiSnackbar-root):not([role="presentation"]) {
1199
+ pointer-events: none !important;
1200
+ }
1201
+ .eos-role-safe-overview .eos-overview-action {
1202
+ appearance: none;
1203
+ -webkit-appearance: none;
1204
+ opacity: 1 !important;
1205
+ }
1206
+ .eos-role-safe-overview .eos-overview-action:focus-visible {
1207
+ outline: 3px solid rgba(69, 213, 255, .85);
1208
+ outline-offset: 3px;
1209
+ }
1210
+
1085
1211
  /* Account management is available only inside Zugänge & Rechte. */
1086
1212
  .eos-account-management-entry {
1087
1213
  position: relative;
@@ -1144,6 +1270,19 @@ html.eos-route-intro #app-paper [class*="card"] {
1144
1270
  .eos-account-management-entry-button { width: 100%; min-width: 0; }
1145
1271
  }
1146
1272
  @media (max-width: 720px) {
1273
+ html.eos-login main.MuiPaper-root::before {
1274
+ width: calc(100vw - 16px);
1275
+ height: min(480px, calc(100vh - 16px));
1276
+ border-radius: 20px;
1277
+ }
1278
+ html.eos-login main.MuiPaper-root > .eos-login-card-modern,
1279
+ html.eos-login main.MuiPaper-root > .MuiPaper-root:has(#username),
1280
+ html.eos-login main.MuiPaper-root > .MuiPaper-root:has(#password) {
1281
+ width: calc(100vw - 44px) !important;
1282
+ height: min(424px, calc(100vh - 44px)) !important;
1283
+ padding: 22px !important;
1284
+ border-radius: 18px !important;
1285
+ }
1147
1286
  .eos-login-role-buttons { grid-template-columns: 1fr; }
1148
1287
  .eos-login-role-buttons button { min-height: 46px; }
1149
1288
  .eos-overview-hero { align-items: flex-start; flex-direction: column; margin: 9px; border-radius: 18px; }
@@ -8,7 +8,7 @@
8
8
  <meta http-equiv="Cache-Control" content="no-store, no-cache, must-revalidate" />
9
9
  <meta http-equiv="Pragma" content="no-cache" />
10
10
  <meta http-equiv="Expires" content="0" />
11
- <script src="./js/eos-manual-write-policy.js?v=89"></script>
11
+ <script src="./js/eos-manual-write-policy.js?v=91"></script>
12
12
  <script type="module" src="./assets/hostInit-v84.js?v=84"></script>
13
13
 
14
14
  <meta charset="utf-8" />
@@ -36,7 +36,7 @@
36
36
  rel="stylesheet"
37
37
  href="css/leaflet.css"
38
38
  />
39
- <link rel="stylesheet" href="./css/nexowatt-native-shell.css?v=89" />
39
+ <link rel="stylesheet" href="./css/nexowatt-native-shell.css?v=91" />
40
40
  <link
41
41
  rel="manifest"
42
42
  href="manifest.json"
@@ -158,15 +158,15 @@
158
158
  </script>
159
159
  <link rel="modulepreload" crossorigin href="./assets/preload-helper-BDBacUwf.js">
160
160
  <link rel="modulepreload" crossorigin href="./assets/iobroker_admin__mf_v__runtimeInit__mf_v__-g2X2zhAf.js">
161
- <script defer src="./js/eos-role-bootstrap.js?v=89" data-eos-entry="./assets/index-CQZugZ1z-v84.js?v=84"></script>
162
- <script defer src="./js/eos-policy-client.js?v=89"></script>
163
- <script defer src="./js/eos-branding-sanitizer.js?v=89"></script>
164
- <script defer src="./js/nexowatt-native-shell.js?v=89"></script>
165
- <script defer src="./js/eos-native-security.js?v=89"></script>
166
- <script defer src="./js/eos-basic-settings.js?v=89"></script>
167
- <script defer src="./js/eos-role-ui.js?v=89"></script>
168
- <script defer src="./js/eos-account-management.js?v=89"></script>
169
- <script defer src="./js/eos-assistant.js?v=89"></script>
161
+ <script defer src="./js/eos-role-bootstrap.js?v=91" data-eos-entry="./assets/index-CQZugZ1z-v84.js?v=84"></script>
162
+ <script defer src="./js/eos-policy-client.js?v=91"></script>
163
+ <script defer src="./js/eos-branding-sanitizer.js?v=91"></script>
164
+ <script defer src="./js/nexowatt-native-shell.js?v=91"></script>
165
+ <script defer src="./js/eos-native-security.js?v=91"></script>
166
+ <script defer src="./js/eos-basic-settings.js?v=91"></script>
167
+ <script defer src="./js/eos-role-ui.js?v=91"></script>
168
+ <script defer src="./js/eos-account-management.js?v=91"></script>
169
+ <script defer src="./js/eos-assistant.js?v=91"></script>
170
170
  </head>
171
171
  <body>
172
172
  <noscript>Für NexoWatt EOS muss JavaScript aktiviert sein.</noscript>
@@ -1,7 +1,7 @@
1
1
  (() => {
2
2
  'use strict';
3
3
 
4
- const VERSION = 'v89-account-management-under-access-rights';
4
+ const VERSION = 'v91-account-management-under-access-rights';
5
5
  const script = document.currentScript || document.querySelector('script[src*="eos-account-management.js"]');
6
6
  const base = new URL('../', script?.src || window.location.href);
7
7
  const abort = new AbortController();
@@ -1,7 +1,7 @@
1
1
  (() => {
2
2
  'use strict';
3
3
 
4
- const VERSION = 'v89-header-eos-assist';
4
+ const VERSION = 'v91-header-eos-assist';
5
5
  const previous = window.NEXOWATT_EOS_ASSIST;
6
6
  if (previous?.version === VERSION) return;
7
7
  previous?.destroy?.();
@@ -1,7 +1,7 @@
1
1
  (() => {
2
2
  'use strict';
3
3
 
4
- const VERSION = 'v89-basic-settings';
4
+ const VERSION = 'v91-basic-settings';
5
5
  const existing = window.NEXOWATT_EOS_BASIC_SETTINGS;
6
6
  if (existing?.version === VERSION) return;
7
7
  existing?.destroy?.();
@@ -1,6 +1,6 @@
1
1
  (() => {
2
2
  'use strict';
3
- const VERSION = 'v89-visible-branding';
3
+ const VERSION = 'v91-visible-branding';
4
4
  const existing = window.NEXOWATT_EOS_BRANDING_SANITIZER;
5
5
  if (existing?.version === VERSION) return;
6
6
  existing?.destroy?.();
@@ -1,7 +1,7 @@
1
1
  (() => {
2
2
  'use strict';
3
3
 
4
- const VERSION = 'v89-product-role-access';
4
+ const VERSION = 'v91-product-role-access';
5
5
  const protectedAdapters = new Set([
6
6
  'admin', 'eos-admin', 'backitup', 'nexowatt-devices', 'nexowatt-device', 'nexowatt-dev', 'nexowatt-ui',
7
7
  ]);
@@ -1,7 +1,7 @@
1
1
  (() => {
2
2
  'use strict';
3
3
 
4
- const VERSION = 'v89-role-access';
4
+ const VERSION = 'v91-role-access';
5
5
  const existing = window.NEXOWATT_EOS_POLICY_CLIENT;
6
6
  if (existing?.version === VERSION) return;
7
7
  existing?.destroy?.();