@oneuptime/common 11.3.26 → 11.3.28

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 (241) hide show
  1. package/Models/DatabaseModels/IncidentEpisodeRoleMember.ts +1 -1
  2. package/Models/DatabaseModels/IncidentMember.ts +1 -1
  3. package/Models/DatabaseModels/IncomingCallPolicy.ts +13 -0
  4. package/Models/DatabaseModels/Index.ts +3 -0
  5. package/Models/DatabaseModels/MigrationFailure.ts +170 -0
  6. package/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.ts +51 -2
  7. package/Models/DatabaseModels/OnCallDutyPolicySchedule.ts +44 -0
  8. package/Models/DatabaseModels/OnCallDutyPolicyScheduleLayer.ts +6 -0
  9. package/Models/DatabaseModels/OnCallDutyPolicyScheduleLayerUser.ts +6 -0
  10. package/Models/DatabaseModels/OnCallDutyPolicyTimeLog.ts +1 -1
  11. package/Models/DatabaseModels/OnCallDutyPolicyUserOverride.ts +2 -2
  12. package/Server/API/AlertAPI.ts +1 -1
  13. package/Server/API/IncidentAPI.ts +2 -2
  14. package/Server/API/IncidentEpisodeAPI.ts +1 -1
  15. package/Server/API/LlmProviderAPI.ts +1 -0
  16. package/Server/API/ScheduledMaintenanceAPI.ts +1 -1
  17. package/Server/Infrastructure/Postgres/SchemaMigrations/1783470000000-AddIncomingCallPolicyRoutingPhoneNumberUnique.ts +25 -0
  18. package/Server/Infrastructure/Postgres/SchemaMigrations/1783510935686-FixNotNullForeignKeysOnDelete.ts +81 -0
  19. package/Server/Infrastructure/Postgres/SchemaMigrations/1783515836148-MigrationName.ts +25 -0
  20. package/Server/Infrastructure/Postgres/SchemaMigrations/1783523076215-AddMigrationFailureTable.ts +35 -0
  21. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
  22. package/Server/Infrastructure/PostgresDatabase.ts +11 -0
  23. package/Server/Services/AIService.ts +74 -2
  24. package/Server/Services/AnalyticsDatabaseService.ts +10 -1
  25. package/Server/Services/DatabaseService.ts +10 -1
  26. package/Server/Services/IncidentService.ts +1 -1
  27. package/Server/Services/IncomingCallPolicyEscalationRuleService.ts +75 -2
  28. package/Server/Services/IncomingCallPolicyService.ts +42 -1
  29. package/Server/Services/Index.ts +2 -0
  30. package/Server/Services/MigrationFailureService.ts +9 -0
  31. package/Server/Services/MonitorProbeService.ts +33 -7
  32. package/Server/Services/MonitorService.ts +19 -7
  33. package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +65 -0
  34. package/Server/Services/OnCallDutyPolicyEscalationRuleService.ts +185 -41
  35. package/Server/Services/OnCallDutyPolicyEscalationRuleUserService.ts +23 -15
  36. package/Server/Services/OnCallDutyPolicyExecutionLogService.ts +39 -0
  37. package/Server/Services/OnCallDutyPolicyScheduleLayerService.ts +148 -0
  38. package/Server/Services/OnCallDutyPolicyScheduleLayerUserService.ts +11 -2
  39. package/Server/Services/OnCallDutyPolicyScheduleService.ts +502 -26
  40. package/Server/Services/OnCallDutyPolicyTimeLogService.ts +49 -7
  41. package/Server/Services/OnCallDutyPolicyUserOverrideService.ts +218 -4
  42. package/Server/Services/ProjectCallSMSConfigService.ts +82 -1
  43. package/Server/Services/TeamMemberService.ts +6 -0
  44. package/Server/Services/UserNotificationRuleService.ts +13 -42
  45. package/Server/Services/UserOnCallLogService.ts +90 -0
  46. package/Server/Services/UserOnCallLogTimelineService.ts +43 -1
  47. package/Server/Types/Database/QueryUtil.ts +57 -0
  48. package/Server/Utils/AI/AlertAIContextBuilder.ts +6 -1
  49. package/Server/Utils/AI/Chat/ChatAgentRunner.ts +14 -2
  50. package/Server/Utils/AI/IncidentAIContextBuilder.ts +18 -3
  51. package/Server/Utils/AI/IncidentEpisodeAIContextBuilder.ts +6 -1
  52. package/Server/Utils/AI/ScheduledMaintenanceAIContextBuilder.ts +12 -2
  53. package/Server/Utils/AI/Toolbox/IncidentTools.ts +183 -1
  54. package/Server/Utils/AI/Toolbox/Index.ts +4 -1
  55. package/Server/Utils/AI/Toolbox/RecentChangesTools.ts +208 -0
  56. package/Server/Utils/AI/Toolbox/Serializer.ts +42 -0
  57. package/Server/Utils/Database/MigrationFailureLog.ts +240 -0
  58. package/Server/Utils/IncomingCallPhoneNumber.ts +41 -0
  59. package/Server/Utils/LLM/LLMService.ts +110 -11
  60. package/Server/Utils/Telemetry/IoTSnapshotScan.ts +12 -9
  61. package/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.ts +12 -9
  62. package/Tests/Server/Services/AnalyticsDatabaseService.test.ts +0 -8
  63. package/Tests/Server/Services/OnCallDutyPolicyScheduleLayerUserReorder.test.ts +233 -0
  64. package/Tests/Server/Services/OnCallDutyPolicyTimeLogServiceScoping.test.ts +242 -0
  65. package/Tests/Server/Services/OnCallDutyPolicyUserOverrideEdit.test.ts +198 -0
  66. package/Tests/Server/Services/UserOnCallLogClaimNotificationRule.test.ts +495 -0
  67. package/Tests/Server/Types/Database/QueryUtil.test.ts +74 -0
  68. package/Tests/Server/Utils/AI/LLMServiceToolCalling.test.ts +78 -0
  69. package/Tests/Server/Utils/AI/ToolResultSerializer.test.ts +68 -0
  70. package/Tests/Types/DateExhaustiveTimezone.test.ts +700 -0
  71. package/Tests/Types/DateTimezoneWallClock.test.ts +99 -0
  72. package/Tests/Types/Events/Recurring.test.ts +22 -9
  73. package/Tests/Types/OnCallDutyPolicy/LayerUtilAuditFixes.test.ts +291 -0
  74. package/Tests/Types/OnCallDutyPolicy/LayerUtilAuditFixesRound2.test.ts +398 -0
  75. package/Tests/Types/OnCallDutyPolicy/LayerUtilDSTWeekendGap.test.ts +114 -0
  76. package/Tests/Types/OnCallDutyPolicy/LayerUtilDSTWeeklyDayShift.test.ts +76 -0
  77. package/Tests/Types/OnCallDutyPolicy/LayerUtilDailyMutation.test.ts +128 -0
  78. package/Tests/Types/OnCallDutyPolicy/LayerUtilDailyProbe.test.ts +203 -0
  79. package/Tests/Types/OnCallDutyPolicy/LayerUtilDiffFuzz.test.ts +322 -0
  80. package/Tests/Types/OnCallDutyPolicy/LayerUtilEdgeCases.test.ts +280 -0
  81. package/Tests/Types/OnCallDutyPolicy/LayerUtilExhaustiveCurrentUser.test.ts +863 -0
  82. package/Tests/Types/OnCallDutyPolicy/LayerUtilExhaustiveDaily.test.ts +900 -0
  83. package/Tests/Types/OnCallDutyPolicy/LayerUtilExhaustiveMultiLayer.test.ts +1104 -0
  84. package/Tests/Types/OnCallDutyPolicy/LayerUtilExhaustiveRotation.test.ts +957 -0
  85. package/Tests/Types/OnCallDutyPolicy/LayerUtilExhaustiveWeekly.test.ts +1095 -0
  86. package/Tests/Types/OnCallDutyPolicy/LayerUtilInvariants.test.ts +232 -0
  87. package/Tests/Types/OnCallDutyPolicy/LayerUtilMergeAudit.test.ts +227 -0
  88. package/Tests/Types/OnCallDutyPolicy/LayerUtilMonthYearAudit.test.ts +255 -0
  89. package/Tests/Types/OnCallDutyPolicy/LayerUtilMultiLayerAudit.test.ts +388 -0
  90. package/Tests/Types/OnCallDutyPolicy/LayerUtilMultiLayerEdge.test.ts +300 -0
  91. package/Tests/Types/OnCallDutyPolicy/LayerUtilOvernightDSTAudit.test.ts +158 -0
  92. package/Tests/Types/OnCallDutyPolicy/LayerUtilRestrictedGapFix.test.ts +253 -0
  93. package/Tests/Types/OnCallDutyPolicy/LayerUtilRestrictedGapRepro.test.ts +157 -0
  94. package/Tests/Types/OnCallDutyPolicy/LayerUtilRotationFixes.test.ts +414 -0
  95. package/Tests/Types/OnCallDutyPolicy/LayerUtilTimezone.test.ts +243 -0
  96. package/Tests/Types/OnCallDutyPolicy/LayerUtilWeekendGapRepro.test.ts +112 -0
  97. package/Tests/Types/OnCallDutyPolicy/OverrideLensAudit.test.ts +117 -0
  98. package/Tests/Types/OnCallDutyPolicy/RestrictionTimes.test.ts +8 -6
  99. package/Tests/Types/OnCallDutyPolicy/RestrictionTimesDefaultDayAudit.test.ts +112 -0
  100. package/Tests/Types/OnCallDutyPolicy/RestrictionTimesExhaustive.test.ts +821 -0
  101. package/Tests/Types/OnCallDutyPolicy/RestrictionTimesMutationInvariant.test.ts +886 -0
  102. package/Tests/Types/OnCallDutyPolicy/UserOverrideUtil.test.ts +255 -0
  103. package/Tests/Types/OnCallDutyPolicy/UserOverrideUtilExhaustive.test.ts +1126 -0
  104. package/Types/Date.ts +200 -15
  105. package/Types/OnCallDutyPolicy/Layer.ts +790 -260
  106. package/Types/OnCallDutyPolicy/RestrictionTimes.ts +39 -13
  107. package/Types/OnCallDutyPolicy/UserOverrideUtil.ts +21 -5
  108. package/UI/Components/Events/RecurringFieldElement.tsx +16 -0
  109. package/UI/Components/ModelFormModal/ModelFormModal.tsx +8 -0
  110. package/UI/Components/RadioButtons/BasicRadioButtons.tsx +1 -1
  111. package/build/dist/Models/DatabaseModels/IncidentEpisodeRoleMember.js +1 -1
  112. package/build/dist/Models/DatabaseModels/IncidentEpisodeRoleMember.js.map +1 -1
  113. package/build/dist/Models/DatabaseModels/IncidentMember.js +1 -1
  114. package/build/dist/Models/DatabaseModels/IncidentMember.js.map +1 -1
  115. package/build/dist/Models/DatabaseModels/IncomingCallPolicy.js +10 -0
  116. package/build/dist/Models/DatabaseModels/IncomingCallPolicy.js.map +1 -1
  117. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  118. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  119. package/build/dist/Models/DatabaseModels/MigrationFailure.js +196 -0
  120. package/build/dist/Models/DatabaseModels/MigrationFailure.js.map +1 -0
  121. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.js +52 -2
  122. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.js.map +1 -1
  123. package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js +45 -0
  124. package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js.map +1 -1
  125. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleLayer.js +6 -0
  126. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleLayer.js.map +1 -1
  127. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleLayerUser.js +6 -0
  128. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleLayerUser.js.map +1 -1
  129. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyTimeLog.js +1 -1
  130. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyTimeLog.js.map +1 -1
  131. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyUserOverride.js +2 -2
  132. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyUserOverride.js.map +1 -1
  133. package/build/dist/Server/API/AlertAPI.js +1 -1
  134. package/build/dist/Server/API/IncidentAPI.js +2 -2
  135. package/build/dist/Server/API/IncidentEpisodeAPI.js +1 -1
  136. package/build/dist/Server/API/LlmProviderAPI.js +1 -0
  137. package/build/dist/Server/API/LlmProviderAPI.js.map +1 -1
  138. package/build/dist/Server/API/ScheduledMaintenanceAPI.js +1 -1
  139. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783470000000-AddIncomingCallPolicyRoutingPhoneNumberUnique.js +18 -0
  140. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783470000000-AddIncomingCallPolicyRoutingPhoneNumberUnique.js.map +1 -0
  141. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783510935686-FixNotNullForeignKeysOnDelete.js +38 -0
  142. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783510935686-FixNotNullForeignKeysOnDelete.js.map +1 -0
  143. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783515836148-MigrationName.js +16 -0
  144. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783515836148-MigrationName.js.map +1 -0
  145. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783523076215-AddMigrationFailureTable.js +18 -0
  146. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783523076215-AddMigrationFailureTable.js.map +1 -0
  147. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
  148. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  149. package/build/dist/Server/Infrastructure/PostgresDatabase.js +9 -0
  150. package/build/dist/Server/Infrastructure/PostgresDatabase.js.map +1 -1
  151. package/build/dist/Server/Services/AIService.js +53 -2
  152. package/build/dist/Server/Services/AIService.js.map +1 -1
  153. package/build/dist/Server/Services/AnalyticsDatabaseService.js +10 -1
  154. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  155. package/build/dist/Server/Services/DatabaseService.js +10 -1
  156. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  157. package/build/dist/Server/Services/IncidentService.js +1 -1
  158. package/build/dist/Server/Services/IncomingCallPolicyEscalationRuleService.js +55 -2
  159. package/build/dist/Server/Services/IncomingCallPolicyEscalationRuleService.js.map +1 -1
  160. package/build/dist/Server/Services/IncomingCallPolicyService.js +40 -0
  161. package/build/dist/Server/Services/IncomingCallPolicyService.js.map +1 -1
  162. package/build/dist/Server/Services/Index.js +2 -0
  163. package/build/dist/Server/Services/Index.js.map +1 -1
  164. package/build/dist/Server/Services/MigrationFailureService.js +9 -0
  165. package/build/dist/Server/Services/MigrationFailureService.js.map +1 -0
  166. package/build/dist/Server/Services/MonitorProbeService.js +33 -7
  167. package/build/dist/Server/Services/MonitorProbeService.js.map +1 -1
  168. package/build/dist/Server/Services/MonitorService.js +12 -5
  169. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  170. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +81 -22
  171. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
  172. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js +134 -31
  173. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js.map +1 -1
  174. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js +21 -13
  175. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js.map +1 -1
  176. package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogService.js +36 -0
  177. package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogService.js.map +1 -1
  178. package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerService.js +121 -0
  179. package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerService.js.map +1 -1
  180. package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerUserService.js +11 -2
  181. package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerUserService.js.map +1 -1
  182. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js +409 -36
  183. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js.map +1 -1
  184. package/build/dist/Server/Services/OnCallDutyPolicyTimeLogService.js +52 -8
  185. package/build/dist/Server/Services/OnCallDutyPolicyTimeLogService.js.map +1 -1
  186. package/build/dist/Server/Services/OnCallDutyPolicyUserOverrideService.js +170 -3
  187. package/build/dist/Server/Services/OnCallDutyPolicyUserOverrideService.js.map +1 -1
  188. package/build/dist/Server/Services/ProjectCallSMSConfigService.js +72 -0
  189. package/build/dist/Server/Services/ProjectCallSMSConfigService.js.map +1 -1
  190. package/build/dist/Server/Services/TeamMemberService.js +6 -0
  191. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  192. package/build/dist/Server/Services/UserNotificationRuleService.js +12 -30
  193. package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
  194. package/build/dist/Server/Services/UserOnCallLogService.js +75 -0
  195. package/build/dist/Server/Services/UserOnCallLogService.js.map +1 -1
  196. package/build/dist/Server/Services/UserOnCallLogTimelineService.js +31 -1
  197. package/build/dist/Server/Services/UserOnCallLogTimelineService.js.map +1 -1
  198. package/build/dist/Server/Types/Database/QueryUtil.js +45 -0
  199. package/build/dist/Server/Types/Database/QueryUtil.js.map +1 -1
  200. package/build/dist/Server/Utils/AI/AlertAIContextBuilder.js +6 -1
  201. package/build/dist/Server/Utils/AI/AlertAIContextBuilder.js.map +1 -1
  202. package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js +13 -2
  203. package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js.map +1 -1
  204. package/build/dist/Server/Utils/AI/IncidentAIContextBuilder.js +18 -3
  205. package/build/dist/Server/Utils/AI/IncidentAIContextBuilder.js.map +1 -1
  206. package/build/dist/Server/Utils/AI/IncidentEpisodeAIContextBuilder.js +6 -1
  207. package/build/dist/Server/Utils/AI/IncidentEpisodeAIContextBuilder.js.map +1 -1
  208. package/build/dist/Server/Utils/AI/ScheduledMaintenanceAIContextBuilder.js +12 -2
  209. package/build/dist/Server/Utils/AI/ScheduledMaintenanceAIContextBuilder.js.map +1 -1
  210. package/build/dist/Server/Utils/AI/Toolbox/IncidentTools.js +152 -1
  211. package/build/dist/Server/Utils/AI/Toolbox/IncidentTools.js.map +1 -1
  212. package/build/dist/Server/Utils/AI/Toolbox/Index.js +4 -1
  213. package/build/dist/Server/Utils/AI/Toolbox/Index.js.map +1 -1
  214. package/build/dist/Server/Utils/AI/Toolbox/RecentChangesTools.js +165 -0
  215. package/build/dist/Server/Utils/AI/Toolbox/RecentChangesTools.js.map +1 -0
  216. package/build/dist/Server/Utils/AI/Toolbox/Serializer.js +40 -0
  217. package/build/dist/Server/Utils/AI/Toolbox/Serializer.js.map +1 -1
  218. package/build/dist/Server/Utils/Database/MigrationFailureLog.js +174 -0
  219. package/build/dist/Server/Utils/Database/MigrationFailureLog.js.map +1 -0
  220. package/build/dist/Server/Utils/IncomingCallPhoneNumber.js +30 -0
  221. package/build/dist/Server/Utils/IncomingCallPhoneNumber.js.map +1 -0
  222. package/build/dist/Server/Utils/LLM/LLMService.js +81 -5
  223. package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
  224. package/build/dist/Server/Utils/Telemetry/IoTSnapshotScan.js +11 -8
  225. package/build/dist/Server/Utils/Telemetry/IoTSnapshotScan.js.map +1 -1
  226. package/build/dist/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.js +11 -8
  227. package/build/dist/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.js.map +1 -1
  228. package/build/dist/Types/Date.js +153 -15
  229. package/build/dist/Types/Date.js.map +1 -1
  230. package/build/dist/Types/OnCallDutyPolicy/Layer.js +602 -171
  231. package/build/dist/Types/OnCallDutyPolicy/Layer.js.map +1 -1
  232. package/build/dist/Types/OnCallDutyPolicy/RestrictionTimes.js +27 -13
  233. package/build/dist/Types/OnCallDutyPolicy/RestrictionTimes.js.map +1 -1
  234. package/build/dist/Types/OnCallDutyPolicy/UserOverrideUtil.js +20 -5
  235. package/build/dist/Types/OnCallDutyPolicy/UserOverrideUtil.js.map +1 -1
  236. package/build/dist/UI/Components/Events/RecurringFieldElement.js +13 -0
  237. package/build/dist/UI/Components/Events/RecurringFieldElement.js.map +1 -1
  238. package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js.map +1 -1
  239. package/build/dist/UI/Components/RadioButtons/BasicRadioButtons.js +1 -1
  240. package/build/dist/UI/Components/RadioButtons/BasicRadioButtons.js.map +1 -1
  241. package/package.json +1 -1
@@ -0,0 +1,208 @@
1
+ import Monitor from "../../../../Models/DatabaseModels/Monitor";
2
+ import MonitorStatusTimeline from "../../../../Models/DatabaseModels/MonitorStatusTimeline";
3
+ import ScheduledMaintenance from "../../../../Models/DatabaseModels/ScheduledMaintenance";
4
+ import TelemetryException from "../../../../Models/DatabaseModels/TelemetryException";
5
+ import { JSONObject } from "../../../../Types/JSON";
6
+ import Permission from "../../../../Types/Permission";
7
+ import SortOrder from "../../../../Types/BaseDatabase/SortOrder";
8
+ import MonitorStatusTimelineService from "../../../Services/MonitorStatusTimelineService";
9
+ import ScheduledMaintenanceService from "../../../Services/ScheduledMaintenanceService";
10
+ import TelemetryExceptionService from "../../../Services/TelemetryExceptionService";
11
+ import QueryHelper from "../../../Types/Database/QueryHelper";
12
+ import logger from "../../Logger";
13
+ import ToolResultSerializer, { SerializedResult } from "./Serializer";
14
+ import {
15
+ ObservabilityTool,
16
+ ToolArgs,
17
+ ToolContext,
18
+ ToolExecutionResult,
19
+ TimeRangeSchemaProperties,
20
+ } from "./ToolTypes";
21
+
22
+ /*
23
+ * Gate on Monitor read permissions. This is defense-in-depth only: every
24
+ * source query below runs under the requesting user's props, so a user who
25
+ * cannot see monitors / exceptions / maintenance simply gets no rows from that
26
+ * source — never another user's data. Resolved lazily to avoid the
27
+ * import-time circular-dependency TypeError other tools document.
28
+ */
29
+ let cachedReadPermissions: Array<Permission> | null = null;
30
+ const resolveReadPermissions: () => Array<Permission> =
31
+ (): Array<Permission> => {
32
+ if (!cachedReadPermissions) {
33
+ cachedReadPermissions = new Monitor().getReadPermissions();
34
+ }
35
+ return cachedReadPermissions;
36
+ };
37
+
38
+ // One normalized entry in the merged "what changed" feed.
39
+ interface ChangeEvent {
40
+ at: Date;
41
+ change: string;
42
+ detail: string;
43
+ }
44
+
45
+ export const RecentChangesTool: ObservabilityTool = {
46
+ name: "recent_changes",
47
+ description:
48
+ "Get a single chronological feed of what changed in a time window: newly-seen exceptions, monitor status changes (up/down), and scheduled maintenance overlapping the window. This is the highest-yield way to answer 'what changed right before this started?' during root-cause analysis — call it with the window around when a problem began.",
49
+ inputSchema: {
50
+ type: "object",
51
+ properties: {
52
+ ...TimeRangeSchemaProperties,
53
+ limitPerSource: {
54
+ type: "number",
55
+ description:
56
+ "Maximum items to pull from each source (exceptions, monitor changes, maintenance) before merging. Default 15, max 30.",
57
+ },
58
+ },
59
+ },
60
+ get requiredPermissions(): Array<Permission> {
61
+ return resolveReadPermissions();
62
+ },
63
+ execute: async (
64
+ args: JSONObject,
65
+ ctx: ToolContext,
66
+ ): Promise<ToolExecutionResult> => {
67
+ const timeRange: { startTime: Date; endTime: Date } = ToolArgs.getTimeRange(
68
+ args,
69
+ { defaultHours: 24, maxDays: 30 },
70
+ );
71
+ const startTime: Date = timeRange.startTime;
72
+ const endTime: Date = timeRange.endTime;
73
+
74
+ const limitPerSource: number = ToolArgs.getNumber(args, "limitPerSource", {
75
+ defaultValue: 15,
76
+ min: 1,
77
+ max: 30,
78
+ });
79
+
80
+ const events: Array<ChangeEvent> = [];
81
+
82
+ // 1) Newly-seen exceptions — their first occurrence falls inside the window.
83
+ try {
84
+ const exceptions: Array<TelemetryException> =
85
+ await TelemetryExceptionService.findBy({
86
+ query: {
87
+ firstSeenAt: QueryHelper.inBetween(startTime, endTime),
88
+ } as never,
89
+ select: {
90
+ message: true,
91
+ exceptionType: true,
92
+ firstSeenAt: true,
93
+ occuranceCount: true,
94
+ },
95
+ sort: { firstSeenAt: SortOrder.Descending },
96
+ limit: limitPerSource,
97
+ skip: 0,
98
+ props: ctx.props,
99
+ });
100
+
101
+ for (const exception of exceptions) {
102
+ if (!exception.firstSeenAt) {
103
+ continue;
104
+ }
105
+ events.push({
106
+ at: exception.firstSeenAt,
107
+ change: "new_exception",
108
+ detail: `${exception.exceptionType || "Exception"}: ${exception.message || ""} (x${exception.occuranceCount ?? 0})`,
109
+ });
110
+ }
111
+ } catch (error) {
112
+ logger.debug(`recent_changes: exceptions source skipped: ${error}`);
113
+ }
114
+
115
+ // 2) Monitor status changes (up/down) inside the window.
116
+ try {
117
+ const statusChanges: Array<MonitorStatusTimeline> =
118
+ await MonitorStatusTimelineService.findBy({
119
+ query: {
120
+ createdAt: QueryHelper.inBetween(startTime, endTime),
121
+ },
122
+ select: {
123
+ createdAt: true,
124
+ monitor: { name: true },
125
+ monitorStatus: { name: true },
126
+ },
127
+ sort: { createdAt: SortOrder.Descending },
128
+ limit: limitPerSource,
129
+ skip: 0,
130
+ props: ctx.props,
131
+ });
132
+
133
+ for (const statusChange of statusChanges) {
134
+ if (!statusChange.createdAt) {
135
+ continue;
136
+ }
137
+ events.push({
138
+ at: statusChange.createdAt,
139
+ change: "monitor_status_change",
140
+ detail: `${statusChange.monitor?.name || "Monitor"} → ${statusChange.monitorStatus?.name || "unknown"}`,
141
+ });
142
+ }
143
+ } catch (error) {
144
+ logger.debug(`recent_changes: monitor source skipped: ${error}`);
145
+ }
146
+
147
+ /*
148
+ * 3) Scheduled maintenance overlapping the window (started before it ended,
149
+ * ends after it started).
150
+ */
151
+ try {
152
+ const maintenanceEvents: Array<ScheduledMaintenance> =
153
+ await ScheduledMaintenanceService.findBy({
154
+ query: {
155
+ startsAt: QueryHelper.lessThanEqualTo(endTime),
156
+ endsAt: QueryHelper.greaterThanEqualTo(startTime),
157
+ },
158
+ select: {
159
+ title: true,
160
+ startsAt: true,
161
+ endsAt: true,
162
+ currentScheduledMaintenanceState: { name: true },
163
+ },
164
+ sort: { startsAt: SortOrder.Descending },
165
+ limit: limitPerSource,
166
+ skip: 0,
167
+ props: ctx.props,
168
+ });
169
+
170
+ for (const maintenance of maintenanceEvents) {
171
+ if (!maintenance.startsAt) {
172
+ continue;
173
+ }
174
+ events.push({
175
+ at: maintenance.startsAt,
176
+ change: "scheduled_maintenance",
177
+ detail: `${maintenance.title || "Maintenance"} (${maintenance.currentScheduledMaintenanceState?.name || "scheduled"})`,
178
+ });
179
+ }
180
+ } catch (error) {
181
+ logger.debug(`recent_changes: maintenance source skipped: ${error}`);
182
+ }
183
+
184
+ // Merge into one chronological feed, most recent first.
185
+ events.sort((a: ChangeEvent, b: ChangeEvent) => {
186
+ return b.at.getTime() - a.at.getTime();
187
+ });
188
+
189
+ const rows: Array<JSONObject> = events.map((event: ChangeEvent) => {
190
+ return {
191
+ at: event.at,
192
+ change: event.change,
193
+ detail: event.detail,
194
+ };
195
+ });
196
+
197
+ const serialized: SerializedResult =
198
+ ToolResultSerializer.serializeRows(rows);
199
+
200
+ return {
201
+ dataForLlm: serialized.text,
202
+ rowCount: serialized.rowCount,
203
+ citationLabel: `Changes ${startTime.toISOString()} → ${endTime.toISOString()} (${serialized.rowCount} events)`,
204
+ redactionCount: serialized.redactionCount,
205
+ isTruncated: serialized.isTruncated,
206
+ };
207
+ },
208
+ };
@@ -32,6 +32,37 @@ const REDACTION_RULES: Array<RedactionRule> = [
32
32
  regex: /Bearer\s+[A-Za-z0-9._~+/-]{16,}=*/gi,
33
33
  replacement: "Bearer [redacted-token]",
34
34
  },
35
+ {
36
+ /*
37
+ * PEM private key blocks (RSA/EC/OPENSSH/PGP…). Match the whole
38
+ * BEGIN…END block, including newlines, so no key material leaks.
39
+ */
40
+ name: "private-key",
41
+ regex:
42
+ /-----BEGIN (?:[A-Z0-9]+ )*PRIVATE KEY-----[\s\S]*?-----END (?:[A-Z0-9]+ )*PRIVATE KEY-----/g,
43
+ replacement: "[redacted-private-key]",
44
+ },
45
+ {
46
+ name: "aws-access-key-id",
47
+ regex: /\b(?:AKIA|ASIA|AGPA|AIDA|AROA|AIPA|ANPA|ANVA|ASCA)[0-9A-Z]{16}\b/g,
48
+ replacement: "[redacted-aws-key]",
49
+ },
50
+ {
51
+ name: "github-token",
52
+ regex:
53
+ /\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{36,}\b|\bgithub_pat_[A-Za-z0-9_]{22,}\b/g,
54
+ replacement: "[redacted-github-token]",
55
+ },
56
+ {
57
+ name: "slack-token",
58
+ regex: /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g,
59
+ replacement: "[redacted-slack-token]",
60
+ },
61
+ {
62
+ name: "google-api-key",
63
+ regex: /\bAIza[0-9A-Za-z_-]{35}\b/g,
64
+ replacement: "[redacted-google-api-key]",
65
+ },
35
66
  {
36
67
  name: "email",
37
68
  regex: /[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g,
@@ -42,6 +73,17 @@ const REDACTION_RULES: Array<RedactionRule> = [
42
73
  regex: /\b(?:\d{1,3}\.){3}\d{1,3}\b/g,
43
74
  replacement: "[redacted-ip]",
44
75
  },
76
+ {
77
+ /*
78
+ * Payment card numbers in the classic space/dash-separated grouping
79
+ * (e.g. "4111 1111 1111 1111"). Deliberately NOT matching bare 16-digit
80
+ * runs: an all-numeric 16-char OTel span id would collide with those and
81
+ * break the search_logs → get_trace pivot.
82
+ */
83
+ name: "credit-card",
84
+ regex: /\b\d{4}[ -]\d{4}[ -]\d{4}[ -]\d{4}\b/g,
85
+ replacement: "[redacted-card]",
86
+ },
45
87
  {
46
88
  /*
47
89
  * Long hex blobs are usually secrets (SHA-256 digests, 40+ char API
@@ -0,0 +1,240 @@
1
+ import os from "os";
2
+ import { DataSource, DataSourceOptions } from "typeorm";
3
+ import logger from "../Logger";
4
+ import { AppVersion } from "../../EnvironmentConfig";
5
+
6
+ /*
7
+ * Records migrations that FAILED to apply into the "MigrationFailure" table so
8
+ * the admin health page can explain WHY a migration is pending (what error,
9
+ * when it ran) instead of only showing that it is behind. Every write here is
10
+ * best-effort: a diagnostic log must never itself crash a boot / migrate Job or
11
+ * mask the real migration error, so all failures inside this module are
12
+ * swallowed (logged, not thrown).
13
+ */
14
+
15
+ // Which runner a failed migration belongs to. Stored verbatim in the table.
16
+ export enum MigrationFailureType {
17
+ PostgresSchema = "PostgresSchema",
18
+ DataMigration = "DataMigration",
19
+ }
20
+
21
+ // Keep a single row bounded so a pathological error/stack can't bloat the table.
22
+ const MAX_ERROR_MESSAGE_LENGTH: number = 10000;
23
+ const MAX_ERROR_STACK_LENGTH: number = 20000;
24
+
25
+ /*
26
+ * Best-effort credential scrub for the free-form error text we persist. DB /
27
+ * migration errors seldom carry secrets, but a connection error can echo a
28
+ * `scheme://user:pass@host` DSN and a failing DDL can quote a literal default,
29
+ * so we mask the obvious vectors before the text is stored and later shown.
30
+ */
31
+ const CONNECTION_STRING_SECRET_PATTERN: RegExp =
32
+ /([a-z][a-z0-9+.-]*:\/\/[^:@\s/]+):[^\s/]+@/gi;
33
+ const KEYWORD_SECRET_PATTERN: RegExp =
34
+ /(password|secret|token|api[_-]?key|apikey|credential|private[_-]?key|auth[_-]?token|access[_-]?key)(\s*[:=]\s*)('(?:[^']|'')*'|"[^"]*"|[^\s,)]+)/gi;
35
+
36
+ export function scrubMigrationErrorText(text: string): string {
37
+ if (!text) {
38
+ return text;
39
+ }
40
+
41
+ return text
42
+ .replace(
43
+ CONNECTION_STRING_SECRET_PATTERN,
44
+ (_match: string, prefix: string): string => {
45
+ return `${prefix}:***REDACTED***@`;
46
+ },
47
+ )
48
+ .replace(
49
+ KEYWORD_SECRET_PATTERN,
50
+ (_match: string, keyword: string, separator: string): string => {
51
+ return `${keyword}${separator}***REDACTED***`;
52
+ },
53
+ );
54
+ }
55
+
56
+ function toErrorMessage(error: unknown): string {
57
+ if (error instanceof Error) {
58
+ return error.message || error.name || "Unknown error";
59
+ }
60
+ return String(error);
61
+ }
62
+
63
+ function toErrorStack(error: unknown): string | null {
64
+ return error instanceof Error && error.stack ? error.stack : null;
65
+ }
66
+
67
+ interface MigrationFailureInput {
68
+ migrationName: string;
69
+ migrationType: MigrationFailureType;
70
+ error: unknown;
71
+ }
72
+
73
+ /*
74
+ * Append one failed-attempt row using the provided (already-connected)
75
+ * DataSource. Raw SQL — not the Service layer — so it also works on a
76
+ * throwaway diagnostic connection and never depends on realtime/event wiring.
77
+ * Returns true if the row was written. If the "MigrationFailure" table does not
78
+ * exist yet (e.g. its own migration is still pending on a first rollout) the
79
+ * INSERT throws and is swallowed — the caller's real error is unaffected.
80
+ */
81
+ export async function recordMigrationFailure(
82
+ dataSource: DataSource,
83
+ input: MigrationFailureInput,
84
+ ): Promise<boolean> {
85
+ try {
86
+ const message: string = scrubMigrationErrorText(
87
+ toErrorMessage(input.error),
88
+ ).substring(0, MAX_ERROR_MESSAGE_LENGTH);
89
+
90
+ const rawStack: string | null = toErrorStack(input.error);
91
+ const stack: string | null = rawStack
92
+ ? scrubMigrationErrorText(rawStack).substring(0, MAX_ERROR_STACK_LENGTH)
93
+ : null;
94
+
95
+ await dataSource.query(
96
+ `INSERT INTO "MigrationFailure"
97
+ ("migrationName", "migrationType", "errorMessage", "errorStack", "attemptedAt", "hostName", "appVersion", "version", "createdAt", "updatedAt")
98
+ VALUES ($1, $2, $3, $4, $5, $6, $7, 1, now(), now())`,
99
+ [
100
+ input.migrationName,
101
+ input.migrationType,
102
+ message,
103
+ stack,
104
+ new Date(),
105
+ os.hostname(),
106
+ AppVersion,
107
+ ],
108
+ );
109
+
110
+ return true;
111
+ } catch (err) {
112
+ // Diagnostic write must never mask the real failure — log and move on.
113
+ logger.warn(
114
+ `Could not record migration failure for "${input.migrationName}" (${input.migrationType}); continuing.`,
115
+ );
116
+ logger.warn(err);
117
+ return false;
118
+ }
119
+ }
120
+
121
+ // Trailing epoch in a migration class name — how TypeORM orders/identifies them.
122
+ function parseMigrationTimestamp(name: string): number {
123
+ const match: RegExpMatchArray | null = name.match(/(\d{10,})$/);
124
+ return match ? Number(match[1]) : 0;
125
+ }
126
+
127
+ /*
128
+ * The TypeORM schema runner (migrationsRun) applies migrations in ascending
129
+ * timestamp order and halts at the first failure, so the FIRST defined
130
+ * migration not yet in the `migrations` table is exactly the one that failed.
131
+ * We recompute it here from a throwaway connection because the app's own
132
+ * connect() has already failed (its DataSource is not usable) at the point a
133
+ * schema migration throws.
134
+ */
135
+ export async function recordSchemaMigrationFailureBestEffort(
136
+ dataSourceOptions: DataSourceOptions,
137
+ originalError: unknown,
138
+ ): Promise<void> {
139
+ /*
140
+ * Only THIS process's own boot runs schema migrations (migrationsRun=true —
141
+ * the migrate Job and single-pod / dev boots). On runtime pods where a
142
+ * dedicated migrate Job owns migrations (migrationsRun=false), a connect()
143
+ * failure is a connectivity problem, never a failed migration — recording
144
+ * one here would misattribute an outage to a (legitimately) pending
145
+ * migration, so skip.
146
+ */
147
+ if (
148
+ (dataSourceOptions as { migrationsRun?: boolean }).migrationsRun !== true
149
+ ) {
150
+ return;
151
+ }
152
+
153
+ let diagnosticDataSource: DataSource | null = null;
154
+
155
+ try {
156
+ diagnosticDataSource = new DataSource({
157
+ ...dataSourceOptions,
158
+ // Never re-run migrations or sync schema on the diagnostic connection.
159
+ migrationsRun: false,
160
+ synchronize: false,
161
+ // Keep the probe short so a genuinely-down DB doesn't slow the failing boot.
162
+ extra: {
163
+ ...((dataSourceOptions as { extra?: Record<string, unknown> }).extra ||
164
+ {}),
165
+ connectionTimeoutMillis: 5000,
166
+ },
167
+ } as DataSourceOptions);
168
+
169
+ /*
170
+ * If this fails, the original error was a connectivity problem (not a bad
171
+ * migration) — there is nothing meaningful to attribute, so we skip.
172
+ */
173
+ await diagnosticDataSource.initialize();
174
+
175
+ const definedMigrationClasses: Array<new () => { name: string }> =
176
+ Array.isArray(dataSourceOptions.migrations)
177
+ ? (dataSourceOptions.migrations as unknown as Array<
178
+ new () => { name: string }
179
+ >)
180
+ : [];
181
+
182
+ const definedNames: Array<string> = Array.from(
183
+ new Set(
184
+ definedMigrationClasses.map(
185
+ (MigrationClass: new () => { name: string }): string => {
186
+ return new MigrationClass().name;
187
+ },
188
+ ),
189
+ ),
190
+ ).sort((a: string, b: string): number => {
191
+ return parseMigrationTimestamp(a) - parseMigrationTimestamp(b);
192
+ });
193
+
194
+ let appliedNames: Set<string> = new Set();
195
+ try {
196
+ const rows: Array<{ name: string }> = await diagnosticDataSource.query(
197
+ "SELECT name FROM migrations",
198
+ );
199
+ appliedNames = new Set(
200
+ rows.map((row: { name: string }): string => {
201
+ return row.name;
202
+ }),
203
+ );
204
+ } catch {
205
+ // migrations table may not exist on a brand-new DB — treat as none applied.
206
+ }
207
+
208
+ const firstPending: string | undefined = definedNames.find(
209
+ (name: string): boolean => {
210
+ return !appliedNames.has(name);
211
+ },
212
+ );
213
+
214
+ /*
215
+ * No pending schema migration means the connect() failure was not a pending
216
+ * migration failing (e.g. an entity-metadata error) — don't misattribute it.
217
+ */
218
+ if (!firstPending) {
219
+ return;
220
+ }
221
+
222
+ await recordMigrationFailure(diagnosticDataSource, {
223
+ migrationName: firstPending,
224
+ migrationType: MigrationFailureType.PostgresSchema,
225
+ error: originalError,
226
+ });
227
+ } catch (err) {
228
+ // Best-effort diagnostics only — swallow everything.
229
+ logger.warn("Could not record Postgres schema migration failure.");
230
+ logger.warn(err);
231
+ } finally {
232
+ try {
233
+ if (diagnosticDataSource && diagnosticDataSource.isInitialized) {
234
+ await diagnosticDataSource.destroy();
235
+ }
236
+ } catch (destroyErr) {
237
+ logger.warn(destroyErr);
238
+ }
239
+ }
240
+ }
@@ -0,0 +1,41 @@
1
+ import { AppApiHostname } from "../EnvironmentConfig";
2
+ import ClusterKeyAuthorization from "../Middleware/ClusterKeyAuthorization";
3
+ import logger from "./Logger";
4
+ import Protocol from "../../Types/API/Protocol";
5
+ import Route from "../../Types/API/Route";
6
+ import URL from "../../Types/API/URL";
7
+ import API from "../../Utils/API";
8
+ import ObjectID from "../../Types/ObjectID";
9
+
10
+ /*
11
+ * Releases a provisioned incoming-call number on the call provider by delegating
12
+ * to the notification app's internal endpoint (the Common layer cannot reach the
13
+ * provider directly). Best-effort: failures are logged but never thrown, so a
14
+ * provider/network issue during cleanup does not block the parent delete.
15
+ */
16
+ export default async function releaseIncomingCallPhoneNumber(data: {
17
+ projectCallSMSConfigId: ObjectID;
18
+ callProviderPhoneNumberId: string;
19
+ }): Promise<void> {
20
+ try {
21
+ await API.post({
22
+ url: new URL(
23
+ Protocol.HTTP,
24
+ AppApiHostname,
25
+ new Route("/api/notification/phone-number/internal/release"),
26
+ ),
27
+ data: {
28
+ projectCallSMSConfigId: data.projectCallSMSConfigId.toString(),
29
+ callProviderPhoneNumberId: data.callProviderPhoneNumberId,
30
+ },
31
+ headers: {
32
+ ...ClusterKeyAuthorization.getClusterKeyHeaders(),
33
+ },
34
+ });
35
+ } catch (err) {
36
+ logger.error(
37
+ "Failed to release incoming-call phone number on the provider during cleanup:",
38
+ );
39
+ logger.error(err);
40
+ }
41
+ }