dt-common-device 2.0.7 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (211) hide show
  1. package/README.md +352 -98
  2. package/dist/alerts/Alert.model.d.ts +28 -0
  3. package/dist/alerts/Alert.model.js +222 -0
  4. package/dist/alerts/Alert.repository.d.ts +106 -0
  5. package/dist/alerts/Alert.repository.js +374 -0
  6. package/dist/alerts/Alert.service.d.ts +137 -0
  7. package/dist/alerts/Alert.service.js +476 -0
  8. package/dist/alerts/AlertBuilder.d.ts +87 -0
  9. package/dist/alerts/AlertBuilder.example.d.ts +11 -0
  10. package/dist/alerts/AlertBuilder.example.js +117 -0
  11. package/dist/alerts/AlertBuilder.js +185 -0
  12. package/dist/alerts/AlertService.example.d.ts +55 -0
  13. package/dist/alerts/AlertService.example.js +148 -0
  14. package/dist/alerts/alert.types.d.ts +57 -0
  15. package/dist/alerts/alert.types.js +22 -0
  16. package/dist/alerts/index.d.ts +3 -0
  17. package/dist/alerts/index.js +19 -0
  18. package/dist/config/config.d.ts +4 -4
  19. package/dist/config/config.js +3 -3
  20. package/dist/config/config.types.d.ts +19 -0
  21. package/dist/config/config.types.js +2 -0
  22. package/dist/connection/Connection.repository.d.ts +8 -0
  23. package/dist/connection/Connection.repository.js +92 -0
  24. package/dist/connection/Connection.service.d.ts +8 -0
  25. package/dist/connection/Connection.service.js +32 -0
  26. package/dist/connection/IConnection.d.ts +26 -0
  27. package/dist/connection/IConnection.js +14 -0
  28. package/dist/connection/index.d.ts +2 -0
  29. package/dist/connection/index.js +18 -0
  30. package/dist/device/cloud/entities/CloudDevice.d.ts +2 -2
  31. package/dist/device/cloud/entities/CloudDeviceService.d.ts +1 -1
  32. package/dist/device/cloud/entities/DeviceFactory.d.ts +1 -1
  33. package/dist/device/cloud/entities/DeviceFactory.js +1 -1
  34. package/dist/device/cloud/interface.d.ts +101 -0
  35. package/dist/device/cloud/interface.js +3 -0
  36. package/dist/device/cloud/interfaces/ICloudDeviceService.d.ts +1 -1
  37. package/dist/device/cloud/interfaces/IDeviceConnectionService.d.ts +7 -0
  38. package/dist/device/cloud/interfaces/IDeviceConnectionService.js +3 -0
  39. package/dist/device/cloud/interfaces/IDevicesService.d.ts +9 -0
  40. package/dist/device/cloud/interfaces/IDevicesService.js +2 -0
  41. package/dist/device/cloud/interfaces/IRawDevice.d.ts +1 -1
  42. package/dist/device/cloud/services/Device.service.d.ts +39 -0
  43. package/dist/device/cloud/services/Device.service.js +9 -0
  44. package/dist/device/cloud/services/DeviceCloudService.d.ts +42 -0
  45. package/dist/device/cloud/services/DeviceCloudService.js +59 -0
  46. package/dist/device/cloud/services/DeviceHub.service.d.ts +3 -0
  47. package/dist/device/cloud/services/DeviceHub.service.js +6 -0
  48. package/dist/device/cloud/services/Hub.service.d.ts +25 -0
  49. package/dist/device/cloud/services/Hub.service.js +9 -0
  50. package/dist/device/cloud/services/SmartThingsDeviceService.d.ts +38 -0
  51. package/dist/device/cloud/services/SmartThingsDeviceService.js +52 -0
  52. package/dist/device/index.d.ts +4 -0
  53. package/dist/device/index.js +20 -0
  54. package/dist/device/local/events/EventHandler.js +6 -6
  55. package/dist/device/local/events/Events.d.ts +12 -33
  56. package/dist/device/local/events/Events.js +12 -33
  57. package/dist/device/local/interface.d.ts +0 -0
  58. package/dist/device/local/interface.js +1 -0
  59. package/dist/device/local/interfaces/index.d.ts +2 -3
  60. package/dist/device/local/interfaces/index.js +2 -3
  61. package/dist/device/local/repository/Device.repository.js +3 -3
  62. package/dist/device/local/repository/Hub.repository.js +4 -4
  63. package/dist/device/local/repository/Schedule.repository.js +2 -2
  64. package/dist/device/local/services/Device.service.d.ts +2 -2
  65. package/dist/device/local/services/Device.service.js +1 -1
  66. package/dist/device/local/services/DeviceHub.service.d.ts +11 -0
  67. package/dist/device/local/services/DeviceHub.service.js +40 -0
  68. package/dist/device/local/services/index.d.ts +0 -4
  69. package/dist/device/local/services/index.js +0 -4
  70. package/dist/events/BaseEventHandler.d.ts +2 -2
  71. package/dist/events/BaseEventHandler.js +2 -2
  72. package/dist/events/BaseEventTransformer.d.ts +1 -1
  73. package/dist/events/BaseEventTransformer.js +1 -1
  74. package/dist/events/DeviceEventHandler.d.ts +1 -1
  75. package/dist/events/DeviceEventHandler.js +2 -2
  76. package/dist/events/EventHandler.js +1 -1
  77. package/dist/events/EventHandlerOrchestrator.js +1 -1
  78. package/dist/events/EventProcessingService.js +1 -1
  79. package/dist/events/InternalEventSubscription.js +1 -1
  80. package/dist/index.d.ts +7 -5
  81. package/dist/index.js +16 -13
  82. package/dist/issues/Issue.model.d.ts +28 -0
  83. package/dist/issues/Issue.model.js +260 -0
  84. package/dist/issues/Issue.repository.d.ts +113 -0
  85. package/dist/issues/Issue.repository.js +401 -0
  86. package/dist/issues/Issue.service.d.ts +168 -0
  87. package/dist/issues/Issue.service.js +642 -0
  88. package/dist/issues/IssueBuilder.d.ts +109 -0
  89. package/dist/issues/IssueBuilder.example.d.ts +16 -0
  90. package/dist/issues/IssueBuilder.example.js +196 -0
  91. package/dist/issues/IssueBuilder.js +237 -0
  92. package/dist/issues/IssueService.example.d.ts +68 -0
  93. package/dist/issues/IssueService.example.js +177 -0
  94. package/dist/issues/index.d.ts +2 -0
  95. package/dist/issues/index.js +18 -0
  96. package/dist/issues/issue.types.d.ts +90 -0
  97. package/dist/issues/issue.types.js +40 -0
  98. package/dist/property/IProperty.d.ts +29 -0
  99. package/dist/property/IProperty.js +2 -0
  100. package/dist/property/Property.repository.d.ts +8 -0
  101. package/dist/property/Property.repository.js +95 -0
  102. package/dist/property/Property.service.d.ts +8 -0
  103. package/dist/property/Property.service.js +36 -0
  104. package/dist/property/index.d.ts +2 -0
  105. package/dist/property/index.js +18 -0
  106. package/dist/queue/entities/HybridHttpQueue.d.ts +24 -0
  107. package/dist/queue/entities/HybridHttpQueue.js +241 -0
  108. package/dist/queue/entities/index.d.ts +1 -0
  109. package/dist/queue/entities/index.js +17 -0
  110. package/dist/queue/index.d.ts +5 -0
  111. package/dist/queue/index.js +22 -0
  112. package/dist/queue/interfaces/IHttpRequestJob.d.ts +9 -0
  113. package/dist/queue/interfaces/IHttpRequestJob.js +2 -0
  114. package/dist/queue/interfaces/IHybridHttpQueue.d.ts +17 -0
  115. package/dist/queue/interfaces/IHybridHttpQueue.js +2 -0
  116. package/dist/queue/interfaces/IJobResult.d.ts +14 -0
  117. package/dist/queue/interfaces/IJobResult.js +2 -0
  118. package/dist/queue/interfaces/IRateLimitConfig.d.ts +5 -0
  119. package/dist/queue/interfaces/IRateLimitConfig.js +2 -0
  120. package/dist/queue/interfaces/index.d.ts +4 -0
  121. package/dist/queue/interfaces/index.js +20 -0
  122. package/dist/queue/services/QueueService.d.ts +19 -0
  123. package/dist/queue/services/QueueService.js +73 -0
  124. package/dist/queue/services/index.d.ts +1 -0
  125. package/dist/queue/services/index.js +17 -0
  126. package/dist/queue/types/http.types.d.ts +21 -0
  127. package/dist/queue/types/http.types.js +2 -0
  128. package/dist/queue/types/index.d.ts +2 -0
  129. package/dist/queue/types/index.js +18 -0
  130. package/dist/queue/types/queue.types.d.ts +31 -0
  131. package/dist/queue/types/queue.types.js +2 -0
  132. package/dist/queue/utils/index.d.ts +3 -0
  133. package/dist/queue/utils/index.js +19 -0
  134. package/dist/queue/utils/jobUtils.d.ts +10 -0
  135. package/dist/queue/utils/jobUtils.js +64 -0
  136. package/dist/queue/utils/queueUtils.d.ts +5 -0
  137. package/dist/queue/utils/queueUtils.js +60 -0
  138. package/dist/queue/utils/rateLimit.utils.d.ts +10 -0
  139. package/dist/queue/utils/rateLimit.utils.js +97 -0
  140. package/package.json +2 -1
  141. package/src/{device/local/models → alerts}/Alert.model.ts +1 -1
  142. package/src/{device/local/repository → alerts}/Alert.repository.ts +2 -2
  143. package/src/{device/local/services → alerts}/Alert.service.ts +14 -7
  144. package/src/{device/local/entities → alerts}/AlertBuilder.example.ts +2 -2
  145. package/src/{device/local/entities → alerts}/AlertBuilder.ts +14 -8
  146. package/src/{device/local/services → alerts}/AlertService.example.ts +6 -5
  147. package/src/{types → alerts}/alert.types.ts +2 -2
  148. package/src/alerts/index.ts +3 -0
  149. package/src/config/config.ts +7 -7
  150. package/src/{types → config}/config.types.ts +1 -1
  151. package/src/{device/local/repository → connection}/Connection.repository.ts +2 -2
  152. package/src/{device/local/services → connection}/Connection.service.ts +2 -2
  153. package/src/connection/index.ts +3 -0
  154. package/src/device/cloud/entities/CloudDevice.ts +2 -2
  155. package/src/device/cloud/entities/CloudDeviceService.ts +1 -1
  156. package/src/device/cloud/entities/DeviceFactory.ts +2 -2
  157. package/src/device/cloud/interfaces/ICloudDeviceService.ts +1 -1
  158. package/src/device/cloud/interfaces/IRawDevice.ts +1 -1
  159. package/src/device/local/interfaces/index.ts +2 -3
  160. package/src/device/local/repository/Device.repository.ts +3 -3
  161. package/src/device/local/repository/Hub.repository.ts +4 -4
  162. package/src/device/local/repository/Schedule.repository.ts +2 -2
  163. package/src/device/local/services/Device.service.ts +1 -1
  164. package/src/device/local/services/index.ts +0 -4
  165. package/{TROUBLESHOOTING.md → src/docs/TROUBLESHOOTING.md} +2 -2
  166. package/src/events/BaseEventHandler.ts +3 -3
  167. package/src/events/BaseEventTransformer.ts +2 -2
  168. package/src/events/DeviceEventHandler.ts +3 -3
  169. package/src/events/EventHandler.ts +1 -1
  170. package/src/events/EventHandlerOrchestrator.ts +2 -2
  171. package/src/events/EventProcessingService.ts +2 -2
  172. package/src/events/InternalEventSubscription.ts +2 -2
  173. package/src/index.ts +19 -13
  174. package/src/{device/local/models → issues}/Issue.model.ts +1 -1
  175. package/src/{device/local/repository → issues}/Issue.repository.ts +2 -2
  176. package/src/{device/local/services → issues}/Issue.service.ts +4 -4
  177. package/src/{device/local/entities → issues}/IssueBuilder.example.ts +1 -1
  178. package/src/{device/local/entities → issues}/IssueBuilder.ts +1 -1
  179. package/src/{device/local/services → issues}/IssueService.example.ts +6 -5
  180. package/src/issues/index.ts +2 -0
  181. package/src/{device/local/repository → property}/Property.repository.ts +2 -2
  182. package/src/{device/local/services → property}/Property.service.ts +1 -1
  183. package/src/property/index.ts +2 -0
  184. package/src/queue/entities/HybridHttpQueue.ts +272 -0
  185. package/src/queue/entities/index.ts +1 -0
  186. package/src/queue/index.ts +6 -0
  187. package/src/queue/interfaces/IHttpRequestJob.ts +10 -0
  188. package/src/queue/interfaces/IHybridHttpQueue.ts +24 -0
  189. package/src/queue/interfaces/IJobResult.ts +15 -0
  190. package/src/queue/interfaces/IRateLimitConfig.ts +5 -0
  191. package/src/queue/interfaces/index.ts +4 -0
  192. package/src/queue/services/QueueService.ts +39 -0
  193. package/src/queue/services/index.ts +1 -0
  194. package/src/queue/types/http.types.ts +22 -0
  195. package/src/queue/types/index.ts +2 -0
  196. package/src/queue/types/queue.types.ts +21 -0
  197. package/src/queue/utils/index.ts +3 -0
  198. package/src/queue/utils/jobUtils.ts +80 -0
  199. package/src/queue/utils/queueUtils.ts +91 -0
  200. package/src/queue/utils/rateLimit.utils.ts +131 -0
  201. package/tsconfig.json +4 -0
  202. package/src/device/local/entities/README.md +0 -173
  203. package/src/device/local/entities/index.ts +0 -2
  204. package/src/types/index.ts +0 -3
  205. /package/src/{device/local/interfaces → connection}/IConnection.ts +0 -0
  206. /package/src/{device/local/models → docs}/Alert.model.md +0 -0
  207. /package/src/{device/local/models/README.md → docs/Alerts&IssuesModel.md} +0 -0
  208. /package/src/{device/local/models → docs}/Issue.model.md +0 -0
  209. /package/{SECURITY.md → src/docs/SECURITY.md} +0 -0
  210. /package/src/{types → issues}/issue.types.ts +0 -0
  211. /package/src/{device/local/interfaces → property}/IProperty.ts +0 -0
@@ -1,8 +1,8 @@
1
1
  import { DeviceEvent } from "./interfaces/DeviceEvent";
2
2
  import { IEventHandler } from "./interfaces/IEventHandler";
3
- import { getConfig } from "../config/config";
4
- import { ILogger } from "../types/config.types";
5
- import { LocalDeviceService } from "../device/local/services/Device.service";
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 "../config/config";
2
- import { ILogger } from "../types/config.types";
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 "../constants/Event";
2
- import { IDevice } from "../device/local/interfaces";
3
- import { LocalHubService } from "../device/local/services";
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 "../constants/Event";
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 "../types/config.types";
5
- import { getConfig } from "../config/config";
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 "../types/config.types";
4
- import { getConfig } from "../config/config";
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 "../config/config";
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 "../types/config.types";
10
+ import { ILogger } from "src/config/config.types";
11
11
 
12
12
  // Event types enum for better type safety
13
13
  export enum InternalEventType {
package/src/index.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  // Main entry point for dt-common-device
2
2
 
3
- // Cloud exports
3
+ // DEVICE EXPORTS
4
4
  export {
5
5
  CloudDevice,
6
6
  CloudDeviceService,
@@ -9,26 +9,32 @@ export {
9
9
  export {
10
10
  LocalDeviceService,
11
11
  LocalHubService,
12
- LocalConnectionService,
13
- LocalPropertyService,
14
12
  LocalScheduleService,
15
13
  } from "./device/local/services";
14
+ export * from "./device/local/interfaces";
15
+ export * from "./device/cloud/interfaces";
16
16
 
17
- // Events exports
18
- export * from "./events";
19
- export * from "./events/interfaces";
17
+ // CONNECTION EXPORTS
18
+ export * from "./connection";
20
19
 
21
- export * from "./device/cloud/interfaces";
20
+ // PROPERTY EXPORTS
21
+ export * from "./property";
22
22
 
23
- // Local exports
24
- export * from "./device/local/interfaces";
23
+ // EVENTS EXPORTS
25
24
  export * from "./events";
26
25
  export * from "./events/interfaces";
27
- // Types exports
28
- export * from "./types";
29
26
 
30
- // Redis utils
27
+ // ALERTS EXPORTS
28
+ export * from "./alerts";
29
+
30
+ // ISSUES EXPORTS
31
+ export * from "./issues";
32
+
33
+ // REDIS EXPORTS
31
34
  export * from "./utils";
32
35
 
33
- //initialize export
36
+ // QUEUE EXPORTS
37
+ export * from "./queue";
38
+
39
+ // CONFIG EXPORTS
34
40
  export { initialize, getConfig, shutdown } from "./config/config";
@@ -9,7 +9,7 @@ import {
9
9
  CreateIssueData,
10
10
  UpdateIssueData,
11
11
  AddCommentData,
12
- } from "../../../types/issue.types";
12
+ } from "./issue.types";
13
13
 
14
14
  // Comment sub-schema
15
15
  const CommentSchema = new Schema<IssueComment>(
@@ -1,5 +1,5 @@
1
1
  import { Service } from "typedi";
2
- import { IssueModel, IIssueDocument } from "../models/Issue.model";
2
+ import { IssueModel, IIssueDocument } from "./Issue.model";
3
3
  import {
4
4
  CreateIssueData,
5
5
  UpdateIssueData,
@@ -7,7 +7,7 @@ import {
7
7
  IssuePriority,
8
8
  IssuesCategory,
9
9
  EntityType,
10
- } from "../../../types/issue.types";
10
+ } from "./issue.types";
11
11
 
12
12
  @Service()
13
13
  export class IssueRepository {
@@ -1,6 +1,6 @@
1
1
  import { Service } from "typedi";
2
- import { IssueRepository } from "../repository/Issue.repository";
3
- import { IssueModel, IIssueDocument } from "../models/Issue.model";
2
+ import { IssueRepository } from "./Issue.repository";
3
+ import { IssueModel, IIssueDocument } from "./Issue.model";
4
4
  import {
5
5
  CreateIssueData,
6
6
  UpdateIssueData,
@@ -9,8 +9,8 @@ import {
9
9
  IssuePriority,
10
10
  IssuesCategory,
11
11
  EntityType,
12
- } from "../../../types/issue.types";
13
- import { IssueBuilder } from "../entities/IssueBuilder";
12
+ } from "./issue.types";
13
+ import { IssueBuilder } from "./IssueBuilder";
14
14
 
15
15
  @Service()
16
16
  export class IssueService {
@@ -1,5 +1,5 @@
1
1
  import { IssueBuilder } from "./IssueBuilder";
2
- import { IssuesCategory, IssuePriority, EntityType } from "../../../types/issue.types";
2
+ import { IssuesCategory, IssuePriority, EntityType } from "./issue.types";
3
3
 
4
4
  /**
5
5
  * Example usage of IssueBuilder
@@ -3,7 +3,7 @@ import {
3
3
  IssuesCategory,
4
4
  IssuePriority,
5
5
  EntityType,
6
- } from "../../../types/issue.types";
6
+ } from "./issue.types";
7
7
 
8
8
  /**
9
9
  * IssueBuilder - A builder pattern implementation for constructing CreateIssueData objects
@@ -1,6 +1,6 @@
1
1
  import { IssueService } from "./Issue.service";
2
- import { IssueBuilder } from "../entities/IssueBuilder";
3
- import { IssuesCategory, IssuePriority, EntityType } from "../../../types/issue.types";
2
+ import { IssueBuilder } from "./IssueBuilder";
3
+ import { IssuesCategory, IssuePriority, EntityType } from "./issue.types";
4
4
 
5
5
  /**
6
6
  * Example usage of the updated IssueService with IssueBuilder integration
@@ -291,17 +291,18 @@ export class IssueServiceExample {
291
291
  category: IssuesCategory.OPERATIONS,
292
292
  propertyId: "prop123",
293
293
  title: "Legacy Issue",
294
- description: "This issue was created using the old CreateIssueData format",
294
+ description:
295
+ "This issue was created using the old CreateIssueData format",
295
296
  entityId: "device456",
296
297
  entityType: EntityType.DEVICE,
297
298
  priority: IssuePriority.MEDIUM,
298
299
  assignedTo: "tech-support",
299
300
  createdBy: "legacy-system",
300
- dueDate: new Date("2024-01-20")
301
+ dueDate: new Date("2024-01-20"),
301
302
  };
302
303
 
303
304
  // This still works with the updated createIssue method
304
305
  const issue = await this.issueService.createIssue(issueData);
305
306
  return issue;
306
307
  }
307
- }
308
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./Issue.service";
2
+ export * from "./issue.types";
@@ -1,6 +1,6 @@
1
- import { getPostgresClient } from "../../../db";
1
+ import { getPostgresClient } from "../db";
2
2
  import { Service } from "typedi";
3
- import { IProperty, IPropertySettings } from "../interfaces/IProperty";
3
+ import { IProperty, IPropertySettings } from "./IProperty";
4
4
 
5
5
  @Service()
6
6
  export class PropertyRepository {
@@ -1,4 +1,4 @@
1
- import { PropertyRepository } from "../repository/Property.repository";
1
+ import { PropertyRepository } from "./Property.repository";
2
2
 
3
3
  export class LocalPropertyService {
4
4
  private readonly propertyRepository: PropertyRepository;
@@ -0,0 +1,2 @@
1
+ export * from "./IProperty";
2
+ export * from "./Property.service";
@@ -0,0 +1,272 @@
1
+ import { HttpCallOption } from "../types/http.types";
2
+ import { getConfig } from "../../config/config";
3
+ import axios from "axios";
4
+ import { publishAudit } from "dt-audit-library";
5
+ import { Service } from "typedi";
6
+ import { RateLimitUtils } from "../utils/rateLimit.utils";
7
+ import { JobUtils } from "../utils/jobUtils";
8
+ import { QueueUtils } from "../utils/queueUtils";
9
+ import {
10
+ IRateLimitConfig,
11
+ IJobResult,
12
+ IHttpRequestJob,
13
+ IQueueResponse,
14
+ } from "../interfaces";
15
+ import { Queue } from "bullmq";
16
+
17
+ @Service()
18
+ export class HybridHttpQueue {
19
+ private readonly queues = new Map<string, any>();
20
+ private readonly workers = new Map<string, any>();
21
+ private readonly rateLimitConfigs: Map<string, IRateLimitConfig>;
22
+ private readonly jobResults = new Map<string, IJobResult>();
23
+
24
+ constructor() {
25
+ this.rateLimitConfigs = RateLimitUtils.initializeRateLimitConfigs();
26
+ }
27
+
28
+ private async handleRateLimitAndQueue(
29
+ url: string,
30
+ method: string,
31
+ options: HttpCallOption
32
+ ): Promise<IQueueResponse> {
33
+ const { connectionId, provider, microservice } =
34
+ JobUtils.extractConnectionDetails(options);
35
+ const key = `rate_limit:${provider}:${connectionId}`;
36
+ const config = this.rateLimitConfigs.get(provider);
37
+ const windowMs = config?.windowMs ?? 60000;
38
+
39
+ const timestamps = await RateLimitUtils.getRawRequestTimestamps(key);
40
+ const now = Date.now();
41
+ const windowStart = now - windowMs;
42
+ const recentRequests = timestamps.filter((t) => t > windowStart);
43
+ const nextAvailableTime =
44
+ recentRequests.length > 0 ? recentRequests[0] + windowMs : now + 1000;
45
+ const delay = Math.max(nextAvailableTime - now, 1000); // at least 1s delay
46
+
47
+ // Create job data
48
+ const jobData = {
49
+ microservice,
50
+ connectionId,
51
+ provider,
52
+ url,
53
+ method,
54
+ options,
55
+ timestamp: Date.now(),
56
+ };
57
+
58
+ // Add job to queue with delay (background processing)
59
+ const queueKey = QueueUtils.getQueueKey(
60
+ microservice,
61
+ connectionId,
62
+ provider
63
+ );
64
+ const queue = QueueUtils.getOrCreateQueue(queueKey, this.queues);
65
+
66
+ QueueUtils.getOrCreateWorker(
67
+ queueKey,
68
+ this.workers,
69
+ this.processHttpRequest.bind(this),
70
+ this.jobResults
71
+ );
72
+
73
+ const job = await queue.add("http-request", jobData, {
74
+ delay,
75
+ attempts: 1,
76
+ removeOnComplete: { age: 300, count: 1 },
77
+ removeOnFail: { age: 300, count: 1 },
78
+ });
79
+
80
+ await publishAudit({
81
+ eventType: "http.request.rateLimitQueued",
82
+ properties: {
83
+ resource: microservice,
84
+ connectionId,
85
+ provider,
86
+ endpoint: url,
87
+ method,
88
+ timestamp: Date.now(),
89
+ queueId: job.id,
90
+ reason: "rate_limit_exceeded_queued",
91
+ delay,
92
+ estimatedProcessingTime: now + delay,
93
+ },
94
+ });
95
+
96
+ // Return immediate response to controller
97
+ return {
98
+ success: true,
99
+ queued: true,
100
+ estimatedProcessingTime: now + delay,
101
+ jobId: job.id,
102
+ };
103
+ }
104
+
105
+ private async processHttpRequest(job: any): Promise<any> {
106
+ const { connectionId, provider, url, method, options } = job.data;
107
+
108
+ const allowed = await RateLimitUtils.isRateLimitAllowed(
109
+ connectionId,
110
+ provider,
111
+ this.rateLimitConfigs
112
+ );
113
+
114
+ if (!allowed) {
115
+ // This shouldn't happen since we check before queuing, but handle it gracefully
116
+ getConfig().LOGGER.warn(
117
+ `Job ${job.id} still rate limited after delay, skipping`
118
+ );
119
+ return;
120
+ }
121
+
122
+ await RateLimitUtils.recordRequest(connectionId, provider);
123
+
124
+ try {
125
+ getConfig().LOGGER.info(
126
+ `Executing HTTP request: ${method} ${url} for ${provider}`
127
+ );
128
+
129
+ const response = await axios({
130
+ method: method.toLowerCase(),
131
+ url: url,
132
+ headers: options.headers || {},
133
+ timeout: 30000,
134
+ ...(options.body && { data: options.body }),
135
+ ...(options.params && { params: options.params }),
136
+ });
137
+
138
+ getConfig().LOGGER.info(
139
+ `HTTP request successful: ${method} ${url} for ${provider}`
140
+ );
141
+ return response.data;
142
+ } catch (error: any) {
143
+ getConfig().LOGGER.error(
144
+ `HTTP request failed ${job.id}: ${error.message}`
145
+ );
146
+
147
+ await publishAudit({
148
+ eventType: "http.request.error",
149
+ properties: {
150
+ connectionId,
151
+ provider,
152
+ endpoint: url,
153
+ method,
154
+ timestamp: Date.now(),
155
+ queueId: job.id,
156
+ reason: "execution_error",
157
+ errorMessage: error.message,
158
+ },
159
+ });
160
+
161
+ throw new Error(`HTTP request failed: ${error.message}`);
162
+ }
163
+ }
164
+
165
+ async request(options: {
166
+ method: string;
167
+ url: string;
168
+ body?: any;
169
+ headers?: Record<string, string>;
170
+ queueOptions?: {
171
+ connectionId: string;
172
+ connectionProvider: string;
173
+ microservice: string;
174
+ };
175
+ }): Promise<IQueueResponse> {
176
+ const { method, url, body, headers, queueOptions } = options;
177
+ // Create HttpCallOption object
178
+ const httpCallOption: HttpCallOption = {
179
+ headers,
180
+ body,
181
+ queueOptions,
182
+ };
183
+ // Call handleRequest with the constructed parameters
184
+ return this.handleRequest(url, method, httpCallOption);
185
+ }
186
+
187
+ async handleRequest(
188
+ url: string,
189
+ method: string,
190
+ options: HttpCallOption
191
+ ): Promise<IQueueResponse> {
192
+ const { connectionId, provider, microservice } =
193
+ JobUtils.extractConnectionDetails(options);
194
+
195
+ // Check rate limit first
196
+ const allowed = await RateLimitUtils.isRateLimitAllowed(
197
+ connectionId,
198
+ provider,
199
+ this.rateLimitConfigs
200
+ );
201
+
202
+ if (!allowed) {
203
+ // Rate limited - queue the request and return immediate response
204
+ return this.handleRateLimitAndQueue(url, method, options);
205
+ }
206
+
207
+ // Not rate limited - process immediately
208
+ getConfig().LOGGER.info(
209
+ `Processing immediately: ${method} ${url} -> ${provider} [${connectionId}]`
210
+ );
211
+
212
+ try {
213
+ // Record the request first
214
+ await RateLimitUtils.recordRequest(connectionId, provider);
215
+
216
+ // Execute the HTTP request
217
+ const response = await axios({
218
+ method: method.toLowerCase(),
219
+ url: url,
220
+ headers: options.headers || {},
221
+ timeout: 30000,
222
+ ...(options.body && { data: options.body }),
223
+ ...(options.params && { params: options.params }),
224
+ });
225
+
226
+ getConfig().LOGGER.info(
227
+ `HTTP request successful: ${method} ${url} for ${provider}`
228
+ );
229
+
230
+ return {
231
+ success: true,
232
+ data: response.data,
233
+ queued: false,
234
+ };
235
+ } catch (error: any) {
236
+ getConfig().LOGGER.error(`HTTP request failed: ${error.message}`);
237
+
238
+ await publishAudit({
239
+ eventType: "http.request.error",
240
+ properties: {
241
+ connectionId,
242
+ provider,
243
+ endpoint: url,
244
+ method,
245
+ timestamp: Date.now(),
246
+ reason: "execution_error",
247
+ errorMessage: error.message,
248
+ },
249
+ });
250
+
251
+ return {
252
+ success: false,
253
+ error: `HTTP request failed: ${error.message}`,
254
+ queued: false,
255
+ };
256
+ }
257
+ }
258
+
259
+ async shutdown(): Promise<void> {
260
+ getConfig().LOGGER.info("Shutting down HTTP queues...");
261
+
262
+ await Promise.all([
263
+ ...Array.from(this.workers.values()).map((worker: any) => worker.close()),
264
+ ...Array.from(this.queues.values()).map((queue: any) => queue.close()),
265
+ ]);
266
+
267
+ this.workers.clear();
268
+ this.queues.clear();
269
+ this.jobResults.clear();
270
+ getConfig().LOGGER.info("HTTP queues shutdown complete");
271
+ }
272
+ }
@@ -0,0 +1 @@
1
+ export * from "./HybridHttpQueue";
@@ -0,0 +1,6 @@
1
+ // Main queue exports
2
+ export * from "./entities";
3
+ export * from "./interfaces";
4
+ export * from "./services";
5
+ export * from "./types";
6
+ export * from "./utils";
@@ -0,0 +1,10 @@
1
+ import { HttpCallOption } from "../types/http.types";
2
+
3
+ export interface IHttpRequestJob {
4
+ connectionId: string;
5
+ provider: string;
6
+ url: string;
7
+ method: string;
8
+ options: HttpCallOption;
9
+ timestamp: number;
10
+ }
@@ -0,0 +1,24 @@
1
+ import { HttpCallOption } from "../types/http.types";
2
+ import { IQueueResponse } from "./IJobResult";
3
+
4
+ export interface IHybridHttpQueue {
5
+ request(options: {
6
+ method: string;
7
+ url: string;
8
+ body?: any;
9
+ headers?: Record<string, string>;
10
+ queueOptions?: {
11
+ connectionId: string;
12
+ connectionProvider: string;
13
+ microservice: string;
14
+ };
15
+ }): Promise<IQueueResponse>;
16
+
17
+ handleRequest(
18
+ url: string,
19
+ method: string,
20
+ options: HttpCallOption
21
+ ): Promise<IQueueResponse>;
22
+
23
+ shutdown(): Promise<void>;
24
+ }
@@ -0,0 +1,15 @@
1
+ export interface IJobResult {
2
+ result?: any;
3
+ error?: string;
4
+ resolved: boolean;
5
+ timestamp: number;
6
+ }
7
+
8
+ export interface IQueueResponse {
9
+ success: boolean;
10
+ data?: any;
11
+ error?: string;
12
+ queued?: boolean;
13
+ estimatedProcessingTime?: number;
14
+ jobId?: string;
15
+ }
@@ -0,0 +1,5 @@
1
+ export interface IRateLimitConfig {
2
+ maxRequests: number;
3
+ windowMs: number;
4
+ provider: string;
5
+ }
@@ -0,0 +1,4 @@
1
+ export * from "./IHybridHttpQueue";
2
+ export * from "./IHttpRequestJob";
3
+ export * from "./IJobResult";
4
+ export * from "./IRateLimitConfig";
@@ -0,0 +1,39 @@
1
+ import { Service } from "typedi";
2
+ import { HybridHttpQueue } from "../entities/HybridHttpQueue";
3
+ import { IHybridHttpQueue, IQueueResponse } from "../interfaces";
4
+ import { HttpCallOption } from "../types/http.types";
5
+
6
+ @Service()
7
+ export class QueueService implements IHybridHttpQueue {
8
+ private readonly hybridQueue: HybridHttpQueue;
9
+
10
+ constructor() {
11
+ this.hybridQueue = new HybridHttpQueue();
12
+ }
13
+
14
+ async request(options: {
15
+ method: string;
16
+ url: string;
17
+ body?: any;
18
+ headers?: Record<string, string>;
19
+ queueOptions?: {
20
+ connectionId: string;
21
+ connectionProvider: string;
22
+ microservice: string;
23
+ };
24
+ }): Promise<IQueueResponse> {
25
+ return this.hybridQueue.request(options);
26
+ }
27
+
28
+ async handleRequest(
29
+ url: string,
30
+ method: string,
31
+ options: HttpCallOption
32
+ ): Promise<IQueueResponse> {
33
+ return this.hybridQueue.handleRequest(url, method, options);
34
+ }
35
+
36
+ async shutdown(): Promise<void> {
37
+ return this.hybridQueue.shutdown();
38
+ }
39
+ }
@@ -0,0 +1 @@
1
+ export * from "./QueueService";
@@ -0,0 +1,22 @@
1
+ export interface HttpCallOption {
2
+ headers?: Record<string, string>;
3
+ body?: any;
4
+ params?: Record<string, any>;
5
+ queueOptions?: {
6
+ connectionId: string;
7
+ connectionProvider: string;
8
+ microservice: string;
9
+ };
10
+ }
11
+
12
+ export interface HttpRequestOptions {
13
+ method: string;
14
+ url: string;
15
+ body?: any;
16
+ headers?: Record<string, string>;
17
+ queueOptions?: {
18
+ connectionId: string;
19
+ connectionProvider: string;
20
+ microservice: string;
21
+ };
22
+ }