@glasshome/sync-layer 0.7.2 → 0.8.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.
Files changed (58) hide show
  1. package/dist/index.d.ts +1291 -54
  2. package/dist/index.js +203 -304
  3. package/dist/service-C8H42I-Q.d.ts +459 -0
  4. package/dist/solid/index.d.ts +119 -6
  5. package/dist/solid/index.js +20 -15
  6. package/dist/{statistics-CtRfIF6D.js → statistics-DyCCTwv2.js} +83 -95
  7. package/dist/worker/worker-main.d.ts +11 -8
  8. package/dist/worker/worker-main.js +2 -3
  9. package/dist/{worker-main-C-3QM4di.js → worker-main-D_wyGAIG.js} +47 -157
  10. package/package.json +3 -3
  11. package/dist/calendar/track.d.ts +0 -19
  12. package/dist/calendar/types.d.ts +0 -32
  13. package/dist/camera/fetch.d.ts +0 -16
  14. package/dist/camera/query.d.ts +0 -15
  15. package/dist/camera/types.d.ts +0 -85
  16. package/dist/camera/webrtc.d.ts +0 -31
  17. package/dist/commands/service.d.ts +0 -53
  18. package/dist/commands/types.d.ts +0 -113
  19. package/dist/connection/adapter.d.ts +0 -48
  20. package/dist/connection/auth.d.ts +0 -126
  21. package/dist/connection/bridged.d.ts +0 -16
  22. package/dist/connection/manager.d.ts +0 -51
  23. package/dist/connection/subscription-manager.d.ts +0 -48
  24. package/dist/connection/subscriptions.d.ts +0 -31
  25. package/dist/connection/types.d.ts +0 -151
  26. package/dist/core/privileged-conn.d.ts +0 -29
  27. package/dist/core/reducers.d.ts +0 -99
  28. package/dist/core/store.d.ts +0 -100
  29. package/dist/core/types.d.ts +0 -339
  30. package/dist/demo/demo-data.d.ts +0 -24
  31. package/dist/demo/demo-provider.d.ts +0 -40
  32. package/dist/demo/energy-sim.d.ts +0 -112
  33. package/dist/energy/prefs.d.ts +0 -56
  34. package/dist/entities/area-views.d.ts +0 -32
  35. package/dist/entities/index.d.ts +0 -54
  36. package/dist/entities/views.d.ts +0 -35
  37. package/dist/history/constants.d.ts +0 -16
  38. package/dist/history/fetch.d.ts +0 -19
  39. package/dist/history/query.d.ts +0 -27
  40. package/dist/history/statistics.d.ts +0 -55
  41. package/dist/history/types.d.ts +0 -146
  42. package/dist/host-api.d.ts +0 -50
  43. package/dist/media/url.d.ts +0 -14
  44. package/dist/query/area-builder.d.ts +0 -25
  45. package/dist/query/builder.d.ts +0 -18
  46. package/dist/query/helpers.d.ts +0 -21
  47. package/dist/query/memoization.d.ts +0 -18
  48. package/dist/query/projections.d.ts +0 -74
  49. package/dist/query/types.d.ts +0 -260
  50. package/dist/solid/hooks.d.ts +0 -119
  51. package/dist/solid/indices.d.ts +0 -15
  52. package/dist/weather/fetch.d.ts +0 -19
  53. package/dist/weather/query.d.ts +0 -23
  54. package/dist/weather/types.d.ts +0 -126
  55. package/dist/worker/bridge-client.d.ts +0 -47
  56. package/dist/worker/enforcement.d.ts +0 -53
  57. package/dist/worker/protocol.d.ts +0 -129
  58. package/dist/worker/token-store.d.ts +0 -3
@@ -1,5 +1,4 @@
1
1
  import { createStore, produce, reconcile } from "solid-js/store";
2
-
3
2
  //#region src/core/store.ts
4
3
  const initialState = {
5
4
  connectionState: "disconnected",
@@ -25,7 +24,6 @@ globalThis.__GH_SYNC_LAYER_STORE__ = true;
25
24
  const storeTuple = createStore(initialState);
26
25
  const state = storeTuple[0];
27
26
  const setState = storeTuple[1];
28
-
29
27
  //#endregion
30
28
  //#region src/core/privileged-conn.ts
31
29
  let privileged = null;
@@ -34,10 +32,9 @@ function privilegedConn() {
34
32
  return privileged;
35
33
  }
36
34
  /** Set by the connection layer on connect/disconnect. Host-side callers only. */
37
- function setPrivilegedConn(conn$1) {
38
- privileged = conn$1;
35
+ function setPrivilegedConn(conn) {
36
+ privileged = conn;
39
37
  }
40
-
41
38
  //#endregion
42
39
  //#region src/calendar/track.ts
43
40
  /**
@@ -53,7 +50,7 @@ const DEFAULT_DAYS_BEHIND = 7;
53
50
  const DEFAULT_DAYS_AHEAD = 35;
54
51
  /** Debounce for untrack, so dashboard switches don't churn subscriptions. */
55
52
  const UNTRACK_FLUSH_DELAY_MS = 5e3;
56
- const DAY_MS = 24 * 60 * 60 * 1e3;
53
+ const DAY_MS = 864e5;
57
54
  const trackers = /* @__PURE__ */ new Map();
58
55
  const active = /* @__PURE__ */ new Map();
59
56
  /** Per-entity reconcile chain; serializes subscribe/unsubscribe per calendar. */
@@ -72,7 +69,7 @@ function windowFor(list) {
72
69
  const dayStart = /* @__PURE__ */ new Date();
73
70
  dayStart.setHours(0, 0, 0, 0);
74
71
  return {
75
- start: new Date(dayStart.getTime() - behind * DAY_MS).toISOString(),
72
+ start: (/* @__PURE__ */ new Date(dayStart.getTime() - behind * DAY_MS)).toISOString(),
76
73
  end: new Date(dayStart.getTime() + (ahead + 1) * DAY_MS).toISOString()
77
74
  };
78
75
  }
@@ -132,7 +129,7 @@ function scheduleFlush$1() {
132
129
  });
133
130
  }
134
131
  async function flushAll() {
135
- const ids = new Set([...trackers.keys(), ...active.keys()]);
132
+ const ids = /* @__PURE__ */ new Set([...trackers.keys(), ...active.keys()]);
136
133
  await Promise.all([...ids].map(reconcileEntity));
137
134
  if (trackers.size === 0) stopRollTimer();
138
135
  }
@@ -157,8 +154,8 @@ async function runReconcile(entityId) {
157
154
  }));
158
155
  return;
159
156
  }
160
- const conn$1 = privilegedConn();
161
- if (!conn$1) return;
157
+ const conn = privilegedConn();
158
+ if (!conn) return;
162
159
  const win = windowFor(list);
163
160
  if (current?.unsub && current.start === win.start && current.end === win.end) return;
164
161
  setState(produce((s) => {
@@ -179,7 +176,7 @@ async function runReconcile(entityId) {
179
176
  };
180
177
  active.set(entityId, entry);
181
178
  try {
182
- entry.unsub = await conn$1.subscribeMessage((msg) => {
179
+ entry.unsub = await conn.subscribeMessage((msg) => {
183
180
  setState(produce((s) => {
184
181
  const rec = s.calendars[entityId];
185
182
  if (!rec) return;
@@ -211,13 +208,13 @@ windows shift, so a reconcile slides every subscription forward. Only
211
208
  armed while something is tracked — an idle app holds no timer. */
212
209
  function ensureRollTimer() {
213
210
  if (rollTimer || trackers.size === 0) return;
214
- const now$1 = /* @__PURE__ */ new Date();
215
- const next = new Date(now$1);
211
+ const now = /* @__PURE__ */ new Date();
212
+ const next = new Date(now);
216
213
  next.setHours(24, 0, 30, 0);
217
214
  rollTimer = setTimeout(() => {
218
215
  rollTimer = null;
219
216
  flushAll().then(ensureRollTimer);
220
- }, next.getTime() - now$1.getTime());
217
+ }, next.getTime() - now.getTime());
221
218
  }
222
219
  function stopRollTimer() {
223
220
  if (rollTimer) {
@@ -225,7 +222,6 @@ function stopRollTimer() {
225
222
  rollTimer = null;
226
223
  }
227
224
  }
228
-
229
225
  //#endregion
230
226
  //#region src/connection/subscription-manager.ts
231
227
  if (globalThis.__GH_SYNC_LAYER_SUB_MGR__) console.error("[@glasshome/sync-layer] DUPLICATE subscription-manager module instantiated. registerEntity() and the connection setter will hit different singletons → subscribe_entities will never be sent. Cause: relative import of subscription-manager from a separate entry point.");
@@ -322,7 +318,6 @@ function setsEqual(a, b) {
322
318
  for (const id of a) if (!b.has(id)) return false;
323
319
  return true;
324
320
  }
325
-
326
321
  //#endregion
327
322
  //#region src/core/types.ts
328
323
  /**
@@ -331,7 +326,6 @@ function setsEqual(a, b) {
331
326
  function extractDomain(entityId) {
332
327
  return entityId.split(".")[0] ?? "";
333
328
  }
334
-
335
329
  //#endregion
336
330
  //#region src/demo/energy-sim.ts
337
331
  const SOLAR_PEAK_W = 5200;
@@ -392,27 +386,24 @@ function cloudFactor(lt) {
392
386
  const phase2 = rand() * Math.PI * 2;
393
387
  const phase3 = rand() * Math.PI * 2;
394
388
  const m = lt.minuteOfDay;
395
- const wave = .16 * Math.sin(m / 37 * Math.PI * 2 + phase1) + .14 * Math.sin(m / 73 * Math.PI * 2 + phase2) + .05 * Math.sin(m / 11 * Math.PI * 2 + phase3);
396
- const f = .85 + wave;
389
+ const f = .85 + (.16 * Math.sin(m / 37 * Math.PI * 2 + phase1) + .14 * Math.sin(m / 73 * Math.PI * 2 + phase2) + .05 * Math.sin(m / 11 * Math.PI * 2 + phase3));
397
390
  return Math.max(.55, Math.min(1, f));
398
391
  }
399
392
  function solarPower(lt) {
400
393
  if (lt.hourFrac <= SUNRISE_HOUR || lt.hourFrac >= SUNSET_HOUR) return 0;
401
- const frac = (lt.hourFrac - SUNRISE_HOUR) / (SUNSET_HOUR - SUNRISE_HOUR);
394
+ const frac = (lt.hourFrac - SUNRISE_HOUR) / 14;
402
395
  const shape = Math.sin(frac * Math.PI) ** 1.3;
403
396
  return SOLAR_PEAK_W * shape * cloudFactor(lt);
404
397
  }
405
398
  /** Coarse solar elevation in degrees for sun.sun attributes. */
406
399
  function sunElevation(lt) {
407
400
  if (lt.hourFrac <= SUNRISE_HOUR || lt.hourFrac >= SUNSET_HOUR) return -12;
408
- const frac = (lt.hourFrac - SUNRISE_HOUR) / (SUNSET_HOUR - SUNRISE_HOUR);
401
+ const frac = (lt.hourFrac - SUNRISE_HOUR) / 14;
409
402
  return 60 * Math.sin(frac * Math.PI);
410
403
  }
411
404
  function fridgePower(lt) {
412
- const rand = mulberry32(hashInt(lt.dayKey * 40503 + 7));
413
- const phase = rand() * FRIDGE_CYCLE_MIN;
414
- const pos = (lt.minuteOfDay + phase) % FRIDGE_CYCLE_MIN;
415
- return pos < FRIDGE_ON_MIN ? FRIDGE_W : 0;
405
+ const phase = mulberry32(hashInt(lt.dayKey * 40503 + 7))() * FRIDGE_CYCLE_MIN;
406
+ return (lt.minuteOfDay + phase) % FRIDGE_CYCLE_MIN < FRIDGE_ON_MIN ? FRIDGE_W : 0;
416
407
  }
417
408
  /** A square wave: `power` while inside [start, start+durationMin). */
418
409
  function windowPower(minuteOfDay, startMin, durationMin, power) {
@@ -423,14 +414,12 @@ function kettlePower(lt) {
423
414
  }
424
415
  function ovenPower(lt) {
425
416
  const start = 1125;
426
- if (lt.minuteOfDay < start || lt.minuteOfDay >= start + 40) return 0;
427
- const into = lt.minuteOfDay - start;
428
- const cyclePos = into % 6.5;
429
- return cyclePos < 4 ? 2200 : 0;
417
+ if (lt.minuteOfDay < start || lt.minuteOfDay >= 1165) return 0;
418
+ return (lt.minuteOfDay - start) % 6.5 < 4 ? 2200 : 0;
430
419
  }
431
420
  function dishwasherPower(lt) {
432
421
  const start = 1270;
433
- if (lt.minuteOfDay < start || lt.minuteOfDay >= start + 65) return 0;
422
+ if (lt.minuteOfDay < start || lt.minuteOfDay >= 1335) return 0;
434
423
  const into = lt.minuteOfDay - start;
435
424
  if (into < 12) return 1900;
436
425
  if (into >= 57) return 1900;
@@ -443,9 +432,8 @@ function washerPower(lt) {
443
432
  6
444
433
  ].includes(lt.dayOfWeek)) return 0;
445
434
  const start = 630;
446
- if (lt.minuteOfDay < start || lt.minuteOfDay >= start + 50) return 0;
447
- const into = lt.minuteOfDay - start;
448
- return into < 14 ? 2100 : 250;
435
+ if (lt.minuteOfDay < start || lt.minuteOfDay >= 680) return 0;
436
+ return lt.minuteOfDay - start < 14 ? 2100 : 250;
449
437
  }
450
438
  function evChargerPower(lt) {
451
439
  if (![
@@ -454,11 +442,9 @@ function evChargerPower(lt) {
454
442
  0
455
443
  ].includes(lt.dayOfWeek)) return 0;
456
444
  const start = 1100;
457
- const stop = 1300;
458
- if (lt.minuteOfDay < start || lt.minuteOfDay >= stop) return 0;
445
+ if (lt.minuteOfDay < start || lt.minuteOfDay >= 1300) return 0;
459
446
  const into = lt.minuteOfDay - start;
460
- const ramp = into < 2 ? into / 2 : 1;
461
- return 7200 * ramp;
447
+ return 7200 * (into < 2 ? into / 2 : 1);
462
448
  }
463
449
  const HEAT_PUMP_PEAK_W = 3200;
464
450
  /**
@@ -487,17 +473,14 @@ function occupancyEnvelope(lt) {
487
473
  }
488
474
  /** Low-amplitude smooth noise multiplier, ±4%, seeded per day. */
489
475
  function homeNoise(lt) {
490
- const rand = mulberry32(hashInt(lt.dayKey * 22699 + 13));
491
- const phase = rand() * Math.PI * 2;
476
+ const phase = mulberry32(hashInt(lt.dayKey * 22699 + 13))() * Math.PI * 2;
492
477
  return 1 + .04 * Math.sin(lt.minuteOfDay / 23 * Math.PI * 2 + phase);
493
478
  }
494
479
  const socCache = /* @__PURE__ */ new Map();
495
480
  /** Net surplus (solar - home) at a given local-time sample, in watts. */
496
481
  function netSurplusAt(timestampMs) {
497
482
  const lt = localTime(timestampMs);
498
- const solar = solarPower(lt);
499
- const home = homePower(lt);
500
- return solar - home;
483
+ return solarPower(lt) - homePower(lt);
501
484
  }
502
485
  /**
503
486
  * Battery SOC (%) at every {@link SOC_STEP_MIN}-minute step from local
@@ -507,28 +490,24 @@ function netSurplusAt(timestampMs) {
507
490
  function socPrefix(dayKey, midnightMs) {
508
491
  const cached = socCache.get(dayKey);
509
492
  if (cached) return cached;
510
- const steps = Math.ceil(24 * 60 / SOC_STEP_MIN);
511
- const arr = new Float64Array(steps + 1);
493
+ const steps = Math.ceil(1440 / SOC_STEP_MIN);
494
+ const arr = /* @__PURE__ */ new Float64Array(289);
512
495
  arr[0] = MIDNIGHT_SOC;
513
496
  const stepMs = SOC_STEP_MIN * 6e4;
514
497
  const stepHours = SOC_STEP_MIN / 60;
515
498
  for (let i = 0; i < steps; i++) {
516
499
  const soc = arr[i] ?? MIDNIGHT_SOC;
517
- const sampleMs = midnightMs + i * stepMs;
518
- const surplus = netSurplusAt(sampleMs);
500
+ const surplus = netSurplusAt(midnightMs + i * stepMs);
519
501
  let chargeW = 0;
520
502
  let dischargeW = 0;
521
503
  if (surplus > 0) {
522
- const headroomWh = (BATTERY_MAX_SOC - soc) / 100 * BATTERY_CAPACITY_WH;
523
- const headroomW = headroomWh / stepHours;
504
+ const headroomW = (BATTERY_MAX_SOC - soc) / 100 * BATTERY_CAPACITY_WH / stepHours;
524
505
  chargeW = Math.min(surplus, BATTERY_POWER_CAP_W, Math.max(0, headroomW));
525
506
  } else if (surplus < 0) {
526
- const availWh = (soc - BATTERY_MIN_SOC) / 100 * BATTERY_CAPACITY_WH;
527
- const availW = availWh / stepHours;
507
+ const availW = (soc - BATTERY_MIN_SOC) / 100 * BATTERY_CAPACITY_WH / stepHours;
528
508
  dischargeW = Math.min(-surplus, BATTERY_POWER_CAP_W, Math.max(0, availW));
529
509
  }
530
- const deltaWh = (chargeW - dischargeW) * stepHours;
531
- const nextSoc = soc + deltaWh / BATTERY_CAPACITY_WH * 100;
510
+ const nextSoc = soc + (chargeW - dischargeW) * stepHours / BATTERY_CAPACITY_WH * 100;
532
511
  arr[i + 1] = Math.max(BATTERY_MIN_SOC, Math.min(BATTERY_MAX_SOC, nextSoc));
533
512
  }
534
513
  socCache.set(dayKey, arr);
@@ -541,12 +520,10 @@ function batterySoc(lt, midnightMs) {
541
520
  const i = Math.floor(stepFloat);
542
521
  const frac = stepFloat - i;
543
522
  const a = prefix[i] ?? MIDNIGHT_SOC;
544
- const b = prefix[i + 1] ?? a;
545
- return a + (b - a) * frac;
523
+ return a + ((prefix[i + 1] ?? a) - a) * frac;
546
524
  }
547
525
  function homePower(lt) {
548
- const base = ALWAYS_ON_W + fridgePower(lt) + kettlePower(lt) + ovenPower(lt) + dishwasherPower(lt) + washerPower(lt) + evChargerPower(lt) + heatPumpPower(lt) + occupancyEnvelope(lt);
549
- return base * homeNoise(lt);
526
+ return (ALWAYS_ON_W + fridgePower(lt) + kettlePower(lt) + ovenPower(lt) + dishwasherPower(lt) + washerPower(lt) + evChargerPower(lt) + heatPumpPower(lt) + occupancyEnvelope(lt)) * homeNoise(lt);
550
527
  }
551
528
  /**
552
529
  * Compute every instantaneous energy value at a timestamp.
@@ -571,10 +548,8 @@ function simulateEnergy(timestampMs) {
571
548
  const surplus = solarW - homeW;
572
549
  let batteryChargeW = 0;
573
550
  let batteryDischargeW = 0;
574
- if (surplus > 0) {
575
- const headroom = soc < BATTERY_MAX_SOC ? BATTERY_POWER_CAP_W : 0;
576
- batteryChargeW = Math.min(surplus, headroom);
577
- } else if (surplus < 0) {
551
+ if (surplus > 0) batteryChargeW = Math.min(surplus, soc < BATTERY_MAX_SOC ? BATTERY_POWER_CAP_W : 0);
552
+ else if (surplus < 0) {
578
553
  const avail = soc > BATTERY_MIN_SOC ? BATTERY_POWER_CAP_W : 0;
579
554
  batteryDischargeW = Math.min(-surplus, avail);
580
555
  }
@@ -648,7 +623,7 @@ function energyEntityValue(entityId, sample) {
648
623
  case "sensor.oven_power": return sample.ovenW;
649
624
  case "sensor.ev_charger_power": return sample.evChargerW;
650
625
  case "sensor.always_on_power": return sample.alwaysOnW;
651
- default: return void 0;
626
+ default: return;
652
627
  }
653
628
  }
654
629
  /** Whether an entity id is one of the simulated energy sensors. */
@@ -705,7 +680,7 @@ function bucketMs(period) {
705
680
  */
706
681
  function synthesizeEnergyStatistics(entityId, startMs, endMs, period) {
707
682
  const span = bucketMs(period);
708
- const sampleMs = 5 * 6e4;
683
+ const sampleMs = 3e5;
709
684
  const buckets = [];
710
685
  let cumulativeWh = 0;
711
686
  for (let bStart = startMs; bStart < endMs; bStart += span) {
@@ -786,7 +761,6 @@ function demoEnergyPreferences() {
786
761
  ]
787
762
  };
788
763
  }
789
-
790
764
  //#endregion
791
765
  //#region src/demo/demo-data.ts
792
766
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -798,10 +772,10 @@ function ctx() {
798
772
  user_id: null
799
773
  };
800
774
  }
801
- function makeEntity(entity_id, state$1, attributes = {}) {
775
+ function makeEntity(entity_id, state, attributes = {}) {
802
776
  return {
803
777
  entity_id,
804
- state: state$1,
778
+ state,
805
779
  attributes: {
806
780
  friendly_name: friendlyName(entity_id),
807
781
  ...attributes
@@ -1008,8 +982,7 @@ function makeWeatherEntity(w) {
1008
982
  });
1009
983
  }
1010
984
  function friendlyName(entityId) {
1011
- const objectId = entityId.split(".")[1] ?? entityId;
1012
- return objectId.split("_").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
985
+ return (entityId.split(".")[1] ?? entityId).split("_").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
1013
986
  }
1014
987
  function makeRegistryEntry(entity_id, overrides = {}) {
1015
988
  const domain = entity_id.split(".")[0] ?? "";
@@ -1487,7 +1460,7 @@ function createDemoFixtures() {
1487
1460
  next_rising: sun.nextRising,
1488
1461
  next_setting: sun.nextSetting
1489
1462
  }), {});
1490
- const powerSensors = [
1463
+ for (const s of [
1491
1464
  {
1492
1465
  id: "sensor.solar_power",
1493
1466
  name: "Solar Production",
@@ -1566,8 +1539,7 @@ function createDemoFixtures() {
1566
1539
  deviceClass: "power",
1567
1540
  unit: "W"
1568
1541
  }
1569
- ];
1570
- for (const s of powerSensors) {
1542
+ ]) {
1571
1543
  const value = energyEntityValue(s.id, sample) ?? 0;
1572
1544
  add(makeEntity(s.id, formatEnergyState(s.id, value), {
1573
1545
  friendly_name: s.name,
@@ -1587,9 +1559,16 @@ function createDemoFixtures() {
1587
1559
  devices
1588
1560
  };
1589
1561
  }
1590
-
1591
1562
  //#endregion
1592
1563
  //#region src/demo/demo-provider.ts
1564
+ /**
1565
+ * Demo Mode Provider
1566
+ *
1567
+ * Loads demo fixtures into the SolidJS store and provides
1568
+ * optimistic local state updates for service calls (toggle, turnOn, turnOff).
1569
+ *
1570
+ * @packageDocumentation
1571
+ */
1593
1572
  let _isDemoMode = false;
1594
1573
  /**
1595
1574
  * Whether demo mode is currently active.
@@ -1685,21 +1664,21 @@ function applyDemoServiceCall(_domain, service, _serviceData = {}, target = {})
1685
1664
  if (!_isDemoMode) return;
1686
1665
  const entityIds = Array.isArray(target.entity_id) ? target.entity_id : target.entity_id ? [target.entity_id] : [];
1687
1666
  for (const entityId of entityIds) {
1688
- const entity = state.entities[entityId];
1689
- if (!entity) continue;
1667
+ if (!state.entities[entityId]) continue;
1690
1668
  const entityDomain = extractDomain(entityId);
1691
1669
  setState(produce((s) => {
1692
1670
  const e = s.entities[entityId];
1693
1671
  if (!e) return;
1694
- const now$1 = (/* @__PURE__ */ new Date()).toISOString();
1695
- e.last_changed = now$1;
1696
- e.last_updated = now$1;
1672
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1673
+ e.last_changed = now;
1674
+ e.last_updated = now;
1697
1675
  if (service === "turn_on") applyTurnOn(e, entityDomain, _serviceData);
1698
- else if (service === "press" && entityDomain === "button") e.state = now$1;
1676
+ else if (service === "press" && entityDomain === "button") e.state = now;
1699
1677
  else if (service === "turn_off") applyTurnOff(e, entityDomain);
1700
- else if (service === "toggle") if (e.state === "on" || e.state === "playing" || e.state === "open") applyTurnOff(e, entityDomain);
1701
- else applyTurnOn(e, entityDomain, _serviceData);
1702
- else if (service === "lock") e.state = "locked";
1678
+ else if (service === "toggle") {
1679
+ if (e.state === "on" || e.state === "playing" || e.state === "open") applyTurnOff(e, entityDomain);
1680
+ else applyTurnOn(e, entityDomain, _serviceData);
1681
+ } else if (service === "lock") e.state = "locked";
1703
1682
  else if (service === "unlock") e.state = "unlocked";
1704
1683
  else if (service === "open_cover") {
1705
1684
  e.state = "open";
@@ -1783,7 +1762,6 @@ function applyTurnOff(e, domain) {
1783
1762
  if ("current_position" in e.attributes) e.attributes.current_position = 0;
1784
1763
  } else e.state = "off";
1785
1764
  }
1786
-
1787
1765
  //#endregion
1788
1766
  //#region src/commands/service.ts
1789
1767
  /**
@@ -1882,7 +1860,6 @@ async function batchServiceCalls(calls) {
1882
1860
  async function batchEntityUpdates(updates) {
1883
1861
  return Promise.all(updates.map((u) => updateEntity(u.entityId, u.updates)));
1884
1862
  }
1885
-
1886
1863
  //#endregion
1887
1864
  //#region src/entities/views.ts
1888
1865
  /**
@@ -1905,10 +1882,10 @@ function resolveIcon(entity, registry) {
1905
1882
  function buildEntityView(entity, registry) {
1906
1883
  const domain = extractDomain(entity.entity_id);
1907
1884
  const attributes = entity.attributes ?? {};
1908
- const friendlyName$1 = attributes.friendly_name ?? registry?.name ?? entity.entity_id;
1909
- const name = registry?.name ?? friendlyName$1;
1885
+ const friendlyName = attributes.friendly_name ?? registry?.name ?? entity.entity_id;
1886
+ const name = registry?.name ?? friendlyName;
1910
1887
  const iconResolution = resolveIcon(entity, registry);
1911
- const { device_class: _dc, unit_of_measurement: _uom, friendly_name: _fn, icon: _icon,...restAttributes } = attributes;
1888
+ const { device_class: _dc, unit_of_measurement: _uom, friendly_name: _fn, icon: _icon, ...restAttributes } = attributes;
1912
1889
  let areaId = registry?.area_id ?? null;
1913
1890
  if (areaId === null && registry?.device_id) {
1914
1891
  const device = state.devices[registry.device_id];
@@ -1927,7 +1904,7 @@ function buildEntityView(entity, registry) {
1927
1904
  userId: entity.context?.user_id ?? null
1928
1905
  },
1929
1906
  name,
1930
- friendlyName: friendlyName$1,
1907
+ friendlyName,
1931
1908
  areaId,
1932
1909
  deviceId: registry?.device_id ?? null,
1933
1910
  platform: registry?.platform ?? "unknown",
@@ -1949,7 +1926,7 @@ function buildEntityView(entity, registry) {
1949
1926
  */
1950
1927
  function getEntityView(entityId) {
1951
1928
  const entity = state.entities[entityId];
1952
- if (!entity) return void 0;
1929
+ if (!entity) return;
1953
1930
  const registry = state.entityRegistry[entityId];
1954
1931
  return buildEntityView(entity, registry);
1955
1932
  }
@@ -1979,9 +1956,22 @@ function entityViewEquals(a, b) {
1979
1956
  if (!a || !b) return false;
1980
1957
  return a.id === b.id && a.state === b.state && a.lastChanged.getTime() === b.lastChanged.getTime() && a.name === b.name && a.friendlyName === b.friendlyName && a.areaId === b.areaId && a.deviceId === b.deviceId && a.icon === b.icon && a.isDisabled === b.isDisabled && a.isHidden === b.isHidden && a.attributes === b.attributes;
1981
1958
  }
1982
-
1983
1959
  //#endregion
1984
1960
  //#region src/entities/area-views.ts
1961
+ /**
1962
+ * Area View Builder
1963
+ *
1964
+ * Constructs unified AreaView objects by combining registry data with computed
1965
+ * entities and devices.
1966
+ *
1967
+ * Membership (which entities/devices belong to an area) is registry-driven and
1968
+ * cheap; live entity *views* read entity state and are therefore exposed as a
1969
+ * lazy `entities` getter. Callers that only need names, ids, or counts never
1970
+ * touch entity state, so building the whole-area list does not recompute on
1971
+ * every entity state tick.
1972
+ *
1973
+ * @packageDocumentation
1974
+ */
1985
1975
  /** The area an entity belongs to: its own `area_id` wins; otherwise it inherits
1986
1976
  * the area of its device. Null when neither resolves. */
1987
1977
  function entityAreaId(entry) {
@@ -2096,10 +2086,9 @@ function getAreaView(areaId) {
2096
2086
  try {
2097
2087
  return buildAreaView(areaId);
2098
2088
  } catch {
2099
- return void 0;
2089
+ return;
2100
2090
  }
2101
2091
  }
2102
-
2103
2092
  //#endregion
2104
2093
  //#region src/history/statistics.ts
2105
2094
  const STATISTIC_TYPES = [
@@ -2150,11 +2139,11 @@ function normalizeStatisticValue(raw) {
2150
2139
  async function fetchStatisticsDuringPeriod(connection, statisticIds, options) {
2151
2140
  const { startTime, endTime, period } = options;
2152
2141
  if (isDemoMode()) {
2153
- const result$1 = {};
2142
+ const result = {};
2154
2143
  const statPeriod = period === "hour" || period === "day" ? period : "day";
2155
2144
  const endMs = (endTime ?? /* @__PURE__ */ new Date()).getTime();
2156
- for (const id of statisticIds) result$1[id] = isEnergyEntity(id) ? synthesizeEnergyStatistics(id, startTime.getTime(), endMs, statPeriod) : [];
2157
- return result$1;
2145
+ for (const id of statisticIds) result[id] = isEnergyEntity(id) ? synthesizeEnergyStatistics(id, startTime.getTime(), endMs, statPeriod) : [];
2146
+ return result;
2158
2147
  }
2159
2148
  const params = {
2160
2149
  type: "recorder/statistics_during_period",
@@ -2170,6 +2159,5 @@ async function fetchStatisticsDuringPeriod(connection, statisticIds, options) {
2170
2159
  if (response && typeof response === "object") for (const [id, buckets] of Object.entries(response)) result[id] = Array.isArray(buckets) ? buckets.map(normalizeStatisticValue) : [];
2171
2160
  return result;
2172
2161
  }
2173
-
2174
2162
  //#endregion
2175
- export { applyDemoServiceCall, batchEntityUpdates, batchServiceCalls, buildAreaView, buildDeviceView, buildEntityView, callService, createDemoFixtures, demoEnergyPreferences, entityViewEquals, extractDomain, fetchStatisticsDuringPeriod, forceResubscribe, forceResubscribeCalendars, getAllEntityViews, getAreaView, getAreaViews, getEntityView, getEntityViews, isDemoMode, isEnergyEntity, loadDemoData, normalizeStatisticTime, privilegedConn, registerEntity, sendCommand, setManagerConnection, setPrivilegedConn, setResubscribeHandler, setState, startDemoEnergyTicker, state, stopDemoEnergyTicker, synthesizeEnergyHistory, toggle, trackCalendarEvents, turnOff, turnOn, unloadDemoData, updateEntity };
2163
+ export { extractDomain as A, state as B, startDemoEnergyTicker as C, demoEnergyPreferences as D, createDemoFixtures as E, forceResubscribeCalendars as F, trackCalendarEvents as I, privilegedConn as L, registerEntity as M, setManagerConnection as N, isEnergyEntity as O, setResubscribeHandler as P, setPrivilegedConn as R, loadDemoData as S, unloadDemoData as T, turnOff as _, getAreaView as a, applyDemoServiceCall as b, entityViewEquals as c, getEntityViews as d, batchEntityUpdates as f, toggle as g, sendCommand as h, buildDeviceView as i, forceResubscribe as j, synthesizeEnergyHistory as k, getAllEntityViews as l, callService as m, normalizeStatisticTime as n, getAreaViews as o, batchServiceCalls as p, buildAreaView as r, buildEntityView as s, fetchStatisticsDuringPeriod as t, getEntityView as u, turnOn as v, stopDemoEnergyTicker as w, isDemoMode as x, updateEntity as y, setState as z };
@@ -1,10 +1,13 @@
1
+ //#region src/worker/worker-main.d.ts
1
2
  /** Structural worker-global surface; the package compiles against DOM libs. */
2
- export interface WorkerScope {
3
- postMessage(message: unknown): void;
4
- onmessage: ((ev: MessageEvent) => void) | null;
5
- location: {
6
- protocol: string;
7
- host: string;
8
- };
3
+ interface WorkerScope {
4
+ postMessage(message: unknown): void;
5
+ onmessage: ((ev: MessageEvent) => void) | null;
6
+ location: {
7
+ protocol: string;
8
+ host: string;
9
+ };
9
10
  }
10
- export declare function runHaBridgeWorker(scope: WorkerScope): void;
11
+ declare function runHaBridgeWorker(scope: WorkerScope): void;
12
+ //#endregion
13
+ export { WorkerScope, runHaBridgeWorker };
@@ -1,3 +1,2 @@
1
- import { runHaBridgeWorker } from "../worker-main-C-3QM4di.js";
2
-
3
- export { runHaBridgeWorker };
1
+ import { t as runHaBridgeWorker } from "../worker-main-D_wyGAIG.js";
2
+ export { runHaBridgeWorker };