@meyicloud/meyi-insight-server 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (389) hide show
  1. package/dist/constants/incidentCategories.d.ts +18 -0
  2. package/dist/constants/incidentCategories.d.ts.map +1 -0
  3. package/dist/constants/incidentCategories.js +36 -0
  4. package/dist/constants/incidentCategories.js.map +1 -0
  5. package/dist/controllers/alert.controller.d.ts +12 -0
  6. package/dist/controllers/alert.controller.d.ts.map +1 -0
  7. package/dist/controllers/alert.controller.js +89 -0
  8. package/dist/controllers/alert.controller.js.map +1 -0
  9. package/dist/controllers/incident.controller.d.ts +16 -0
  10. package/dist/controllers/incident.controller.d.ts.map +1 -0
  11. package/dist/controllers/incident.controller.js +215 -0
  12. package/dist/controllers/incident.controller.js.map +1 -0
  13. package/dist/controllers/notification-provider.controller.d.ts +10 -0
  14. package/dist/controllers/notification-provider.controller.d.ts.map +1 -0
  15. package/dist/controllers/notification-provider.controller.js +59 -0
  16. package/dist/controllers/notification-provider.controller.js.map +1 -0
  17. package/dist/controllers/settings.controller.d.ts +7 -0
  18. package/dist/controllers/settings.controller.d.ts.map +1 -0
  19. package/dist/controllers/settings.controller.js +27 -0
  20. package/dist/controllers/settings.controller.js.map +1 -0
  21. package/dist/controllers/sop.controller.d.ts +11 -0
  22. package/dist/controllers/sop.controller.d.ts.map +1 -0
  23. package/dist/controllers/sop.controller.js +89 -0
  24. package/dist/controllers/sop.controller.js.map +1 -0
  25. package/dist/controllers/source.controller.d.ts +26 -0
  26. package/dist/controllers/source.controller.d.ts.map +1 -0
  27. package/dist/controllers/source.controller.js +333 -0
  28. package/dist/controllers/source.controller.js.map +1 -0
  29. package/dist/controllers/sourceDatadog.controller.d.ts +17 -0
  30. package/dist/controllers/sourceDatadog.controller.d.ts.map +1 -0
  31. package/dist/controllers/sourceDatadog.controller.js +169 -0
  32. package/dist/controllers/sourceDatadog.controller.js.map +1 -0
  33. package/dist/controllers/tenant.controller.d.ts +7 -0
  34. package/dist/controllers/tenant.controller.d.ts.map +1 -0
  35. package/dist/controllers/tenant.controller.js +33 -0
  36. package/dist/controllers/tenant.controller.js.map +1 -0
  37. package/dist/controllers/webhook.controller.d.ts +6 -0
  38. package/dist/controllers/webhook.controller.d.ts.map +1 -0
  39. package/dist/controllers/webhook.controller.js +83 -0
  40. package/dist/controllers/webhook.controller.js.map +1 -0
  41. package/dist/controllers/workflow.controller.d.ts +18 -0
  42. package/dist/controllers/workflow.controller.d.ts.map +1 -0
  43. package/dist/controllers/workflow.controller.js +118 -0
  44. package/dist/controllers/workflow.controller.js.map +1 -0
  45. package/dist/database/index.d.ts +7 -0
  46. package/dist/database/index.d.ts.map +1 -0
  47. package/dist/database/index.js +12 -0
  48. package/dist/database/index.js.map +1 -0
  49. package/dist/database/schema.d.ts +5358 -0
  50. package/dist/database/schema.d.ts.map +1 -0
  51. package/dist/database/schema.js +516 -0
  52. package/dist/database/schema.js.map +1 -0
  53. package/dist/features/sources/cloudtrail/controller.d.ts +38 -0
  54. package/dist/features/sources/cloudtrail/controller.d.ts.map +1 -0
  55. package/dist/features/sources/cloudtrail/controller.js +421 -0
  56. package/dist/features/sources/cloudtrail/controller.js.map +1 -0
  57. package/dist/features/sources/cloudtrail/routes.d.ts +6 -0
  58. package/dist/features/sources/cloudtrail/routes.d.ts.map +1 -0
  59. package/dist/features/sources/cloudtrail/routes.js +8 -0
  60. package/dist/features/sources/cloudtrail/routes.js.map +1 -0
  61. package/dist/features/sources/cloudtrail/schema.d.ts +2 -0
  62. package/dist/features/sources/cloudtrail/schema.d.ts.map +1 -0
  63. package/dist/features/sources/cloudtrail/schema.js +26 -0
  64. package/dist/features/sources/cloudtrail/schema.js.map +1 -0
  65. package/dist/features/sources/cloudtrail/stackTemplates.d.ts +3 -0
  66. package/dist/features/sources/cloudtrail/stackTemplates.d.ts.map +1 -0
  67. package/dist/features/sources/cloudtrail/stackTemplates.js +548 -0
  68. package/dist/features/sources/cloudtrail/stackTemplates.js.map +1 -0
  69. package/dist/features/sources/cloudtrail/template.d.ts +21 -0
  70. package/dist/features/sources/cloudtrail/template.d.ts.map +1 -0
  71. package/dist/features/sources/cloudtrail/template.js +1230 -0
  72. package/dist/features/sources/cloudtrail/template.js.map +1 -0
  73. package/dist/features/sources/cloudwatch/controller.d.ts +13 -0
  74. package/dist/features/sources/cloudwatch/controller.d.ts.map +1 -0
  75. package/dist/features/sources/cloudwatch/controller.js +514 -0
  76. package/dist/features/sources/cloudwatch/controller.js.map +1 -0
  77. package/dist/features/sources/cloudwatch/eventbridgeTemplate.d.ts +7 -0
  78. package/dist/features/sources/cloudwatch/eventbridgeTemplate.d.ts.map +1 -0
  79. package/dist/features/sources/cloudwatch/eventbridgeTemplate.js +230 -0
  80. package/dist/features/sources/cloudwatch/eventbridgeTemplate.js.map +1 -0
  81. package/dist/features/sources/cloudwatch/service.d.ts +50 -0
  82. package/dist/features/sources/cloudwatch/service.d.ts.map +1 -0
  83. package/dist/features/sources/cloudwatch/service.js +269 -0
  84. package/dist/features/sources/cloudwatch/service.js.map +1 -0
  85. package/dist/features/sources/cloudwatch/template.d.ts +26 -0
  86. package/dist/features/sources/cloudwatch/template.d.ts.map +1 -0
  87. package/dist/features/sources/cloudwatch/template.js +335 -0
  88. package/dist/features/sources/cloudwatch/template.js.map +1 -0
  89. package/dist/features/sources/cloudwatch/types.d.ts +26 -0
  90. package/dist/features/sources/cloudwatch/types.d.ts.map +1 -0
  91. package/dist/features/sources/cloudwatch/types.js +2 -0
  92. package/dist/features/sources/cloudwatch/types.js.map +1 -0
  93. package/dist/features/sources/grafana/controller.d.ts +18 -0
  94. package/dist/features/sources/grafana/controller.d.ts.map +1 -0
  95. package/dist/features/sources/grafana/controller.js +183 -0
  96. package/dist/features/sources/grafana/controller.js.map +1 -0
  97. package/dist/features/sources/grafana/routes.d.ts +6 -0
  98. package/dist/features/sources/grafana/routes.d.ts.map +1 -0
  99. package/dist/features/sources/grafana/routes.js +6 -0
  100. package/dist/features/sources/grafana/routes.js.map +1 -0
  101. package/dist/features/sources/grafana/schema.d.ts +2 -0
  102. package/dist/features/sources/grafana/schema.d.ts.map +1 -0
  103. package/dist/features/sources/grafana/schema.js +24 -0
  104. package/dist/features/sources/grafana/schema.js.map +1 -0
  105. package/dist/features/sources/grafana/service.d.ts +33 -0
  106. package/dist/features/sources/grafana/service.d.ts.map +1 -0
  107. package/dist/features/sources/grafana/service.js +215 -0
  108. package/dist/features/sources/grafana/service.js.map +1 -0
  109. package/dist/features/sources/index.d.ts +29 -0
  110. package/dist/features/sources/index.d.ts.map +1 -0
  111. package/dist/features/sources/index.js +47 -0
  112. package/dist/features/sources/index.js.map +1 -0
  113. package/dist/features/sources/observability/controller.d.ts +6 -0
  114. package/dist/features/sources/observability/controller.d.ts.map +1 -0
  115. package/dist/features/sources/observability/controller.js +16 -0
  116. package/dist/features/sources/observability/controller.js.map +1 -0
  117. package/dist/features/sources/observability/routes.d.ts +4 -0
  118. package/dist/features/sources/observability/routes.d.ts.map +1 -0
  119. package/dist/features/sources/observability/routes.js +8 -0
  120. package/dist/features/sources/observability/routes.js.map +1 -0
  121. package/dist/features/sources/observability/schema.d.ts +3 -0
  122. package/dist/features/sources/observability/schema.d.ts.map +1 -0
  123. package/dist/features/sources/observability/schema.js +44 -0
  124. package/dist/features/sources/observability/schema.js.map +1 -0
  125. package/dist/features/sources/observability/service.d.ts +36 -0
  126. package/dist/features/sources/observability/service.d.ts.map +1 -0
  127. package/dist/features/sources/observability/service.js +127 -0
  128. package/dist/features/sources/observability/service.js.map +1 -0
  129. package/dist/features/sources/prometheus/controller.d.ts +9 -0
  130. package/dist/features/sources/prometheus/controller.d.ts.map +1 -0
  131. package/dist/features/sources/prometheus/controller.js +359 -0
  132. package/dist/features/sources/prometheus/controller.js.map +1 -0
  133. package/dist/features/sources/prometheus/templates.d.ts +18 -0
  134. package/dist/features/sources/prometheus/templates.d.ts.map +1 -0
  135. package/dist/features/sources/prometheus/templates.js +244 -0
  136. package/dist/features/sources/prometheus/templates.js.map +1 -0
  137. package/dist/index.d.ts +7 -0
  138. package/dist/index.d.ts.map +1 -0
  139. package/dist/index.js +7 -0
  140. package/dist/index.js.map +1 -0
  141. package/dist/migrations/0007_pipeline_yaml_definitions.d.ts +3 -0
  142. package/dist/migrations/0007_pipeline_yaml_definitions.d.ts.map +1 -0
  143. package/dist/migrations/0007_pipeline_yaml_definitions.js +19 -0
  144. package/dist/migrations/0007_pipeline_yaml_definitions.js.map +1 -0
  145. package/dist/migrations/0008_tenant_isolation.d.ts +3 -0
  146. package/dist/migrations/0008_tenant_isolation.d.ts.map +1 -0
  147. package/dist/migrations/0008_tenant_isolation.js +42 -0
  148. package/dist/migrations/0008_tenant_isolation.js.map +1 -0
  149. package/dist/migrations/run.d.ts +6 -0
  150. package/dist/migrations/run.d.ts.map +1 -0
  151. package/dist/migrations/run.js +1262 -0
  152. package/dist/migrations/run.js.map +1 -0
  153. package/dist/models/alarm-group.model.d.ts +42 -0
  154. package/dist/models/alarm-group.model.d.ts.map +1 -0
  155. package/dist/models/alarm-group.model.js +98 -0
  156. package/dist/models/alarm-group.model.js.map +1 -0
  157. package/dist/models/alert.model.d.ts +54 -0
  158. package/dist/models/alert.model.d.ts.map +1 -0
  159. package/dist/models/alert.model.js +119 -0
  160. package/dist/models/alert.model.js.map +1 -0
  161. package/dist/models/dedup-config.model.d.ts +53 -0
  162. package/dist/models/dedup-config.model.d.ts.map +1 -0
  163. package/dist/models/dedup-config.model.js +157 -0
  164. package/dist/models/dedup-config.model.js.map +1 -0
  165. package/dist/models/grouping-config.model.d.ts +70 -0
  166. package/dist/models/grouping-config.model.d.ts.map +1 -0
  167. package/dist/models/grouping-config.model.js +174 -0
  168. package/dist/models/grouping-config.model.js.map +1 -0
  169. package/dist/models/incident-comment.model.d.ts +14 -0
  170. package/dist/models/incident-comment.model.d.ts.map +1 -0
  171. package/dist/models/incident-comment.model.js +38 -0
  172. package/dist/models/incident-comment.model.js.map +1 -0
  173. package/dist/models/incident-event.model.d.ts +16 -0
  174. package/dist/models/incident-event.model.d.ts.map +1 -0
  175. package/dist/models/incident-event.model.js +31 -0
  176. package/dist/models/incident-event.model.js.map +1 -0
  177. package/dist/models/incident.model.d.ts +47 -0
  178. package/dist/models/incident.model.d.ts.map +1 -0
  179. package/dist/models/incident.model.js +201 -0
  180. package/dist/models/incident.model.js.map +1 -0
  181. package/dist/models/normalization-config.model.d.ts +44 -0
  182. package/dist/models/normalization-config.model.d.ts.map +1 -0
  183. package/dist/models/normalization-config.model.js +153 -0
  184. package/dist/models/normalization-config.model.js.map +1 -0
  185. package/dist/models/notification-provider.model.d.ts +12 -0
  186. package/dist/models/notification-provider.model.d.ts.map +1 -0
  187. package/dist/models/notification-provider.model.js +48 -0
  188. package/dist/models/notification-provider.model.js.map +1 -0
  189. package/dist/models/pipeline-event.model.d.ts +15 -0
  190. package/dist/models/pipeline-event.model.d.ts.map +1 -0
  191. package/dist/models/pipeline-event.model.js +32 -0
  192. package/dist/models/pipeline-event.model.js.map +1 -0
  193. package/dist/models/settings.model.d.ts +8 -0
  194. package/dist/models/settings.model.d.ts.map +1 -0
  195. package/dist/models/settings.model.js +30 -0
  196. package/dist/models/settings.model.js.map +1 -0
  197. package/dist/models/sop.model.d.ts +58 -0
  198. package/dist/models/sop.model.d.ts.map +1 -0
  199. package/dist/models/sop.model.js +138 -0
  200. package/dist/models/sop.model.js.map +1 -0
  201. package/dist/models/source.model.d.ts +177 -0
  202. package/dist/models/source.model.d.ts.map +1 -0
  203. package/dist/models/source.model.js +794 -0
  204. package/dist/models/source.model.js.map +1 -0
  205. package/dist/models/tenant.model.d.ts +13 -0
  206. package/dist/models/tenant.model.d.ts.map +1 -0
  207. package/dist/models/tenant.model.js +28 -0
  208. package/dist/models/tenant.model.js.map +1 -0
  209. package/dist/models/workflow.model.d.ts +36 -0
  210. package/dist/models/workflow.model.d.ts.map +1 -0
  211. package/dist/models/workflow.model.js +136 -0
  212. package/dist/models/workflow.model.js.map +1 -0
  213. package/dist/pipeline/AlarmPipelineWorker.d.ts +18 -0
  214. package/dist/pipeline/AlarmPipelineWorker.d.ts.map +1 -0
  215. package/dist/pipeline/AlarmPipelineWorker.js +342 -0
  216. package/dist/pipeline/AlarmPipelineWorker.js.map +1 -0
  217. package/dist/pipeline/CanonicalAlarm.d.ts +59 -0
  218. package/dist/pipeline/CanonicalAlarm.d.ts.map +1 -0
  219. package/dist/pipeline/CanonicalAlarm.js +81 -0
  220. package/dist/pipeline/CanonicalAlarm.js.map +1 -0
  221. package/dist/pipeline/DedupService.d.ts +29 -0
  222. package/dist/pipeline/DedupService.d.ts.map +1 -0
  223. package/dist/pipeline/DedupService.js +172 -0
  224. package/dist/pipeline/DedupService.js.map +1 -0
  225. package/dist/pipeline/GroupFlushWorker.d.ts +16 -0
  226. package/dist/pipeline/GroupFlushWorker.d.ts.map +1 -0
  227. package/dist/pipeline/GroupFlushWorker.js +196 -0
  228. package/dist/pipeline/GroupFlushWorker.js.map +1 -0
  229. package/dist/pipeline/GroupingService.d.ts +27 -0
  230. package/dist/pipeline/GroupingService.d.ts.map +1 -0
  231. package/dist/pipeline/GroupingService.js +338 -0
  232. package/dist/pipeline/GroupingService.js.map +1 -0
  233. package/dist/pipeline/NormalizationRuleEngine.d.ts +5 -0
  234. package/dist/pipeline/NormalizationRuleEngine.d.ts.map +1 -0
  235. package/dist/pipeline/NormalizationRuleEngine.js +86 -0
  236. package/dist/pipeline/NormalizationRuleEngine.js.map +1 -0
  237. package/dist/pipeline/NormalizationService.d.ts +29 -0
  238. package/dist/pipeline/NormalizationService.d.ts.map +1 -0
  239. package/dist/pipeline/NormalizationService.js +275 -0
  240. package/dist/pipeline/NormalizationService.js.map +1 -0
  241. package/dist/pipeline/alarmQueue.d.ts +66 -0
  242. package/dist/pipeline/alarmQueue.d.ts.map +1 -0
  243. package/dist/pipeline/alarmQueue.js +254 -0
  244. package/dist/pipeline/alarmQueue.js.map +1 -0
  245. package/dist/pipeline/defaults/ensureDefaults.d.ts +3 -0
  246. package/dist/pipeline/defaults/ensureDefaults.d.ts.map +1 -0
  247. package/dist/pipeline/defaults/ensureDefaults.js +124 -0
  248. package/dist/pipeline/defaults/ensureDefaults.js.map +1 -0
  249. package/dist/pipeline/defaults/pipelineDefaults.d.ts +13 -0
  250. package/dist/pipeline/defaults/pipelineDefaults.d.ts.map +1 -0
  251. package/dist/pipeline/defaults/pipelineDefaults.js +266 -0
  252. package/dist/pipeline/defaults/pipelineDefaults.js.map +1 -0
  253. package/dist/pipeline/yaml/DedupYaml.d.ts +33 -0
  254. package/dist/pipeline/yaml/DedupYaml.d.ts.map +1 -0
  255. package/dist/pipeline/yaml/DedupYaml.js +25 -0
  256. package/dist/pipeline/yaml/DedupYaml.js.map +1 -0
  257. package/dist/pipeline/yaml/GroupingYaml.d.ts +49 -0
  258. package/dist/pipeline/yaml/GroupingYaml.d.ts.map +1 -0
  259. package/dist/pipeline/yaml/GroupingYaml.js +39 -0
  260. package/dist/pipeline/yaml/GroupingYaml.js.map +1 -0
  261. package/dist/pipeline/yaml/NormalizationYaml.d.ts +54 -0
  262. package/dist/pipeline/yaml/NormalizationYaml.d.ts.map +1 -0
  263. package/dist/pipeline/yaml/NormalizationYaml.js +23 -0
  264. package/dist/pipeline/yaml/NormalizationYaml.js.map +1 -0
  265. package/dist/pipeline/yaml/pipelineYaml.d.ts +11 -0
  266. package/dist/pipeline/yaml/pipelineYaml.d.ts.map +1 -0
  267. package/dist/pipeline/yaml/pipelineYaml.js +49 -0
  268. package/dist/pipeline/yaml/pipelineYaml.js.map +1 -0
  269. package/dist/realtime/events.d.ts +11 -0
  270. package/dist/realtime/events.d.ts.map +1 -0
  271. package/dist/realtime/events.js +21 -0
  272. package/dist/realtime/events.js.map +1 -0
  273. package/dist/routes/alert.routes.d.ts +4 -0
  274. package/dist/routes/alert.routes.d.ts.map +1 -0
  275. package/dist/routes/alert.routes.js +15 -0
  276. package/dist/routes/alert.routes.js.map +1 -0
  277. package/dist/routes/dedup-config.routes.d.ts +4 -0
  278. package/dist/routes/dedup-config.routes.d.ts.map +1 -0
  279. package/dist/routes/dedup-config.routes.js +82 -0
  280. package/dist/routes/dedup-config.routes.js.map +1 -0
  281. package/dist/routes/grouping-config.routes.d.ts +4 -0
  282. package/dist/routes/grouping-config.routes.d.ts.map +1 -0
  283. package/dist/routes/grouping-config.routes.js +82 -0
  284. package/dist/routes/grouping-config.routes.js.map +1 -0
  285. package/dist/routes/incident.routes.d.ts +4 -0
  286. package/dist/routes/incident.routes.d.ts.map +1 -0
  287. package/dist/routes/incident.routes.js +21 -0
  288. package/dist/routes/incident.routes.js.map +1 -0
  289. package/dist/routes/index.d.ts +47 -0
  290. package/dist/routes/index.d.ts.map +1 -0
  291. package/dist/routes/index.js +83 -0
  292. package/dist/routes/index.js.map +1 -0
  293. package/dist/routes/normalization-config.routes.d.ts +4 -0
  294. package/dist/routes/normalization-config.routes.d.ts.map +1 -0
  295. package/dist/routes/normalization-config.routes.js +199 -0
  296. package/dist/routes/normalization-config.routes.js.map +1 -0
  297. package/dist/routes/notification-provider.routes.d.ts +4 -0
  298. package/dist/routes/notification-provider.routes.d.ts.map +1 -0
  299. package/dist/routes/notification-provider.routes.js +13 -0
  300. package/dist/routes/notification-provider.routes.js.map +1 -0
  301. package/dist/routes/pipeline.routes.d.ts +8 -0
  302. package/dist/routes/pipeline.routes.d.ts.map +1 -0
  303. package/dist/routes/pipeline.routes.js +243 -0
  304. package/dist/routes/pipeline.routes.js.map +1 -0
  305. package/dist/routes/settings.routes.d.ts +4 -0
  306. package/dist/routes/settings.routes.d.ts.map +1 -0
  307. package/dist/routes/settings.routes.js +10 -0
  308. package/dist/routes/settings.routes.js.map +1 -0
  309. package/dist/routes/sop.routes.d.ts +4 -0
  310. package/dist/routes/sop.routes.d.ts.map +1 -0
  311. package/dist/routes/sop.routes.js +14 -0
  312. package/dist/routes/sop.routes.js.map +1 -0
  313. package/dist/routes/source.routes.d.ts +9 -0
  314. package/dist/routes/source.routes.d.ts.map +1 -0
  315. package/dist/routes/source.routes.js +31 -0
  316. package/dist/routes/source.routes.js.map +1 -0
  317. package/dist/routes/tenant.routes.d.ts +4 -0
  318. package/dist/routes/tenant.routes.d.ts.map +1 -0
  319. package/dist/routes/tenant.routes.js +10 -0
  320. package/dist/routes/tenant.routes.js.map +1 -0
  321. package/dist/routes/workflow.routes.d.ts +4 -0
  322. package/dist/routes/workflow.routes.d.ts.map +1 -0
  323. package/dist/routes/workflow.routes.js +18 -0
  324. package/dist/routes/workflow.routes.js.map +1 -0
  325. package/dist/server.d.ts +22 -0
  326. package/dist/server.d.ts.map +1 -0
  327. package/dist/server.js +76 -0
  328. package/dist/server.js.map +1 -0
  329. package/dist/service.d.ts +159 -0
  330. package/dist/service.d.ts.map +1 -0
  331. package/dist/service.js +156 -0
  332. package/dist/service.js.map +1 -0
  333. package/dist/services/alert.service.d.ts +76 -0
  334. package/dist/services/alert.service.d.ts.map +1 -0
  335. package/dist/services/alert.service.js +688 -0
  336. package/dist/services/alert.service.js.map +1 -0
  337. package/dist/services/connector.service.d.ts +65 -0
  338. package/dist/services/connector.service.d.ts.map +1 -0
  339. package/dist/services/connector.service.js +28 -0
  340. package/dist/services/connector.service.js.map +1 -0
  341. package/dist/services/incident.service.d.ts +108 -0
  342. package/dist/services/incident.service.d.ts.map +1 -0
  343. package/dist/services/incident.service.js +325 -0
  344. package/dist/services/incident.service.js.map +1 -0
  345. package/dist/services/notification-provider.service.d.ts +12 -0
  346. package/dist/services/notification-provider.service.d.ts.map +1 -0
  347. package/dist/services/notification-provider.service.js +25 -0
  348. package/dist/services/notification-provider.service.js.map +1 -0
  349. package/dist/services/settings.service.d.ts +8 -0
  350. package/dist/services/settings.service.d.ts.map +1 -0
  351. package/dist/services/settings.service.js +14 -0
  352. package/dist/services/settings.service.js.map +1 -0
  353. package/dist/services/sop.service.d.ts +60 -0
  354. package/dist/services/sop.service.d.ts.map +1 -0
  355. package/dist/services/sop.service.js +66 -0
  356. package/dist/services/sop.service.js.map +1 -0
  357. package/dist/services/source.service.d.ts +162 -0
  358. package/dist/services/source.service.d.ts.map +1 -0
  359. package/dist/services/source.service.js +124 -0
  360. package/dist/services/source.service.js.map +1 -0
  361. package/dist/services/tenant.service.d.ts +11 -0
  362. package/dist/services/tenant.service.d.ts.map +1 -0
  363. package/dist/services/tenant.service.js +22 -0
  364. package/dist/services/tenant.service.js.map +1 -0
  365. package/dist/services/workflow.service.d.ts +32 -0
  366. package/dist/services/workflow.service.d.ts.map +1 -0
  367. package/dist/services/workflow.service.js +291 -0
  368. package/dist/services/workflow.service.js.map +1 -0
  369. package/dist/standalone.d.ts +2 -0
  370. package/dist/standalone.d.ts.map +1 -0
  371. package/dist/standalone.js +55 -0
  372. package/dist/standalone.js.map +1 -0
  373. package/dist/tenancy.d.ts +5 -0
  374. package/dist/tenancy.d.ts.map +1 -0
  375. package/dist/tenancy.js +35 -0
  376. package/dist/tenancy.js.map +1 -0
  377. package/dist/utils/notificationTemplates.d.ts +98 -0
  378. package/dist/utils/notificationTemplates.d.ts.map +1 -0
  379. package/dist/utils/notificationTemplates.js +227 -0
  380. package/dist/utils/notificationTemplates.js.map +1 -0
  381. package/dist/utils/secretCrypto.d.ts +3 -0
  382. package/dist/utils/secretCrypto.d.ts.map +1 -0
  383. package/dist/utils/secretCrypto.js +40 -0
  384. package/dist/utils/secretCrypto.js.map +1 -0
  385. package/dist/utils/workflowYaml.d.ts +53 -0
  386. package/dist/utils/workflowYaml.d.ts.map +1 -0
  387. package/dist/utils/workflowYaml.js +269 -0
  388. package/dist/utils/workflowYaml.js.map +1 -0
  389. package/package.json +73 -0
@@ -0,0 +1,688 @@
1
+ import { enqueueAlarm, isRedisAvailable } from "../pipeline/alarmQueue.js";
2
+ import { CloudWatchClient, ListTagsForResourceCommand } from "@aws-sdk/client-cloudwatch";
3
+ function parseMaybeJson(value) {
4
+ if (typeof value !== "string")
5
+ return null;
6
+ try {
7
+ return JSON.parse(value);
8
+ }
9
+ catch {
10
+ return null;
11
+ }
12
+ }
13
+ function parseTags(rawTags) {
14
+ const result = {};
15
+ if (!rawTags)
16
+ return result;
17
+ if (Array.isArray(rawTags)) {
18
+ for (const item of rawTags) {
19
+ if (!item || typeof item !== "object")
20
+ continue;
21
+ const key = item.Key ?? item.key;
22
+ const value = item.Value ?? item.value;
23
+ if (key !== undefined && value !== undefined && key !== null) {
24
+ result[String(key).trim()] = String(value).trim();
25
+ }
26
+ }
27
+ }
28
+ else if (typeof rawTags === "object") {
29
+ for (const [key, value] of Object.entries(rawTags)) {
30
+ if (value !== undefined && value !== null) {
31
+ result[key.trim()] = String(value).trim();
32
+ }
33
+ }
34
+ }
35
+ return result;
36
+ }
37
+ function unwrapCloudWatchPayload(body) {
38
+ if (!body || typeof body !== "object")
39
+ return body;
40
+ const snsMessage = parseMaybeJson(body?.Message);
41
+ if (snsMessage && typeof snsMessage === "object") {
42
+ return snsMessage;
43
+ }
44
+ return body;
45
+ }
46
+ function extractCloudWatchState(payload) {
47
+ if (!payload || typeof payload !== "object")
48
+ return null;
49
+ if (payload?.NewStateValue)
50
+ return payload.NewStateValue;
51
+ if (payload?.detail?.state?.value)
52
+ return payload.detail.state.value;
53
+ if (payload?.alarmData?.state?.value)
54
+ return payload.alarmData.state.value;
55
+ return null;
56
+ }
57
+ function normalizeCloudWatchPayload(body) {
58
+ const payload = unwrapCloudWatchPayload(body);
59
+ if (!payload || typeof payload !== "object")
60
+ return payload;
61
+ const account = payload.account ||
62
+ payload.accountId ||
63
+ payload.AWSAccountId ||
64
+ payload.detail?.recipientAccountId ||
65
+ payload.detail?.account ||
66
+ payload.rawEvent?.account;
67
+ const tags = payload.tags ||
68
+ payload.Tags ||
69
+ payload.detail?.tags ||
70
+ payload.rawEvent?.tags ||
71
+ payload.rawEvent?.detail?.tags;
72
+ const alarmName = payload.AlarmName ||
73
+ payload.alarmName ||
74
+ payload.detail?.alarmName ||
75
+ payload.alarmData?.alarmName;
76
+ const alarmArn = payload.AlarmArn ||
77
+ payload.alarmArn ||
78
+ payload.detail?.alarmArn ||
79
+ (Array.isArray(payload.rawEvent?.resources) && payload.rawEvent.resources[0]) ||
80
+ (Array.isArray(payload.resources) && payload.resources[0]) ||
81
+ (account && alarmName && (payload.region || payload.rawEvent?.region)
82
+ ? `arn:aws:cloudwatch:${payload.region || payload.rawEvent?.region}:${account}:alarm:${alarmName}`
83
+ : undefined);
84
+ if (payload?.alarmData?.state?.value) {
85
+ return {
86
+ ...payload,
87
+ AlarmName: payload.alarmData.alarmName || alarmName,
88
+ AlarmArn: alarmArn || payload.alarmArn,
89
+ alarmArn: alarmArn || payload.alarmArn,
90
+ NewStateValue: payload.alarmData.state.value,
91
+ NewStateReason: payload.alarmData.state.reason,
92
+ StateChangeTime: payload.alarmData.state.timestamp || payload.time,
93
+ configuration: payload.alarmData.configuration,
94
+ ...(account ? { account, accountId: account } : {}),
95
+ ...(tags ? { tags } : {}),
96
+ ...(alarmArn ? { AlarmArn: alarmArn, alarmArn } : {}),
97
+ };
98
+ }
99
+ if (payload?.detail?.state?.value) {
100
+ return {
101
+ ...payload,
102
+ AlarmName: payload.detail.alarmName || alarmName,
103
+ AlarmArn: alarmArn || payload.detail.alarmArn,
104
+ alarmArn: alarmArn || payload.detail.alarmArn,
105
+ NewStateValue: payload.detail.state.value,
106
+ NewStateReason: payload.detail.state.reason,
107
+ StateChangeTime: payload.detail.state.timestamp || payload.time,
108
+ configuration: payload.detail.configuration,
109
+ ...(account ? { account, accountId: account } : {}),
110
+ ...(tags ? { tags } : {}),
111
+ ...(alarmArn ? { AlarmArn: alarmArn, alarmArn } : {}),
112
+ };
113
+ }
114
+ return {
115
+ ...payload,
116
+ ...(account ? { account, accountId: account } : {}),
117
+ ...(tags ? { tags } : {}),
118
+ ...(alarmArn ? { AlarmArn: alarmArn, alarmArn } : {}),
119
+ };
120
+ }
121
+ async function enrichCloudWatchTagsIfMissing(source, body) {
122
+ if (source?.type !== "cloudwatch" || !body || typeof body !== "object")
123
+ return;
124
+ const existingTags = body.tags || body.Tags || body.detail?.tags || body.rawEvent?.tags || body.rawEvent?.detail?.tags;
125
+ if (existingTags && typeof existingTags === "object" && Object.keys(existingTags).length > 0)
126
+ return;
127
+ const alarmArn = body.AlarmArn ||
128
+ body.alarmArn ||
129
+ body.detail?.alarmArn ||
130
+ (Array.isArray(body.rawEvent?.resources) && body.rawEvent.resources[0]) ||
131
+ (Array.isArray(body.resources) && body.resources[0]) ||
132
+ (body.accountId && (body.AlarmName || body.alarmName) && (body.region || body.rawEvent?.region)
133
+ ? `arn:aws:cloudwatch:${body.region || body.rawEvent?.region || "ap-south-1"}:${body.accountId}:alarm:${body.AlarmName || body.alarmName}`
134
+ : null);
135
+ if (!alarmArn)
136
+ return;
137
+ if (source.awsAccessKeyId && source.awsSecretAccessKey) {
138
+ try {
139
+ const client = new CloudWatchClient({
140
+ region: source.awsRegion || body.region || body.rawEvent?.region || "ap-south-1",
141
+ credentials: {
142
+ accessKeyId: source.awsAccessKeyId,
143
+ secretAccessKey: source.awsSecretAccessKey,
144
+ ...(source.awsSessionToken ? { sessionToken: source.awsSessionToken } : {}),
145
+ },
146
+ });
147
+ const res = await client.send(new ListTagsForResourceCommand({ ResourceARN: alarmArn }));
148
+ const tags = {};
149
+ for (const t of res.Tags || []) {
150
+ if (t && t.Key)
151
+ tags[t.Key] = t.Value || "";
152
+ }
153
+ if (Object.keys(tags).length > 0) {
154
+ body.tags = tags;
155
+ if (!body.AlarmArn)
156
+ body.AlarmArn = alarmArn;
157
+ }
158
+ }
159
+ catch (err) {
160
+ console.warn(`[AlertService] Could not fetch CloudWatch tags for ${alarmArn}:`, err?.message);
161
+ }
162
+ }
163
+ }
164
+ function cloudWatchSeverityFromState(stateValue) {
165
+ if (stateValue === "ALARM")
166
+ return "critical";
167
+ if (stateValue === "INSUFFICIENT_DATA")
168
+ return "medium";
169
+ return "low";
170
+ }
171
+ function webhookProcessingErrorMessage(error) {
172
+ const message = String(error?.message || "");
173
+ const detail = String(error?.cause?.message || error?.detail || "");
174
+ const combined = `${message} ${detail}`.toLowerCase();
175
+ if (combined.includes("not-null") || combined.includes("null value")) {
176
+ return "Webhook received, but required alert fields were missing after payload mapping.";
177
+ }
178
+ if (combined.includes("duplicate key") || combined.includes("unique constraint")) {
179
+ return "Webhook received, but it matches an alert record that already exists.";
180
+ }
181
+ if (combined.includes("does not exist") || combined.includes("column")) {
182
+ return "Webhook received, but alert storage is not ready. Run migrations and restart the backend.";
183
+ }
184
+ if (message.startsWith("Failed query:") || combined.includes("insert into")) {
185
+ return "Webhook received, but Meyi Connect could not save the alert. Check payload mapping and database migrations.";
186
+ }
187
+ return message || "Webhook processing failed.";
188
+ }
189
+ export function normalizePayload(sourceType, rawBody) {
190
+ const body = sourceType === "cloudwatch" ? normalizeCloudWatchPayload(rawBody) : rawBody;
191
+ let resourceId = "";
192
+ let resourceName = "";
193
+ let resourceType = sourceType;
194
+ let tags = {};
195
+ let severity = "high";
196
+ let alertName = "Unknown Alert";
197
+ let description;
198
+ let additionalConfiguration;
199
+ let downTime;
200
+ let accountId;
201
+ let accountName;
202
+ let metricName;
203
+ let labels;
204
+ if (sourceType === "meyi_pulse") {
205
+ resourceId = body.monitorId ?? body.monitor_id ?? body.id ?? crypto.randomUUID();
206
+ resourceName = body.monitorName ?? body.monitor_name ?? body.name ?? "Unknown Monitor";
207
+ resourceType = body.monitorType ?? body.monitor_type ?? "monitor";
208
+ tags = parseTags(body.tags ?? body.Tags ?? (body.tag ? { project: body.tag } : undefined));
209
+ severity = body.severity ?? "high";
210
+ alertName = body.monitorName ?? body.title ?? "Monitor Down";
211
+ description = body.message ?? body.description;
212
+ downTime = body.downTime ?? body.down_time ?? body.timestamp;
213
+ }
214
+ else if (sourceType === "grafana") {
215
+ const alert = Array.isArray(body.alerts) ? body.alerts[0] : body;
216
+ const l = alert.labels ?? {};
217
+ const ann = alert.annotations ?? {};
218
+ resourceId = l.instance ?? l.job ?? crypto.randomUUID();
219
+ resourceName = l.instance ?? l.alertname ?? "Grafana Alert";
220
+ resourceType = l.type ?? "metric";
221
+ tags = { ...l, ...(ann.project ? { project: ann.project } : {}) };
222
+ severity = l.severity ?? "high";
223
+ alertName = l.alertname ?? ann.summary ?? "Grafana Alert";
224
+ description = ann.description ?? ann.summary;
225
+ downTime = alert.startsAt;
226
+ labels = l;
227
+ }
228
+ else if (sourceType === "datadog") {
229
+ resourceId = String(body.id ?? crypto.randomUUID());
230
+ resourceName = body.host ?? body.title ?? "Datadog Resource";
231
+ resourceType = body.source_type_name ?? "datadog";
232
+ const dTags = {};
233
+ if (Array.isArray(body.tags)) {
234
+ for (const t of body.tags) {
235
+ if (typeof t === "string" && t.includes(":")) {
236
+ const [k, ...v] = t.split(":");
237
+ dTags[k.trim()] = v.join(":").trim();
238
+ }
239
+ }
240
+ }
241
+ else if (typeof body.tags === "object" && body.tags) {
242
+ Object.assign(dTags, parseTags(body.tags));
243
+ }
244
+ tags = dTags;
245
+ severity = body.alert_type === "error" ? "critical" : body.alert_type ?? "high";
246
+ alertName = body.title ?? "Datadog Alert";
247
+ description = body.text ?? body.body;
248
+ downTime = body.date ? new Date(body.date * 1000).toISOString() : undefined;
249
+ }
250
+ else if (sourceType === "cloudwatch") {
251
+ const stateValue = body.NewStateValue;
252
+ const alarmName = body.AlarmName || body.alarmName || body.detail?.alarmName;
253
+ const alarmArn = body.AlarmArn ||
254
+ body.alarmArn ||
255
+ body.detail?.alarmArn ||
256
+ (Array.isArray(body.rawEvent?.resources) && body.rawEvent.resources[0]) ||
257
+ (Array.isArray(body.resources) && body.resources[0]);
258
+ resourceId = alarmName ?? alarmArn ?? crypto.randomUUID();
259
+ resourceName = alarmName ?? "CloudWatch";
260
+ resourceType = "cloudwatch";
261
+ // Robust account ID extraction:
262
+ // 1. Direct account / accountId / AWSAccountId properties
263
+ // 2. Event envelope properties (detail.recipientAccountId, rawEvent.account)
264
+ // 3. ARN regex parsing: arn:aws:cloudwatch:<region>:<accountId>:alarm:<name>
265
+ let extractedAccount = body.account ??
266
+ body.accountId ??
267
+ body.AWSAccountId ??
268
+ body.rawEvent?.account ??
269
+ body.detail?.recipientAccountId ??
270
+ body.detail?.account ??
271
+ body.recipientAccountId;
272
+ if (!extractedAccount && alarmArn) {
273
+ const arnMatch = String(alarmArn).match(/^arn:aws[a-z0-9-]*:cloudwatch:[^:]+:([0-9]{12}):alarm:/i);
274
+ if (arnMatch) {
275
+ extractedAccount = arnMatch[1];
276
+ }
277
+ }
278
+ if (!extractedAccount && Array.isArray(body.resources) && body.resources[0]) {
279
+ const resMatch = String(body.resources[0]).match(/^arn:aws[a-z0-9-]*:cloudwatch:[^:]+:([0-9]{12}):alarm:/i);
280
+ if (resMatch) {
281
+ extractedAccount = resMatch[1];
282
+ }
283
+ }
284
+ if (extractedAccount && extractedAccount !== "unknown") {
285
+ accountId = String(extractedAccount);
286
+ }
287
+ // Robust tags extraction:
288
+ // Handles array of { Key, Value }, { key, value }, and dictionary { [key]: value }
289
+ const tagsRecord = parseTags(body.tags ??
290
+ body.Tags ??
291
+ body.detail?.tags ??
292
+ body.rawEvent?.tags ??
293
+ body.rawEvent?.detail?.tags);
294
+ tags = tagsRecord;
295
+ severity = cloudWatchSeverityFromState(stateValue);
296
+ alertName = alarmName
297
+ ? `${alarmName} (${stateValue || "UNKNOWN"})`
298
+ : `${stateValue || "UNKNOWN"}`;
299
+ description = body.NewStateReason ?? body.description ?? body.message ?? body.text;
300
+ additionalConfiguration = {
301
+ ...(typeof body.configuration === "object" ? body.configuration : {}),
302
+ ...(Object.keys(tagsRecord).length > 0 ? { tags: tagsRecord } : {}),
303
+ ...(accountId ? { accountId } : {}),
304
+ };
305
+ downTime = body.StateChangeTime;
306
+ labels = Object.keys(tagsRecord).length > 0 ? tagsRecord : undefined;
307
+ metricName = body.MetricName || body.metricName || body.configuration?.metrics?.[0]?.metricStat?.metric?.name;
308
+ }
309
+ else if (sourceType === "cloudtrail") {
310
+ // CloudTrail events arrive via SNS → EventBridge. The SNS message wrapper may nest
311
+ // the EventBridge detail under `detail` (direct EventBridge) or as a JSON string in `Message`.
312
+ let event = body;
313
+ if (typeof body.Message === "string") {
314
+ try {
315
+ event = JSON.parse(body.Message);
316
+ }
317
+ catch {
318
+ event = body;
319
+ }
320
+ }
321
+ const detail = event?.detail ?? event;
322
+ const evtSrc = detail?.eventSource ?? event?.source ?? "aws.unknown";
323
+ const evtName = detail?.eventName ?? "UnknownEvent";
324
+ const user = detail?.userIdentity?.arn ?? detail?.userIdentity?.userName ?? detail?.userIdentity?.type ?? "unknown";
325
+ const srcIp = detail?.sourceIPAddress ?? "unknown";
326
+ const region = event?.region ?? detail?.awsRegion ?? "unknown";
327
+ const account = event?.account ?? detail?.recipientAccountId ?? "unknown";
328
+ accountId = account !== "unknown" ? account : undefined;
329
+ const req = detail?.requestParameters;
330
+ const resp = detail?.responseElements;
331
+ const targetResource = req?.groupId ??
332
+ req?.ModifySecurityGroupRulesRequest?.GroupId ??
333
+ req?.bucketName ??
334
+ req?.instanceId ??
335
+ req?.dbInstanceIdentifier ??
336
+ req?.functionName ??
337
+ req?.userName ??
338
+ req?.roleName ??
339
+ resp?.groupId ??
340
+ resp?.instancesSet?.items?.[0]?.instanceId;
341
+ if (targetResource) {
342
+ resourceId = `${evtSrc}/${targetResource}`;
343
+ resourceName = `${evtName} (${targetResource})`;
344
+ }
345
+ else {
346
+ resourceId = `${evtSrc}/${evtName}`;
347
+ resourceName = evtName;
348
+ }
349
+ resourceType = evtSrc.replace(/^aws\./, "") || "cloudtrail";
350
+ severity = "high"; // CloudTrail events are always security-relevant — treat as high
351
+ alertName = targetResource ? `${evtName}: ${targetResource}` : `${evtName} (${evtSrc})`;
352
+ description = `${evtName} on ${targetResource || evtSrc} by ${user} from ${srcIp} in ${region} (account: ${account})`;
353
+ additionalConfiguration = { eventSource: evtSrc, eventName: evtName, targetResource, user, sourceIp: srcIp, region, account };
354
+ downTime = detail?.eventTime ?? event?.time ?? new Date().toISOString();
355
+ tags = parseTags(body.tags ?? body.Tags ?? (account && account !== "unknown" ? { account } : undefined));
356
+ }
357
+ else if (sourceType === "prometheus") {
358
+ // Q3: Prometheus Alertmanager sends an alerts[] array. Process alerts[0] for now.
359
+ // Full batch processing (one record per alert) deferred to Phase 5.
360
+ const alerts = body.alerts ?? [];
361
+ if (alerts.length > 1) {
362
+ console.warn(`[normalizePayload] Prometheus batch contains ${alerts.length} alerts — processing alerts[0] only. Full batch support coming in Phase 5.`);
363
+ }
364
+ const alert = alerts[0] ?? body;
365
+ const l = alert.labels ?? {};
366
+ const ann = alert.annotations ?? {};
367
+ const status = (alert.status ?? body.status ?? "firing");
368
+ resourceId = l.instance ?? l.job ?? crypto.randomUUID();
369
+ resourceName = l.instance ?? l.alertname ?? "Prometheus Alert";
370
+ resourceType = l.job ?? "prometheus";
371
+ tags = { ...l, ...(ann.project ? { project: ann.project } : {}) };
372
+ severity = l.severity ?? "high";
373
+ alertName = l.alertname ?? ann.summary ?? "Prometheus Alert";
374
+ description = ann.description ?? ann.summary;
375
+ downTime = alert.startsAt ?? new Date().toISOString();
376
+ additionalConfiguration = { status, groupLabels: body.groupLabels, commonLabels: body.commonLabels };
377
+ labels = l;
378
+ }
379
+ else {
380
+ resourceId = body.resource_id ?? body.instanceId ?? body.id ?? crypto.randomUUID();
381
+ resourceName = body.resource_name ?? body.monitorName ?? body.name ?? "Unknown Resource";
382
+ resourceType = body.resource_type ?? body.monitorType ?? body.type ?? "custom";
383
+ tags = parseTags(body.tags ?? body.Tags ?? body.labels ?? (body.tag ? { project: body.tag } : undefined));
384
+ severity = body.severity ?? "high";
385
+ alertName = body.title ?? body.alertname ?? body.summary ?? "Alert";
386
+ description = body.description ?? body.message ?? body.text;
387
+ downTime = body.downTime ?? body.down_time ?? body.timestamp ?? body.time;
388
+ }
389
+ if (!accountName) {
390
+ accountName = body.accountName ?? body.account_name ?? body.detail?.accountName ?? body.detail?.account_name ?? body.rawEvent?.accountName;
391
+ }
392
+ if (!downTime) {
393
+ downTime = new Date().toISOString();
394
+ }
395
+ return {
396
+ resourceId,
397
+ resourceName,
398
+ resourceType,
399
+ tags,
400
+ severity,
401
+ alertName,
402
+ description,
403
+ additionalConfiguration,
404
+ downTime,
405
+ accountId,
406
+ accountName,
407
+ metricName,
408
+ labels: Object.keys(tags).length > 0 ? tags : labels,
409
+ };
410
+ }
411
+ export class AlertService {
412
+ alertModel;
413
+ incidentModel;
414
+ sourceModel;
415
+ publisher;
416
+ observabilityService;
417
+ workflowService;
418
+ constructor(alertModel, incidentModel, sourceModel, publisher, observabilityService, workflowService) {
419
+ this.alertModel = alertModel;
420
+ this.incidentModel = incidentModel;
421
+ this.sourceModel = sourceModel;
422
+ this.publisher = publisher;
423
+ this.observabilityService = observabilityService;
424
+ this.workflowService = workflowService;
425
+ }
426
+ async summary(params) {
427
+ return this.alertModel.summary(params);
428
+ }
429
+ async emitTotals(reason) {
430
+ if (!this.publisher)
431
+ return;
432
+ try {
433
+ const summary = await this.alertModel.summary({ status: "all" });
434
+ const payload = {
435
+ total: Number(summary?.total ?? 0),
436
+ bySeverity: {
437
+ critical: Number(summary?.bySeverity?.critical ?? 0),
438
+ high: Number(summary?.bySeverity?.high ?? 0),
439
+ medium: Number(summary?.bySeverity?.medium ?? 0),
440
+ low: Number(summary?.bySeverity?.low ?? 0),
441
+ },
442
+ reason,
443
+ };
444
+ this.publisher.emit({
445
+ topic: "alerts.totals",
446
+ payload,
447
+ ts: new Date().toISOString(),
448
+ });
449
+ }
450
+ catch {
451
+ // Best-effort realtime signal, do not fail request path.
452
+ }
453
+ }
454
+ emitSourceUpdated(sourceId, reason) {
455
+ if (!this.publisher)
456
+ return;
457
+ try {
458
+ this.publisher.emit({
459
+ topic: "sources.updated",
460
+ payload: { sourceId, reason },
461
+ ts: new Date().toISOString(),
462
+ });
463
+ }
464
+ catch {
465
+ // Best-effort realtime signal, do not fail request path.
466
+ }
467
+ }
468
+ async list(params) {
469
+ const page = Math.max(1, params.page ?? 1);
470
+ const limit = Math.min(100, params.limit ?? 20);
471
+ const result = await this.alertModel.list({
472
+ page,
473
+ limit,
474
+ status: params.status,
475
+ severity: params.severity,
476
+ sourceId: params.sourceId,
477
+ search: params.search,
478
+ tenantId: params.tenantId,
479
+ incidentId: params.incidentId,
480
+ });
481
+ const incidentIds = result.alerts
482
+ .map(a => a.incidentId)
483
+ .filter((id) => Boolean(id));
484
+ if (incidentIds.length > 0) {
485
+ const incidents = await this.incidentModel.findByIds(incidentIds, params.tenantId);
486
+ const assigneeMap = new Map(incidents.map(inc => [inc.id, inc.assigneeId]));
487
+ result.alerts = result.alerts.map(a => ({
488
+ ...a,
489
+ incidentAssigneeId: a.incidentId ? assigneeMap.get(a.incidentId) : null,
490
+ }));
491
+ }
492
+ return result;
493
+ }
494
+ async getById(id, tenantId) {
495
+ return this.alertModel.findById(id, tenantId);
496
+ }
497
+ async ingestWebhook(token, authToken, body, meta) {
498
+ const validation = await this.sourceModel.validateWebhookToken(token, authToken);
499
+ if (!validation.source) {
500
+ const reason = validation.reason || "NOT_FOUND";
501
+ const sourceId = validation.rejectedSource?.id ?? null;
502
+ // Do not log a failure for the initial AWS SNS / HTTP challenge request (no auth token provided)
503
+ const isAuthChallenge = reason === "UNAUTHORIZED" && !authToken;
504
+ if (!isAuthChallenge) {
505
+ await this.observabilityService?.recordFailure({
506
+ ...meta,
507
+ sourceId,
508
+ token,
509
+ errorCode: `SOURCE_${reason}`,
510
+ errorMessage: reason === "EXPIRED"
511
+ ? "Webhook token expired"
512
+ : reason === "INACTIVE"
513
+ ? "Source is inactive"
514
+ : reason === "UNAUTHORIZED"
515
+ ? "Unauthorized webhook token"
516
+ : "Invalid webhook token",
517
+ payload: body,
518
+ });
519
+ }
520
+ if (reason === "INACTIVE")
521
+ throw new Error("SOURCE_INACTIVE");
522
+ if (reason === "EXPIRED")
523
+ throw new Error("SOURCE_EXPIRED");
524
+ if (reason === "UNAUTHORIZED")
525
+ throw new Error("SOURCE_UNAUTHORIZED");
526
+ throw new Error("SOURCE_NOT_FOUND");
527
+ }
528
+ const source = validation.source;
529
+ // Server-side fallback: enrich tags for CloudWatch alarms if not already present in the payload
530
+ await enrichCloudWatchTagsIfMissing(source, body);
531
+ // ── Queue-first path (pipeline active) ───────────────────────────────────
532
+ if (isRedisAvailable()) {
533
+ try {
534
+ // Phase 5 (Q3): Prometheus multi-alert batch — fan-out each alert as a separate job
535
+ if (source.type === "prometheus" && Array.isArray(body?.alerts) && body.alerts.length > 1) {
536
+ let enqueuedCount = 0;
537
+ for (const singleAlert of body.alerts) {
538
+ // Reconstruct a single-alert Alertmanager payload
539
+ const singlePayload = {
540
+ ...body,
541
+ alerts: [singleAlert],
542
+ };
543
+ const enqueued = await enqueueAlarm({
544
+ sourceId: source.id,
545
+ sourceType: source.type,
546
+ sourceName: source.name,
547
+ tenantId: source.tenantId ?? null,
548
+ rawPayload: singlePayload,
549
+ receivedAt: new Date().toISOString(),
550
+ token,
551
+ });
552
+ if (enqueued)
553
+ enqueuedCount++;
554
+ }
555
+ if (enqueuedCount > 0) {
556
+ console.info(`[AlertService] Prometheus batch: enqueued ${enqueuedCount}/${body.alerts.length} alerts`);
557
+ this.emitSourceUpdated(source.id, "webhook_queued");
558
+ return { alertId: null, incidentId: null, queued: true };
559
+ }
560
+ }
561
+ // Standard single-payload enqueue
562
+ const enqueued = await enqueueAlarm({
563
+ sourceId: source.id,
564
+ sourceType: source.type,
565
+ sourceName: source.name,
566
+ tenantId: source.tenantId ?? null,
567
+ rawPayload: body,
568
+ receivedAt: new Date().toISOString(),
569
+ token,
570
+ });
571
+ if (enqueued) {
572
+ this.emitSourceUpdated(source.id, "webhook_queued");
573
+ return { alertId: null, incidentId: null, queued: true };
574
+ }
575
+ }
576
+ catch (err) {
577
+ console.warn("[AlertService] Queue enqueue failed, falling back to sync:", err.message);
578
+ }
579
+ }
580
+ // ── Sync fallback (Redis unavailable or enqueue failed) ──────────────
581
+ console.info("[AlertService] Using synchronous fallback path (Redis unavailable)");
582
+ try {
583
+ const payload = source.type === "cloudwatch" ? normalizeCloudWatchPayload(body) : body;
584
+ const normalized = normalizePayload(source.type, payload);
585
+ const row = await this.alertModel.create({
586
+ sourceId: source.id,
587
+ tenantId: source.tenantId ?? null,
588
+ sourceName: source.name,
589
+ sourceType: source.type,
590
+ resourceId: normalized.resourceId,
591
+ resourceName: normalized.resourceName,
592
+ resourceType: normalized.resourceType,
593
+ accountId: normalized.accountId ?? null,
594
+ accountName: normalized.accountName ?? null,
595
+ tags: normalized.tags,
596
+ severity: normalized.severity,
597
+ alertName: normalized.alertName,
598
+ description: normalized.description ?? null,
599
+ additionalConfiguration: normalized.additionalConfiguration ?? null,
600
+ downTime: normalized.downTime,
601
+ aliasId: null,
602
+ pipelineStatus: "routed", // sync path = fully processed immediately
603
+ rawPayload: body,
604
+ });
605
+ let incidentId = null;
606
+ try {
607
+ await this.observabilityService?.recordSuccess({ sourceId: source.id, alertId: row.id });
608
+ }
609
+ catch { /* best-effort */ }
610
+ this.emitSourceUpdated(source.id, "webhook_success");
611
+ void this.emitTotals("created");
612
+ if (this.workflowService) {
613
+ const savedAlert = await this.alertModel.findById(row.id);
614
+ if (savedAlert) {
615
+ this.workflowService.evaluateAndExecute(savedAlert).catch(err => {
616
+ console.error("[WorkflowService] evaluateAndExecute error:", err);
617
+ });
618
+ }
619
+ }
620
+ return { alertId: row.id, incidentId, queued: false };
621
+ }
622
+ catch (e) {
623
+ const publicErrorMessage = webhookProcessingErrorMessage(e);
624
+ await this.observabilityService?.recordFailure({
625
+ ...meta,
626
+ sourceId: source.id,
627
+ token,
628
+ errorCode: "WEBHOOK_PROCESSING_FAILED",
629
+ errorMessage: publicErrorMessage,
630
+ payload: body,
631
+ });
632
+ this.emitSourceUpdated(source.id, "webhook_failure");
633
+ throw new Error("WEBHOOK_PROCESSING_FAILED");
634
+ }
635
+ }
636
+ async convert(id, tenantId) {
637
+ const alert = await this.alertModel.findById(id, tenantId);
638
+ if (!alert)
639
+ throw new Error("Alert not found");
640
+ if (alert.status !== "open") {
641
+ throw new Error(`Alert cannot be converted: status is "${alert.status}"`);
642
+ }
643
+ const incident = await this.incidentModel.create({
644
+ name: alert.alertName,
645
+ source: (alert.sourceType || alert.source_type || alert.sourceName || "Unknown").toLowerCase(),
646
+ resourceName: alert.resourceName,
647
+ resourceType: alert.resourceType,
648
+ downMessage: alert.description ?? `Alert on ${alert.resourceName}`,
649
+ tags: alert.tags ?? {},
650
+ accountId: alert.accountId ?? null,
651
+ accountName: alert.accountName ?? alert.account_name ?? null,
652
+ downTime: alert.downTime instanceof Date
653
+ ? alert.downTime.toISOString()
654
+ : String(alert.downTime),
655
+ alertId: alert.id,
656
+ assigneeIds: alert.assigneeId ? [alert.assigneeId] : [],
657
+ tenantId: alert.tenantId ?? null,
658
+ });
659
+ await this.alertModel.update(id, {
660
+ status: "converted",
661
+ convertedIncidentId: incident.id,
662
+ incidentId: incident.id,
663
+ });
664
+ void this.emitTotals("converted");
665
+ return { incidentId: incident.id };
666
+ }
667
+ async dismiss(id, tenantId) {
668
+ const existing = await this.alertModel.findById(id, tenantId);
669
+ if (!existing)
670
+ throw new Error("Alert not found");
671
+ await this.alertModel.update(id, { status: "dismissed" });
672
+ void this.emitTotals("dismissed");
673
+ }
674
+ async update(id, data, tenantId) {
675
+ const existing = await this.alertModel.findById(id, tenantId);
676
+ if (!existing)
677
+ throw new Error("Alert not found");
678
+ await this.alertModel.update(id, data);
679
+ }
680
+ async delete(id, tenantId) {
681
+ const existing = await this.alertModel.findById(id, tenantId);
682
+ if (!existing)
683
+ throw new Error("Alert not found");
684
+ await this.alertModel.delete(id);
685
+ void this.emitTotals("deleted");
686
+ }
687
+ }
688
+ //# sourceMappingURL=alert.service.js.map