@oneuptime/common 13.0.7 → 13.0.8

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 (463) hide show
  1. package/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.ts +1 -1
  2. package/Models/DatabaseModels/ProjectOnCallCalendarFeed.ts +1 -1
  3. package/Models/DatabaseModels/UserOnCallCalendarFeed.ts +1 -1
  4. package/Server/API/AIBillingAPI.ts +1 -0
  5. package/Server/API/AIInsightAPI.ts +1 -4
  6. package/Server/API/AIInvestigationAPI.ts +1 -4
  7. package/Server/API/AIReadinessAPI.ts +4 -5
  8. package/Server/API/AlertAPI.ts +1 -0
  9. package/Server/API/AutoRemediationAPI.ts +1 -4
  10. package/Server/API/BaseAPI.ts +13 -0
  11. package/Server/API/BaseAnalyticsAPI.ts +80 -9
  12. package/Server/API/BillingAPI.ts +2 -0
  13. package/Server/API/BillingInvoiceAPI.ts +1 -0
  14. package/Server/API/BillingPaymentMethodAPI.ts +2 -0
  15. package/Server/API/CodeFixRunAPI.ts +1 -3
  16. package/Server/API/CommonAPI.ts +68 -4
  17. package/Server/API/DashboardAPI.ts +12 -12
  18. package/Server/API/GlobalConfigAPI.ts +17 -0
  19. package/Server/API/IncidentAPI.ts +2 -0
  20. package/Server/API/IncidentEpisodeAPI.ts +1 -0
  21. package/Server/API/NotificationAPI.ts +1 -0
  22. package/Server/API/OnCallCalendarAPI.ts +4 -5
  23. package/Server/API/OnCallDutyPolicyAPI.ts +7 -0
  24. package/Server/API/OnCallReadinessAPI.ts +4 -1
  25. package/Server/API/OnCallScheduleTimelineAPI.ts +731 -0
  26. package/Server/API/ProjectAPI.ts +1 -0
  27. package/Server/API/ScheduledMaintenanceAPI.ts +1 -0
  28. package/Server/API/StatusPageAPI.ts +161 -32
  29. package/Server/API/TeamMemberAPI.ts +3 -0
  30. package/Server/API/UserCallAPI.ts +2 -0
  31. package/Server/API/UserEmailAPI.ts +2 -0
  32. package/Server/API/UserIncomingCallNumberAPI.ts +2 -0
  33. package/Server/API/UserMicrosoftTeamsAPI.ts +1 -0
  34. package/Server/API/UserSlackAPI.ts +1 -0
  35. package/Server/API/UserSmsAPI.ts +2 -0
  36. package/Server/API/UserTotpAuthAPI.ts +1 -0
  37. package/Server/API/UserWebAuthnAPI.ts +2 -0
  38. package/Server/API/UserWebhookAPI.ts +1 -0
  39. package/Server/API/UserWhatsAppAPI.ts +2 -0
  40. package/Server/Middleware/MasterAdminAuthorization.ts +13 -2
  41. package/Server/Middleware/UserAuthorization.ts +79 -5
  42. package/Server/Services/ApiKeyPermissionService.ts +101 -4
  43. package/Server/Services/DatabaseService.ts +245 -0
  44. package/Server/Services/DetectionRuleService.ts +5 -4
  45. package/Server/Services/OnCallDutyPolicyChildService.ts +261 -0
  46. package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +2 -2
  47. package/Server/Services/OnCallDutyPolicyEscalationRuleService.ts +2 -2
  48. package/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.ts +2 -2
  49. package/Server/Services/OnCallDutyPolicyEscalationRuleUserService.ts +2 -2
  50. package/Server/Services/PayAsYouGoBillingService.ts +23 -28
  51. package/Server/Services/ProjectService.ts +18 -0
  52. package/Server/Services/RumSessionPinService.ts +274 -22
  53. package/Server/Services/TeamPermissionService.ts +120 -26
  54. package/Server/Services/ThreatIntelFeedService.ts +6 -3
  55. package/Server/Types/Database/Permissions/BasePermission.ts +9 -7
  56. package/Server/Types/Database/Permissions/Index.ts +75 -11
  57. package/Server/Types/Database/Permissions/TablePermission.ts +24 -28
  58. package/Server/Utils/AI/AIChatPrivacyFilter.ts +8 -0
  59. package/Server/Utils/AI/AIRunPrivacyFilter.ts +8 -0
  60. package/Server/Utils/MasterAdminPageAccess.ts +61 -0
  61. package/Server/Utils/Monitor/MonitorAlert.ts +3 -1
  62. package/Server/Utils/Monitor/MonitorIncident.ts +3 -1
  63. package/Server/Utils/OnCall/OnCallCalendarFeedRenderer.ts +1 -1
  64. package/Server/Utils/Realtime.ts +163 -45
  65. package/Server/Utils/SecurityEvent/DetectionRuleEvaluator.ts +11 -28
  66. package/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepair.ts +170 -0
  67. package/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.ts +1 -1
  68. package/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelFeedPoller.ts +6 -2
  69. package/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelMatcher.ts +10 -9
  70. package/Tests/App/Dashboard/AffectedResourcesPicker.test.tsx +1059 -0
  71. package/Tests/App/Dashboard/AffectedResourcesPickerEditForm.test.tsx +376 -0
  72. package/Tests/App/Dashboard/AffectedResourcesPickerHiddenTypes.test.tsx +757 -0
  73. package/Tests/App/Dashboard/AffectedResourcesSummaryStep.test.tsx +307 -0
  74. package/Tests/App/Dashboard/ArgumentsFormGroupByUnlistedAttributes.test.tsx +131 -0
  75. package/Tests/App/Dashboard/DashboardHeaderRequests.test.tsx +1 -1
  76. package/Tests/App/Dashboard/DashboardMonitorLabelVariable.test.tsx +9 -1
  77. package/Tests/App/Dashboard/DashboardVariableAllContract.test.tsx +24 -0
  78. package/Tests/App/Dashboard/DashboardVariableSelector.test.tsx +162 -8
  79. package/Tests/App/Dashboard/EntityFilterDropdownArchivedSlos.test.tsx +105 -6
  80. package/Tests/App/Dashboard/EntityFilterDropdownUnlistedSelection.test.tsx +434 -0
  81. package/Tests/App/Dashboard/EscalationRuleReadiness.test.tsx +276 -1
  82. package/Tests/App/Dashboard/OnCallCalendarFeedSideMenus.test.tsx +9 -1
  83. package/Tests/App/Dashboard/PayAsYouGoConsentGate.test.tsx +58 -42
  84. package/Tests/App/Dashboard/PayAsYouGoNotices.test.tsx +42 -5
  85. package/Tests/App/Dashboard/ResourceAuditLogsSideMenus.test.tsx +34 -23
  86. package/Tests/App/Dashboard/ScheduleTimeline.test.tsx +1580 -0
  87. package/Tests/App/Dashboard/ScheduleTimelineAPI.test.ts +280 -0
  88. package/Tests/App/Dashboard/ScheduleTimelineModel.test.ts +673 -0
  89. package/Tests/App/Dashboard/SecurityEventConnectionDiagnostics.test.tsx +95 -68
  90. package/Tests/App/Dashboard/SecurityEventsDetectionRulesPage.test.tsx +86 -3
  91. package/Tests/App/Dashboard/SecurityEventsEmptyState.test.tsx +28 -3
  92. package/Tests/App/Dashboard/SecurityEventsExplorer.test.tsx +761 -0
  93. package/Tests/App/Dashboard/SecurityEventsGuideContent.test.ts +1313 -0
  94. package/Tests/App/Dashboard/SecurityEventsHowItWorksCard.test.tsx +536 -0
  95. package/Tests/App/Dashboard/SecurityEventsNoResults.test.tsx +222 -0
  96. package/Tests/App/Dashboard/SecurityEventsThreatIntelPage.test.tsx +199 -0
  97. package/Tests/App/Dashboard/SecurityEventsVolumeChart.test.tsx +321 -0
  98. package/Tests/App/Dashboard/SloOverviewHero.test.tsx +171 -36
  99. package/Tests/App/Dashboard/SloViewSideMenu.test.tsx +215 -0
  100. package/Tests/App/Dashboard/SloViewSideMenuCounts.test.tsx +40 -3
  101. package/Tests/App/PublicDashboard/DashboardVariableSelector.test.tsx +12 -4
  102. package/Tests/App/PublicDashboard/PublicDashboardWidgetListAuth.test.tsx +623 -0
  103. package/Tests/Models/OnCallCalendarFeedModels.test.ts +23 -1
  104. package/Tests/Server/API/AIChatRouteAuthorization.test.ts +138 -5
  105. package/Tests/Server/API/AIGenerationProjectAIToggle.test.ts +187 -0
  106. package/Tests/Server/API/AIInvestigationAvailabilityAuthorization.test.ts +51 -3
  107. package/Tests/Server/API/AIInvestigationEvidenceAPI.test.ts +55 -2
  108. package/Tests/Server/API/BaseAnalyticsAPIAggregateCache.test.ts +729 -0
  109. package/Tests/Server/API/BillingPayAsYouGoStatus.test.ts +93 -7
  110. package/Tests/Server/API/BillingPaymentMethodAPI.test.ts +36 -3
  111. package/Tests/Server/API/CommonAPIAuthGuard.test.ts +1003 -24
  112. package/Tests/Server/API/DashboardPublicRateLimit.test.ts +6 -3
  113. package/Tests/Server/API/ExpiredSessionAIRoutes.test.ts +708 -0
  114. package/Tests/Server/API/ExpiredSessionCustomRoutes.test.ts +928 -0
  115. package/Tests/Server/API/ExpiredSessionMonitorTemplate.test.ts +319 -0
  116. package/Tests/Server/API/ExpiredSessionOnCallDutyPolicy.test.ts +336 -0
  117. package/Tests/Server/API/ExpiredSessionRouteGuards.test.ts +820 -0
  118. package/Tests/Server/API/GlobalConfigLicense.test.ts +140 -0
  119. package/Tests/Server/API/NotificationChannelVerificationAPI.test.ts +115 -12
  120. package/Tests/Server/API/OnCallCalendarAPI.test.ts +375 -8
  121. package/Tests/Server/API/OnCallReadinessAPI.test.ts +175 -17
  122. package/Tests/Server/API/OnCallScheduleTimelineAPI.test.ts +1513 -0
  123. package/Tests/Server/API/OnCallSetupReminderAPI.test.ts +119 -7
  124. package/Tests/Server/API/ProjectScopedCustomRouteAuth.test.ts +111 -4
  125. package/Tests/Server/API/PublicRouteInvalidAccessToken.test.ts +615 -0
  126. package/Tests/Server/API/SecurityEventAttributesAPI.test.ts +89 -2
  127. package/Tests/Server/API/SessionReplayAPI.test.ts +121 -0
  128. package/Tests/Server/API/StatusPageMasterPasswordRateLimit.test.ts +4 -2
  129. package/Tests/Server/API/StatusPagePostmortemVisibility.test.ts +441 -0
  130. package/Tests/Server/API/StatusPageTestEmailReportAuth.test.ts +664 -0
  131. package/Tests/Server/API/TeamMemberRemoveUserFromProjectAPI.test.ts +7 -0
  132. package/Tests/Server/API/UserIncomingCallNumberApi.test.ts +6 -0
  133. package/Tests/Server/API/UserNotificationSettingAPI.test.ts +65 -4
  134. package/Tests/Server/API/UserProjectsAPI.test.ts +63 -3
  135. package/Tests/Server/API/UserTotpAuthAPI.test.ts +48 -2
  136. package/Tests/Server/API/UserWebAuthnAuthenticationOptionsRoute.test.ts +11 -2
  137. package/Tests/Server/API/UserWebAuthnBackupCodeMinting.test.ts +46 -3
  138. package/Tests/Server/API/UserWebAuthnPasskeyAPI.test.ts +18 -2
  139. package/Tests/Server/API/ZZVerifyChatsAuth.test.ts +24 -7
  140. package/Tests/Server/Middleware/ExpiredSessionUserMiddleware.test.ts +563 -0
  141. package/Tests/Server/Middleware/MasterAdminAuthorization.test.ts +299 -19
  142. package/Tests/Server/Middleware/PublicRouteUserMiddleware.test.ts +453 -0
  143. package/Tests/Server/Services/AIChatPrivacyPin.test.ts +24 -0
  144. package/Tests/Server/Services/ApiKeyPermissionSecurity.test.ts +2 -0
  145. package/Tests/Server/Services/ApiKeyPermissionService.test.ts +3 -3
  146. package/Tests/Server/Services/DatabaseServiceCreateSuppliedId.test.ts +147 -0
  147. package/Tests/Server/Services/DatabaseServiceLoginBeforeHooks.test.ts +1078 -0
  148. package/Tests/Server/Services/DatabaseServiceTenantRelationGuard.test.ts +259 -0
  149. package/Tests/Server/Services/DatabaseServiceWriteOperatorValues.test.ts +147 -0
  150. package/Tests/Server/Services/MonitorPayAsYouGoBilling.test.ts +115 -1
  151. package/Tests/Server/Services/OnCallChildCreateAuthorizationPostgres.test.ts +711 -0
  152. package/Tests/Server/Services/OnCallDutyPolicyChildService.test.ts +733 -0
  153. package/Tests/Server/Services/PayAsYouGoBillingService.test.ts +190 -140
  154. package/Tests/Server/Services/PayAsYouGoStripeRateLimitBudget.test.ts +4 -9
  155. package/Tests/Server/Services/PermissionBlockDeletion.test.ts +780 -0
  156. package/Tests/Server/Services/PermissionBlockDeletionPostgres.test.ts +628 -0
  157. package/Tests/Server/Services/ProjectServiceCreateSubscriptionStarted.test.ts +77 -1
  158. package/Tests/Server/Services/RumSessionPinCreatePermission.test.ts +715 -0
  159. package/Tests/Server/Services/TeamMemberMultiTenantReadPostgres.test.ts +394 -0
  160. package/Tests/Server/Services/TeamPrivilegeEscalation.test.ts +6 -0
  161. package/Tests/Server/Services/TelemetryPayAsYouGoBilling.test.ts +131 -0
  162. package/Tests/Server/Services/UserNotificationRuleAdminGuards.test.ts +13 -2
  163. package/Tests/Server/Types/Database/Permissions/ModelPermissionAnonymousRefusal.test.ts +518 -0
  164. package/Tests/Server/Types/Database/Permissions/MultiTenantPermissions.test.ts +350 -0
  165. package/Tests/Server/Types/Database/Permissions/OnCallCalendarFeedPermissions.test.ts +282 -25
  166. package/Tests/Server/Types/Database/Permissions/TableLevelBlockPermission.test.ts +459 -0
  167. package/Tests/Server/Utils/AI/AIRunPrivacyFilter.test.ts +101 -9
  168. package/Tests/Server/Utils/AI/ChatAgentHelpers.test.ts +88 -4
  169. package/Tests/Server/Utils/AI/Toolbox/ExceptionTools.test.ts +459 -0
  170. package/Tests/Server/Utils/AI/Toolbox/LogTools.test.ts +794 -0
  171. package/Tests/Server/Utils/AI/Toolbox/RecentChangesTools.test.ts +574 -0
  172. package/Tests/Server/Utils/AI/Toolbox/SecurityEventTools.test.ts +596 -0
  173. package/Tests/Server/Utils/CaptchaRequestAndLogging.test.ts +395 -0
  174. package/Tests/Server/Utils/MasterAdminPageAccess.test.ts +251 -0
  175. package/Tests/Server/Utils/Monitor/MonitorActionTimestamps.test.ts +616 -0
  176. package/Tests/Server/Utils/Realtime.test.ts +502 -0
  177. package/Tests/Server/Utils/SecurityEvent/Connectors/GoogleSecOps/GoogleSecOpsConnectorSeverity.test.ts +216 -0
  178. package/Tests/Server/Utils/SecurityEvent/DetectionRuleEvaluator.test.ts +142 -0
  179. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepair.test.ts +140 -0
  180. package/Tests/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepairClickhouseIntegration.test.ts +542 -0
  181. package/Tests/Server/Utils/Telemetry/ChangeEventRow.test.ts +743 -0
  182. package/Tests/Server/Utils/Telemetry/RuntimeMetrics.test.ts +465 -0
  183. package/Tests/Server/Utils/Workspace/MicrosoftTeams/Messages/Alert.test.ts +202 -0
  184. package/Tests/Server/Utils/Workspace/MicrosoftTeams/Messages/Incident.test.ts +194 -0
  185. package/Tests/Server/Utils/Workspace/MicrosoftTeams/Messages/ScheduledMaintenance.test.ts +231 -0
  186. package/Tests/Server/Utils/Workspace/Slack/Messages/Alert.test.ts +194 -0
  187. package/Tests/Server/Utils/Workspace/Slack/Messages/AlertEpisode.test.ts +194 -0
  188. package/Tests/Server/Utils/Workspace/Slack/Messages/Incident.test.ts +194 -0
  189. package/Tests/Server/Utils/Workspace/Slack/Messages/IncidentEpisode.test.ts +194 -0
  190. package/Tests/Server/Utils/Workspace/Slack/Messages/ScheduledMaintenance.test.ts +247 -0
  191. package/Tests/Types/AI/AIInsightEvidence.test.ts +206 -0
  192. package/Tests/Types/BaseDatabase/DatabaseCommonInteractionPropsUtilAnonymous.test.ts +144 -0
  193. package/Tests/Types/Call/CallProvider.test.ts +528 -0
  194. package/Tests/Types/Kubernetes/KubernetesCostIngest.test.ts +236 -0
  195. package/Tests/Types/OnCallDutyPolicy/ScheduleTimeline.test.ts +736 -0
  196. package/Tests/Types/OnCallDutyPolicy/ScheduleTimelineLayout.test.ts +996 -0
  197. package/Tests/Types/SecurityEvent/SigmaRule.test.ts +142 -0
  198. package/Tests/Types/Workflow/Components/JSON.test.ts +182 -0
  199. package/Tests/UI/Components/BasicFormDropdownNormalization.test.tsx +116 -1
  200. package/Tests/UI/Components/Dropdown/DropdownAsyncOptions.test.tsx +81 -0
  201. package/Tests/UI/Components/EditionLabelLicenseRefresh.test.tsx +89 -1
  202. package/Tests/UI/Components/EventAttachmentList.test.tsx +174 -0
  203. package/Tests/UI/Components/Forms/BasicFormBurnRateTemplateDefaults.test.tsx +395 -0
  204. package/Tests/UI/Components/Forms/BasicFormCollapsibleSections.test.tsx +286 -0
  205. package/Tests/UI/Components/Forms/FormSummary.test.tsx +128 -0
  206. package/Tests/UI/Components/ModelTable/BaseModelTableQueryChange.test.tsx +365 -0
  207. package/Tests/UI/Components/OpenAuthenticatedUrl.test.ts +358 -0
  208. package/Tests/UI/Components/SessionAwareImage.test.tsx +496 -0
  209. package/Tests/UI/Components/TelemetryHistogramZeroBuckets.test.tsx +190 -0
  210. package/Tests/UI/Components/TooltipInteractive.test.tsx +97 -0
  211. package/Tests/UI/MicrosoftTeams/MicrosoftTeamsChatsCardInstallGuidance.test.tsx +1 -1
  212. package/Tests/UI/Monitor/EvaluationLogListTimestamps.test.tsx +367 -0
  213. package/Tests/UI/Utils/API/BaseAPIRefreshSession.test.ts +1087 -0
  214. package/Tests/UI/Utils/API/DashboardHost.ts +12 -0
  215. package/Tests/UI/Utils/API/FakeAxiosServer.ts +183 -0
  216. package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +10 -0
  217. package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +2 -0
  218. package/Tests/UI/Utils/Cookie.test.ts +440 -0
  219. package/Tests/UI/Utils/ModelAPIRequestClient.test.ts +278 -0
  220. package/Tests/UI/Utils/Navigation.test.ts +33 -0
  221. package/Tests/UI/Utils/PricingPlan.test.ts +295 -0
  222. package/Tests/UI/Utils/Realtime.test.ts +759 -0
  223. package/Tests/UI/Utils/Telemetry/Telemetry.test.ts +500 -0
  224. package/Tests/Utils/APIInstanceDispatch.test.ts +311 -0
  225. package/Tests/Utils/SecurityEvent/GoogleSecOpsAlertNormalizerSeverity.test.ts +565 -0
  226. package/Types/BaseDatabase/DatabaseCommonInteractionPropsUtil.ts +40 -0
  227. package/Types/Monitor/MonitorEvaluationSummary.ts +3 -0
  228. package/Types/OnCallDutyPolicy/ScheduleTimeline.ts +507 -0
  229. package/Types/OnCallDutyPolicy/ScheduleTimelineLayout.ts +589 -0
  230. package/Types/Realtime/EventName.ts +11 -0
  231. package/Types/SecurityEvent/DetectionFindingConstants.ts +14 -0
  232. package/Types/SecurityEvent/OcsfSeverity.ts +31 -26
  233. package/Types/SecurityEvent/SigmaRule.ts +51 -0
  234. package/Types/SecurityEvent/ThreatIntelConstants.ts +18 -0
  235. package/UI/Components/AttachmentList/EventAttachmentList.tsx +30 -2
  236. package/UI/Components/Dashboard/DashboardVariableControl.tsx +12 -2
  237. package/UI/Components/Dropdown/Dropdown.tsx +6 -1
  238. package/UI/Components/EditionLabel/EditionLabel.tsx +12 -0
  239. package/UI/Components/EventItem/EventItem.tsx +12 -1
  240. package/UI/Components/Forms/BasicForm.tsx +151 -126
  241. package/UI/Components/Forms/CollapsibleFormSection.tsx +63 -0
  242. package/UI/Components/Forms/Fields/FormField.tsx +10 -4
  243. package/UI/Components/Forms/FormSummary.tsx +7 -0
  244. package/UI/Components/Forms/Types/Field.ts +10 -0
  245. package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +2 -1
  246. package/UI/Components/Markdown.tsx/SessionAwareImage.tsx +122 -0
  247. package/UI/Components/ModelTable/BaseModelTable.tsx +34 -5
  248. package/UI/Components/ModelTable/TableView.tsx +1 -1
  249. package/UI/Components/TelemetryViewer/components/TelemetryHistogram.tsx +8 -1
  250. package/UI/Components/Tooltip/Tooltip.tsx +8 -1
  251. package/UI/Utils/API/API.ts +173 -12
  252. package/UI/Utils/API/RequestOptions.ts +11 -0
  253. package/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.ts +31 -7
  254. package/UI/Utils/ModelAPI/ModelAPI.ts +30 -9
  255. package/UI/Utils/Navigation.ts +9 -0
  256. package/UI/Utils/OpenAuthenticatedUrl.ts +154 -0
  257. package/UI/Utils/Realtime.ts +176 -30
  258. package/Utils/API.ts +14 -5
  259. package/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.ts +157 -7
  260. package/Utils/SecurityEvent/Sigma/SigmaRuleParser.ts +9 -17
  261. package/Utils/Slo/SloBurnRateTemplate.ts +2 -2
  262. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.js +1 -1
  263. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyScheduleCalendarFeed.js.map +1 -1
  264. package/build/dist/Models/DatabaseModels/ProjectOnCallCalendarFeed.js +1 -1
  265. package/build/dist/Models/DatabaseModels/ProjectOnCallCalendarFeed.js.map +1 -1
  266. package/build/dist/Models/DatabaseModels/UserOnCallCalendarFeed.js +1 -1
  267. package/build/dist/Models/DatabaseModels/UserOnCallCalendarFeed.js.map +1 -1
  268. package/build/dist/Server/API/AIBillingAPI.js +1 -1
  269. package/build/dist/Server/API/AIBillingAPI.js.map +1 -1
  270. package/build/dist/Server/API/AIInsightAPI.js +1 -4
  271. package/build/dist/Server/API/AIInsightAPI.js.map +1 -1
  272. package/build/dist/Server/API/AIInvestigationAPI.js +1 -4
  273. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  274. package/build/dist/Server/API/AIReadinessAPI.js +1 -3
  275. package/build/dist/Server/API/AIReadinessAPI.js.map +1 -1
  276. package/build/dist/Server/API/AlertAPI.js +1 -1
  277. package/build/dist/Server/API/AlertAPI.js.map +1 -1
  278. package/build/dist/Server/API/AutoRemediationAPI.js +1 -4
  279. package/build/dist/Server/API/AutoRemediationAPI.js.map +1 -1
  280. package/build/dist/Server/API/BaseAPI.js +12 -0
  281. package/build/dist/Server/API/BaseAPI.js.map +1 -1
  282. package/build/dist/Server/API/BaseAnalyticsAPI.js +55 -10
  283. package/build/dist/Server/API/BaseAnalyticsAPI.js.map +1 -1
  284. package/build/dist/Server/API/BillingAPI.js +2 -2
  285. package/build/dist/Server/API/BillingAPI.js.map +1 -1
  286. package/build/dist/Server/API/BillingInvoiceAPI.js +1 -1
  287. package/build/dist/Server/API/BillingInvoiceAPI.js.map +1 -1
  288. package/build/dist/Server/API/BillingPaymentMethodAPI.js +2 -2
  289. package/build/dist/Server/API/BillingPaymentMethodAPI.js.map +1 -1
  290. package/build/dist/Server/API/CodeFixRunAPI.js +1 -3
  291. package/build/dist/Server/API/CodeFixRunAPI.js.map +1 -1
  292. package/build/dist/Server/API/CommonAPI.js +50 -5
  293. package/build/dist/Server/API/CommonAPI.js.map +1 -1
  294. package/build/dist/Server/API/DashboardAPI.js +12 -12
  295. package/build/dist/Server/API/DashboardAPI.js.map +1 -1
  296. package/build/dist/Server/API/GlobalConfigAPI.js +12 -0
  297. package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
  298. package/build/dist/Server/API/IncidentAPI.js +2 -2
  299. package/build/dist/Server/API/IncidentAPI.js.map +1 -1
  300. package/build/dist/Server/API/IncidentEpisodeAPI.js +1 -1
  301. package/build/dist/Server/API/IncidentEpisodeAPI.js.map +1 -1
  302. package/build/dist/Server/API/NotificationAPI.js +1 -1
  303. package/build/dist/Server/API/NotificationAPI.js.map +1 -1
  304. package/build/dist/Server/API/OnCallCalendarAPI.js +1 -4
  305. package/build/dist/Server/API/OnCallCalendarAPI.js.map +1 -1
  306. package/build/dist/Server/API/OnCallDutyPolicyAPI.js +6 -0
  307. package/build/dist/Server/API/OnCallDutyPolicyAPI.js.map +1 -1
  308. package/build/dist/Server/API/OnCallReadinessAPI.js +4 -1
  309. package/build/dist/Server/API/OnCallReadinessAPI.js.map +1 -1
  310. package/build/dist/Server/API/OnCallScheduleTimelineAPI.js +494 -0
  311. package/build/dist/Server/API/OnCallScheduleTimelineAPI.js.map +1 -0
  312. package/build/dist/Server/API/ProjectAPI.js +1 -1
  313. package/build/dist/Server/API/ProjectAPI.js.map +1 -1
  314. package/build/dist/Server/API/ScheduledMaintenanceAPI.js +1 -1
  315. package/build/dist/Server/API/ScheduledMaintenanceAPI.js.map +1 -1
  316. package/build/dist/Server/API/StatusPageAPI.js +125 -33
  317. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  318. package/build/dist/Server/API/TeamMemberAPI.js +3 -3
  319. package/build/dist/Server/API/TeamMemberAPI.js.map +1 -1
  320. package/build/dist/Server/API/UserCallAPI.js +2 -2
  321. package/build/dist/Server/API/UserCallAPI.js.map +1 -1
  322. package/build/dist/Server/API/UserEmailAPI.js +2 -2
  323. package/build/dist/Server/API/UserEmailAPI.js.map +1 -1
  324. package/build/dist/Server/API/UserIncomingCallNumberAPI.js +2 -2
  325. package/build/dist/Server/API/UserIncomingCallNumberAPI.js.map +1 -1
  326. package/build/dist/Server/API/UserMicrosoftTeamsAPI.js +1 -1
  327. package/build/dist/Server/API/UserMicrosoftTeamsAPI.js.map +1 -1
  328. package/build/dist/Server/API/UserSlackAPI.js +1 -1
  329. package/build/dist/Server/API/UserSlackAPI.js.map +1 -1
  330. package/build/dist/Server/API/UserSmsAPI.js +2 -2
  331. package/build/dist/Server/API/UserSmsAPI.js.map +1 -1
  332. package/build/dist/Server/API/UserTotpAuthAPI.js +1 -1
  333. package/build/dist/Server/API/UserTotpAuthAPI.js.map +1 -1
  334. package/build/dist/Server/API/UserWebAuthnAPI.js +2 -2
  335. package/build/dist/Server/API/UserWebAuthnAPI.js.map +1 -1
  336. package/build/dist/Server/API/UserWebhookAPI.js +1 -1
  337. package/build/dist/Server/API/UserWebhookAPI.js.map +1 -1
  338. package/build/dist/Server/API/UserWhatsAppAPI.js +2 -2
  339. package/build/dist/Server/API/UserWhatsAppAPI.js.map +1 -1
  340. package/build/dist/Server/Middleware/MasterAdminAuthorization.js +11 -2
  341. package/build/dist/Server/Middleware/MasterAdminAuthorization.js.map +1 -1
  342. package/build/dist/Server/Middleware/UserAuthorization.js +64 -4
  343. package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
  344. package/build/dist/Server/Services/ApiKeyPermissionService.js +80 -4
  345. package/build/dist/Server/Services/ApiKeyPermissionService.js.map +1 -1
  346. package/build/dist/Server/Services/DatabaseService.js +171 -0
  347. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  348. package/build/dist/Server/Services/DetectionRuleService.js +4 -4
  349. package/build/dist/Server/Services/DetectionRuleService.js.map +1 -1
  350. package/build/dist/Server/Services/OnCallDutyPolicyChildService.js +170 -0
  351. package/build/dist/Server/Services/OnCallDutyPolicyChildService.js.map +1 -0
  352. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +2 -2
  353. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
  354. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js +2 -2
  355. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleService.js.map +1 -1
  356. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js +2 -2
  357. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js.map +1 -1
  358. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js +2 -2
  359. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js.map +1 -1
  360. package/build/dist/Server/Services/PayAsYouGoBillingService.js +20 -27
  361. package/build/dist/Server/Services/PayAsYouGoBillingService.js.map +1 -1
  362. package/build/dist/Server/Services/ProjectService.js +17 -0
  363. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  364. package/build/dist/Server/Services/RumSessionPinService.js +180 -16
  365. package/build/dist/Server/Services/RumSessionPinService.js.map +1 -1
  366. package/build/dist/Server/Services/TeamPermissionService.js +89 -27
  367. package/build/dist/Server/Services/TeamPermissionService.js.map +1 -1
  368. package/build/dist/Server/Services/ThreatIntelFeedService.js +5 -4
  369. package/build/dist/Server/Services/ThreatIntelFeedService.js.map +1 -1
  370. package/build/dist/Server/Types/Database/Permissions/BasePermission.js +9 -6
  371. package/build/dist/Server/Types/Database/Permissions/BasePermission.js.map +1 -1
  372. package/build/dist/Server/Types/Database/Permissions/Index.js +60 -6
  373. package/build/dist/Server/Types/Database/Permissions/Index.js.map +1 -1
  374. package/build/dist/Server/Types/Database/Permissions/TablePermission.js +14 -13
  375. package/build/dist/Server/Types/Database/Permissions/TablePermission.js.map +1 -1
  376. package/build/dist/Server/Utils/AI/AIChatPrivacyFilter.js +7 -0
  377. package/build/dist/Server/Utils/AI/AIChatPrivacyFilter.js.map +1 -1
  378. package/build/dist/Server/Utils/AI/AIRunPrivacyFilter.js +7 -0
  379. package/build/dist/Server/Utils/AI/AIRunPrivacyFilter.js.map +1 -1
  380. package/build/dist/Server/Utils/MasterAdminPageAccess.js +39 -0
  381. package/build/dist/Server/Utils/MasterAdminPageAccess.js.map +1 -0
  382. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +3 -1
  383. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  384. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +3 -1
  385. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  386. package/build/dist/Server/Utils/Realtime.js +126 -37
  387. package/build/dist/Server/Utils/Realtime.js.map +1 -1
  388. package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js +7 -25
  389. package/build/dist/Server/Utils/SecurityEvent/DetectionRuleEvaluator.js.map +1 -1
  390. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepair.js +127 -0
  391. package/build/dist/Server/Utils/SecurityEvent/GoogleSecOpsSeverityRepair.js.map +1 -0
  392. package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js +1 -1
  393. package/build/dist/Server/Utils/SecurityEvent/Sigma/SigmaClickhouseCompiler.js.map +1 -1
  394. package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelFeedPoller.js +3 -2
  395. package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelFeedPoller.js.map +1 -1
  396. package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelMatcher.js +4 -8
  397. package/build/dist/Server/Utils/SecurityEvent/ThreatIntel/ThreatIntelMatcher.js.map +1 -1
  398. package/build/dist/Types/BaseDatabase/DatabaseCommonInteractionPropsUtil.js +31 -1
  399. package/build/dist/Types/BaseDatabase/DatabaseCommonInteractionPropsUtil.js.map +1 -1
  400. package/build/dist/Types/OnCallDutyPolicy/ScheduleTimeline.js +321 -0
  401. package/build/dist/Types/OnCallDutyPolicy/ScheduleTimeline.js.map +1 -0
  402. package/build/dist/Types/OnCallDutyPolicy/ScheduleTimelineLayout.js +372 -0
  403. package/build/dist/Types/OnCallDutyPolicy/ScheduleTimelineLayout.js.map +1 -0
  404. package/build/dist/Types/Realtime/EventName.js +10 -0
  405. package/build/dist/Types/Realtime/EventName.js.map +1 -1
  406. package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js +11 -0
  407. package/build/dist/Types/SecurityEvent/DetectionFindingConstants.js.map +1 -1
  408. package/build/dist/Types/SecurityEvent/OcsfSeverity.js +30 -25
  409. package/build/dist/Types/SecurityEvent/OcsfSeverity.js.map +1 -1
  410. package/build/dist/Types/SecurityEvent/SigmaRule.js +47 -0
  411. package/build/dist/Types/SecurityEvent/SigmaRule.js.map +1 -1
  412. package/build/dist/Types/SecurityEvent/ThreatIntelConstants.js +14 -0
  413. package/build/dist/Types/SecurityEvent/ThreatIntelConstants.js.map +1 -1
  414. package/build/dist/UI/Components/AttachmentList/EventAttachmentList.js +9 -4
  415. package/build/dist/UI/Components/AttachmentList/EventAttachmentList.js.map +1 -1
  416. package/build/dist/UI/Components/Dashboard/DashboardVariableControl.js +10 -2
  417. package/build/dist/UI/Components/Dashboard/DashboardVariableControl.js.map +1 -1
  418. package/build/dist/UI/Components/Dropdown/Dropdown.js +5 -1
  419. package/build/dist/UI/Components/Dropdown/Dropdown.js.map +1 -1
  420. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +11 -0
  421. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  422. package/build/dist/UI/Components/EventItem/EventItem.js +2 -2
  423. package/build/dist/UI/Components/EventItem/EventItem.js.map +1 -1
  424. package/build/dist/UI/Components/Forms/BasicForm.js +70 -64
  425. package/build/dist/UI/Components/Forms/BasicForm.js.map +1 -1
  426. package/build/dist/UI/Components/Forms/CollapsibleFormSection.js +27 -0
  427. package/build/dist/UI/Components/Forms/CollapsibleFormSection.js.map +1 -0
  428. package/build/dist/UI/Components/Forms/Fields/FormField.js +10 -7
  429. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  430. package/build/dist/UI/Components/Forms/FormSummary.js +7 -0
  431. package/build/dist/UI/Components/Forms/FormSummary.js.map +1 -1
  432. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +2 -1
  433. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
  434. package/build/dist/UI/Components/Markdown.tsx/SessionAwareImage.js +84 -0
  435. package/build/dist/UI/Components/Markdown.tsx/SessionAwareImage.js.map +1 -0
  436. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +14 -1
  437. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  438. package/build/dist/UI/Components/ModelTable/TableView.js +1 -1
  439. package/build/dist/UI/Components/ModelTable/TableView.js.map +1 -1
  440. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js +8 -1
  441. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js.map +1 -1
  442. package/build/dist/UI/Components/Tooltip/Tooltip.js +2 -1
  443. package/build/dist/UI/Components/Tooltip/Tooltip.js.map +1 -1
  444. package/build/dist/UI/Utils/API/API.js +143 -19
  445. package/build/dist/UI/Utils/API/API.js.map +1 -1
  446. package/build/dist/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.js +21 -7
  447. package/build/dist/UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI.js.map +1 -1
  448. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +26 -9
  449. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
  450. package/build/dist/UI/Utils/Navigation.js +8 -0
  451. package/build/dist/UI/Utils/Navigation.js.map +1 -1
  452. package/build/dist/UI/Utils/OpenAuthenticatedUrl.js +92 -0
  453. package/build/dist/UI/Utils/OpenAuthenticatedUrl.js.map +1 -0
  454. package/build/dist/UI/Utils/Realtime.js +120 -15
  455. package/build/dist/UI/Utils/Realtime.js.map +1 -1
  456. package/build/dist/Utils/API.js +13 -5
  457. package/build/dist/Utils/API.js.map +1 -1
  458. package/build/dist/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.js +123 -6
  459. package/build/dist/Utils/SecurityEvent/GoogleSecOpsAlertNormalizer.js.map +1 -1
  460. package/build/dist/Utils/SecurityEvent/Sigma/SigmaRuleParser.js +4 -18
  461. package/build/dist/Utils/SecurityEvent/Sigma/SigmaRuleParser.js.map +1 -1
  462. package/build/dist/Utils/Slo/SloBurnRateTemplate.js +2 -2
  463. package/package.json +1 -1
@@ -0,0 +1,278 @@
1
+ import {
2
+ afterEach,
3
+ beforeEach,
4
+ describe,
5
+ expect,
6
+ jest,
7
+ test,
8
+ } from "@jest/globals";
9
+ import Log from "../../../Models/AnalyticsModels/Log";
10
+ import Incident from "../../../Models/DatabaseModels/Incident";
11
+ import Project from "../../../Models/DatabaseModels/Project";
12
+ import HTTPResponse from "../../../Types/API/HTTPResponse";
13
+ import URL from "../../../Types/API/URL";
14
+ import Dictionary from "../../../Types/Dictionary";
15
+ import { JSONArray, JSONObject } from "../../../Types/JSON";
16
+ import ObjectID from "../../../Types/ObjectID";
17
+ import AnalyticsModelAPI from "../../../UI/Utils/AnalyticsModelAPI/AnalyticsModelAPI";
18
+ import DashboardAPI from "../../../UI/Utils/API/API";
19
+ import ModelAPI from "../../../UI/Utils/ModelAPI/ModelAPI";
20
+ import ProjectUtil from "../../../UI/Utils/Project";
21
+
22
+ /*
23
+ * RequestOptions.apiClient picks the client for ONE model request. A public
24
+ * dashboard widget uses it to send its /public-dashboard-api read through the
25
+ * public dashboard's client, so that endpoint's 401 never reaches the
26
+ * dashboard client's refresh-token + User.logout + /accounts/login.
27
+ *
28
+ * Each client's `fetch` is spied independently, and the dashboard spy rejects
29
+ * whenever it must not be used, so a model API that ignores the routed client
30
+ * (or hard-codes the dashboard client again) fails here.
31
+ */
32
+
33
+ interface StaticSpy {
34
+ mockResolvedValue: (value: unknown) => StaticSpy;
35
+ mockRejectedValue: (value: unknown) => StaticSpy;
36
+ mock: { calls: Array<Array<unknown>> };
37
+ }
38
+
39
+ class RoutedAPI extends DashboardAPI {}
40
+
41
+ class SubclassDefaultAPI extends DashboardAPI {}
42
+
43
+ class SubclassModelAPI extends ModelAPI {
44
+ protected static override getApiClient(): typeof DashboardAPI {
45
+ return SubclassDefaultAPI;
46
+ }
47
+ }
48
+
49
+ const VIEWER_PROJECT_ID: string = "019acd20-1111-4111-8111-111111111111";
50
+
51
+ const OVERRIDE_URL: string =
52
+ "https://dashboards.example.com/public-dashboard-api/resource-list/dashboard-id/incident";
53
+
54
+ let routedFetchSpy: StaticSpy;
55
+ let subclassDefaultFetchSpy: StaticSpy;
56
+ let dashboardFetchSpy: StaticSpy;
57
+
58
+ const listResponse: () => HTTPResponse<JSONArray> =
59
+ (): HTTPResponse<JSONArray> => {
60
+ return new HTTPResponse<JSONArray>(
61
+ 200,
62
+ { data: [], count: 0, skip: 0, limit: 10 },
63
+ {},
64
+ );
65
+ };
66
+
67
+ const countResponse: () => HTTPResponse<JSONObject> =
68
+ (): HTTPResponse<JSONObject> => {
69
+ return new HTTPResponse<JSONObject>(200, { count: 0 }, {});
70
+ };
71
+
72
+ const requestedUrl: (spy: StaticSpy) => string = (spy: StaticSpy): string => {
73
+ return String((spy.mock.calls[0]![0] as { url: URL }).url);
74
+ };
75
+
76
+ beforeEach(() => {
77
+ /*
78
+ * Spy on the inherited statics of the subclasses first: jest then installs
79
+ * own spies on them, and the later DashboardAPI spy stays independent.
80
+ */
81
+ routedFetchSpy = jest.spyOn(RoutedAPI, "fetch") as unknown as StaticSpy;
82
+ subclassDefaultFetchSpy = jest.spyOn(
83
+ SubclassDefaultAPI,
84
+ "fetch",
85
+ ) as unknown as StaticSpy;
86
+ dashboardFetchSpy = jest.spyOn(DashboardAPI, "fetch") as unknown as StaticSpy;
87
+
88
+ routedFetchSpy.mockResolvedValue(listResponse());
89
+ subclassDefaultFetchSpy.mockResolvedValue(listResponse());
90
+ dashboardFetchSpy.mockRejectedValue(
91
+ new Error("the dashboard client must not receive this request"),
92
+ );
93
+ });
94
+
95
+ afterEach(() => {
96
+ jest.restoreAllMocks();
97
+ });
98
+
99
+ describe("RequestOptions.apiClient routes a single model request", () => {
100
+ test("ModelAPI.getList sends a routed read through the routed client", async () => {
101
+ await ModelAPI.getList<Incident>({
102
+ modelType: Incident,
103
+ query: {},
104
+ limit: 10,
105
+ skip: 0,
106
+ select: { title: true },
107
+ sort: {},
108
+ requestOptions: {
109
+ overrideRequestUrl: URL.fromString(OVERRIDE_URL),
110
+ apiClient: RoutedAPI,
111
+ },
112
+ });
113
+
114
+ expect(routedFetchSpy.mock.calls).toHaveLength(1);
115
+ expect(requestedUrl(routedFetchSpy)).toContain(OVERRIDE_URL);
116
+ expect(dashboardFetchSpy.mock.calls).toHaveLength(0);
117
+ });
118
+
119
+ test("ModelAPI.count sends a routed read through the routed client", async () => {
120
+ routedFetchSpy.mockResolvedValue(countResponse());
121
+
122
+ await ModelAPI.count<Incident>({
123
+ modelType: Incident,
124
+ query: {},
125
+ requestOptions: {
126
+ overrideRequestUrl: URL.fromString(OVERRIDE_URL),
127
+ apiClient: RoutedAPI,
128
+ },
129
+ });
130
+
131
+ expect(routedFetchSpy.mock.calls).toHaveLength(1);
132
+ expect(dashboardFetchSpy.mock.calls).toHaveLength(0);
133
+ });
134
+
135
+ test("AnalyticsModelAPI.getList sends a routed read through the routed client", async () => {
136
+ await AnalyticsModelAPI.getList<Log>({
137
+ modelType: Log,
138
+ query: {},
139
+ limit: 10,
140
+ skip: 0,
141
+ select: { body: true },
142
+ sort: {},
143
+ requestOptions: {
144
+ overrideRequestUrl: URL.fromString(OVERRIDE_URL),
145
+ apiClient: RoutedAPI,
146
+ },
147
+ });
148
+
149
+ expect(routedFetchSpy.mock.calls).toHaveLength(1);
150
+ expect(requestedUrl(routedFetchSpy)).toContain(OVERRIDE_URL);
151
+ expect(dashboardFetchSpy.mock.calls).toHaveLength(0);
152
+ });
153
+
154
+ test("AnalyticsModelAPI.count sends a routed read through the routed client", async () => {
155
+ routedFetchSpy.mockResolvedValue(countResponse());
156
+
157
+ await AnalyticsModelAPI.count<Log>(
158
+ Log,
159
+ {},
160
+ {
161
+ overrideRequestUrl: URL.fromString(OVERRIDE_URL),
162
+ apiClient: RoutedAPI,
163
+ },
164
+ );
165
+
166
+ expect(routedFetchSpy.mock.calls).toHaveLength(1);
167
+ expect(dashboardFetchSpy.mock.calls).toHaveLength(0);
168
+ });
169
+
170
+ test("without a routed client, both model APIs keep the dashboard client", async () => {
171
+ dashboardFetchSpy.mockResolvedValue(listResponse());
172
+
173
+ await ModelAPI.getList<Incident>({
174
+ modelType: Incident,
175
+ query: {},
176
+ limit: 10,
177
+ skip: 0,
178
+ select: { title: true },
179
+ sort: {},
180
+ });
181
+
182
+ await AnalyticsModelAPI.getList<Log>({
183
+ modelType: Log,
184
+ query: {},
185
+ limit: 10,
186
+ skip: 0,
187
+ select: { body: true },
188
+ sort: {},
189
+ requestOptions: { overrideRequestUrl: URL.fromString(OVERRIDE_URL) },
190
+ });
191
+
192
+ expect(dashboardFetchSpy.mock.calls).toHaveLength(2);
193
+ expect(routedFetchSpy.mock.calls).toHaveLength(0);
194
+ });
195
+
196
+ /*
197
+ * A ModelAPI subclass (StatusPageModelAPI) changes the DEFAULT client; a
198
+ * request that names its own client still wins, and one that does not keeps
199
+ * the subclass's default rather than falling back to the dashboard client.
200
+ */
201
+ test("a routed client wins over a subclass's default, which still applies otherwise", async () => {
202
+ await SubclassModelAPI.getList<Incident>({
203
+ modelType: Incident,
204
+ query: {},
205
+ limit: 10,
206
+ skip: 0,
207
+ select: { title: true },
208
+ sort: {},
209
+ requestOptions: {
210
+ overrideRequestUrl: URL.fromString(OVERRIDE_URL),
211
+ apiClient: RoutedAPI,
212
+ },
213
+ });
214
+
215
+ expect(routedFetchSpy.mock.calls).toHaveLength(1);
216
+ expect(subclassDefaultFetchSpy.mock.calls).toHaveLength(0);
217
+
218
+ await SubclassModelAPI.getList<Incident>({
219
+ modelType: Incident,
220
+ query: {},
221
+ limit: 10,
222
+ skip: 0,
223
+ select: { title: true },
224
+ sort: {},
225
+ requestOptions: { overrideRequestUrl: URL.fromString(OVERRIDE_URL) },
226
+ });
227
+
228
+ expect(subclassDefaultFetchSpy.mock.calls).toHaveLength(1);
229
+ expect(dashboardFetchSpy.mock.calls).toHaveLength(0);
230
+ });
231
+ });
232
+
233
+ /*
234
+ * A routed request is scoped by its own client, not by the viewer's dashboard
235
+ * project: the public dashboard's client sends an empty tenant, and a
236
+ * remembered (possibly stale or foreign) project would override it and turn
237
+ * the public read into a 405 (tenant not found).
238
+ */
239
+ describe("RequestOptions.apiClient and the viewer's dashboard project", () => {
240
+ beforeEach(() => {
241
+ const project: Project = new Project();
242
+ project.id = new ObjectID(VIEWER_PROJECT_ID);
243
+
244
+ // ModelAPI reads the id; AnalyticsModelAPI reads the stored project.
245
+ jest
246
+ .spyOn(ProjectUtil, "getCurrentProjectId")
247
+ .mockReturnValue(new ObjectID(VIEWER_PROJECT_ID));
248
+ jest.spyOn(ProjectUtil, "getCurrentProject").mockReturnValue(project);
249
+ });
250
+
251
+ test("a routed request does not carry the viewer's tenant", () => {
252
+ const modelHeaders: Dictionary<string> = ModelAPI.getCommonHeaders({
253
+ overrideRequestUrl: URL.fromString(OVERRIDE_URL),
254
+ apiClient: RoutedAPI,
255
+ });
256
+
257
+ const analyticsHeaders: Dictionary<string> =
258
+ AnalyticsModelAPI.getCommonHeaders({
259
+ overrideRequestUrl: URL.fromString(OVERRIDE_URL),
260
+ apiClient: RoutedAPI,
261
+ });
262
+
263
+ expect(modelHeaders["tenantid"]).toBeUndefined();
264
+ expect(analyticsHeaders["tenantid"]).toBeUndefined();
265
+ });
266
+
267
+ test("every other request still carries it", () => {
268
+ expect(ModelAPI.getCommonHeaders()["tenantid"]).toBe(VIEWER_PROJECT_ID);
269
+ expect(
270
+ ModelAPI.getCommonHeaders({
271
+ overrideRequestUrl: URL.fromString(OVERRIDE_URL),
272
+ })["tenantid"],
273
+ ).toBe(VIEWER_PROJECT_ID);
274
+ expect(AnalyticsModelAPI.getCommonHeaders()["tenantid"]).toBe(
275
+ VIEWER_PROJECT_ID,
276
+ );
277
+ });
278
+ });
@@ -317,3 +317,36 @@ describe("Navigation internal route safety", () => {
317
317
  expect(window.location.hash).toBe("#forced");
318
318
  });
319
319
  });
320
+
321
+ describe("Navigation current route", () => {
322
+ const clearRouterLocation: () => void = (): void => {
323
+ (Navigation as unknown as { location: unknown }).location = undefined;
324
+ };
325
+
326
+ afterEach(() => {
327
+ clearRouterLocation();
328
+ window.history.replaceState(null, "", "/");
329
+ });
330
+
331
+ test("reads the address bar before the router has provided a location", () => {
332
+ clearRouterLocation();
333
+ window.history.replaceState(null, "", "/status-page/abc/login?x=1");
334
+
335
+ expect(Navigation.getCurrentRoute().toString()).toBe(
336
+ "/status-page/abc/login",
337
+ );
338
+ });
339
+
340
+ test("prefers the router's location once it has been set", () => {
341
+ window.history.replaceState(null, "", "/from-the-address-bar");
342
+ Navigation.setLocation({
343
+ pathname: "/from-the-router",
344
+ search: "",
345
+ hash: "",
346
+ state: null,
347
+ key: "navigation-current-route",
348
+ });
349
+
350
+ expect(Navigation.getCurrentRoute().toString()).toBe("/from-the-router");
351
+ });
352
+ });
@@ -0,0 +1,295 @@
1
+ import { afterEach, beforeEach, describe, expect, it } from "@jest/globals";
2
+ import PricingPlan from "../../../UI/Utils/PricingPlan";
3
+ import PricingPlanType from "../../../Types/PricingPlan";
4
+ import BadDataException from "../../../Types/Exception/BadDataException";
5
+
6
+ /*
7
+ * PricingPlan picks between two hard-coded Stripe catalogues based on whether
8
+ * the public Stripe key is a test key. `env()` reads process.env on every call,
9
+ * so each test can switch environment by setting STRIPE_PUBLIC_KEY.
10
+ */
11
+
12
+ const TEST_PLAN_IDS: Array<string> = [
13
+ "plan_GoWIYiX2L8hwzx",
14
+ "plan_GoWIqpBpStiqQp",
15
+ "plan_GoWKgxRnPPBJWy",
16
+ "plan_GoWKiTdQ6NiQFw",
17
+ "plan_H9Iox3l2YqLTDR",
18
+ "plan_H9IlBKhsFz4hV2",
19
+ ];
20
+
21
+ const LIVE_PLAN_IDS: Array<string> = [
22
+ "plan_GoVgVbvNdbWwlm",
23
+ "plan_GoVgJu5PKMLRJU",
24
+ "plan_GoVi9EIa6MU0fG",
25
+ "plan_GoViZshjqzZ0vv",
26
+ "plan_H9Ii6Qj3HLdtty",
27
+ "plan_H9IjvX2Flsvlcg",
28
+ ];
29
+
30
+ const getPlanIds: () => Array<string> = (): Array<string> => {
31
+ return PricingPlan.getPlans().map((plan: PricingPlanType) => {
32
+ return plan.planId;
33
+ });
34
+ };
35
+
36
+ const firstDollarAmount: (details: string) => number = (
37
+ details: string,
38
+ ): number => {
39
+ const match: RegExpMatchArray | null = details.match(/\$(\d+)/);
40
+ expect(match).not.toBeNull();
41
+ return Number((match as RegExpMatchArray)[1]);
42
+ };
43
+
44
+ describe("UI PricingPlan util", () => {
45
+ let originalStripeKey: string | undefined;
46
+
47
+ beforeEach(() => {
48
+ originalStripeKey = process.env["STRIPE_PUBLIC_KEY"];
49
+ delete process.env["STRIPE_PUBLIC_KEY"];
50
+ });
51
+
52
+ afterEach(() => {
53
+ if (originalStripeKey === undefined) {
54
+ delete process.env["STRIPE_PUBLIC_KEY"];
55
+ } else {
56
+ process.env["STRIPE_PUBLIC_KEY"] = originalStripeKey;
57
+ }
58
+ });
59
+
60
+ describe("getPlans environment selection", () => {
61
+ it("returns the live catalogue when no Stripe key is configured", () => {
62
+ expect(getPlanIds()).toEqual(LIVE_PLAN_IDS);
63
+ });
64
+
65
+ it("returns the live catalogue for an empty Stripe key", () => {
66
+ process.env["STRIPE_PUBLIC_KEY"] = "";
67
+ expect(getPlanIds()).toEqual(LIVE_PLAN_IDS);
68
+ });
69
+
70
+ it("returns the live catalogue for a live Stripe key", () => {
71
+ process.env["STRIPE_PUBLIC_KEY"] = "pk_live_abc123";
72
+ expect(getPlanIds()).toEqual(LIVE_PLAN_IDS);
73
+ });
74
+
75
+ it("returns the test catalogue for a pk_test key", () => {
76
+ process.env["STRIPE_PUBLIC_KEY"] = "pk_test_abc123";
77
+ expect(getPlanIds()).toEqual(TEST_PLAN_IDS);
78
+ });
79
+
80
+ it("only treats a pk_test PREFIX as a test key", () => {
81
+ process.env["STRIPE_PUBLIC_KEY"] = "xpk_test_abc";
82
+ expect(getPlanIds()).toEqual(LIVE_PLAN_IDS);
83
+
84
+ process.env["STRIPE_PUBLIC_KEY"] = "PK_TEST_abc";
85
+ expect(getPlanIds()).toEqual(LIVE_PLAN_IDS);
86
+ });
87
+
88
+ it("re-evaluates the environment on every call", () => {
89
+ process.env["STRIPE_PUBLIC_KEY"] = "pk_test_1";
90
+ expect(getPlanIds()).toEqual(TEST_PLAN_IDS);
91
+
92
+ process.env["STRIPE_PUBLIC_KEY"] = "pk_live_1";
93
+ expect(getPlanIds()).toEqual(LIVE_PLAN_IDS);
94
+ });
95
+
96
+ it("returns a fresh array each call so callers cannot corrupt the catalogue", () => {
97
+ const first: Array<PricingPlanType> = PricingPlan.getPlans();
98
+ first.pop();
99
+ (first[0] as PricingPlanType).amount = 1;
100
+
101
+ const second: Array<PricingPlanType> = PricingPlan.getPlans();
102
+ expect(second).toHaveLength(6);
103
+ expect((second[0] as PricingPlanType).amount).toBe(25);
104
+ });
105
+ });
106
+
107
+ describe.each([
108
+ ["live", "pk_live_x"],
109
+ ["test", "pk_test_x"],
110
+ ])("%s catalogue shape", (_label: string, key: string) => {
111
+ beforeEach(() => {
112
+ process.env["STRIPE_PUBLIC_KEY"] = key;
113
+ });
114
+
115
+ it("has unique plan ids", () => {
116
+ const ids: Array<string> = getPlanIds();
117
+ expect(new Set(ids).size).toBe(ids.length);
118
+ });
119
+
120
+ it("offers exactly a monthly and an annual plan for each category", () => {
121
+ const plans: Array<PricingPlanType> = PricingPlan.getPlans();
122
+ const categories: Array<string> = ["Startup", "Growth", "Scale"];
123
+
124
+ expect(
125
+ Array.from(
126
+ new Set(
127
+ plans.map((plan: PricingPlanType) => {
128
+ return plan.category;
129
+ }),
130
+ ),
131
+ ),
132
+ ).toEqual(categories);
133
+
134
+ for (const category of categories) {
135
+ const types: Array<string> = plans
136
+ .filter((plan: PricingPlanType) => {
137
+ return plan.category === category;
138
+ })
139
+ .map((plan: PricingPlanType) => {
140
+ return plan.type;
141
+ })
142
+ .sort();
143
+
144
+ expect(types).toEqual(["annual", "month"]);
145
+ }
146
+ });
147
+
148
+ it("prices tiers in ascending order and makes annual cheaper per month", () => {
149
+ const plans: Array<PricingPlanType> = PricingPlan.getPlans();
150
+ const monthly: Array<number> = plans
151
+ .filter((plan: PricingPlanType) => {
152
+ return plan.type === "month";
153
+ })
154
+ .map((plan: PricingPlanType) => {
155
+ return plan.amount;
156
+ });
157
+
158
+ expect(monthly).toEqual([25, 59, 99]);
159
+
160
+ for (const plan of plans.filter((p: PricingPlanType) => {
161
+ return p.type === "annual";
162
+ })) {
163
+ const monthlyPlan: PricingPlanType = plans.find(
164
+ (p: PricingPlanType) => {
165
+ return p.category === plan.category && p.type === "month";
166
+ },
167
+ ) as PricingPlanType;
168
+
169
+ /*
170
+ * Compared with the ADVERTISED monthly price: because the monthly
171
+ * Scale plan charges 99 (not the advertised 120), Scale annual is
172
+ * exactly equal to the charged monthly amount (1188 / 12 === 99).
173
+ */
174
+ expect(plan.amount / 12).toBeLessThan(
175
+ firstDollarAmount(monthlyPlan.details),
176
+ );
177
+ expect(plan.amount / 12).toBeLessThanOrEqual(monthlyPlan.amount);
178
+ }
179
+ });
180
+
181
+ it("annual amount equals 12x the advertised per-month price", () => {
182
+ const annualPlans: Array<PricingPlanType> = PricingPlan.getPlans().filter(
183
+ (plan: PricingPlanType) => {
184
+ return plan.type === "annual";
185
+ },
186
+ );
187
+
188
+ for (const plan of annualPlans) {
189
+ expect(plan.amount).toBe(firstDollarAmount(plan.details) * 12);
190
+ expect(plan.details).toContain("paid annually");
191
+ }
192
+ });
193
+
194
+ it("monthly Startup and Growth amounts match their advertised price", () => {
195
+ const plans: Array<PricingPlanType> = PricingPlan.getPlans();
196
+
197
+ for (const category of ["Startup", "Growth"]) {
198
+ const plan: PricingPlanType = plans.find((p: PricingPlanType) => {
199
+ return p.category === category && p.type === "month";
200
+ }) as PricingPlanType;
201
+
202
+ expect(plan.amount).toBe(firstDollarAmount(plan.details));
203
+ }
204
+ });
205
+
206
+ /*
207
+ * The monthly Scale plan charges 99 but advertises "$120 / Month / User".
208
+ * Pinned here so the discrepancy is visible; see the report.
209
+ */
210
+ it("monthly Scale plan amount (99) differs from its advertised price ($120)", () => {
211
+ const plan: PricingPlanType = PricingPlan.getPlans().find(
212
+ (p: PricingPlanType) => {
213
+ return p.category === "Scale" && p.type === "month";
214
+ },
215
+ ) as PricingPlanType;
216
+
217
+ expect(plan.amount).toBe(99);
218
+ expect(firstDollarAmount(plan.details)).toBe(120);
219
+ });
220
+ });
221
+
222
+ describe("getPlanById", () => {
223
+ it("returns the matching live plan", () => {
224
+ process.env["STRIPE_PUBLIC_KEY"] = "pk_live_x";
225
+
226
+ expect(PricingPlan.getPlanById("plan_GoVi9EIa6MU0fG")).toEqual({
227
+ category: "Growth",
228
+ planId: "plan_GoVi9EIa6MU0fG",
229
+ type: "month",
230
+ amount: 59,
231
+ details: "$59 / Month / User",
232
+ });
233
+ });
234
+
235
+ it("returns the matching test plan", () => {
236
+ process.env["STRIPE_PUBLIC_KEY"] = "pk_test_x";
237
+
238
+ expect(PricingPlan.getPlanById("plan_H9IlBKhsFz4hV2")).toEqual({
239
+ category: "Scale",
240
+ planId: "plan_H9IlBKhsFz4hV2",
241
+ type: "annual",
242
+ amount: 1188,
243
+ details: "$99/mo per user paid annually. ",
244
+ });
245
+ });
246
+
247
+ it("resolves every plan id in the active catalogue", () => {
248
+ process.env["STRIPE_PUBLIC_KEY"] = "pk_test_x";
249
+ for (const id of TEST_PLAN_IDS) {
250
+ expect(PricingPlan.getPlanById(id).planId).toBe(id);
251
+ }
252
+
253
+ process.env["STRIPE_PUBLIC_KEY"] = "pk_live_x";
254
+ for (const id of LIVE_PLAN_IDS) {
255
+ expect(PricingPlan.getPlanById(id).planId).toBe(id);
256
+ }
257
+ });
258
+
259
+ it("does not resolve a test plan id when running against live Stripe", () => {
260
+ process.env["STRIPE_PUBLIC_KEY"] = "pk_live_x";
261
+
262
+ expect(() => {
263
+ PricingPlan.getPlanById("plan_GoWIYiX2L8hwzx");
264
+ }).toThrow(BadDataException);
265
+ });
266
+
267
+ it("does not resolve a live plan id when running against test Stripe", () => {
268
+ process.env["STRIPE_PUBLIC_KEY"] = "pk_test_x";
269
+
270
+ expect(() => {
271
+ PricingPlan.getPlanById("plan_GoVgVbvNdbWwlm");
272
+ }).toThrow(BadDataException);
273
+ });
274
+
275
+ it("throws a BadDataException naming the unknown id", () => {
276
+ expect(() => {
277
+ PricingPlan.getPlanById("plan_does_not_exist");
278
+ }).toThrow("Plan with id plan_does_not_exist not found");
279
+ });
280
+
281
+ it("does not match on empty or partial ids", () => {
282
+ expect(() => {
283
+ PricingPlan.getPlanById("");
284
+ }).toThrow(BadDataException);
285
+
286
+ expect(() => {
287
+ PricingPlan.getPlanById("plan_GoVgVbvNdbWwl");
288
+ }).toThrow(BadDataException);
289
+
290
+ expect(() => {
291
+ PricingPlan.getPlanById("PLAN_GOVGVBVNDBWWLM");
292
+ }).toThrow(BadDataException);
293
+ });
294
+ });
295
+ });