dt-common-device 13.0.10 → 13.0.14

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.
@@ -603,14 +603,14 @@ let AlertService = (() => {
603
603
  const alerts = await this.queryAlerts(query);
604
604
  if (!alerts.length)
605
605
  return null;
606
- if (alerts.length > 1) {
607
- throw new Error("Multiple alerts found, please specify a more specific query");
606
+ for (const alert of alerts) {
607
+ const alertModel = await Alert_model_1.AlertModel.findById(alert._id || alert.id);
608
+ if (!alertModel)
609
+ return null;
610
+ alertModel.deactivate(updatedBy);
611
+ await alertModel.save();
608
612
  }
609
- const alert = await Alert_model_1.AlertModel.findById(alerts[0]._id || alerts[0].id);
610
- if (!alert)
611
- return null;
612
- alert.deactivate(updatedBy);
613
- return await alert.save();
613
+ return null;
614
614
  }
615
615
  /**
616
616
  * Snooze an alert with business logic
@@ -74,6 +74,11 @@ async function initialize(cfg) {
74
74
  db_keys = constants_1.CONFIG_KEYS.OPERATION_NODE.db_keys;
75
75
  await validateServiceConfig(cfg);
76
76
  }
77
+ if (cfg.SOURCE === "NOTIFICATION_SERVICE") {
78
+ sourceKey = "NOTIFICATION";
79
+ db_keys = constants_1.CONFIG_KEYS.NOTIFICATION.db_keys;
80
+ await validateServiceConfig(cfg);
81
+ }
77
82
  // Connect to databases
78
83
  try {
79
84
  await (0, db_1.connectDatabase)();
@@ -4,7 +4,7 @@ export interface ILogger {
4
4
  warn(message: string, ...args: any[]): void;
5
5
  error(message: string, ...args: any[]): void;
6
6
  }
7
- type AllowedSource = "ACCESS_SERVICE" | "ADMIN_SERVICE" | "ENERGY_SERVICE" | "REMOTE_SERVICE" | "SCHEDULE_SERVICE" | "MIGRATION" | "OPERATION_NODE_SERVICE";
7
+ type AllowedSource = "ACCESS_SERVICE" | "ADMIN_SERVICE" | "ENERGY_SERVICE" | "REMOTE_SERVICE" | "SCHEDULE_SERVICE" | "MIGRATION" | "OPERATION_NODE_SERVICE" | "NOTIFICATION_SERVICE";
8
8
  export type IConfig = {
9
9
  SOURCE: AllowedSource;
10
10
  INTERNAL_EVENT_HANDLER?: IInternalEvent;
@@ -63,4 +63,12 @@ export declare const CONFIG_KEYS: {
63
63
  pms: string;
64
64
  };
65
65
  };
66
+ NOTIFICATION: {
67
+ env: string[];
68
+ INTERNAL_EVENT_HANDLER: boolean;
69
+ db_keys: {
70
+ redis: string;
71
+ redis_port: string;
72
+ };
73
+ };
66
74
  };
@@ -106,4 +106,12 @@ exports.CONFIG_KEYS = {
106
106
  pms: "PMS_DB_URI",
107
107
  },
108
108
  },
109
+ NOTIFICATION: {
110
+ env: ["REDIS_HOST", "REDIS_PORT"],
111
+ INTERNAL_EVENT_HANDLER: false,
112
+ db_keys: {
113
+ redis: "REDIS_HOST",
114
+ redis_port: "REDIS_PORT",
115
+ },
116
+ },
109
117
  };
package/dist/index.d.ts CHANGED
@@ -20,3 +20,4 @@ export { initialize, getConfig, shutdown } from "./config/config";
20
20
  export * from "./webhookQueue";
21
21
  export * from "./copilotQueue";
22
22
  export * from "./serviceQueue";
23
+ export * from "./notificationQueue";
package/dist/index.js CHANGED
@@ -65,3 +65,5 @@ __exportStar(require("./webhookQueue"), exports);
65
65
  __exportStar(require("./copilotQueue"), exports);
66
66
  //Export Service Queue
67
67
  __exportStar(require("./serviceQueue"), exports);
68
+ // Export Notification Queue (Redis pub/sub for notifications)
69
+ __exportStar(require("./notificationQueue"), exports);
@@ -0,0 +1 @@
1
+ export * from "./queue.service";
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./queue.service"), exports);
@@ -0,0 +1,21 @@
1
+ export interface NotificationQueuePayload {
2
+ userId: string;
3
+ orgId?: string;
4
+ propertyId?: string;
5
+ data?: any;
6
+ title?: string;
7
+ message?: string;
8
+ url?: string;
9
+ }
10
+ export interface NotificationQueueOptions {
11
+ channel?: string;
12
+ }
13
+ /**
14
+ * Publish an event payload to Redis so any interested consumer can process it.
15
+ */
16
+ export declare function enqueueEvent(event: NotificationQueuePayload, opts?: NotificationQueueOptions): Promise<void>;
17
+ /**
18
+ * Start a single pub/sub consumer in this process.
19
+ * The `handler` is responsible for business logic (e.g. calling processEvent()).
20
+ */
21
+ export declare function startConsumer(handler: (payload: NotificationQueuePayload) => Promise<void>, opts?: NotificationQueueOptions): Promise<void>;
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.enqueueEvent = enqueueEvent;
4
+ exports.startConsumer = startConsumer;
5
+ const redis_1 = require("../db/redis");
6
+ const DEFAULT_CHANNEL = "notification:events";
7
+ let consumerStarted = false;
8
+ /**
9
+ * Publish an event payload to Redis so any interested consumer can process it.
10
+ */
11
+ async function enqueueEvent(event, opts) {
12
+ const client = (0, redis_1.getRedisClient)();
13
+ const channel = opts?.channel ?? DEFAULT_CHANNEL;
14
+ try {
15
+ await client.publish(channel, JSON.stringify(event));
16
+ }
17
+ catch (error) {
18
+ // eslint-disable-next-line no-console
19
+ console.error("Failed to publish notification event", {
20
+ error,
21
+ channel,
22
+ event,
23
+ });
24
+ }
25
+ }
26
+ /**
27
+ * Start a single pub/sub consumer in this process.
28
+ * The `handler` is responsible for business logic (e.g. calling processEvent()).
29
+ */
30
+ async function startConsumer(handler, opts) {
31
+ if (consumerStarted) {
32
+ // eslint-disable-next-line no-console
33
+ console.warn("NotificationQueue consumer already started; skipping");
34
+ return;
35
+ }
36
+ consumerStarted = true;
37
+ const baseClient = (0, redis_1.getRedisClient)();
38
+ const subscriber = baseClient.duplicate();
39
+ const channel = opts?.channel ?? DEFAULT_CHANNEL;
40
+ try {
41
+ await subscriber.connect();
42
+ }
43
+ catch (error) {
44
+ // eslint-disable-next-line no-console
45
+ console.error("Failed to connect Redis subscriber for notifications", {
46
+ error,
47
+ });
48
+ return;
49
+ }
50
+ subscriber.on("error", (error) => {
51
+ // eslint-disable-next-line no-console
52
+ console.error("Redis notification subscriber error", { error });
53
+ });
54
+ try {
55
+ // ioredis `subscribe` expects an (err, count) callback, not a message handler.
56
+ // We subscribe first, then attach a separate "message" listener.
57
+ await subscriber.subscribe(channel);
58
+ subscriber.on("message", async (subscribedChannel, message) => {
59
+ // Only process messages for the intended channel (defensive in case of multiple subscriptions)
60
+ if (subscribedChannel !== channel) {
61
+ return;
62
+ }
63
+ let payload;
64
+ try {
65
+ payload = JSON.parse(message);
66
+ }
67
+ catch (error) {
68
+ // eslint-disable-next-line no-console
69
+ console.error("Failed to parse pub/sub notification payload", {
70
+ error,
71
+ message,
72
+ channel: subscribedChannel,
73
+ });
74
+ return;
75
+ }
76
+ try {
77
+ await handler(payload);
78
+ }
79
+ catch (error) {
80
+ // eslint-disable-next-line no-console
81
+ console.error("Failed to process pub/sub notification event", {
82
+ error,
83
+ payload,
84
+ channel: subscribedChannel,
85
+ });
86
+ }
87
+ });
88
+ }
89
+ catch (error) {
90
+ // eslint-disable-next-line no-console
91
+ console.error("Error while subscribing to notification channel", {
92
+ error,
93
+ channel,
94
+ });
95
+ }
96
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dt-common-device",
3
- "version": "13.0.10",
3
+ "version": "13.0.14",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "files": [