UNPKG

dt-common-device

Version:

A secure and robust device management library for IoT applications

514 lines (513 loc) 24.1 kB
"use strict"; 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;