dt-common-device 9.1.6 → 9.1.8
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/dist/alerts/alert.types.d.ts +2 -1
- package/dist/alerts/alert.types.js +1 -0
- package/dist/copilotQueue/index.d.ts +4 -0
- package/dist/copilotQueue/index.js +21 -0
- package/dist/copilotQueue/interfaces/ICopilotQueueRequest.d.ts +27 -0
- package/dist/copilotQueue/interfaces/ICopilotQueueRequest.js +2 -0
- package/dist/copilotQueue/interfaces/ICopilotQueueService.d.ts +24 -0
- package/dist/copilotQueue/interfaces/ICopilotQueueService.js +2 -0
- package/dist/copilotQueue/interfaces/index.d.ts +2 -0
- package/dist/copilotQueue/interfaces/index.js +18 -0
- package/dist/copilotQueue/services/CopilotQueue.service.d.ts +13 -0
- package/dist/copilotQueue/services/CopilotQueue.service.js +196 -0
- package/dist/copilotQueue/services/index.d.ts +1 -0
- package/dist/copilotQueue/services/index.js +17 -0
- package/dist/copilotQueue/types/copilot.types.d.ts +13 -0
- package/dist/copilotQueue/types/copilot.types.js +2 -0
- package/dist/copilotQueue/types/index.d.ts +1 -0
- package/dist/copilotQueue/types/index.js +17 -0
- package/dist/copilotQueue/utils/index.d.ts +1 -0
- package/dist/copilotQueue/utils/index.js +17 -0
- package/dist/copilotQueue/utils/queueManager.d.ts +31 -0
- package/dist/copilotQueue/utils/queueManager.js +156 -0
- package/dist/cronicle/Cronicle.service.js +3 -2
- package/dist/cronicle/ICronicle.interface.d.ts +2 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/issues/issue.types.d.ts +3 -1
- package/dist/issues/issue.types.js +2 -0
- package/package.json +1 -1
|
@@ -25,7 +25,8 @@ export declare enum AlertType {
|
|
|
25
25
|
GUEST_LOCK_FIRST_ACCESS = "GUEST_LOCK_FIRST_ACCESS",
|
|
26
26
|
DEVICE_ONLINE = "DEVICE_ONLINE",
|
|
27
27
|
ZONE_NOT_MAPPED_TO_ACCESS_GROUP = "ZONE_NOT_MAPPED_TO_ACCESS_GROUP",
|
|
28
|
-
INCORRECT_CODE_USED = "INCORRECT_CODE_USED"
|
|
28
|
+
INCORRECT_CODE_USED = "INCORRECT_CODE_USED",
|
|
29
|
+
LOW_GUEST_CODES = "LOW_GUEST_CODES"
|
|
29
30
|
}
|
|
30
31
|
export interface AlertDocument {
|
|
31
32
|
_id: string;
|
|
@@ -31,6 +31,7 @@ var AlertType;
|
|
|
31
31
|
AlertType["DEVICE_ONLINE"] = "DEVICE_ONLINE";
|
|
32
32
|
AlertType["ZONE_NOT_MAPPED_TO_ACCESS_GROUP"] = "ZONE_NOT_MAPPED_TO_ACCESS_GROUP";
|
|
33
33
|
AlertType["INCORRECT_CODE_USED"] = "INCORRECT_CODE_USED";
|
|
34
|
+
AlertType["LOW_GUEST_CODES"] = "LOW_GUEST_CODES";
|
|
34
35
|
})(AlertType || (exports.AlertType = AlertType = {}));
|
|
35
36
|
// Re-export EntityType from issue.types.ts to avoid duplication
|
|
36
37
|
var issue_types_1 = require("../issues/issue.types");
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
// Main copilot queue exports
|
|
18
|
+
__exportStar(require("./interfaces"), exports);
|
|
19
|
+
__exportStar(require("./services"), exports);
|
|
20
|
+
__exportStar(require("./types"), exports);
|
|
21
|
+
__exportStar(require("./utils"), exports);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface ICopilotQueueRequest {
|
|
2
|
+
url: string;
|
|
3
|
+
method: "GET" | "POST" | "PUT" | "DELETE";
|
|
4
|
+
headers?: Record<string, string>;
|
|
5
|
+
params?: Record<string, string>;
|
|
6
|
+
query?: Record<string, string>;
|
|
7
|
+
body: any;
|
|
8
|
+
timestamp?: number;
|
|
9
|
+
jobId?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface ICopilotQueueResponse {
|
|
12
|
+
success: boolean;
|
|
13
|
+
data?: any;
|
|
14
|
+
error?: string;
|
|
15
|
+
jobId: string;
|
|
16
|
+
propertyId: string;
|
|
17
|
+
processingTime?: number;
|
|
18
|
+
}
|
|
19
|
+
export interface ICopilotQueueOptions {
|
|
20
|
+
delay?: number;
|
|
21
|
+
priority?: number;
|
|
22
|
+
attempts?: number;
|
|
23
|
+
backoff?: {
|
|
24
|
+
type: "fixed" | "exponential";
|
|
25
|
+
delay: number;
|
|
26
|
+
};
|
|
27
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ICopilotQueueRequest, ICopilotQueueOptions } from "./ICopilotQueueRequest";
|
|
2
|
+
export interface ICopilotQueueService {
|
|
3
|
+
/**
|
|
4
|
+
* Add a request to the queue for processing
|
|
5
|
+
* @param request - The request data including URL, method, headers, and body (with propertyId)
|
|
6
|
+
* @param options - Optional queue configuration
|
|
7
|
+
* @returns Promise with job ID and queue response
|
|
8
|
+
*/
|
|
9
|
+
addQueueRequest(request: ICopilotQueueRequest, options?: ICopilotQueueOptions): Promise<{
|
|
10
|
+
jobId: string;
|
|
11
|
+
queued: boolean;
|
|
12
|
+
}>;
|
|
13
|
+
/**
|
|
14
|
+
* Get the status of a queued job
|
|
15
|
+
* @param jobId - The job ID to check
|
|
16
|
+
* @returns Promise with job status
|
|
17
|
+
*/
|
|
18
|
+
getJobStatus(jobId: string): Promise<any>;
|
|
19
|
+
/**
|
|
20
|
+
* Shutdown the queue service
|
|
21
|
+
* @returns Promise that resolves when shutdown is complete
|
|
22
|
+
*/
|
|
23
|
+
shutdown(): Promise<void>;
|
|
24
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./ICopilotQueueRequest"), exports);
|
|
18
|
+
__exportStar(require("./ICopilotQueueService"), exports);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ICopilotQueueService, ICopilotQueueRequest, ICopilotQueueOptions } from "../interfaces";
|
|
2
|
+
export declare class CopilotQueueService implements ICopilotQueueService {
|
|
3
|
+
private readonly copilotQueues;
|
|
4
|
+
private readonly workers;
|
|
5
|
+
constructor();
|
|
6
|
+
private processRequest;
|
|
7
|
+
addQueueRequest(request: ICopilotQueueRequest, options?: ICopilotQueueOptions): Promise<{
|
|
8
|
+
jobId: string;
|
|
9
|
+
queued: boolean;
|
|
10
|
+
}>;
|
|
11
|
+
getJobStatus(jobId: string): Promise<any>;
|
|
12
|
+
shutdown(): Promise<void>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
|
|
3
|
+
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
|
|
4
|
+
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
|
|
5
|
+
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
|
|
6
|
+
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
|
|
7
|
+
var _, done = false;
|
|
8
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
9
|
+
var context = {};
|
|
10
|
+
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
|
|
11
|
+
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
|
|
12
|
+
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
|
|
13
|
+
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
|
|
14
|
+
if (kind === "accessor") {
|
|
15
|
+
if (result === void 0) continue;
|
|
16
|
+
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
|
|
17
|
+
if (_ = accept(result.get)) descriptor.get = _;
|
|
18
|
+
if (_ = accept(result.set)) descriptor.set = _;
|
|
19
|
+
if (_ = accept(result.init)) initializers.unshift(_);
|
|
20
|
+
}
|
|
21
|
+
else if (_ = accept(result)) {
|
|
22
|
+
if (kind === "field") initializers.unshift(_);
|
|
23
|
+
else descriptor[key] = _;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
27
|
+
done = true;
|
|
28
|
+
};
|
|
29
|
+
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
|
|
30
|
+
var useValue = arguments.length > 2;
|
|
31
|
+
for (var i = 0; i < initializers.length; i++) {
|
|
32
|
+
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
|
|
33
|
+
}
|
|
34
|
+
return useValue ? value : void 0;
|
|
35
|
+
};
|
|
36
|
+
var __setFunctionName = (this && this.__setFunctionName) || function (f, name, prefix) {
|
|
37
|
+
if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
|
|
38
|
+
return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
|
|
39
|
+
};
|
|
40
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
41
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
42
|
+
};
|
|
43
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
+
exports.CopilotQueueService = void 0;
|
|
45
|
+
const typedi_1 = require("typedi");
|
|
46
|
+
const axios_1 = __importDefault(require("axios"));
|
|
47
|
+
const config_1 = require("../../config/config");
|
|
48
|
+
const utils_1 = require("../utils");
|
|
49
|
+
let CopilotQueueService = (() => {
|
|
50
|
+
let _classDecorators = [(0, typedi_1.Service)()];
|
|
51
|
+
let _classDescriptor;
|
|
52
|
+
let _classExtraInitializers = [];
|
|
53
|
+
let _classThis;
|
|
54
|
+
var CopilotQueueService = _classThis = class {
|
|
55
|
+
constructor() {
|
|
56
|
+
this.copilotQueues = new Map(); // BullMQ Queue instances
|
|
57
|
+
this.workers = new Map(); // BullMQ Worker instances
|
|
58
|
+
}
|
|
59
|
+
async processRequest(job) {
|
|
60
|
+
const { url, method, headers, body } = job.data;
|
|
61
|
+
const propertyId = body?.propertyId;
|
|
62
|
+
const startTime = Date.now();
|
|
63
|
+
try {
|
|
64
|
+
(0, config_1.getConfig)().LOGGER.info(`Processing request for property ${propertyId}: ${method} ${url}`);
|
|
65
|
+
// Prepare axios request configuration
|
|
66
|
+
const axiosConfig = {
|
|
67
|
+
method: method.toLowerCase(),
|
|
68
|
+
url,
|
|
69
|
+
headers: {
|
|
70
|
+
"Content-Type": "application/json",
|
|
71
|
+
...headers,
|
|
72
|
+
},
|
|
73
|
+
timeout: 30000, // 30 second timeout
|
|
74
|
+
};
|
|
75
|
+
// Add body for POST, PUT, PATCH requests
|
|
76
|
+
if (body && ["post", "put", "patch"].includes(method.toLowerCase())) {
|
|
77
|
+
axiosConfig.data = body;
|
|
78
|
+
}
|
|
79
|
+
// Execute the HTTP request (fire and forget - no response processing)
|
|
80
|
+
await (0, axios_1.default)(axiosConfig);
|
|
81
|
+
const responseTime = Date.now() - startTime;
|
|
82
|
+
(0, config_1.getConfig)().LOGGER.info(`Request executed for property ${propertyId}: ${method} ${url} (${responseTime}ms)`);
|
|
83
|
+
return {
|
|
84
|
+
success: true,
|
|
85
|
+
responseTime,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
const responseTime = Date.now() - startTime;
|
|
90
|
+
const errorMessage = error.response?.data?.message || error.message || "Unknown error";
|
|
91
|
+
(0, config_1.getConfig)().LOGGER.error(`Request failed for property ${propertyId}: ${errorMessage} (${responseTime}ms)`);
|
|
92
|
+
return {
|
|
93
|
+
success: false,
|
|
94
|
+
error: errorMessage,
|
|
95
|
+
statusCode: error.response?.status || 500,
|
|
96
|
+
responseTime,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
async addQueueRequest(request, options) {
|
|
101
|
+
try {
|
|
102
|
+
// Validate required fields
|
|
103
|
+
if (!request.url ||
|
|
104
|
+
!request.method ||
|
|
105
|
+
!request.body ||
|
|
106
|
+
!request.body.propertyId) {
|
|
107
|
+
throw new Error("Missing required fields: url, method, and body with propertyId are required");
|
|
108
|
+
}
|
|
109
|
+
const propertyId = request.body.propertyId;
|
|
110
|
+
const queueName = utils_1.QueueManager.generateQueueName(propertyId);
|
|
111
|
+
// Get or create queue and worker using the QueueManager
|
|
112
|
+
const queue = await utils_1.QueueManager.getOrCreateQueue(queueName, this.copilotQueues);
|
|
113
|
+
// Create worker for this queue if it doesn't exist
|
|
114
|
+
await utils_1.QueueManager.getOrCreateWorker(queueName, this.workers, this.copilotQueues, this.processRequest.bind(this));
|
|
115
|
+
// Prepare job data
|
|
116
|
+
const jobData = {
|
|
117
|
+
url: request.url,
|
|
118
|
+
method: request.method,
|
|
119
|
+
headers: request.headers,
|
|
120
|
+
body: request.body,
|
|
121
|
+
timestamp: Date.now(),
|
|
122
|
+
};
|
|
123
|
+
// Add job to queue with TTL (similar to WebhookQueueService)
|
|
124
|
+
const job = await queue.add("copilot-request", jobData, {
|
|
125
|
+
removeOnComplete: { age: 5 * 60 }, // Remove after 5 minutes
|
|
126
|
+
removeOnFail: { age: 10 * 60 }, // Remove failed jobs after 10 minutes
|
|
127
|
+
attempts: 1, // No retries - execute only once
|
|
128
|
+
delay: options?.delay || 0,
|
|
129
|
+
priority: options?.priority || 0,
|
|
130
|
+
// Use propertyId as job group to ensure FIFO ordering per property
|
|
131
|
+
jobId: utils_1.QueueManager.generateJobId(propertyId),
|
|
132
|
+
});
|
|
133
|
+
(0, config_1.getConfig)().LOGGER.info(`Request queued for property ${propertyId}: ${request.method} ${request.url} (Job ID: ${job.id})`);
|
|
134
|
+
return {
|
|
135
|
+
jobId: job.id,
|
|
136
|
+
queued: true,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
(0, config_1.getConfig)().LOGGER.error("Failed to add request to queue:", error.message);
|
|
141
|
+
throw error;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
async getJobStatus(jobId) {
|
|
145
|
+
try {
|
|
146
|
+
// Extract propertyId from jobId (format: propertyId-timestamp-random)
|
|
147
|
+
const propertyId = utils_1.QueueManager.extractPropertyIdFromJobId(jobId);
|
|
148
|
+
const queueName = utils_1.QueueManager.generateQueueName(propertyId);
|
|
149
|
+
// Get or create queue
|
|
150
|
+
const queue = await utils_1.QueueManager.getOrCreateQueue(queueName, this.copilotQueues);
|
|
151
|
+
const job = await queue.getJob(jobId);
|
|
152
|
+
if (!job) {
|
|
153
|
+
return { exists: false };
|
|
154
|
+
}
|
|
155
|
+
const state = await job.getState();
|
|
156
|
+
return {
|
|
157
|
+
exists: true,
|
|
158
|
+
id: job.id,
|
|
159
|
+
state,
|
|
160
|
+
data: job.data,
|
|
161
|
+
progress: job.progress,
|
|
162
|
+
returnvalue: job.returnvalue,
|
|
163
|
+
failedReason: job.failedReason,
|
|
164
|
+
processedOn: job.processedOn,
|
|
165
|
+
finishedOn: job.finishedOn,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
(0, config_1.getConfig)().LOGGER.error(`Failed to get job status for ${jobId}:`, error.message);
|
|
170
|
+
throw error;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
async shutdown() {
|
|
174
|
+
try {
|
|
175
|
+
(0, config_1.getConfig)().LOGGER.info("Shutting down CopilotQueue service...");
|
|
176
|
+
// Close all workers and queues using QueueManager
|
|
177
|
+
await utils_1.QueueManager.closeAllWorkersAndQueues(this.workers, this.copilotQueues);
|
|
178
|
+
(0, config_1.getConfig)().LOGGER.info("CopilotQueue service shutdown complete");
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
(0, config_1.getConfig)().LOGGER.error("Error during CopilotQueue shutdown:", error.message);
|
|
182
|
+
throw error;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
__setFunctionName(_classThis, "CopilotQueueService");
|
|
187
|
+
(() => {
|
|
188
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
|
|
189
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
190
|
+
CopilotQueueService = _classThis = _classDescriptor.value;
|
|
191
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
192
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
193
|
+
})();
|
|
194
|
+
return CopilotQueueService = _classThis;
|
|
195
|
+
})();
|
|
196
|
+
exports.CopilotQueueService = CopilotQueueService;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./CopilotQueue.service";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./CopilotQueue.service"), exports);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Job, Queue, Worker } from "bullmq";
|
|
2
|
+
export interface CopilotJobData {
|
|
3
|
+
url: string;
|
|
4
|
+
method: "GET" | "POST" | "PUT" | "DELETE";
|
|
5
|
+
params?: Record<string, string>;
|
|
6
|
+
query?: Record<string, string>;
|
|
7
|
+
headers?: Record<string, string>;
|
|
8
|
+
body: any;
|
|
9
|
+
timestamp?: number;
|
|
10
|
+
}
|
|
11
|
+
export type CopilotQueue = Queue<CopilotJobData>;
|
|
12
|
+
export type CopilotWorker = Worker<CopilotJobData>;
|
|
13
|
+
export type CopilotJob = Job<CopilotJobData>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./copilot.types";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./copilot.types"), exports);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./queueManager";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./queueManager"), exports);
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Job } from "bullmq";
|
|
2
|
+
export declare class QueueManager {
|
|
3
|
+
/**
|
|
4
|
+
* Get or create a BullMQ queue
|
|
5
|
+
*/
|
|
6
|
+
static getOrCreateQueue(queueKey: string, queues: Map<string, any>): Promise<any>;
|
|
7
|
+
/**
|
|
8
|
+
* Get or create a BullMQ worker
|
|
9
|
+
*/
|
|
10
|
+
static getOrCreateWorker(queueKey: string, workers: Map<string, any>, queues: Map<string, any>, processor: (job: Job) => Promise<any>): Promise<any>;
|
|
11
|
+
/**
|
|
12
|
+
* Check if queue is empty and cleanup worker if no jobs are pending
|
|
13
|
+
*/
|
|
14
|
+
static checkAndCleanupWorker(queueKey: string, workers: Map<string, any>, queues: Map<string, any>): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Close all workers and queues
|
|
17
|
+
*/
|
|
18
|
+
static closeAllWorkersAndQueues(workers: Map<string, any>, queues: Map<string, any>): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Generate queue name for a property
|
|
21
|
+
*/
|
|
22
|
+
static generateQueueName(propertyId: string): string;
|
|
23
|
+
/**
|
|
24
|
+
* Extract property ID from job ID
|
|
25
|
+
*/
|
|
26
|
+
static extractPropertyIdFromJobId(jobId: string): string;
|
|
27
|
+
/**
|
|
28
|
+
* Generate unique job ID
|
|
29
|
+
*/
|
|
30
|
+
static generateJobId(propertyId: string): string;
|
|
31
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.QueueManager = void 0;
|
|
37
|
+
const redis_1 = require("../../db/redis");
|
|
38
|
+
const config_1 = require("../../config/config");
|
|
39
|
+
class QueueManager {
|
|
40
|
+
/**
|
|
41
|
+
* Get or create a BullMQ queue
|
|
42
|
+
*/
|
|
43
|
+
static async getOrCreateQueue(queueKey, queues) {
|
|
44
|
+
if (queues.has(queueKey)) {
|
|
45
|
+
return queues.get(queueKey);
|
|
46
|
+
}
|
|
47
|
+
const { Queue } = await Promise.resolve().then(() => __importStar(require("bullmq")));
|
|
48
|
+
const queue = new Queue(queueKey, {
|
|
49
|
+
connection: (0, redis_1.getRedisClient)(),
|
|
50
|
+
});
|
|
51
|
+
queues.set(queueKey, queue);
|
|
52
|
+
return queue;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Get or create a BullMQ worker
|
|
56
|
+
*/
|
|
57
|
+
static async getOrCreateWorker(queueKey, workers, queues, processor) {
|
|
58
|
+
if (workers.has(queueKey)) {
|
|
59
|
+
return workers.get(queueKey);
|
|
60
|
+
}
|
|
61
|
+
const { Worker } = await Promise.resolve().then(() => __importStar(require("bullmq")));
|
|
62
|
+
const worker = new Worker(queueKey, processor, {
|
|
63
|
+
connection: (0, redis_1.getRedisClient)(),
|
|
64
|
+
concurrency: 1, // Process one job at a time for FIFO ordering
|
|
65
|
+
});
|
|
66
|
+
// Setup event listeners
|
|
67
|
+
worker.on("completed", async (job) => {
|
|
68
|
+
const propertyId = job.data.body?.propertyId || "unknown";
|
|
69
|
+
(0, config_1.getConfig)().LOGGER.info(`Job ${job.id} completed for property ${propertyId}`);
|
|
70
|
+
// Check if queue is empty and cleanup worker
|
|
71
|
+
await QueueManager.checkAndCleanupWorker(queueKey, workers, queues);
|
|
72
|
+
});
|
|
73
|
+
worker.on("failed", async (job, err) => {
|
|
74
|
+
const propertyId = job?.data?.body?.propertyId || "unknown";
|
|
75
|
+
(0, config_1.getConfig)().LOGGER.error(`Job ${job?.id} failed for property ${propertyId}:`, err.message);
|
|
76
|
+
// Check if queue is empty and cleanup worker
|
|
77
|
+
await QueueManager.checkAndCleanupWorker(queueKey, workers, queues);
|
|
78
|
+
});
|
|
79
|
+
worker.on("error", (err) => {
|
|
80
|
+
(0, config_1.getConfig)().LOGGER.error("Worker error:", err.message);
|
|
81
|
+
});
|
|
82
|
+
workers.set(queueKey, worker);
|
|
83
|
+
return worker;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Check if queue is empty and cleanup worker if no jobs are pending
|
|
87
|
+
*/
|
|
88
|
+
static async checkAndCleanupWorker(queueKey, workers, queues) {
|
|
89
|
+
try {
|
|
90
|
+
const queue = queues.get(queueKey);
|
|
91
|
+
if (!queue)
|
|
92
|
+
return;
|
|
93
|
+
// Check if queue has any waiting, active, or delayed jobs
|
|
94
|
+
const [waiting, active, delayed] = await Promise.all([
|
|
95
|
+
queue.getWaiting(),
|
|
96
|
+
queue.getActive(),
|
|
97
|
+
queue.getDelayed(),
|
|
98
|
+
]);
|
|
99
|
+
const totalJobs = waiting.length + active.length + delayed.length;
|
|
100
|
+
// If no jobs are pending, cleanup the worker
|
|
101
|
+
if (totalJobs === 0) {
|
|
102
|
+
const worker = workers.get(queueKey);
|
|
103
|
+
if (worker) {
|
|
104
|
+
await worker.close();
|
|
105
|
+
workers.delete(queueKey);
|
|
106
|
+
// Extract propertyId from queueKey (format: propertyId_copilot)
|
|
107
|
+
const propertyId = queueKey.replace("_copilot", "");
|
|
108
|
+
(0, config_1.getConfig)().LOGGER.info(`Worker cleaned up for property ${propertyId} - no pending jobs`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
(0, config_1.getConfig)().LOGGER.error(`Error during worker cleanup for ${queueKey}:`, error.message);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Close all workers and queues
|
|
118
|
+
*/
|
|
119
|
+
static async closeAllWorkersAndQueues(workers, queues) {
|
|
120
|
+
try {
|
|
121
|
+
// Close all workers and queues
|
|
122
|
+
await Promise.all([
|
|
123
|
+
...Array.from(workers.values()).map((worker) => worker.close()),
|
|
124
|
+
...Array.from(queues.values()).map((queue) => queue.close()),
|
|
125
|
+
]);
|
|
126
|
+
workers.clear();
|
|
127
|
+
queues.clear();
|
|
128
|
+
(0, config_1.getConfig)().LOGGER.info("All workers and queues closed successfully");
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
(0, config_1.getConfig)().LOGGER.error("Error closing workers and queues:", error.message);
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Generate queue name for a property
|
|
137
|
+
*/
|
|
138
|
+
static generateQueueName(propertyId) {
|
|
139
|
+
return `${propertyId}_copilot`;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Extract property ID from job ID
|
|
143
|
+
*/
|
|
144
|
+
static extractPropertyIdFromJobId(jobId) {
|
|
145
|
+
return jobId.split("-")[0];
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Generate unique job ID
|
|
149
|
+
*/
|
|
150
|
+
static generateJobId(propertyId) {
|
|
151
|
+
return `${propertyId}-${Date.now()}-${Math.random()
|
|
152
|
+
.toString(36)
|
|
153
|
+
.substr(2, 9)}`;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
exports.QueueManager = QueueManager;
|
|
@@ -12,14 +12,14 @@ class CronicleService {
|
|
|
12
12
|
this.cronicleApiKey = process.env.CRONICLE_API_KEY || "";
|
|
13
13
|
}
|
|
14
14
|
async registerJob(payload) {
|
|
15
|
-
const { name, apiUrl, method, schedule, cronJobId, target, category } = payload;
|
|
15
|
+
const { name, apiUrl, method, schedule, cronJobId, target, category, timezone, } = payload;
|
|
16
16
|
try {
|
|
17
17
|
await axios_1.default.post(`${this.cronicleEndpoint}/create_event/v1`, {
|
|
18
18
|
id: cronJobId,
|
|
19
19
|
title: name,
|
|
20
20
|
category: "general",
|
|
21
21
|
plugin: "urlplug",
|
|
22
|
-
timeZone: "UTC",
|
|
22
|
+
timeZone: timezone || "UTC",
|
|
23
23
|
enabled: 1,
|
|
24
24
|
target: target,
|
|
25
25
|
api_key: this.cronicleApiKey,
|
|
@@ -40,6 +40,7 @@ class CronicleService {
|
|
|
40
40
|
hours: schedule.hours,
|
|
41
41
|
minutes: schedule.minutes,
|
|
42
42
|
},
|
|
43
|
+
timeout: 120,
|
|
43
44
|
});
|
|
44
45
|
}
|
|
45
46
|
catch (error) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export interface ICronicle {
|
|
2
2
|
name: string;
|
|
3
3
|
cronJobId: string;
|
|
4
|
-
category?: "heartbeat" | "replenish_codes" | "sync_schedules" | "delete_schedules" | "deliver_codes" | "daily_summary" | "battery_report" | "
|
|
4
|
+
category?: "heartbeat" | "replenish_codes" | "sync_schedules" | "delete_schedules" | "deliver_codes" | "daily_summary" | "battery_report" | "replenish_alerts";
|
|
5
5
|
apiUrl: string;
|
|
6
6
|
method: "POST";
|
|
7
7
|
target: string;
|
|
@@ -13,4 +13,5 @@ export interface ICronicle {
|
|
|
13
13
|
hours?: number[];
|
|
14
14
|
minutes?: number[];
|
|
15
15
|
};
|
|
16
|
+
timezone?: string;
|
|
16
17
|
}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -61,3 +61,5 @@ Object.defineProperty(exports, "getConfig", { enumerable: true, get: function ()
|
|
|
61
61
|
Object.defineProperty(exports, "shutdown", { enumerable: true, get: function () { return config_1.shutdown; } });
|
|
62
62
|
//Export PMS Webhook Queue
|
|
63
63
|
__exportStar(require("./webhookQueue"), exports);
|
|
64
|
+
//Export Copilot Queue
|
|
65
|
+
__exportStar(require("./copilotQueue"), exports);
|
|
@@ -70,7 +70,9 @@ export declare enum IssueType {
|
|
|
70
70
|
ACCOUNT_UNAUTHORIZED = "ACCOUNT_UNAUTHORIZED",
|
|
71
71
|
ACCOUNT_MISSING_DEVICE = "ACCOUNT_MISSING_DEVICE",
|
|
72
72
|
LOCK_JAMMED = "LOCK_JAMMED",
|
|
73
|
-
DEVICE_MALFUNCTION = "DEVICE_MALFUNCTION"
|
|
73
|
+
DEVICE_MALFUNCTION = "DEVICE_MALFUNCTION",
|
|
74
|
+
NO_GUEST_CODES = "NO_GUEST_CODES",
|
|
75
|
+
JUST_ENOUGH_GUEST_CODES = "JUST_ENOUGH_GUEST_CODES"
|
|
74
76
|
}
|
|
75
77
|
export interface IssueDocument {
|
|
76
78
|
id: string;
|
|
@@ -76,4 +76,6 @@ var IssueType;
|
|
|
76
76
|
IssueType["ACCOUNT_MISSING_DEVICE"] = "ACCOUNT_MISSING_DEVICE";
|
|
77
77
|
IssueType["LOCK_JAMMED"] = "LOCK_JAMMED";
|
|
78
78
|
IssueType["DEVICE_MALFUNCTION"] = "DEVICE_MALFUNCTION";
|
|
79
|
+
IssueType["NO_GUEST_CODES"] = "NO_GUEST_CODES";
|
|
80
|
+
IssueType["JUST_ENOUGH_GUEST_CODES"] = "JUST_ENOUGH_GUEST_CODES";
|
|
79
81
|
})(IssueType || (exports.IssueType = IssueType = {}));
|