Compare commits

..

18 Commits

Author SHA1 Message Date
Yosi Levy 54a8e6c294 RTL fix for automation row (#52200) 2026-05-25 12:38:34 +02:00
Yosi Levy bfec22d828 RTL fix for new suggestion tree (#52199) 2026-05-25 11:52:54 +02:00
steven cde6450cfc Fix stale wake word display after wake word change in voice satellite set up wizard (#52194)
Fix stale wake word display after wake word change in satellite wizard

The config re-fetch was fire-and-forgotten, so the step transition to
STEP.WAKEWORD raced ahead with stale assistConfiguration. Awaiting the
fetch ensures the fresh active_wake_words are in place before rendering.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 07:41:56 +00:00
Petar Petrov ab39e70629 Recover brand icons after Home Assistant restart (#52158)
* Recover brand icons after Home Assistant restart

* Make _refreshBrandsAccessToken async
2026-05-25 09:36:50 +02:00
J. Nick Koston 69f209e3c3 Teach Bluetooth UI about auto scanning mode (#52192)
* Teach Bluetooth UI about auto scanning mode

* Drop unreachable auto cases and add isScannerStateMismatch tests
2026-05-25 09:30:03 +02:00
J. Nick Koston f4c5561a54 Show raw advertisement bytes in Bluetooth device info (#52193)
* Show raw advertisement bytes in Bluetooth device info

* Use plain div for raw hex to avoid fragile pre whitespace
2026-05-25 09:24:46 +02:00
renovate[bot] 5147937a6f Update dependency generate-license-file to v4.2.1 (#52195)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-25 09:24:42 +02:00
renovate[bot] ee39605aa7 Update dependency intl-messageformat to v11.2.7 (#52197)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-25 09:24:38 +02:00
renovate[bot] 4af4f1dc51 Update dependency idb-keyval to v6.2.4 (#52190)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-24 14:01:55 +00:00
renovate[bot] a2d8859d94 Update dependency @date-fns/tz to v1.5.0 (#52187)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-24 14:03:30 +03:00
renovate[bot] afea8180c4 Update dependency idb-keyval to v6.2.3 (#52186)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-24 13:53:50 +03:00
dependabot[bot] b9c077489d Bump github/codeql-action from 4.35.4 to 4.35.5 (#52183)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.35.4 to 4.35.5.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/68bde559dea0fdcac2102bfdf6230c5f70eb485e...9e0d7b8d25671d64c341c19c0152d693099fb5ba)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.35.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-24 09:33:38 +03:00
karwosts 440bb32056 Remove unintended sort from select selector (#52179) 2026-05-23 21:14:24 +02:00
renovate[bot] 8f371621ad Update dependency @rspack/core to v2.0.4 (#52178)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-23 16:18:20 +03:00
renovate[bot] 61815b20e3 Update vitest monorepo to v4.1.7 (#52173)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-23 13:03:54 +02:00
ildar170975 1942fa3a77 hui-entity-editor: fix vertical spacings (#52170)
fix spacings
2026-05-23 10:04:46 +02:00
renovate[bot] 865e67a06f Update Yarn to v4.15.0 (#52169)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-23 10:03:23 +02:00
renovate[bot] 412dce4c1f Update dependency tinykeys to v4 (#52172)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-05-23 10:02:58 +02:00
21 changed files with 682 additions and 448 deletions
+3 -3
View File
@@ -41,14 +41,14 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4.35.4
uses: github/codeql-action/init@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5
with:
languages: ${{ matrix.language }}
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4.35.4
uses: github/codeql-action/autobuild@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5
# ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@@ -62,4 +62,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4.35.4
uses: github/codeql-action/analyze@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -13,4 +13,4 @@ nodeLinker: node-modules
npmMinimalAgeGate: 3d
yarnPath: .yarn/releases/yarn-4.14.1.cjs
yarnPath: .yarn/releases/yarn-4.15.0.cjs
+10 -10
View File
@@ -38,7 +38,7 @@
"@codemirror/search": "6.7.0",
"@codemirror/state": "6.6.0",
"@codemirror/view": "6.43.0",
"@date-fns/tz": "1.4.1",
"@date-fns/tz": "1.5.0",
"@egjs/hammerjs": "2.0.17",
"@formatjs/intl-datetimeformat": "7.4.6",
"@formatjs/intl-displaynames": "7.3.8",
@@ -90,15 +90,15 @@
"deep-clone-simple": "1.1.1",
"deep-freeze": "0.0.1",
"dialog-polyfill": "0.5.6",
"echarts": "6.1.0",
"echarts": "6.0.0",
"element-internals-polyfill": "3.0.2",
"fuse.js": "7.3.0",
"google-timezones-json": "1.2.0",
"gulp-zopfli-green": "7.0.0",
"hls.js": "1.6.16",
"home-assistant-js-websocket": "9.6.0",
"idb-keyval": "6.2.2",
"intl-messageformat": "11.2.6",
"idb-keyval": "6.2.4",
"intl-messageformat": "11.2.7",
"js-yaml": "4.1.1",
"leaflet": "1.9.4",
"leaflet-draw": "patch:leaflet-draw@npm%3A1.0.4#./.yarn/patches/leaflet-draw-npm-1.0.4-0ca0ebcf65.patch",
@@ -118,7 +118,7 @@
"sortablejs": "patch:sortablejs@npm%3A1.15.6#~/.yarn/patches/sortablejs-npm-1.15.6-3235a8f83b.patch",
"stacktrace-js": "2.0.2",
"superstruct": "2.0.2",
"tinykeys": "3.1.0",
"tinykeys": "4.0.0",
"weekstart": "2.0.0",
"workbox-cacheable-response": "7.4.1",
"workbox-core": "7.4.1",
@@ -141,7 +141,7 @@
"@octokit/plugin-retry": "8.1.0",
"@octokit/rest": "22.0.1",
"@rsdoctor/rspack-plugin": "1.5.11",
"@rspack/core": "2.0.3",
"@rspack/core": "2.0.4",
"@rspack/dev-server": "2.0.1",
"@types/babel__plugin-transform-runtime": "7.9.5",
"@types/chromecast-caf-receiver": "6.0.26",
@@ -160,7 +160,7 @@
"@types/sortablejs": "1.15.9",
"@types/tar": "7.0.87",
"@types/webspeechapi": "0.0.29",
"@vitest/coverage-v8": "4.1.6",
"@vitest/coverage-v8": "4.1.7",
"babel-loader": "10.1.1",
"babel-plugin-template-html-minifier": "4.1.0",
"browserslist-useragent-regexp": "4.1.4",
@@ -175,7 +175,7 @@
"eslint-plugin-wc": "3.1.0",
"fancy-log": "2.0.0",
"fs-extra": "11.3.5",
"generate-license-file": "4.1.1",
"generate-license-file": "4.2.1",
"glob": "13.0.6",
"globals": "17.6.0",
"gulp": "5.0.1",
@@ -203,7 +203,7 @@
"typescript": "6.0.3",
"typescript-eslint": "8.59.4",
"vite-tsconfig-paths": "6.1.1",
"vitest": "4.1.6",
"vitest": "4.1.7",
"webpack-stats-plugin": "1.1.3",
"webpackbar": "7.0.0",
"workbox-build": "patch:workbox-build@npm%3A7.4.1#~/.yarn/patches/workbox-build-npm-7.4.1-c84561662c.patch"
@@ -219,7 +219,7 @@
"@material/mwc-list@^0.27.0": "patch:@material/mwc-list@npm%3A0.27.0#~/.yarn/patches/@material-mwc-list-npm-0.27.0-5344fc9de4.patch",
"glob@^10.2.2": "^10.5.0"
},
"packageManager": "yarn@4.14.1",
"packageManager": "yarn@4.15.0",
"volta": {
"node": "24.16.0"
}
@@ -128,7 +128,9 @@ export class HaAutomationRow extends LitElement {
}
.row {
display: flex;
padding: 0 0 0 var(--ha-space-3);
padding-left: var(--ha-space-3);
padding-inline-start: var(--ha-space-3);
padding-inline-end: initial;
min-height: 48px;
align-items: flex-start;
cursor: pointer;
@@ -144,6 +146,8 @@ export class HaAutomationRow extends LitElement {
transition: transform 150ms cubic-bezier(0.4, 0, 0.2, 1);
color: var(--ha-color-on-neutral-quiet);
margin-left: calc(var(--ha-space-2) * -1);
margin-inline-start: calc(var(--ha-space-2) * -1);
margin-inline-end: initial;
}
:host([building-block]) .leading-icon-wrapper {
background-color: var(--ha-color-fill-neutral-loud-resting);
+3
View File
@@ -109,6 +109,8 @@ export class HaGenericPicker extends PickerMixin(LitElement) {
@property({ attribute: "custom-value-label" })
public customValueLabel?: string;
@property({ type: Boolean, attribute: "no-sort" }) public noSort = false;
@query(".container") private _containerElement?: HTMLDivElement;
@query("ha-picker-combo-box") private _comboBox?: HaPickerComboBox;
@@ -271,6 +273,7 @@ export class HaGenericPicker extends PickerMixin(LitElement) {
.selectedSection=${this.selectedSection}
.searchKeys=${this.searchKeys}
.customValueLabel=${this.customValueLabel}
.noSort=${this.noSort}
></ha-picker-combo-box>
`;
}
+3 -1
View File
@@ -167,6 +167,8 @@ export class HaPickerComboBox extends ScrollableFadeMixin(LitElement) {
@property({ type: Boolean, reflect: true }) public clearable = false;
@property({ type: Boolean, attribute: "no-sort" }) public noSort = false;
@query("lit-virtualizer") public virtualizerElement?: LitVirtualizer;
@query("ha-input-search") private _searchFieldElement?: HaInputSearch;
@@ -342,7 +344,7 @@ export class HaPickerComboBox extends ScrollableFadeMixin(LitElement) {
private _getItems = () => {
let items = [...(this.getItems(this._search, this._selectedSection) || [])];
if (!this.sections?.length) {
if (!this.sections?.length && !this.noSort) {
items = items.sort((entityA, entityB) => {
const sortLabelA =
typeof entityA === "string" ? entityA : entityA.sorting_label;
@@ -199,6 +199,7 @@ export class HaSelectSelector extends LitElement {
: nothing}
<ha-generic-picker
no-sort
.hass=${this.hass}
.helper=${this.helper}
.disabled=${this.disabled}
@@ -215,6 +216,7 @@ export class HaSelectSelector extends LitElement {
if (this.selector.select?.custom_value) {
return html`
<ha-generic-picker
no-sort
.hass=${this.hass}
.label=${this.label}
.helper=${this.helper}
+11 -2
View File
@@ -17,6 +17,7 @@ export interface BluetoothDeviceData extends DataTableRowData {
source: string;
time: number;
tx_power: number;
raw: string | null;
}
export interface BluetoothConnectionData extends DataTableRowData {
@@ -58,13 +59,21 @@ export interface BluetoothAllocationsData {
allocated: string[];
}
export type BluetoothScannerMode = "active" | "passive";
export type BluetoothScannerRequestedMode = BluetoothScannerMode | "auto";
export interface BluetoothScannerState {
source: string;
adapter: string;
current_mode: "active" | "passive" | null;
requested_mode: "active" | "passive" | null;
current_mode: BluetoothScannerMode | null;
requested_mode: BluetoothScannerRequestedMode | null;
}
export const isScannerStateMismatch = (state: BluetoothScannerState): boolean =>
state.requested_mode !== "auto" &&
state.current_mode !== state.requested_mode;
export const subscribeBluetoothScannersDetailsUpdates = (
conn: Connection,
store: Store<BluetoothScannersDetails>
@@ -343,9 +343,9 @@ export class HaVoiceAssistantSetupDialog extends LitElement {
this._step = this._previousSteps.pop()!;
}
private _goToNextStep(ev?: CustomEvent) {
private async _goToNextStep(ev?: CustomEvent) {
if (ev?.detail?.updateConfig) {
this._fetchAssistConfiguration();
await this._fetchAssistConfiguration();
}
if (ev?.detail?.nextStep) {
this._nextStep = ev.detail.nextStep;
@@ -19,6 +19,7 @@ import type {
HaScannerType,
} from "../../../../../data/bluetooth";
import {
isScannerStateMismatch,
subscribeBluetoothConnectionAllocations,
subscribeBluetoothScannerState,
subscribeBluetoothScannersDetails,
@@ -285,9 +286,7 @@ export class BluetoothAdapterInfoPage extends LitElement {
const scannerType: HaScannerType =
scannerDetails?.scanner_type ?? "unknown";
const isRemoteScanner = scannerType === "remote";
const hasMismatch =
scannerState &&
scannerState.current_mode !== scannerState.requested_mode;
const hasMismatch = scannerState && isScannerStateMismatch(scannerState);
const allocations = scannerDetails
? this._connectionAllocationData.find(
@@ -438,6 +437,13 @@ export class BluetoothAdapterInfoPage extends LitElement {
);
}
if (scannerState.requested_mode === "auto") {
return this.hass.localize(
"ui.panel.config.bluetooth.scanning_mode_auto_with_current",
{ current: this._formatMode(scannerState.current_mode) }
);
}
return this._formatModeLabel(scannerState.current_mode);
}
@@ -23,6 +23,7 @@ import type {
BluetoothScannerState,
} from "../../../../../data/bluetooth";
import {
isScannerStateMismatch,
subscribeBluetoothAdvertisements,
subscribeBluetoothConnectionAllocations,
subscribeBluetoothScannerState,
@@ -144,7 +145,7 @@ export class BluetoothConfigDashboard extends LitElement {
0
);
const hasMismatch = Object.values(this._scannerStates).some(
(s) => s.current_mode !== s.requested_mode
isScannerStateMismatch
);
const isOffline = adapterCount === 0;
const status = isOffline ? "offline" : hasMismatch ? "warning" : "online";
@@ -1,5 +1,5 @@
import type { TemplateResult } from "lit";
import { html, LitElement, nothing } from "lit";
import type { CSSResultGroup, TemplateResult } from "lit";
import { css, html, LitElement, nothing } from "lit";
import { customElement, property, state } from "lit/decorators";
import { fireEvent } from "../../../../../common/dom/fire_event";
import { copyToClipboard } from "../../../../../common/util/copy-clipboard";
@@ -121,6 +121,19 @@ class DialogBluetoothDeviceInfo extends LitElement {
)}
</tbody>
</table>
${this._params.entry.raw
? html`
<h4>
${this.hass.localize(
"ui.panel.config.bluetooth.raw_advertisement"
)}
</h4>
<div class="raw">
${this.showDataAsHex(this._params.entry.raw)}
</div>
`
: nothing}
<ha-dialog-footer slot="footer">
<ha-button
slot="secondaryAction"
@@ -133,6 +146,14 @@ class DialogBluetoothDeviceInfo extends LitElement {
</ha-dialog>
`;
}
static readonly styles: CSSResultGroup = css`
.raw {
word-break: break-all;
font-family: var(--ha-font-family-code);
font-size: var(--ha-font-size-s);
}
`;
}
declare global {
@@ -229,9 +229,6 @@ export class HuiEntityEditor extends LitElement {
}
static styles = css`
ha-entity-picker {
margin-top: 8px;
}
.entity {
display: flex;
align-items: center;
@@ -253,6 +250,11 @@ export class HuiEntityEditor extends LitElement {
ha-md-list {
gap: 8px;
padding-top: 0;
display: flex;
flex-direction: column;
}
ha-md-list:has(> *) {
margin-bottom: var(--ha-space-2);
}
ha-md-list-item {
border: 1px solid var(--divider-color);
@@ -2,6 +2,7 @@ import { consume } from "@lit/context";
import {
mdiChevronDown,
mdiChevronRight,
mdiChevronLeft,
mdiMagnify,
mdiTextureBox,
} from "@mdi/js";
@@ -16,6 +17,7 @@ import { computeEntityName } from "../../../../common/entity/compute_entity_name
import { computeStateName } from "../../../../common/entity/compute_state_name";
import { computeRTL } from "../../../../common/util/compute_rtl";
import { debounce } from "../../../../common/util/debounce";
import { mainWindow } from "../../../../common/dom/get_main_window";
import "../../../../components/entity/state-badge";
import "../../../../components/ha-combo-box-item";
import "../../../../components/ha-domain-icon";
@@ -294,7 +296,11 @@ export class HuiSuggestionEntityTree extends LitElement {
private _renderChevron(expanded: boolean): TemplateResult {
return html`<ha-svg-icon
class="chevron"
.path=${expanded ? mdiChevronDown : mdiChevronRight}
.path=${expanded
? mdiChevronDown
: mainWindow.document.dir === "rtl"
? mdiChevronLeft
: mdiChevronRight}
></ha-svg-icon>`;
}
+13 -4
View File
@@ -313,8 +313,7 @@ export const connectionMixin = <T extends Constructor<HassBaseEl>>(
});
clearInterval(this.__backendPingInterval);
// Fetch the brands access token on initial connect and schedule refresh
fetchAndScheduleBrandsAccessToken(this.hass!);
this._refreshBrandsAccessToken();
this.__backendPingInterval = setInterval(() => {
if (this.hass?.connected) {
@@ -340,8 +339,7 @@ export const connectionMixin = <T extends Constructor<HassBaseEl>>(
this._updateHass({ connected: true });
broadcastConnectionStatus("connected");
// Refresh the brands access token on reconnect and restart refresh schedule
fetchAndScheduleBrandsAccessToken(this.hass!);
this._refreshBrandsAccessToken();
// on reconnect always fetch config as we might miss an update while we were disconnected
// @ts-ignore
@@ -362,4 +360,15 @@ export const connectionMixin = <T extends Constructor<HassBaseEl>>(
clearInterval(this.__backendPingInterval);
clearBrandsTokenRefresh();
}
private async _refreshBrandsAccessToken() {
// The brands WS handler may not be registered yet after a server restart;
// fetchAndScheduleBrandsAccessToken retries internally. If the token
// changed, re-render so any brand <img> elements that rendered against a
// different (or missing) token recompute their src and re-fetch.
const changed = await fetchAndScheduleBrandsAccessToken(this.hass!);
if (changed) {
this._updateHass({});
}
}
};
+2
View File
@@ -7132,6 +7132,7 @@
"scanning_mode_passive": "passive",
"scanning_mode_active_label": "Active scanning",
"scanning_mode_passive_label": "Passive scanning",
"scanning_mode_auto_with_current": "Auto ({current})",
"scanning_mode_none_label": "No scanning",
"scanner_mode_mismatch": "{name} requested {requested} mode but is operating in {current} mode. The scanner is in a bad state and needs to be power cycled.",
"scanner_mode_mismatch_remote": "For proxies: reboot the device",
@@ -7149,6 +7150,7 @@
"manufacturer_data": "Manufacturer data",
"service_data": "Service data",
"service_uuids": "Service UUIDs",
"raw_advertisement": "Raw advertisement",
"copy_to_clipboard": "[%key:ui::panel::config::automation::editor::copy_to_clipboard%]",
"area": "Area",
"scanners": "Scanners",
+28 -7
View File
@@ -1,3 +1,4 @@
import { waitForMs } from "../common/util/wait";
import type { HomeAssistant } from "../types";
export interface BrandsOptions {
@@ -20,15 +21,35 @@ let _brandsRefreshInterval: ReturnType<typeof setInterval> | undefined;
// Re-fetch every 30 minutes to always have a valid token.
const TOKEN_REFRESH_MS = 30 * 60 * 1000;
export const fetchAndScheduleBrandsAccessToken = (
// Delays before each attempt. The first attempt fires immediately; subsequent
// ones back off to ride through the window after a Home Assistant restart
// where the WebSocket server accepts connections but the brands integration
// hasn't registered its WS handler yet. On older backends without the command,
// every attempt fails and we give up.
const FETCH_DELAYS_MS = [0, 500, 1000, 2000, 5000, 10000, 15000];
// Returns true if the cached token changed as a result of this call, so
// callers can decide whether they need to trigger a re-render.
export const fetchAndScheduleBrandsAccessToken = async (
hass: HomeAssistant
): Promise<void> =>
fetchBrandsAccessToken(hass).then(
() => scheduleBrandsTokenRefresh(hass),
() => {
// Ignore failures; older backends may not support this command
): Promise<boolean> => {
const previousToken = _brandsAccessToken;
/* eslint-disable no-await-in-loop -- retries are intentionally sequential */
for (const delay of FETCH_DELAYS_MS) {
if (delay) {
await waitForMs(delay);
}
);
try {
await fetchBrandsAccessToken(hass);
scheduleBrandsTokenRefresh(hass);
return _brandsAccessToken !== previousToken;
} catch {
// try next delay
}
}
/* eslint-enable no-await-in-loop */
return false;
};
export const fetchBrandsAccessToken = async (
hass: HomeAssistant
+65
View File
@@ -0,0 +1,65 @@
import { describe, expect, it } from "vitest";
import type { BluetoothScannerState } from "../../src/data/bluetooth";
import { isScannerStateMismatch } from "../../src/data/bluetooth";
const state = (
overrides: Partial<BluetoothScannerState>
): BluetoothScannerState => ({
source: "AA:BB:CC:DD:EE:FF",
adapter: "hci0",
current_mode: null,
requested_mode: null,
...overrides,
});
describe("isScannerStateMismatch", () => {
it("is never a mismatch when requested mode is auto", () => {
expect(
isScannerStateMismatch(
state({ requested_mode: "auto", current_mode: "passive" })
)
).toBe(false);
expect(
isScannerStateMismatch(
state({ requested_mode: "auto", current_mode: "active" })
)
).toBe(false);
expect(
isScannerStateMismatch(
state({ requested_mode: "auto", current_mode: null })
)
).toBe(false);
});
it("flags a mismatch when requested and current differ", () => {
expect(
isScannerStateMismatch(
state({ requested_mode: "active", current_mode: "passive" })
)
).toBe(true);
expect(
isScannerStateMismatch(
state({ requested_mode: "passive", current_mode: "active" })
)
).toBe(true);
expect(
isScannerStateMismatch(
state({ requested_mode: "active", current_mode: null })
)
).toBe(true);
});
it("is not a mismatch when requested and current agree", () => {
expect(
isScannerStateMismatch(
state({ requested_mode: "active", current_mode: "active" })
)
).toBe(false);
expect(
isScannerStateMismatch(
state({ requested_mode: "passive", current_mode: "passive" })
)
).toBe(false);
});
});
+81
View File
@@ -4,6 +4,7 @@ import {
addBrandsAuth,
brandsUrl,
clearBrandsTokenRefresh,
fetchAndScheduleBrandsAccessToken,
fetchBrandsAccessToken,
scheduleBrandsTokenRefresh,
} from "../../src/util/brands-url";
@@ -169,3 +170,83 @@ describe("scheduleBrandsTokenRefresh", () => {
assert.strictEqual(callCount, 1);
});
});
describe("fetchAndScheduleBrandsAccessToken", () => {
afterEach(() => {
clearBrandsTokenRefresh();
vi.restoreAllMocks();
vi.useRealTimers();
});
it("retries with backoff until the WS call succeeds, returns true when the token changed", async () => {
vi.useFakeTimers();
let callCount = 0;
const mockHass = {
callWS: async () => {
callCount++;
if (callCount < 3) {
throw new Error("unknown_command");
}
return { token: `retry-token-${callCount}` };
},
} as unknown as HomeAssistant;
const promise = fetchAndScheduleBrandsAccessToken(mockHass);
// First attempt fires immediately, fails
await vi.advanceTimersByTimeAsync(0);
assert.strictEqual(callCount, 1);
// 500ms backoff → second attempt fails
await vi.advanceTimersByTimeAsync(500);
assert.strictEqual(callCount, 2);
// 1000ms backoff → third attempt succeeds
await vi.advanceTimersByTimeAsync(1000);
const changed = await promise;
assert.strictEqual(changed, true);
assert.strictEqual(callCount, 3);
assert.strictEqual(
brandsUrl(
{ domain: "test", type: "icon" },
"http://homeassistant.local:8123"
),
"http://homeassistant.local:8123/api/brands/integration/test/icon.png?token=retry-token-3"
);
});
it("returns false when the backend returns the same token (no UI change needed)", async () => {
const mockHass = {
callWS: async () => ({ token: "stable-token" }),
} as unknown as HomeAssistant;
// Prime the cached token
await fetchBrandsAccessToken(mockHass);
// Same token returned → no change
const changed = await fetchAndScheduleBrandsAccessToken(mockHass);
assert.strictEqual(changed, false);
});
it("returns false after all retries fail (e.g. older backend)", async () => {
vi.useFakeTimers();
let callCount = 0;
const mockHass = {
callWS: async () => {
callCount++;
throw new Error("unknown_command");
},
} as unknown as HomeAssistant;
const promise = fetchAndScheduleBrandsAccessToken(mockHass);
// Exhaust all retry delays: 500 + 1000 + 2000 + 5000 + 10000 + 15000
await vi.advanceTimersByTimeAsync(33500);
const changed = await promise;
assert.strictEqual(changed, false);
// 1 immediate attempt + 6 retries = 7 attempts
assert.strictEqual(callCount, 7);
});
});
+159 -159
View File
@@ -2,7 +2,7 @@
# Manual changes might be lost - proceed with caution!
__metadata:
version: 9
version: 10
cacheKey: 10
"@apideck/better-ajv-errors@npm:^0.3.1":
@@ -1469,10 +1469,10 @@ __metadata:
languageName: node
linkType: hard
"@date-fns/tz@npm:1.4.1":
version: 1.4.1
resolution: "@date-fns/tz@npm:1.4.1"
checksum: 10/062097590005cce3da4c7d9880f9c77d386cff5b4dd58fa3dde3c346a8b2e4f4a8025a613306351a7cad8eb71178a0f67b4840d5884f73aa4c759085fac92063
"@date-fns/tz@npm:1.5.0":
version: 1.5.0
resolution: "@date-fns/tz@npm:1.5.0"
checksum: 10/a629879b1f307429e0a00a92dea71e19f63398ba304ee0f58f4d141d50c3058d678c4095b25962f7e5fda508c70502811dd565e58df99e5632dc16097da184a8
languageName: node
linkType: hard
@@ -1660,12 +1660,12 @@ __metadata:
languageName: node
linkType: hard
"@formatjs/icu-messageformat-parser@npm:3.5.9":
version: 3.5.9
resolution: "@formatjs/icu-messageformat-parser@npm:3.5.9"
"@formatjs/icu-messageformat-parser@npm:3.5.10":
version: 3.5.10
resolution: "@formatjs/icu-messageformat-parser@npm:3.5.10"
dependencies:
"@formatjs/icu-skeleton-parser": "npm:2.1.9"
checksum: 10/b2543274b8359873ea279139c9da3ab0f42421651b28855c63d2ca7768a747e662f30ff3d296a1807425d08f1b3ae84376372289749da2fb17ba342e9686673a
checksum: 10/44392248b9247cf83a21b43c749025bfbc23acd63782b9a1b7dc47bf5520b686f8a5dccfa56716bc81fe0680000029aba22f5eb5c821ec529646758bd2d6af79
languageName: node
linkType: hard
@@ -3676,51 +3676,51 @@ __metadata:
languageName: node
linkType: hard
"@rspack/binding-darwin-arm64@npm:2.0.3":
version: 2.0.3
resolution: "@rspack/binding-darwin-arm64@npm:2.0.3"
"@rspack/binding-darwin-arm64@npm:2.0.4":
version: 2.0.4
resolution: "@rspack/binding-darwin-arm64@npm:2.0.4"
conditions: os=darwin & cpu=arm64
languageName: node
linkType: hard
"@rspack/binding-darwin-x64@npm:2.0.3":
version: 2.0.3
resolution: "@rspack/binding-darwin-x64@npm:2.0.3"
"@rspack/binding-darwin-x64@npm:2.0.4":
version: 2.0.4
resolution: "@rspack/binding-darwin-x64@npm:2.0.4"
conditions: os=darwin & cpu=x64
languageName: node
linkType: hard
"@rspack/binding-linux-arm64-gnu@npm:2.0.3":
version: 2.0.3
resolution: "@rspack/binding-linux-arm64-gnu@npm:2.0.3"
"@rspack/binding-linux-arm64-gnu@npm:2.0.4":
version: 2.0.4
resolution: "@rspack/binding-linux-arm64-gnu@npm:2.0.4"
conditions: os=linux & cpu=arm64 & libc=glibc
languageName: node
linkType: hard
"@rspack/binding-linux-arm64-musl@npm:2.0.3":
version: 2.0.3
resolution: "@rspack/binding-linux-arm64-musl@npm:2.0.3"
"@rspack/binding-linux-arm64-musl@npm:2.0.4":
version: 2.0.4
resolution: "@rspack/binding-linux-arm64-musl@npm:2.0.4"
conditions: os=linux & cpu=arm64 & libc=musl
languageName: node
linkType: hard
"@rspack/binding-linux-x64-gnu@npm:2.0.3":
version: 2.0.3
resolution: "@rspack/binding-linux-x64-gnu@npm:2.0.3"
"@rspack/binding-linux-x64-gnu@npm:2.0.4":
version: 2.0.4
resolution: "@rspack/binding-linux-x64-gnu@npm:2.0.4"
conditions: os=linux & cpu=x64 & libc=glibc
languageName: node
linkType: hard
"@rspack/binding-linux-x64-musl@npm:2.0.3":
version: 2.0.3
resolution: "@rspack/binding-linux-x64-musl@npm:2.0.3"
"@rspack/binding-linux-x64-musl@npm:2.0.4":
version: 2.0.4
resolution: "@rspack/binding-linux-x64-musl@npm:2.0.4"
conditions: os=linux & cpu=x64 & libc=musl
languageName: node
linkType: hard
"@rspack/binding-wasm32-wasi@npm:2.0.3":
version: 2.0.3
resolution: "@rspack/binding-wasm32-wasi@npm:2.0.3"
"@rspack/binding-wasm32-wasi@npm:2.0.4":
version: 2.0.4
resolution: "@rspack/binding-wasm32-wasi@npm:2.0.4"
dependencies:
"@emnapi/core": "npm:1.10.0"
"@emnapi/runtime": "npm:1.10.0"
@@ -3729,41 +3729,41 @@ __metadata:
languageName: node
linkType: hard
"@rspack/binding-win32-arm64-msvc@npm:2.0.3":
version: 2.0.3
resolution: "@rspack/binding-win32-arm64-msvc@npm:2.0.3"
"@rspack/binding-win32-arm64-msvc@npm:2.0.4":
version: 2.0.4
resolution: "@rspack/binding-win32-arm64-msvc@npm:2.0.4"
conditions: os=win32 & cpu=arm64
languageName: node
linkType: hard
"@rspack/binding-win32-ia32-msvc@npm:2.0.3":
version: 2.0.3
resolution: "@rspack/binding-win32-ia32-msvc@npm:2.0.3"
"@rspack/binding-win32-ia32-msvc@npm:2.0.4":
version: 2.0.4
resolution: "@rspack/binding-win32-ia32-msvc@npm:2.0.4"
conditions: os=win32 & cpu=ia32
languageName: node
linkType: hard
"@rspack/binding-win32-x64-msvc@npm:2.0.3":
version: 2.0.3
resolution: "@rspack/binding-win32-x64-msvc@npm:2.0.3"
"@rspack/binding-win32-x64-msvc@npm:2.0.4":
version: 2.0.4
resolution: "@rspack/binding-win32-x64-msvc@npm:2.0.4"
conditions: os=win32 & cpu=x64
languageName: node
linkType: hard
"@rspack/binding@npm:2.0.3":
version: 2.0.3
resolution: "@rspack/binding@npm:2.0.3"
"@rspack/binding@npm:2.0.4":
version: 2.0.4
resolution: "@rspack/binding@npm:2.0.4"
dependencies:
"@rspack/binding-darwin-arm64": "npm:2.0.3"
"@rspack/binding-darwin-x64": "npm:2.0.3"
"@rspack/binding-linux-arm64-gnu": "npm:2.0.3"
"@rspack/binding-linux-arm64-musl": "npm:2.0.3"
"@rspack/binding-linux-x64-gnu": "npm:2.0.3"
"@rspack/binding-linux-x64-musl": "npm:2.0.3"
"@rspack/binding-wasm32-wasi": "npm:2.0.3"
"@rspack/binding-win32-arm64-msvc": "npm:2.0.3"
"@rspack/binding-win32-ia32-msvc": "npm:2.0.3"
"@rspack/binding-win32-x64-msvc": "npm:2.0.3"
"@rspack/binding-darwin-arm64": "npm:2.0.4"
"@rspack/binding-darwin-x64": "npm:2.0.4"
"@rspack/binding-linux-arm64-gnu": "npm:2.0.4"
"@rspack/binding-linux-arm64-musl": "npm:2.0.4"
"@rspack/binding-linux-x64-gnu": "npm:2.0.4"
"@rspack/binding-linux-x64-musl": "npm:2.0.4"
"@rspack/binding-wasm32-wasi": "npm:2.0.4"
"@rspack/binding-win32-arm64-msvc": "npm:2.0.4"
"@rspack/binding-win32-ia32-msvc": "npm:2.0.4"
"@rspack/binding-win32-x64-msvc": "npm:2.0.4"
dependenciesMeta:
"@rspack/binding-darwin-arm64":
optional: true
@@ -3785,15 +3785,15 @@ __metadata:
optional: true
"@rspack/binding-win32-x64-msvc":
optional: true
checksum: 10/21b7510a6945ebab50db8bd54ae5b1e19fb3caf51016c2c21238fe37beb30eacc569f84d17cca924955a9a3b7e6dbed2818b6246b00e7dffbd6d30b164c45874
checksum: 10/55832bec03a4c94d6c60a16ebb6484e9c32a6e88cf820874f9873293787d1cbb95ee4276acf5dbf5b6bf6e63d6c9f8e3023efd40f8c2526a52324927b41a9316
languageName: node
linkType: hard
"@rspack/core@npm:2.0.3":
version: 2.0.3
resolution: "@rspack/core@npm:2.0.3"
"@rspack/core@npm:2.0.4":
version: 2.0.4
resolution: "@rspack/core@npm:2.0.4"
dependencies:
"@rspack/binding": "npm:2.0.3"
"@rspack/binding": "npm:2.0.4"
peerDependencies:
"@module-federation/runtime-tools": ^0.24.1 || ^2.0.0
"@swc/helpers": ">=0.5.1"
@@ -3802,7 +3802,7 @@ __metadata:
optional: true
"@swc/helpers":
optional: true
checksum: 10/71da00e09299a65c7503f775380c66126dfcfbc9a03efb50fab10573db6009b90cccd824fdbbf39c1dc141cb61cd1b66e68b06cfba6abf913b1fba7c860bd02d
checksum: 10/49249480a403259e5ee862cbd4694920da1b6ca5aba82146b31e4868430954eccb8a81e93fa730514dd3a39b65aa3fd52dbf0583bce1213086e6aec1a23ff9d1
languageName: node
linkType: hard
@@ -5032,12 +5032,12 @@ __metadata:
languageName: node
linkType: hard
"@vitest/coverage-v8@npm:4.1.6":
version: 4.1.6
resolution: "@vitest/coverage-v8@npm:4.1.6"
"@vitest/coverage-v8@npm:4.1.7":
version: 4.1.7
resolution: "@vitest/coverage-v8@npm:4.1.7"
dependencies:
"@bcoe/v8-coverage": "npm:^1.0.2"
"@vitest/utils": "npm:4.1.6"
"@vitest/utils": "npm:4.1.7"
ast-v8-to-istanbul: "npm:^1.0.0"
istanbul-lib-coverage: "npm:^3.2.2"
istanbul-lib-report: "npm:^3.0.1"
@@ -5047,34 +5047,34 @@ __metadata:
std-env: "npm:^4.0.0-rc.1"
tinyrainbow: "npm:^3.1.0"
peerDependencies:
"@vitest/browser": 4.1.6
vitest: 4.1.6
"@vitest/browser": 4.1.7
vitest: 4.1.7
peerDependenciesMeta:
"@vitest/browser":
optional: true
checksum: 10/351ddb5ccebc57ba290b669676db1e24960e4becd9c776a49e2a1ddb02cc2c644870a88010ff044f557fd9082dbe291b8c5e868d562fac93bd02c40d4bedf6bd
checksum: 10/ebfe69453f635946449303356fd7b41d6db5ef2449c7e50fe4789930d4b386685c5d8e3587c0fb8ce4010463371dad195471dda2efad673ee26b58d6ff5b7fbe
languageName: node
linkType: hard
"@vitest/expect@npm:4.1.6":
version: 4.1.6
resolution: "@vitest/expect@npm:4.1.6"
"@vitest/expect@npm:4.1.7":
version: 4.1.7
resolution: "@vitest/expect@npm:4.1.7"
dependencies:
"@standard-schema/spec": "npm:^1.1.0"
"@types/chai": "npm:^5.2.2"
"@vitest/spy": "npm:4.1.6"
"@vitest/utils": "npm:4.1.6"
"@vitest/spy": "npm:4.1.7"
"@vitest/utils": "npm:4.1.7"
chai: "npm:^6.2.2"
tinyrainbow: "npm:^3.1.0"
checksum: 10/20de26292c543f7f5076b59fd50a5fa89217755402de89b62e5d8c104c90441413b87b5c1d310a682a310418c76c0d4bd309dd1faf13b1b2dec79dc3bb90fef0
checksum: 10/a609af6c0497cd510ce8aed099f18faf6d6642bc8eb3432b688f2b39d7354a04d1c4ee9dc28bcfb9d4be701ceac88384d586592a520a324b3773ea43e8a1e677
languageName: node
linkType: hard
"@vitest/mocker@npm:4.1.6":
version: 4.1.6
resolution: "@vitest/mocker@npm:4.1.6"
"@vitest/mocker@npm:4.1.7":
version: 4.1.7
resolution: "@vitest/mocker@npm:4.1.7"
dependencies:
"@vitest/spy": "npm:4.1.6"
"@vitest/spy": "npm:4.1.7"
estree-walker: "npm:^3.0.3"
magic-string: "npm:^0.30.21"
peerDependencies:
@@ -5085,56 +5085,56 @@ __metadata:
optional: true
vite:
optional: true
checksum: 10/d0669d0b1a8822ec3bc83b5261ead6b05a7e5d8c2077d1f8b9eb0c8507967e54347f16027894be28ca26cf8993e544b8269230a3b78c4eb50c8feb780cb4c688
checksum: 10/124d0ec9cc099fde1fca4b065b81a389e9ba2204ecba9729751a0a022d0ffaa34609d9dc60c1f8494ee972c2209035a4476ff1dddc1790e07d1ca28a1103b30d
languageName: node
linkType: hard
"@vitest/pretty-format@npm:4.1.6":
version: 4.1.6
resolution: "@vitest/pretty-format@npm:4.1.6"
"@vitest/pretty-format@npm:4.1.7":
version: 4.1.7
resolution: "@vitest/pretty-format@npm:4.1.7"
dependencies:
tinyrainbow: "npm:^3.1.0"
checksum: 10/28dc121181fdf619e4a9ea4a3279a63974e54567fc59f82462d3b11d4b72d893cd7966f8a7c1a9365c62eae6dee4c6fb08353074486f708aee50b80462d0bd37
checksum: 10/79c86c39173577250955744c3444d8c0c9304c95c7d351b91a916229252c3733a0e969741a8f3441a5c4777b5a4371707ecb747ea4bfd2c07e72ddf1ef621293
languageName: node
linkType: hard
"@vitest/runner@npm:4.1.6":
version: 4.1.6
resolution: "@vitest/runner@npm:4.1.6"
"@vitest/runner@npm:4.1.7":
version: 4.1.7
resolution: "@vitest/runner@npm:4.1.7"
dependencies:
"@vitest/utils": "npm:4.1.6"
"@vitest/utils": "npm:4.1.7"
pathe: "npm:^2.0.3"
checksum: 10/0e175bb61b10ca6cb79a0734a45b3d8b1570806078d53b4f2aa7dbfabd10307c9566460ee8f263a34ac909e8481da614551eee28eaff834fbecd86b4902b845b
checksum: 10/429f1e0cc93f66a681d8acc816e21ac41258b07550f9139d004aab103bb06be53e3d91fc66886cef1ba1460a120f5fe4b12d6fe32dafdb1b06740dd119d70f7e
languageName: node
linkType: hard
"@vitest/snapshot@npm:4.1.6":
version: 4.1.6
resolution: "@vitest/snapshot@npm:4.1.6"
"@vitest/snapshot@npm:4.1.7":
version: 4.1.7
resolution: "@vitest/snapshot@npm:4.1.7"
dependencies:
"@vitest/pretty-format": "npm:4.1.6"
"@vitest/utils": "npm:4.1.6"
"@vitest/pretty-format": "npm:4.1.7"
"@vitest/utils": "npm:4.1.7"
magic-string: "npm:^0.30.21"
pathe: "npm:^2.0.3"
checksum: 10/167b96971ae6e31a8a7c42063abf3d48590908bdea8ae24d9e5035cd08690e47e15a12ab96cc017e5ddd6324a994b8096c901c8e87ac6e5e617910a2814717fd
checksum: 10/ef7001add6724c025772891616338e6081ecdb11a92c084ca1d09c4662cf632e5877bec4cb38056aabc311f29fbe149c89fbf332975829087f3817554fe92cde
languageName: node
linkType: hard
"@vitest/spy@npm:4.1.6":
version: 4.1.6
resolution: "@vitest/spy@npm:4.1.6"
checksum: 10/6c1bddbf1eaae42af96d66e31f8c14837203707552f60e7a0f512dc2513d285e3de1fdcf057a79a5588fd20ee382ce5a53c1a69430b2a79eb623fd3517d54878
"@vitest/spy@npm:4.1.7":
version: 4.1.7
resolution: "@vitest/spy@npm:4.1.7"
checksum: 10/49a9959c615f45ec593379a6d1a238190d08524857a6c4819b724134ce8a1a96d94e20144723d245941ce1ada54d8b00552573810d629880ecb8c3ff03b6d1ad
languageName: node
linkType: hard
"@vitest/utils@npm:4.1.6":
version: 4.1.6
resolution: "@vitest/utils@npm:4.1.6"
"@vitest/utils@npm:4.1.7":
version: 4.1.7
resolution: "@vitest/utils@npm:4.1.7"
dependencies:
"@vitest/pretty-format": "npm:4.1.6"
"@vitest/pretty-format": "npm:4.1.7"
convert-source-map: "npm:^2.0.0"
tinyrainbow: "npm:^3.1.0"
checksum: 10/a81506e9f167389e771503ba5bee91a61cd4f09ac386867815b65c12c9c236051fab6450d686c69b41e3fd028461d0195ee4c4ae47fd22ead649716ddb7777b3
checksum: 10/9cc729618dade24de3ad6862c288c22e9daac3fda5cae0abc9b6ce87035cc8e7efa2b66c3c124ae08beef462b36761b062e792bbc619798b832a7ea9382ed12a
languageName: node
linkType: hard
@@ -6999,13 +6999,13 @@ __metadata:
languageName: node
linkType: hard
"echarts@npm:6.1.0":
version: 6.1.0
resolution: "echarts@npm:6.1.0"
"echarts@npm:6.0.0":
version: 6.0.0
resolution: "echarts@npm:6.0.0"
dependencies:
tslib: "npm:2.3.0"
zrender: "npm:6.1.0"
checksum: 10/ae294b6050a2d7eb377609ae392f76a2db9463b322d12a861c017f5bbab192d59c2b7d618fa2b683cadafd3f37616bb65c5de8ed220421c648bbdb7b4b4c32ea
zrender: "npm:6.0.0"
checksum: 10/8dbb160cf22e99a2bce04174db756b73e52ba5c00048901c5dbda0c10e6e7b514e5344daa49aa2cdd9c620c9dcc2f4eb15c0614bb2d8a97d9d33e17552ae3655
languageName: node
linkType: hard
@@ -8070,9 +8070,9 @@ __metadata:
languageName: node
linkType: hard
"generate-license-file@npm:4.1.1":
version: 4.1.1
resolution: "generate-license-file@npm:4.1.1"
"generate-license-file@npm:4.2.1":
version: 4.2.1
resolution: "generate-license-file@npm:4.2.1"
dependencies:
"@commander-js/extra-typings": "npm:^14.0.0"
"@npmcli/arborist": "npm:^9.0.0"
@@ -8080,14 +8080,14 @@ __metadata:
commander: "npm:^14.0.2"
cosmiconfig: "npm:^9.0.0"
enquirer: "npm:^2.3.6"
glob: "npm:^11.0.0"
glob: "npm:^13.0.0"
json5: "npm:^2.2.3"
ora: "npm:^5.4.1"
tslib: "npm:^2.3.0"
zod: "npm:^3.21.4"
zod: "npm:^4.0.0"
bin:
generate-license-file: bin/generate-license-file
checksum: 10/8a9ed962a5cc8f4851d79df7cd8babbc7dec8fbcc2fe25b6a85babfb497572d933ef5189d6bffc204e31e74aa131760ca0b8a90039997cb9a11df7e948b3edf8
checksum: 10/03876abeba28efea39a0fbd4d048e2c0fe1f59477c14e3a5e9f7022235f9197a3f451b7f26124dc09da5cc63140376f53b4ee9167f238eee58241ab954e62efd
languageName: node
linkType: hard
@@ -8272,7 +8272,7 @@ __metadata:
languageName: node
linkType: hard
"glob@npm:^11.0.0, glob@npm:^11.0.1":
"glob@npm:^11.0.1":
version: 11.1.0
resolution: "glob@npm:11.1.0"
dependencies:
@@ -8568,7 +8568,7 @@ __metadata:
"@codemirror/search": "npm:6.7.0"
"@codemirror/state": "npm:6.6.0"
"@codemirror/view": "npm:6.43.0"
"@date-fns/tz": "npm:1.4.1"
"@date-fns/tz": "npm:1.5.0"
"@egjs/hammerjs": "npm:2.0.17"
"@eslint/js": "npm:10.0.1"
"@formatjs/intl-datetimeformat": "npm:7.4.6"
@@ -8609,7 +8609,7 @@ __metadata:
"@octokit/rest": "npm:22.0.1"
"@replit/codemirror-indentation-markers": "npm:6.5.3"
"@rsdoctor/rspack-plugin": "npm:1.5.11"
"@rspack/core": "npm:2.0.3"
"@rspack/core": "npm:2.0.4"
"@rspack/dev-server": "npm:2.0.1"
"@swc/helpers": "npm:0.5.21"
"@thomasloven/round-slider": "npm:0.6.0"
@@ -8633,7 +8633,7 @@ __metadata:
"@types/tar": "npm:7.0.87"
"@types/webspeechapi": "npm:0.0.29"
"@vibrant/color": "npm:4.0.4"
"@vitest/coverage-v8": "npm:4.1.6"
"@vitest/coverage-v8": "npm:4.1.7"
"@webcomponents/scoped-custom-element-registry": "npm:0.0.10"
"@webcomponents/webcomponentsjs": "npm:2.8.0"
babel-loader: "npm:10.1.1"
@@ -8651,7 +8651,7 @@ __metadata:
deep-freeze: "npm:0.0.1"
del: "npm:8.0.1"
dialog-polyfill: "npm:0.5.6"
echarts: "npm:6.1.0"
echarts: "npm:6.0.0"
element-internals-polyfill: "npm:3.0.2"
eslint: "npm:10.4.0"
eslint-config-prettier: "npm:10.1.8"
@@ -8664,7 +8664,7 @@ __metadata:
fancy-log: "npm:2.0.0"
fs-extra: "npm:11.3.5"
fuse.js: "npm:7.3.0"
generate-license-file: "npm:4.1.1"
generate-license-file: "npm:4.2.1"
glob: "npm:13.0.6"
globals: "npm:17.6.0"
google-timezones-json: "npm:1.2.0"
@@ -8677,8 +8677,8 @@ __metadata:
home-assistant-js-websocket: "npm:9.6.0"
html-minifier-terser: "npm:7.2.0"
husky: "npm:9.1.7"
idb-keyval: "npm:6.2.2"
intl-messageformat: "npm:11.2.6"
idb-keyval: "npm:6.2.4"
intl-messageformat: "npm:11.2.7"
js-yaml: "npm:4.1.1"
jsdom: "npm:29.1.1"
jszip: "npm:3.10.1"
@@ -8713,12 +8713,12 @@ __metadata:
superstruct: "npm:2.0.2"
tar: "npm:7.5.15"
terser-webpack-plugin: "npm:5.6.0"
tinykeys: "npm:3.1.0"
tinykeys: "npm:4.0.0"
ts-lit-plugin: "npm:2.0.2"
typescript: "npm:6.0.3"
typescript-eslint: "npm:8.59.4"
vite-tsconfig-paths: "npm:6.1.1"
vitest: "npm:4.1.6"
vitest: "npm:4.1.7"
webpack-stats-plugin: "npm:1.1.3"
webpackbar: "npm:7.0.0"
weekstart: "npm:2.0.0"
@@ -8900,10 +8900,10 @@ __metadata:
languageName: node
linkType: hard
"idb-keyval@npm:6.2.2":
version: 6.2.2
resolution: "idb-keyval@npm:6.2.2"
checksum: 10/8c22342d94deba01066460fe6593f29c78027d0935a6ed7a1da68b28a7a68b89d0830dada4b30d51b779ed1dc1e362007a8939cda651b9ad0807176bd841e8cb
"idb-keyval@npm:6.2.4":
version: 6.2.4
resolution: "idb-keyval@npm:6.2.4"
checksum: 10/b1bc874eb582c6bed89dd40a07fe5ca593238b37cded9c604e0cb74b396d2b8caa850519af4467e5ca1b4628682a6102150299db69a393702d0a0718945bc5ec
languageName: node
linkType: hard
@@ -9023,13 +9023,13 @@ __metadata:
languageName: node
linkType: hard
"intl-messageformat@npm:11.2.6":
version: 11.2.6
resolution: "intl-messageformat@npm:11.2.6"
"intl-messageformat@npm:11.2.7":
version: 11.2.7
resolution: "intl-messageformat@npm:11.2.7"
dependencies:
"@formatjs/fast-memoize": "npm:3.1.5"
"@formatjs/icu-messageformat-parser": "npm:3.5.9"
checksum: 10/a93a33c607be110715d76f532f74c0f34f1a4e39e28822333d8dd801d0e5e3f4f9a82e2d88895c179b7583d4a9135b1e6bb4044a8ce84c17fd67f2d78cfd84e1
"@formatjs/icu-messageformat-parser": "npm:3.5.10"
checksum: 10/ccd566358c90c7d33fbc71206d46501c18e66dac10cfdab1ea226bc16c3b31d25d987619ef355ca24c5b9f415075d2abe5cf383c69dbbe758bd78e7f72017ab9
languageName: node
linkType: hard
@@ -13434,10 +13434,10 @@ __metadata:
languageName: node
linkType: hard
"tinykeys@npm:3.1.0":
version: 3.1.0
resolution: "tinykeys@npm:3.1.0"
checksum: 10/472c1350b71ff4043acbe158b72431aaf4cecf879a85b4372fdd36871cfd3eb9dbc1e4a7976380a3239066551c027f13d6c6ac5b620f183d61a53707bae9be4c
"tinykeys@npm:4.0.0":
version: 4.0.0
resolution: "tinykeys@npm:4.0.0"
checksum: 10/e31dd0345098bffc87c4df2469f9dcc9cf9a519c592f0d774592f1eeee46798adc66e40058dcaad0c2697eec0f3212c09876c480f3b0ae32e938cb080e664651
languageName: node
linkType: hard
@@ -14191,17 +14191,17 @@ __metadata:
languageName: node
linkType: hard
"vitest@npm:4.1.6":
version: 4.1.6
resolution: "vitest@npm:4.1.6"
"vitest@npm:4.1.7":
version: 4.1.7
resolution: "vitest@npm:4.1.7"
dependencies:
"@vitest/expect": "npm:4.1.6"
"@vitest/mocker": "npm:4.1.6"
"@vitest/pretty-format": "npm:4.1.6"
"@vitest/runner": "npm:4.1.6"
"@vitest/snapshot": "npm:4.1.6"
"@vitest/spy": "npm:4.1.6"
"@vitest/utils": "npm:4.1.6"
"@vitest/expect": "npm:4.1.7"
"@vitest/mocker": "npm:4.1.7"
"@vitest/pretty-format": "npm:4.1.7"
"@vitest/runner": "npm:4.1.7"
"@vitest/snapshot": "npm:4.1.7"
"@vitest/spy": "npm:4.1.7"
"@vitest/utils": "npm:4.1.7"
es-module-lexer: "npm:^2.0.0"
expect-type: "npm:^1.3.0"
magic-string: "npm:^0.30.21"
@@ -14219,12 +14219,12 @@ __metadata:
"@edge-runtime/vm": "*"
"@opentelemetry/api": ^1.9.0
"@types/node": ^20.0.0 || ^22.0.0 || >=24.0.0
"@vitest/browser-playwright": 4.1.6
"@vitest/browser-preview": 4.1.6
"@vitest/browser-webdriverio": 4.1.6
"@vitest/coverage-istanbul": 4.1.6
"@vitest/coverage-v8": 4.1.6
"@vitest/ui": 4.1.6
"@vitest/browser-playwright": 4.1.7
"@vitest/browser-preview": 4.1.7
"@vitest/browser-webdriverio": 4.1.7
"@vitest/coverage-istanbul": 4.1.7
"@vitest/coverage-v8": 4.1.7
"@vitest/ui": 4.1.7
happy-dom: "*"
jsdom: "*"
vite: ^6.0.0 || ^7.0.0 || ^8.0.0
@@ -14255,7 +14255,7 @@ __metadata:
optional: false
bin:
vitest: vitest.mjs
checksum: 10/3816121537930455e5338b5b3305179fa6c68d6cbba50e5d8ca8dcb2c0410887ed38aca61e0d2da9f673af1cc1f20278eef941fc4756644e6f8f96366822b8e6
checksum: 10/23ce0ce8bf81856c1acf983c6138efda5d01b60cbdc5734abd0948f3b39cde14ea7bf0981a2ec8a6b05fe7f3658b211116997fd658fcd20c2f5740b5465502ca
languageName: node
linkType: hard
@@ -15099,19 +15099,19 @@ __metadata:
languageName: node
linkType: hard
"zod@npm:^3.21.4":
version: 3.25.76
resolution: "zod@npm:3.25.76"
checksum: 10/f0c963ec40cd96858451d1690404d603d36507c1fc9682f2dae59ab38b578687d542708a7fdbf645f77926f78c9ed558f57c3d3aa226c285f798df0c4da16995
"zod@npm:^4.0.0":
version: 4.4.3
resolution: "zod@npm:4.4.3"
checksum: 10/804b9a42aa8f35f2b3c5a8dff906291cb749115f83ee2afe3576d70b5b5c53c965365c7f4967690647a9c54af9838ff232a85ff9577a0a36c44b68bc6cdefe36
languageName: node
linkType: hard
"zrender@npm:6.1.0":
version: 6.1.0
resolution: "zrender@npm:6.1.0"
"zrender@npm:6.0.0":
version: 6.0.0
resolution: "zrender@npm:6.0.0"
dependencies:
tslib: "npm:2.3.0"
checksum: 10/c6bc87252127ef430cbbd47aa8476b0f8ecec1abade26928c2a46b2b01b0be93818b8741cfe0cfd7a48ffd82816dd9b5169801d6e6f98d1d5f0e08ce9e67d875
checksum: 10/d7b6572ebe400d40d9dc6e066a3a5841d4da1fdea3a9c1fd605239e116ffe05553002a351cbb236bcfbf516a41d3bd67f85ef39a43ccc7ffdc5b70a0ceec6aa8
languageName: node
linkType: hard