@digital-alchemy/hass 24.11.4 → 25.2.1

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 (57) hide show
  1. package/dist/dynamic.d.mts +45 -44
  2. package/dist/dynamic.mjs +0 -1
  3. package/dist/dynamic.mjs.map +1 -1
  4. package/dist/helpers/utility.d.mts +1 -2
  5. package/dist/helpers/utility.mjs +1 -2
  6. package/dist/helpers/utility.mjs.map +1 -1
  7. package/dist/merge.d.mts +4 -0
  8. package/dist/merge.mjs +2 -0
  9. package/dist/merge.mjs.map +1 -0
  10. package/dist/mock_assistant/services/entity.service.mjs +2 -1
  11. package/dist/mock_assistant/services/entity.service.mjs.map +1 -1
  12. package/dist/mock_assistant/services/fixtures.service.mjs +2 -1
  13. package/dist/mock_assistant/services/fixtures.service.mjs.map +1 -1
  14. package/dist/services/backup.service.d.mts +1 -1
  15. package/dist/services/backup.service.mjs +2 -2
  16. package/dist/services/backup.service.mjs.map +1 -1
  17. package/dist/services/call-proxy.service.mjs +1 -1
  18. package/dist/services/call-proxy.service.mjs.map +1 -1
  19. package/dist/services/config.service.mjs +2 -1
  20. package/dist/services/config.service.mjs.map +1 -1
  21. package/dist/services/entity.service.mjs +2 -1
  22. package/dist/services/entity.service.mjs.map +1 -1
  23. package/dist/services/events.service.d.mts +1 -1
  24. package/dist/services/events.service.mjs +7 -8
  25. package/dist/services/events.service.mjs.map +1 -1
  26. package/dist/services/fetch-api.service.d.mts +1 -1
  27. package/dist/services/fetch-api.service.mjs +2 -2
  28. package/dist/services/fetch-api.service.mjs.map +1 -1
  29. package/dist/services/id-by.service.d.mts +1 -1
  30. package/dist/services/id-by.service.mjs +7 -8
  31. package/dist/services/id-by.service.mjs.map +1 -1
  32. package/dist/services/internal.service.d.mts +1 -1
  33. package/dist/services/internal.service.mjs +5 -3
  34. package/dist/services/internal.service.mjs.map +1 -1
  35. package/dist/services/reference.service.mjs +2 -1
  36. package/dist/services/reference.service.mjs.map +1 -1
  37. package/dist/services/websocket-api.service.mjs +15 -8
  38. package/dist/services/websocket-api.service.mjs.map +1 -1
  39. package/dist/testing/fetch-api.spec.mjs +1 -1
  40. package/dist/testing/fetch-api.spec.mjs.map +1 -1
  41. package/package.json +27 -27
  42. package/src/dynamic.mts +192 -149
  43. package/src/helpers/utility.mts +1 -2
  44. package/src/merge.mts +9 -0
  45. package/src/mock_assistant/services/entity.service.mts +2 -1
  46. package/src/mock_assistant/services/fixtures.service.mts +2 -1
  47. package/src/services/backup.service.mts +9 -2
  48. package/src/services/call-proxy.service.mts +2 -1
  49. package/src/services/config.service.mts +2 -9
  50. package/src/services/entity.service.mts +1 -1
  51. package/src/services/events.service.mts +8 -8
  52. package/src/services/fetch-api.service.mts +11 -2
  53. package/src/services/id-by.service.mts +14 -8
  54. package/src/services/internal.service.mts +6 -2
  55. package/src/services/reference.service.mts +2 -1
  56. package/src/services/websocket-api.service.mts +24 -9
  57. package/src/testing/fetch-api.spec.mts +1 -1
@@ -1,4 +1,4 @@
1
- import { is, TServiceParams } from "@digital-alchemy/core";
1
+ import { TServiceParams } from "@digital-alchemy/core";
2
2
 
3
3
  import {
4
4
  AREA_REGISTRY_UPDATED,
@@ -11,31 +11,31 @@ import {
11
11
  ZONE_REGISTRY_UPDATED,
12
12
  } from "../helpers/index.mts";
13
13
 
14
- export function EventsService({ event }: TServiceParams): HassEventsService {
14
+ export function EventsService({ event, internal }: TServiceParams): HassEventsService {
15
15
  return {
16
16
  onAreaRegistryUpdate: (callback: SimpleCallback) => {
17
17
  event.on(AREA_REGISTRY_UPDATED, callback);
18
- return is.removeFn(() => event.removeListener(AREA_REGISTRY_UPDATED, callback));
18
+ return internal.removeFn(() => event.removeListener(AREA_REGISTRY_UPDATED, callback));
19
19
  },
20
20
  onDeviceRegistryUpdate: (callback: SimpleCallback) => {
21
21
  event.on(DEVICE_REGISTRY_UPDATED, callback);
22
- return is.removeFn(() => event.removeListener(DEVICE_REGISTRY_UPDATED, callback));
22
+ return internal.removeFn(() => event.removeListener(DEVICE_REGISTRY_UPDATED, callback));
23
23
  },
24
24
  onEntityRegistryUpdate: (callback: SimpleCallback) => {
25
25
  event.on(ENTITY_REGISTRY_UPDATED, callback);
26
- return is.removeFn(() => event.removeListener(ENTITY_REGISTRY_UPDATED, callback));
26
+ return internal.removeFn(() => event.removeListener(ENTITY_REGISTRY_UPDATED, callback));
27
27
  },
28
28
  onFloorRegistryUpdate: (callback: SimpleCallback) => {
29
29
  event.on(FLOOR_REGISTRY_UPDATED, callback);
30
- return is.removeFn(() => event.removeListener(FLOOR_REGISTRY_UPDATED, callback));
30
+ return internal.removeFn(() => event.removeListener(FLOOR_REGISTRY_UPDATED, callback));
31
31
  },
32
32
  onLabelRegistryUpdate: (callback: SimpleCallback) => {
33
33
  event.on(LABEL_REGISTRY_UPDATED, callback);
34
- return is.removeFn(() => event.removeListener(LABEL_REGISTRY_UPDATED, callback));
34
+ return internal.removeFn(() => event.removeListener(LABEL_REGISTRY_UPDATED, callback));
35
35
  },
36
36
  onZoneRegistryUpdate: (callback: SimpleCallback) => {
37
37
  event.on(ZONE_REGISTRY_UPDATED, callback);
38
- return is.removeFn(() => event.removeListener(ZONE_REGISTRY_UPDATED, callback));
38
+ return internal.removeFn(() => event.removeListener(ZONE_REGISTRY_UPDATED, callback));
39
39
  },
40
40
  };
41
41
  }
@@ -1,4 +1,4 @@
1
- import { DOWN, is, NO_CHANGE, SECOND, TServiceParams, UP } from "@digital-alchemy/core";
1
+ import { DOWN, NO_CHANGE, SECOND, TServiceParams, UP } from "@digital-alchemy/core";
2
2
  import dayjs, { Dayjs } from "dayjs";
3
3
  import { lt } from "semver";
4
4
 
@@ -25,7 +25,16 @@ type SendBody<STATE extends string | number = string, ATTRIBUTES extends object
25
25
  state?: STATE;
26
26
  };
27
27
 
28
- export function FetchAPI({ logger, lifecycle, context, hass, config }: TServiceParams) {
28
+ export function FetchAPI({
29
+ logger,
30
+ lifecycle,
31
+ context,
32
+ hass,
33
+ config,
34
+ internal: {
35
+ utils: { is },
36
+ },
37
+ }: TServiceParams) {
29
38
  const fetcher = hass.internals({ context });
30
39
  const { download: downloader } = fetcher;
31
40
 
@@ -1,4 +1,4 @@
1
- import { is, TServiceParams } from "@digital-alchemy/core";
1
+ import { TServiceParams } from "@digital-alchemy/core";
2
2
 
3
3
  import {
4
4
  TAreaId,
@@ -22,14 +22,20 @@ import {
22
22
  PICK_FROM_PLATFORM,
23
23
  } from "../helpers/index.mts";
24
24
 
25
- const check = <RAW extends ANY_ENTITY>(raw: RAW[], domains: ALL_DOMAINS[]) => {
26
- if (!is.empty(domains)) {
27
- raw = raw.filter(entity => is.domain(entity, domains));
28
- }
29
- return raw;
30
- };
25
+ export function IDByExtension({
26
+ hass,
27
+ logger,
28
+ internal: {
29
+ utils: { is },
30
+ },
31
+ }: TServiceParams): IDByInterface {
32
+ const check = <RAW extends ANY_ENTITY>(raw: RAW[], domains: ALL_DOMAINS[]) => {
33
+ if (!is.empty(domains)) {
34
+ raw = raw.filter(entity => is.domain(entity, domains));
35
+ }
36
+ return raw;
37
+ };
31
38
 
32
- export function IDByExtension({ hass, logger }: TServiceParams): IDByInterface {
33
39
  // * byDomain
34
40
  function byDomain<DOMAIN extends ALL_DOMAINS>(domain: DOMAIN) {
35
41
  const MASTER_STATE = hass.entity._masterState();
@@ -1,4 +1,4 @@
1
- import { FIRST, InternalError, is, TServiceParams } from "@digital-alchemy/core";
1
+ import { FIRST, InternalError, TServiceParams } from "@digital-alchemy/core";
2
2
  import { createWriteStream } from "fs";
3
3
  import { pipeline } from "stream";
4
4
  import { promisify } from "util";
@@ -10,13 +10,17 @@ import {
10
10
  FetcherOptions,
11
11
  FetchProcessTypes,
12
12
  FetchWith,
13
+ isDomain,
13
14
  MaybeHttpError,
14
15
  TFetchBody,
15
16
  } from "../helpers/index.mts";
16
17
 
17
18
  const streamPipeline = promisify(pipeline);
18
19
 
19
- export function FetchInternals({ logger, context: parentContext }: TServiceParams) {
20
+ export function FetchInternals({ internal, logger, context: parentContext }: TServiceParams) {
21
+ const { is } = internal.utils;
22
+ is.domain = isDomain;
23
+
20
24
  return ({ headers: base_headers, baseUrl: base_url, context: logContext }: FetcherOptions) => {
21
25
  const capabilities: string[] = [];
22
26
 
@@ -1,4 +1,4 @@
1
- import { DOWN, is, NONE, sleep, TAnyFunction, TServiceParams, UP } from "@digital-alchemy/core";
1
+ import { DOWN, NONE, sleep, TAnyFunction, TServiceParams, UP } from "@digital-alchemy/core";
2
2
  import dayjs, { Dayjs } from "dayjs";
3
3
  import { Get } from "type-fest";
4
4
 
@@ -86,6 +86,7 @@ export function ReferenceService({
86
86
  internal,
87
87
  event,
88
88
  }: TServiceParams): HassReferenceService {
89
+ const { is } = internal.utils;
89
90
  // #MARK:proxyGetLogic
90
91
  function proxyGetLogic<ENTITY extends ANY_ENTITY = ANY_ENTITY, PROPERTY extends string = string>(
91
92
  entity: ENTITY,
@@ -1,6 +1,5 @@
1
1
  import {
2
2
  InternalError,
3
- is,
4
3
  SECOND,
5
4
  sleep,
6
5
  START,
@@ -27,6 +26,14 @@ const CONNECTION_FAILED = 2;
27
26
  let messageCount = START;
28
27
  export const SOCKET_CONNECTED = "SOCKET_CONNECTED";
29
28
 
29
+ type WaitingMap = Map<
30
+ number,
31
+ {
32
+ sent: unknown;
33
+ callback: (result: unknown) => TBlackHole;
34
+ }
35
+ >;
36
+
30
37
  export function WebsocketAPI({
31
38
  context,
32
39
  event,
@@ -37,6 +44,8 @@ export function WebsocketAPI({
37
44
  logger,
38
45
  scheduler,
39
46
  }: TServiceParams): HassWebsocketAPI {
47
+ const { is } = internal.utils;
48
+
40
49
  /**
41
50
  * Local attachment points for socket events
42
51
  */
@@ -45,7 +54,7 @@ export function WebsocketAPI({
45
54
 
46
55
  let MESSAGE_TIMESTAMPS: number[] = [];
47
56
  let onSocketReady: () => void;
48
- const waitingCallback = new Map<number, (result: unknown) => TBlackHole>();
57
+ const waitingCallback: WaitingMap = new Map();
49
58
  const isOld = (date: Dayjs) =>
50
59
  is.undefined(date) || date.diff(dayjs(), "s") >= config.hass.RETRY_INTERVAL;
51
60
 
@@ -248,7 +257,10 @@ export function WebsocketAPI({
248
257
  return undefined;
249
258
  }
250
259
  return await new Promise<RESPONSE_VALUE>(async done => {
251
- waitingCallback.set(id, done as (result: unknown) => TBlackHole);
260
+ waitingCallback.set(id, {
261
+ callback: done as (result: unknown) => TBlackHole,
262
+ sent: data,
263
+ });
252
264
  await hass.socket.waitForReply(id, data, sentAt);
253
265
  });
254
266
  }
@@ -258,6 +270,7 @@ export function WebsocketAPI({
258
270
  if (!waitingCallback.has(id)) {
259
271
  return;
260
272
  }
273
+ const { sent } = waitingCallback.get(id);
261
274
  // this could happen around dropped connections, or a number of other reasons
262
275
  //
263
276
  // discard the promise so whatever flow is depending on this can get garbage collected
@@ -266,6 +279,7 @@ export function WebsocketAPI({
266
279
  {
267
280
  message: data,
268
281
  name: waitForReply,
282
+ sent,
269
283
  sentAt: internal.utils.relativeDate(sentAt),
270
284
  },
271
285
  `sent message, did not receive reply`,
@@ -464,21 +478,22 @@ export function WebsocketAPI({
464
478
  return;
465
479
  }
466
480
  if (waitingCallback.has(id)) {
467
- const f = waitingCallback.get(id);
481
+ const { callback } = waitingCallback.get(id);
468
482
  waitingCallback.delete(id);
469
- f(message.event.result);
483
+ callback(message.event.result);
470
484
  }
471
485
  socketEvents.emit(message.event.event_type, message.event);
472
486
  }
473
487
 
474
488
  function onMessageResult(id: number, message: SocketMessageDTO) {
475
489
  if (waitingCallback.has(id)) {
490
+ const { callback, sent } = waitingCallback.get(id);
491
+ waitingCallback.delete(id);
476
492
  if (message.error) {
477
- logger.error({ message, name: onMessageResult });
493
+ logger.error({ message, name: "onMessageResult", sent }, "message result error");
494
+ return;
478
495
  }
479
- const f = waitingCallback.get(id);
480
- waitingCallback.delete(id);
481
- f(message.result);
496
+ callback(message.result);
482
497
  }
483
498
  }
484
499
 
@@ -9,7 +9,7 @@ describe("FetchAPI", () => {
9
9
  const TOKEN =
10
10
  // TODO: Replace hard coded token w/ faker when avail
11
11
  // https://github.com/faker-js/faker/pull/2936
12
- // eslint-disable-next-line @cspell/spellchecker
12
+ // eslint-disable-next-line @cspell/spellchecker, sonarjs/no-hardcoded-secrets
13
13
  "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2aWRlbyI6Imh0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9ZFF3NHc5V2dYY1EifQ.gPIttZEaLZgov3VZziu3LovcgtDbj8H0-XfBg4f08Y0";
14
14
 
15
15
  hassTestRunner.configure({