@oneuptime/common 11.3.25 → 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 (397) hide show
  1. package/Models/DatabaseModels/AIConversation.ts +322 -0
  2. package/Models/DatabaseModels/AIConversationMessage.ts +495 -0
  3. package/Models/DatabaseModels/AIRun.ts +584 -0
  4. package/Models/DatabaseModels/AIRunEvent.ts +443 -0
  5. package/Models/DatabaseModels/IncidentEpisodeRoleMember.ts +1 -1
  6. package/Models/DatabaseModels/IncidentMember.ts +1 -1
  7. package/Models/DatabaseModels/IncomingCallPolicy.ts +13 -0
  8. package/Models/DatabaseModels/Index.ts +11 -0
  9. package/Models/DatabaseModels/LlmLog.ts +26 -0
  10. package/Models/DatabaseModels/LlmProvider.ts +2 -2
  11. package/Models/DatabaseModels/MigrationFailure.ts +170 -0
  12. package/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.ts +51 -2
  13. package/Models/DatabaseModels/OnCallDutyPolicySchedule.ts +44 -0
  14. package/Models/DatabaseModels/OnCallDutyPolicyScheduleLayer.ts +6 -0
  15. package/Models/DatabaseModels/OnCallDutyPolicyScheduleLayerUser.ts +6 -0
  16. package/Models/DatabaseModels/OnCallDutyPolicyTimeLog.ts +1 -1
  17. package/Models/DatabaseModels/OnCallDutyPolicyUserOverride.ts +2 -2
  18. package/Server/API/AIChatAPI.ts +693 -0
  19. package/Server/API/AlertAPI.ts +1 -1
  20. package/Server/API/IncidentAPI.ts +2 -2
  21. package/Server/API/IncidentEpisodeAPI.ts +1 -1
  22. package/Server/API/LlmProviderAPI.ts +170 -0
  23. package/Server/API/MicrosoftTeamsAPI.ts +5 -0
  24. package/Server/API/ScheduledMaintenanceAPI.ts +1 -1
  25. package/Server/API/SlackAPI.ts +663 -0
  26. package/Server/Infrastructure/Postgres/SchemaMigrations/1783363279075-AddAIChatModels.ts +245 -0
  27. package/Server/Infrastructure/Postgres/SchemaMigrations/1783443471795-AddLlmProviderToAIConversation.ts +36 -0
  28. package/Server/Infrastructure/Postgres/SchemaMigrations/1783453297388-AddAIChatWriteActionsAndWidgets.ts +46 -0
  29. package/Server/Infrastructure/Postgres/SchemaMigrations/1783461767405-MigrationName.ts +119 -0
  30. package/Server/Infrastructure/Postgres/SchemaMigrations/1783470000000-AddIncomingCallPolicyRoutingPhoneNumberUnique.ts +25 -0
  31. package/Server/Infrastructure/Postgres/SchemaMigrations/1783510935686-FixNotNullForeignKeysOnDelete.ts +81 -0
  32. package/Server/Infrastructure/Postgres/SchemaMigrations/1783515836148-MigrationName.ts +25 -0
  33. package/Server/Infrastructure/Postgres/SchemaMigrations/1783523076215-AddMigrationFailureTable.ts +35 -0
  34. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +16 -0
  35. package/Server/Infrastructure/PostgresDatabase.ts +11 -0
  36. package/Server/Services/AIConversationMessageService.ts +39 -0
  37. package/Server/Services/AIConversationService.ts +63 -0
  38. package/Server/Services/AIRunEventService.ts +39 -0
  39. package/Server/Services/AIRunService.ts +39 -0
  40. package/Server/Services/AIService.ts +127 -33
  41. package/Server/Services/AnalyticsDatabaseService.ts +10 -1
  42. package/Server/Services/DatabaseService.ts +29 -1
  43. package/Server/Services/IncidentService.ts +1 -1
  44. package/Server/Services/IncomingCallPolicyEscalationRuleService.ts +75 -2
  45. package/Server/Services/IncomingCallPolicyService.ts +42 -1
  46. package/Server/Services/Index.ts +2 -0
  47. package/Server/Services/LlmProviderService.ts +110 -0
  48. package/Server/Services/MigrationFailureService.ts +9 -0
  49. package/Server/Services/MonitorProbeService.ts +33 -7
  50. package/Server/Services/MonitorService.ts +19 -7
  51. package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +65 -0
  52. package/Server/Services/OnCallDutyPolicyEscalationRuleService.ts +185 -41
  53. package/Server/Services/OnCallDutyPolicyEscalationRuleUserService.ts +23 -15
  54. package/Server/Services/OnCallDutyPolicyExecutionLogService.ts +39 -0
  55. package/Server/Services/OnCallDutyPolicyScheduleLayerService.ts +148 -0
  56. package/Server/Services/OnCallDutyPolicyScheduleLayerUserService.ts +11 -2
  57. package/Server/Services/OnCallDutyPolicyScheduleService.ts +502 -26
  58. package/Server/Services/OnCallDutyPolicyTimeLogService.ts +49 -7
  59. package/Server/Services/OnCallDutyPolicyUserOverrideService.ts +218 -4
  60. package/Server/Services/ProjectCallSMSConfigService.ts +82 -1
  61. package/Server/Services/ProjectService.ts +24 -0
  62. package/Server/Services/TeamMemberService.ts +6 -0
  63. package/Server/Services/UserNotificationRuleService.ts +13 -42
  64. package/Server/Services/UserOnCallLogService.ts +90 -0
  65. package/Server/Services/UserOnCallLogTimelineService.ts +43 -1
  66. package/Server/Types/AnalyticsDatabase/ModelPermission.ts +74 -9
  67. package/Server/Types/Database/QueryUtil.ts +57 -0
  68. package/Server/Utils/AI/AIChatPrivacyFilter.ts +28 -0
  69. package/Server/Utils/AI/AlertAIContextBuilder.ts +6 -1
  70. package/Server/Utils/AI/Chat/ChatAgentRunner.ts +1066 -0
  71. package/Server/Utils/AI/Chat/ObservabilityAssistant.ts +239 -0
  72. package/Server/Utils/AI/Chat/ObservabilityChatPrompt.ts +51 -0
  73. package/Server/Utils/AI/IncidentAIContextBuilder.ts +18 -3
  74. package/Server/Utils/AI/IncidentEpisodeAIContextBuilder.ts +6 -1
  75. package/Server/Utils/AI/ScheduledMaintenanceAIContextBuilder.ts +12 -2
  76. package/Server/Utils/AI/Toolbox/AlertTools.ts +201 -0
  77. package/Server/Utils/AI/Toolbox/AlertWriteTools.ts +174 -0
  78. package/Server/Utils/AI/Toolbox/ContextTools.ts +189 -0
  79. package/Server/Utils/AI/Toolbox/ExceptionTools.ts +149 -0
  80. package/Server/Utils/AI/Toolbox/IncidentTools.ts +386 -0
  81. package/Server/Utils/AI/Toolbox/IncidentWriteTools.ts +350 -0
  82. package/Server/Utils/AI/Toolbox/Index.ts +231 -0
  83. package/Server/Utils/AI/Toolbox/LogTools.ts +339 -0
  84. package/Server/Utils/AI/Toolbox/MetricTools.ts +179 -0
  85. package/Server/Utils/AI/Toolbox/MonitorTools.ts +193 -0
  86. package/Server/Utils/AI/Toolbox/RecentChangesTools.ts +208 -0
  87. package/Server/Utils/AI/Toolbox/Serializer.ts +299 -0
  88. package/Server/Utils/AI/Toolbox/ToolTypes.ts +249 -0
  89. package/Server/Utils/AI/Toolbox/TraceTools.ts +402 -0
  90. package/Server/Utils/AI/Toolbox/WidgetBuilder.ts +189 -0
  91. package/Server/Utils/Database/MigrationFailureLog.ts +240 -0
  92. package/Server/Utils/IncomingCallPhoneNumber.ts +41 -0
  93. package/Server/Utils/LLM/LLMService.ts +605 -96
  94. package/Server/Utils/Telemetry/IoTSnapshotScan.ts +12 -9
  95. package/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.ts +12 -9
  96. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +512 -19
  97. package/Server/Utils/Workspace/Slack/Slack.ts +80 -0
  98. package/Server/Utils/Workspace/Slack/app-manifest.json +16 -1
  99. package/Tests/Server/Services/AnalyticsDatabaseService.test.ts +0 -8
  100. package/Tests/Server/Services/OnCallDutyPolicyScheduleLayerUserReorder.test.ts +233 -0
  101. package/Tests/Server/Services/OnCallDutyPolicyTimeLogServiceScoping.test.ts +242 -0
  102. package/Tests/Server/Services/OnCallDutyPolicyUserOverrideEdit.test.ts +198 -0
  103. package/Tests/Server/Services/UserOnCallLogClaimNotificationRule.test.ts +495 -0
  104. package/Tests/Server/Types/Database/QueryUtil.test.ts +74 -0
  105. package/Tests/Server/Utils/AI/AIChatModelACL.test.ts +42 -0
  106. package/Tests/Server/Utils/AI/ChatAgentHelpers.test.ts +89 -0
  107. package/Tests/Server/Utils/AI/LLMServiceBaseUrl.test.ts +139 -0
  108. package/Tests/Server/Utils/AI/LLMServiceToolCalling.test.ts +386 -0
  109. package/Tests/Server/Utils/AI/ToolArgsGetTimeRange.test.ts +62 -0
  110. package/Tests/Server/Utils/AI/ToolArgsScopeServiceIds.test.ts +79 -0
  111. package/Tests/Server/Utils/AI/ToolResultSerializer.test.ts +223 -0
  112. package/Tests/Types/Billing/SubscriptionStatus.test.ts +127 -0
  113. package/Tests/Types/DateExhaustiveTimezone.test.ts +700 -0
  114. package/Tests/Types/DateTimezoneWallClock.test.ts +99 -0
  115. package/Tests/Types/Events/Recurring.test.ts +22 -9
  116. package/Tests/Types/Metrics/RecordingRuleDefinition.test.ts +213 -0
  117. package/Tests/Types/OnCallDutyPolicy/LayerUtilAuditFixes.test.ts +291 -0
  118. package/Tests/Types/OnCallDutyPolicy/LayerUtilAuditFixesRound2.test.ts +398 -0
  119. package/Tests/Types/OnCallDutyPolicy/LayerUtilDSTWeekendGap.test.ts +114 -0
  120. package/Tests/Types/OnCallDutyPolicy/LayerUtilDSTWeeklyDayShift.test.ts +76 -0
  121. package/Tests/Types/OnCallDutyPolicy/LayerUtilDailyMutation.test.ts +128 -0
  122. package/Tests/Types/OnCallDutyPolicy/LayerUtilDailyProbe.test.ts +203 -0
  123. package/Tests/Types/OnCallDutyPolicy/LayerUtilDiffFuzz.test.ts +322 -0
  124. package/Tests/Types/OnCallDutyPolicy/LayerUtilEdgeCases.test.ts +280 -0
  125. package/Tests/Types/OnCallDutyPolicy/LayerUtilExhaustiveCurrentUser.test.ts +863 -0
  126. package/Tests/Types/OnCallDutyPolicy/LayerUtilExhaustiveDaily.test.ts +900 -0
  127. package/Tests/Types/OnCallDutyPolicy/LayerUtilExhaustiveMultiLayer.test.ts +1104 -0
  128. package/Tests/Types/OnCallDutyPolicy/LayerUtilExhaustiveRotation.test.ts +957 -0
  129. package/Tests/Types/OnCallDutyPolicy/LayerUtilExhaustiveWeekly.test.ts +1095 -0
  130. package/Tests/Types/OnCallDutyPolicy/LayerUtilInvariants.test.ts +232 -0
  131. package/Tests/Types/OnCallDutyPolicy/LayerUtilMergeAudit.test.ts +227 -0
  132. package/Tests/Types/OnCallDutyPolicy/LayerUtilMonthYearAudit.test.ts +255 -0
  133. package/Tests/Types/OnCallDutyPolicy/LayerUtilMultiLayerAudit.test.ts +388 -0
  134. package/Tests/Types/OnCallDutyPolicy/LayerUtilMultiLayerEdge.test.ts +300 -0
  135. package/Tests/Types/OnCallDutyPolicy/LayerUtilOvernightDSTAudit.test.ts +158 -0
  136. package/Tests/Types/OnCallDutyPolicy/LayerUtilRestrictedGapFix.test.ts +253 -0
  137. package/Tests/Types/OnCallDutyPolicy/LayerUtilRestrictedGapRepro.test.ts +157 -0
  138. package/Tests/Types/OnCallDutyPolicy/LayerUtilRotationFixes.test.ts +414 -0
  139. package/Tests/Types/OnCallDutyPolicy/LayerUtilTimezone.test.ts +243 -0
  140. package/Tests/Types/OnCallDutyPolicy/LayerUtilWeekendGapRepro.test.ts +112 -0
  141. package/Tests/Types/OnCallDutyPolicy/OverrideLensAudit.test.ts +117 -0
  142. package/Tests/Types/OnCallDutyPolicy/RestrictionTimes.test.ts +8 -6
  143. package/Tests/Types/OnCallDutyPolicy/RestrictionTimesDefaultDayAudit.test.ts +112 -0
  144. package/Tests/Types/OnCallDutyPolicy/RestrictionTimesExhaustive.test.ts +821 -0
  145. package/Tests/Types/OnCallDutyPolicy/RestrictionTimesMutationInvariant.test.ts +886 -0
  146. package/Tests/Types/OnCallDutyPolicy/UserOverrideUtil.test.ts +255 -0
  147. package/Tests/Types/OnCallDutyPolicy/UserOverrideUtilExhaustive.test.ts +1126 -0
  148. package/Types/AI/AIChatMessageRole.ts +6 -0
  149. package/Types/AI/AIChatMessageStatus.ts +32 -0
  150. package/Types/AI/AIChatPermissionMode.ts +69 -0
  151. package/Types/AI/AIChatTypes.ts +231 -0
  152. package/Types/AI/AIRunEventType.ts +17 -0
  153. package/Types/AI/AIRunStatus.ts +28 -0
  154. package/Types/AI/AIRunType.ts +6 -0
  155. package/Types/Date.ts +200 -15
  156. package/Types/LLM/LlmType.ts +6 -0
  157. package/Types/OnCallDutyPolicy/Layer.ts +790 -260
  158. package/Types/OnCallDutyPolicy/RestrictionTimes.ts +39 -13
  159. package/Types/OnCallDutyPolicy/UserOverrideUtil.ts +21 -5
  160. package/UI/Components/Events/RecurringFieldElement.tsx +16 -0
  161. package/UI/Components/Header/HeaderIconDropdownButton.tsx +22 -12
  162. package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +35 -3
  163. package/UI/Components/ModelFormModal/ModelFormModal.tsx +8 -0
  164. package/UI/Components/Page/Page.tsx +14 -0
  165. package/UI/Components/RadioButtons/BasicRadioButtons.tsx +1 -1
  166. package/UI/Utils/LlmTypeDropdownOptions.ts +40 -0
  167. package/UI/Utils/TestLLMProvider.ts +59 -0
  168. package/build/dist/Models/DatabaseModels/AIConversation.js +345 -0
  169. package/build/dist/Models/DatabaseModels/AIConversation.js.map +1 -0
  170. package/build/dist/Models/DatabaseModels/AIConversationMessage.js +521 -0
  171. package/build/dist/Models/DatabaseModels/AIConversationMessage.js.map +1 -0
  172. package/build/dist/Models/DatabaseModels/AIRun.js +619 -0
  173. package/build/dist/Models/DatabaseModels/AIRun.js.map +1 -0
  174. package/build/dist/Models/DatabaseModels/AIRunEvent.js +469 -0
  175. package/build/dist/Models/DatabaseModels/AIRunEvent.js.map +1 -0
  176. package/build/dist/Models/DatabaseModels/IncidentEpisodeRoleMember.js +1 -1
  177. package/build/dist/Models/DatabaseModels/IncidentEpisodeRoleMember.js.map +1 -1
  178. package/build/dist/Models/DatabaseModels/IncidentMember.js +1 -1
  179. package/build/dist/Models/DatabaseModels/IncidentMember.js.map +1 -1
  180. package/build/dist/Models/DatabaseModels/IncomingCallPolicy.js +10 -0
  181. package/build/dist/Models/DatabaseModels/IncomingCallPolicy.js.map +1 -1
  182. package/build/dist/Models/DatabaseModels/Index.js +10 -0
  183. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  184. package/build/dist/Models/DatabaseModels/LlmLog.js +28 -0
  185. package/build/dist/Models/DatabaseModels/LlmLog.js.map +1 -1
  186. package/build/dist/Models/DatabaseModels/LlmProvider.js +2 -2
  187. package/build/dist/Models/DatabaseModels/LlmProvider.js.map +1 -1
  188. package/build/dist/Models/DatabaseModels/MigrationFailure.js +196 -0
  189. package/build/dist/Models/DatabaseModels/MigrationFailure.js.map +1 -0
  190. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.js +52 -2
  191. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.js.map +1 -1
  192. package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js +45 -0
  193. package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js.map +1 -1
  194. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleLayer.js +6 -0
  195. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleLayer.js.map +1 -1
  196. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleLayerUser.js +6 -0
  197. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleLayerUser.js.map +1 -1
  198. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyTimeLog.js +1 -1
  199. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyTimeLog.js.map +1 -1
  200. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyUserOverride.js +2 -2
  201. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyUserOverride.js.map +1 -1
  202. package/build/dist/Server/API/AIChatAPI.js +498 -0
  203. package/build/dist/Server/API/AIChatAPI.js.map +1 -0
  204. package/build/dist/Server/API/AlertAPI.js +1 -1
  205. package/build/dist/Server/API/IncidentAPI.js +2 -2
  206. package/build/dist/Server/API/IncidentEpisodeAPI.js +1 -1
  207. package/build/dist/Server/API/LlmProviderAPI.js +108 -1
  208. package/build/dist/Server/API/LlmProviderAPI.js.map +1 -1
  209. package/build/dist/Server/API/MicrosoftTeamsAPI.js +4 -0
  210. package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -1
  211. package/build/dist/Server/API/ScheduledMaintenanceAPI.js +1 -1
  212. package/build/dist/Server/API/SlackAPI.js +442 -0
  213. package/build/dist/Server/API/SlackAPI.js.map +1 -1
  214. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783363279075-AddAIChatModels.js +96 -0
  215. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783363279075-AddAIChatModels.js.map +1 -0
  216. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783443471795-AddLlmProviderToAIConversation.js +25 -0
  217. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783443471795-AddLlmProviderToAIConversation.js.map +1 -0
  218. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783453297388-AddAIChatWriteActionsAndWidgets.js +31 -0
  219. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783453297388-AddAIChatWriteActionsAndWidgets.js.map +1 -0
  220. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783461767405-MigrationName.js +46 -0
  221. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783461767405-MigrationName.js.map +1 -0
  222. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783470000000-AddIncomingCallPolicyRoutingPhoneNumberUnique.js +18 -0
  223. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783470000000-AddIncomingCallPolicyRoutingPhoneNumberUnique.js.map +1 -0
  224. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783510935686-FixNotNullForeignKeysOnDelete.js +38 -0
  225. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783510935686-FixNotNullForeignKeysOnDelete.js.map +1 -0
  226. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783515836148-MigrationName.js +16 -0
  227. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783515836148-MigrationName.js.map +1 -0
  228. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783523076215-AddMigrationFailureTable.js +18 -0
  229. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1783523076215-AddMigrationFailureTable.js.map +1 -0
  230. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +16 -0
  231. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  232. package/build/dist/Server/Infrastructure/PostgresDatabase.js +9 -0
  233. package/build/dist/Server/Infrastructure/PostgresDatabase.js.map +1 -1
  234. package/build/dist/Server/Services/AIConversationMessageService.js +34 -0
  235. package/build/dist/Server/Services/AIConversationMessageService.js.map +1 -0
  236. package/build/dist/Server/Services/AIConversationService.js +42 -0
  237. package/build/dist/Server/Services/AIConversationService.js.map +1 -0
  238. package/build/dist/Server/Services/AIRunEventService.js +34 -0
  239. package/build/dist/Server/Services/AIRunEventService.js.map +1 -0
  240. package/build/dist/Server/Services/AIRunService.js +34 -0
  241. package/build/dist/Server/Services/AIRunService.js.map +1 -0
  242. package/build/dist/Server/Services/AIService.js +84 -25
  243. package/build/dist/Server/Services/AIService.js.map +1 -1
  244. package/build/dist/Server/Services/AnalyticsDatabaseService.js +10 -1
  245. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  246. package/build/dist/Server/Services/DatabaseService.js +20 -1
  247. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  248. package/build/dist/Server/Services/IncidentService.js +1 -1
  249. package/build/dist/Server/Services/IncomingCallPolicyEscalationRuleService.js +55 -2
  250. package/build/dist/Server/Services/IncomingCallPolicyEscalationRuleService.js.map +1 -1
  251. package/build/dist/Server/Services/IncomingCallPolicyService.js +40 -0
  252. package/build/dist/Server/Services/IncomingCallPolicyService.js.map +1 -1
  253. package/build/dist/Server/Services/Index.js +2 -0
  254. package/build/dist/Server/Services/Index.js.map +1 -1
  255. package/build/dist/Server/Services/LlmProviderService.js +108 -0
  256. package/build/dist/Server/Services/LlmProviderService.js.map +1 -1
  257. package/build/dist/Server/Services/MigrationFailureService.js +9 -0
  258. package/build/dist/Server/Services/MigrationFailureService.js.map +1 -0
  259. package/build/dist/Server/Services/MonitorProbeService.js +33 -7
  260. package/build/dist/Server/Services/MonitorProbeService.js.map +1 -1
  261. package/build/dist/Server/Services/MonitorService.js +12 -5
  262. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  263. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +81 -22
  264. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
  265. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js +134 -31
  266. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js.map +1 -1
  267. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js +21 -13
  268. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js.map +1 -1
  269. package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogService.js +36 -0
  270. package/build/dist/Server/Services/OnCallDutyPolicyExecutionLogService.js.map +1 -1
  271. package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerService.js +121 -0
  272. package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerService.js.map +1 -1
  273. package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerUserService.js +11 -2
  274. package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerUserService.js.map +1 -1
  275. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js +409 -36
  276. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js.map +1 -1
  277. package/build/dist/Server/Services/OnCallDutyPolicyTimeLogService.js +52 -8
  278. package/build/dist/Server/Services/OnCallDutyPolicyTimeLogService.js.map +1 -1
  279. package/build/dist/Server/Services/OnCallDutyPolicyUserOverrideService.js +170 -3
  280. package/build/dist/Server/Services/OnCallDutyPolicyUserOverrideService.js.map +1 -1
  281. package/build/dist/Server/Services/ProjectCallSMSConfigService.js +72 -0
  282. package/build/dist/Server/Services/ProjectCallSMSConfigService.js.map +1 -1
  283. package/build/dist/Server/Services/ProjectService.js +25 -0
  284. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  285. package/build/dist/Server/Services/TeamMemberService.js +6 -0
  286. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  287. package/build/dist/Server/Services/UserNotificationRuleService.js +12 -30
  288. package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
  289. package/build/dist/Server/Services/UserOnCallLogService.js +75 -0
  290. package/build/dist/Server/Services/UserOnCallLogService.js.map +1 -1
  291. package/build/dist/Server/Services/UserOnCallLogTimelineService.js +31 -1
  292. package/build/dist/Server/Services/UserOnCallLogTimelineService.js.map +1 -1
  293. package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js +50 -7
  294. package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js.map +1 -1
  295. package/build/dist/Server/Types/Database/QueryUtil.js +45 -0
  296. package/build/dist/Server/Types/Database/QueryUtil.js.map +1 -1
  297. package/build/dist/Server/Utils/AI/AIChatPrivacyFilter.js +18 -0
  298. package/build/dist/Server/Utils/AI/AIChatPrivacyFilter.js.map +1 -0
  299. package/build/dist/Server/Utils/AI/AlertAIContextBuilder.js +6 -1
  300. package/build/dist/Server/Utils/AI/AlertAIContextBuilder.js.map +1 -1
  301. package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js +756 -0
  302. package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js.map +1 -0
  303. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js +165 -0
  304. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js.map +1 -0
  305. package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js +44 -0
  306. package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js.map +1 -0
  307. package/build/dist/Server/Utils/AI/IncidentAIContextBuilder.js +18 -3
  308. package/build/dist/Server/Utils/AI/IncidentAIContextBuilder.js.map +1 -1
  309. package/build/dist/Server/Utils/AI/IncidentEpisodeAIContextBuilder.js +6 -1
  310. package/build/dist/Server/Utils/AI/IncidentEpisodeAIContextBuilder.js.map +1 -1
  311. package/build/dist/Server/Utils/AI/ScheduledMaintenanceAIContextBuilder.js +12 -2
  312. package/build/dist/Server/Utils/AI/ScheduledMaintenanceAIContextBuilder.js.map +1 -1
  313. package/build/dist/Server/Utils/AI/Toolbox/AlertTools.js +167 -0
  314. package/build/dist/Server/Utils/AI/Toolbox/AlertTools.js.map +1 -0
  315. package/build/dist/Server/Utils/AI/Toolbox/AlertWriteTools.js +136 -0
  316. package/build/dist/Server/Utils/AI/Toolbox/AlertWriteTools.js.map +1 -0
  317. package/build/dist/Server/Utils/AI/Toolbox/ContextTools.js +141 -0
  318. package/build/dist/Server/Utils/AI/Toolbox/ContextTools.js.map +1 -0
  319. package/build/dist/Server/Utils/AI/Toolbox/ExceptionTools.js +117 -0
  320. package/build/dist/Server/Utils/AI/Toolbox/ExceptionTools.js.map +1 -0
  321. package/build/dist/Server/Utils/AI/Toolbox/IncidentTools.js +318 -0
  322. package/build/dist/Server/Utils/AI/Toolbox/IncidentTools.js.map +1 -0
  323. package/build/dist/Server/Utils/AI/Toolbox/IncidentWriteTools.js +280 -0
  324. package/build/dist/Server/Utils/AI/Toolbox/IncidentWriteTools.js.map +1 -0
  325. package/build/dist/Server/Utils/AI/Toolbox/Index.js +153 -0
  326. package/build/dist/Server/Utils/AI/Toolbox/Index.js.map +1 -0
  327. package/build/dist/Server/Utils/AI/Toolbox/LogTools.js +246 -0
  328. package/build/dist/Server/Utils/AI/Toolbox/LogTools.js.map +1 -0
  329. package/build/dist/Server/Utils/AI/Toolbox/MetricTools.js +120 -0
  330. package/build/dist/Server/Utils/AI/Toolbox/MetricTools.js.map +1 -0
  331. package/build/dist/Server/Utils/AI/Toolbox/MonitorTools.js +158 -0
  332. package/build/dist/Server/Utils/AI/Toolbox/MonitorTools.js.map +1 -0
  333. package/build/dist/Server/Utils/AI/Toolbox/RecentChangesTools.js +165 -0
  334. package/build/dist/Server/Utils/AI/Toolbox/RecentChangesTools.js.map +1 -0
  335. package/build/dist/Server/Utils/AI/Toolbox/Serializer.js +228 -0
  336. package/build/dist/Server/Utils/AI/Toolbox/Serializer.js.map +1 -0
  337. package/build/dist/Server/Utils/AI/Toolbox/ToolTypes.js +142 -0
  338. package/build/dist/Server/Utils/AI/Toolbox/ToolTypes.js.map +1 -0
  339. package/build/dist/Server/Utils/AI/Toolbox/TraceTools.js +309 -0
  340. package/build/dist/Server/Utils/AI/Toolbox/TraceTools.js.map +1 -0
  341. package/build/dist/Server/Utils/AI/Toolbox/WidgetBuilder.js +120 -0
  342. package/build/dist/Server/Utils/AI/Toolbox/WidgetBuilder.js.map +1 -0
  343. package/build/dist/Server/Utils/Database/MigrationFailureLog.js +174 -0
  344. package/build/dist/Server/Utils/Database/MigrationFailureLog.js.map +1 -0
  345. package/build/dist/Server/Utils/IncomingCallPhoneNumber.js +30 -0
  346. package/build/dist/Server/Utils/IncomingCallPhoneNumber.js.map +1 -0
  347. package/build/dist/Server/Utils/LLM/LLMService.js +452 -92
  348. package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
  349. package/build/dist/Server/Utils/Telemetry/IoTSnapshotScan.js +11 -8
  350. package/build/dist/Server/Utils/Telemetry/IoTSnapshotScan.js.map +1 -1
  351. package/build/dist/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.js +11 -8
  352. package/build/dist/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.js.map +1 -1
  353. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +378 -15
  354. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  355. package/build/dist/Server/Utils/Workspace/Slack/Slack.js +59 -0
  356. package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
  357. package/build/dist/Server/Utils/Workspace/Slack/app-manifest.json +16 -1
  358. package/build/dist/Types/AI/AIChatMessageRole.js +7 -0
  359. package/build/dist/Types/AI/AIChatMessageRole.js.map +1 -0
  360. package/build/dist/Types/AI/AIChatMessageStatus.js +27 -0
  361. package/build/dist/Types/AI/AIChatMessageStatus.js.map +1 -0
  362. package/build/dist/Types/AI/AIChatPermissionMode.js +53 -0
  363. package/build/dist/Types/AI/AIChatPermissionMode.js.map +1 -0
  364. package/build/dist/Types/AI/AIChatTypes.js +74 -0
  365. package/build/dist/Types/AI/AIChatTypes.js.map +1 -0
  366. package/build/dist/Types/AI/AIRunEventType.js +18 -0
  367. package/build/dist/Types/AI/AIRunEventType.js.map +1 -0
  368. package/build/dist/Types/AI/AIRunStatus.js +26 -0
  369. package/build/dist/Types/AI/AIRunStatus.js.map +1 -0
  370. package/build/dist/Types/AI/AIRunType.js +7 -0
  371. package/build/dist/Types/AI/AIRunType.js.map +1 -0
  372. package/build/dist/Types/Date.js +153 -15
  373. package/build/dist/Types/Date.js.map +1 -1
  374. package/build/dist/Types/LLM/LlmType.js +6 -0
  375. package/build/dist/Types/LLM/LlmType.js.map +1 -1
  376. package/build/dist/Types/OnCallDutyPolicy/Layer.js +602 -171
  377. package/build/dist/Types/OnCallDutyPolicy/Layer.js.map +1 -1
  378. package/build/dist/Types/OnCallDutyPolicy/RestrictionTimes.js +27 -13
  379. package/build/dist/Types/OnCallDutyPolicy/RestrictionTimes.js.map +1 -1
  380. package/build/dist/Types/OnCallDutyPolicy/UserOverrideUtil.js +20 -5
  381. package/build/dist/Types/OnCallDutyPolicy/UserOverrideUtil.js.map +1 -1
  382. package/build/dist/UI/Components/Events/RecurringFieldElement.js +13 -0
  383. package/build/dist/UI/Components/Events/RecurringFieldElement.js.map +1 -1
  384. package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js +10 -5
  385. package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js.map +1 -1
  386. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +18 -4
  387. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
  388. package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js.map +1 -1
  389. package/build/dist/UI/Components/Page/Page.js +3 -1
  390. package/build/dist/UI/Components/Page/Page.js.map +1 -1
  391. package/build/dist/UI/Components/RadioButtons/BasicRadioButtons.js +1 -1
  392. package/build/dist/UI/Components/RadioButtons/BasicRadioButtons.js.map +1 -1
  393. package/build/dist/UI/Utils/LlmTypeDropdownOptions.js +38 -0
  394. package/build/dist/UI/Utils/LlmTypeDropdownOptions.js.map +1 -0
  395. package/build/dist/UI/Utils/TestLLMProvider.js +37 -0
  396. package/build/dist/UI/Utils/TestLLMProvider.js.map +1 -0
  397. package/package.json +1 -1
@@ -0,0 +1,232 @@
1
+ /**
2
+ * EMPIRICAL invariant fuzzing (audit lens).
3
+ *
4
+ * For unrestricted rotations over long horizons:
5
+ * (A) CONTIGUITY: sorted events cover [start, end] with no gap > 2s and no
6
+ * overlap (events are stitched with a +1s seam, so a 1s gap is expected).
7
+ * (B) FAIRNESS: over many periods each user's shift count is within 1.
8
+ * (C) ORDER: users cycle A,B,C,A,B,C... with no skip/repeat, including across
9
+ * DST transitions.
10
+ */
11
+ import LayerUtil, { LayerProps } from "../../../Types/OnCallDutyPolicy/Layer";
12
+ import CalendarEvent from "../../../Types/Calendar/CalendarEvent";
13
+ import RestrictionTimes, {
14
+ RestrictionType,
15
+ } from "../../../Types/OnCallDutyPolicy/RestrictionTimes";
16
+ import Recurring from "../../../Types/Events/Recurring";
17
+ import OneUptimeDate from "../../../Types/Date";
18
+ import User from "../../../Models/DatabaseModels/User";
19
+ import EventInterval from "../../../Types/Events/EventInterval";
20
+ import PositiveNumber from "../../../Types/PositiveNumber";
21
+
22
+ function user(id: string): User {
23
+ return {
24
+ id: {
25
+ toString: (): string => {
26
+ return id;
27
+ },
28
+ } as any,
29
+ } as User;
30
+ }
31
+
32
+ function noRestriction(): RestrictionTimes {
33
+ const r: RestrictionTimes = new RestrictionTimes();
34
+ r.restictionType = RestrictionType.None;
35
+ r.dayRestrictionTimes = null;
36
+ return r;
37
+ }
38
+
39
+ interface Config {
40
+ name: string;
41
+ intervalType: EventInterval;
42
+ intervalCount: number;
43
+ userIds: string[];
44
+ timezone?: string | undefined;
45
+ start: Date;
46
+ }
47
+
48
+ function layerOf(c: Config): LayerProps {
49
+ const rot: Recurring = new Recurring();
50
+ rot.intervalType = c.intervalType;
51
+ rot.intervalCount = new PositiveNumber(c.intervalCount);
52
+ const handoff: Date = Recurring.getNextDateInterval(c.start, rot);
53
+ return {
54
+ users: c.userIds.map(user),
55
+ startDateTimeOfLayer: c.start,
56
+ restrictionTimes: noRestriction(),
57
+ handOffTime: handoff,
58
+ rotation: rot,
59
+ timezone: c.timezone,
60
+ };
61
+ }
62
+
63
+ function fullExpand(layer: LayerProps, to: Date): Array<CalendarEvent> {
64
+ const util: LayerUtil = new LayerUtil();
65
+ const events: Array<CalendarEvent> = util.getEvents({
66
+ ...layer,
67
+ calendarStartDate: layer.startDateTimeOfLayer,
68
+ calendarEndDate: to,
69
+ });
70
+ events.sort((a: CalendarEvent, b: CalendarEvent) => {
71
+ return a.start.getTime() - b.start.getTime();
72
+ });
73
+ return events;
74
+ }
75
+
76
+ const START: Date = OneUptimeDate.fromString("2025-01-06T00:00:00.000Z"); // Monday
77
+
78
+ describe("INVARIANT: 24/7 coverage contiguity (no gap > 2s, no overlap)", () => {
79
+ const configs: Config[] = [];
80
+ const intervals: EventInterval[] = [
81
+ EventInterval.Hour,
82
+ EventInterval.Day,
83
+ EventInterval.Week,
84
+ ];
85
+ const counts: number[] = [1, 2, 3];
86
+ const userSets: string[][] = [
87
+ ["A", "B"],
88
+ ["A", "B", "C"],
89
+ ];
90
+ const timezones: (string | undefined)[] = [
91
+ undefined,
92
+ "America/New_York",
93
+ "Asia/Kolkata",
94
+ ];
95
+ for (const it of intervals) {
96
+ for (const count of counts) {
97
+ for (const users of userSets) {
98
+ for (const tz of timezones) {
99
+ configs.push({
100
+ name: `${count}x${it} users=${users.length} tz=${tz ?? "local"}`,
101
+ intervalType: it,
102
+ intervalCount: count,
103
+ userIds: users,
104
+ timezone: tz,
105
+ start: START,
106
+ });
107
+ }
108
+ }
109
+ }
110
+ }
111
+
112
+ const horizonMs: Record<string, number> = {
113
+ [EventInterval.Hour]: 60 * 3600000, // 60 hours
114
+ [EventInterval.Day]: 60 * 86400000, // 60 days (crosses spring DST)
115
+ [EventInterval.Week]: 40 * 604800000, // 40 weeks (crosses DST both ways)
116
+ };
117
+
118
+ for (const c of configs) {
119
+ it(`${c.name}`, () => {
120
+ const layer: LayerProps = layerOf(c);
121
+ const to: Date = new Date(
122
+ START.getTime() + (horizonMs[c.intervalType] || 60 * 86400000),
123
+ );
124
+ const events: Array<CalendarEvent> = fullExpand(layer, to);
125
+
126
+ const problems: string[] = [];
127
+ for (let i: number = 1; i < events.length; i++) {
128
+ const prev: CalendarEvent = events[i - 1]!;
129
+ const cur: CalendarEvent = events[i]!;
130
+ const gapMs: number = cur.start.getTime() - prev.end.getTime();
131
+ // Expected seam is +1s. Flag gaps > 2s (coverage hole) or overlaps (<0).
132
+ if (gapMs > 2000) {
133
+ problems.push(
134
+ `GAP ${gapMs}ms between ${prev.title}@${prev.end.toISOString()} and ${cur.title}@${cur.start.toISOString()}`,
135
+ );
136
+ }
137
+ if (gapMs < 0) {
138
+ problems.push(
139
+ `OVERLAP ${gapMs}ms between ${prev.title}@${prev.end.toISOString()} and ${cur.title}@${cur.start.toISOString()}`,
140
+ );
141
+ }
142
+ }
143
+
144
+ expect({ config: c.name, problems }).toEqual({
145
+ config: c.name,
146
+ problems: [],
147
+ });
148
+ });
149
+ }
150
+ });
151
+
152
+ describe("INVARIANT: rotation order + fairness over many periods", () => {
153
+ const configs: Config[] = [];
154
+ const intervals: EventInterval[] = [
155
+ EventInterval.Hour,
156
+ EventInterval.Day,
157
+ EventInterval.Week,
158
+ ];
159
+ const counts: number[] = [1, 2, 3];
160
+ const userSets: string[][] = [
161
+ ["A", "B", "C"],
162
+ ["A", "B", "C", "D", "E"],
163
+ ];
164
+ const timezones: (string | undefined)[] = [undefined, "America/New_York"];
165
+ for (const it of intervals) {
166
+ for (const count of counts) {
167
+ for (const users of userSets) {
168
+ for (const tz of timezones) {
169
+ configs.push({
170
+ name: `${count}x${it} users=${users.length} tz=${tz ?? "local"}`,
171
+ intervalType: it,
172
+ intervalCount: count,
173
+ userIds: users,
174
+ timezone: tz,
175
+ start: START,
176
+ });
177
+ }
178
+ }
179
+ }
180
+ }
181
+
182
+ const horizonMs: Record<string, number> = {
183
+ [EventInterval.Hour]: 120 * 3600000,
184
+ [EventInterval.Day]: 120 * 86400000,
185
+ [EventInterval.Week]: 60 * 604800000,
186
+ };
187
+
188
+ for (const c of configs) {
189
+ it(`${c.name}`, () => {
190
+ const layer: LayerProps = layerOf(c);
191
+ const to: Date = new Date(
192
+ START.getTime() + (horizonMs[c.intervalType] || 120 * 86400000),
193
+ );
194
+ const events: Array<CalendarEvent> = fullExpand(layer, to);
195
+
196
+ // ORDER: consecutive events cycle in userIds order.
197
+ const orderProblems: string[] = [];
198
+ const n: number = c.userIds.length;
199
+ for (let i: number = 0; i < events.length; i++) {
200
+ const expected: string = c.userIds[i % n]!;
201
+ if (events[i]!.title !== expected) {
202
+ orderProblems.push(
203
+ `event#${i} start=${events[i]!.start.toISOString()} expected=${expected} actual=${events[i]!.title}`,
204
+ );
205
+ break; // first divergence is enough
206
+ }
207
+ }
208
+
209
+ // FAIRNESS: drop the final (possibly clipped) event, count shifts.
210
+ const counts: Record<string, number> = {};
211
+ const usable: Array<CalendarEvent> = events.slice(0, -1);
212
+ for (const e of usable) {
213
+ counts[e.title] = (counts[e.title] || 0) + 1;
214
+ }
215
+ const values: number[] = c.userIds.map((u: string) => {
216
+ return counts[u] || 0;
217
+ });
218
+ const max: number = Math.max(...values);
219
+ const min: number = Math.min(...values);
220
+
221
+ expect({
222
+ config: c.name,
223
+ orderProblems,
224
+ fairnessSpread: max - min,
225
+ }).toEqual({
226
+ config: c.name,
227
+ orderProblems: [],
228
+ fairnessSpread: max - min <= 1 ? max - min : "TOO_WIDE:" + (max - min),
229
+ });
230
+ });
231
+ }
232
+ });
@@ -0,0 +1,227 @@
1
+ import LayerUtil, { LayerProps } from "../../../Types/OnCallDutyPolicy/Layer";
2
+ import RestrictionTimes, {
3
+ RestrictionType,
4
+ } from "../../../Types/OnCallDutyPolicy/RestrictionTimes";
5
+ import Recurring from "../../../Types/Events/Recurring";
6
+ import EventInterval from "../../../Types/Events/EventInterval";
7
+ import PositiveNumber from "../../../Types/PositiveNumber";
8
+ import OneUptimeDate from "../../../Types/Date";
9
+ import User from "../../../Models/DatabaseModels/User";
10
+ import CalendarEvent from "../../../Types/Calendar/CalendarEvent";
11
+ import { describe, expect, test } from "@jest/globals";
12
+
13
+ /*
14
+ * Audit H2: removeOverlappingEvents ran a full Array.sort() INSIDE its per-event
15
+ * loop (O(n^2 log n)); getEvents rebuilt its array with [...events, ...] each
16
+ * period (O(n^2)). The fix hoists the sort to a single post-loop sort and pushes
17
+ * per-period segments, and makes the lower-priority "trim current event" step a
18
+ * monotonic max so it is independent of finalEvents ordering (which is what made
19
+ * hoisting the sort safe). These tests lock in the merge INVARIANTS the
20
+ * optimization must preserve: no overlaps, sorted, positive length, and correct
21
+ * priority/fallback coverage with no gaps under a 24/7 fallback.
22
+ */
23
+
24
+ function user(id: string): User {
25
+ return {
26
+ id: {
27
+ toString: (): string => {
28
+ return id;
29
+ },
30
+ } as any,
31
+ } as User;
32
+ }
33
+
34
+ function rotation(type: EventInterval, count: number): Recurring {
35
+ const r: Recurring = new Recurring();
36
+ r.intervalType = type;
37
+ r.intervalCount = new PositiveNumber(count);
38
+ return r;
39
+ }
40
+
41
+ function businessHoursRestriction(): RestrictionTimes {
42
+ const rt: RestrictionTimes = new RestrictionTimes();
43
+ rt.restictionType = RestrictionType.Daily;
44
+ rt.dayRestrictionTimes = {
45
+ startTime: new Date(Date.UTC(2025, 0, 1, 9, 0, 0)),
46
+ endTime: new Date(Date.UTC(2025, 0, 1, 17, 0, 0)),
47
+ };
48
+ return rt;
49
+ }
50
+
51
+ function assertSortedNonOverlappingPositive(
52
+ events: Array<CalendarEvent>,
53
+ ): void {
54
+ for (let i: number = 0; i < events.length; i++) {
55
+ // positive length
56
+ expect(new Date(events[i]!.end).getTime()).toBeGreaterThan(
57
+ new Date(events[i]!.start).getTime(),
58
+ );
59
+ if (i > 0) {
60
+ // sorted by start
61
+ expect(new Date(events[i]!.start).getTime()).toBeGreaterThanOrEqual(
62
+ new Date(events[i - 1]!.start).getTime(),
63
+ );
64
+ // non-overlapping (previous end is at/before this start)
65
+ expect(new Date(events[i - 1]!.end).getTime()).toBeLessThanOrEqual(
66
+ new Date(events[i]!.start).getTime(),
67
+ );
68
+ }
69
+ }
70
+ }
71
+
72
+ describe("LayerUtil audit H2: multi-layer merge invariants preserved", () => {
73
+ const windowStart: Date = new Date(Date.UTC(2025, 5, 2, 0, 0, 0));
74
+ const windowEnd: Date = new Date(Date.UTC(2025, 5, 6, 0, 0, 0));
75
+
76
+ test("high-priority business-hours layer over a 24/7 fallback: no overlaps, no gaps, both users present", () => {
77
+ const layers: Array<LayerProps> = [
78
+ {
79
+ // priority 1 (higher): business-hours coverage by X
80
+ users: [user("X")],
81
+ startDateTimeOfLayer: new Date(Date.UTC(2025, 5, 1, 0, 0, 0)),
82
+ handOffTime: new Date(Date.UTC(2025, 5, 1, 0, 0, 0)),
83
+ restrictionTimes: businessHoursRestriction(),
84
+ rotation: rotation(EventInterval.Day, 1),
85
+ timezone: "UTC",
86
+ },
87
+ {
88
+ // priority 2 (fallback): 24/7 coverage by Y
89
+ users: [user("Y")],
90
+ startDateTimeOfLayer: new Date(Date.UTC(2025, 5, 1, 0, 0, 0)),
91
+ handOffTime: new Date(Date.UTC(2025, 5, 1, 0, 0, 0)),
92
+ restrictionTimes: RestrictionTimes.getDefault(),
93
+ rotation: rotation(EventInterval.Week, 1),
94
+ timezone: "UTC",
95
+ },
96
+ ];
97
+
98
+ const events: Array<CalendarEvent> = new LayerUtil().getMultiLayerEvents({
99
+ layers,
100
+ calendarStartDate: windowStart,
101
+ calendarEndDate: windowEnd,
102
+ });
103
+
104
+ assertSortedNonOverlappingPositive(events);
105
+
106
+ const titles: Set<string> = new Set(
107
+ events.map((e: CalendarEvent) => {
108
+ return e.title;
109
+ }),
110
+ );
111
+ expect(titles.has("X")).toBe(true); // higher priority appears
112
+ expect(titles.has("Y")).toBe(true); // fallback fills the gaps
113
+
114
+ /*
115
+ * With a 24/7 fallback the merged coverage must be CONTIGUOUS across the
116
+ * window (no uncovered gap). Allow the ~1s boundary seam the engine leaves
117
+ * between adjacent events.
118
+ */
119
+ for (let i: number = 1; i < events.length; i++) {
120
+ const gapSeconds: number =
121
+ (new Date(events[i]!.start).getTime() -
122
+ new Date(events[i - 1]!.end).getTime()) /
123
+ 1000;
124
+ expect(gapSeconds).toBeLessThanOrEqual(2);
125
+ }
126
+ });
127
+
128
+ test("two back-to-back higher-priority windows over a fallback preserve the fallback's trailing tail (max-trim path)", () => {
129
+ /*
130
+ * Higher-priority daily rotation with two users creates adjacent daily
131
+ * windows; the fallback must survive as gaps/tail with no overlap.
132
+ */
133
+ const layers: Array<LayerProps> = [
134
+ {
135
+ users: [user("P"), user("Q")],
136
+ startDateTimeOfLayer: new Date(Date.UTC(2025, 5, 1, 0, 0, 0)),
137
+ handOffTime: new Date(Date.UTC(2025, 5, 1, 0, 0, 0)),
138
+ restrictionTimes: businessHoursRestriction(),
139
+ rotation: rotation(EventInterval.Day, 1),
140
+ timezone: "UTC",
141
+ },
142
+ {
143
+ users: [user("F")],
144
+ startDateTimeOfLayer: new Date(Date.UTC(2025, 5, 1, 0, 0, 0)),
145
+ handOffTime: new Date(Date.UTC(2025, 5, 1, 0, 0, 0)),
146
+ restrictionTimes: RestrictionTimes.getDefault(),
147
+ rotation: rotation(EventInterval.Week, 1),
148
+ timezone: "UTC",
149
+ },
150
+ ];
151
+
152
+ const events: Array<CalendarEvent> = new LayerUtil().getMultiLayerEvents({
153
+ layers,
154
+ calendarStartDate: windowStart,
155
+ calendarEndDate: windowEnd,
156
+ });
157
+
158
+ assertSortedNonOverlappingPositive(events);
159
+
160
+ /*
161
+ * The fallback F must appear (it owns the nights/weekends the higher layer
162
+ * does not cover) — the trailing-tail reconstruction must not delete it.
163
+ */
164
+ const titles: Set<string> = new Set(
165
+ events.map((e: CalendarEvent) => {
166
+ return e.title;
167
+ }),
168
+ );
169
+ expect(titles.has("F")).toBe(true);
170
+ });
171
+
172
+ test("single unrestricted layer: getNumberOfEvents returns exactly the requested current+next", () => {
173
+ const layer: LayerProps = {
174
+ users: [user("A"), user("B")],
175
+ startDateTimeOfLayer: new Date(Date.UTC(2025, 5, 1, 0, 0, 0)),
176
+ handOffTime: new Date(Date.UTC(2025, 5, 1, 0, 0, 0)),
177
+ restrictionTimes: RestrictionTimes.getDefault(),
178
+ rotation: rotation(EventInterval.Day, 1),
179
+ timezone: "UTC",
180
+ };
181
+
182
+ const events: Array<CalendarEvent> = new LayerUtil().getMultiLayerEvents(
183
+ {
184
+ layers: [layer],
185
+ calendarStartDate: new Date(Date.UTC(2025, 5, 3, 12, 0, 0)),
186
+ calendarEndDate: new Date(Date.UTC(2025, 5, 10, 0, 0, 0)),
187
+ },
188
+ { getNumberOfEvents: 2 },
189
+ );
190
+
191
+ expect(events.length).toBe(2);
192
+ assertSortedNonOverlappingPositive(events);
193
+ // current and next are different users in a 2-user daily rotation.
194
+ expect(events[0]!.title).not.toBe(events[1]!.title);
195
+ });
196
+
197
+ test("hourly layer over a multi-day window resolves quickly (push not O(n^2) spread)", () => {
198
+ const layer: LayerProps = {
199
+ users: [user("A"), user("B")],
200
+ startDateTimeOfLayer: new Date(Date.UTC(2025, 5, 1, 0, 0, 0)),
201
+ handOffTime: new Date(Date.UTC(2025, 5, 1, 0, 0, 0)),
202
+ restrictionTimes: RestrictionTimes.getDefault(),
203
+ rotation: rotation(EventInterval.Hour, 1),
204
+ timezone: "UTC",
205
+ };
206
+
207
+ const start: number = OneUptimeDate.getCurrentDate().getTime();
208
+ const events: Array<CalendarEvent> = new LayerUtil().getMultiLayerEvents({
209
+ layers: [layer],
210
+ /*
211
+ * ~20 days of hourly events (~480) — the merge must stay well under any
212
+ * pathological quadratic blowup.
213
+ */
214
+ calendarStartDate: new Date(Date.UTC(2025, 5, 1, 0, 0, 0)),
215
+ calendarEndDate: new Date(Date.UTC(2025, 5, 21, 0, 0, 0)),
216
+ });
217
+ const elapsedMs: number = OneUptimeDate.getCurrentDate().getTime() - start;
218
+
219
+ expect(events.length).toBeGreaterThan(0);
220
+ assertSortedNonOverlappingPositive(events);
221
+ /*
222
+ * Generous ceiling — the pre-fix quadratic path took tens of seconds for far
223
+ * fewer events; this must complete in a small fraction of that.
224
+ */
225
+ expect(elapsedMs).toBeLessThan(15000);
226
+ });
227
+ });