iobroker.hassemu 1.33.2 → 1.35.0
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/README.md +21 -20
- package/admin/i18n/de.json +16 -1
- package/admin/i18n/en.json +16 -1
- package/admin/i18n/es.json +16 -1
- package/admin/i18n/fr.json +16 -1
- package/admin/i18n/it.json +16 -1
- package/admin/i18n/nl.json +16 -1
- package/admin/i18n/pl.json +16 -1
- package/admin/i18n/pt.json +16 -1
- package/admin/i18n/ru.json +16 -1
- package/admin/i18n/uk.json +16 -1
- package/admin/i18n/zh-cn.json +16 -1
- package/build/lib/auth-page.js +29 -39
- package/build/lib/auth-page.js.map +2 -2
- package/build/lib/client-registry.js +1 -0
- package/build/lib/client-registry.js.map +2 -2
- package/build/lib/coerce.js +0 -2
- package/build/lib/coerce.js.map +2 -2
- package/build/lib/constants.js +5 -2
- package/build/lib/constants.js.map +2 -2
- package/build/lib/external-bridge.js +2 -2
- package/build/lib/external-bridge.js.map +2 -2
- package/build/lib/global-config.js +1 -24
- package/build/lib/global-config.js.map +2 -2
- package/build/lib/html-shared.js +53 -0
- package/build/lib/html-shared.js.map +7 -0
- package/build/lib/i18n.js +18 -7
- package/build/lib/i18n.js.map +2 -2
- package/build/lib/landing-page.js +16 -174
- package/build/lib/landing-page.js.map +2 -2
- package/build/lib/redirect-wrapper.js +14 -118
- package/build/lib/redirect-wrapper.js.map +2 -2
- package/build/lib/schema-repair.js +69 -0
- package/build/lib/schema-repair.js.map +7 -0
- package/build/lib/types.js.map +1 -1
- package/build/lib/url-discovery.js +2 -2
- package/build/lib/url-discovery.js.map +2 -2
- package/build/lib/webserver.js +327 -144
- package/build/lib/webserver.js.map +3 -3
- package/build/main.js +3 -60
- package/build/main.js.map +2 -2
- package/io-package.json +33 -28
- package/package.json +9 -7
package/README.md
CHANGED
|
@@ -1,15 +1,10 @@
|
|
|
1
|
-
# ioBroker.hassemu
|
|
1
|
+
# <img src="https://cdn.jsdelivr.net/gh/krobipd/ioBroker.hassemu@main/admin/hassemu.svg" width="48" align="top" /> ioBroker.hassemu
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/iobroker.hassemu)
|
|
4
|
-

|
|
5
|
-

|
|
6
|
-
[](LICENSE)
|
|
7
|
-
[](https://www.npmjs.com/package/iobroker.hassemu)
|
|
8
|
-

|
|
9
|
-
[](https://ko-fi.com/krobipd)
|
|
10
|
-
[](https://paypal.me/krobipd)
|
|
3
|
+
**Release:** [](https://www.npmjs.com/package/iobroker.hassemu)   [](https://www.npmjs.com/package/iobroker.hassemu)
|
|
11
4
|
|
|
12
|
-
|
|
5
|
+
**Build:** [](https://github.com/krobipd/ioBroker.hassemu/actions/workflows/test-and-release.yml)   [](LICENSE) [](https://github.com/ioBroker/plugin-sentry#plugin-sentry)
|
|
6
|
+
|
|
7
|
+
**Support:** [](https://ko-fi.com/krobipd) [](https://paypal.me/krobipd)
|
|
13
8
|
|
|
14
9
|
Emulates a Home Assistant server so displays that only accept an HA dashboard show any web URL instead.
|
|
15
10
|
|
|
@@ -151,12 +146,26 @@ Got scripts that still write to `visUrl`? Update them — write to `manualUrl` i
|
|
|
151
146
|
|
|
152
147
|
---
|
|
153
148
|
|
|
149
|
+
## Sentry / Error reporting
|
|
150
|
+
|
|
151
|
+
This adapter uses [Sentry](https://sentry.io) to automatically report exceptions and errors to the developer, so problems can be found and fixed quickly. Reporting only happens if you have enabled error reporting in the ioBroker diagnostics (**System settings → Diagnostics and error reporting**). Only an anonymous installation ID is transmitted — no name, e-mail address or IP address.
|
|
152
|
+
|
|
153
|
+
For details and how to disable it, see the [Sentry plugin documentation](https://github.com/ioBroker/plugin-sentry#plugin-sentry). Error reporting requires js-controller 3.0 or newer.
|
|
154
|
+
|
|
154
155
|
## Changelog
|
|
155
156
|
|
|
156
157
|
<!--
|
|
157
158
|
Placeholder for the next version (at the beginning of the line):
|
|
158
159
|
### **WORK IN PROGRESS**
|
|
159
160
|
-->
|
|
161
|
+
### 1.35.0 (2026-06-07)
|
|
162
|
+
|
|
163
|
+
- Added optional Sentry error reporting: crashes are sent to the developer so issues get fixed faster. Active only with ioBroker diagnostics enabled; anonymous.
|
|
164
|
+
|
|
165
|
+
### 1.34.0 (2026-06-02)
|
|
166
|
+
|
|
167
|
+
- Home Assistant Companion App and Shelly Wall Display (firmware 2.6.0+): sign-out and device registration now complete reliably.
|
|
168
|
+
|
|
160
169
|
### 1.33.2 (2026-05-23)
|
|
161
170
|
|
|
162
171
|
- Changelog rewritten in user-centric style across all versions.
|
|
@@ -169,17 +178,9 @@ Got scripts that still write to `visUrl`? Update them — write to `manualUrl` i
|
|
|
169
178
|
|
|
170
179
|
- User-modified state names are no longer overwritten on adapter restart
|
|
171
180
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
- Improved error handling and stability.
|
|
175
|
-
|
|
176
|
-
### 1.32.5 (2026-05-21)
|
|
177
|
-
|
|
178
|
-
- Verified against Node.js 24. Internal cleanup.
|
|
179
|
-
|
|
180
|
-
Older entries are in [CHANGELOG_OLD.md](CHANGELOG_OLD.md).
|
|
181
|
+
[Older changelogs can be found there](CHANGELOG_OLD.md)
|
|
181
182
|
|
|
182
|
-
|
|
183
|
+
## Support Development
|
|
183
184
|
|
|
184
185
|
This adapter is free and open source. If you find it useful, consider buying me a coffee:
|
|
185
186
|
|
package/admin/i18n/de.json
CHANGED
|
@@ -40,5 +40,20 @@
|
|
|
40
40
|
"refreshUrlsDesc": "Auf true setzen, um den Broker nach VIS/VIS-2-Projekten, Admin-Kacheln und weiteren URLs neu zu durchsuchen. Sinnvoll nach Anlegen einer neuen VIS-View ohne Adapter-Neustart.",
|
|
41
41
|
"noChoice": "---",
|
|
42
42
|
"globalUrl": "Globale URL",
|
|
43
|
-
"manualUrl": "Manuelle URL"
|
|
43
|
+
"manualUrl": "Manuelle URL",
|
|
44
|
+
"pageConnectedTitle": "Verbunden · ioBroker",
|
|
45
|
+
"pageConnectedHeading": "Display verbunden",
|
|
46
|
+
"pageConnectedSubhead": "Dieses Display ist mit ioBroker verbunden. Wähle noch eine Weiterleitungs-URL aus.",
|
|
47
|
+
"pageSetupTitle": "Einrichtung abschließen",
|
|
48
|
+
"pageSetupIntro": "Lege fest, welche URL das Display beim nächsten Refresh öffnen soll:",
|
|
49
|
+
"pageStep1": "Öffne im ioBroker-Admin die Ansicht „Objekte\".",
|
|
50
|
+
"pageStep2": "Navigiere zu diesem Datenpunkt:",
|
|
51
|
+
"pageStep3": "Trage hier die gewünschte URL ein (VIS-Projekt, Grafana, Dashboard, …).",
|
|
52
|
+
"pageAutoRefresh": "Diese Seite aktualisiert sich automatisch alle 15 Sekunden.",
|
|
53
|
+
"pageOfflineTitle": "hassemu offline · ioBroker",
|
|
54
|
+
"pageOfflineHeading": "hassemu offline",
|
|
55
|
+
"pageOfflineSubhead": "Die Seite oben ist die letzte Ansicht, die das Display erhalten hat. Sobald hassemu wieder erreichbar ist, aktualisiert sich die Anzeige automatisch.",
|
|
56
|
+
"pageReload": "Jetzt neu laden",
|
|
57
|
+
"pageDeviceId": "Geräte-ID",
|
|
58
|
+
"pageIpAddress": "IP-Adresse"
|
|
44
59
|
}
|
package/admin/i18n/en.json
CHANGED
|
@@ -40,5 +40,20 @@
|
|
|
40
40
|
"refreshUrlsDesc": "Write true to re-scan the broker for VIS/VIS-2 projects, Admin tiles and other discovered URLs. Useful after creating a new VIS view without restarting the adapter.",
|
|
41
41
|
"noChoice": "---",
|
|
42
42
|
"globalUrl": "Global URL",
|
|
43
|
-
"manualUrl": "Manual URL"
|
|
43
|
+
"manualUrl": "Manual URL",
|
|
44
|
+
"pageConnectedTitle": "Connected · ioBroker",
|
|
45
|
+
"pageConnectedHeading": "Display connected",
|
|
46
|
+
"pageConnectedSubhead": "This display is linked to ioBroker. Choose a redirect URL to finish setup.",
|
|
47
|
+
"pageSetupTitle": "Finish setup",
|
|
48
|
+
"pageSetupIntro": "Set the URL that this display should open on next refresh:",
|
|
49
|
+
"pageStep1": "Open the ioBroker admin and switch to the Objects view.",
|
|
50
|
+
"pageStep2": "Go to this datapoint:",
|
|
51
|
+
"pageStep3": "Enter the URL you want to show here (VIS project, Grafana, dashboard, …).",
|
|
52
|
+
"pageAutoRefresh": "This page refreshes automatically every 15 seconds.",
|
|
53
|
+
"pageOfflineTitle": "hassemu offline · ioBroker",
|
|
54
|
+
"pageOfflineHeading": "hassemu offline",
|
|
55
|
+
"pageOfflineSubhead": "The page above is the last view this display received. As soon as hassemu is reachable again, the display updates by itself.",
|
|
56
|
+
"pageReload": "Reload now",
|
|
57
|
+
"pageDeviceId": "Device ID",
|
|
58
|
+
"pageIpAddress": "IP address"
|
|
44
59
|
}
|
package/admin/i18n/es.json
CHANGED
|
@@ -40,5 +40,20 @@
|
|
|
40
40
|
"refreshUrlsDesc": "Escribe true para volver a escanear el broker en busca de proyectos VIS/VIS-2, mosaicos Admin y otras URLs. Útil tras crear una nueva vista VIS sin reiniciar el adaptador.",
|
|
41
41
|
"noChoice": "---",
|
|
42
42
|
"globalUrl": "URL global",
|
|
43
|
-
"manualUrl": "URL manual"
|
|
43
|
+
"manualUrl": "URL manual",
|
|
44
|
+
"pageConnectedTitle": "Conectado · ioBroker",
|
|
45
|
+
"pageConnectedHeading": "Pantalla conectada",
|
|
46
|
+
"pageConnectedSubhead": "Esta pantalla está vinculada a ioBroker. Elige una URL de redirección para terminar la configuración.",
|
|
47
|
+
"pageSetupTitle": "Completar configuración",
|
|
48
|
+
"pageSetupIntro": "Indica la URL que esta pantalla abrirá en la próxima actualización:",
|
|
49
|
+
"pageStep1": "Abre el admin de ioBroker y cambia a la vista Objetos.",
|
|
50
|
+
"pageStep2": "Navega hasta este datapoint:",
|
|
51
|
+
"pageStep3": "Introduce aquí la URL deseada (proyecto VIS, Grafana, panel, …).",
|
|
52
|
+
"pageAutoRefresh": "Esta página se actualiza automáticamente cada 15 segundos.",
|
|
53
|
+
"pageOfflineTitle": "hassemu sin conexión · ioBroker",
|
|
54
|
+
"pageOfflineHeading": "hassemu sin conexión",
|
|
55
|
+
"pageOfflineSubhead": "La página de arriba es la última vista que recibió esta pantalla. En cuanto hassemu vuelva a estar disponible, la pantalla se actualizará automáticamente.",
|
|
56
|
+
"pageReload": "Recargar",
|
|
57
|
+
"pageDeviceId": "ID del dispositivo",
|
|
58
|
+
"pageIpAddress": "Dirección IP"
|
|
44
59
|
}
|
package/admin/i18n/fr.json
CHANGED
|
@@ -40,5 +40,20 @@
|
|
|
40
40
|
"refreshUrlsDesc": "Écrivez true pour ré-analyser le broker à la recherche de projets VIS/VIS-2, de tuiles Admin et d’autres URL. Utile après la création d’une nouvelle vue VIS sans redémarrer l’adaptateur.",
|
|
41
41
|
"noChoice": "---",
|
|
42
42
|
"globalUrl": "URL globale",
|
|
43
|
-
"manualUrl": "URL manuelle"
|
|
43
|
+
"manualUrl": "URL manuelle",
|
|
44
|
+
"pageConnectedTitle": "Connecté · ioBroker",
|
|
45
|
+
"pageConnectedHeading": "Écran connecté",
|
|
46
|
+
"pageConnectedSubhead": "Cet écran est relié à ioBroker. Choisissez l'URL de redirection pour terminer la configuration.",
|
|
47
|
+
"pageSetupTitle": "Finaliser la configuration",
|
|
48
|
+
"pageSetupIntro": "Indiquez l'URL que cet écran doit ouvrir à la prochaine actualisation :",
|
|
49
|
+
"pageStep1": "Ouvrez l'admin ioBroker et passez à la vue Objets.",
|
|
50
|
+
"pageStep2": "Allez sur ce datapoint :",
|
|
51
|
+
"pageStep3": "Saisissez ici l'URL souhaitée (projet VIS, Grafana, tableau de bord, …).",
|
|
52
|
+
"pageAutoRefresh": "Cette page se rafraîchit automatiquement toutes les 15 secondes.",
|
|
53
|
+
"pageOfflineTitle": "hassemu hors ligne · ioBroker",
|
|
54
|
+
"pageOfflineHeading": "hassemu hors ligne",
|
|
55
|
+
"pageOfflineSubhead": "La page ci-dessus est la dernière vue reçue par cet écran. Dès que hassemu est de nouveau accessible, l'écran se met à jour automatiquement.",
|
|
56
|
+
"pageReload": "Recharger",
|
|
57
|
+
"pageDeviceId": "Identifiant de l'appareil",
|
|
58
|
+
"pageIpAddress": "Adresse IP"
|
|
44
59
|
}
|
package/admin/i18n/it.json
CHANGED
|
@@ -40,5 +40,20 @@
|
|
|
40
40
|
"refreshUrlsDesc": "Scrivi true per ri-scansionare il broker per progetti VIS/VIS-2, tile Admin e altri URL. Utile dopo aver creato una nuova view VIS senza riavviare l’adattatore.",
|
|
41
41
|
"noChoice": "---",
|
|
42
42
|
"globalUrl": "URL globale",
|
|
43
|
-
"manualUrl": "URL manuale"
|
|
43
|
+
"manualUrl": "URL manuale",
|
|
44
|
+
"pageConnectedTitle": "Connesso · ioBroker",
|
|
45
|
+
"pageConnectedHeading": "Display connesso",
|
|
46
|
+
"pageConnectedSubhead": "Questo display è collegato a ioBroker. Scegli un URL di reindirizzamento per completare la configurazione.",
|
|
47
|
+
"pageSetupTitle": "Completa la configurazione",
|
|
48
|
+
"pageSetupIntro": "Imposta l'URL che il display deve aprire al prossimo aggiornamento:",
|
|
49
|
+
"pageStep1": "Apri l'admin di ioBroker e passa alla vista Oggetti.",
|
|
50
|
+
"pageStep2": "Vai a questo datapoint:",
|
|
51
|
+
"pageStep3": "Inserisci qui l'URL desiderato (progetto VIS, Grafana, dashboard, …).",
|
|
52
|
+
"pageAutoRefresh": "Questa pagina si aggiorna automaticamente ogni 15 secondi.",
|
|
53
|
+
"pageOfflineTitle": "hassemu offline · ioBroker",
|
|
54
|
+
"pageOfflineHeading": "hassemu offline",
|
|
55
|
+
"pageOfflineSubhead": "La pagina sopra è l’ultima vista ricevuta dal display. Appena hassemu sarà nuovamente raggiungibile, la schermata si aggiornerà automaticamente.",
|
|
56
|
+
"pageReload": "Ricarica",
|
|
57
|
+
"pageDeviceId": "ID dispositivo",
|
|
58
|
+
"pageIpAddress": "Indirizzo IP"
|
|
44
59
|
}
|
package/admin/i18n/nl.json
CHANGED
|
@@ -40,5 +40,20 @@
|
|
|
40
40
|
"refreshUrlsDesc": "Schrijf true om de broker opnieuw te scannen op VIS/VIS-2-projecten, admin-tegels en andere URLs. Handig na het aanmaken van een nieuwe VIS-view zonder de adapter te herstarten.",
|
|
41
41
|
"noChoice": "---",
|
|
42
42
|
"globalUrl": "Globale URL",
|
|
43
|
-
"manualUrl": "Handmatige URL"
|
|
43
|
+
"manualUrl": "Handmatige URL",
|
|
44
|
+
"pageConnectedTitle": "Verbonden · ioBroker",
|
|
45
|
+
"pageConnectedHeading": "Display verbonden",
|
|
46
|
+
"pageConnectedSubhead": "Dit display is met ioBroker verbonden. Kies een redirect-URL om de setup af te ronden.",
|
|
47
|
+
"pageSetupTitle": "Setup afronden",
|
|
48
|
+
"pageSetupIntro": "Stel de URL in die dit display bij de volgende refresh moet openen:",
|
|
49
|
+
"pageStep1": "Open de ioBroker-admin en ga naar de Objects-weergave.",
|
|
50
|
+
"pageStep2": "Navigeer naar dit datapoint:",
|
|
51
|
+
"pageStep3": "Voer hier de gewenste URL in (VIS-project, Grafana, dashboard, …).",
|
|
52
|
+
"pageAutoRefresh": "Deze pagina vernieuwt zich automatisch elke 15 seconden.",
|
|
53
|
+
"pageOfflineTitle": "hassemu offline · ioBroker",
|
|
54
|
+
"pageOfflineHeading": "hassemu offline",
|
|
55
|
+
"pageOfflineSubhead": "De pagina hierboven is de laatste weergave die dit display heeft ontvangen. Zodra hassemu weer bereikbaar is, wordt het scherm automatisch bijgewerkt.",
|
|
56
|
+
"pageReload": "Opnieuw laden",
|
|
57
|
+
"pageDeviceId": "Apparaat-ID",
|
|
58
|
+
"pageIpAddress": "IP-adres"
|
|
44
59
|
}
|
package/admin/i18n/pl.json
CHANGED
|
@@ -40,5 +40,20 @@
|
|
|
40
40
|
"refreshUrlsDesc": "Wpisz true, aby ponownie przeszukać broker pod kątem projektów VIS/VIS-2, kafelków Admin i innych URL. Przydatne po utworzeniu nowego widoku VIS bez restartu adaptera.",
|
|
41
41
|
"noChoice": "---",
|
|
42
42
|
"globalUrl": "Globalny URL",
|
|
43
|
-
"manualUrl": "Ręczny URL"
|
|
43
|
+
"manualUrl": "Ręczny URL",
|
|
44
|
+
"pageConnectedTitle": "Połączono · ioBroker",
|
|
45
|
+
"pageConnectedHeading": "Wyświetlacz połączony",
|
|
46
|
+
"pageConnectedSubhead": "Ten wyświetlacz jest połączony z ioBrokerem. Wybierz adres URL przekierowania.",
|
|
47
|
+
"pageSetupTitle": "Zakończ konfigurację",
|
|
48
|
+
"pageSetupIntro": "Ustaw URL, który ma otwierać ten wyświetlacz przy następnym odświeżeniu:",
|
|
49
|
+
"pageStep1": "Otwórz panel ioBroker i przejdź do widoku Obiektów.",
|
|
50
|
+
"pageStep2": "Przejdź do tego datapointu:",
|
|
51
|
+
"pageStep3": "Wpisz tutaj żądany URL (projekt VIS, Grafana, dashboard, …).",
|
|
52
|
+
"pageAutoRefresh": "Ta strona odświeża się automatycznie co 15 sekund.",
|
|
53
|
+
"pageOfflineTitle": "hassemu offline · ioBroker",
|
|
54
|
+
"pageOfflineHeading": "hassemu offline",
|
|
55
|
+
"pageOfflineSubhead": "Strona powyżej to ostatni widok otrzymany przez ten wyświetlacz. Gdy hassemu znów będzie dostępny, ekran odświeży się sam.",
|
|
56
|
+
"pageReload": "Załaduj ponownie",
|
|
57
|
+
"pageDeviceId": "ID urządzenia",
|
|
58
|
+
"pageIpAddress": "Adres IP"
|
|
44
59
|
}
|
package/admin/i18n/pt.json
CHANGED
|
@@ -40,5 +40,20 @@
|
|
|
40
40
|
"refreshUrlsDesc": "Escreve true para voltar a procurar projetos VIS/VIS-2, mosaicos Admin e outros URLs no broker. Útil após criar uma nova view VIS sem reiniciar o adaptador.",
|
|
41
41
|
"noChoice": "---",
|
|
42
42
|
"globalUrl": "URL global",
|
|
43
|
-
"manualUrl": "URL manual"
|
|
43
|
+
"manualUrl": "URL manual",
|
|
44
|
+
"pageConnectedTitle": "Conectado · ioBroker",
|
|
45
|
+
"pageConnectedHeading": "Display conectado",
|
|
46
|
+
"pageConnectedSubhead": "Este display está conectado ao ioBroker. Escolha um URL de redirecionamento.",
|
|
47
|
+
"pageSetupTitle": "Concluir configuração",
|
|
48
|
+
"pageSetupIntro": "Defina o URL que este display deve abrir na próxima atualização:",
|
|
49
|
+
"pageStep1": "Abra o admin do ioBroker e mude para a visão de Objetos.",
|
|
50
|
+
"pageStep2": "Navegue até este datapoint:",
|
|
51
|
+
"pageStep3": "Insira o URL desejado (projeto VIS, Grafana, dashboard, …).",
|
|
52
|
+
"pageAutoRefresh": "Esta página atualiza automaticamente a cada 15 segundos.",
|
|
53
|
+
"pageOfflineTitle": "hassemu offline · ioBroker",
|
|
54
|
+
"pageOfflineHeading": "hassemu offline",
|
|
55
|
+
"pageOfflineSubhead": "A página acima é a última visualização que este ecrã recebeu. Assim que o hassemu voltar a estar disponível, o ecrã atualiza-se automaticamente.",
|
|
56
|
+
"pageReload": "Recarregar",
|
|
57
|
+
"pageDeviceId": "ID do dispositivo",
|
|
58
|
+
"pageIpAddress": "Endereço IP"
|
|
44
59
|
}
|
package/admin/i18n/ru.json
CHANGED
|
@@ -40,5 +40,20 @@
|
|
|
40
40
|
"refreshUrlsDesc": "Запишите true, чтобы пересканировать брокер на VIS/VIS-2-проекты, Admin-плитки и другие URL. Удобно после создания новой VIS-view без перезапуска адаптера.",
|
|
41
41
|
"noChoice": "---",
|
|
42
42
|
"globalUrl": "Глобальный URL",
|
|
43
|
-
"manualUrl": "Ручной URL"
|
|
43
|
+
"manualUrl": "Ручной URL",
|
|
44
|
+
"pageConnectedTitle": "Подключено · ioBroker",
|
|
45
|
+
"pageConnectedHeading": "Дисплей подключён",
|
|
46
|
+
"pageConnectedSubhead": "Этот дисплей подключён к ioBroker. Выберите URL для перенаправления.",
|
|
47
|
+
"pageSetupTitle": "Завершение настройки",
|
|
48
|
+
"pageSetupIntro": "Укажите URL, который дисплей откроет при следующем обновлении:",
|
|
49
|
+
"pageStep1": "Откройте админку ioBroker и перейдите в раздел «Объекты».",
|
|
50
|
+
"pageStep2": "Перейдите к этому датапункту:",
|
|
51
|
+
"pageStep3": "Введите нужный URL (проект VIS, Grafana, дашборд и т. д.).",
|
|
52
|
+
"pageAutoRefresh": "Страница автоматически обновляется каждые 15 секунд.",
|
|
53
|
+
"pageOfflineTitle": "hassemu недоступен · ioBroker",
|
|
54
|
+
"pageOfflineHeading": "hassemu недоступен",
|
|
55
|
+
"pageOfflineSubhead": "Страница выше — последний вид, который получил дисплей. Как только hassemu снова доступен, экран обновится автоматически.",
|
|
56
|
+
"pageReload": "Перезагрузить",
|
|
57
|
+
"pageDeviceId": "ID устройства",
|
|
58
|
+
"pageIpAddress": "IP-адрес"
|
|
44
59
|
}
|
package/admin/i18n/uk.json
CHANGED
|
@@ -40,5 +40,20 @@
|
|
|
40
40
|
"refreshUrlsDesc": "Запишіть true, щоб повторно сканувати брокер на проекти VIS/VIS-2, admin-плитки та інші URL. Корисно після створення нової VIS-view без перезапуску адаптера.",
|
|
41
41
|
"noChoice": "---",
|
|
42
42
|
"globalUrl": "Глобальний URL",
|
|
43
|
-
"manualUrl": "Ручний URL"
|
|
43
|
+
"manualUrl": "Ручний URL",
|
|
44
|
+
"pageConnectedTitle": "З'єднано · ioBroker",
|
|
45
|
+
"pageConnectedHeading": "Дисплей під'єднано",
|
|
46
|
+
"pageConnectedSubhead": "Цей дисплей з'єднано з ioBroker. Оберіть URL для перенаправлення.",
|
|
47
|
+
"pageSetupTitle": "Завершити налаштування",
|
|
48
|
+
"pageSetupIntro": "Вкажіть URL, який дисплей відкриє при наступному оновленні:",
|
|
49
|
+
"pageStep1": "Відкрийте адмін ioBroker і перейдіть до перегляду «Об'єкти».",
|
|
50
|
+
"pageStep2": "Перейдіть до цього датапоінта:",
|
|
51
|
+
"pageStep3": "Введіть потрібний URL (проєкт VIS, Grafana, дашборд, …).",
|
|
52
|
+
"pageAutoRefresh": "Ця сторінка автоматично оновлюється кожні 15 секунд.",
|
|
53
|
+
"pageOfflineTitle": "hassemu офлайн · ioBroker",
|
|
54
|
+
"pageOfflineHeading": "hassemu офлайн",
|
|
55
|
+
"pageOfflineSubhead": "Сторінка вище — останній вигляд, який отримав цей дисплей. Щойно hassemu знову буде доступним, екран оновиться автоматично.",
|
|
56
|
+
"pageReload": "Перезавантажити",
|
|
57
|
+
"pageDeviceId": "ID пристрою",
|
|
58
|
+
"pageIpAddress": "IP-адреса"
|
|
44
59
|
}
|
package/admin/i18n/zh-cn.json
CHANGED
|
@@ -40,5 +40,20 @@
|
|
|
40
40
|
"refreshUrlsDesc": "写入 true 以重新扫描 broker 上的 VIS/VIS-2 项目、Admin 瓷贴和其他 URL。在不重启适配器的情况下创建新 VIS 视图后很有用。",
|
|
41
41
|
"noChoice": "---",
|
|
42
42
|
"globalUrl": "全局 URL",
|
|
43
|
-
"manualUrl": "手动 URL"
|
|
43
|
+
"manualUrl": "手动 URL",
|
|
44
|
+
"pageConnectedTitle": "已连接 · ioBroker",
|
|
45
|
+
"pageConnectedHeading": "显示器已连接",
|
|
46
|
+
"pageConnectedSubhead": "此显示器已连接到 ioBroker。请选择跳转 URL 以完成设置。",
|
|
47
|
+
"pageSetupTitle": "完成设置",
|
|
48
|
+
"pageSetupIntro": "设置此显示器下次刷新时要打开的 URL:",
|
|
49
|
+
"pageStep1": "打开 ioBroker 管理界面并切换到「对象」视图。",
|
|
50
|
+
"pageStep2": "导航到此数据点:",
|
|
51
|
+
"pageStep3": "在此处输入所需的 URL(VIS 项目、Grafana、仪表板等)。",
|
|
52
|
+
"pageAutoRefresh": "此页面每 15 秒自动刷新一次。",
|
|
53
|
+
"pageOfflineTitle": "hassemu 离线 · ioBroker",
|
|
54
|
+
"pageOfflineHeading": "hassemu 离线",
|
|
55
|
+
"pageOfflineSubhead": "上方页面是此显示器收到的最后一次视图。hassemu 重新可用后,屏幕会自动刷新。",
|
|
56
|
+
"pageReload": "立即重新加载",
|
|
57
|
+
"pageDeviceId": "设备 ID",
|
|
58
|
+
"pageIpAddress": "IP 地址"
|
|
44
59
|
}
|
package/build/lib/auth-page.js
CHANGED
|
@@ -50,42 +50,43 @@ button{display:block;width:100%;padding:14px;background:#03a9f4;color:#fff;borde
|
|
|
50
50
|
button:hover{background:#039be5;}
|
|
51
51
|
.loading{text-align:center;color:#888;padding:16px;}
|
|
52
52
|
`.trim();
|
|
53
|
-
function
|
|
54
|
-
const a = (0, import_coerce.escapeHtml)(target);
|
|
55
|
-
const j = JSON.stringify(target);
|
|
53
|
+
function htmlShell(opts) {
|
|
56
54
|
return `<!DOCTYPE html>
|
|
57
55
|
<html lang="en">
|
|
58
56
|
<head>
|
|
59
57
|
<meta charset="utf-8">
|
|
60
|
-
|
|
61
|
-
<title
|
|
58
|
+
${opts.headExtra}
|
|
59
|
+
<title>${opts.title}</title>
|
|
62
60
|
<style>${STYLE}</style>
|
|
63
61
|
</head>
|
|
64
62
|
<body>
|
|
65
63
|
<div class="card">
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
<script>(function(){document.location.assign(${j});})();</script>
|
|
64
|
+
${opts.cardInner}
|
|
65
|
+
</div>${opts.bodyExtra ? `
|
|
66
|
+
${opts.bodyExtra}` : ""}
|
|
70
67
|
</body>
|
|
71
68
|
</html>`;
|
|
72
69
|
}
|
|
70
|
+
function renderAuthorizeRedirect(target) {
|
|
71
|
+
const a = (0, import_coerce.escapeHtml)(target);
|
|
72
|
+
const j = JSON.stringify(target);
|
|
73
|
+
return htmlShell({
|
|
74
|
+
title: "Home Assistant",
|
|
75
|
+
headExtra: `<meta http-equiv="refresh" content="0; URL=${a}">`,
|
|
76
|
+
cardInner: `<h1>Home Assistant</h1>
|
|
77
|
+
<p class="loading">Signing in\u2026</p>`,
|
|
78
|
+
bodyExtra: `<script>(function(){document.location.assign(${j});})();</script>`
|
|
79
|
+
});
|
|
80
|
+
}
|
|
73
81
|
function renderAuthorizeForm(params, errorMessage) {
|
|
74
82
|
const cid = (0, import_coerce.escapeHtml)(params.clientId);
|
|
75
83
|
const ru = (0, import_coerce.escapeHtml)(params.redirectUri);
|
|
76
84
|
const st = params.state ? (0, import_coerce.escapeHtml)(params.state) : "";
|
|
77
85
|
const errBlock = errorMessage ? `<div class="err">${(0, import_coerce.escapeHtml)(errorMessage)}</div>` : "";
|
|
78
|
-
return
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
83
|
-
<title>Home Assistant \u2014 Sign In</title>
|
|
84
|
-
<style>${STYLE}</style>
|
|
85
|
-
</head>
|
|
86
|
-
<body>
|
|
87
|
-
<div class="card">
|
|
88
|
-
<h1>Home Assistant</h1>
|
|
86
|
+
return htmlShell({
|
|
87
|
+
title: "Home Assistant \u2014 Sign In",
|
|
88
|
+
headExtra: `<meta name="viewport" content="width=device-width, initial-scale=1">`,
|
|
89
|
+
cardInner: `<h1>Home Assistant</h1>
|
|
89
90
|
<p class="subtitle">Sign in to authorize this device.</p>
|
|
90
91
|
${errBlock}
|
|
91
92
|
<form method="POST" action="/auth/authorize" autocomplete="off">
|
|
@@ -96,28 +97,17 @@ ${errBlock}
|
|
|
96
97
|
<input type="text" name="username" placeholder="Username" autofocus required>
|
|
97
98
|
<input type="password" name="password" placeholder="Password" required>
|
|
98
99
|
<button type="submit">Sign in</button>
|
|
99
|
-
</form
|
|
100
|
-
|
|
101
|
-
</body>
|
|
102
|
-
</html>`;
|
|
100
|
+
</form>`
|
|
101
|
+
});
|
|
103
102
|
}
|
|
104
103
|
function renderAuthorizeError(reason, detail) {
|
|
105
|
-
return
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
110
|
-
<title>Home Assistant \u2014 ${(0, import_coerce.escapeHtml)(reason)}</title>
|
|
111
|
-
<style>${STYLE}</style>
|
|
112
|
-
</head>
|
|
113
|
-
<body>
|
|
114
|
-
<div class="card">
|
|
115
|
-
<h1>Authorization failed</h1>
|
|
104
|
+
return htmlShell({
|
|
105
|
+
title: `Home Assistant \u2014 ${(0, import_coerce.escapeHtml)(reason)}`,
|
|
106
|
+
headExtra: `<meta name="viewport" content="width=device-width, initial-scale=1">`,
|
|
107
|
+
cardInner: `<h1>Authorization failed</h1>
|
|
116
108
|
<div class="err">${(0, import_coerce.escapeHtml)(detail)}</div>
|
|
117
|
-
<p class="subtitle">${(0, import_coerce.escapeHtml)(reason)}</p
|
|
118
|
-
|
|
119
|
-
</body>
|
|
120
|
-
</html>`;
|
|
109
|
+
<p class="subtitle">${(0, import_coerce.escapeHtml)(reason)}</p>`
|
|
110
|
+
});
|
|
121
111
|
}
|
|
122
112
|
// Annotate the CommonJS export names for ESM import in node:
|
|
123
113
|
0 && (module.exports = {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/auth-page.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Minimal HTML templates for the OAuth2 browser-flow at `/auth/authorize`.\n *\n * The real Home Assistant frontend renders the auth UI via a multi-MB\n * Lit/Polymer Web Component bundle. For hassemu we re-implement only the\n * subset the HA Companion App and the Shelly Wall Display app actually need:\n *\n * - `authRequired=false`: auto-submit page that calls `document.location.assign`\n * with `redirect_uri?code=\u2026&state=\u2026` immediately. Matches HA's frontend\n * redirect helper `redirectWithAuthCode` 1:1.\n * - `authRequired=true`: a minimal username/password form that POSTs to\n * `/auth/authorize`. The handler verifies credentials and replies with\n * the same auto-submit redirect on success, or re-renders the form with\n * an error banner on failure.\n * - `400` error page when query parameters are malformed or the\n * `redirect_uri` fails validation \u2014 never redirects, so an attacker\n * cannot use the endpoint as an open redirector.\n *\n * Source: `home-assistant/frontend/src/data/auth.ts:redirectWithAuthCode` \u2014\n * `document.location.assign(url)` with `code=<encoded>&state=<encoded>`.\n */\n\n// v1.32.0: lokales `escAttr` (4 Char) ersetzt durch shared `escapeHtml` (5 Char)\n// aus `coerce.ts` \u2014 defense-in-depth, `'` zus\u00E4tzlich geh\u00E4rtet.\nimport { escapeHtml as escAttr } from \"./coerce\";\n\n/**\n * Build the final redirect URL with the auth code appended.\n *\n * @param redirectUri Already-validated `redirect_uri` from the OAuth2 query.\n * @param code Auth code to deliver (will be URL-encoded).\n * @param state Optional `state` parameter \u2014 round-tripped verbatim per OAuth2 CSRF.\n */\nexport function buildRedirectUrl(redirectUri: string, code: string, state: string | undefined): string {\n // Source: home-assistant/frontend/src/data/auth.ts \u2014 OAuth 2: 3.1.2 we\n // need to retain the existing query of a redirect URI.\n let url = redirectUri;\n if (!url.includes(\"?\")) {\n url += \"?\";\n } else if (!url.endsWith(\"&\") && !url.endsWith(\"?\")) {\n url += \"&\";\n }\n url += `code=${encodeURIComponent(code)}`;\n if (state) {\n url += `&state=${encodeURIComponent(state)}`;\n }\n return url;\n}\n\nconst STYLE = `\nhtml,body{margin:0;padding:0;height:100%;background:#111;color:#fff;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;}\n.card{max-width:380px;margin:64px auto;padding:32px;background:#1c1c1c;border-radius:8px;box-shadow:0 4px 12px rgba(0,0,0,0.5);}\nh1{margin:0 0 24px;font-size:24px;font-weight:500;text-align:center;color:#03a9f4;}\n.subtitle{color:#888;font-size:14px;text-align:center;margin:-16px 0 24px;}\n.err{background:#3a1a1a;color:#ff8a80;padding:12px;border-radius:4px;margin-bottom:16px;font-size:14px;}\ninput{display:block;width:100%;padding:12px;margin:8px 0 16px;background:#2a2a2a;border:1px solid #444;color:#fff;border-radius:4px;font-size:16px;box-sizing:border-box;}\ninput:focus{outline:none;border-color:#03a9f4;}\nbutton{display:block;width:100%;padding:14px;background:#03a9f4;color:#fff;border:none;border-radius:4px;font-size:16px;cursor:pointer;}\nbutton:hover{background:#039be5;}\n.loading{text-align:center;color:#888;padding:16px;}\n`.trim();\n\n/**\n * Render the auto-submit redirect page. Used when `authRequired=false` (after\n * generating an auth_code) OR after a successful POST login.\n *\n * Uses `document.location.assign(url)` to match HA's `redirectWithAuthCode`.\n * `<meta http-equiv=\"refresh\">` as a fallback for clients without JS, though\n * the HA Companion App and Shelly Wall Display WebView both have JS enabled.\n *\n * @param target The fully-built `redirect_uri?code=\u2026&state=\u2026` URL.\n */\nexport function renderAuthorizeRedirect(target: string): string {\n const a = escAttr(target);\n const j = JSON.stringify(target); // safe for inline JS string literal\n return
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwBA,oBAAsC;AAS/B,SAAS,iBAAiB,aAAqB,MAAc,OAAmC;AAGrG,MAAI,MAAM;AACV,MAAI,CAAC,IAAI,SAAS,GAAG,GAAG;AACtB,WAAO;AAAA,EACT,WAAW,CAAC,IAAI,SAAS,GAAG,KAAK,CAAC,IAAI,SAAS,GAAG,GAAG;AACnD,WAAO;AAAA,EACT;AACA,SAAO,QAAQ,mBAAmB,IAAI,CAAC;AACvC,MAAI,OAAO;AACT,WAAO,UAAU,mBAAmB,KAAK,CAAC;AAAA,EAC5C;AACA,SAAO;AACT;AAEA,MAAM,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWZ,KAAK;
|
|
4
|
+
"sourcesContent": ["/**\n * Minimal HTML templates for the OAuth2 browser-flow at `/auth/authorize`.\n *\n * The real Home Assistant frontend renders the auth UI via a multi-MB\n * Lit/Polymer Web Component bundle. For hassemu we re-implement only the\n * subset the HA Companion App and the Shelly Wall Display app actually need:\n *\n * - `authRequired=false`: auto-submit page that calls `document.location.assign`\n * with `redirect_uri?code=\u2026&state=\u2026` immediately. Matches HA's frontend\n * redirect helper `redirectWithAuthCode` 1:1.\n * - `authRequired=true`: a minimal username/password form that POSTs to\n * `/auth/authorize`. The handler verifies credentials and replies with\n * the same auto-submit redirect on success, or re-renders the form with\n * an error banner on failure.\n * - `400` error page when query parameters are malformed or the\n * `redirect_uri` fails validation \u2014 never redirects, so an attacker\n * cannot use the endpoint as an open redirector.\n *\n * Source: `home-assistant/frontend/src/data/auth.ts:redirectWithAuthCode` \u2014\n * `document.location.assign(url)` with `code=<encoded>&state=<encoded>`.\n */\n\n// v1.32.0: lokales `escAttr` (4 Char) ersetzt durch shared `escapeHtml` (5 Char)\n// aus `coerce.ts` \u2014 defense-in-depth, `'` zus\u00E4tzlich geh\u00E4rtet.\nimport { escapeHtml as escAttr } from \"./coerce\";\n\n/**\n * Build the final redirect URL with the auth code appended.\n *\n * @param redirectUri Already-validated `redirect_uri` from the OAuth2 query.\n * @param code Auth code to deliver (will be URL-encoded).\n * @param state Optional `state` parameter \u2014 round-tripped verbatim per OAuth2 CSRF.\n */\nexport function buildRedirectUrl(redirectUri: string, code: string, state: string | undefined): string {\n // Source: home-assistant/frontend/src/data/auth.ts \u2014 OAuth 2: 3.1.2 we\n // need to retain the existing query of a redirect URI.\n let url = redirectUri;\n if (!url.includes(\"?\")) {\n url += \"?\";\n } else if (!url.endsWith(\"&\") && !url.endsWith(\"?\")) {\n url += \"&\";\n }\n url += `code=${encodeURIComponent(code)}`;\n if (state) {\n url += `&state=${encodeURIComponent(state)}`;\n }\n return url;\n}\n\nconst STYLE = `\nhtml,body{margin:0;padding:0;height:100%;background:#111;color:#fff;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;}\n.card{max-width:380px;margin:64px auto;padding:32px;background:#1c1c1c;border-radius:8px;box-shadow:0 4px 12px rgba(0,0,0,0.5);}\nh1{margin:0 0 24px;font-size:24px;font-weight:500;text-align:center;color:#03a9f4;}\n.subtitle{color:#888;font-size:14px;text-align:center;margin:-16px 0 24px;}\n.err{background:#3a1a1a;color:#ff8a80;padding:12px;border-radius:4px;margin-bottom:16px;font-size:14px;}\ninput{display:block;width:100%;padding:12px;margin:8px 0 16px;background:#2a2a2a;border:1px solid #444;color:#fff;border-radius:4px;font-size:16px;box-sizing:border-box;}\ninput:focus{outline:none;border-color:#03a9f4;}\nbutton{display:block;width:100%;padding:14px;background:#03a9f4;color:#fff;border:none;border-radius:4px;font-size:16px;cursor:pointer;}\nbutton:hover{background:#039be5;}\n.loading{text-align:center;color:#888;padding:16px;}\n`.trim();\n\n/**\n * Shared page frame for the 3 auth pages \u2014 identical DOCTYPE / `<head>` / style /\n * `.card` wrapper. Each page supplies its own `<title>`, an extra `<head>` line\n * (viewport or the redirect `meta refresh`), the card body, and optional trailing\n * body markup (the redirect `<script>`).\n *\n * @param opts Page parts to assemble into the shared shell.\n * @param opts.title `<title>` text (already escaped by the caller if dynamic).\n * @param opts.headExtra One extra `<head>` line (viewport meta / refresh meta).\n * @param opts.cardInner Inner HTML of the `.card` container.\n * @param opts.bodyExtra Optional markup appended after the card (e.g. the redirect script).\n */\nfunction htmlShell(opts: { title: string; headExtra: string; cardInner: string; bodyExtra?: string }): string {\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n${opts.headExtra}\n<title>${opts.title}</title>\n<style>${STYLE}</style>\n</head>\n<body>\n<div class=\"card\">\n${opts.cardInner}\n</div>${opts.bodyExtra ? `\\n${opts.bodyExtra}` : \"\"}\n</body>\n</html>`;\n}\n\n/**\n * Render the auto-submit redirect page. Used when `authRequired=false` (after\n * generating an auth_code) OR after a successful POST login.\n *\n * Uses `document.location.assign(url)` to match HA's `redirectWithAuthCode`.\n * `<meta http-equiv=\"refresh\">` as a fallback for clients without JS, though\n * the HA Companion App and Shelly Wall Display WebView both have JS enabled.\n *\n * @param target The fully-built `redirect_uri?code=\u2026&state=\u2026` URL.\n */\nexport function renderAuthorizeRedirect(target: string): string {\n const a = escAttr(target);\n const j = JSON.stringify(target); // safe for inline JS string literal\n return htmlShell({\n title: \"Home Assistant\",\n headExtra: `<meta http-equiv=\"refresh\" content=\"0; URL=${a}\">`,\n cardInner: `<h1>Home Assistant</h1>\n<p class=\"loading\">Signing in\u2026</p>`,\n bodyExtra: `<script>(function(){document.location.assign(${j});})();</script>`,\n });\n}\n\n/**\n * Render the login form. Used on GET `/auth/authorize` when `authRequired=true`,\n * and re-used by the POST handler on credential failure with the error banner.\n *\n * Hidden fields preserve the OAuth2 query params across the form-submit so the\n * POST handler can finish the flow.\n *\n * @param params Form context \u2014 `client_id`, `redirect_uri`, `state` (optional).\n * @param params.clientId The OAuth2 `client_id` to round-trip in a hidden input.\n * @param params.redirectUri Already-validated `redirect_uri` to round-trip in a hidden input.\n * @param params.state Optional OAuth2 `state` (CSRF token) to round-trip.\n * @param errorMessage Optional error banner text (i.e. \"Invalid username or password.\").\n */\nexport function renderAuthorizeForm(\n params: { clientId: string; redirectUri: string; state?: string },\n errorMessage?: string,\n): string {\n const cid = escAttr(params.clientId);\n const ru = escAttr(params.redirectUri);\n const st = params.state ? escAttr(params.state) : \"\";\n const errBlock = errorMessage ? `<div class=\"err\">${escAttr(errorMessage)}</div>` : \"\";\n return htmlShell({\n title: \"Home Assistant \u2014 Sign In\",\n headExtra: `<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">`,\n cardInner: `<h1>Home Assistant</h1>\n<p class=\"subtitle\">Sign in to authorize this device.</p>\n${errBlock}\n<form method=\"POST\" action=\"/auth/authorize\" autocomplete=\"off\">\n<input type=\"hidden\" name=\"response_type\" value=\"code\">\n<input type=\"hidden\" name=\"client_id\" value=\"${cid}\">\n<input type=\"hidden\" name=\"redirect_uri\" value=\"${ru}\">\n<input type=\"hidden\" name=\"state\" value=\"${st}\">\n<input type=\"text\" name=\"username\" placeholder=\"Username\" autofocus required>\n<input type=\"password\" name=\"password\" placeholder=\"Password\" required>\n<button type=\"submit\">Sign in</button>\n</form>`,\n });\n}\n\n/**\n * Render the authorization error page. Used when query params are malformed\n * or when `redirect_uri` fails validation. NEVER auto-redirects \u2014 we don't\n * want to leak codes to attacker-controlled URIs by accident.\n *\n * @param reason Short OAuth2 error code (e.g. `invalid_request`).\n * @param detail Human-readable explanation.\n */\nexport function renderAuthorizeError(reason: string, detail: string): string {\n return htmlShell({\n title: `Home Assistant \u2014 ${escAttr(reason)}`,\n headExtra: `<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">`,\n cardInner: `<h1>Authorization failed</h1>\n<div class=\"err\">${escAttr(detail)}</div>\n<p class=\"subtitle\">${escAttr(reason)}</p>`,\n });\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwBA,oBAAsC;AAS/B,SAAS,iBAAiB,aAAqB,MAAc,OAAmC;AAGrG,MAAI,MAAM;AACV,MAAI,CAAC,IAAI,SAAS,GAAG,GAAG;AACtB,WAAO;AAAA,EACT,WAAW,CAAC,IAAI,SAAS,GAAG,KAAK,CAAC,IAAI,SAAS,GAAG,GAAG;AACnD,WAAO;AAAA,EACT;AACA,SAAO,QAAQ,mBAAmB,IAAI,CAAC;AACvC,MAAI,OAAO;AACT,WAAO,UAAU,mBAAmB,KAAK,CAAC;AAAA,EAC5C;AACA,SAAO;AACT;AAEA,MAAM,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWZ,KAAK;AAcP,SAAS,UAAU,MAA2F;AAC5G,SAAO;AAAA;AAAA;AAAA;AAAA,EAIP,KAAK,SAAS;AAAA,SACP,KAAK,KAAK;AAAA,SACV,KAAK;AAAA;AAAA;AAAA;AAAA,EAIZ,KAAK,SAAS;AAAA,QACR,KAAK,YAAY;AAAA,EAAK,KAAK,SAAS,KAAK,EAAE;AAAA;AAAA;AAGnD;AAYO,SAAS,wBAAwB,QAAwB;AAC9D,QAAM,QAAI,cAAAA,YAAQ,MAAM;AACxB,QAAM,IAAI,KAAK,UAAU,MAAM;AAC/B,SAAO,UAAU;AAAA,IACf,OAAO;AAAA,IACP,WAAW,8CAA8C,CAAC;AAAA,IAC1D,WAAW;AAAA;AAAA,IAEX,WAAW,gDAAgD,CAAC;AAAA,EAC9D,CAAC;AACH;AAeO,SAAS,oBACd,QACA,cACQ;AACR,QAAM,UAAM,cAAAA,YAAQ,OAAO,QAAQ;AACnC,QAAM,SAAK,cAAAA,YAAQ,OAAO,WAAW;AACrC,QAAM,KAAK,OAAO,YAAQ,cAAAA,YAAQ,OAAO,KAAK,IAAI;AAClD,QAAM,WAAW,eAAe,wBAAoB,cAAAA,YAAQ,YAAY,CAAC,WAAW;AACpF,SAAO,UAAU;AAAA,IACf,OAAO;AAAA,IACP,WAAW;AAAA,IACX,WAAW;AAAA;AAAA,EAEb,QAAQ;AAAA;AAAA;AAAA,+CAGqC,GAAG;AAAA,kDACA,EAAE;AAAA,2CACT,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA,EAK3C,CAAC;AACH;AAUO,SAAS,qBAAqB,QAAgB,QAAwB;AAC3E,SAAO,UAAU;AAAA,IACf,OAAO,6BAAoB,cAAAA,YAAQ,MAAM,CAAC;AAAA,IAC1C,WAAW;AAAA,IACX,WAAW;AAAA,uBACI,cAAAA,YAAQ,MAAM,CAAC;AAAA,0BACZ,cAAAA,YAAQ,MAAM,CAAC;AAAA,EACnC,CAAC;AACH;",
|
|
6
6
|
"names": ["escAttr"]
|
|
7
7
|
}
|
|
@@ -549,6 +549,7 @@ class ClientRegistry {
|
|
|
549
549
|
native: { cookie, token: null }
|
|
550
550
|
});
|
|
551
551
|
const modeFullCommon = {
|
|
552
|
+
// tName returns StringOrTranslated, which common.name accepts directly.
|
|
552
553
|
name: (0, import_i18n.tName)("clientMode"),
|
|
553
554
|
// 'mixed' future-proofs against the upcoming js-controller
|
|
554
555
|
// strict-type cast (see govee-smart v1.11.0 pattern).
|