dt-common-device 2.0.6 → 3.0.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.
- package/README.md +321 -99
- package/dist/alerts/Alert.model.d.ts +28 -0
- package/dist/alerts/Alert.model.js +222 -0
- package/dist/alerts/Alert.repository.d.ts +106 -0
- package/dist/alerts/Alert.repository.js +374 -0
- package/dist/alerts/Alert.service.d.ts +137 -0
- package/dist/alerts/Alert.service.js +476 -0
- package/dist/alerts/AlertBuilder.d.ts +87 -0
- package/dist/alerts/AlertBuilder.example.d.ts +11 -0
- package/dist/alerts/AlertBuilder.example.js +117 -0
- package/dist/alerts/AlertBuilder.js +185 -0
- package/dist/alerts/AlertService.example.d.ts +55 -0
- package/dist/alerts/AlertService.example.js +148 -0
- package/dist/alerts/alert.types.d.ts +57 -0
- package/dist/alerts/alert.types.js +22 -0
- package/dist/alerts/index.d.ts +3 -0
- package/dist/alerts/index.js +19 -0
- package/dist/config/config.d.ts +4 -4
- package/dist/config/config.js +3 -3
- package/dist/config/config.types.d.ts +19 -0
- package/dist/config/config.types.js +2 -0
- package/dist/connection/Connection.repository.d.ts +8 -0
- package/dist/connection/Connection.repository.js +92 -0
- package/dist/connection/Connection.service.d.ts +8 -0
- package/dist/connection/Connection.service.js +32 -0
- package/dist/connection/IConnection.d.ts +26 -0
- package/dist/connection/IConnection.js +14 -0
- package/dist/connection/index.d.ts +2 -0
- package/dist/connection/index.js +18 -0
- package/dist/device/cloud/entities/CloudDevice.d.ts +2 -2
- package/dist/device/cloud/entities/CloudDeviceService.d.ts +1 -1
- package/dist/device/cloud/entities/DeviceFactory.d.ts +1 -1
- package/dist/device/cloud/entities/DeviceFactory.js +1 -1
- package/dist/device/cloud/interfaces/ICloudDeviceService.d.ts +1 -1
- package/dist/device/cloud/interfaces/IRawDevice.d.ts +1 -1
- package/dist/device/local/interfaces/index.d.ts +2 -3
- package/dist/device/local/interfaces/index.js +2 -3
- package/dist/device/local/repository/Device.repository.d.ts +2 -0
- package/dist/device/local/repository/Device.repository.js +22 -3
- package/dist/device/local/repository/Hub.repository.js +4 -4
- package/dist/device/local/repository/Schedule.repository.js +2 -2
- package/dist/device/local/services/Device.service.d.ts +2 -2
- package/dist/device/local/services/Device.service.js +3 -1
- package/dist/device/local/services/index.d.ts +0 -4
- package/dist/device/local/services/index.js +0 -4
- package/dist/events/BaseEventHandler.d.ts +2 -2
- package/dist/events/BaseEventHandler.js +2 -2
- package/dist/events/BaseEventTransformer.d.ts +1 -1
- package/dist/events/BaseEventTransformer.js +1 -1
- package/dist/events/DeviceEventHandler.d.ts +1 -1
- package/dist/events/DeviceEventHandler.js +2 -2
- package/dist/events/EventHandler.js +1 -1
- package/dist/events/EventHandlerOrchestrator.js +1 -1
- package/dist/events/EventProcessingService.js +1 -1
- package/dist/events/InternalEventSubscription.js +1 -1
- package/dist/index.d.ts +7 -5
- package/dist/index.js +16 -13
- package/dist/issues/Issue.model.d.ts +28 -0
- package/dist/issues/Issue.model.js +260 -0
- package/dist/issues/Issue.repository.d.ts +113 -0
- package/dist/issues/Issue.repository.js +401 -0
- package/dist/issues/Issue.service.d.ts +168 -0
- package/dist/issues/Issue.service.js +642 -0
- package/dist/issues/IssueBuilder.d.ts +109 -0
- package/dist/issues/IssueBuilder.example.d.ts +16 -0
- package/dist/issues/IssueBuilder.example.js +196 -0
- package/dist/issues/IssueBuilder.js +237 -0
- package/dist/issues/IssueService.example.d.ts +68 -0
- package/dist/issues/IssueService.example.js +177 -0
- package/dist/issues/index.d.ts +2 -0
- package/dist/issues/index.js +18 -0
- package/dist/issues/issue.types.d.ts +90 -0
- package/dist/issues/issue.types.js +40 -0
- package/dist/property/IProperty.d.ts +29 -0
- package/dist/property/IProperty.js +2 -0
- package/dist/property/Property.repository.d.ts +8 -0
- package/dist/property/Property.repository.js +95 -0
- package/dist/property/Property.service.d.ts +8 -0
- package/dist/property/Property.service.js +36 -0
- package/dist/property/index.d.ts +2 -0
- package/dist/property/index.js +18 -0
- package/dist/queue/entities/HybridHttpQueue.d.ts +23 -0
- package/dist/queue/entities/HybridHttpQueue.js +189 -0
- package/dist/queue/entities/index.d.ts +1 -0
- package/dist/queue/entities/index.js +17 -0
- package/dist/queue/index.d.ts +5 -0
- package/dist/queue/index.js +22 -0
- package/dist/queue/interfaces/IHttpRequestJob.d.ts +9 -0
- package/dist/queue/interfaces/IHttpRequestJob.js +2 -0
- package/dist/queue/interfaces/IHybridHttpQueue.d.ts +16 -0
- package/dist/queue/interfaces/IHybridHttpQueue.js +2 -0
- package/dist/queue/interfaces/IJobResult.d.ts +6 -0
- package/dist/queue/interfaces/IJobResult.js +2 -0
- package/dist/queue/interfaces/IRateLimitConfig.d.ts +5 -0
- package/dist/queue/interfaces/IRateLimitConfig.js +2 -0
- package/dist/queue/interfaces/index.d.ts +4 -0
- package/dist/queue/interfaces/index.js +20 -0
- package/dist/queue/services/QueueService.d.ts +19 -0
- package/dist/queue/services/QueueService.js +73 -0
- package/dist/queue/services/index.d.ts +1 -0
- package/dist/queue/services/index.js +17 -0
- package/dist/queue/types/http.types.d.ts +21 -0
- package/dist/queue/types/http.types.js +2 -0
- package/dist/queue/types/index.d.ts +2 -0
- package/dist/queue/types/index.js +18 -0
- package/dist/queue/types/queue.types.d.ts +35 -0
- package/dist/queue/types/queue.types.js +2 -0
- package/dist/queue/utils/index.d.ts +3 -0
- package/dist/queue/utils/index.js +19 -0
- package/dist/queue/utils/jobUtils.d.ts +10 -0
- package/dist/queue/utils/jobUtils.js +64 -0
- package/dist/queue/utils/queueUtils.d.ts +5 -0
- package/dist/queue/utils/queueUtils.js +59 -0
- package/dist/queue/utils/rateLimit.utils.d.ts +6 -0
- package/dist/queue/utils/rateLimit.utils.js +44 -0
- package/package.json +2 -1
- package/src/{device/local/models → alerts}/Alert.model.ts +1 -1
- package/src/{device/local/repository → alerts}/Alert.repository.ts +2 -2
- package/src/{device/local/services → alerts}/Alert.service.ts +14 -7
- package/src/{device/local/entities → alerts}/AlertBuilder.example.ts +2 -2
- package/src/{device/local/entities → alerts}/AlertBuilder.ts +14 -8
- package/src/{device/local/services → alerts}/AlertService.example.ts +6 -5
- package/src/{types → alerts}/alert.types.ts +2 -2
- package/src/alerts/index.ts +3 -0
- package/src/config/config.ts +7 -7
- package/src/{types → config}/config.types.ts +1 -1
- package/src/{device/local/repository → connection}/Connection.repository.ts +2 -2
- package/src/{device/local/services → connection}/Connection.service.ts +2 -2
- package/src/connection/index.ts +3 -0
- package/src/device/cloud/entities/CloudDevice.ts +2 -2
- package/src/device/cloud/entities/CloudDeviceService.ts +1 -1
- package/src/device/cloud/entities/DeviceFactory.ts +2 -2
- package/src/device/cloud/interfaces/ICloudDeviceService.ts +1 -1
- package/src/device/cloud/interfaces/IRawDevice.ts +1 -1
- package/src/device/local/interfaces/index.ts +2 -3
- package/src/device/local/repository/Device.repository.ts +29 -3
- package/src/device/local/repository/Hub.repository.ts +4 -4
- package/src/device/local/repository/Schedule.repository.ts +2 -2
- package/src/device/local/services/Device.service.ts +5 -1
- package/src/device/local/services/index.ts +0 -4
- package/{TROUBLESHOOTING.md → src/docs/TROUBLESHOOTING.md} +2 -2
- package/src/events/BaseEventHandler.ts +3 -3
- package/src/events/BaseEventTransformer.ts +2 -2
- package/src/events/DeviceEventHandler.ts +3 -3
- package/src/events/EventHandler.ts +1 -1
- package/src/events/EventHandlerOrchestrator.ts +2 -2
- package/src/events/EventProcessingService.ts +2 -2
- package/src/events/InternalEventSubscription.ts +2 -2
- package/src/index.ts +19 -13
- package/src/{device/local/models → issues}/Issue.model.ts +1 -1
- package/src/{device/local/repository → issues}/Issue.repository.ts +2 -2
- package/src/{device/local/services → issues}/Issue.service.ts +4 -4
- package/src/{device/local/entities → issues}/IssueBuilder.example.ts +1 -1
- package/src/{device/local/entities → issues}/IssueBuilder.ts +1 -1
- package/src/{device/local/services → issues}/IssueService.example.ts +6 -5
- package/src/issues/index.ts +2 -0
- package/src/{device/local/repository → property}/Property.repository.ts +2 -2
- package/src/{device/local/services → property}/Property.service.ts +1 -1
- package/src/property/index.ts +2 -0
- package/src/queue/entities/HybridHttpQueue.ts +196 -0
- package/src/queue/entities/index.ts +1 -0
- package/src/queue/index.ts +6 -0
- package/src/queue/interfaces/IHttpRequestJob.ts +10 -0
- package/src/queue/interfaces/IHybridHttpQueue.ts +23 -0
- package/src/queue/interfaces/IJobResult.ts +6 -0
- package/src/queue/interfaces/IRateLimitConfig.ts +5 -0
- package/src/queue/interfaces/index.ts +4 -0
- package/src/queue/services/QueueService.ts +39 -0
- package/src/queue/services/index.ts +1 -0
- package/src/queue/types/http.types.ts +22 -0
- package/src/queue/types/index.ts +2 -0
- package/src/queue/types/queue.types.ts +22 -0
- package/src/queue/utils/index.ts +3 -0
- package/src/queue/utils/jobUtils.ts +80 -0
- package/src/queue/utils/queueUtils.ts +90 -0
- package/src/queue/utils/rateLimit.utils.ts +58 -0
- package/tsconfig.json +4 -0
- package/src/device/local/entities/README.md +0 -173
- package/src/device/local/entities/index.ts +0 -2
- package/src/types/index.ts +0 -3
- /package/src/{device/local/interfaces → connection}/IConnection.ts +0 -0
- /package/src/{device/local/models → docs}/Alert.model.md +0 -0
- /package/src/{device/local/models/README.md → docs/Alerts&IssuesModel.md} +0 -0
- /package/src/{device/local/models → docs}/Issue.model.md +0 -0
- /package/{SECURITY.md → src/docs/SECURITY.md} +0 -0
- /package/src/{types → issues}/issue.types.ts +0 -0
- /package/src/{device/local/interfaces → property}/IProperty.ts +0 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.QueueUtils = void 0;
|
|
4
|
+
const config_1 = require("../../config/config");
|
|
5
|
+
class QueueUtils {
|
|
6
|
+
static getQueueKey(microservice, connectionId, provider) {
|
|
7
|
+
return `${microservice}_${provider}_${connectionId}`;
|
|
8
|
+
}
|
|
9
|
+
static getOrCreateQueue(queueKey, queues) {
|
|
10
|
+
return (queues.get(queueKey) ??
|
|
11
|
+
queues
|
|
12
|
+
.set(queueKey, new (require("bullmq").Queue)(queueKey, {
|
|
13
|
+
connection: require("../../db/redis").getRedisClient(),
|
|
14
|
+
}))
|
|
15
|
+
.get(queueKey));
|
|
16
|
+
}
|
|
17
|
+
static getOrCreateWorker(queueKey, workers, processFunction, jobResults) {
|
|
18
|
+
if (workers.has(queueKey))
|
|
19
|
+
return;
|
|
20
|
+
const { Worker } = require("bullmq");
|
|
21
|
+
const worker = new Worker(queueKey, processFunction, {
|
|
22
|
+
connection: require("../../db/redis").getRedisClient(),
|
|
23
|
+
concurrency: 1,
|
|
24
|
+
removeOnComplete: { age: 300, count: 1 },
|
|
25
|
+
removeOnFail: { age: 300, count: 1 },
|
|
26
|
+
lockDuration: 300000,
|
|
27
|
+
stalledInterval: 60000,
|
|
28
|
+
});
|
|
29
|
+
// Simplified event handlers
|
|
30
|
+
worker.on("completed", (job) => {
|
|
31
|
+
(0, config_1.getConfig)().LOGGER.info(`HTTP request completed: ${job.id} [${queueKey}]`);
|
|
32
|
+
job.returnvalue
|
|
33
|
+
.then((result) => jobResults.set(job.id, {
|
|
34
|
+
result,
|
|
35
|
+
resolved: true,
|
|
36
|
+
timestamp: Date.now(),
|
|
37
|
+
}))
|
|
38
|
+
.catch((error) => jobResults.set(job.id, {
|
|
39
|
+
error: error.message,
|
|
40
|
+
resolved: true,
|
|
41
|
+
timestamp: Date.now(),
|
|
42
|
+
}));
|
|
43
|
+
});
|
|
44
|
+
worker.on("failed", (job, err) => {
|
|
45
|
+
(0, config_1.getConfig)().LOGGER.error(`HTTP request failed: ${job?.id} [${queueKey}], Error: ${err.message}`);
|
|
46
|
+
jobResults.set(job.id, {
|
|
47
|
+
error: err.message,
|
|
48
|
+
resolved: true,
|
|
49
|
+
timestamp: Date.now(),
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
worker.on("error", (err) => (0, config_1.getConfig)().LOGGER.error(`Worker error for ${queueKey}: ${err.message}`));
|
|
53
|
+
worker.on("stalled", (jobId) => (0, config_1.getConfig)().LOGGER.warn(`Job ${jobId} stalled in worker ${queueKey}`));
|
|
54
|
+
worker.on("active", (job) => (0, config_1.getConfig)().LOGGER.info(`HTTP request started: ${job.id} [${queueKey}]`));
|
|
55
|
+
workers.set(queueKey, worker);
|
|
56
|
+
(0, config_1.getConfig)().LOGGER.info(`Worker initialized for queue: ${queueKey}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
exports.QueueUtils = QueueUtils;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { IRateLimitConfig } from "../interfaces";
|
|
2
|
+
export declare class RateLimitUtils {
|
|
3
|
+
private static redisClient;
|
|
4
|
+
static checkRateLimit(connectionId: string, provider: string, rateLimitConfigs: Map<string, IRateLimitConfig>): Promise<boolean>;
|
|
5
|
+
static initializeRateLimitConfigs(): Map<string, IRateLimitConfig>;
|
|
6
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RateLimitUtils = void 0;
|
|
4
|
+
const redis_1 = require("../../db/redis");
|
|
5
|
+
const config_1 = require("../../config/config");
|
|
6
|
+
class RateLimitUtils {
|
|
7
|
+
static async checkRateLimit(connectionId, provider, rateLimitConfigs) {
|
|
8
|
+
const config = rateLimitConfigs.get(provider);
|
|
9
|
+
if (!config) {
|
|
10
|
+
(0, config_1.getConfig)().LOGGER.warn(`No rate limit config found for provider: ${provider}`);
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
const key = `rate_limit:${provider}:${connectionId}`;
|
|
14
|
+
const now = Date.now();
|
|
15
|
+
const windowStart = now - config.windowMs;
|
|
16
|
+
try {
|
|
17
|
+
const data = await this.redisClient.get(key);
|
|
18
|
+
const requests = data
|
|
19
|
+
? JSON.parse(data).filter((t) => t > windowStart)
|
|
20
|
+
: [];
|
|
21
|
+
if (requests.length >= config.maxRequests)
|
|
22
|
+
return false;
|
|
23
|
+
requests.push(now);
|
|
24
|
+
await this.redisClient.setex(key, Math.ceil(config.windowMs / 1000), JSON.stringify(requests));
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
(0, config_1.getConfig)().LOGGER.error(`Rate limit check error: ${error}`);
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
static initializeRateLimitConfigs() {
|
|
33
|
+
const configs = new Map();
|
|
34
|
+
// Configure rate limits for different providers
|
|
35
|
+
configs.set("Sensibo", {
|
|
36
|
+
maxRequests: 40,
|
|
37
|
+
windowMs: 60000,
|
|
38
|
+
provider: "Sensibo",
|
|
39
|
+
});
|
|
40
|
+
return configs;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
exports.RateLimitUtils = RateLimitUtils;
|
|
44
|
+
RateLimitUtils.redisClient = (0, redis_1.getRedisClient)();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dt-common-device",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"scripts": {
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"axios": "1.10.0",
|
|
42
|
+
"bullmq": "5.56.4",
|
|
42
43
|
"dt-audit-library": "^1.0.3",
|
|
43
44
|
"dt-pub-sub": "^1.0.0",
|
|
44
45
|
"ioredis": "5.6.1",
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { Service } from "typedi";
|
|
2
|
-
import { AlertModel, IAlertDocument } from "
|
|
2
|
+
import { AlertModel, IAlertDocument } from "./Alert.model";
|
|
3
3
|
import {
|
|
4
4
|
CreateAlertData,
|
|
5
5
|
UpdateAlertData,
|
|
6
6
|
AlertCategory,
|
|
7
7
|
AlertSeverity,
|
|
8
8
|
EntityType,
|
|
9
|
-
} from "
|
|
9
|
+
} from "./alert.types";
|
|
10
10
|
|
|
11
11
|
@Service()
|
|
12
12
|
export class AlertRepository {
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { Service } from "typedi";
|
|
2
|
-
import { AlertRepository } from "
|
|
3
|
-
import { AlertModel, IAlertDocument } from "
|
|
2
|
+
import { AlertRepository } from "./Alert.repository";
|
|
3
|
+
import { AlertModel, IAlertDocument } from "./Alert.model";
|
|
4
4
|
import {
|
|
5
5
|
CreateAlertData,
|
|
6
6
|
UpdateAlertData,
|
|
7
7
|
AlertCategory,
|
|
8
8
|
AlertSeverity,
|
|
9
9
|
EntityType,
|
|
10
|
-
} from "
|
|
11
|
-
import { AlertBuilder } from "
|
|
10
|
+
} from "./alert.types";
|
|
11
|
+
import { AlertBuilder } from "./AlertBuilder";
|
|
12
12
|
|
|
13
13
|
@Service()
|
|
14
14
|
export class AlertService {
|
|
@@ -156,7 +156,9 @@ export class AlertService {
|
|
|
156
156
|
* Create a new alert with business logic validation
|
|
157
157
|
* Accepts either a CreateAlertData object or an AlertBuilder instance
|
|
158
158
|
*/
|
|
159
|
-
async createAlert(
|
|
159
|
+
async createAlert(
|
|
160
|
+
alertData: CreateAlertData | AlertBuilder
|
|
161
|
+
): Promise<IAlertDocument> {
|
|
160
162
|
let processedAlertData: CreateAlertData;
|
|
161
163
|
|
|
162
164
|
// Handle AlertBuilder instance
|
|
@@ -171,11 +173,16 @@ export class AlertService {
|
|
|
171
173
|
|
|
172
174
|
// Business logic: Set default severity if not provided
|
|
173
175
|
if (!processedAlertData.severity) {
|
|
174
|
-
processedAlertData.severity = this.determineDefaultSeverity(
|
|
176
|
+
processedAlertData.severity = this.determineDefaultSeverity(
|
|
177
|
+
processedAlertData.category
|
|
178
|
+
);
|
|
175
179
|
}
|
|
176
180
|
|
|
177
181
|
// Business logic: Validate snooze date is in the future
|
|
178
|
-
if (
|
|
182
|
+
if (
|
|
183
|
+
processedAlertData.snoozeUntil &&
|
|
184
|
+
processedAlertData.snoozeUntil <= new Date()
|
|
185
|
+
) {
|
|
179
186
|
throw new Error("Snooze date must be in the future");
|
|
180
187
|
}
|
|
181
188
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AlertBuilder } from "./AlertBuilder";
|
|
2
|
-
import { AlertCategory, AlertSeverity, EntityType } from "
|
|
2
|
+
import { AlertCategory, AlertSeverity, EntityType } from "./alert.types";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Example usage of AlertBuilder
|
|
@@ -123,4 +123,4 @@ export function createMultipleAlerts() {
|
|
|
123
123
|
.build();
|
|
124
124
|
|
|
125
125
|
return [alert1, alert2];
|
|
126
|
-
}
|
|
126
|
+
}
|
|
@@ -3,15 +3,15 @@ import {
|
|
|
3
3
|
AlertCategory,
|
|
4
4
|
AlertSeverity,
|
|
5
5
|
EntityType,
|
|
6
|
-
} from "
|
|
6
|
+
} from "./alert.types";
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* AlertBuilder - A builder pattern implementation for constructing CreateAlertData objects
|
|
10
|
-
*
|
|
10
|
+
*
|
|
11
11
|
* This builder provides a fluent interface for creating alert data with proper validation
|
|
12
12
|
* and default values. It follows the Builder pattern which is a standard design pattern
|
|
13
13
|
* in TypeScript for constructing complex objects.
|
|
14
|
-
*
|
|
14
|
+
*
|
|
15
15
|
* Usage example:
|
|
16
16
|
* const alertData = new AlertBuilder()
|
|
17
17
|
* .setCategory(AlertCategory.OPERATIONS)
|
|
@@ -120,8 +120,16 @@ export class AlertBuilder {
|
|
|
120
120
|
* Validates that all required fields are present
|
|
121
121
|
*/
|
|
122
122
|
private validate(): void {
|
|
123
|
-
const requiredFields = [
|
|
124
|
-
|
|
123
|
+
const requiredFields = [
|
|
124
|
+
"category",
|
|
125
|
+
"propertyId",
|
|
126
|
+
"title",
|
|
127
|
+
"description",
|
|
128
|
+
"entityType",
|
|
129
|
+
];
|
|
130
|
+
const missingFields = requiredFields.filter(
|
|
131
|
+
(field) => !this.data[field as keyof CreateAlertData]
|
|
132
|
+
);
|
|
125
133
|
|
|
126
134
|
if (missingFields.length > 0) {
|
|
127
135
|
throw new Error(`Missing required fields: ${missingFields.join(", ")}`);
|
|
@@ -197,6 +205,4 @@ export class AlertBuilder {
|
|
|
197
205
|
.setEntityId(hubId)
|
|
198
206
|
.setPropertyId(propertyId);
|
|
199
207
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
}
|
|
208
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AlertService } from "./Alert.service";
|
|
2
|
-
import { AlertBuilder } from "
|
|
3
|
-
import { AlertCategory, AlertSeverity, EntityType } from "
|
|
2
|
+
import { AlertBuilder } from "./AlertBuilder";
|
|
3
|
+
import { AlertCategory, AlertSeverity, EntityType } from "./alert.types";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Example usage of the updated AlertService with AlertBuilder integration
|
|
@@ -215,15 +215,16 @@ export class AlertServiceExample {
|
|
|
215
215
|
category: AlertCategory.OPERATIONS,
|
|
216
216
|
propertyId: "prop123",
|
|
217
217
|
title: "Legacy Alert",
|
|
218
|
-
description:
|
|
218
|
+
description:
|
|
219
|
+
"This alert was created using the old CreateAlertData format",
|
|
219
220
|
entityId: "device456",
|
|
220
221
|
entityType: EntityType.DEVICE,
|
|
221
222
|
severity: AlertSeverity.MEDIUM,
|
|
222
|
-
createdBy: "legacy-system"
|
|
223
|
+
createdBy: "legacy-system",
|
|
223
224
|
};
|
|
224
225
|
|
|
225
226
|
// This still works with the updated createAlert method
|
|
226
227
|
const alert = await this.alertService.createAlert(alertData);
|
|
227
228
|
return alert;
|
|
228
229
|
}
|
|
229
|
-
}
|
|
230
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { EntityType } from "
|
|
1
|
+
import { EntityType } from "../issues/issue.types";
|
|
2
2
|
|
|
3
3
|
export enum AlertCategory {
|
|
4
4
|
READINESS = "READINESS",
|
|
@@ -61,4 +61,4 @@ export interface UpdateAlertData {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
// Re-export EntityType from issue.types.ts to avoid duplication
|
|
64
|
-
export { EntityType } from "
|
|
64
|
+
export { EntityType } from "../issues/issue.types";
|
package/src/config/config.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { DeviceConfig } from "../types";
|
|
2
1
|
import { initializeAudit } from "dt-audit-library";
|
|
3
|
-
import { connectDatabase } from "
|
|
2
|
+
import { connectDatabase } from "src/db/db";
|
|
4
3
|
import dotenv from "dotenv";
|
|
5
|
-
import { InternalEventSubscription } from "
|
|
6
|
-
import { validateServiceUrl } from "
|
|
4
|
+
import { InternalEventSubscription } from "src/events";
|
|
5
|
+
import { validateServiceUrl } from "src/utils/http.utils";
|
|
6
|
+
import { IConfig } from "./config.types";
|
|
7
7
|
|
|
8
8
|
dotenv.config();
|
|
9
9
|
|
|
10
|
-
let config:
|
|
10
|
+
let config: IConfig | null = null;
|
|
11
11
|
let auditInitialized = false;
|
|
12
12
|
let eventSubscription: InternalEventSubscription | null = null;
|
|
13
13
|
|
|
14
|
-
export async function initialize(cfg:
|
|
14
|
+
export async function initialize(cfg: IConfig): Promise<void> {
|
|
15
15
|
// Initialize config
|
|
16
16
|
config = { ...cfg };
|
|
17
17
|
|
|
@@ -77,7 +77,7 @@ export async function initialize(cfg: DeviceConfig): Promise<void> {
|
|
|
77
77
|
console.log("dt-common-device: Initialization completed successfully");
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
export function getConfig():
|
|
80
|
+
export function getConfig(): IConfig {
|
|
81
81
|
if (!config) {
|
|
82
82
|
throw new Error(
|
|
83
83
|
"dt-common-device: Library not initialized. Call initialize() first."
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Container } from "typedi";
|
|
2
|
-
import { ConnectionRepository } from "
|
|
3
|
-
import { IConnection } from "
|
|
2
|
+
import { ConnectionRepository } from "./Connection.repository";
|
|
3
|
+
import { IConnection } from "./IConnection";
|
|
4
4
|
|
|
5
5
|
export class LocalConnectionService {
|
|
6
6
|
private readonly connectionRepository: ConnectionRepository;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { IDevice } from "
|
|
1
|
+
import { IDevice } from "src/device/local/interfaces";
|
|
2
2
|
import { ICloudDevice } from "../interfaces/ICloudDevice";
|
|
3
3
|
import { ICloudDeviceService } from "../interfaces/ICloudDeviceService";
|
|
4
|
-
import { IConnection } from "
|
|
4
|
+
import { IConnection } from "src/connection";
|
|
5
5
|
|
|
6
6
|
export abstract class CloudDevice implements ICloudDevice {
|
|
7
7
|
deviceId: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ICloudDeviceService } from "../interfaces/ICloudDeviceService";
|
|
2
|
-
import { IConnection } from "
|
|
2
|
+
import { IConnection } from "src/connection";
|
|
3
3
|
|
|
4
4
|
export class CloudDeviceService implements ICloudDeviceService {
|
|
5
5
|
async getConnection(deviceId: string): Promise<IConnection> {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { IDevice } from "
|
|
2
|
-
import { LocalDeviceService } from "
|
|
1
|
+
import { IDevice } from "src/device/local/interfaces";
|
|
2
|
+
import { LocalDeviceService } from "src/device/local/services/Device.service";
|
|
3
3
|
import { IDeviceFactory } from "../interfaces/IDeviceFactory";
|
|
4
4
|
|
|
5
5
|
export class DeviceFactory implements IDeviceFactory {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { IDevice, IStatus } from "../interfaces/IDevice";
|
|
2
|
-
import { getConfig } from "
|
|
3
|
-
import { getPostgresClient } from "
|
|
2
|
+
import { getConfig } from "src/config/config";
|
|
3
|
+
import { getPostgresClient } from "src/db";
|
|
4
4
|
import { Service } from "typedi";
|
|
5
5
|
import { IDtDevice } from "../interfaces/IDtDevice";
|
|
6
|
-
import { getDeviceServiceAxiosInstance } from "
|
|
6
|
+
import { getDeviceServiceAxiosInstance } from "src/utils/http.utils";
|
|
7
7
|
|
|
8
8
|
@Service()
|
|
9
9
|
export class DeviceRepository {
|
|
@@ -44,6 +44,32 @@ export class DeviceRepository {
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
async updateDevice(deviceId: string, body: any): Promise<IDevice> {
|
|
48
|
+
try {
|
|
49
|
+
const response = await this.axiosInstance.put(
|
|
50
|
+
`/devices/${deviceId}`,
|
|
51
|
+
body
|
|
52
|
+
);
|
|
53
|
+
return response.data;
|
|
54
|
+
} catch (error: any) {
|
|
55
|
+
getConfig().LOGGER.error(`Failed to update device ${deviceId}:`, error);
|
|
56
|
+
throw new Error(
|
|
57
|
+
`Failed to update device: ${error.message || "Unknown error"}`
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async deleteDevice(deviceId: string): Promise<void> {
|
|
63
|
+
try {
|
|
64
|
+
await this.axiosInstance.delete(`/devices/${deviceId}`);
|
|
65
|
+
} catch (error: any) {
|
|
66
|
+
getConfig().LOGGER.error(`Failed to delete device ${deviceId}:`, error);
|
|
67
|
+
throw new Error(
|
|
68
|
+
`Failed to delete device: ${error.message || "Unknown error"}`
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
47
73
|
async getDevices(
|
|
48
74
|
deviceIds: string[],
|
|
49
75
|
withHubDetails: boolean = false
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { getConfig } from "
|
|
2
|
-
import { getPostgresClient } from "
|
|
1
|
+
import { getConfig } from "src/config/config";
|
|
2
|
+
import { getPostgresClient } from "src/db";
|
|
3
3
|
import { Service } from "typedi";
|
|
4
4
|
import { IDevice } from "../interfaces";
|
|
5
|
-
import { getDeviceServiceAxiosInstance } from "
|
|
5
|
+
import { getDeviceServiceAxiosInstance } from "src/utils/http.utils";
|
|
6
6
|
|
|
7
7
|
@Service()
|
|
8
8
|
export class HubRepository {
|
|
@@ -26,7 +26,7 @@ export class HubRepository {
|
|
|
26
26
|
|
|
27
27
|
async getHubs(hubIds: string[]): Promise<IDevice[]> {
|
|
28
28
|
try {
|
|
29
|
-
const query = hubIds
|
|
29
|
+
const query = hubIds?.length ? `?ids=${hubIds.join(",")}` : "";
|
|
30
30
|
const response = await this.axiosInstance.get(`/devices/hubs${query}`);
|
|
31
31
|
return response.data;
|
|
32
32
|
} catch (error: any) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Service } from "typedi";
|
|
2
|
-
import { getConfig } from "
|
|
2
|
+
import { getConfig } from "src/config/config";
|
|
3
3
|
import { ISchedule } from "../interfaces/ISchedule";
|
|
4
|
-
import { getDeviceServiceAxiosInstance } from "
|
|
4
|
+
import { getDeviceServiceAxiosInstance } from "src/utils/http.utils";
|
|
5
5
|
|
|
6
6
|
@Service()
|
|
7
7
|
export class ScheduleRepository {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IDevice, IStatus } from "../interfaces";
|
|
2
|
-
import { EventHandler } from "
|
|
2
|
+
import { EventHandler } from "src/events/EventHandler";
|
|
3
3
|
import { isEqual } from "lodash";
|
|
4
4
|
import { DeviceRepository } from "../repository/Device.repository";
|
|
5
5
|
import Container from "typedi";
|
|
@@ -74,6 +74,8 @@ export class LocalDeviceService {
|
|
|
74
74
|
if (!deviceId) {
|
|
75
75
|
throw new Error("Device ID is required");
|
|
76
76
|
}
|
|
77
|
+
|
|
78
|
+
await this.deviceRepository.updateDevice(deviceId, body);
|
|
77
79
|
return await this.eventHandler.onDeviceUpdate(deviceId, body);
|
|
78
80
|
}
|
|
79
81
|
|
|
@@ -81,6 +83,8 @@ export class LocalDeviceService {
|
|
|
81
83
|
if (!deviceId) {
|
|
82
84
|
throw new Error("Device ID is required");
|
|
83
85
|
}
|
|
86
|
+
|
|
87
|
+
await this.deviceRepository.deleteDevice(deviceId);
|
|
84
88
|
return await this.eventHandler.onDeviceDelete(deviceId);
|
|
85
89
|
}
|
|
86
90
|
|
|
@@ -20,7 +20,7 @@ This error typically occurs when HTTP requests fail due to network connectivity
|
|
|
20
20
|
|
|
21
21
|
```typescript
|
|
22
22
|
// Ensure DEVICE_SERVICE URL is properly configured
|
|
23
|
-
const config:
|
|
23
|
+
const config: IConfig = {
|
|
24
24
|
DEVICE_SERVICE: "http://localhost:3000", // or your actual service URL
|
|
25
25
|
// ... other config
|
|
26
26
|
};
|
|
@@ -41,7 +41,7 @@ This error typically occurs when HTTP requests fail due to network connectivity
|
|
|
41
41
|
|
|
42
42
|
4. **Enable Debug Logging**
|
|
43
43
|
```typescript
|
|
44
|
-
const config:
|
|
44
|
+
const config: IConfig = {
|
|
45
45
|
LOGGER: {
|
|
46
46
|
info: (msg, ...args) => console.log(msg, ...args),
|
|
47
47
|
warn: (msg, ...args) => console.warn(msg, ...args),
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { DeviceEvent } from "./interfaces/DeviceEvent";
|
|
2
2
|
import { IEventHandler } from "./interfaces/IEventHandler";
|
|
3
|
-
import { getConfig } from "
|
|
4
|
-
import { ILogger } from "
|
|
5
|
-
import { LocalDeviceService } from "
|
|
3
|
+
import { getConfig } from "src/config/config";
|
|
4
|
+
import { ILogger } from "src/config/config.types";
|
|
5
|
+
import { LocalDeviceService } from "src/device/local/services/Device.service";
|
|
6
6
|
|
|
7
7
|
export abstract class BaseEventHandler implements IEventHandler {
|
|
8
8
|
protected readonly supportedEventTypes: string[];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { getConfig } from "
|
|
2
|
-
import { ILogger } from "
|
|
1
|
+
import { getConfig } from "src/config/config";
|
|
2
|
+
import { ILogger } from "src/config/config.types";
|
|
3
3
|
import { DeviceEvent } from "./interfaces/DeviceEvent";
|
|
4
4
|
import { IEventTransformer } from "./interfaces/IEventTransformer";
|
|
5
5
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { DT_EVENT_TYPES } from "
|
|
2
|
-
import { IDevice } from "
|
|
3
|
-
import { LocalHubService } from "
|
|
1
|
+
import { DT_EVENT_TYPES } from "src/constants/Event";
|
|
2
|
+
import { IDevice } from "src/device/local/interfaces";
|
|
3
|
+
import { LocalHubService } from "src/device/local/services";
|
|
4
4
|
import { BaseEventHandler } from "./BaseEventHandler";
|
|
5
5
|
import {
|
|
6
6
|
DeviceEvent,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { eventDispatcher } from "dt-pub-sub";
|
|
2
2
|
import { publishAudit } from "dt-audit-library";
|
|
3
|
-
import { DT_EVENT_TYPES } from "
|
|
3
|
+
import { DT_EVENT_TYPES } from "src/constants/Event";
|
|
4
4
|
|
|
5
5
|
export class EventHandler {
|
|
6
6
|
private readonly source: string;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Service } from "typedi";
|
|
2
2
|
import { IEventHandler } from "./interfaces/IEventHandler";
|
|
3
3
|
import { DeviceEvent } from "./interfaces/DeviceEvent";
|
|
4
|
-
import { ILogger } from "
|
|
5
|
-
import { getConfig } from "
|
|
4
|
+
import { ILogger } from "src/config/config.types";
|
|
5
|
+
import { getConfig } from "src/config/config";
|
|
6
6
|
|
|
7
7
|
@Service()
|
|
8
8
|
export class EventHandlerOrchestrator {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Service } from "typedi";
|
|
2
2
|
import { DeviceEventHandler } from "./DeviceEventHandler";
|
|
3
|
-
import { ILogger } from "
|
|
4
|
-
import { getConfig } from "
|
|
3
|
+
import { ILogger } from "src/config/config.types";
|
|
4
|
+
import { getConfig } from "src/config/config";
|
|
5
5
|
import { DeviceEvent } from "./interfaces/DeviceEvent";
|
|
6
6
|
import { IEventTransformer } from "./interfaces/IEventTransformer";
|
|
7
7
|
import { EventHandlerOrchestrator } from "./EventHandlerOrchestrator";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { eventDispatcher } from "dt-pub-sub";
|
|
2
|
-
import { getConfig } from "
|
|
2
|
+
import { getConfig } from "src/config/config";
|
|
3
3
|
import {
|
|
4
4
|
IInternalEvent,
|
|
5
5
|
HeartbeatEventData,
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
ReservationEventData,
|
|
8
8
|
ServiceEventData,
|
|
9
9
|
} from "./interfaces/IInternalEvent";
|
|
10
|
-
import { ILogger } from "
|
|
10
|
+
import { ILogger } from "src/config/config.types";
|
|
11
11
|
|
|
12
12
|
// Event types enum for better type safety
|
|
13
13
|
export enum InternalEventType {
|