@oneuptime/common 12.0.29 → 12.0.31

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 (664) hide show
  1. package/Models/AnalyticsModels/SecurityEvent.ts +48 -16
  2. package/Models/AnalyticsModels/ThreatIntelIndicator.ts +10 -5
  3. package/Models/DatabaseModels/AlertSeverity.ts +44 -0
  4. package/Models/DatabaseModels/DetectionRule.ts +16 -5
  5. package/Models/DatabaseModels/GoogleSecOpsConnection.ts +14 -5
  6. package/Models/DatabaseModels/IncidentSeverity.ts +44 -0
  7. package/Models/DatabaseModels/Index.ts +13 -0
  8. package/Models/DatabaseModels/NetworkDevice.ts +113 -3
  9. package/Models/DatabaseModels/NetworkDeviceAutoImportRule.ts +88 -0
  10. package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +22 -0
  11. package/Models/DatabaseModels/NetworkDeviceOidTemplate.ts +499 -0
  12. package/Models/DatabaseModels/OnCallDutyPolicySchedule.ts +43 -0
  13. package/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.ts +662 -0
  14. package/Models/DatabaseModels/ProjectOnCallCalendarFeed.ts +584 -0
  15. package/Models/DatabaseModels/ThreatIntelFeed.ts +16 -5
  16. package/Models/DatabaseModels/UserOnCallCalendarFeed.ts +546 -0
  17. package/Models/DatabaseModels/UserOnCallShiftReminder.ts +231 -0
  18. package/Models/DatabaseModels/UserOnCallShiftReminderLog.ts +331 -0
  19. package/Server/API/GlobalConfigAPI.ts +362 -183
  20. package/Server/API/OnCallCalendarAPI.ts +2194 -0
  21. package/Server/API/TelemetryAPI.ts +42 -4
  22. package/Server/EnvironmentConfig.ts +250 -0
  23. package/Server/Infrastructure/OnCallCalendarFeedCache.ts +1050 -0
  24. package/Server/Infrastructure/Postgres/SchemaMigrations/1790400000000-AddOnCallCalendarFeeds.ts +253 -0
  25. package/Server/Infrastructure/Postgres/SchemaMigrations/1790500000000-AddNetworkDeviceOidTemplate.ts +59 -0
  26. package/Server/Infrastructure/Postgres/SchemaMigrations/1790600000000-AddAutoImportRuleOidTemplate.ts +25 -0
  27. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
  28. package/Server/Middleware/MultipartFormData.ts +118 -32
  29. package/Server/Middleware/OnCallCalendarFeedRateLimit.ts +487 -0
  30. package/Server/Services/AlertEpisodeLabelRuleEngineService.ts +9 -1
  31. package/Server/Services/AlertEpisodeOnCallRuleEngineService.ts +9 -1
  32. package/Server/Services/AlertEpisodeOwnerRuleEngineService.ts +9 -1
  33. package/Server/Services/AlertEpisodePrivacyRuleEngineService.ts +9 -1
  34. package/Server/Services/AlertGroupingEngineService.ts +9 -1
  35. package/Server/Services/AlertLabelRuleEngineService.ts +9 -1
  36. package/Server/Services/AlertOnCallRuleEngineService.ts +9 -1
  37. package/Server/Services/AlertOwnerRuleEngineService.ts +9 -1
  38. package/Server/Services/AlertPrivacyRuleEngineService.ts +9 -1
  39. package/Server/Services/AlertReminderRuleService.ts +9 -1
  40. package/Server/Services/AutoRemediationRuleEngineService.ts +9 -1
  41. package/Server/Services/CephClusterLabelRuleEngineService.ts +9 -1
  42. package/Server/Services/CephClusterOwnerRuleEngineService.ts +9 -1
  43. package/Server/Services/CloudResourceLabelRuleEngineService.ts +9 -1
  44. package/Server/Services/CloudResourceOwnerRuleEngineService.ts +9 -1
  45. package/Server/Services/DashboardLabelRuleEngineService.ts +9 -1
  46. package/Server/Services/DashboardOwnerRuleEngineService.ts +9 -1
  47. package/Server/Services/DockerHostLabelRuleEngineService.ts +9 -1
  48. package/Server/Services/DockerHostOwnerRuleEngineService.ts +9 -1
  49. package/Server/Services/DockerSwarmClusterLabelRuleEngineService.ts +9 -1
  50. package/Server/Services/DockerSwarmClusterOwnerRuleEngineService.ts +9 -1
  51. package/Server/Services/HostLabelRuleEngineService.ts +9 -1
  52. package/Server/Services/HostOwnerRuleEngineService.ts +9 -1
  53. package/Server/Services/IncidentEpisodeLabelRuleEngineService.ts +9 -1
  54. package/Server/Services/IncidentEpisodeOnCallRuleEngineService.ts +9 -1
  55. package/Server/Services/IncidentEpisodeOwnerRuleEngineService.ts +9 -1
  56. package/Server/Services/IncidentEpisodePrivacyRuleEngineService.ts +9 -1
  57. package/Server/Services/IncidentGroupingEngineService.ts +9 -1
  58. package/Server/Services/IncidentLabelRuleEngineService.ts +9 -1
  59. package/Server/Services/IncidentOnCallRuleEngineService.ts +9 -1
  60. package/Server/Services/IncidentOwnerRuleEngineService.ts +9 -1
  61. package/Server/Services/IncidentPrivacyRuleEngineService.ts +9 -1
  62. package/Server/Services/IncidentReminderRuleService.ts +9 -1
  63. package/Server/Services/IncidentSlaRuleService.ts +9 -1
  64. package/Server/Services/IncomingCallPolicyLabelRuleEngineService.ts +9 -1
  65. package/Server/Services/IncomingCallPolicyOwnerRuleEngineService.ts +9 -1
  66. package/Server/Services/Index.ts +14 -0
  67. package/Server/Services/IoTFleetLabelRuleEngineService.ts +9 -1
  68. package/Server/Services/IoTFleetOwnerRuleEngineService.ts +9 -1
  69. package/Server/Services/KubernetesClusterLabelRuleEngineService.ts +9 -1
  70. package/Server/Services/KubernetesClusterOwnerRuleEngineService.ts +9 -1
  71. package/Server/Services/KubernetesResourceService.ts +5 -1
  72. package/Server/Services/MonitorLabelRuleEngineService.ts +9 -1
  73. package/Server/Services/MonitorOwnerRuleEngineService.ts +9 -1
  74. package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +35 -0
  75. package/Server/Services/NetworkDeviceAutoImportRuleService.ts +96 -0
  76. package/Server/Services/NetworkDeviceLabelRuleEngineService.ts +9 -1
  77. package/Server/Services/NetworkDeviceOidTemplateService.ts +201 -0
  78. package/Server/Services/NetworkDeviceOwnerRuleEngineService.ts +9 -1
  79. package/Server/Services/NetworkDeviceService.ts +209 -1
  80. package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +32 -0
  81. package/Server/Services/OnCallDutyPolicyLabelRuleEngineService.ts +9 -1
  82. package/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.ts +9 -1
  83. package/Server/Services/OnCallDutyPolicyScheduleCalendarFeedService.ts +260 -0
  84. package/Server/Services/OnCallDutyPolicyScheduleLabelRuleEngineService.ts +9 -1
  85. package/Server/Services/OnCallDutyPolicyScheduleLayerService.ts +70 -3
  86. package/Server/Services/OnCallDutyPolicyScheduleLayerUserService.ts +138 -3
  87. package/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.ts +9 -1
  88. package/Server/Services/OnCallDutyPolicyScheduleService.ts +1465 -134
  89. package/Server/Services/OnCallDutyPolicyUserOverrideService.ts +167 -31
  90. package/Server/Services/PodmanHostLabelRuleEngineService.ts +9 -1
  91. package/Server/Services/PodmanHostOwnerRuleEngineService.ts +9 -1
  92. package/Server/Services/ProjectOnCallCalendarFeedService.ts +192 -0
  93. package/Server/Services/ProxmoxClusterLabelRuleEngineService.ts +9 -1
  94. package/Server/Services/ProxmoxClusterOwnerRuleEngineService.ts +9 -1
  95. package/Server/Services/RumApplicationLabelRuleEngineService.ts +9 -1
  96. package/Server/Services/RumApplicationOwnerRuleEngineService.ts +9 -1
  97. package/Server/Services/RunbookLabelRuleEngineService.ts +9 -1
  98. package/Server/Services/RunbookOwnerRuleEngineService.ts +9 -1
  99. package/Server/Services/RunbookRuleEngineService.ts +9 -1
  100. package/Server/Services/ScheduledMaintenanceLabelRuleEngineService.ts +9 -1
  101. package/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.ts +9 -1
  102. package/Server/Services/ScheduledMaintenanceReminderRuleService.ts +9 -1
  103. package/Server/Services/ServerlessFunctionLabelRuleEngineService.ts +9 -1
  104. package/Server/Services/ServerlessFunctionOwnerRuleEngineService.ts +9 -1
  105. package/Server/Services/ServiceLabelRuleEngineService.ts +9 -1
  106. package/Server/Services/ServiceOwnerRuleEngineService.ts +9 -1
  107. package/Server/Services/StatusPageLabelRuleEngineService.ts +9 -1
  108. package/Server/Services/StatusPageMonitorRuleEngineService.ts +7 -0
  109. package/Server/Services/StatusPageOwnerRuleEngineService.ts +9 -1
  110. package/Server/Services/TeamMemberService.ts +489 -1
  111. package/Server/Services/TeamService.ts +50 -0
  112. package/Server/Services/TelemetrySourceMapService.ts +266 -23
  113. package/Server/Services/UserNotificationSettingService.ts +44 -1
  114. package/Server/Services/UserOnCallCalendarFeedService.ts +159 -0
  115. package/Server/Services/UserOnCallShiftReminderLogService.ts +151 -0
  116. package/Server/Services/UserOnCallShiftReminderService.ts +112 -0
  117. package/Server/Services/UserService.ts +27 -0
  118. package/Server/Services/WorkflowLabelRuleEngineService.ts +9 -1
  119. package/Server/Services/WorkflowOwnerRuleEngineService.ts +9 -1
  120. package/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.ts +186 -0
  121. package/Server/Utils/Monitor/CapturedMetricAttributeUtil.ts +245 -0
  122. package/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.ts +21 -2
  123. package/Server/Utils/Monitor/MonitorMetricUtil.ts +55 -21
  124. package/Server/Utils/Monitor/MonitorTemplateUtil.ts +32 -0
  125. package/Server/Utils/Monitor/NetworkDeviceMetricUtil.ts +15 -2
  126. package/Server/Utils/Monitor/NetworkDeviceWalkUtil.ts +18 -1
  127. package/Server/Utils/Monitor/NetworkInventoryUtil.ts +10 -0
  128. package/Server/Utils/Monitor/SeriesResourceLabels.ts +34 -0
  129. package/Server/Utils/OnCall/CalendarFeedToken.ts +241 -0
  130. package/Server/Utils/OnCall/OnCallCalendarFeedRenderer.ts +1488 -0
  131. package/Server/Utils/OnCall/OnCallCalendarFeedUrls.ts +230 -0
  132. package/Server/Utils/OnCall/OnCallShiftChangeListeners.ts +227 -0
  133. package/Server/Utils/OnCall/OnCallShiftMaterializer.ts +1127 -0
  134. package/Server/Utils/OnCall/OnCallShiftReminderListener.ts +174 -0
  135. package/Server/Utils/OnCall/OnCallShiftReminderRunner.ts +2584 -0
  136. package/Server/Utils/Response.ts +134 -0
  137. package/Server/Utils/Rules/RuleEngineRuleRead.ts +48 -0
  138. package/Server/Utils/StartServer.ts +10 -0
  139. package/Server/Utils/Telemetry/AppMetrics.ts +51 -0
  140. package/Server/Utils/Telemetry/ExceptionSanitizer.ts +14 -1
  141. package/Server/Utils/Telemetry/LogExceptionExtractor.ts +14 -2
  142. package/Server/Utils/Telemetry/SourceMapResolver.ts +16 -5
  143. package/Server/Utils/Telemetry/StackTraceParser.ts +399 -0
  144. package/Tests/App/Dashboard/EventOverlayHook.test.tsx +125 -0
  145. package/Tests/App/Dashboard/HeaderImageAssets.test.tsx +93 -0
  146. package/Tests/App/Dashboard/OnCallCalendarFeedLinks.test.tsx +229 -0
  147. package/Tests/App/Dashboard/OnCallCalendarFeedPlanGate.test.tsx +489 -0
  148. package/Tests/App/Dashboard/OnCallCalendarFeedSideMenus.test.tsx +149 -0
  149. package/Tests/App/Dashboard/OnCallCalendarFeedUtil.test.ts +855 -0
  150. package/Tests/App/Dashboard/OnCallPersonalCalendarFeed.test.tsx +1209 -0
  151. package/Tests/App/Dashboard/OnCallReadinessSurfaces.test.tsx +3 -3
  152. package/Tests/App/Dashboard/OnCallSharedCalendarFeedCard.test.tsx +1019 -0
  153. package/Tests/App/Dashboard/OnCallShiftRemindersAndUpcomingShifts.test.tsx +655 -0
  154. package/Tests/App/Dashboard/UserElementEmail.test.tsx +12 -4
  155. package/Tests/App/Dashboard/UserEmailCallSites.test.tsx +1 -1
  156. package/Tests/App/Dashboard/UserSettingsSetupChecklistModel.test.ts +73 -0
  157. package/Tests/Models/DatabaseModels/DomainRoleTierCoverage.test.ts +14 -0
  158. package/Tests/Models/DatabaseModels/ModelRegistryInvariants.test.ts +469 -0
  159. package/Tests/Models/OnCallCalendarFeedModels.test.ts +642 -0
  160. package/Tests/Models/OnCallDutyPolicyScheduleCalendarFeed.test.ts +288 -0
  161. package/Tests/Models/OnCallDutyPolicyScheduleShiftConfigVersion.test.ts +88 -0
  162. package/Tests/Models/SecurityDomainAccessControl.test.ts +429 -0
  163. package/Tests/Models/UserOnCallShiftReminderModels.test.ts +368 -0
  164. package/Tests/Server/API/GlobalConfigLicense.test.ts +657 -0
  165. package/Tests/Server/API/Helpers.ts +8 -0
  166. package/Tests/Server/API/OnCallCalendarAPI.test.ts +4461 -0
  167. package/Tests/Server/API/SecurityEventAttributesAPI.test.ts +84 -6
  168. package/Tests/Server/API/TelemetryResolveStackTraceAPI.test.ts +805 -0
  169. package/Tests/Server/EnvironmentConfigOnCallCalendarFeed.test.ts +357 -0
  170. package/Tests/Server/Infrastructure/OnCallCalendarFeedCache.test.ts +1589 -0
  171. package/Tests/Server/Infrastructure/Postgres/AddOnCallCalendarFeedsMigration.test.ts +394 -0
  172. package/Tests/Server/Middleware/IdentityRateLimit.test.ts +1144 -0
  173. package/Tests/Server/Middleware/MultipartFormData.test.ts +618 -3
  174. package/Tests/Server/Middleware/OnCallCalendarFeedRateLimit.test.ts +1365 -0
  175. package/Tests/Server/Services/FeedRetentionConsistency.test.ts +70 -0
  176. package/Tests/Server/Services/MonitorLabelRuleEngineScale.test.ts +520 -0
  177. package/Tests/Server/Services/NetworkDeviceOidTemplateService.test.ts +332 -0
  178. package/Tests/Server/Services/NetworkDeviceOidTemplateWriteGuards.test.ts +409 -0
  179. package/Tests/Server/Services/OnCallCalendarFeedServices.test.ts +1103 -0
  180. package/Tests/Server/Services/OnCallDutyPolicyScheduleResolver.test.ts +1037 -0
  181. package/Tests/Server/Services/OnCallShiftConfigPropagation.test.ts +1270 -0
  182. package/Tests/Server/Services/RuleEngineRuleFetchLimit.test.ts +239 -0
  183. package/Tests/Server/Services/TeamDeleteMemberCleanup.test.ts +156 -0
  184. package/Tests/Server/Services/TeamMemberOnCallCleanup.test.ts +755 -0
  185. package/Tests/Server/Services/TelemetrySourceMapService.test.ts +1210 -2
  186. package/Tests/Server/Services/UserNotificationSettingShiftReminderDefaults.test.ts +267 -0
  187. package/Tests/Server/Services/UserOnCallShiftReminderServices.test.ts +583 -0
  188. package/Tests/Server/Services/UserServiceSeatLimit.test.ts +182 -0
  189. package/Tests/Server/Types/AnalyticsDatabase/SecurityEventModelPermission.test.ts +255 -0
  190. package/Tests/Server/Types/Database/Permissions/OnCallCalendarFeedPermissions.test.ts +254 -0
  191. package/Tests/Server/Types/Database/Permissions/ReadBlockPermission.test.ts +212 -0
  192. package/Tests/Server/Types/Database/Permissions/SecurityRoleAccess.test.ts +413 -0
  193. package/Tests/Server/Utils/CodeRepository.test.ts +689 -0
  194. package/Tests/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.test.ts +495 -0
  195. package/Tests/Server/Utils/ExceptionSanitizer.test.ts +77 -0
  196. package/Tests/Server/Utils/Monitor/CapturedMetricAttributeUtil.test.ts +284 -0
  197. package/Tests/Server/Utils/Monitor/MonitorCustomMetricAttributes.test.ts +503 -0
  198. package/Tests/Server/Utils/Monitor/MonitorTemplatePrototypePollution.test.ts +106 -0
  199. package/Tests/Server/Utils/Monitor/NetworkDeviceWalkLogWritePath.test.ts +33 -4
  200. package/Tests/Server/Utils/Monitor/NetworkDeviceWalkUtil.test.ts +14 -4
  201. package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +44 -0
  202. package/Tests/Server/Utils/OnCall/CalendarFeedToken.test.ts +467 -0
  203. package/Tests/Server/Utils/OnCall/OnCallCalendarFeedRenderer.test.ts +2142 -0
  204. package/Tests/Server/Utils/OnCall/OnCallCalendarFeedUrls.test.ts +278 -0
  205. package/Tests/Server/Utils/OnCall/OnCallResolverTestHarness.ts +440 -0
  206. package/Tests/Server/Utils/OnCall/OnCallShiftChangeListeners.test.ts +314 -0
  207. package/Tests/Server/Utils/OnCall/OnCallShiftMaterializer.test.ts +1502 -0
  208. package/Tests/Server/Utils/OnCall/OnCallShiftReminderListener.test.ts +491 -0
  209. package/Tests/Server/Utils/OnCall/OnCallShiftReminderRunner.test.ts +3088 -0
  210. package/Tests/Server/Utils/OnCall/OnCallShiftReminderTestHarness.ts +910 -0
  211. package/Tests/Server/Utils/OpenAPISpec.test.ts +536 -0
  212. package/Tests/Server/Utils/ResponseSendCalendarResponse.test.ts +561 -0
  213. package/Tests/Server/Utils/Rules/RuleEngineRuleRead.test.ts +115 -0
  214. package/Tests/Server/Utils/StackTraceParser.test.ts +610 -0
  215. package/Tests/Server/Utils/StartServerEncryptionSecretWarning.test.ts +64 -0
  216. package/Tests/Server/Utils/Telemetry/AppMetrics.test.ts +29 -0
  217. package/Tests/Server/Utils/Telemetry/LogExceptionExtractor.test.ts +0 -0
  218. package/Tests/Server/Utils/Telemetry/SourceMapLimits.test.ts +656 -0
  219. package/Tests/Server/Utils/Telemetry/SourceMapResolver.test.ts +100 -0
  220. package/Tests/Types/Calendar/ICalendar.test.ts +488 -0
  221. package/Tests/Types/Monitor/SnmpMonitor/SnmpOidListUtil.test.ts +454 -0
  222. package/Tests/Types/NotificationSetting/NotificationSettingEventType.test.ts +53 -0
  223. package/Tests/Types/OnCallDutyPolicy/CalendarFeedTestFixtures.ts +310 -0
  224. package/Tests/Types/OnCallDutyPolicy/CalendarFeedWindow.test.ts +205 -0
  225. package/Tests/Types/OnCallDutyPolicy/LayerUtilLayerMetaAndIterationCap.test.ts +458 -0
  226. package/Tests/Types/OnCallDutyPolicy/MaterializedShift.test.ts +197 -0
  227. package/Tests/Types/OnCallDutyPolicy/OnCallCalendarFeedUtil.test.ts +1986 -0
  228. package/Tests/Types/OnCallDutyPolicy/ScheduleShiftUtilGroupKey.test.ts +678 -0
  229. package/Tests/Types/OnCallDutyPolicy/ShiftSeamUtil.test.ts +417 -0
  230. package/Tests/Types/SecurityRolePermissions.test.ts +193 -0
  231. package/Tests/UI/Components/Charts/AnnotationLayout.test.ts +773 -0
  232. package/Tests/UI/Components/Charts/ChartAnnotationRail.test.tsx +789 -0
  233. package/Tests/UI/Components/Charts/ChartBucketIdentity.test.ts +254 -0
  234. package/Tests/UI/Components/Charts/TimeAnnotation.test.ts +471 -0
  235. package/Tests/UI/Components/EditionLabelLicenseRefresh.test.tsx +405 -0
  236. package/Tests/UI/Components/ErrorMessageRefreshControl.test.tsx +83 -0
  237. package/Tests/UI/Components/MarkdownConverters.test.ts +686 -0
  238. package/Tests/UI/Components/ModelTable/BaseModelTableDeleteAndEmptyStates.test.tsx +341 -0
  239. package/Tests/UI/Components/OrderedStatesList.test.tsx +5 -5
  240. package/Tests/UI/Components/PendingProjectInvitations.test.tsx +1 -1
  241. package/Tests/UI/Components/TableSortAndMobileColumns.test.tsx +195 -0
  242. package/Tests/UI/Components/XAxis.test.ts +270 -5
  243. package/Tests/UI/Components/XAxisDaylightSaving.test.ts +113 -0
  244. package/Tests/UI/Styles/ChartFocusRing.test.ts +153 -0
  245. package/Tests/UI/Styles/ChartFocusRingCoverage.test.tsx +377 -0
  246. package/Tests/UI/Styles/ThemeStylesheet.ts +162 -0
  247. package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +10 -0
  248. package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +2 -0
  249. package/Tests/Utils/EnterpriseLicenseSeats.test.ts +507 -0
  250. package/Tests/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.test.ts +951 -1
  251. package/Tests/Utils/NetworkDiscovery/DiscoveredHostUtil.test.ts +238 -0
  252. package/Tests/Utils/NetworkDiscovery/DiscoveryReverseDnsChain.test.ts +1056 -0
  253. package/Tests/Utils/NetworkDiscovery/ReverseDnsNameUtil.test.ts +882 -0
  254. package/Types/Calendar/ICalendar.ts +442 -0
  255. package/Types/Date.ts +39 -0
  256. package/Types/Email/EmailTemplateType.ts +2 -0
  257. package/Types/Monitor/SnmpMonitor/SnmpOidListUtil.ts +333 -0
  258. package/Types/NotificationSetting/NotificationSettingEventType.ts +4 -0
  259. package/Types/OnCallDutyPolicy/CalendarFeedWindow.ts +140 -0
  260. package/Types/OnCallDutyPolicy/Layer.ts +190 -35
  261. package/Types/OnCallDutyPolicy/MaterializedShift.ts +274 -0
  262. package/Types/OnCallDutyPolicy/OnCallCalendarFeedUtil.ts +1415 -0
  263. package/Types/OnCallDutyPolicy/ScheduleShiftUtil.ts +159 -4
  264. package/Types/OnCallDutyPolicy/ShiftSeamUtil.ts +106 -0
  265. package/Types/Permission.ts +96 -0
  266. package/Types/Rum/SessionReplay.ts +21 -0
  267. package/Types/Telemetry/SourceMap.ts +8 -0
  268. package/UI/Components/Charts/ChartLibrary/Annotations/AnnotationHoverCard.tsx +176 -0
  269. package/UI/Components/Charts/ChartLibrary/Annotations/AnnotationLayout.ts +745 -0
  270. package/UI/Components/Charts/ChartLibrary/Annotations/ChartAnnotationLayer.tsx +576 -0
  271. package/UI/Components/Charts/ChartLibrary/Annotations/UseChartAnnotations.tsx +204 -0
  272. package/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.tsx +491 -544
  273. package/UI/Components/Charts/ChartLibrary/BarChart/BarChart.tsx +324 -372
  274. package/UI/Components/Charts/ChartLibrary/LineChart/LineChart.tsx +487 -540
  275. package/UI/Components/Charts/ChartLibrary/Types/FormattedReferenceRegion.ts +7 -3
  276. package/UI/Components/Charts/ChartLibrary/Types/FormattedTimeReferenceLine.ts +14 -3
  277. package/UI/Components/Charts/Types/ChartEventKind.ts +13 -0
  278. package/UI/Components/Charts/Types/ReferenceRegionProps.ts +6 -0
  279. package/UI/Components/Charts/Types/TimeReferenceLineProps.ts +20 -3
  280. package/UI/Components/Charts/Utils/TimeAnnotation.ts +69 -35
  281. package/UI/Components/Charts/Utils/XAxis.ts +125 -18
  282. package/UI/Components/EditionLabel/EditionLabel.tsx +280 -26
  283. package/UI/Components/ErrorMessage/ErrorMessage.tsx +21 -10
  284. package/UI/Components/Feed/FeedItem.tsx +4 -5
  285. package/UI/Components/Header/HeaderIconDropdownButton.tsx +1 -2
  286. package/UI/Components/Header/UserProfile/UserProfile.tsx +1 -2
  287. package/UI/Components/Image/Image.tsx +20 -3
  288. package/UI/Components/Markdown.tsx/MarkdownConverters.ts +0 -0
  289. package/UI/Components/MemberRoleAssignment/MemberRoleAssignment.tsx +1 -2
  290. package/UI/Components/ModelTable/BaseModelTable.tsx +150 -24
  291. package/UI/Components/Table/TableHeader.tsx +64 -48
  292. package/UI/Components/Table/TableRow.tsx +13 -3
  293. package/UI/Styles/Theme.css +38 -0
  294. package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +271 -0
  295. package/Utils/NetworkDiscovery/AutoImportRuleMatcher.ts +6 -0
  296. package/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.ts +141 -10
  297. package/Utils/NetworkDiscovery/DiscoveredHostUtil.ts +55 -3
  298. package/Utils/NetworkDiscovery/ReverseDnsNameUtil.ts +151 -0
  299. package/Utils/Rules/RuleEngineLimits.ts +32 -0
  300. package/build/dist/Models/AnalyticsModels/SecurityEvent.js +48 -16
  301. package/build/dist/Models/AnalyticsModels/SecurityEvent.js.map +1 -1
  302. package/build/dist/Models/AnalyticsModels/ThreatIntelIndicator.js +10 -5
  303. package/build/dist/Models/AnalyticsModels/ThreatIntelIndicator.js.map +1 -1
  304. package/build/dist/Models/DatabaseModels/AlertSeverity.js +46 -1
  305. package/build/dist/Models/DatabaseModels/AlertSeverity.js.map +1 -1
  306. package/build/dist/Models/DatabaseModels/DetectionRule.js +16 -5
  307. package/build/dist/Models/DatabaseModels/DetectionRule.js.map +1 -1
  308. package/build/dist/Models/DatabaseModels/GoogleSecOpsConnection.js +14 -5
  309. package/build/dist/Models/DatabaseModels/GoogleSecOpsConnection.js.map +1 -1
  310. package/build/dist/Models/DatabaseModels/IncidentSeverity.js +46 -1
  311. package/build/dist/Models/DatabaseModels/IncidentSeverity.js.map +1 -1
  312. package/build/dist/Models/DatabaseModels/Index.js +13 -0
  313. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  314. package/build/dist/Models/DatabaseModels/NetworkDevice.js +115 -3
  315. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
  316. package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js +88 -0
  317. package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js.map +1 -1
  318. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
  319. package/build/dist/Models/DatabaseModels/NetworkDeviceOidTemplate.js +519 -0
  320. package/build/dist/Models/DatabaseModels/NetworkDeviceOidTemplate.js.map +1 -0
  321. package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js +44 -0
  322. package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js.map +1 -1
  323. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.js +699 -0
  324. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.js.map +1 -0
  325. package/build/dist/Models/DatabaseModels/ProjectOnCallCalendarFeed.js +620 -0
  326. package/build/dist/Models/DatabaseModels/ProjectOnCallCalendarFeed.js.map +1 -0
  327. package/build/dist/Models/DatabaseModels/ThreatIntelFeed.js +16 -5
  328. package/build/dist/Models/DatabaseModels/ThreatIntelFeed.js.map +1 -1
  329. package/build/dist/Models/DatabaseModels/UserOnCallCalendarFeed.js +585 -0
  330. package/build/dist/Models/DatabaseModels/UserOnCallCalendarFeed.js.map +1 -0
  331. package/build/dist/Models/DatabaseModels/UserOnCallShiftReminder.js +247 -0
  332. package/build/dist/Models/DatabaseModels/UserOnCallShiftReminder.js.map +1 -0
  333. package/build/dist/Models/DatabaseModels/UserOnCallShiftReminderLog.js +355 -0
  334. package/build/dist/Models/DatabaseModels/UserOnCallShiftReminderLog.js.map +1 -0
  335. package/build/dist/Server/API/GlobalConfigAPI.js +293 -176
  336. package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
  337. package/build/dist/Server/API/OnCallCalendarAPI.js +1371 -0
  338. package/build/dist/Server/API/OnCallCalendarAPI.js.map +1 -0
  339. package/build/dist/Server/API/TelemetryAPI.js +31 -3
  340. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  341. package/build/dist/Server/EnvironmentConfig.js +185 -0
  342. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  343. package/build/dist/Server/Infrastructure/OnCallCalendarFeedCache.js +663 -0
  344. package/build/dist/Server/Infrastructure/OnCallCalendarFeedCache.js.map +1 -0
  345. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790400000000-AddOnCallCalendarFeeds.js +103 -0
  346. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790400000000-AddOnCallCalendarFeeds.js.map +1 -0
  347. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790500000000-AddNetworkDeviceOidTemplate.js +26 -0
  348. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790500000000-AddNetworkDeviceOidTemplate.js.map +1 -0
  349. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790600000000-AddAutoImportRuleOidTemplate.js +14 -0
  350. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790600000000-AddAutoImportRuleOidTemplate.js.map +1 -0
  351. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
  352. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  353. package/build/dist/Server/Middleware/MultipartFormData.js +93 -28
  354. package/build/dist/Server/Middleware/MultipartFormData.js.map +1 -1
  355. package/build/dist/Server/Middleware/OnCallCalendarFeedRateLimit.js +342 -0
  356. package/build/dist/Server/Middleware/OnCallCalendarFeedRateLimit.js.map +1 -0
  357. package/build/dist/Server/Services/AlertEpisodeLabelRuleEngineService.js +8 -1
  358. package/build/dist/Server/Services/AlertEpisodeLabelRuleEngineService.js.map +1 -1
  359. package/build/dist/Server/Services/AlertEpisodeOnCallRuleEngineService.js +8 -1
  360. package/build/dist/Server/Services/AlertEpisodeOnCallRuleEngineService.js.map +1 -1
  361. package/build/dist/Server/Services/AlertEpisodeOwnerRuleEngineService.js +8 -1
  362. package/build/dist/Server/Services/AlertEpisodeOwnerRuleEngineService.js.map +1 -1
  363. package/build/dist/Server/Services/AlertEpisodePrivacyRuleEngineService.js +8 -1
  364. package/build/dist/Server/Services/AlertEpisodePrivacyRuleEngineService.js.map +1 -1
  365. package/build/dist/Server/Services/AlertGroupingEngineService.js +8 -1
  366. package/build/dist/Server/Services/AlertGroupingEngineService.js.map +1 -1
  367. package/build/dist/Server/Services/AlertLabelRuleEngineService.js +8 -1
  368. package/build/dist/Server/Services/AlertLabelRuleEngineService.js.map +1 -1
  369. package/build/dist/Server/Services/AlertOnCallRuleEngineService.js +8 -1
  370. package/build/dist/Server/Services/AlertOnCallRuleEngineService.js.map +1 -1
  371. package/build/dist/Server/Services/AlertOwnerRuleEngineService.js +8 -1
  372. package/build/dist/Server/Services/AlertOwnerRuleEngineService.js.map +1 -1
  373. package/build/dist/Server/Services/AlertPrivacyRuleEngineService.js +8 -1
  374. package/build/dist/Server/Services/AlertPrivacyRuleEngineService.js.map +1 -1
  375. package/build/dist/Server/Services/AlertReminderRuleService.js +8 -1
  376. package/build/dist/Server/Services/AlertReminderRuleService.js.map +1 -1
  377. package/build/dist/Server/Services/AutoRemediationRuleEngineService.js +8 -1
  378. package/build/dist/Server/Services/AutoRemediationRuleEngineService.js.map +1 -1
  379. package/build/dist/Server/Services/CephClusterLabelRuleEngineService.js +8 -1
  380. package/build/dist/Server/Services/CephClusterLabelRuleEngineService.js.map +1 -1
  381. package/build/dist/Server/Services/CephClusterOwnerRuleEngineService.js +8 -1
  382. package/build/dist/Server/Services/CephClusterOwnerRuleEngineService.js.map +1 -1
  383. package/build/dist/Server/Services/CloudResourceLabelRuleEngineService.js +8 -1
  384. package/build/dist/Server/Services/CloudResourceLabelRuleEngineService.js.map +1 -1
  385. package/build/dist/Server/Services/CloudResourceOwnerRuleEngineService.js +8 -1
  386. package/build/dist/Server/Services/CloudResourceOwnerRuleEngineService.js.map +1 -1
  387. package/build/dist/Server/Services/DashboardLabelRuleEngineService.js +8 -1
  388. package/build/dist/Server/Services/DashboardLabelRuleEngineService.js.map +1 -1
  389. package/build/dist/Server/Services/DashboardOwnerRuleEngineService.js +8 -1
  390. package/build/dist/Server/Services/DashboardOwnerRuleEngineService.js.map +1 -1
  391. package/build/dist/Server/Services/DockerHostLabelRuleEngineService.js +8 -1
  392. package/build/dist/Server/Services/DockerHostLabelRuleEngineService.js.map +1 -1
  393. package/build/dist/Server/Services/DockerHostOwnerRuleEngineService.js +8 -1
  394. package/build/dist/Server/Services/DockerHostOwnerRuleEngineService.js.map +1 -1
  395. package/build/dist/Server/Services/DockerSwarmClusterLabelRuleEngineService.js +8 -1
  396. package/build/dist/Server/Services/DockerSwarmClusterLabelRuleEngineService.js.map +1 -1
  397. package/build/dist/Server/Services/DockerSwarmClusterOwnerRuleEngineService.js +8 -1
  398. package/build/dist/Server/Services/DockerSwarmClusterOwnerRuleEngineService.js.map +1 -1
  399. package/build/dist/Server/Services/HostLabelRuleEngineService.js +8 -1
  400. package/build/dist/Server/Services/HostLabelRuleEngineService.js.map +1 -1
  401. package/build/dist/Server/Services/HostOwnerRuleEngineService.js +8 -1
  402. package/build/dist/Server/Services/HostOwnerRuleEngineService.js.map +1 -1
  403. package/build/dist/Server/Services/IncidentEpisodeLabelRuleEngineService.js +8 -1
  404. package/build/dist/Server/Services/IncidentEpisodeLabelRuleEngineService.js.map +1 -1
  405. package/build/dist/Server/Services/IncidentEpisodeOnCallRuleEngineService.js +8 -1
  406. package/build/dist/Server/Services/IncidentEpisodeOnCallRuleEngineService.js.map +1 -1
  407. package/build/dist/Server/Services/IncidentEpisodeOwnerRuleEngineService.js +8 -1
  408. package/build/dist/Server/Services/IncidentEpisodeOwnerRuleEngineService.js.map +1 -1
  409. package/build/dist/Server/Services/IncidentEpisodePrivacyRuleEngineService.js +8 -1
  410. package/build/dist/Server/Services/IncidentEpisodePrivacyRuleEngineService.js.map +1 -1
  411. package/build/dist/Server/Services/IncidentGroupingEngineService.js +8 -1
  412. package/build/dist/Server/Services/IncidentGroupingEngineService.js.map +1 -1
  413. package/build/dist/Server/Services/IncidentLabelRuleEngineService.js +8 -1
  414. package/build/dist/Server/Services/IncidentLabelRuleEngineService.js.map +1 -1
  415. package/build/dist/Server/Services/IncidentOnCallRuleEngineService.js +8 -1
  416. package/build/dist/Server/Services/IncidentOnCallRuleEngineService.js.map +1 -1
  417. package/build/dist/Server/Services/IncidentOwnerRuleEngineService.js +8 -1
  418. package/build/dist/Server/Services/IncidentOwnerRuleEngineService.js.map +1 -1
  419. package/build/dist/Server/Services/IncidentPrivacyRuleEngineService.js +8 -1
  420. package/build/dist/Server/Services/IncidentPrivacyRuleEngineService.js.map +1 -1
  421. package/build/dist/Server/Services/IncidentReminderRuleService.js +8 -1
  422. package/build/dist/Server/Services/IncidentReminderRuleService.js.map +1 -1
  423. package/build/dist/Server/Services/IncidentSlaRuleService.js +8 -1
  424. package/build/dist/Server/Services/IncidentSlaRuleService.js.map +1 -1
  425. package/build/dist/Server/Services/IncomingCallPolicyLabelRuleEngineService.js +8 -1
  426. package/build/dist/Server/Services/IncomingCallPolicyLabelRuleEngineService.js.map +1 -1
  427. package/build/dist/Server/Services/IncomingCallPolicyOwnerRuleEngineService.js +8 -1
  428. package/build/dist/Server/Services/IncomingCallPolicyOwnerRuleEngineService.js.map +1 -1
  429. package/build/dist/Server/Services/Index.js +14 -0
  430. package/build/dist/Server/Services/Index.js.map +1 -1
  431. package/build/dist/Server/Services/IoTFleetLabelRuleEngineService.js +8 -1
  432. package/build/dist/Server/Services/IoTFleetLabelRuleEngineService.js.map +1 -1
  433. package/build/dist/Server/Services/IoTFleetOwnerRuleEngineService.js +8 -1
  434. package/build/dist/Server/Services/IoTFleetOwnerRuleEngineService.js.map +1 -1
  435. package/build/dist/Server/Services/KubernetesClusterLabelRuleEngineService.js +8 -1
  436. package/build/dist/Server/Services/KubernetesClusterLabelRuleEngineService.js.map +1 -1
  437. package/build/dist/Server/Services/KubernetesClusterOwnerRuleEngineService.js +8 -1
  438. package/build/dist/Server/Services/KubernetesClusterOwnerRuleEngineService.js.map +1 -1
  439. package/build/dist/Server/Services/KubernetesResourceService.js +5 -1
  440. package/build/dist/Server/Services/KubernetesResourceService.js.map +1 -1
  441. package/build/dist/Server/Services/MonitorLabelRuleEngineService.js +8 -1
  442. package/build/dist/Server/Services/MonitorLabelRuleEngineService.js.map +1 -1
  443. package/build/dist/Server/Services/MonitorOwnerRuleEngineService.js +8 -1
  444. package/build/dist/Server/Services/MonitorOwnerRuleEngineService.js.map +1 -1
  445. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +30 -21
  446. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -1
  447. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js +64 -0
  448. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js.map +1 -1
  449. package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js +8 -1
  450. package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js.map +1 -1
  451. package/build/dist/Server/Services/NetworkDeviceOidTemplateService.js +180 -0
  452. package/build/dist/Server/Services/NetworkDeviceOidTemplateService.js.map +1 -0
  453. package/build/dist/Server/Services/NetworkDeviceOwnerRuleEngineService.js +8 -1
  454. package/build/dist/Server/Services/NetworkDeviceOwnerRuleEngineService.js.map +1 -1
  455. package/build/dist/Server/Services/NetworkDeviceService.js +154 -1
  456. package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
  457. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +20 -0
  458. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
  459. package/build/dist/Server/Services/OnCallDutyPolicyLabelRuleEngineService.js +8 -1
  460. package/build/dist/Server/Services/OnCallDutyPolicyLabelRuleEngineService.js.map +1 -1
  461. package/build/dist/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.js +8 -1
  462. package/build/dist/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.js.map +1 -1
  463. package/build/dist/Server/Services/OnCallDutyPolicyScheduleCalendarFeedService.js +219 -0
  464. package/build/dist/Server/Services/OnCallDutyPolicyScheduleCalendarFeedService.js.map +1 -0
  465. package/build/dist/Server/Services/OnCallDutyPolicyScheduleLabelRuleEngineService.js +8 -1
  466. package/build/dist/Server/Services/OnCallDutyPolicyScheduleLabelRuleEngineService.js.map +1 -1
  467. package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerService.js +47 -3
  468. package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerService.js.map +1 -1
  469. package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerUserService.js +112 -3
  470. package/build/dist/Server/Services/OnCallDutyPolicyScheduleLayerUserService.js.map +1 -1
  471. package/build/dist/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.js +8 -1
  472. package/build/dist/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.js.map +1 -1
  473. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js +955 -9
  474. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js.map +1 -1
  475. package/build/dist/Server/Services/OnCallDutyPolicyUserOverrideService.js +93 -6
  476. package/build/dist/Server/Services/OnCallDutyPolicyUserOverrideService.js.map +1 -1
  477. package/build/dist/Server/Services/PodmanHostLabelRuleEngineService.js +8 -1
  478. package/build/dist/Server/Services/PodmanHostLabelRuleEngineService.js.map +1 -1
  479. package/build/dist/Server/Services/PodmanHostOwnerRuleEngineService.js +8 -1
  480. package/build/dist/Server/Services/PodmanHostOwnerRuleEngineService.js.map +1 -1
  481. package/build/dist/Server/Services/ProjectOnCallCalendarFeedService.js +157 -0
  482. package/build/dist/Server/Services/ProjectOnCallCalendarFeedService.js.map +1 -0
  483. package/build/dist/Server/Services/ProxmoxClusterLabelRuleEngineService.js +8 -1
  484. package/build/dist/Server/Services/ProxmoxClusterLabelRuleEngineService.js.map +1 -1
  485. package/build/dist/Server/Services/ProxmoxClusterOwnerRuleEngineService.js +8 -1
  486. package/build/dist/Server/Services/ProxmoxClusterOwnerRuleEngineService.js.map +1 -1
  487. package/build/dist/Server/Services/RumApplicationLabelRuleEngineService.js +8 -1
  488. package/build/dist/Server/Services/RumApplicationLabelRuleEngineService.js.map +1 -1
  489. package/build/dist/Server/Services/RumApplicationOwnerRuleEngineService.js +8 -1
  490. package/build/dist/Server/Services/RumApplicationOwnerRuleEngineService.js.map +1 -1
  491. package/build/dist/Server/Services/RunbookLabelRuleEngineService.js +8 -1
  492. package/build/dist/Server/Services/RunbookLabelRuleEngineService.js.map +1 -1
  493. package/build/dist/Server/Services/RunbookOwnerRuleEngineService.js +8 -1
  494. package/build/dist/Server/Services/RunbookOwnerRuleEngineService.js.map +1 -1
  495. package/build/dist/Server/Services/RunbookRuleEngineService.js +8 -1
  496. package/build/dist/Server/Services/RunbookRuleEngineService.js.map +1 -1
  497. package/build/dist/Server/Services/ScheduledMaintenanceLabelRuleEngineService.js +8 -1
  498. package/build/dist/Server/Services/ScheduledMaintenanceLabelRuleEngineService.js.map +1 -1
  499. package/build/dist/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.js +8 -1
  500. package/build/dist/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.js.map +1 -1
  501. package/build/dist/Server/Services/ScheduledMaintenanceReminderRuleService.js +8 -1
  502. package/build/dist/Server/Services/ScheduledMaintenanceReminderRuleService.js.map +1 -1
  503. package/build/dist/Server/Services/ServerlessFunctionLabelRuleEngineService.js +8 -1
  504. package/build/dist/Server/Services/ServerlessFunctionLabelRuleEngineService.js.map +1 -1
  505. package/build/dist/Server/Services/ServerlessFunctionOwnerRuleEngineService.js +8 -1
  506. package/build/dist/Server/Services/ServerlessFunctionOwnerRuleEngineService.js.map +1 -1
  507. package/build/dist/Server/Services/ServiceLabelRuleEngineService.js +8 -1
  508. package/build/dist/Server/Services/ServiceLabelRuleEngineService.js.map +1 -1
  509. package/build/dist/Server/Services/ServiceOwnerRuleEngineService.js +8 -1
  510. package/build/dist/Server/Services/ServiceOwnerRuleEngineService.js.map +1 -1
  511. package/build/dist/Server/Services/StatusPageLabelRuleEngineService.js +8 -1
  512. package/build/dist/Server/Services/StatusPageLabelRuleEngineService.js.map +1 -1
  513. package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js +6 -0
  514. package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js.map +1 -1
  515. package/build/dist/Server/Services/StatusPageOwnerRuleEngineService.js +8 -1
  516. package/build/dist/Server/Services/StatusPageOwnerRuleEngineService.js.map +1 -1
  517. package/build/dist/Server/Services/TeamMemberService.js +396 -1
  518. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  519. package/build/dist/Server/Services/TeamService.js +43 -0
  520. package/build/dist/Server/Services/TeamService.js.map +1 -1
  521. package/build/dist/Server/Services/TelemetrySourceMapService.js +213 -19
  522. package/build/dist/Server/Services/TelemetrySourceMapService.js.map +1 -1
  523. package/build/dist/Server/Services/UserNotificationSettingService.js +26 -1
  524. package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
  525. package/build/dist/Server/Services/UserOnCallCalendarFeedService.js +140 -0
  526. package/build/dist/Server/Services/UserOnCallCalendarFeedService.js.map +1 -0
  527. package/build/dist/Server/Services/UserOnCallShiftReminderLogService.js +116 -0
  528. package/build/dist/Server/Services/UserOnCallShiftReminderLogService.js.map +1 -0
  529. package/build/dist/Server/Services/UserOnCallShiftReminderService.js +92 -0
  530. package/build/dist/Server/Services/UserOnCallShiftReminderService.js.map +1 -0
  531. package/build/dist/Server/Services/UserService.js +25 -0
  532. package/build/dist/Server/Services/UserService.js.map +1 -1
  533. package/build/dist/Server/Services/WorkflowLabelRuleEngineService.js +8 -1
  534. package/build/dist/Server/Services/WorkflowLabelRuleEngineService.js.map +1 -1
  535. package/build/dist/Server/Services/WorkflowOwnerRuleEngineService.js +8 -1
  536. package/build/dist/Server/Services/WorkflowOwnerRuleEngineService.js.map +1 -1
  537. package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js +145 -0
  538. package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js.map +1 -0
  539. package/build/dist/Server/Utils/Monitor/CapturedMetricAttributeUtil.js +201 -0
  540. package/build/dist/Server/Utils/Monitor/CapturedMetricAttributeUtil.js.map +1 -0
  541. package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js +19 -2
  542. package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js.map +1 -1
  543. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +42 -23
  544. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
  545. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +29 -0
  546. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
  547. package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js +11 -2
  548. package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js.map +1 -1
  549. package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js +16 -1
  550. package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js.map +1 -1
  551. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +10 -0
  552. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
  553. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +33 -0
  554. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -1
  555. package/build/dist/Server/Utils/OnCall/CalendarFeedToken.js +161 -0
  556. package/build/dist/Server/Utils/OnCall/CalendarFeedToken.js.map +1 -0
  557. package/build/dist/Server/Utils/OnCall/OnCallCalendarFeedRenderer.js +983 -0
  558. package/build/dist/Server/Utils/OnCall/OnCallCalendarFeedRenderer.js.map +1 -0
  559. package/build/dist/Server/Utils/OnCall/OnCallCalendarFeedUrls.js +155 -0
  560. package/build/dist/Server/Utils/OnCall/OnCallCalendarFeedUrls.js.map +1 -0
  561. package/build/dist/Server/Utils/OnCall/OnCallShiftChangeListeners.js +145 -0
  562. package/build/dist/Server/Utils/OnCall/OnCallShiftChangeListeners.js.map +1 -0
  563. package/build/dist/Server/Utils/OnCall/OnCallShiftMaterializer.js +752 -0
  564. package/build/dist/Server/Utils/OnCall/OnCallShiftMaterializer.js.map +1 -0
  565. package/build/dist/Server/Utils/OnCall/OnCallShiftReminderListener.js +92 -0
  566. package/build/dist/Server/Utils/OnCall/OnCallShiftReminderListener.js.map +1 -0
  567. package/build/dist/Server/Utils/OnCall/OnCallShiftReminderRunner.js +1786 -0
  568. package/build/dist/Server/Utils/OnCall/OnCallShiftReminderRunner.js.map +1 -0
  569. package/build/dist/Server/Utils/Response.js +97 -0
  570. package/build/dist/Server/Utils/Response.js.map +1 -1
  571. package/build/dist/Server/Utils/Rules/RuleEngineRuleRead.js +37 -0
  572. package/build/dist/Server/Utils/Rules/RuleEngineRuleRead.js.map +1 -0
  573. package/build/dist/Server/Utils/StartServer.js +9 -1
  574. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  575. package/build/dist/Server/Utils/Telemetry/AppMetrics.js +41 -0
  576. package/build/dist/Server/Utils/Telemetry/AppMetrics.js.map +1 -1
  577. package/build/dist/Server/Utils/Telemetry/ExceptionSanitizer.js +12 -1
  578. package/build/dist/Server/Utils/Telemetry/ExceptionSanitizer.js.map +1 -1
  579. package/build/dist/Server/Utils/Telemetry/LogExceptionExtractor.js +14 -2
  580. package/build/dist/Server/Utils/Telemetry/LogExceptionExtractor.js.map +1 -1
  581. package/build/dist/Server/Utils/Telemetry/SourceMapResolver.js +15 -5
  582. package/build/dist/Server/Utils/Telemetry/SourceMapResolver.js.map +1 -1
  583. package/build/dist/Server/Utils/Telemetry/StackTraceParser.js +307 -0
  584. package/build/dist/Server/Utils/Telemetry/StackTraceParser.js.map +1 -1
  585. package/build/dist/Types/Calendar/ICalendar.js +290 -0
  586. package/build/dist/Types/Calendar/ICalendar.js.map +1 -0
  587. package/build/dist/Types/Date.js +27 -0
  588. package/build/dist/Types/Date.js.map +1 -1
  589. package/build/dist/Types/Email/EmailTemplateType.js +2 -0
  590. package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
  591. package/build/dist/Types/Monitor/SnmpMonitor/SnmpOidListUtil.js +253 -0
  592. package/build/dist/Types/Monitor/SnmpMonitor/SnmpOidListUtil.js.map +1 -0
  593. package/build/dist/Types/NotificationSetting/NotificationSettingEventType.js +3 -0
  594. package/build/dist/Types/NotificationSetting/NotificationSettingEventType.js.map +1 -1
  595. package/build/dist/Types/OnCallDutyPolicy/CalendarFeedWindow.js +97 -0
  596. package/build/dist/Types/OnCallDutyPolicy/CalendarFeedWindow.js.map +1 -0
  597. package/build/dist/Types/OnCallDutyPolicy/Layer.js +113 -19
  598. package/build/dist/Types/OnCallDutyPolicy/Layer.js.map +1 -1
  599. package/build/dist/Types/OnCallDutyPolicy/MaterializedShift.js +134 -0
  600. package/build/dist/Types/OnCallDutyPolicy/MaterializedShift.js.map +1 -0
  601. package/build/dist/Types/OnCallDutyPolicy/OnCallCalendarFeedUtil.js +800 -0
  602. package/build/dist/Types/OnCallDutyPolicy/OnCallCalendarFeedUtil.js.map +1 -0
  603. package/build/dist/Types/OnCallDutyPolicy/ScheduleShiftUtil.js +97 -3
  604. package/build/dist/Types/OnCallDutyPolicy/ScheduleShiftUtil.js.map +1 -1
  605. package/build/dist/Types/OnCallDutyPolicy/ShiftSeamUtil.js +77 -0
  606. package/build/dist/Types/OnCallDutyPolicy/ShiftSeamUtil.js.map +1 -0
  607. package/build/dist/Types/Permission.js +86 -0
  608. package/build/dist/Types/Permission.js.map +1 -1
  609. package/build/dist/Types/Rum/SessionReplay.js +19 -0
  610. package/build/dist/Types/Rum/SessionReplay.js.map +1 -1
  611. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationHoverCard.js +83 -0
  612. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationHoverCard.js.map +1 -0
  613. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationLayout.js +531 -0
  614. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationLayout.js.map +1 -0
  615. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/ChartAnnotationLayer.js +264 -0
  616. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/ChartAnnotationLayer.js.map +1 -0
  617. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/UseChartAnnotations.js +122 -0
  618. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/UseChartAnnotations.js.map +1 -0
  619. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js +213 -233
  620. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js.map +1 -1
  621. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js +139 -152
  622. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js.map +1 -1
  623. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js +212 -232
  624. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js.map +1 -1
  625. package/build/dist/UI/Components/Charts/Types/ChartEventKind.js +14 -0
  626. package/build/dist/UI/Components/Charts/Types/ChartEventKind.js.map +1 -0
  627. package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js +57 -28
  628. package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js.map +1 -1
  629. package/build/dist/UI/Components/Charts/Utils/XAxis.js +103 -17
  630. package/build/dist/UI/Components/Charts/Utils/XAxis.js.map +1 -1
  631. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +198 -23
  632. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  633. package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js +15 -5
  634. package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js.map +1 -1
  635. package/build/dist/UI/Components/Feed/FeedItem.js +4 -5
  636. package/build/dist/UI/Components/Feed/FeedItem.js.map +1 -1
  637. package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js +1 -2
  638. package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js.map +1 -1
  639. package/build/dist/UI/Components/Header/UserProfile/UserProfile.js.map +1 -1
  640. package/build/dist/UI/Components/Image/Image.js +6 -1
  641. package/build/dist/UI/Components/Image/Image.js.map +1 -1
  642. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js +0 -0
  643. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js.map +1 -1
  644. package/build/dist/UI/Components/MemberRoleAssignment/MemberRoleAssignment.js +1 -2
  645. package/build/dist/UI/Components/MemberRoleAssignment/MemberRoleAssignment.js.map +1 -1
  646. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +104 -23
  647. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  648. package/build/dist/UI/Components/Table/TableHeader.js +20 -22
  649. package/build/dist/UI/Components/Table/TableHeader.js.map +1 -1
  650. package/build/dist/UI/Components/Table/TableRow.js +13 -4
  651. package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
  652. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js +153 -0
  653. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js.map +1 -0
  654. package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js.map +1 -1
  655. package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js +127 -7
  656. package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js.map +1 -1
  657. package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js +50 -3
  658. package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js.map +1 -1
  659. package/build/dist/Utils/NetworkDiscovery/ReverseDnsNameUtil.js +132 -0
  660. package/build/dist/Utils/NetworkDiscovery/ReverseDnsNameUtil.js.map +1 -0
  661. package/build/dist/Utils/Rules/RuleEngineLimits.js +31 -0
  662. package/build/dist/Utils/Rules/RuleEngineLimits.js.map +1 -0
  663. package/jest.config.json +1 -0
  664. package/package.json +2 -2
@@ -0,0 +1,1371 @@
1
+ import { DisableOnCallCalendarFeed, Host, HttpProtocol, ProvisionSsl, TrustedProxyHops, } from "../EnvironmentConfig";
2
+ import OnCallCalendarFeedCache from "../Infrastructure/OnCallCalendarFeedCache";
3
+ import Semaphore from "../Infrastructure/Semaphore";
4
+ import OnCallCalendarFeedRateLimit from "../Middleware/OnCallCalendarFeedRateLimit";
5
+ import UserMiddleware from "../Middleware/UserAuthorization";
6
+ import OnCallDutyPolicyScheduleCalendarFeedService from "../Services/OnCallDutyPolicyScheduleCalendarFeedService";
7
+ import OnCallDutyPolicyScheduleService from "../Services/OnCallDutyPolicyScheduleService";
8
+ import ProjectOnCallCalendarFeedService from "../Services/ProjectOnCallCalendarFeedService";
9
+ import UserOnCallCalendarFeedService from "../Services/UserOnCallCalendarFeedService";
10
+ import Express from "../Utils/Express";
11
+ import logger from "../Utils/Logger";
12
+ import CalendarFeedToken from "../Utils/OnCall/CalendarFeedToken";
13
+ import OnCallCalendarFeedRenderer, { FEED_DISABLED_REASON, FeedRenderStatus, TOKEN_ROTATED_REASON, } from "../Utils/OnCall/OnCallCalendarFeedRenderer";
14
+ import OnCallCalendarFeedUrls from "../Utils/OnCall/OnCallCalendarFeedUrls";
15
+ import Response from "../Utils/Response";
16
+ import CommonAPI from "./CommonAPI";
17
+ import OnCallDutyPolicyScheduleCalendarFeed from "../../Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed";
18
+ import ProjectOnCallCalendarFeed from "../../Models/DatabaseModels/ProjectOnCallCalendarFeed";
19
+ import Protocol from "../../Types/API/Protocol";
20
+ import OneUptimeDate from "../../Types/Date";
21
+ import BadDataException from "../../Types/Exception/BadDataException";
22
+ import Exception from "../../Types/Exception/Exception";
23
+ import NotFoundException from "../../Types/Exception/NotFoundException";
24
+ import ServiceUnavailableException from "../../Types/Exception/ServiceUnavailableException";
25
+ import ObjectID from "../../Types/ObjectID";
26
+ import { DEFAULT_FUTURE_DAYS, DEFAULT_PAST_DAYS, MAX_FUTURE_DAYS, MAX_PAST_DAYS, } from "../../Types/OnCallDutyPolicy/CalendarFeedWindow";
27
+ import MaterializedShiftUtil from "../../Types/OnCallDutyPolicy/MaterializedShift";
28
+ import { OnCallCalendarFeedKind } from "../../Types/OnCallDutyPolicy/OnCallCalendarFeedUtil";
29
+ /*
30
+ * The HTTP face of the on-call calendar feeds.
31
+ *
32
+ * Two very different kinds of route share this router, and the difference is
33
+ * the whole design:
34
+ *
35
+ * PUBLIC CAPABILITY ROUTES (no UserMiddleware). A calendar client sends no
36
+ * cookie and no bearer token; the 43-character token in the path IS the
37
+ * credential. UserMiddleware is deliberately absent: with no cookie it would
38
+ * add nothing, but a browser holding an expired session cookie would be
39
+ * answered 401 before the token was even read, and an `apikey` header -- even
40
+ * an empty one -- would hijack the request into API-key authentication. The
41
+ * pipeline is, in order: kill switch -> scheme guard -> rate limit -> shape
42
+ * guard -> token lookup (current hash, then the rotated-out hash inside its
43
+ * grace) -> the renderer, which re-derives authorisation on every fetch
44
+ * (a valid token is not authorisation) -> response -> bookkeeping.
45
+ *
46
+ * ONE RESPONSE RULE, applied everywhere:
47
+ * unknown / malformed / expired token -> 404, generic body
48
+ * disabled, rotated-out-in-grace, below plan,
49
+ * no eligible schedule -> 200, EMPTY VCALENDAR
50
+ * kill switch, or render cap with nothing cached -> 503 + Retry-After
51
+ * The empty-calendar cases are 200 on purpose: a client that gets 404 keeps
52
+ * showing the last copy it downloaded (or drops the subscription with an
53
+ * error), whereas an empty calendar makes it clear its copy.
54
+ *
55
+ * SESSION ROUTES (UserMiddleware + requireUserAuthentication). The settings
56
+ * pages and the mobile app read and rotate feeds here. /current is the ONLY
57
+ * place the encrypted `token` column is ever read back; the public routes
58
+ * never select it, so a rotated ENCRYPTION_SECRET can break the settings page
59
+ * (which says "Regenerate link") but never the subscribed calendars.
60
+ *
61
+ * The token never reaches a log line, an error message, a span attribute or
62
+ * a cache key. Everything that identifies a request in logs is the feed kind
63
+ * and the row id.
64
+ */
65
+ const router = Express.getRouter();
66
+ // -- Routes (exported so tests and the dashboard pin the same strings) ------
67
+ export const PERSONAL_FEED_ROUTE = "/on-call-calendar/user/:token/shifts.ics";
68
+ export const SCHEDULE_FEED_ROUTE = "/on-call-calendar/schedule/:token/schedule.ics";
69
+ export const PROJECT_FEED_ROUTE = "/on-call-calendar/project/:token/project.ics";
70
+ /*
71
+ * Anything else under a token-bearing prefix: a link pasted without the
72
+ * trailing `shifts.ics`, a typo in the filename, a client or a scanner
73
+ * sending POST/PUT/DELETE to a feed URL. Without these the request falls
74
+ * through to the application's own catch-alls, which answer
75
+ * `Page not found - ${req.url}` -- the plaintext token, at ERROR level, in
76
+ * stdout, in the master-admin support bundle's recent-log buffer and in the
77
+ * OTel log exporter. The token is the credential; it must never be logged.
78
+ */
79
+ export const PERSONAL_FEED_FALLBACK_ROUTE = "/on-call-calendar/user/*";
80
+ export const SCHEDULE_FEED_FALLBACK_ROUTE = "/on-call-calendar/schedule/*";
81
+ export const PROJECT_FEED_FALLBACK_ROUTE = "/on-call-calendar/project/*";
82
+ export const FEED_CURRENT_ROUTE = "/on-call-calendar/feed/current";
83
+ export const FEED_ROTATE_ROUTE = "/on-call-calendar/feed/rotate";
84
+ export const SCHEDULE_FEED_CURRENT_ROUTE = "/on-call-calendar/schedule-feed/:scheduleId/current";
85
+ export const SCHEDULE_FEED_PUBLISH_ROUTE = "/on-call-calendar/schedule-feed/:scheduleId/publish";
86
+ export const SCHEDULE_FEED_ROTATE_ROUTE = "/on-call-calendar/schedule-feed/:scheduleId/rotate";
87
+ export const PROJECT_FEED_CURRENT_ROUTE = "/on-call-calendar/project-feed/current";
88
+ export const PROJECT_FEED_PUBLISH_ROUTE = "/on-call-calendar/project-feed/publish";
89
+ export const PROJECT_FEED_ROTATE_ROUTE = "/on-call-calendar/project-feed/rotate";
90
+ export const MY_SHIFTS_ROUTE = "/on-call-calendar/my-shifts";
91
+ // -- Constants --------------------------------------------------------------
92
+ export const KILL_SWITCH_RETRY_AFTER_SECONDS = 3600;
93
+ /* Bookkeeping is written at most this often per feed. */
94
+ export const BOOKKEEPING_INTERVAL_MS = 5 * 60 * 1000;
95
+ export const MY_SHIFTS_DEFAULT_DAYS = 30;
96
+ export const MY_SHIFTS_MAX_DAYS = 120;
97
+ export const ROTATE_LOCK_NAMESPACE = "OnCallCalendarFeed.rotate";
98
+ export const ROTATE_LOCK_TIMEOUT_MS = 10000;
99
+ const STALE_WARNING_HEADER = '110 - "Response is Stale"';
100
+ /* The body of every 404 on the public routes. Says nothing. */
101
+ const NOT_FOUND_MESSAGE = "Not found.";
102
+ /*
103
+ * 415. ExceptionCode has no member named for it; the numeric value is what
104
+ * res.status() needs and what the client sees.
105
+ */
106
+ class UnsupportedMediaTypeException extends Exception {
107
+ constructor(message) {
108
+ super(415, message);
109
+ }
110
+ }
111
+ /* 405, same reasoning as the 415 above. */
112
+ class MethodNotAllowedException extends Exception {
113
+ constructor(message) {
114
+ super(405, message);
115
+ }
116
+ }
117
+ // -- Public-route middleware ----------------------------------------------
118
+ /*
119
+ * Kill switch. Answered BEFORE the rate limiter so a switched-off install
120
+ * spends no Redis round trips per poll. 503 + Retry-After: clients keep the
121
+ * copy they have and come back later, which is the point of a switch that
122
+ * says "not now" rather than "never".
123
+ */
124
+ export function killSwitchMiddleware(req, res, next) {
125
+ if (DisableOnCallCalendarFeed) {
126
+ res.set("Retry-After", String(KILL_SWITCH_RETRY_AFTER_SECONDS));
127
+ return Response.sendErrorResponse(req, res, new ServiceUnavailableException("On-call calendar feeds are disabled on this OneUptime instance."));
128
+ }
129
+ return next();
130
+ }
131
+ /*
132
+ * The X-Forwarded-Proto entry written by OUR proxy, read the way ClientIp
133
+ * reads X-Forwarded-For: counting in from the right by TRUSTED_PROXY_HOPS,
134
+ * never the leftmost (caller-supplied) entry. With no trusted proxies there
135
+ * is no trustworthy header at all, and undefined is returned.
136
+ */
137
+ export function resolveTrustedForwardedProto(req, options) {
138
+ var _a;
139
+ const configuredHops = (options === null || options === void 0 ? void 0 : options.trustedProxyHops) === undefined
140
+ ? TrustedProxyHops
141
+ : options.trustedProxyHops;
142
+ const hops = Number.isFinite(configuredHops) && configuredHops > 0
143
+ ? Math.floor(configuredHops)
144
+ : 0;
145
+ if (hops === 0) {
146
+ return undefined;
147
+ }
148
+ const header = (_a = req.headers) === null || _a === void 0 ? void 0 : _a["x-forwarded-proto"];
149
+ if (header === undefined || header === null) {
150
+ return undefined;
151
+ }
152
+ const raw = Array.isArray(header) ? header.join(",") : header;
153
+ if (!raw.trim()) {
154
+ return undefined;
155
+ }
156
+ const entries = raw.split(",");
157
+ if (entries.length < hops) {
158
+ return undefined;
159
+ }
160
+ const entry = entries[entries.length - hops];
161
+ return entry ? entry.trim().toLowerCase() : undefined;
162
+ }
163
+ /*
164
+ * Scheme guard. An https instance whose proxy reports the request arrived
165
+ * over plain http answers 301 to the https URL, so a link pasted without the
166
+ * "s" is corrected once instead of served in the clear forever. The target
167
+ * is built from HOST, never from the request's own Host header (an open
168
+ * redirect otherwise). Nginx only does this itself when billing is on.
169
+ *
170
+ * It only fires when OUR nginx terminates TLS (PROVISION_SSL=true). Every
171
+ * proxying location in Nginx/default.conf.template sets
172
+ * `X-Forwarded-Proto $scheme`, REPLACING whatever an outer proxy sent, so on
173
+ * an install that terminates TLS on an external reverse proxy
174
+ * (PROVISION_SSL=false with HTTP_PROTOCOL=https -- the topology
175
+ * config.example.env documents) nginx always reports `http` even though the
176
+ * client spoke https. Redirecting there would 301 to the very URL the client
177
+ * just asked for: an endless loop, ERR_TOO_MANY_REDIRECTS in a browser and a
178
+ * dead subscription in every calendar client. Serving the feed is the right
179
+ * answer; the settings page still shows `protocolWarning` when the install
180
+ * really is plain http.
181
+ */
182
+ export function schemeGuardMiddleware(req, res, next) {
183
+ if (HttpProtocol !== Protocol.HTTPS) {
184
+ return next();
185
+ }
186
+ if (!ProvisionSsl) {
187
+ return next();
188
+ }
189
+ const forwardedProto = resolveTrustedForwardedProto(req);
190
+ if (forwardedProto !== "http") {
191
+ return next();
192
+ }
193
+ const host = OnCallCalendarFeedUrls.normalizeHost(Host);
194
+ if (!host) {
195
+ return next();
196
+ }
197
+ const originalUrl = req.originalUrl || req.url || "/";
198
+ res.set("Cache-Control", "no-store");
199
+ res.redirect(301, `${Protocol.HTTPS}${host}${originalUrl}`);
200
+ }
201
+ // -- Helpers ----------------------------------------------------------------
202
+ function sendNotFound(req, res) {
203
+ return Response.sendErrorResponse(req, res, new NotFoundException(NOT_FOUND_MESSAGE));
204
+ }
205
+ function sendUnavailable(req, res, retryAfterSeconds) {
206
+ res.set("Retry-After", String(retryAfterSeconds));
207
+ return Response.sendErrorResponse(req, res, new ServiceUnavailableException("The calendar feed cannot be rendered right now. Please try again later."));
208
+ }
209
+ /*
210
+ * The answer to every near miss on a token-bearing path. It says nothing
211
+ * about the URL it was asked for: the message is a constant, so neither the
212
+ * response body nor the error log line sendErrorResponse writes can carry
213
+ * the token. OPTIONS is answered the way OPTIONS should be; any other wrong
214
+ * method gets 405 + Allow (a client can fix that); a wrong or missing
215
+ * filename gets the same generic 404 an unknown token gets.
216
+ */
217
+ export const FEED_ALLOWED_METHODS = "GET, HEAD, OPTIONS";
218
+ export function feedFallbackHandler(req, res) {
219
+ const method = (req.method || "GET").toUpperCase();
220
+ if (method === "OPTIONS") {
221
+ res.set("Allow", FEED_ALLOWED_METHODS);
222
+ return Response.sendEmptySuccessResponse(req, res);
223
+ }
224
+ if (method !== "GET" && method !== "HEAD") {
225
+ res.set("Allow", FEED_ALLOWED_METHODS);
226
+ return Response.sendErrorResponse(req, res, new MethodNotAllowedException("Calendar feeds are read with GET on the full feed URL."));
227
+ }
228
+ return sendNotFound(req, res);
229
+ }
230
+ /*
231
+ * The `?schedule=` filter of the personal feed. Absent -> no filter. Present
232
+ * but not a UUID -> null, which the route answers 404: a URL the user
233
+ * believed was filtered must never quietly render the whole feed.
234
+ */
235
+ export function readScheduleFilter(req) {
236
+ var _a, _b;
237
+ const raw = (_a = req.query) === null || _a === void 0 ? void 0 : _a["schedule"];
238
+ if (raw === undefined || raw === null) {
239
+ return undefined;
240
+ }
241
+ const value = Array.isArray(raw) ? String((_b = raw[0]) !== null && _b !== void 0 ? _b : "") : String(raw);
242
+ const trimmed = value.trim();
243
+ if (!trimmed) {
244
+ return undefined;
245
+ }
246
+ if (!ObjectID.isValidUUID(trimmed)) {
247
+ return null;
248
+ }
249
+ return new ObjectID(trimmed);
250
+ }
251
+ /*
252
+ * Coarse client family only, from the User-Agent. The raw string is never
253
+ * stored: it is high-cardinality, occasionally carries device identifiers,
254
+ * and the settings page only wants to say "Google Calendar, 12 minutes ago".
255
+ */
256
+ export function classifyCalendarClient(userAgent) {
257
+ const raw = (Array.isArray(userAgent) ? userAgent.join(" ") : userAgent || "").trim();
258
+ if (!raw) {
259
+ return null;
260
+ }
261
+ const value = raw.toLowerCase();
262
+ if (value.includes("google-calendar") || value.includes("googlecalendar")) {
263
+ return "Google Calendar";
264
+ }
265
+ if (value.includes("outlook") ||
266
+ value.includes("microsoft office") ||
267
+ value.includes("exchange") ||
268
+ value.includes("microsoft-cryptoapi")) {
269
+ return "Microsoft Outlook";
270
+ }
271
+ if (value.includes("calendaragent") ||
272
+ value.includes("dataaccessd") ||
273
+ value.includes("ios/") ||
274
+ value.includes("macos/") ||
275
+ value.includes("darwin") ||
276
+ value.includes("ical")) {
277
+ return "Apple Calendar";
278
+ }
279
+ if (value.includes("thunderbird") || value.includes("lightning")) {
280
+ return "Thunderbird";
281
+ }
282
+ if (value.includes("okhttp") || value.includes("android")) {
283
+ return "Android app";
284
+ }
285
+ if (value.includes("mozilla") ||
286
+ value.includes("chrome") ||
287
+ value.includes("safari") ||
288
+ value.includes("firefox") ||
289
+ value.includes("edge")) {
290
+ return "Browser";
291
+ }
292
+ if (value.includes("curl") || value.includes("wget")) {
293
+ return "Command line";
294
+ }
295
+ return "Other";
296
+ }
297
+ function toDate(value) {
298
+ if (value instanceof Date) {
299
+ return Number.isNaN(value.getTime()) ? null : value;
300
+ }
301
+ if (typeof value === "string" && value) {
302
+ const parsed = OneUptimeDate.fromString(value);
303
+ return Number.isNaN(parsed.getTime()) ? null : parsed;
304
+ }
305
+ return null;
306
+ }
307
+ function toIso(value) {
308
+ const date = toDate(value);
309
+ return date ? date.toISOString() : null;
310
+ }
311
+ /*
312
+ * Is a previousTokenHash match still honoured? Only while
313
+ * previousTokenExpiresAt lies in the future; a rotated-out hash past its
314
+ * grace is indistinguishable from an unknown one (404).
315
+ */
316
+ export function isPreviousTokenInGrace(feed, now) {
317
+ const expiresAt = toDate(feed.previousTokenExpiresAt);
318
+ if (!expiresAt) {
319
+ return false;
320
+ }
321
+ return expiresAt.getTime() > now.getTime();
322
+ }
323
+ /*
324
+ * Bookkeeping is only worth a write once in a while, and only for a real
325
+ * fetch: a HEAD is a client checking whether anything changed, not a read.
326
+ */
327
+ export function shouldRecordFetch(data) {
328
+ if ((data.method || "GET").toUpperCase() !== "GET") {
329
+ return false;
330
+ }
331
+ const last = toDate(data.lastFetchedAt);
332
+ if (!last) {
333
+ return true;
334
+ }
335
+ return data.now.getTime() - last.getTime() >= BOOKKEEPING_INTERVAL_MS;
336
+ }
337
+ function readObjectIdParam(req, name) {
338
+ var _a;
339
+ const raw = (_a = req.params) === null || _a === void 0 ? void 0 : _a[name];
340
+ if (typeof raw !== "string" || !ObjectID.isValidUUID(raw.trim())) {
341
+ throw new BadDataException(`${name} must be a valid id.`);
342
+ }
343
+ return new ObjectID(raw.trim());
344
+ }
345
+ /*
346
+ * POST bodies on the session routes must be application/json, else 415. The
347
+ * routes carry no payload, so this is not about parsing: a JSON content type
348
+ * cannot be produced by a cross-site form post, which is what keeps a
349
+ * "rotate my link" request from being triggered by a page the user did not
350
+ * mean to visit.
351
+ */
352
+ export function assertJsonRequest(req) {
353
+ var _a;
354
+ const contentType = (_a = req.headers) === null || _a === void 0 ? void 0 : _a["content-type"];
355
+ const value = (Array.isArray(contentType) ? contentType[0] || "" : contentType || "")
356
+ .trim()
357
+ .toLowerCase();
358
+ if (!value.startsWith("application/json")) {
359
+ throw new UnsupportedMediaTypeException("This endpoint expects a JSON request (Content-Type: application/json).");
360
+ }
361
+ }
362
+ /*
363
+ * Parse ?from / ?to for /my-shifts. Defaults now -> +30 d; the span is
364
+ * capped at 120 d by moving `to` in, never by refusing the request.
365
+ *
366
+ * The window is then clamped into the same range the feeds themselves can
367
+ * address -- [now - MAX_PAST_DAYS, now + MAX_FUTURE_DAYS]. Without that,
368
+ * `?from=2500-01-01` was accepted: every distinct day-aligned window is a
369
+ * fresh schedule-cache entry AND a fresh LayerUtil expansion that walks one
370
+ * rotation period at a time from the layer's start to the window, which for a
371
+ * far-future start means the full 200,000-iteration cap per restricted layer
372
+ * -- seconds of synchronous CPU per request, holding one of the four
373
+ * per-process render slots the public feeds share. Clamping keeps a session
374
+ * request no more expensive than a feed poll and keeps it on the same cache
375
+ * keys.
376
+ */
377
+ export function readMyShiftsWindow(req, now) {
378
+ var _a, _b;
379
+ const rawFrom = (_a = req.query) === null || _a === void 0 ? void 0 : _a["from"];
380
+ const rawTo = (_b = req.query) === null || _b === void 0 ? void 0 : _b["to"];
381
+ let from = now;
382
+ if (typeof rawFrom === "string" && rawFrom.trim()) {
383
+ if (!OneUptimeDate.isValidDateString(rawFrom.trim())) {
384
+ throw new BadDataException("from must be an ISO 8601 date.");
385
+ }
386
+ from = OneUptimeDate.fromString(rawFrom.trim());
387
+ }
388
+ let to = OneUptimeDate.addRemoveDays(from, MY_SHIFTS_DEFAULT_DAYS);
389
+ if (typeof rawTo === "string" && rawTo.trim()) {
390
+ if (!OneUptimeDate.isValidDateString(rawTo.trim())) {
391
+ throw new BadDataException("to must be an ISO 8601 date.");
392
+ }
393
+ to = OneUptimeDate.fromString(rawTo.trim());
394
+ }
395
+ if (Number.isNaN(from.getTime()) || Number.isNaN(to.getTime())) {
396
+ throw new BadDataException("from and to must be ISO 8601 dates.");
397
+ }
398
+ if (to.getTime() <= from.getTime()) {
399
+ throw new BadDataException("to must be after from.");
400
+ }
401
+ /*
402
+ * The addressable range. It is 240 days wide, so it always leaves room for
403
+ * a non-empty window whatever the caller asked for.
404
+ */
405
+ const earliestFrom = OneUptimeDate.addRemoveDays(now, -MAX_PAST_DAYS);
406
+ const latestTo = OneUptimeDate.addRemoveDays(now, MAX_FUTURE_DAYS);
407
+ const latestFrom = OneUptimeDate.addRemoveDays(latestTo, -1);
408
+ if (from.getTime() < earliestFrom.getTime()) {
409
+ from = earliestFrom;
410
+ }
411
+ if (from.getTime() > latestFrom.getTime()) {
412
+ from = latestFrom;
413
+ }
414
+ /*
415
+ * `to` was validated against the RAW `from`; once `from` has moved, a `to`
416
+ * that now lies at or before it is answered with the default span rather
417
+ * than an empty window.
418
+ */
419
+ if (to.getTime() <= from.getTime()) {
420
+ to = OneUptimeDate.addRemoveDays(from, MY_SHIFTS_DEFAULT_DAYS);
421
+ }
422
+ const spanCap = OneUptimeDate.addRemoveDays(from, MY_SHIFTS_MAX_DAYS);
423
+ if (to.getTime() > spanCap.getTime()) {
424
+ to = spanCap;
425
+ }
426
+ if (to.getTime() > latestTo.getTime()) {
427
+ to = latestTo;
428
+ }
429
+ return { from, to };
430
+ }
431
+ // -- FeedStatus -------------------------------------------------------------
432
+ function defaultSettings(kind) {
433
+ if (kind === OnCallCalendarFeedKind.Personal) {
434
+ return {
435
+ includeCoveringShifts: true,
436
+ pastDays: DEFAULT_PAST_DAYS,
437
+ futureDays: DEFAULT_FUTURE_DAYS,
438
+ };
439
+ }
440
+ return {
441
+ includeCoverageGaps: false,
442
+ minimumGapMinutes: 60,
443
+ pastDays: DEFAULT_PAST_DAYS,
444
+ futureDays: DEFAULT_FUTURE_DAYS,
445
+ rotateWhenMemberLeaves: false,
446
+ };
447
+ }
448
+ /*
449
+ * FeedStatus for a feed that does not exist (yet).
450
+ */
451
+ export function buildAbsentFeedStatus(kind) {
452
+ return {
453
+ exists: false,
454
+ feedId: null,
455
+ isEnabled: false,
456
+ needsRegeneration: false,
457
+ tokenHint: null,
458
+ rotatedAt: null,
459
+ previousTokenExpiresAt: null,
460
+ lastFetchedAt: null,
461
+ lastFetchedClient: null,
462
+ fetchCount: 0,
463
+ lastRenderTruncated: false,
464
+ settings: defaultSettings(kind),
465
+ urls: null,
466
+ hostWarning: OnCallCalendarFeedUrls.getHostWarning(),
467
+ protocolWarning: OnCallCalendarFeedUrls.getProtocolWarning(),
468
+ };
469
+ }
470
+ /*
471
+ * FeedStatus for an existing row. `plaintextToken` is the token just minted
472
+ * by a rotate/publish (known without a decrypt); otherwise `decryptedToken`
473
+ * is what the root read handed back, verified against the stored hash. A
474
+ * token that fails to decrypt or does not hash to tokenHash means the
475
+ * ENCRYPTION_SECRET changed under the row: the URL cannot be shown and the
476
+ * UI offers "Regenerate link".
477
+ *
478
+ * The hash the decrypted token is checked against is `verifiedTokenHash` --
479
+ * the one readTokenForStatus read alongside the token -- falling back to the
480
+ * row's own `tokenHash`. The status rows the routes read do NOT carry
481
+ * tokenHash (STATUS_SELECT cannot select it: the column's read access list is
482
+ * empty, so the non-root schedule/project reads would be refused), and
483
+ * requiring it here is what made every /current and /publish answer
484
+ * `needsRegeneration: true, urls: null` for a perfectly good feed.
485
+ */
486
+ export function buildFeedStatus(data) {
487
+ var _a, _b, _c, _d, _e;
488
+ const feed = data.feed;
489
+ const expectedTokenHash = feed.tokenHash || data.verifiedTokenHash;
490
+ let token = null;
491
+ let needsRegeneration = false;
492
+ if (data.plaintextToken &&
493
+ CalendarFeedToken.isValidShape(data.plaintextToken)) {
494
+ token = data.plaintextToken;
495
+ }
496
+ else if (data.decryptFailed) {
497
+ needsRegeneration = true;
498
+ }
499
+ else if (data.decryptedToken &&
500
+ CalendarFeedToken.isValidShape(data.decryptedToken) &&
501
+ expectedTokenHash &&
502
+ CalendarFeedToken.isHashEqual(CalendarFeedToken.hash(data.decryptedToken), expectedTokenHash)) {
503
+ token = data.decryptedToken;
504
+ }
505
+ else {
506
+ needsRegeneration = true;
507
+ }
508
+ const settings = data.kind === OnCallCalendarFeedKind.Personal
509
+ ? {
510
+ includeCoveringShifts: feed.includeCoveringShifts !== false,
511
+ pastDays: (_a = feed.pastDays) !== null && _a !== void 0 ? _a : DEFAULT_PAST_DAYS,
512
+ futureDays: (_b = feed.futureDays) !== null && _b !== void 0 ? _b : DEFAULT_FUTURE_DAYS,
513
+ }
514
+ : {
515
+ includeCoverageGaps: feed.includeCoverageGaps === true,
516
+ minimumGapMinutes: (_c = feed.minimumGapMinutes) !== null && _c !== void 0 ? _c : 60,
517
+ pastDays: (_d = feed.pastDays) !== null && _d !== void 0 ? _d : DEFAULT_PAST_DAYS,
518
+ futureDays: (_e = feed.futureDays) !== null && _e !== void 0 ? _e : DEFAULT_FUTURE_DAYS,
519
+ rotateWhenMemberLeaves: feed.rotateWhenMemberLeaves === true,
520
+ };
521
+ const feedId = feed.id
522
+ ? feed.id.toString()
523
+ : feed._id
524
+ ? feed._id.toString()
525
+ : null;
526
+ return {
527
+ exists: true,
528
+ feedId,
529
+ isEnabled: feed.isEnabled !== false,
530
+ needsRegeneration,
531
+ tokenHint: feed.tokenHint || null,
532
+ rotatedAt: toIso(feed.rotatedAt),
533
+ previousTokenExpiresAt: toIso(feed.previousTokenExpiresAt),
534
+ lastFetchedAt: toIso(feed.lastFetchedAt),
535
+ lastFetchedClient: feed.lastFetchedClient || null,
536
+ fetchCount: typeof feed.fetchCount === "number" ? feed.fetchCount : 0,
537
+ lastRenderTruncated: feed.lastRenderTruncated === true,
538
+ settings,
539
+ urls: token
540
+ ? OnCallCalendarFeedUrls.buildFeedUrls({ kind: data.kind, token })
541
+ : null,
542
+ hostWarning: OnCallCalendarFeedUrls.getHostWarning(),
543
+ protocolWarning: OnCallCalendarFeedUrls.getProtocolWarning(),
544
+ };
545
+ }
546
+ /*
547
+ * The one decrypting read. Selecting `token` makes DatabaseService run
548
+ * Encryption.decrypt on the way out; with the wrong secret that either
549
+ * throws or yields bytes that do not hash to tokenHash. Both become
550
+ * needsRegeneration, never a 500.
551
+ */
552
+ async function readTokenForStatus(data) {
553
+ try {
554
+ let row = null;
555
+ if (data.kind === OnCallCalendarFeedKind.Personal) {
556
+ row = await UserOnCallCalendarFeedService.findOneById({
557
+ id: data.id,
558
+ select: { _id: true, token: true, tokenHash: true },
559
+ props: { isRoot: true, ignoreHooks: true },
560
+ });
561
+ }
562
+ else if (data.kind === OnCallCalendarFeedKind.Schedule) {
563
+ row = await OnCallDutyPolicyScheduleCalendarFeedService.findOneById({
564
+ id: data.id,
565
+ select: { _id: true, token: true, tokenHash: true },
566
+ props: { isRoot: true, ignoreHooks: true },
567
+ });
568
+ }
569
+ else {
570
+ row = await ProjectOnCallCalendarFeedService.findOneById({
571
+ id: data.id,
572
+ select: { _id: true, token: true, tokenHash: true },
573
+ props: { isRoot: true, ignoreHooks: true },
574
+ });
575
+ }
576
+ if (!row || !row.token) {
577
+ return { decryptFailed: true };
578
+ }
579
+ if (!row.tokenHash ||
580
+ !CalendarFeedToken.isValidShape(row.token) ||
581
+ !CalendarFeedToken.isHashEqual(CalendarFeedToken.hash(row.token), row.tokenHash)) {
582
+ return { decryptFailed: true };
583
+ }
584
+ return {
585
+ decryptedToken: row.token,
586
+ verifiedTokenHash: row.tokenHash,
587
+ decryptFailed: false,
588
+ };
589
+ }
590
+ catch (err) {
591
+ logger.warn(`OnCallCalendarAPI: could not decrypt the ${data.kind} calendar feed token for feed ${data.id.toString()}; the link needs regenerating.`);
592
+ logger.warn(err);
593
+ return { decryptFailed: true };
594
+ }
595
+ }
596
+ async function buildStatusForRow(data) {
597
+ if (data.plaintextToken) {
598
+ return buildFeedStatus({
599
+ kind: data.kind,
600
+ feed: data.feed,
601
+ plaintextToken: data.plaintextToken,
602
+ });
603
+ }
604
+ if (!data.feed.id) {
605
+ return buildFeedStatus({
606
+ kind: data.kind,
607
+ feed: data.feed,
608
+ decryptFailed: true,
609
+ });
610
+ }
611
+ const decrypted = await readTokenForStatus({ kind: data.kind, id: data.feed.id });
612
+ return buildFeedStatus({
613
+ kind: data.kind,
614
+ feed: data.feed,
615
+ decryptedToken: decrypted.decryptedToken,
616
+ verifiedTokenHash: decrypted.verifiedTokenHash,
617
+ decryptFailed: decrypted.decryptFailed,
618
+ });
619
+ }
620
+ /* The non-secret columns a status read selects (any of the three models). */
621
+ const STATUS_SELECT = {
622
+ _id: true,
623
+ projectId: true,
624
+ isEnabled: true,
625
+ tokenHint: true,
626
+ rotatedAt: true,
627
+ previousTokenExpiresAt: true,
628
+ lastFetchedAt: true,
629
+ lastFetchedClient: true,
630
+ fetchCount: true,
631
+ lastRenderTruncated: true,
632
+ pastDays: true,
633
+ futureDays: true,
634
+ };
635
+ // -- Public feed lookup -----------------------------------------------------
636
+ /*
637
+ * The columns the PUBLIC path reads. `token` is never among them: the public
638
+ * routes must keep working after an ENCRYPTION_SECRET rotation, and a select
639
+ * that included the encrypted column would make DatabaseService decrypt it on
640
+ * every poll. Tests pin this.
641
+ */
642
+ const PUBLIC_COMMON_SELECT = {
643
+ _id: true,
644
+ projectId: true,
645
+ isEnabled: true,
646
+ pastDays: true,
647
+ futureDays: true,
648
+ lastFetchedAt: true,
649
+ fetchCount: true,
650
+ previousTokenExpiresAt: true,
651
+ };
652
+ async function lookupPersonalFeed(tokenHash, now) {
653
+ const select = Object.assign(Object.assign({}, PUBLIC_COMMON_SELECT), { userId: true, includeCoveringShifts: true });
654
+ const current = await UserOnCallCalendarFeedService.findOneBy({
655
+ query: { tokenHash },
656
+ select,
657
+ props: { isRoot: true, ignoreHooks: true },
658
+ });
659
+ if (current) {
660
+ return { feed: current, viaPreviousToken: false };
661
+ }
662
+ const previous = await UserOnCallCalendarFeedService.findOneBy({
663
+ query: { previousTokenHash: tokenHash },
664
+ select,
665
+ props: { isRoot: true, ignoreHooks: true },
666
+ });
667
+ if (!previous || !isPreviousTokenInGrace(previous, now)) {
668
+ return null;
669
+ }
670
+ return { feed: previous, viaPreviousToken: true };
671
+ }
672
+ async function lookupScheduleFeed(tokenHash, now) {
673
+ const select = Object.assign(Object.assign({}, PUBLIC_COMMON_SELECT), { onCallDutyPolicyScheduleId: true, includeCoverageGaps: true, minimumGapMinutes: true });
674
+ const current = await OnCallDutyPolicyScheduleCalendarFeedService.findOneBy({
675
+ query: { tokenHash },
676
+ select,
677
+ props: { isRoot: true, ignoreHooks: true },
678
+ });
679
+ if (current) {
680
+ return { feed: current, viaPreviousToken: false };
681
+ }
682
+ const previous = await OnCallDutyPolicyScheduleCalendarFeedService.findOneBy({
683
+ query: { previousTokenHash: tokenHash },
684
+ select,
685
+ props: { isRoot: true, ignoreHooks: true },
686
+ });
687
+ if (!previous || !isPreviousTokenInGrace(previous, now)) {
688
+ return null;
689
+ }
690
+ return { feed: previous, viaPreviousToken: true };
691
+ }
692
+ async function lookupProjectFeed(tokenHash, now) {
693
+ const select = Object.assign(Object.assign({}, PUBLIC_COMMON_SELECT), { includeCoverageGaps: true, minimumGapMinutes: true });
694
+ const current = await ProjectOnCallCalendarFeedService.findOneBy({
695
+ query: { tokenHash },
696
+ select,
697
+ props: { isRoot: true, ignoreHooks: true },
698
+ });
699
+ if (current) {
700
+ return { feed: current, viaPreviousToken: false };
701
+ }
702
+ const previous = await ProjectOnCallCalendarFeedService.findOneBy({
703
+ query: { previousTokenHash: tokenHash },
704
+ select,
705
+ props: { isRoot: true, ignoreHooks: true },
706
+ });
707
+ if (!previous || !isPreviousTokenInGrace(previous, now)) {
708
+ return null;
709
+ }
710
+ return { feed: previous, viaPreviousToken: true };
711
+ }
712
+ // -- Bookkeeping ------------------------------------------------------------
713
+ /*
714
+ * Fire-and-forget root update after a served GET: when it was fetched, by
715
+ * what kind of client, how many times (read-modify-write of the value the
716
+ * lookup already read, so approximate under concurrency and deliberately
717
+ * so), and whether the last render was cut. Never awaited by the route, never
718
+ * allowed to throw into it.
719
+ */
720
+ function recordFetch(data) {
721
+ var _a;
722
+ if (!data.feed.id) {
723
+ return;
724
+ }
725
+ if (!shouldRecordFetch({
726
+ method: data.req.method,
727
+ lastFetchedAt: data.feed.lastFetchedAt,
728
+ now: data.now,
729
+ })) {
730
+ return;
731
+ }
732
+ const client = classifyCalendarClient((_a = data.req.headers) === null || _a === void 0 ? void 0 : _a["user-agent"]);
733
+ const previousCount = typeof data.feed.fetchCount === "number" &&
734
+ Number.isFinite(data.feed.fetchCount)
735
+ ? data.feed.fetchCount
736
+ : Number(data.feed.fetchCount) || 0;
737
+ const update = {
738
+ lastFetchedAt: data.now,
739
+ lastFetchedClient: client || "Other",
740
+ fetchCount: previousCount + 1,
741
+ lastRenderTruncated: data.truncated,
742
+ };
743
+ const id = data.feed.id;
744
+ let write;
745
+ if (data.kind === OnCallCalendarFeedKind.Personal) {
746
+ write = UserOnCallCalendarFeedService.updateOneById({
747
+ id,
748
+ data: update,
749
+ props: { isRoot: true, ignoreHooks: true },
750
+ });
751
+ }
752
+ else if (data.kind === OnCallCalendarFeedKind.Schedule) {
753
+ write = OnCallDutyPolicyScheduleCalendarFeedService.updateOneById({
754
+ id,
755
+ data: update,
756
+ props: { isRoot: true, ignoreHooks: true },
757
+ });
758
+ }
759
+ else {
760
+ write = ProjectOnCallCalendarFeedService.updateOneById({
761
+ id,
762
+ data: update,
763
+ props: { isRoot: true, ignoreHooks: true },
764
+ });
765
+ }
766
+ write.catch((err) => {
767
+ logger.warn(`OnCallCalendarAPI: bookkeeping for the ${data.kind} calendar feed ${id.toString()} failed.`);
768
+ logger.warn(err);
769
+ });
770
+ }
771
+ // -- Public routes ----------------------------------------------------------
772
+ /*
773
+ * The shared tail of the three public routes, from "we have a lookup result"
774
+ * to "bytes went out". Everything kind-specific is in the render request.
775
+ */
776
+ async function serveFeed(data) {
777
+ let outcome;
778
+ if (data.lookup.viaPreviousToken) {
779
+ outcome = OnCallCalendarFeedRenderer.buildEmptyOutcome({
780
+ kind: data.kind,
781
+ reason: TOKEN_ROTATED_REASON,
782
+ now: data.now,
783
+ });
784
+ }
785
+ else if (data.lookup.feed.isEnabled === false) {
786
+ outcome = OnCallCalendarFeedRenderer.buildEmptyOutcome({
787
+ kind: data.kind,
788
+ reason: FEED_DISABLED_REASON,
789
+ now: data.now,
790
+ });
791
+ }
792
+ else {
793
+ outcome = await OnCallCalendarFeedRenderer.render(data.request);
794
+ }
795
+ if (outcome.status === FeedRenderStatus.Unavailable) {
796
+ return sendUnavailable(data.req, data.res, outcome.retryAfterSeconds || KILL_SWITCH_RETRY_AFTER_SECONDS);
797
+ }
798
+ if (outcome.stale) {
799
+ data.res.set("Warning", STALE_WARNING_HEADER);
800
+ }
801
+ Response.sendCalendarResponse(data.req, data.res, {
802
+ body: outcome.body,
803
+ etag: outcome.etag,
804
+ lastModified: outcome.lastModified,
805
+ });
806
+ /*
807
+ * Only a real, current, enabled feed is worth bookkeeping. An empty
808
+ * calendar served for a rotated-out link or a disabled feed is not a
809
+ * fetch the settings page should count -- the two conditions above say so
810
+ * exactly. Everything else that went out as a 200 IS a fetch, including the
811
+ * empty calendars the renderer produces for "you are not on a schedule yet"
812
+ * or "this project is below plan": those are precisely the users staring at
813
+ * an empty calendar and asking "is my calendar app even reaching the
814
+ * server?", which lastFetchedAt/lastFetchedClient exist to answer. Only an
815
+ * Unavailable outcome is skipped, and that one already returned above
816
+ * without sending a body.
817
+ */
818
+ if (!data.lookup.viaPreviousToken && data.lookup.feed.isEnabled !== false) {
819
+ recordFetch({
820
+ kind: data.kind,
821
+ feed: data.lookup.feed,
822
+ req: data.req,
823
+ now: data.now,
824
+ truncated: outcome.truncated || outcome.stale,
825
+ });
826
+ }
827
+ }
828
+ router.get(PERSONAL_FEED_ROUTE, killSwitchMiddleware, schemeGuardMiddleware, OnCallCalendarFeedRateLimit.getMiddleware(), async (req, res, next) => {
829
+ var _a, _b, _c;
830
+ try {
831
+ const token = (_a = req.params) === null || _a === void 0 ? void 0 : _a["token"];
832
+ if (!CalendarFeedToken.isValidShape(token)) {
833
+ return sendNotFound(req, res);
834
+ }
835
+ const scheduleFilter = readScheduleFilter(req);
836
+ if (scheduleFilter === null) {
837
+ return sendNotFound(req, res);
838
+ }
839
+ const now = OneUptimeDate.getCurrentDate();
840
+ const tokenHash = CalendarFeedToken.hash(token);
841
+ const lookup = await lookupPersonalFeed(tokenHash, now);
842
+ if (!lookup || !lookup.feed.id || !lookup.feed.projectId) {
843
+ return sendNotFound(req, res);
844
+ }
845
+ if (!lookup.feed.userId) {
846
+ return sendNotFound(req, res);
847
+ }
848
+ return await serveFeed({
849
+ kind: OnCallCalendarFeedKind.Personal,
850
+ req,
851
+ res,
852
+ lookup,
853
+ now,
854
+ request: {
855
+ kind: OnCallCalendarFeedKind.Personal,
856
+ feedId: lookup.feed.id,
857
+ projectId: lookup.feed.projectId,
858
+ userId: lookup.feed.userId,
859
+ tokenHash,
860
+ includeCoveringShifts: lookup.feed.includeCoveringShifts !== false,
861
+ pastDays: (_b = lookup.feed.pastDays) !== null && _b !== void 0 ? _b : DEFAULT_PAST_DAYS,
862
+ futureDays: (_c = lookup.feed.futureDays) !== null && _c !== void 0 ? _c : DEFAULT_FUTURE_DAYS,
863
+ scheduleFilterId: scheduleFilter,
864
+ now,
865
+ },
866
+ });
867
+ }
868
+ catch (err) {
869
+ next(err);
870
+ }
871
+ });
872
+ router.get(SCHEDULE_FEED_ROUTE, killSwitchMiddleware, schemeGuardMiddleware, OnCallCalendarFeedRateLimit.getMiddleware(), async (req, res, next) => {
873
+ var _a, _b, _c, _d;
874
+ try {
875
+ const token = (_a = req.params) === null || _a === void 0 ? void 0 : _a["token"];
876
+ if (!CalendarFeedToken.isValidShape(token)) {
877
+ return sendNotFound(req, res);
878
+ }
879
+ const now = OneUptimeDate.getCurrentDate();
880
+ const tokenHash = CalendarFeedToken.hash(token);
881
+ const lookup = await lookupScheduleFeed(tokenHash, now);
882
+ if (!lookup ||
883
+ !lookup.feed.id ||
884
+ !lookup.feed.projectId ||
885
+ !lookup.feed.onCallDutyPolicyScheduleId) {
886
+ return sendNotFound(req, res);
887
+ }
888
+ return await serveFeed({
889
+ kind: OnCallCalendarFeedKind.Schedule,
890
+ req,
891
+ res,
892
+ lookup,
893
+ now,
894
+ request: {
895
+ kind: OnCallCalendarFeedKind.Schedule,
896
+ feedId: lookup.feed.id,
897
+ projectId: lookup.feed.projectId,
898
+ scheduleId: lookup.feed.onCallDutyPolicyScheduleId,
899
+ tokenHash,
900
+ includeCoverageGaps: lookup.feed.includeCoverageGaps === true,
901
+ minimumGapMinutes: (_b = lookup.feed.minimumGapMinutes) !== null && _b !== void 0 ? _b : 60,
902
+ pastDays: (_c = lookup.feed.pastDays) !== null && _c !== void 0 ? _c : DEFAULT_PAST_DAYS,
903
+ futureDays: (_d = lookup.feed.futureDays) !== null && _d !== void 0 ? _d : DEFAULT_FUTURE_DAYS,
904
+ now,
905
+ },
906
+ });
907
+ }
908
+ catch (err) {
909
+ next(err);
910
+ }
911
+ });
912
+ router.get(PROJECT_FEED_ROUTE, killSwitchMiddleware, schemeGuardMiddleware, OnCallCalendarFeedRateLimit.getMiddleware(), async (req, res, next) => {
913
+ var _a, _b, _c, _d;
914
+ try {
915
+ const token = (_a = req.params) === null || _a === void 0 ? void 0 : _a["token"];
916
+ if (!CalendarFeedToken.isValidShape(token)) {
917
+ return sendNotFound(req, res);
918
+ }
919
+ const now = OneUptimeDate.getCurrentDate();
920
+ const tokenHash = CalendarFeedToken.hash(token);
921
+ const lookup = await lookupProjectFeed(tokenHash, now);
922
+ if (!lookup || !lookup.feed.id || !lookup.feed.projectId) {
923
+ return sendNotFound(req, res);
924
+ }
925
+ return await serveFeed({
926
+ kind: OnCallCalendarFeedKind.Project,
927
+ req,
928
+ res,
929
+ lookup,
930
+ now,
931
+ request: {
932
+ kind: OnCallCalendarFeedKind.Project,
933
+ feedId: lookup.feed.id,
934
+ projectId: lookup.feed.projectId,
935
+ tokenHash,
936
+ includeCoverageGaps: lookup.feed.includeCoverageGaps === true,
937
+ minimumGapMinutes: (_b = lookup.feed.minimumGapMinutes) !== null && _b !== void 0 ? _b : 60,
938
+ pastDays: (_c = lookup.feed.pastDays) !== null && _c !== void 0 ? _c : DEFAULT_PAST_DAYS,
939
+ futureDays: (_d = lookup.feed.futureDays) !== null && _d !== void 0 ? _d : DEFAULT_FUTURE_DAYS,
940
+ now,
941
+ },
942
+ });
943
+ }
944
+ catch (err) {
945
+ next(err);
946
+ }
947
+ });
948
+ /*
949
+ * Registered AFTER the three exact GET routes, so those still win, and
950
+ * before the session routes, whose paths (`feed/`, `schedule-feed/`,
951
+ * `project-feed/`, `my-shifts`) share no prefix with these.
952
+ */
953
+ router.all(PERSONAL_FEED_FALLBACK_ROUTE, feedFallbackHandler);
954
+ router.all(SCHEDULE_FEED_FALLBACK_ROUTE, feedFallbackHandler);
955
+ router.all(PROJECT_FEED_FALLBACK_ROUTE, feedFallbackHandler);
956
+ // -- Session routes: personal feed -----------------------------------------
957
+ /*
958
+ * The caller's own feed row in the tenant project. Root read: the row is
959
+ * addressed by (projectId, userId) where userId is the SESSION's user, so
960
+ * the model's CurrentUser predicate is satisfied by construction and a
961
+ * non-root read would only add a permission round trip.
962
+ */
963
+ async function findPersonalFeed(data) {
964
+ return await UserOnCallCalendarFeedService.findOneBy({
965
+ query: {
966
+ projectId: data.projectId,
967
+ userId: data.userId,
968
+ },
969
+ select: Object.assign(Object.assign({}, STATUS_SELECT), { userId: true, includeCoveringShifts: true }),
970
+ props: { isRoot: true, ignoreHooks: true },
971
+ });
972
+ }
973
+ function requireUserId(props) {
974
+ if (!props.userId) {
975
+ throw new BadDataException("A logged-in user is required.");
976
+ }
977
+ return props.userId;
978
+ }
979
+ router.get(FEED_CURRENT_ROUTE, UserMiddleware.getUserMiddleware, UserMiddleware.requireUserAuthentication, async (req, res, next) => {
980
+ try {
981
+ const props = await CommonAPI.getDatabaseCommonInteractionProps(req);
982
+ const projectId = CommonAPI.assertAuthenticatedProjectMember(props);
983
+ const userId = requireUserId(props);
984
+ const feed = await findPersonalFeed({
985
+ projectId,
986
+ userId,
987
+ });
988
+ if (!feed) {
989
+ return Response.sendJsonObjectResponse(req, res, buildAbsentFeedStatus(OnCallCalendarFeedKind.Personal));
990
+ }
991
+ const status = await buildStatusForRow({
992
+ kind: OnCallCalendarFeedKind.Personal,
993
+ feed,
994
+ });
995
+ return Response.sendJsonObjectResponse(req, res, status);
996
+ }
997
+ catch (err) {
998
+ next(err);
999
+ }
1000
+ });
1001
+ /*
1002
+ * Mint-or-rotate under a per-(project, user) lock. The UNIQUE(projectId,
1003
+ * userId) index is the backstop; the lock is what turns a double click into
1004
+ * one new link rather than one new link and one 500. Without Redis the lock
1005
+ * cannot be taken, and the index alone has to do -- logged, not fatal.
1006
+ */
1007
+ async function withRotateLock(key, work) {
1008
+ let mutex = null;
1009
+ try {
1010
+ mutex = await Semaphore.lock({
1011
+ key,
1012
+ namespace: ROTATE_LOCK_NAMESPACE,
1013
+ lockTimeout: ROTATE_LOCK_TIMEOUT_MS,
1014
+ });
1015
+ }
1016
+ catch (err) {
1017
+ logger.warn("OnCallCalendarAPI: could not take the rotate lock; relying on the unique index.");
1018
+ logger.warn(err);
1019
+ mutex = null;
1020
+ }
1021
+ try {
1022
+ return await work();
1023
+ }
1024
+ finally {
1025
+ if (mutex) {
1026
+ try {
1027
+ await Semaphore.release(mutex);
1028
+ }
1029
+ catch (err) {
1030
+ logger.warn("OnCallCalendarAPI: releasing the rotate lock failed.");
1031
+ logger.warn(err);
1032
+ }
1033
+ }
1034
+ }
1035
+ }
1036
+ router.post(FEED_ROTATE_ROUTE, UserMiddleware.getUserMiddleware, UserMiddleware.requireUserAuthentication, async (req, res, next) => {
1037
+ try {
1038
+ assertJsonRequest(req);
1039
+ const props = await CommonAPI.getDatabaseCommonInteractionProps(req);
1040
+ const projectId = CommonAPI.assertAuthenticatedProjectMember(props);
1041
+ const userId = requireUserId(props);
1042
+ const plaintextToken = await withRotateLock(`${projectId.toString()}-${userId.toString()}`, async () => {
1043
+ const existing = await UserOnCallCalendarFeedService.findOneBy({
1044
+ query: { projectId, userId },
1045
+ select: { _id: true },
1046
+ props: { isRoot: true, ignoreHooks: true },
1047
+ });
1048
+ if (!existing || !existing.id) {
1049
+ const created = await UserOnCallCalendarFeedService.createForUser({
1050
+ projectId,
1051
+ userId,
1052
+ });
1053
+ return created.minted.token;
1054
+ }
1055
+ const rotation = await UserOnCallCalendarFeedService.rotateTokenById({
1056
+ id: existing.id,
1057
+ });
1058
+ return rotation.token;
1059
+ });
1060
+ await OnCallCalendarFeedCache.purgeForUser(projectId.toString(), userId.toString());
1061
+ const feed = await findPersonalFeed({
1062
+ projectId,
1063
+ userId,
1064
+ });
1065
+ if (!feed) {
1066
+ throw new NotFoundException("Calendar feed not found.");
1067
+ }
1068
+ const status = await buildStatusForRow({
1069
+ kind: OnCallCalendarFeedKind.Personal,
1070
+ feed,
1071
+ plaintextToken,
1072
+ });
1073
+ return Response.sendJsonObjectResponse(req, res, status);
1074
+ }
1075
+ catch (err) {
1076
+ next(err);
1077
+ }
1078
+ });
1079
+ // -- Session routes: schedule feed -----------------------------------------
1080
+ /*
1081
+ * NON-root read with the caller's props: the copied TableAccessControl and
1082
+ * the @CanAccessIfCanReadOn label scoping decide whether this caller may see
1083
+ * that the feed exists at all.
1084
+ */
1085
+ async function findScheduleFeedAsCaller(data) {
1086
+ return await OnCallDutyPolicyScheduleCalendarFeedService.findOneBy({
1087
+ query: {
1088
+ onCallDutyPolicyScheduleId: data.scheduleId,
1089
+ projectId: data.projectId,
1090
+ },
1091
+ select: Object.assign(Object.assign({}, STATUS_SELECT), { onCallDutyPolicyScheduleId: true, includeCoverageGaps: true, minimumGapMinutes: true, rotateWhenMemberLeaves: true }),
1092
+ props: data.props,
1093
+ });
1094
+ }
1095
+ router.get(SCHEDULE_FEED_CURRENT_ROUTE, UserMiddleware.getUserMiddleware, UserMiddleware.requireUserAuthentication, async (req, res, next) => {
1096
+ try {
1097
+ const props = await CommonAPI.getDatabaseCommonInteractionProps(req);
1098
+ const projectId = CommonAPI.assertAuthenticatedProjectMember(props);
1099
+ const scheduleId = readObjectIdParam(req, "scheduleId");
1100
+ const feed = await findScheduleFeedAsCaller({ scheduleId, projectId, props });
1101
+ if (!feed) {
1102
+ return Response.sendJsonObjectResponse(req, res, buildAbsentFeedStatus(OnCallCalendarFeedKind.Schedule));
1103
+ }
1104
+ const status = await buildStatusForRow({
1105
+ kind: OnCallCalendarFeedKind.Schedule,
1106
+ feed,
1107
+ });
1108
+ return Response.sendJsonObjectResponse(req, res, status);
1109
+ }
1110
+ catch (err) {
1111
+ next(err);
1112
+ }
1113
+ });
1114
+ /*
1115
+ * Publish = a NON-root create with the caller's props, so DatabaseService
1116
+ * runs the schedule's Create permission check and the service hook mints the
1117
+ * token (anything the request carried is discarded). A feed that already
1118
+ * exists is re-enabled through a non-root update instead -- same permission
1119
+ * gate, and the existing link keeps working for everyone who already has it.
1120
+ */
1121
+ router.post(SCHEDULE_FEED_PUBLISH_ROUTE, UserMiddleware.getUserMiddleware, UserMiddleware.requireUserAuthentication, async (req, res, next) => {
1122
+ try {
1123
+ assertJsonRequest(req);
1124
+ const props = await CommonAPI.getDatabaseCommonInteractionProps(req);
1125
+ const projectId = CommonAPI.assertAuthenticatedProjectMember(props);
1126
+ const scheduleId = readObjectIdParam(req, "scheduleId");
1127
+ const existing = await findScheduleFeedAsCaller({ scheduleId, projectId, props });
1128
+ if (existing && existing.id) {
1129
+ await OnCallDutyPolicyScheduleCalendarFeedService.updateOneBy({
1130
+ query: { _id: existing.id, projectId },
1131
+ data: { isEnabled: true },
1132
+ props,
1133
+ });
1134
+ }
1135
+ else {
1136
+ /*
1137
+ * The create alone is not enough of a gate. Its permission check
1138
+ * (CreatePermission) looks at table and column permissions and at
1139
+ * ownership; @CanAccessIfCanReadOn -- the label scoping that decides
1140
+ * WHICH schedules an editor may touch -- is only applied to query
1141
+ * operations (read/update/delete), and the service's own check runs
1142
+ * as root. So a label-restricted editor who knows a schedule's id
1143
+ * could publish a feed for a schedule outside their labels. Reading
1144
+ * the schedule with the caller's props first applies exactly the
1145
+ * scoping /current and /rotate already get.
1146
+ */
1147
+ const schedule = await OnCallDutyPolicyScheduleService.findOneBy({
1148
+ query: { _id: scheduleId, projectId },
1149
+ select: { _id: true },
1150
+ props,
1151
+ });
1152
+ if (!schedule) {
1153
+ throw new NotFoundException("On-call schedule not found.");
1154
+ }
1155
+ const model = new OnCallDutyPolicyScheduleCalendarFeed();
1156
+ model.projectId = projectId;
1157
+ model.onCallDutyPolicyScheduleId = scheduleId;
1158
+ await OnCallDutyPolicyScheduleCalendarFeedService.create({
1159
+ data: model,
1160
+ props,
1161
+ });
1162
+ }
1163
+ await OnCallCalendarFeedCache.purgeForSchedule(scheduleId.toString());
1164
+ const feed = await findScheduleFeedAsCaller({ scheduleId, projectId, props });
1165
+ if (!feed) {
1166
+ throw new NotFoundException("Calendar feed not found.");
1167
+ }
1168
+ const status = await buildStatusForRow({
1169
+ kind: OnCallCalendarFeedKind.Schedule,
1170
+ feed,
1171
+ });
1172
+ return Response.sendJsonObjectResponse(req, res, status);
1173
+ }
1174
+ catch (err) {
1175
+ next(err);
1176
+ }
1177
+ });
1178
+ /*
1179
+ * Rotate = a NON-root update of an updatable column (isEnabled, written back
1180
+ * with its current value) so the Edit permission check runs, THEN the root
1181
+ * mint. The token columns themselves are root-only on update, which is why
1182
+ * the permission probe cannot be the rotation write itself.
1183
+ */
1184
+ router.post(SCHEDULE_FEED_ROTATE_ROUTE, UserMiddleware.getUserMiddleware, UserMiddleware.requireUserAuthentication, async (req, res, next) => {
1185
+ try {
1186
+ assertJsonRequest(req);
1187
+ const props = await CommonAPI.getDatabaseCommonInteractionProps(req);
1188
+ const projectId = CommonAPI.assertAuthenticatedProjectMember(props);
1189
+ const scheduleId = readObjectIdParam(req, "scheduleId");
1190
+ const existing = await findScheduleFeedAsCaller({ scheduleId, projectId, props });
1191
+ if (!existing || !existing.id) {
1192
+ throw new NotFoundException("This schedule has no shared calendar feed yet. Publish one first.");
1193
+ }
1194
+ await OnCallDutyPolicyScheduleCalendarFeedService.updateOneBy({
1195
+ query: { _id: existing.id, projectId },
1196
+ data: { isEnabled: existing.isEnabled !== false },
1197
+ props,
1198
+ });
1199
+ const rotation = await OnCallDutyPolicyScheduleCalendarFeedService.rotateTokenById({
1200
+ id: existing.id,
1201
+ });
1202
+ await OnCallCalendarFeedCache.purgeForSchedule(scheduleId.toString());
1203
+ const feed = await findScheduleFeedAsCaller({ scheduleId, projectId, props });
1204
+ if (!feed) {
1205
+ throw new NotFoundException("Calendar feed not found.");
1206
+ }
1207
+ const status = await buildStatusForRow({
1208
+ kind: OnCallCalendarFeedKind.Schedule,
1209
+ feed,
1210
+ plaintextToken: rotation.token,
1211
+ });
1212
+ return Response.sendJsonObjectResponse(req, res, status);
1213
+ }
1214
+ catch (err) {
1215
+ next(err);
1216
+ }
1217
+ });
1218
+ // -- Session routes: project feed ------------------------------------------
1219
+ async function findProjectFeedAsCaller(data) {
1220
+ return await ProjectOnCallCalendarFeedService.findOneBy({
1221
+ query: {
1222
+ projectId: data.projectId,
1223
+ },
1224
+ select: Object.assign(Object.assign({}, STATUS_SELECT), { includeCoverageGaps: true, minimumGapMinutes: true, rotateWhenMemberLeaves: true }),
1225
+ props: data.props,
1226
+ });
1227
+ }
1228
+ router.get(PROJECT_FEED_CURRENT_ROUTE, UserMiddleware.getUserMiddleware, UserMiddleware.requireUserAuthentication, async (req, res, next) => {
1229
+ try {
1230
+ const props = await CommonAPI.getDatabaseCommonInteractionProps(req);
1231
+ const projectId = CommonAPI.assertAuthenticatedProjectMember(props);
1232
+ const feed = await findProjectFeedAsCaller({ projectId, props });
1233
+ if (!feed) {
1234
+ return Response.sendJsonObjectResponse(req, res, buildAbsentFeedStatus(OnCallCalendarFeedKind.Project));
1235
+ }
1236
+ const status = await buildStatusForRow({
1237
+ kind: OnCallCalendarFeedKind.Project,
1238
+ feed,
1239
+ });
1240
+ return Response.sendJsonObjectResponse(req, res, status);
1241
+ }
1242
+ catch (err) {
1243
+ next(err);
1244
+ }
1245
+ });
1246
+ router.post(PROJECT_FEED_PUBLISH_ROUTE, UserMiddleware.getUserMiddleware, UserMiddleware.requireUserAuthentication, async (req, res, next) => {
1247
+ try {
1248
+ assertJsonRequest(req);
1249
+ const props = await CommonAPI.getDatabaseCommonInteractionProps(req);
1250
+ const projectId = CommonAPI.assertAuthenticatedProjectMember(props);
1251
+ const existing = await findProjectFeedAsCaller({ projectId, props });
1252
+ if (existing && existing.id) {
1253
+ await ProjectOnCallCalendarFeedService.updateOneBy({
1254
+ query: { _id: existing.id, projectId },
1255
+ data: { isEnabled: true },
1256
+ props,
1257
+ });
1258
+ }
1259
+ else {
1260
+ const model = new ProjectOnCallCalendarFeed();
1261
+ model.projectId = projectId;
1262
+ await ProjectOnCallCalendarFeedService.create({
1263
+ data: model,
1264
+ props,
1265
+ });
1266
+ }
1267
+ await OnCallCalendarFeedCache.purgeForProject(projectId.toString());
1268
+ const feed = await findProjectFeedAsCaller({ projectId, props });
1269
+ if (!feed) {
1270
+ throw new NotFoundException("Calendar feed not found.");
1271
+ }
1272
+ const status = await buildStatusForRow({
1273
+ kind: OnCallCalendarFeedKind.Project,
1274
+ feed,
1275
+ });
1276
+ return Response.sendJsonObjectResponse(req, res, status);
1277
+ }
1278
+ catch (err) {
1279
+ next(err);
1280
+ }
1281
+ });
1282
+ router.post(PROJECT_FEED_ROTATE_ROUTE, UserMiddleware.getUserMiddleware, UserMiddleware.requireUserAuthentication, async (req, res, next) => {
1283
+ try {
1284
+ assertJsonRequest(req);
1285
+ const props = await CommonAPI.getDatabaseCommonInteractionProps(req);
1286
+ const projectId = CommonAPI.assertAuthenticatedProjectMember(props);
1287
+ const existing = await findProjectFeedAsCaller({ projectId, props });
1288
+ if (!existing || !existing.id) {
1289
+ throw new NotFoundException("This project has no shared calendar feed yet. Publish one first.");
1290
+ }
1291
+ await ProjectOnCallCalendarFeedService.updateOneBy({
1292
+ query: { _id: existing.id, projectId },
1293
+ data: { isEnabled: existing.isEnabled !== false },
1294
+ props,
1295
+ });
1296
+ const rotation = await ProjectOnCallCalendarFeedService.rotateTokenById({
1297
+ id: existing.id,
1298
+ });
1299
+ await OnCallCalendarFeedCache.purgeForProject(projectId.toString());
1300
+ const feed = await findProjectFeedAsCaller({ projectId, props });
1301
+ if (!feed) {
1302
+ throw new NotFoundException("Calendar feed not found.");
1303
+ }
1304
+ const status = await buildStatusForRow({
1305
+ kind: OnCallCalendarFeedKind.Project,
1306
+ feed,
1307
+ plaintextToken: rotation.token,
1308
+ });
1309
+ return Response.sendJsonObjectResponse(req, res, status);
1310
+ }
1311
+ catch (err) {
1312
+ next(err);
1313
+ }
1314
+ });
1315
+ // -- Session route: /my-shifts ---------------------------------------------
1316
+ /*
1317
+ * The caller's own upcoming shifts as JSON. Scoped to the tenant project
1318
+ * when a `tenantid` header is present (the dashboard), to every project the
1319
+ * caller is rostered in otherwise (the mobile app). Same resolver and
1320
+ * schedule-level cache as the feeds; the per-process render cap applies, and
1321
+ * a capped request is a 503 the mobile app answers by falling back to its
1322
+ * roster-derived list.
1323
+ */
1324
+ router.get(MY_SHIFTS_ROUTE, UserMiddleware.getUserMiddleware, UserMiddleware.requireUserAuthentication, async (req, res, next) => {
1325
+ try {
1326
+ const props = await CommonAPI.getDatabaseCommonInteractionProps(req);
1327
+ const userId = requireUserId(props);
1328
+ let projectIds = undefined;
1329
+ if (props.tenantId) {
1330
+ projectIds = [CommonAPI.assertAuthenticatedProjectMember(props)];
1331
+ }
1332
+ const now = OneUptimeDate.getCurrentDate();
1333
+ const window = readMyShiftsWindow(req, now);
1334
+ /*
1335
+ * Session renders leave slots free for the public feeds. /my-shifts is
1336
+ * called by a logged-in client that can retry and that falls back to
1337
+ * its roster list; a calendar client that gets a 503 shows a stale or
1338
+ * empty calendar to somebody who may be on call. With the default
1339
+ * concurrency of 4 this route may hold at most 2 slots at once.
1340
+ */
1341
+ if (!OnCallCalendarFeedCache.tryAcquireRenderSlot({
1342
+ leaveFreeSlots: Math.floor(OnCallCalendarFeedCache.getRenderConcurrency() / 2),
1343
+ })) {
1344
+ return sendUnavailable(req, res, 60);
1345
+ }
1346
+ let result;
1347
+ try {
1348
+ result = await OnCallCalendarFeedRenderer.materializeUserShifts({
1349
+ userId,
1350
+ projectIds,
1351
+ from: window.from,
1352
+ to: window.to,
1353
+ now,
1354
+ });
1355
+ }
1356
+ finally {
1357
+ OnCallCalendarFeedCache.releaseRenderSlot();
1358
+ }
1359
+ const payload = {
1360
+ shifts: MaterializedShiftUtil.toJSONArray(result.shifts),
1361
+ truncated: result.truncated,
1362
+ generatedAt: result.generatedAt.toISOString(),
1363
+ };
1364
+ return Response.sendJsonObjectResponse(req, res, payload);
1365
+ }
1366
+ catch (err) {
1367
+ next(err);
1368
+ }
1369
+ });
1370
+ export default router;
1371
+ //# sourceMappingURL=OnCallCalendarAPI.js.map