dt-common-device 3.0.10 → 3.0.11

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 (113) hide show
  1. package/dist/config/config.d.ts +1 -2
  2. package/dist/config/config.js +4 -5
  3. package/dist/device/local/repository/Schedule.repository.d.ts +0 -1
  4. package/dist/device/local/repository/Schedule.repository.js +6 -6
  5. package/dist/queue/entities/HybridHttpQueue.d.ts +4 -14
  6. package/dist/queue/entities/HybridHttpQueue.js +31 -119
  7. package/dist/queue/interfaces/IHybridHttpQueue.d.ts +2 -12
  8. package/dist/queue/interfaces/IJobResult.d.ts +1 -8
  9. package/dist/queue/interfaces/index.d.ts +0 -1
  10. package/dist/queue/interfaces/index.js +0 -1
  11. package/dist/queue/services/QueueService.d.ts +2 -12
  12. package/dist/queue/types/queue.types.d.ts +10 -29
  13. package/dist/queue/utils/jobUtils.d.ts +0 -3
  14. package/dist/queue/utils/jobUtils.js +0 -48
  15. package/dist/queue/utils/queueUtils.d.ts +7 -0
  16. package/dist/queue/utils/queueUtils.js +113 -4
  17. package/package.json +6 -1
  18. package/.eslintrc.js +0 -44
  19. package/src/alerts/Alert.model.ts +0 -289
  20. package/src/alerts/Alert.repository.ts +0 -487
  21. package/src/alerts/Alert.service.ts +0 -711
  22. package/src/alerts/AlertBuilder.example.ts +0 -126
  23. package/src/alerts/AlertBuilder.ts +0 -208
  24. package/src/alerts/AlertService.example.ts +0 -232
  25. package/src/alerts/alert.types.ts +0 -64
  26. package/src/alerts/index.ts +0 -3
  27. package/src/config/config.ts +0 -202
  28. package/src/config/config.types.ts +0 -21
  29. package/src/connection/Connection.repository.ts +0 -52
  30. package/src/connection/Connection.service.ts +0 -39
  31. package/src/connection/IConnection.ts +0 -27
  32. package/src/connection/index.ts +0 -3
  33. package/src/constants/ConnectionProviders.ts +0 -11
  34. package/src/constants/Event.ts +0 -89
  35. package/src/constants/Service.ts +0 -17
  36. package/src/constants/index.ts +0 -3
  37. package/src/db/db.ts +0 -24
  38. package/src/db/index.ts +0 -2
  39. package/src/db/redis.ts +0 -20
  40. package/src/device/cloud/entities/CloudDevice.ts +0 -40
  41. package/src/device/cloud/entities/CloudDeviceService.ts +0 -8
  42. package/src/device/cloud/entities/DeviceFactory.ts +0 -27
  43. package/src/device/cloud/entities/index.ts +0 -3
  44. package/src/device/cloud/interfaces/ICloudDevice.ts +0 -14
  45. package/src/device/cloud/interfaces/ICloudDeviceService.ts +0 -6
  46. package/src/device/cloud/interfaces/IDeviceFactory.ts +0 -5
  47. package/src/device/cloud/interfaces/IRawDataTransformer.ts +0 -5
  48. package/src/device/cloud/interfaces/IRawDevice.ts +0 -19
  49. package/src/device/cloud/interfaces/index.ts +0 -5
  50. package/src/device/local/interfaces/IDevice.ts +0 -62
  51. package/src/device/local/interfaces/IDtDevice.ts +0 -16
  52. package/src/device/local/interfaces/ISchedule.ts +0 -40
  53. package/src/device/local/interfaces/index.ts +0 -3
  54. package/src/device/local/repository/Device.repository.ts +0 -368
  55. package/src/device/local/repository/Hub.repository.ts +0 -107
  56. package/src/device/local/repository/Schedule.repository.ts +0 -72
  57. package/src/device/local/services/Device.service.ts +0 -436
  58. package/src/device/local/services/Hub.service.ts +0 -57
  59. package/src/device/local/services/Schedule.service.ts +0 -26
  60. package/src/device/local/services/index.ts +0 -3
  61. package/src/docs/Alert.model.md +0 -319
  62. package/src/docs/Alerts&IssuesModel.md +0 -312
  63. package/src/docs/Issue.model.md +0 -386
  64. package/src/docs/SECURITY.md +0 -67
  65. package/src/docs/TROUBLESHOOTING.md +0 -184
  66. package/src/events/BaseEventHandler.ts +0 -145
  67. package/src/events/BaseEventTransformer.ts +0 -97
  68. package/src/events/DeviceEventHandler.ts +0 -213
  69. package/src/events/DeviceEventTransformerFactory.ts +0 -77
  70. package/src/events/EventHandler.ts +0 -124
  71. package/src/events/EventHandlerOrchestrator.ts +0 -119
  72. package/src/events/EventProcessingService.ts +0 -248
  73. package/src/events/InternalEventSubscription.ts +0 -194
  74. package/src/events/index.ts +0 -9
  75. package/src/events/interfaces/DeviceEvent.ts +0 -56
  76. package/src/events/interfaces/IEventHandler.ts +0 -28
  77. package/src/events/interfaces/IEventTransformer.ts +0 -8
  78. package/src/events/interfaces/IInternalEvent.ts +0 -33
  79. package/src/events/interfaces/index.ts +0 -4
  80. package/src/index.ts +0 -43
  81. package/src/issues/Issue.model.ts +0 -350
  82. package/src/issues/Issue.repository.ts +0 -517
  83. package/src/issues/Issue.service.ts +0 -932
  84. package/src/issues/IssueBuilder.example.ts +0 -210
  85. package/src/issues/IssueBuilder.ts +0 -263
  86. package/src/issues/IssueService.example.ts +0 -310
  87. package/src/issues/index.ts +0 -2
  88. package/src/issues/issue.types.ts +0 -98
  89. package/src/property/IProperty.ts +0 -30
  90. package/src/property/Property.repository.ts +0 -53
  91. package/src/property/Property.service.ts +0 -38
  92. package/src/property/index.ts +0 -2
  93. package/src/queue/entities/HybridHttpQueue.ts +0 -274
  94. package/src/queue/entities/index.ts +0 -1
  95. package/src/queue/index.ts +0 -6
  96. package/src/queue/interfaces/IHttpRequestJob.ts +0 -10
  97. package/src/queue/interfaces/IHybridHttpQueue.ts +0 -25
  98. package/src/queue/interfaces/IJobResult.ts +0 -15
  99. package/src/queue/interfaces/IRateLimitConfig.ts +0 -5
  100. package/src/queue/interfaces/index.ts +0 -4
  101. package/src/queue/services/QueueService.ts +0 -40
  102. package/src/queue/services/index.ts +0 -1
  103. package/src/queue/types/http.types.ts +0 -23
  104. package/src/queue/types/index.ts +0 -2
  105. package/src/queue/types/queue.types.ts +0 -21
  106. package/src/queue/utils/index.ts +0 -3
  107. package/src/queue/utils/jobUtils.ts +0 -79
  108. package/src/queue/utils/queueUtils.ts +0 -84
  109. package/src/queue/utils/rateLimit.utils.ts +0 -131
  110. package/src/utils/http.utils.ts +0 -143
  111. package/src/utils/index.ts +0 -2
  112. package/src/utils/redis.utils.ts +0 -74
  113. package/tsconfig.json +0 -20
@@ -1,12 +1,21 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.QueueUtils = void 0;
7
+ const rateLimit_utils_1 = require("./rateLimit.utils");
8
+ const axios_1 = __importDefault(require("axios"));
9
+ const dt_audit_library_1 = require("dt-audit-library");
4
10
  const config_1 = require("../../config/config");
5
11
  const redis_1 = require("../../db/redis");
6
12
  class QueueUtils {
7
13
  static getQueueKey(microservice, connectionId, provider) {
8
14
  return `${microservice}_${provider}_${connectionId}`;
9
15
  }
16
+ static getRequestQueueKey(connectionId, provider) {
17
+ return `${connectionId}_${provider}`;
18
+ }
10
19
  static getOrCreateQueue(queueKey, queues) {
11
20
  return (queues.get(queueKey) ??
12
21
  queues
@@ -27,10 +36,9 @@ class QueueUtils {
27
36
  lockDuration: 300000,
28
37
  stalledInterval: 60000,
29
38
  });
30
- // Simplified event handlers
39
+ // Event handlers for job tracking
31
40
  worker.on("completed", (job) => {
32
41
  (0, config_1.getConfig)().LOGGER.info(`HTTP request completed: ${job.id} [${queueKey}]`);
33
- // job.returnvalue is the actual result, not a Promise
34
42
  const result = job.returnvalue;
35
43
  jobResults.set(job.id, {
36
44
  result,
@@ -47,10 +55,111 @@ class QueueUtils {
47
55
  });
48
56
  });
49
57
  worker.on("error", (err) => (0, config_1.getConfig)().LOGGER.error(`Worker error for ${queueKey}: ${err.message}`));
50
- worker.on("stalled", (jobId) => (0, config_1.getConfig)().LOGGER.warn(`Job ${jobId} stalled in worker ${queueKey}`));
51
- worker.on("active", (job) => (0, config_1.getConfig)().LOGGER.info(`HTTP request started: ${job.id} [${queueKey}]`));
52
58
  workers.set(queueKey, worker);
53
59
  (0, config_1.getConfig)().LOGGER.info(`Worker initialized for queue: ${queueKey}`);
54
60
  }
61
+ static async waitForRateLimitExpiry(connectionId, provider, rateLimitConfigs) {
62
+ const key = `rate_limit:${provider}:${connectionId}`;
63
+ const config = rateLimitConfigs.get(provider);
64
+ if (!config)
65
+ return;
66
+ while (true) {
67
+ const timestamps = await rateLimit_utils_1.RateLimitUtils.getRawRequestTimestamps(key);
68
+ const now = Date.now();
69
+ const windowStart = now - config.windowMs;
70
+ const recentRequests = timestamps.filter((t) => t > windowStart);
71
+ if (recentRequests.length < config.maxRequests) {
72
+ // Rate limit not exceeded, we can proceed
73
+ break;
74
+ }
75
+ // Calculate when the earliest request will expire
76
+ const earliestRequest = recentRequests[0];
77
+ const nextAvailableTime = earliestRequest + config.windowMs;
78
+ const delay = Math.max(nextAvailableTime - now, 1000); // At least 1 second
79
+ (0, config_1.getConfig)().LOGGER.info(`Rate limit exceeded for ${provider} [${connectionId}]. Waiting ${delay}ms until next allowed request. Current requests in window: ${recentRequests.length}/${config.maxRequests}`);
80
+ // Wait for the calculated delay
81
+ await new Promise((resolve) => setTimeout(resolve, delay));
82
+ }
83
+ }
84
+ static async executeHttpRequest(url, method, options, connectionId, provider) {
85
+ (0, config_1.getConfig)().LOGGER.info(`Executing: ${method} ${url} -> ${provider} [${connectionId}]`);
86
+ try {
87
+ // Record the request first
88
+ await rateLimit_utils_1.RateLimitUtils.recordRequest(connectionId, provider);
89
+ // Execute the HTTP request
90
+ const response = await (0, axios_1.default)({
91
+ method: method.toLowerCase(),
92
+ url: url,
93
+ headers: options.headers || {},
94
+ timeout: 30000,
95
+ ...(options.body && { data: options.body }),
96
+ ...(options.params && { params: options.params }),
97
+ });
98
+ (0, config_1.getConfig)().LOGGER.info(`HTTP request successful: ${method} ${url} for ${provider} [${connectionId}]`);
99
+ // Return only the response data
100
+ return response.data;
101
+ }
102
+ catch (error) {
103
+ (0, config_1.getConfig)().LOGGER.error(`HTTP request failed: ${error.message}`);
104
+ await (0, dt_audit_library_1.publishAudit)({
105
+ eventType: "http.request.error",
106
+ properties: {
107
+ connectionId,
108
+ provider,
109
+ endpoint: url,
110
+ method,
111
+ timestamp: Date.now(),
112
+ reason: "execution_error",
113
+ errorMessage: error.message,
114
+ },
115
+ });
116
+ // Throw the error instead of returning it
117
+ throw new Error(`HTTP request failed: ${error.message}`);
118
+ }
119
+ }
120
+ static async addJobToQueue(queueKey, jobData, delay, queues) {
121
+ const queue = this.getOrCreateQueue(queueKey, queues);
122
+ const job = await queue.add("http-request", jobData, {
123
+ delay,
124
+ attempts: 1,
125
+ removeOnComplete: { age: 300, count: 1 },
126
+ removeOnFail: { age: 300, count: 1 },
127
+ });
128
+ return job.id;
129
+ }
130
+ static async waitForJobCompletion(jobId, queueKey, jobResults) {
131
+ return new Promise((resolve, reject) => {
132
+ let timeoutId;
133
+ let checkCount = 0;
134
+ const maxChecks = 600;
135
+ const checkJob = async () => {
136
+ if (++checkCount >= maxChecks) {
137
+ clearTimeout(timeoutId);
138
+ return reject(new Error("Job timeout: Request took too long"));
139
+ }
140
+ try {
141
+ const memoryResult = jobResults.get(jobId);
142
+ if (memoryResult?.resolved) {
143
+ clearTimeout(timeoutId);
144
+ return memoryResult.result !== undefined
145
+ ? resolve(memoryResult.result)
146
+ : reject(new Error(memoryResult.error || "Unknown error"));
147
+ }
148
+ // Continue checking
149
+ timeoutId = setTimeout(checkJob, checkCount < 10 ? 50 : 100);
150
+ }
151
+ catch (error) {
152
+ clearTimeout(timeoutId);
153
+ reject(new Error(`Error checking job: ${error.message}`));
154
+ }
155
+ };
156
+ checkJob();
157
+ // Backup timeout
158
+ setTimeout(() => {
159
+ clearTimeout(timeoutId);
160
+ reject(new Error("Request timeout: Maximum wait time exceeded"));
161
+ }, 60000);
162
+ });
163
+ }
55
164
  }
56
165
  exports.QueueUtils = QueueUtils;
package/package.json CHANGED
@@ -1,8 +1,13 @@
1
1
  {
2
2
  "name": "dt-common-device",
3
- "version": "3.0.10",
3
+ "version": "3.0.11",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
+ "files": [
7
+ "dist",
8
+ "README.md",
9
+ "LICENSE"
10
+ ],
6
11
  "scripts": {
7
12
  "build": "tsc",
8
13
  "patch": "npm version patch && npm run build && npm publish",
package/.eslintrc.js DELETED
@@ -1,44 +0,0 @@
1
- module.exports = {
2
- parser: "@typescript-eslint/parser",
3
- extends: ["eslint:recommended", "@typescript-eslint/recommended"],
4
- plugins: ["@typescript-eslint"],
5
- env: {
6
- node: true,
7
- es2020: true,
8
- },
9
- parserOptions: {
10
- ecmaVersion: 2020,
11
- sourceType: "module",
12
- },
13
- rules: {
14
- // Security rules
15
- "no-eval": "error",
16
- "no-implied-eval": "error",
17
- "no-new-func": "error",
18
- "no-script-url": "error",
19
- "no-unsafe-finally": "error",
20
-
21
- // TypeScript security
22
- "@typescript-eslint/no-explicit-any": "warn",
23
- "@typescript-eslint/no-unsafe-assignment": "warn",
24
- "@typescript-eslint/no-unsafe-call": "warn",
25
- "@typescript-eslint/no-unsafe-member-access": "warn",
26
- "@typescript-eslint/no-unsafe-return": "warn",
27
-
28
- // Code quality
29
- "@typescript-eslint/explicit-function-return-type": "warn",
30
- "@typescript-eslint/no-unused-vars": "error",
31
- "@typescript-eslint/prefer-const": "error",
32
- "@typescript-eslint/no-var-requires": "error",
33
-
34
- // Error handling
35
- "no-console": "warn",
36
- "no-throw-literal": "error",
37
-
38
- // Best practices
39
- "prefer-const": "error",
40
- "no-var": "error",
41
- "object-shorthand": "error",
42
- },
43
- ignorePatterns: ["dist/", "node_modules/", "*.js"],
44
- };
@@ -1,289 +0,0 @@
1
- import mongoose, { Schema, Model } from "mongoose";
2
- import {
3
- AlertCategory,
4
- AlertSeverity,
5
- EntityType,
6
- AlertDocument as IAlertDocument,
7
- CreateAlertData,
8
- UpdateAlertData,
9
- } from "./alert.types";
10
-
11
- // Interface for instance methods
12
- interface IAlertMethods {
13
- markAsRead(updatedBy: string): void;
14
- markAsUnread(updatedBy: string): void;
15
- activate(updatedBy: string): void;
16
- deactivate(updatedBy: string): void;
17
- snooze(until: Date, updatedBy: string): void;
18
- unsnooze(updatedBy: string): void;
19
- }
20
-
21
- // Interface for static methods
22
- interface IAlertModel extends Model<IAlertDocument, {}, IAlertMethods> {
23
- findByProperty(
24
- propertyId: string,
25
- includeDeleted?: boolean
26
- ): Promise<IAlertDocument[]>;
27
- findByEntity(
28
- entityId: string,
29
- entityType: EntityType,
30
- includeDeleted?: boolean
31
- ): Promise<IAlertDocument[]>;
32
- findByCategory(
33
- category: AlertCategory,
34
- includeDeleted?: boolean
35
- ): Promise<IAlertDocument[]>;
36
- findBySeverity(
37
- severity: AlertSeverity,
38
- includeDeleted?: boolean
39
- ): Promise<IAlertDocument[]>;
40
- findActive(includeDeleted?: boolean): Promise<IAlertDocument[]>;
41
- findUnread(includeDeleted?: boolean): Promise<IAlertDocument[]>;
42
- findSnoozed(includeDeleted?: boolean): Promise<IAlertDocument[]>;
43
- findExpiredSnooze(includeDeleted?: boolean): Promise<IAlertDocument[]>;
44
- }
45
-
46
- // Main Alert schema
47
- const AlertSchema = new Schema<IAlertDocument, IAlertModel, IAlertMethods>(
48
- {
49
- category: {
50
- type: [String],
51
- enum: Object.values(AlertCategory),
52
- required: true,
53
- validate: {
54
- validator: function (categories: string[]) {
55
- return categories && categories.length > 0;
56
- },
57
- message: "At least one category is required",
58
- },
59
- },
60
- propertyId: {
61
- type: String,
62
- required: true,
63
- index: true,
64
- },
65
- title: {
66
- type: String,
67
- required: true,
68
- trim: true,
69
- },
70
- description: {
71
- type: String,
72
- required: true,
73
- trim: true,
74
- },
75
- entityId: {
76
- type: String,
77
- index: true,
78
- },
79
- entityType: {
80
- type: String,
81
- enum: Object.values(EntityType),
82
- required: true,
83
- index: true,
84
- },
85
- severity: {
86
- type: String,
87
- enum: Object.values(AlertSeverity),
88
- default: AlertSeverity.MEDIUM,
89
- },
90
- isRead: {
91
- type: Boolean,
92
- default: false,
93
- index: true,
94
- },
95
- isActive: {
96
- type: Boolean,
97
- default: true,
98
- index: true,
99
- },
100
- isDeleted: {
101
- type: Boolean,
102
- default: false,
103
- },
104
- snoozeUntil: {
105
- type: Date,
106
- },
107
- createdBy: {
108
- type: String,
109
- },
110
- updatedBy: {
111
- type: String,
112
- },
113
- createdAt: {
114
- type: Date,
115
- default: Date.now,
116
- },
117
- updatedAt: {
118
- type: Date,
119
- default: Date.now,
120
- },
121
- },
122
- {
123
- timestamps: true,
124
- collection: "dt_alerts",
125
- }
126
- );
127
-
128
- // Compound indexes to match Prisma schema
129
- AlertSchema.index({ propertyId: 1, isActive: 1, isRead: 1 });
130
- AlertSchema.index({ entityId: 1, entityType: 1 });
131
- AlertSchema.index({ createdAt: 1 });
132
-
133
- // Pre-save middleware to update the updatedAt field
134
- AlertSchema.pre("save", function (next) {
135
- this.updatedAt = new Date();
136
- next();
137
- });
138
-
139
- // Pre-update middleware to update the updatedAt field
140
- AlertSchema.pre(
141
- ["updateOne", "findOneAndUpdate", "updateMany"],
142
- function (next) {
143
- this.set({ updatedAt: new Date() });
144
- next();
145
- }
146
- );
147
-
148
- // Instance methods
149
- AlertSchema.methods.markAsRead = function (updatedBy: string): void {
150
- this.isRead = true;
151
- this.updatedBy = updatedBy;
152
- };
153
-
154
- AlertSchema.methods.markAsUnread = function (updatedBy: string): void {
155
- this.isRead = false;
156
- this.updatedBy = updatedBy;
157
- };
158
-
159
- AlertSchema.methods.activate = function (updatedBy: string): void {
160
- this.isActive = true;
161
- this.updatedBy = updatedBy;
162
- };
163
-
164
- AlertSchema.methods.deactivate = function (updatedBy: string): void {
165
- this.isActive = false;
166
- this.updatedBy = updatedBy;
167
- };
168
-
169
- AlertSchema.methods.snooze = function (until: Date, updatedBy: string): void {
170
- this.snoozeUntil = until;
171
- this.updatedBy = updatedBy;
172
- };
173
-
174
- AlertSchema.methods.unsnooze = function (updatedBy: string): void {
175
- this.snoozeUntil = undefined;
176
- this.updatedBy = updatedBy;
177
- };
178
-
179
- // Static methods
180
- AlertSchema.statics.findByProperty = function (
181
- propertyId: string,
182
- includeDeleted = false
183
- ) {
184
- const query: any = { propertyId };
185
- if (!includeDeleted) {
186
- query.isDeleted = false;
187
- }
188
- return this.find(query).sort({ createdAt: -1 });
189
- };
190
-
191
- AlertSchema.statics.findByEntity = function (
192
- entityId: string,
193
- entityType: EntityType,
194
- includeDeleted = false
195
- ) {
196
- const query: any = { entityId, entityType };
197
- if (!includeDeleted) {
198
- query.isDeleted = false;
199
- }
200
- return this.find(query).sort({ createdAt: -1 });
201
- };
202
-
203
- AlertSchema.statics.findByCategory = function (
204
- category: AlertCategory,
205
- includeDeleted = false
206
- ) {
207
- const query: any = { category: { $in: [category] } };
208
- if (!includeDeleted) {
209
- query.isDeleted = false;
210
- }
211
- return this.find(query).sort({ createdAt: -1 });
212
- };
213
-
214
- AlertSchema.statics.findBySeverity = function (
215
- severity: AlertSeverity,
216
- includeDeleted = false
217
- ) {
218
- const query: any = { severity };
219
- if (!includeDeleted) {
220
- query.isDeleted = false;
221
- }
222
- return this.find(query).sort({ severity: -1, createdAt: -1 });
223
- };
224
-
225
- AlertSchema.statics.findActive = function (includeDeleted = false) {
226
- const query: any = { isActive: true };
227
- if (!includeDeleted) {
228
- query.isDeleted = false;
229
- }
230
- return this.find(query).sort({ severity: -1, createdAt: -1 });
231
- };
232
-
233
- AlertSchema.statics.findUnread = function (includeDeleted = false) {
234
- const query: any = { isRead: false };
235
- if (!includeDeleted) {
236
- query.isDeleted = false;
237
- }
238
- return this.find(query).sort({ severity: -1, createdAt: -1 });
239
- };
240
-
241
- AlertSchema.statics.findSnoozed = function (includeDeleted = false) {
242
- const query: any = { snoozeUntil: { $exists: true, $ne: null } };
243
- if (!includeDeleted) {
244
- query.isDeleted = false;
245
- }
246
- return this.find(query).sort({ snoozeUntil: 1 });
247
- };
248
-
249
- AlertSchema.statics.findExpiredSnooze = function (includeDeleted = false) {
250
- const query: any = {
251
- snoozeUntil: { $lt: new Date() },
252
- isActive: true,
253
- };
254
- if (!includeDeleted) {
255
- query.isDeleted = false;
256
- }
257
- return this.find(query).sort({ snoozeUntil: 1 });
258
- };
259
-
260
- // Virtual for snooze status
261
- AlertSchema.virtual("isSnoozed").get(function () {
262
- return this.snoozeUntil && this.snoozeUntil > new Date();
263
- });
264
-
265
- AlertSchema.virtual("isSnoozeExpired").get(function () {
266
- return this.snoozeUntil && this.snoozeUntil <= new Date();
267
- });
268
-
269
- // Ensure virtuals are serialized
270
- AlertSchema.set("toJSON", { virtuals: true });
271
- AlertSchema.set("toObject", { virtuals: true });
272
-
273
- // Create and export the model
274
- export const AlertModel = mongoose.model<IAlertDocument, IAlertModel>(
275
- "Alert",
276
- AlertSchema
277
- );
278
-
279
- // Export the schema for potential reuse
280
- export { AlertSchema };
281
-
282
- // Export types for external use
283
- export type {
284
- IAlertDocument,
285
- CreateAlertData,
286
- UpdateAlertData,
287
- IAlertMethods,
288
- IAlertModel,
289
- };