dt-common-device
Version:
A secure and robust device management library for IoT applications
514 lines (513 loc) • 24.1 kB
JavaScript
;
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
var _, done = false;
for (var i = decorators.length - 1; i >= 0; i--) {
var context = {};
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
if (kind === "accessor") {
if (result === void 0) continue;
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
if (_ = accept(result.get)) descriptor.get = _;
if (_ = accept(result.set)) descriptor.set = _;
if (_ = accept(result.init)) initializers.unshift(_);
}
else if (_ = accept(result)) {
if (kind === "field") initializers.unshift(_);
else descriptor[key] = _;
}
}
if (target) Object.defineProperty(target, contextIn.name, descriptor);
done = true;
};
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
var useValue = arguments.length > 2;
for (var i = 0; i < initializers.length; i++) {
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
}
return useValue ? value : void 0;
};
var __setFunctionName = (this && this.__setFunctionName) || function (f, name, prefix) {
if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AlertService = void 0;
const typedi_1 = require("typedi");
const Alert_model_1 = require("./Alert.model");
const alert_types_1 = require("./alert.types");
const AlertBuilder_1 = require("./AlertBuilder");
let AlertService = (() => {
let _classDecorators = [(0, typedi_1.Service)()];
let _classDescriptor;
let _classExtraInitializers = [];
let _classThis;
var AlertService = _classThis = class {
constructor(alertRepository) {
this.alertRepository = alertRepository;
}
/**
* Create a readiness alert using AlertBuilder
*/
async raiseReadinessAlert(propertyId, title, description, entityId, entityType, createdBy) {
const alertBuilder = AlertBuilder_1.AlertBuilder.createReadinessAlert()
.setPropertyId(propertyId)
.setTitle(title)
.setDescription(description);
if (entityId)
alertBuilder.setEntityId(entityId);
if (entityType)
alertBuilder.setEntityType(entityType);
if (createdBy)
alertBuilder.setCreatedBy(createdBy);
return await this.createAlert(alertBuilder);
}
/**
* Create an operations alert using AlertBuilder
*/
async raiseOperationsAlert(propertyId, title, description, entityId, entityType, createdBy) {
const alertBuilder = AlertBuilder_1.AlertBuilder.createOperationsAlert()
.setPropertyId(propertyId)
.setTitle(title)
.setDescription(description);
if (entityId)
alertBuilder.setEntityId(entityId);
if (entityType)
alertBuilder.setEntityType(entityType);
if (createdBy)
alertBuilder.setCreatedBy(createdBy);
return await this.createAlert(alertBuilder);
}
/**
* Create a security alert using AlertBuilder
*/
async raiseSecurityAlert(propertyId, title, description, entityId, entityType, createdBy) {
const alertBuilder = AlertBuilder_1.AlertBuilder.createSecurityAlert()
.setPropertyId(propertyId)
.setTitle(title)
.setDescription(description);
if (entityId)
alertBuilder.setEntityId(entityId);
if (entityType)
alertBuilder.setEntityType(entityType);
if (createdBy)
alertBuilder.setCreatedBy(createdBy);
return await this.createAlert(alertBuilder);
}
/**
* Create an energy alert using AlertBuilder
*/
async raiseEnergyAlert(propertyId, title, description, entityId, entityType, createdBy) {
const alertBuilder = AlertBuilder_1.AlertBuilder.createEnergyAlert()
.setPropertyId(propertyId)
.setTitle(title)
.setDescription(description);
if (entityId)
alertBuilder.setEntityId(entityId);
if (entityType)
alertBuilder.setEntityType(entityType);
if (createdBy)
alertBuilder.setCreatedBy(createdBy);
return await this.createAlert(alertBuilder);
}
/**
* Create a device-specific alert using AlertBuilder
*/
async raiseDeviceAlert(deviceId, propertyId, title, description, category, severity, source) {
const alertBuilder = AlertBuilder_1.AlertBuilder.createDeviceAlert(deviceId, propertyId)
.setTitle(title)
.setDescription(description);
if (category)
alertBuilder.setCategory(category);
if (severity)
alertBuilder.setSeverity(severity);
if (source)
alertBuilder.setCreatedBy(source);
return await this.createAlert(alertBuilder);
}
/**
* Create a hub-specific alert using AlertBuilder
*/
async raiseHubAlert(hubId, propertyId, title, description, category, severity, createdBy) {
const alertBuilder = AlertBuilder_1.AlertBuilder.createHubAlert(hubId, propertyId)
.setTitle(title)
.setDescription(description);
if (category)
alertBuilder.setCategory(category);
if (severity)
alertBuilder.setSeverity(severity);
if (createdBy)
alertBuilder.setCreatedBy(createdBy);
return await this.createAlert(alertBuilder);
}
/**
* Raise alert for device going offline (OPERATIONAL only)
*/
async raiseDeviceOfflineAlert(device, source, reason) {
return await this.raiseDeviceAlert(device.deviceId, device.propertyId, "Device Offline", `Device ${device.name} (${device.deviceId}) has gone offline. ${reason ? `Reason: ${reason}` : ""}`, [alert_types_1.AlertCategory.OPERATIONS], alert_types_1.AlertSeverity.HIGH, source);
}
/**
* Raise alert for device coming online (OPERATIONAL only)
*/
async raiseDeviceOnlineAlert(device, source, reason) {
return await this.raiseDeviceAlert(device.deviceId, device.propertyId, "Device Online", `Device ${device.name} (${device.deviceId}) is now online. ${reason ? `Reason: ${reason}` : ""}`, [alert_types_1.AlertCategory.OPERATIONS], alert_types_1.AlertSeverity.INFO, source);
}
/**
* Raise alert for device battery level below threshold (READINESS + OPERATIONAL + ENERGY)
*/
async raiseDeviceBatteryAlert(device, batteryLevel, threshold, source) {
return await this.raiseDeviceAlert(device.deviceId, device.propertyId, "Device Battery Low", `Device ${device.name} (${device.deviceId}) battery level is ${batteryLevel}%, which is below the property threshold of ${threshold}%.`, [alert_types_1.AlertCategory.READINESS, alert_types_1.AlertCategory.OPERATIONS, alert_types_1.AlertCategory.ENERGY], alert_types_1.AlertSeverity.MEDIUM, source);
}
/**
* Raise alert for device issue (jammed or malfunctioned) (READINESS + OPERATIONAL)
*/
async raiseDeviceIssueAlert(device, issueType, source, reason) {
return await this.raiseDeviceAlert(device.deviceId, device.propertyId, `Device Issue - ${issueType}`, `Device ${device.name} (${device.deviceId}) has an issue: ${issueType}. ${reason ? `Reason: ${reason}` : ""}`, [alert_types_1.AlertCategory.READINESS, alert_types_1.AlertCategory.OPERATIONS], alert_types_1.AlertSeverity.HIGH, source);
}
/**
* Create a new alert with business logic validation
* Accepts either a CreateAlertData object or an AlertBuilder instance
*/
async createAlert(alertData) {
let processedAlertData;
// Handle AlertBuilder instance
if (alertData instanceof AlertBuilder_1.AlertBuilder) {
processedAlertData = alertData.build();
}
else {
processedAlertData = alertData;
}
// Business logic: Validate alert data
this.validateAlertData(processedAlertData);
// Business logic: Set default severity if not provided
if (!processedAlertData.severity) {
processedAlertData.severity = this.determineDefaultSeverity(processedAlertData.category);
}
// Business logic: Validate snooze date is in the future
if (processedAlertData.snoozeUntil &&
processedAlertData.snoozeUntil <= new Date()) {
throw new Error("Snooze date must be in the future");
}
return await this.alertRepository.create(processedAlertData);
}
/**
* Get alert by ID with business logic
*/
async getAlertById(id, includeDeleted = false) {
if (!id) {
throw new Error("Alert ID is required");
}
const alert = await this.alertRepository.findById(id, includeDeleted);
// Business logic: Check if alert is snoozed and expired
if (alert?.snoozeUntil && alert.snoozeUntil <= new Date()) {
console.warn(`Alert ${id} snooze has expired`);
}
return alert;
}
/**
* Get all alerts with business logic filtering
*/
async getAlerts(filters = {}) {
// Business logic: Validate filters
this.validateFilters(filters);
// Business logic: Apply business rules to filters
const enhancedFilters = this.applyBusinessRules(filters);
return await this.alertRepository.findAll(enhancedFilters);
}
/**
* Update an alert with business logic validation
*/
async updateAlert(id, updateData) {
if (!id) {
throw new Error("Alert ID is required");
}
// Business logic: Validate update data
this.validateUpdateData(updateData);
// Business logic: Check if alert exists and is not deleted
const existingAlert = await this.alertRepository.findById(id);
if (!existingAlert) {
throw new Error("Alert not found");
}
// Business logic: Handle snooze validation
if (updateData.snoozeUntil) {
this.validateSnoozeDate(updateData.snoozeUntil);
}
return await this.alertRepository.update(id, updateData);
}
/**
* Soft delete an alert with business logic
*/
async deleteAlert(id, deletedBy) {
if (!id || !deletedBy) {
throw new Error("Alert ID and deleted by user are required");
}
// Business logic: Check if alert can be deleted
const alert = await this.alertRepository.findById(id);
if (!alert) {
throw new Error("Alert not found");
}
// Business logic: Prevent deletion of critical alerts (optional rule)
if (alert.severity === alert_types_1.AlertSeverity.CRITICAL) {
throw new Error("Cannot delete critical alerts");
}
return await this.alertRepository.softDelete(id, deletedBy);
}
/**
* Mark alert as read with business logic
*/
async markAsRead(id, updatedBy) {
if (!id || !updatedBy) {
throw new Error("Alert ID and updated by user are required");
}
const alertModel = await Alert_model_1.AlertModel.findById(id);
if (!alertModel)
return null;
alertModel.markAsRead(updatedBy);
return await alertModel.save();
}
/**
* Mark alert as unread with business logic
*/
async markAsUnread(id, updatedBy) {
if (!id || !updatedBy) {
throw new Error("Alert ID and updated by user are required");
}
const alertModel = await Alert_model_1.AlertModel.findById(id);
if (!alertModel)
return null;
alertModel.markAsUnread(updatedBy);
return await alertModel.save();
}
/**
* Activate an alert with business logic
*/
async activateAlert(id, updatedBy) {
if (!id || !updatedBy) {
throw new Error("Alert ID and updated by user are required");
}
const alertModel = await Alert_model_1.AlertModel.findById(id);
if (!alertModel)
return null;
alertModel.activate(updatedBy);
return await alertModel.save();
}
/**
* Deactivate an alert with business logic
*/
async deactivateAlert(id, updatedBy) {
if (!id || !updatedBy) {
throw new Error("Alert ID and updated by user are required");
}
const alertModel = await Alert_model_1.AlertModel.findById(id);
if (!alertModel)
return null;
alertModel.deactivate(updatedBy);
return await alertModel.save();
}
/**
* Snooze an alert with business logic
*/
async snoozeAlert(id, until, updatedBy) {
if (!id || !until || !updatedBy) {
throw new Error("Alert ID, snooze date, and updated by user are required");
}
// Business logic: Validate snooze date
this.validateSnoozeDate(until);
const alertModel = await Alert_model_1.AlertModel.findById(id);
if (!alertModel)
return null;
alertModel.snooze(until, updatedBy);
return await alertModel.save();
}
/**
* Unsnooze an alert with business logic
*/
async unsnoozeAlert(id, updatedBy) {
if (!id || !updatedBy) {
throw new Error("Alert ID and updated by user are required");
}
const alertModel = await Alert_model_1.AlertModel.findById(id);
if (!alertModel)
return null;
alertModel.unsnooze(updatedBy);
return await alertModel.save();
}
/**
* Get alerts by property with business logic
*/
async getAlertsByProperty(propertyId, includeDeleted = false) {
if (!propertyId) {
throw new Error("Property ID is required");
}
return await this.alertRepository.findByProperty(propertyId, includeDeleted);
}
/**
* Get alerts by entity with business logic
*/
async getAlertsByEntity(entityId, entityType, includeDeleted = false) {
if (!entityId || !entityType) {
throw new Error("Entity ID and entity type are required");
}
return await this.alertRepository.findByEntity(entityId, entityType, includeDeleted);
}
/**
* Get alerts by category with business logic
*/
async getAlertsByCategory(category, includeDeleted = false) {
if (!category) {
throw new Error("Alert category is required");
}
return await this.alertRepository.findByCategory(category, includeDeleted);
}
/**
* Get alerts by severity with business logic
*/
async getAlertsBySeverity(severity, includeDeleted = false) {
if (!severity) {
throw new Error("Alert severity is required");
}
return await this.alertRepository.findBySeverity(severity, includeDeleted);
}
/**
* Get active alerts with business logic
*/
async getActiveAlerts(includeDeleted = false) {
const activeAlerts = await this.alertRepository.findActive(includeDeleted);
// Business logic: Log active alerts for monitoring
if (activeAlerts.length > 0) {
console.log(`Found ${activeAlerts.length} active alerts`);
}
return activeAlerts;
}
/**
* Get unread alerts with business logic
*/
async getUnreadAlerts(includeDeleted = false) {
const unreadAlerts = await this.alertRepository.findUnread(includeDeleted);
// Business logic: Log unread alerts for monitoring
if (unreadAlerts.length > 0) {
console.warn(`Found ${unreadAlerts.length} unread alerts`);
}
return unreadAlerts;
}
/**
* Get snoozed alerts with business logic
*/
async getSnoozedAlerts(includeDeleted = false) {
return await this.alertRepository.findSnoozed(includeDeleted);
}
/**
* Get expired snooze alerts with business logic
*/
async getExpiredSnoozeAlerts(includeDeleted = false) {
const expiredAlerts = await this.alertRepository.findExpiredSnooze(includeDeleted);
// Business logic: Log expired snooze alerts
if (expiredAlerts.length > 0) {
console.warn(`Found ${expiredAlerts.length} alerts with expired snooze`);
}
return expiredAlerts;
}
/**
* Get alert statistics with business logic
*/
async getAlertStatistics(propertyId) {
const stats = await this.alertRepository.getStatistics(propertyId);
// Business logic: Add alerts for critical metrics
if (stats.unread > 0) {
console.warn(`Alert: ${stats.unread} unread alerts require attention`);
}
if (stats.bySeverity[alert_types_1.AlertSeverity.CRITICAL] > 0) {
console.error(`Alert: ${stats.bySeverity[alert_types_1.AlertSeverity.CRITICAL]} critical alerts require immediate attention`);
}
if (stats.bySeverity[alert_types_1.AlertSeverity.HIGH] > 0) {
console.warn(`Alert: ${stats.bySeverity[alert_types_1.AlertSeverity.HIGH]} high severity alerts require attention`);
}
return stats;
}
// Private business logic methods
validateAlertData(data) {
if (!data.title || data.title.trim().length < 3) {
throw new Error("Alert title must be at least 3 characters long");
}
if (!data.description || data.description.trim().length < 5) {
throw new Error("Alert description must be at least 5 characters long");
}
if (!data.propertyId) {
throw new Error("Property ID is required");
}
if (!data.entityType) {
throw new Error("Entity type is required");
}
}
validateFilters(filters) {
if (filters.limit && (filters.limit < 1 || filters.limit > 100)) {
throw new Error("Limit must be between 1 and 100");
}
if (filters.skip && filters.skip < 0) {
throw new Error("Skip must be non-negative");
}
}
validateUpdateData(data) {
if (data.title && data.title.trim().length < 3) {
throw new Error("Alert title must be at least 3 characters long");
}
if (data.description && data.description.trim().length < 5) {
throw new Error("Alert description must be at least 5 characters long");
}
}
validateSnoozeDate(snoozeUntil) {
if (snoozeUntil <= new Date()) {
throw new Error("Snooze date must be in the future");
}
}
determineDefaultSeverity(category) {
// Business logic: Determine default severity based on category
const categorySeverities = {
[alert_types_1.AlertCategory.READINESS]: alert_types_1.AlertSeverity.MEDIUM,
[alert_types_1.AlertCategory.OPERATIONS]: alert_types_1.AlertSeverity.HIGH,
[alert_types_1.AlertCategory.SECURITY]: alert_types_1.AlertSeverity.CRITICAL,
[alert_types_1.AlertCategory.ENERGY]: alert_types_1.AlertSeverity.LOW,
[alert_types_1.AlertCategory.OTHER]: alert_types_1.AlertSeverity.MEDIUM,
};
// If it's an array, use the highest severity category
if (Array.isArray(category)) {
const severities = category.map((cat) => categorySeverities[cat] || alert_types_1.AlertSeverity.MEDIUM);
const severityOrder = [
alert_types_1.AlertSeverity.CRITICAL,
alert_types_1.AlertSeverity.HIGH,
alert_types_1.AlertSeverity.MEDIUM,
alert_types_1.AlertSeverity.LOW,
alert_types_1.AlertSeverity.INFO,
];
return (severityOrder.find((severity) => severities.includes(severity)) ||
alert_types_1.AlertSeverity.MEDIUM);
}
return categorySeverities[category] || alert_types_1.AlertSeverity.MEDIUM;
}
applyBusinessRules(filters) {
// Business logic: Apply additional filters based on business rules
const enhancedFilters = { ...filters };
// Example: Always exclude deleted alerts unless explicitly requested
if (!enhancedFilters.includeDeleted) {
enhancedFilters.includeDeleted = false;
}
return enhancedFilters;
}
};
__setFunctionName(_classThis, "AlertService");
(() => {
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
AlertService = _classThis = _classDescriptor.value;
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
__runInitializers(_classThis, _classExtraInitializers);
})();
return AlertService = _classThis;
})();
exports.AlertService = AlertService;