@oneuptime/common 12.0.32 → 12.0.34

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 (1191) hide show
  1. package/Models/AnalyticsModels/RumSession.ts +117 -1
  2. package/Models/AnalyticsModels/RumSessionChunk.ts +13 -0
  3. package/Models/AnalyticsModels/Span.ts +14 -0
  4. package/Models/DatabaseModels/AlertCustomField.ts +77 -3
  5. package/Models/DatabaseModels/ApiKeyPermission.ts +3 -27
  6. package/Models/DatabaseModels/EnterpriseLicense.ts +56 -0
  7. package/Models/DatabaseModels/IncidentCustomField.ts +77 -3
  8. package/Models/DatabaseModels/Index.ts +10 -0
  9. package/Models/DatabaseModels/InventoryItemCustomField.ts +77 -3
  10. package/Models/DatabaseModels/Monitor.ts +76 -0
  11. package/Models/DatabaseModels/MonitorCustomField.ts +77 -3
  12. package/Models/DatabaseModels/NetworkAlertPolicy.ts +690 -0
  13. package/Models/DatabaseModels/NetworkDevice.ts +176 -1
  14. package/Models/DatabaseModels/NetworkSite.ts +201 -2
  15. package/Models/DatabaseModels/NetworkSiteType.ts +102 -3
  16. package/Models/DatabaseModels/NetworkSnmpCredentialProfile.ts +841 -0
  17. package/Models/DatabaseModels/OnCallDutyPolicyCustomField.ts +77 -3
  18. package/Models/DatabaseModels/RumApplication.ts +6 -6
  19. package/Models/DatabaseModels/ScheduledMaintenanceCustomField.ts +77 -3
  20. package/Models/DatabaseModels/StatusPageCustomField.ts +77 -3
  21. package/Models/DatabaseModels/TeamCustomField.ts +77 -3
  22. package/Models/DatabaseModels/TeamMember.ts +0 -9
  23. package/Models/DatabaseModels/TeamMemberCustomField.ts +77 -3
  24. package/Models/DatabaseModels/TeamPermission.ts +3 -24
  25. package/Models/DatabaseModels/TelemetryException.ts +119 -0
  26. package/Models/DatabaseModels/TelemetryIngestionKey.ts +260 -0
  27. package/Models/DatabaseModels/UserNotificationEmailRollupBatch.ts +334 -0
  28. package/Models/DatabaseModels/UserNotificationEmailRollupItem.ts +370 -0
  29. package/Models/DatabaseModels/UserNotificationEmailRollupSetting.ts +282 -0
  30. package/Models/DatabaseModels/UserTelegram.ts +0 -4
  31. package/Scripts/benchmark-fanin-capacity.js +181 -0
  32. package/Server/API/EnterpriseLicenseAPI.ts +391 -64
  33. package/Server/API/LlmProviderAPI.ts +137 -22
  34. package/Server/API/TelemetryAPI.ts +1284 -164
  35. package/Server/API/UserNotificationSettingAPI.ts +55 -0
  36. package/Server/API/UserTelegramAPI.ts +48 -4
  37. package/Server/EnvironmentConfig.ts +49 -2
  38. package/Server/Infrastructure/Postgres/SchemaMigrations/1790700000000-AddNetworkSiteTypeParentHierarchy.ts +55 -0
  39. package/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddEnterpriseLicenseUsageProvenance.ts +31 -0
  40. package/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddTelemetryExceptionErrorClass.ts +124 -0
  41. package/Server/Infrastructure/Postgres/SchemaMigrations/1791000000000-AddUserNotificationEmailRollup.ts +132 -0
  42. package/Server/Infrastructure/Postgres/SchemaMigrations/1791100000000-AddUserNotificationEmailRollupSetting.ts +79 -0
  43. package/Server/Infrastructure/Postgres/SchemaMigrations/1791200000000-AddNetworkSnmpCredentialProfilesAndAlertPolicies.ts +191 -0
  44. package/Server/Infrastructure/Postgres/SchemaMigrations/1791300000000-AddTelemetryIngestionKeyType.ts +91 -0
  45. package/Server/Infrastructure/Postgres/SchemaMigrations/1791400000000-SessionReplayRecordEverySessionByDefault.ts +67 -0
  46. package/Server/Infrastructure/Postgres/SchemaMigrations/1791500000000-WidenCustomFieldDropdownOptions.ts +139 -0
  47. package/Server/Infrastructure/Postgres/SchemaMigrations/1791600000000-AddCustomFieldValueMapping.ts +121 -0
  48. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +20 -0
  49. package/Server/Infrastructure/QueueWorker.ts +59 -23
  50. package/Server/Infrastructure/Semaphore.ts +2 -0
  51. package/Server/Middleware/BearerTokenAuthorization.ts +12 -0
  52. package/Server/Middleware/ProjectAuthorization.ts +11 -0
  53. package/Server/Middleware/SCIMAuthorization.ts +12 -0
  54. package/Server/Middleware/TelemetryIngest.ts +464 -7
  55. package/Server/Services/AIBillingService.ts +101 -27
  56. package/Server/Services/AccessTokenService.ts +1 -0
  57. package/Server/Services/AlertCustomFieldService.ts +98 -0
  58. package/Server/Services/AlertService.ts +37 -0
  59. package/Server/Services/ApiKeyPermissionService.ts +461 -29
  60. package/Server/Services/CustomFieldMappingService.ts +879 -0
  61. package/Server/Services/EnterpriseLicenseInstanceService.ts +197 -0
  62. package/Server/Services/EnterpriseLicenseService.ts +55 -0
  63. package/Server/Services/GlobalConfigService.ts +194 -0
  64. package/Server/Services/IncidentCustomFieldService.ts +98 -0
  65. package/Server/Services/IncidentService.ts +35 -0
  66. package/Server/Services/Index.ts +10 -0
  67. package/Server/Services/MetricService.ts +194 -0
  68. package/Server/Services/MonitorService.ts +175 -21
  69. package/Server/Services/MonitorStatusTimelineService.ts +150 -8
  70. package/Server/Services/MonitorTemplateService.ts +217 -1
  71. package/Server/Services/NetworkAlertPolicyEngineService.ts +2159 -0
  72. package/Server/Services/NetworkAlertPolicyService.ts +944 -0
  73. package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +87 -35
  74. package/Server/Services/NetworkDeviceAutoImportRuleService.ts +60 -15
  75. package/Server/Services/NetworkDeviceService.ts +1032 -73
  76. package/Server/Services/NetworkSiteService.ts +1502 -129
  77. package/Server/Services/NetworkSiteTypeService.ts +1216 -0
  78. package/Server/Services/NetworkSnmpCredentialProfileService.ts +238 -0
  79. package/Server/Services/NotificationService.ts +118 -28
  80. package/Server/Services/ProjectService.ts +127 -48
  81. package/Server/Services/RoutineEmailSettingsService.ts +73 -0
  82. package/Server/Services/RumSessionReplayViewService.ts +104 -24
  83. package/Server/Services/ScheduledMaintenanceCustomFieldService.ts +98 -0
  84. package/Server/Services/ScheduledMaintenanceService.ts +32 -0
  85. package/Server/Services/StatusPagePrivateUserService.ts +103 -3
  86. package/Server/Services/TeamMemberService.ts +78 -0
  87. package/Server/Services/TeamPermissionService.ts +235 -3
  88. package/Server/Services/TelemetryIngestionKeyService.ts +722 -19
  89. package/Server/Services/UserNotificationEmailRollupBatchService.ts +78 -0
  90. package/Server/Services/UserNotificationEmailRollupItemService.ts +79 -0
  91. package/Server/Services/UserNotificationEmailRollupSettingService.ts +113 -0
  92. package/Server/Services/UserNotificationSettingService.ts +90 -25
  93. package/Server/Services/UserService.ts +95 -0
  94. package/Server/Services/UserTelegramService.ts +326 -5
  95. package/Server/Types/Database/QueryHelper.ts +4 -2
  96. package/Server/Utils/AI/Chat/ObservabilityChatPrompt.ts +14 -3
  97. package/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.ts +10 -0
  98. package/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.ts +10 -0
  99. package/Server/Utils/AI/SRE/Insights/InsightTriageRunner.ts +62 -1
  100. package/Server/Utils/AI/Toolbox/AlertTools.ts +15 -1
  101. package/Server/Utils/APIKey/AccessPermission.ts +5 -2
  102. package/Server/Utils/Billing/BillingFailureNoticeThrottle.ts +80 -0
  103. package/Server/Utils/CustomField/CustomFieldDefinitionMappingHooks.ts +54 -0
  104. package/Server/Utils/CustomField/CustomFieldMappingRegistry.ts +415 -0
  105. package/Server/Utils/CustomField/CustomFieldMappingValidator.ts +335 -0
  106. package/Server/Utils/DataSource/EgressGuard.ts +177 -8
  107. package/Server/Utils/DataSource/HttpFetch.ts +9 -2
  108. package/Server/Utils/EmailRollup/EmailRollupConstants.ts +131 -0
  109. package/Server/Utils/EmailRollup/EmailRollupFlushRunner.ts +925 -0
  110. package/Server/Utils/EmailRollup/EmailRollupRenderer.ts +781 -0
  111. package/Server/Utils/EmailRollup/EmailRollupWriter.ts +368 -0
  112. package/Server/Utils/FrontendEnvironment.ts +40 -0
  113. package/Server/Utils/LLM/LLMService.ts +78 -0
  114. package/Server/Utils/LogRedaction.ts +28 -0
  115. package/Server/Utils/Logger.ts +90 -1
  116. package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +338 -77
  117. package/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.ts +190 -0
  118. package/Server/Utils/Monitor/Criteria/EvaluateOverTime.ts +9 -2
  119. package/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.ts +30 -4
  120. package/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.ts +61 -1
  121. package/Server/Utils/Monitor/MonitorAlert.ts +29 -6
  122. package/Server/Utils/Monitor/MonitorCriteriaDataExtractor.ts +14 -0
  123. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +159 -15
  124. package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +255 -4
  125. package/Server/Utils/Monitor/MonitorIncident.ts +22 -6
  126. package/Server/Utils/Monitor/MonitorMetricUtil.ts +41 -0
  127. package/Server/Utils/Monitor/MonitorTemplateUtil.ts +72 -0
  128. package/Server/Utils/Monitor/NetworkDeviceHydrationUtil.ts +499 -19
  129. package/Server/Utils/Monitor/NetworkDeviceMetricUtil.ts +66 -10
  130. package/Server/Utils/Monitor/NetworkDeviceWalkUtil.ts +238 -44
  131. package/Server/Utils/Monitor/NetworkInventoryUtil.ts +146 -39
  132. package/Server/Utils/Monitor/SeriesContextEnricher.ts +304 -0
  133. package/Server/Utils/NetworkDevice/DeviceHealthAggregation.ts +31 -18
  134. package/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.ts +213 -0
  135. package/Server/Utils/OutboundUserAgent.ts +152 -0
  136. package/Server/Utils/SSRFProtection.ts +217 -10
  137. package/Server/Utils/SessionReplay/SessionReplayGateCache.ts +239 -138
  138. package/Server/Utils/SessionReplay/SessionReplayHealthCounters.ts +305 -0
  139. package/Server/Utils/SessionReplay/SessionReplayReadService.ts +1430 -289
  140. package/Server/Utils/StartServer.ts +53 -36
  141. package/Server/Utils/TelegramVerificationToken.ts +185 -0
  142. package/Server/Utils/Telemetry/CaptureSpan.ts +32 -8
  143. package/Server/Utils/Telemetry/ErrorClassResolver.ts +120 -0
  144. package/Server/Utils/Telemetry/PinServiceName.ts +197 -0
  145. package/Server/Utils/Telemetry/SpanUtil.ts +33 -0
  146. package/Server/Utils/Telemetry/TelemetryFanInWriter.ts +38 -16
  147. package/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.ts +92 -0
  148. package/Server/Utils/Telemetry/TelemetryIngestionKeyRateLimiter.ts +217 -0
  149. package/Server/Utils/Telemetry.ts +198 -51
  150. package/Server/Utils/VM/VMAPI.ts +1 -0
  151. package/Server/Utils/VM/VMRunner.ts +975 -95
  152. package/Server/Views/Partials/SensitiveUrlToken.ejs +140 -0
  153. package/Tests/App/AdminDashboard/AdminHeaderSmallScreens.test.tsx +202 -0
  154. package/Tests/App/Dashboard/AddNeighborToMonitoringModal.test.tsx +134 -33
  155. package/Tests/App/Dashboard/AskAiSuggestedPrompts.test.ts +279 -0
  156. package/Tests/App/Dashboard/DashboardEditPermissions.test.tsx +517 -0
  157. package/Tests/App/Dashboard/DashboardHeaderSmallScreens.test.tsx +404 -0
  158. package/Tests/App/Dashboard/DashboardVariablesDiscard.test.tsx +26 -0
  159. package/Tests/App/Dashboard/DeviceStatusHero.test.tsx +588 -0
  160. package/Tests/App/Dashboard/DiscoveryScanWizardValidation.test.tsx +486 -9
  161. package/Tests/App/Dashboard/MonitorCreateFromMonitorBackedDevice.test.tsx +632 -0
  162. package/Tests/App/Dashboard/MonitorRecommendationCreateProgress.test.tsx +682 -0
  163. package/Tests/App/Dashboard/MonitorTypePicker.test.tsx +4 -2
  164. package/Tests/App/Dashboard/NetworkDeviceCreateFormMonitorBinding.test.tsx +676 -0
  165. package/Tests/App/Dashboard/NetworkDeviceCreateFormPingMonitor.test.tsx +791 -0
  166. package/Tests/App/Dashboard/NetworkDeviceCreateFormProbeAndSnmp.test.tsx +833 -0
  167. package/Tests/App/Dashboard/NetworkDeviceCriteriaFilter.test.ts +161 -0
  168. package/Tests/App/Dashboard/NetworkDeviceSettingsMonitoringSection.test.tsx +458 -0
  169. package/Tests/App/Dashboard/NetworkSideMenu.test.tsx +41 -5
  170. package/Tests/App/Dashboard/NotificationEmailPreferences.test.tsx +399 -0
  171. package/Tests/App/Dashboard/PingMonitorProvisioning.test.ts +368 -0
  172. package/Tests/App/Dashboard/RecommendationCard.test.tsx +796 -0
  173. package/Tests/App/Dashboard/RecommendationToolbar.test.tsx +519 -0
  174. package/Tests/App/Dashboard/RecommendationsList.test.tsx +661 -0
  175. package/Tests/App/Dashboard/UseBulkCreatePingMonitors.test.tsx +899 -0
  176. package/Tests/App/Dashboard/UseBulkSnmpCredentialProfileActions.test.tsx +732 -0
  177. package/Tests/App/SensitiveUrlTokenBootstrap.test.ts +256 -0
  178. package/Tests/App/StatusPage/StatusPageIndexPageRobotsMeta.test.ts +11 -1
  179. package/Tests/App/StatusPage/StatusPageLastUpdated.test.tsx +263 -0
  180. package/Tests/App/StatusPage/StatusPageLoginCodeBootstrap.test.ts +9 -4
  181. package/Tests/App/StatusPage/StatusPageOverviewLiveAndSearch.test.tsx +753 -0
  182. package/Tests/App/StatusPage/StatusPageResourceSearchBox.test.tsx +224 -0
  183. package/Tests/Models/AnalyticsModels/RumSessionReplayColumns.test.ts +262 -0
  184. package/Tests/Models/CustomFieldMappingColumns.test.ts +166 -0
  185. package/Tests/Models/DatabaseModels/SessionReplayModels.test.ts +20 -6
  186. package/Tests/Models/NetworkSiteHierarchy.test.ts +41 -4
  187. package/Tests/ResponsiveVisibility.test.ts +115 -0
  188. package/Tests/ResponsiveVisibility.ts +183 -0
  189. package/Tests/Server/API/EnterpriseLicenseReportUserCount.test.ts +951 -7
  190. package/Tests/Server/API/LlmProviderConnectionTest.test.ts +522 -0
  191. package/Tests/Server/API/SessionReplayAPI.test.ts +1940 -216
  192. package/Tests/Server/API/UserNotificationSettingAPI.test.ts +186 -0
  193. package/Tests/Server/API/UserTelegramAPISecurity.test.ts +231 -0
  194. package/Tests/Server/EnvironmentConfigFrontendSecurity.test.ts +234 -0
  195. package/Tests/Server/Infrastructure/Postgres/CustomFieldValueMappingMigration.test.ts +202 -0
  196. package/Tests/Server/Infrastructure/Postgres/InventoryItemArchiveMigration.test.ts +41 -0
  197. package/Tests/Server/Infrastructure/Postgres/NetworkSnmpCredentialProfilesAndAlertPoliciesMigration.test.ts +854 -0
  198. package/Tests/Server/Infrastructure/Postgres/SchemaMigrationsOrdering.test.ts +18 -0
  199. package/Tests/Server/Infrastructure/Postgres/SessionReplayRecordEverySessionByDefaultMigration.test.ts +169 -0
  200. package/Tests/Server/Infrastructure/Postgres/UserNotificationEmailRollupTableMigration.test.ts +535 -0
  201. package/Tests/Server/Infrastructure/QueueWorkerTimeout.test.ts +210 -0
  202. package/Tests/Server/Infrastructure/TelemetryExporterDeploymentConfig.test.ts +130 -0
  203. package/Tests/Server/Middleware/ProjectAuthorizationApiKeyMiddleware.test.ts +4 -1
  204. package/Tests/Server/Middleware/TelemetryIngestBrowserKey.test.ts +1163 -0
  205. package/Tests/Server/Middleware/TelemetryIngestTokenLog.test.ts +5 -3
  206. package/Tests/Server/Services/AIChatPrivacyPin.test.ts +560 -0
  207. package/Tests/Server/Services/AddTelemetryIngestionKeyTypeMigration.test.ts +555 -0
  208. package/Tests/Server/Services/ApiKeyPermissionSecurity.test.ts +678 -0
  209. package/Tests/Server/Services/ApiKeyPermissionService.test.ts +276 -28
  210. package/Tests/Server/Services/BillingRechargeOwnerEmailGuards.test.ts +783 -0
  211. package/Tests/Server/Services/CustomFieldDropdownOptionsColumnWidth.test.ts +431 -0
  212. package/Tests/Server/Services/CustomFieldMappingService.test.ts +850 -0
  213. package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +32 -0
  214. package/Tests/Server/Services/EnterpriseLicenseInstanceServiceDeletionUsage.test.ts +707 -0
  215. package/Tests/Server/Services/EnterpriseLicenseServiceUsageAggregationLock.test.ts +329 -0
  216. package/Tests/Server/Services/GlobalConfigService.test.ts +414 -1
  217. package/Tests/Server/Services/MetricRawEntityKeyPrune.test.ts +592 -0
  218. package/Tests/Server/Services/MonitorServiceDeleteNetworkDeviceCleanup.test.ts +294 -0
  219. package/Tests/Server/Services/MonitorStatusBridgeProbePath.test.ts +802 -0
  220. package/Tests/Server/Services/MonitorStatusTimelineService.test.ts +72 -2
  221. package/Tests/Server/Services/NetworkAlertPolicyEngineHooks.test.ts +752 -0
  222. package/Tests/Server/Services/NetworkAlertPolicyEngineService.test.ts +1849 -0
  223. package/Tests/Server/Services/NetworkAlertPolicyModel.test.ts +1793 -0
  224. package/Tests/Server/Services/NetworkDeviceAutoImportRuleEngineService.test.ts +273 -5
  225. package/Tests/Server/Services/NetworkDeviceAutoImportRuleService.test.ts +97 -12
  226. package/Tests/Server/Services/NetworkDeviceAutoMonitorLifecycle.test.ts +148 -3
  227. package/Tests/Server/Services/NetworkDeviceMonitorBindingUpdateGuard.test.ts +514 -0
  228. package/Tests/Server/Services/NetworkDeviceMonitorStatusStamp.test.ts +447 -58
  229. package/Tests/Server/Services/NetworkDeviceMonitoringMethodTransition.test.ts +739 -0
  230. package/Tests/Server/Services/NetworkDevicePollingTenancy.test.ts +501 -0
  231. package/Tests/Server/Services/NetworkDeviceSiteDefaultProbe.test.ts +432 -0
  232. package/Tests/Server/Services/NetworkSiteMonitoringDefaults.test.ts +498 -0
  233. package/Tests/Server/Services/NetworkSiteRollupPolicyAndMaintenance.test.ts +337 -55
  234. package/Tests/Server/Services/NetworkSiteService.test.ts +1868 -131
  235. package/Tests/Server/Services/NetworkSiteTypeService.test.ts +1109 -0
  236. package/Tests/Server/Services/NetworkSnmpCredentialProfileModel.test.ts +926 -0
  237. package/Tests/Server/Services/NetworkSnmpCredentialProfileService.test.ts +796 -0
  238. package/Tests/Server/Services/ProjectServiceNetworkSiteTypeDefaults.test.ts +214 -0
  239. package/Tests/Server/Services/RoutineEmailSettingsPostgres.test.ts +329 -0
  240. package/Tests/Server/Services/RumSessionReplayViewService.test.ts +267 -0
  241. package/Tests/Server/Services/StatusPagePrivateUserEmailChangePasswordResetExpiry.test.ts +269 -0
  242. package/Tests/Server/Services/TeamMemberAutoAcceptInvitation.test.ts +9 -0
  243. package/Tests/Server/Services/TeamMemberInviteRegistrationToken.test.ts +9 -0
  244. package/Tests/Server/Services/TeamPrivilegeEscalation.test.ts +834 -0
  245. package/Tests/Server/Services/TelemetryIngestionKeyPolicyResolution.test.ts +814 -0
  246. package/Tests/Server/Services/TelemetryIngestionKeyValidation.test.ts +998 -0
  247. package/Tests/Server/Services/UserEmailChangePasswordResetExpiry.test.ts +472 -0
  248. package/Tests/Server/Services/UserNotificationEmailRollupModels.test.ts +569 -0
  249. package/Tests/Server/Services/UserNotificationEmailRollupSettingModel.test.ts +314 -0
  250. package/Tests/Server/Services/UserNotificationEmailRollupSettingService.test.ts +409 -0
  251. package/Tests/Server/Services/UserNotificationSettingRollupRouting.test.ts +997 -0
  252. package/Tests/Server/Services/UserNotificationSettingWorkspaceChannels.test.ts +110 -1
  253. package/Tests/Server/Services/UserTelegramVerificationSecurity.test.ts +688 -0
  254. package/Tests/Server/Types/Database/Permissions/DashboardAccessPermission.test.ts +321 -0
  255. package/Tests/Server/Types/Database/QueryHelperOperators.test.ts +17 -0
  256. package/Tests/Server/Utils/AI/AlertMonitorFilters.test.ts +124 -0
  257. package/Tests/Server/Utils/AI/Insights/InsightTriageRunner.test.ts +208 -0
  258. package/Tests/Server/Utils/AI/LLMServiceToolCalling.test.ts +235 -0
  259. package/Tests/Server/Utils/AI/ObservabilityChatPrompt.test.ts +253 -0
  260. package/Tests/Server/Utils/AI/SRE/Insights/FixRouting.test.ts +497 -0
  261. package/Tests/Server/Utils/AI/Toolbox/Serializer.test.ts +383 -0
  262. package/Tests/Server/Utils/APIKey/AccessPermission.test.ts +7 -3
  263. package/Tests/Server/Utils/AnalyticsDatabase/ClusterConfig.test.ts +315 -0
  264. package/Tests/Server/Utils/Captcha.test.ts +422 -0
  265. package/Tests/Server/Utils/CustomField/CustomFieldMappingValidator.test.ts +437 -0
  266. package/Tests/Server/Utils/DataSource/EgressGuard.test.ts +300 -11
  267. package/Tests/Server/Utils/DataSource/HttpFetch.test.ts +96 -2
  268. package/Tests/Server/Utils/Database/MigrationFailureLog.test.ts +466 -0
  269. package/Tests/Server/Utils/EmailRollup/EmailRollupBurstWindow.test.ts +83 -0
  270. package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerBehaviour.test.ts +1096 -0
  271. package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerClaim.test.ts +466 -0
  272. package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerPreferences.test.ts +362 -0
  273. package/Tests/Server/Utils/EmailRollup/EmailRollupRenderer.test.ts +1428 -0
  274. package/Tests/Server/Utils/EmailRollup/EmailRollupTestHarness.ts +828 -0
  275. package/Tests/Server/Utils/EmailRollup/EmailRollupWriter.test.ts +864 -0
  276. package/Tests/Server/Utils/FrontendEnvironment.test.ts +190 -0
  277. package/Tests/Server/Utils/LogRedaction.test.ts +26 -0
  278. package/Tests/Server/Utils/LoggerCredentialLeak.test.ts +23 -9
  279. package/Tests/Server/Utils/LoggerFaultDemotion.test.ts +346 -0
  280. package/Tests/Server/Utils/Monitor/Criteria/CompareCriteriaAggregation.test.ts +584 -0
  281. package/Tests/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.test.ts +633 -0
  282. package/Tests/Server/Utils/Monitor/Criteria/IncomingRequestHeaderCriteria.test.ts +236 -0
  283. package/Tests/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.test.ts +196 -0
  284. package/Tests/Server/Utils/Monitor/DatabaseMetricWrite.test.ts +367 -0
  285. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +437 -0
  286. package/Tests/Server/Utils/Monitor/MonitorCriteriaObservationBuilderUnits.test.ts +100 -0
  287. package/Tests/Server/Utils/Monitor/MonitorStepResourceIdentity.test.ts +5 -0
  288. package/Tests/Server/Utils/Monitor/MonitorTemplateUtilSeriesContext.test.ts +176 -0
  289. package/Tests/Server/Utils/Monitor/NetworkDeviceHydrationUtil.test.ts +512 -31
  290. package/Tests/Server/Utils/Monitor/NetworkDeviceMetricUtil.test.ts +252 -0
  291. package/Tests/Server/Utils/Monitor/NetworkDeviceWalkUtil.test.ts +479 -42
  292. package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +351 -5
  293. package/Tests/Server/Utils/Monitor/SeriesContextEnricher.test.ts +356 -0
  294. package/Tests/Server/Utils/NetworkDevice/DeviceHealthAggregation.test.ts +136 -12
  295. package/Tests/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.test.ts +306 -0
  296. package/Tests/Server/Utils/OutboundUserAgent.test.ts +266 -0
  297. package/Tests/Server/Utils/SSRFProtectionCloudServiceAddresses.test.ts +595 -0
  298. package/Tests/Server/Utils/SecurityEvent/ThreatIntel/TaxiiClientUserAgent.test.ts +141 -0
  299. package/Tests/Server/Utils/SessionReplay/SessionReplayGateCachePolicy.test.ts +198 -1
  300. package/Tests/Server/Utils/SessionReplay/SessionReplayHealthCounters.test.ts +453 -0
  301. package/Tests/Server/Utils/SessionReplay/SessionReplayReadServiceQueries.test.ts +1378 -0
  302. package/Tests/Server/Utils/SessionReplayOriginAllowListRefactor.test.ts +420 -0
  303. package/Tests/Server/Utils/TelegramVerificationToken.test.ts +253 -0
  304. package/Tests/Server/Utils/Telemetry/ErrorClassResolver.test.ts +298 -0
  305. package/Tests/Server/Utils/Telemetry/PinServiceName.test.ts +666 -0
  306. package/Tests/Server/Utils/Telemetry/TelemetryFanInWriterCapacity.test.ts +458 -0
  307. package/Tests/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.test.ts +424 -0
  308. package/Tests/Server/Utils/Telemetry/TelemetryIngestionKeyRateLimiter.test.ts +528 -0
  309. package/Tests/Server/Utils/Telemetry.test.ts +456 -66
  310. package/Tests/Server/Utils/TelemetryExporterEnvironment.test.ts +56 -0
  311. package/Tests/Server/Utils/VM/VMRunnerHostBridgeLatency.test.ts +74 -0
  312. package/Tests/Server/Utils/VM/VMRunnerPrivateNetworkWiring.test.ts +100 -7
  313. package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +1176 -6
  314. package/Tests/Types/CustomField/CustomFieldMappingCatalog.test.ts +220 -0
  315. package/Tests/Types/CustomField/CustomFieldValueMapping.test.ts +348 -0
  316. package/Tests/Types/JSONFunctions.test.ts +260 -0
  317. package/Tests/Types/Monitor/CephAlertTemplates.test.ts +422 -53
  318. package/Tests/Types/Monitor/DatabaseMetricCatalog.test.ts +388 -0
  319. package/Tests/Types/Monitor/DockerAlertTemplates.test.ts +495 -15
  320. package/Tests/Types/Monitor/DockerSwarmAlertTemplates.test.ts +191 -45
  321. package/Tests/Types/Monitor/HostAlertTemplates.test.ts +370 -42
  322. package/Tests/Types/Monitor/IotAlertTemplates.test.ts +375 -20
  323. package/Tests/Types/Monitor/KubernetesAlertTemplates.test.ts +636 -42
  324. package/Tests/Types/Monitor/KubernetesMetricCatalog.test.ts +189 -0
  325. package/Tests/Types/Monitor/KubernetesTemplateGroupByKeys.test.ts +95 -14
  326. package/Tests/Types/Monitor/MonitorStepDatabaseMonitor.test.ts +243 -0
  327. package/Tests/Types/Monitor/MonitorStepDefaultTelemetryConfig.test.ts +1 -0
  328. package/Tests/Types/Monitor/MonitorType.test.ts +1 -0
  329. package/Tests/Types/Monitor/MonitorTypeKeywords.test.ts +16 -7
  330. package/Tests/Types/Monitor/NetworkDeviceAlertPack.test.ts +60 -0
  331. package/Tests/Types/Monitor/PodmanAlertTemplates.test.ts +190 -21
  332. package/Tests/Types/Monitor/ProxmoxAlertTemplates.test.ts +352 -22
  333. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationAlertDebuggability.test.ts +363 -0
  334. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +93 -18
  335. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.test.ts +259 -0
  336. package/Tests/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.test.ts +476 -0
  337. package/Tests/Types/Monitor/RumAlertTemplates.test.ts +136 -0
  338. package/Tests/Types/Monitor/SeriesContext/SeriesDebugHints.test.ts +661 -0
  339. package/Tests/Types/Monitor/SeriesContext/SeriesLabelDisplay.test.ts +507 -0
  340. package/Tests/Types/Monitor/ServiceAlertTemplates.test.ts +270 -0
  341. package/Tests/Types/Monitor/TemplateGroupByKeys.test.ts +38 -10
  342. package/Tests/Types/Monitor/Utils/RecommendationCriteriaAssertions.ts +102 -0
  343. package/Tests/Types/NetworkDevice/NetworkAlertPolicyScope.test.ts +655 -0
  344. package/Tests/Types/NetworkDevice/NetworkDeviceMonitoringMethod.test.ts +115 -26
  345. package/Tests/Types/NetworkSite/DefaultNetworkSiteType.test.ts +39 -0
  346. package/Tests/Types/NotificationSetting/NotificationEmailRollupPolicy.test.ts +299 -0
  347. package/Tests/Types/NotificationSetting/RoutineEmailEvents.test.ts +47 -0
  348. package/Tests/Types/Rum/SessionReplayApiContracts.test.ts +608 -0
  349. package/Tests/Types/Rum/SessionReplayCustomEvents.test.ts +434 -0
  350. package/Tests/Types/Telemetry/ErrorClass.test.ts +483 -0
  351. package/Tests/Types/WebsiteRequest.test.ts +285 -3
  352. package/Tests/UI/Components/BasicRadioButtons.test.tsx +336 -0
  353. package/Tests/UI/Components/Charts/ChartBucketIdentity.test.ts +16 -3
  354. package/Tests/UI/Components/Charts/ChartTrailingBucketGap.test.ts +691 -0
  355. package/Tests/UI/Components/ComponentsModal.test.tsx +12 -4
  356. package/Tests/UI/Components/ComponentsModalUsability.test.tsx +518 -0
  357. package/Tests/UI/Components/CustomFields/CustomFieldsDetailMapping.test.tsx +324 -0
  358. package/Tests/UI/Components/CustomFields/MapFromCustomFieldInput.test.tsx +176 -0
  359. package/Tests/UI/Components/Graphs/DayUptimeGraph.test.tsx +484 -0
  360. package/Tests/UI/Components/HeaderRightRail.test.tsx +157 -0
  361. package/Tests/UI/Components/IconDropdownItem.test.tsx +102 -0
  362. package/Tests/UI/Components/JSONTablePrototypePollution.test.tsx +117 -0
  363. package/Tests/UI/Components/KeyboardShortcutsModal.test.tsx +214 -0
  364. package/Tests/UI/Components/ModelTable/ModelTableWrapContent.test.tsx +561 -0
  365. package/Tests/UI/Components/MonitorGraphs/UptimeBarDayModal.test.tsx +302 -0
  366. package/Tests/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.test.ts +43 -12
  367. package/Tests/UI/Components/ProgressBar.test.tsx +38 -2
  368. package/Tests/UI/Components/ShortcutDialogGuard.test.tsx +74 -0
  369. package/Tests/UI/Components/SideMenuItem.test.tsx +226 -4
  370. package/Tests/UI/Components/SideMenuSection.test.tsx +310 -0
  371. package/Tests/UI/Components/SideOverSubmitState.test.tsx +335 -0
  372. package/Tests/UI/Components/StatusPage/ResourceGroupSectionAutoExpand.test.tsx +248 -0
  373. package/Tests/UI/Components/TableCellWrapping.test.tsx +625 -0
  374. package/Tests/UI/Components/TableLoadingStates.test.tsx +205 -0
  375. package/Tests/UI/Components/Workflow/NodePlacement.test.ts +148 -0
  376. package/Tests/UI/Components/Workflow/Workflow.test.tsx +981 -0
  377. package/Tests/UI/ConfigBrowserTelemetry.test.ts +70 -0
  378. package/Tests/UI/Rum/ChunkLoader.test.ts +1036 -2
  379. package/Tests/UI/Rum/FidelityNotices.test.ts +187 -0
  380. package/Tests/UI/Rum/InactivityMap.test.ts +341 -0
  381. package/Tests/UI/Rum/PrivacySummaryCard.test.tsx +259 -0
  382. package/Tests/UI/Rum/RecordingHealthCard.test.tsx +855 -0
  383. package/Tests/UI/Rum/RecordingHealthStrip.test.tsx +594 -0
  384. package/Tests/UI/Rum/ReplayCard.test.tsx +451 -0
  385. package/Tests/UI/Rum/ReplayCorrelationPanel.test.tsx +536 -0
  386. package/Tests/UI/Rum/ReplayEngine.test.ts +2503 -0
  387. package/Tests/UI/Rum/ReplayEngineTypes.test.ts +171 -0
  388. package/Tests/UI/Rum/ReplayHeader.test.tsx +711 -0
  389. package/Tests/UI/Rum/ReplayLink.test.tsx +119 -0
  390. package/Tests/UI/Rum/ReplayPinControl.test.tsx +408 -0
  391. package/Tests/UI/Rum/ReplayPlaybackIntent.test.ts +152 -0
  392. package/Tests/UI/Rum/ReplayRail.test.tsx +1296 -0
  393. package/Tests/UI/Rum/ReplayRailDetail.test.tsx +900 -0
  394. package/Tests/UI/Rum/ReplayScrubber.test.tsx +763 -147
  395. package/Tests/UI/Rum/ReplaySignalTypes.test.ts +189 -0
  396. package/Tests/UI/Rum/ReplaySignals.test.ts +1579 -0
  397. package/Tests/UI/Rum/ReplayStage.test.tsx +396 -473
  398. package/Tests/UI/Rum/ReplayStageOverlays.test.tsx +918 -0
  399. package/Tests/UI/Rum/ReplayTimeline.test.tsx +696 -0
  400. package/Tests/UI/Rum/SessionReplayEmptyState.test.tsx +499 -0
  401. package/Tests/UI/Rum/SessionReplaySearchBar.test.tsx +346 -0
  402. package/Tests/UI/Rum/SessionReplaySetupGuide.test.tsx +545 -0
  403. package/Tests/UI/Rum/SessionReplayTable.test.tsx +991 -0
  404. package/Tests/UI/Rum/TargetedCapturePanel.test.tsx +254 -0
  405. package/Tests/UI/Telemetry/BrowserExporterIsolation.test.ts +71 -0
  406. package/Tests/UI/Utils/GlobalKeyboardShortcut.test.ts +344 -0
  407. package/Tests/UI/Utils/PageScrollLock.test.tsx +377 -0
  408. package/Tests/UI/Utils/PermissionGate.test.ts +78 -0
  409. package/Tests/UI/Utils/SensitiveUrlToken.test.ts +140 -0
  410. package/Tests/Utils/API.test.ts +308 -0
  411. package/Tests/Utils/EnterpriseLicenseSeats.test.ts +69 -0
  412. package/Tests/Utils/EnterpriseLicenseSync.test.ts +7 -1
  413. package/Tests/Utils/EnterpriseLicenseUsage.test.ts +433 -2
  414. package/Tests/Utils/HTTPResponseBodyReader.test.ts +323 -0
  415. package/Tests/Utils/Monitor/MonitorMetricType.test.ts +280 -1
  416. package/Tests/Utils/Monitor/MonitorSummarySnapshotUtil.test.ts +1 -0
  417. package/Tests/Utils/Monitor/NetworkTopologyUtil.test.ts +38 -0
  418. package/Tests/Utils/NetworkDevice/DeviceHealthStateUtil.test.ts +284 -23
  419. package/Tests/Utils/NetworkDevice/DeviceReachabilityUtil.test.ts +177 -0
  420. package/Tests/Utils/NetworkDevice/MonitoringMethodThreadedClassifiers.test.ts +992 -0
  421. package/Tests/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.test.ts +427 -0
  422. package/Tests/Utils/NetworkDevice/ReachabilityStampConsistency.test.ts +185 -0
  423. package/Tests/Utils/NetworkDevice/SnmpCredentialUtil.test.ts +268 -0
  424. package/Tests/Utils/NetworkDiscovery/AutoImportRuleMatcher.test.ts +55 -5
  425. package/Tests/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.test.ts +98 -21
  426. package/Tests/Utils/NetworkDiscovery/DiscoveryImportEligibility.test.ts +98 -20
  427. package/Tests/Utils/NetworkDiscovery/DiscoveryReverseDnsChain.test.ts +8 -7
  428. package/Tests/Utils/NetworkDiscovery/DiscoveryScanStatus.test.ts +117 -0
  429. package/Tests/Utils/NetworkDiscovery/PingMonitorBuilderForAddress.test.ts +274 -0
  430. package/Tests/Utils/NetworkSite/SiteStatusRollupUtil.test.ts +230 -51
  431. package/Tests/Utils/NetworkSite/TypeHierarchyUtil.test.ts +209 -0
  432. package/Tests/Utils/Rum/ChunkMath.test.ts +83 -0
  433. package/Tests/Utils/Rum/SessionReplayHealthDiagnosis.test.ts +993 -0
  434. package/Tests/Utils/Rum/SessionReplayStringMap.test.ts +245 -0
  435. package/Tests/Utils/StatusPage/ResourceSearch.test.ts +631 -0
  436. package/Tests/Utils/Telemetry/CaptureSpanExportGating.test.ts +145 -0
  437. package/Tests/Utils/Telemetry/OriginAllowList.test.ts +633 -0
  438. package/Tests/Utils/Uptime/DayUptimeGraphUtil.test.ts +461 -0
  439. package/Tests/Utils/ValueFormatter.test.ts +148 -0
  440. package/Types/AI/ExceptionAIClassification.ts +10 -24
  441. package/Types/CustomField/CustomFieldMappingCatalog.ts +161 -0
  442. package/Types/CustomField/CustomFieldMappingSourceResource.ts +19 -0
  443. package/Types/CustomField/CustomFieldValueMapping.ts +288 -0
  444. package/Types/Email/EmailTemplateType.ts +2 -0
  445. package/Types/EnterpriseLicense/EnterpriseLicenseInstanceSummary.ts +5 -0
  446. package/Types/EnterpriseLicense/EnterpriseLicenseUsageSnapshot.ts +13 -0
  447. package/Types/EnterpriseLicense/EnterpriseLicenseUserCountSource.ts +6 -0
  448. package/Types/Exception/ApiException.ts +10 -0
  449. package/Types/Exception/BadDataException.ts +11 -0
  450. package/Types/Exception/BadRequestException.ts +11 -0
  451. package/Types/Exception/Exception.ts +65 -0
  452. package/Types/Exception/ForbiddenException.ts +10 -0
  453. package/Types/Exception/NotAuthenticatedException.ts +10 -0
  454. package/Types/Exception/NotAuthorizedException.ts +10 -0
  455. package/Types/Exception/NotFoundException.ts +11 -0
  456. package/Types/Exception/PayloadTooLargeException.ts +11 -0
  457. package/Types/Exception/PaymentRequiredException.ts +10 -0
  458. package/Types/Exception/ServiceUnavailableException.ts +10 -0
  459. package/Types/Exception/SsoAuthorizationException.ts +10 -0
  460. package/Types/Exception/TenantNotFoundException.ts +11 -0
  461. package/Types/Exception/TimeoutException.ts +10 -0
  462. package/Types/Exception/TooManyRequestsException.ts +10 -0
  463. package/Types/Exception/UnableToReachServer.ts +10 -0
  464. package/Types/Exception/WebsiteRequestException.ts +10 -0
  465. package/Types/Icon/IconProp.ts +1 -0
  466. package/Types/JSONFunctions.ts +189 -43
  467. package/Types/Monitor/CephAlertTemplates.ts +157 -195
  468. package/Types/Monitor/CriteriaFilter.ts +60 -2
  469. package/Types/Monitor/DatabaseMetricCatalog.ts +693 -0
  470. package/Types/Monitor/DatabaseMonitor/DatabaseMonitorResponse.ts +83 -0
  471. package/Types/Monitor/DockerAlertTemplates.ts +338 -128
  472. package/Types/Monitor/DockerSwarmAlertTemplates.ts +95 -112
  473. package/Types/Monitor/HostAlertTemplates.ts +302 -130
  474. package/Types/Monitor/IotAlertTemplates.ts +112 -104
  475. package/Types/Monitor/KubernetesAlertTemplates.ts +415 -224
  476. package/Types/Monitor/KubernetesMetricCatalog.ts +23 -19
  477. package/Types/Monitor/MonitorCriteriaInstance.ts +76 -0
  478. package/Types/Monitor/MonitorMetricType.ts +71 -0
  479. package/Types/Monitor/MonitorStep.ts +76 -0
  480. package/Types/Monitor/MonitorStepDatabaseMonitor.ts +171 -0
  481. package/Types/Monitor/MonitorStepSqlMonitor.ts +2 -20
  482. package/Types/Monitor/MonitorType.ts +47 -1
  483. package/Types/Monitor/PodmanAlertTemplates.ts +116 -163
  484. package/Types/Monitor/ProxmoxAlertTemplates.ts +217 -99
  485. package/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.ts +98 -6
  486. package/Types/Monitor/Recommendation/MonitorRecommendationUtil.ts +44 -7
  487. package/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.ts +383 -0
  488. package/Types/Monitor/RumAlertTemplates.ts +46 -7
  489. package/Types/Monitor/SeriesContext/SeriesDebugHints.ts +596 -0
  490. package/Types/Monitor/SeriesContext/SeriesLabelDisplay.ts +554 -0
  491. package/Types/Monitor/ServiceAlertTemplates.ts +98 -11
  492. package/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.ts +22 -1
  493. package/Types/Monitor/SqlConnectionConfig.ts +31 -0
  494. package/Types/Monitor/UptimeHistoryLabels.ts +56 -0
  495. package/Types/NetworkDevice/NetworkAlertPolicyScope.ts +343 -0
  496. package/Types/NetworkDevice/NetworkDeviceMonitoringMethod.ts +42 -22
  497. package/Types/NetworkSite/DefaultNetworkSiteTypeHierarchy.ts +30 -0
  498. package/Types/NotificationSetting/NotificationEmailRollupCategory.ts +255 -0
  499. package/Types/NotificationSetting/NotificationEmailRollupPolicy.ts +104 -0
  500. package/Types/NotificationSetting/RoutineEmailEvents.ts +30 -0
  501. package/Types/Permission.ts +90 -0
  502. package/Types/Probe/ProbeMonitorResponse.ts +16 -0
  503. package/Types/Rum/SessionReplay.ts +209 -0
  504. package/Types/Rum/SessionReplayApi.ts +722 -0
  505. package/Types/Rum/SessionReplayCaptureTrigger.ts +21 -12
  506. package/Types/Rum/SessionReplayConsentMode.ts +11 -7
  507. package/Types/Rum/SessionReplayCustomEvents.ts +549 -0
  508. package/Types/Rum/SessionReplayHealth.ts +238 -0
  509. package/Types/Telemetry/ErrorClass.ts +274 -0
  510. package/Types/Telemetry/TelemetryIngestSurface.ts +95 -0
  511. package/Types/Telemetry/TelemetryIngestionKeyPolicy.ts +75 -0
  512. package/Types/Telemetry/TelemetryIngestionKeyType.ts +29 -0
  513. package/Types/Telemetry/UnitOfWork.ts +59 -0
  514. package/Types/WebsiteRequest.ts +85 -3
  515. package/UI/Components/Charts/Area/AreaChart.tsx +13 -2
  516. package/UI/Components/Charts/Bar/BarChart.tsx +6 -2
  517. package/UI/Components/Charts/Line/LineChart.tsx +13 -2
  518. package/UI/Components/Charts/Types/XAxis/XAxis.ts +29 -0
  519. package/UI/Components/Charts/Utils/DataPoint.ts +22 -3
  520. package/UI/Components/Charts/Utils/TimeAnnotation.ts +76 -9
  521. package/UI/Components/Charts/Utils/XAxis.ts +217 -0
  522. package/UI/Components/CommandPalette/CommandPalette.tsx +2 -8
  523. package/UI/Components/CustomFields/CustomFieldsDetail.tsx +143 -25
  524. package/UI/Components/CustomFields/MapFromCustomFieldInput.tsx +216 -0
  525. package/UI/Components/EditionLabel/EditionLabel.tsx +4 -0
  526. package/UI/Components/Graphs/DayUptimeGraph.tsx +173 -8
  527. package/UI/Components/Graphs/UptimeBarTooltip.tsx +22 -278
  528. package/UI/Components/Graphs/UptimeDaySummary.tsx +327 -0
  529. package/UI/Components/Header/Header.tsx +25 -9
  530. package/UI/Components/Header/IconDropdown/IconDropdownItem.tsx +10 -1
  531. package/UI/Components/Header/IconDropdown/IconDropdownMenu.tsx +6 -1
  532. package/UI/Components/Header/ProjectPicker/ProjectPicker.tsx +6 -1
  533. package/UI/Components/HeaderAlert/NotificationBell/NotificationBellDropdown.tsx +6 -1
  534. package/UI/Components/Icon/Icon.tsx +11 -0
  535. package/UI/Components/JSONTable/JSONTable.tsx +2 -2
  536. package/UI/Components/KeyboardShortcut/KeyboardShortcutsModal.tsx +125 -0
  537. package/UI/Components/KeyboardShortcut/Screenshots/README.md +19 -0
  538. package/UI/Components/KeyboardShortcut/Screenshots/keyboard-shortcuts-command-palette.png +0 -0
  539. package/UI/Components/KeyboardShortcut/Screenshots/keyboard-shortcuts-dialog-dark.png +0 -0
  540. package/UI/Components/KeyboardShortcut/Screenshots/keyboard-shortcuts-dialog.png +0 -0
  541. package/UI/Components/KeyboardShortcut/Screenshots/keyboard-shortcuts-help-menu.png +0 -0
  542. package/UI/Components/KeyboardShortcut/Screenshots/keyboard-shortcuts-narrow.png +0 -0
  543. package/UI/Components/Modal/Modal.tsx +2 -8
  544. package/UI/Components/ModelTable/Column.ts +15 -0
  545. package/UI/Components/Monitor/SeriesDebugCommandsViewer.tsx +64 -0
  546. package/UI/Components/Monitor/SeriesLabelsViewer.tsx +93 -0
  547. package/UI/Components/MonitorGraphs/Uptime.tsx +14 -2
  548. package/UI/Components/MonitorGraphs/UptimeBarDayModal.tsx +63 -10
  549. package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +88 -0
  550. package/UI/Components/ProgressBar/ProgressBar.tsx +12 -1
  551. package/UI/Components/RadioButtons/BasicRadioButtons.tsx +37 -7
  552. package/UI/Components/SideMenu/SideMenu.tsx +123 -5
  553. package/UI/Components/SideMenu/SideMenuItem.tsx +76 -84
  554. package/UI/Components/SideMenu/SideMenuSection.tsx +55 -23
  555. package/UI/Components/SideOver/SideOver.tsx +21 -20
  556. package/UI/Components/StatusPage/ResourceGroupSection.tsx +40 -0
  557. package/UI/Components/Table/CellClassName.ts +81 -0
  558. package/UI/Components/Table/TableRow.tsx +20 -14
  559. package/UI/Components/Table/TableSkeletonRows.tsx +9 -9
  560. package/UI/Components/Table/Types/Column.ts +36 -0
  561. package/UI/Components/Tooltip/Tooltip.tsx +11 -1
  562. package/UI/Components/Workflow/ComponentsModal.tsx +60 -39
  563. package/UI/Components/Workflow/NodePlacement.ts +57 -0
  564. package/UI/Components/Workflow/Workflow.tsx +47 -18
  565. package/UI/Config.ts +15 -33
  566. package/UI/Utils/GlobalKeyboardShortcut.ts +208 -0
  567. package/UI/Utils/PageScrollLock.ts +79 -3
  568. package/UI/Utils/PermissionGate.ts +61 -0
  569. package/UI/Utils/SensitiveUrlToken.ts +112 -0
  570. package/UI/Utils/Telemetry/BrowserTelemetryConfig.ts +28 -0
  571. package/UI/Utils/Telemetry/Telemetry.ts +10 -8
  572. package/UI/Utils/TestLLMProvider.ts +11 -0
  573. package/Utils/API.ts +129 -3
  574. package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +16 -0
  575. package/Utils/EnterpriseLicense/EnterpriseLicenseUsage.ts +191 -11
  576. package/Utils/HTTPResponseBodyReader.ts +221 -0
  577. package/Utils/Monitor/MonitorMetricType.ts +153 -1
  578. package/Utils/Monitor/NetworkTopologyUtil.ts +23 -3
  579. package/Utils/NetworkDevice/DeviceHealthStateUtil.ts +65 -14
  580. package/Utils/NetworkDevice/DeviceReachabilityUtil.ts +43 -14
  581. package/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.ts +247 -0
  582. package/Utils/NetworkDevice/SnmpCredentialUtil.ts +68 -0
  583. package/Utils/NetworkDiscovery/AutoImportRuleMatcher.ts +15 -7
  584. package/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.ts +52 -17
  585. package/Utils/NetworkDiscovery/DiscoveryImportEligibility.ts +55 -23
  586. package/Utils/NetworkDiscovery/DiscoveryScanStatus.ts +77 -0
  587. package/Utils/NetworkDiscovery/PingMonitorBuilder.ts +115 -13
  588. package/Utils/NetworkSite/SiteStatusRollupUtil.ts +66 -20
  589. package/Utils/NetworkSite/TypeHierarchyUtil.ts +313 -0
  590. package/Utils/Rum/ChunkMath.ts +106 -0
  591. package/Utils/Rum/SessionReplayHealth.ts +732 -0
  592. package/Utils/Rum/SessionReplayStringMap.ts +226 -0
  593. package/Utils/Schema/ModelSchema.ts +1 -0
  594. package/Utils/StatusPage/ResourceSearch.ts +290 -0
  595. package/Utils/Telemetry/OriginAllowList.ts +355 -0
  596. package/Utils/Uptime/DayUptimeGraphUtil.ts +205 -0
  597. package/Utils/ValueFormatter.ts +35 -1
  598. package/build/dist/Models/AnalyticsModels/RumSession.js +102 -19
  599. package/build/dist/Models/AnalyticsModels/RumSession.js.map +1 -1
  600. package/build/dist/Models/AnalyticsModels/RumSessionChunk.js +11 -9
  601. package/build/dist/Models/AnalyticsModels/RumSessionChunk.js.map +1 -1
  602. package/build/dist/Models/AnalyticsModels/Span.js +14 -0
  603. package/build/dist/Models/AnalyticsModels/Span.js.map +1 -1
  604. package/build/dist/Models/DatabaseModels/AlertCustomField.js +79 -3
  605. package/build/dist/Models/DatabaseModels/AlertCustomField.js.map +1 -1
  606. package/build/dist/Models/DatabaseModels/ApiKeyPermission.js +3 -27
  607. package/build/dist/Models/DatabaseModels/ApiKeyPermission.js.map +1 -1
  608. package/build/dist/Models/DatabaseModels/EnterpriseLicense.js +59 -0
  609. package/build/dist/Models/DatabaseModels/EnterpriseLicense.js.map +1 -1
  610. package/build/dist/Models/DatabaseModels/IncidentCustomField.js +79 -3
  611. package/build/dist/Models/DatabaseModels/IncidentCustomField.js.map +1 -1
  612. package/build/dist/Models/DatabaseModels/Index.js +10 -0
  613. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  614. package/build/dist/Models/DatabaseModels/InventoryItemCustomField.js +79 -3
  615. package/build/dist/Models/DatabaseModels/InventoryItemCustomField.js.map +1 -1
  616. package/build/dist/Models/DatabaseModels/Monitor.js +75 -0
  617. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  618. package/build/dist/Models/DatabaseModels/MonitorCustomField.js +79 -3
  619. package/build/dist/Models/DatabaseModels/MonitorCustomField.js.map +1 -1
  620. package/build/dist/Models/DatabaseModels/NetworkAlertPolicy.js +713 -0
  621. package/build/dist/Models/DatabaseModels/NetworkAlertPolicy.js.map +1 -0
  622. package/build/dist/Models/DatabaseModels/NetworkDevice.js +180 -1
  623. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
  624. package/build/dist/Models/DatabaseModels/NetworkSite.js +200 -2
  625. package/build/dist/Models/DatabaseModels/NetworkSite.js.map +1 -1
  626. package/build/dist/Models/DatabaseModels/NetworkSiteType.js +102 -3
  627. package/build/dist/Models/DatabaseModels/NetworkSiteType.js.map +1 -1
  628. package/build/dist/Models/DatabaseModels/NetworkSnmpCredentialProfile.js +878 -0
  629. package/build/dist/Models/DatabaseModels/NetworkSnmpCredentialProfile.js.map +1 -0
  630. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyCustomField.js +79 -3
  631. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyCustomField.js.map +1 -1
  632. package/build/dist/Models/DatabaseModels/RumApplication.js +6 -6
  633. package/build/dist/Models/DatabaseModels/RumApplication.js.map +1 -1
  634. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceCustomField.js +79 -3
  635. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceCustomField.js.map +1 -1
  636. package/build/dist/Models/DatabaseModels/StatusPageCustomField.js +79 -3
  637. package/build/dist/Models/DatabaseModels/StatusPageCustomField.js.map +1 -1
  638. package/build/dist/Models/DatabaseModels/TeamCustomField.js +79 -3
  639. package/build/dist/Models/DatabaseModels/TeamCustomField.js.map +1 -1
  640. package/build/dist/Models/DatabaseModels/TeamMember.js +0 -9
  641. package/build/dist/Models/DatabaseModels/TeamMember.js.map +1 -1
  642. package/build/dist/Models/DatabaseModels/TeamMemberCustomField.js +79 -3
  643. package/build/dist/Models/DatabaseModels/TeamMemberCustomField.js.map +1 -1
  644. package/build/dist/Models/DatabaseModels/TeamPermission.js +3 -24
  645. package/build/dist/Models/DatabaseModels/TeamPermission.js.map +1 -1
  646. package/build/dist/Models/DatabaseModels/TelemetryException.js +123 -0
  647. package/build/dist/Models/DatabaseModels/TelemetryException.js.map +1 -1
  648. package/build/dist/Models/DatabaseModels/TelemetryIngestionKey.js +267 -0
  649. package/build/dist/Models/DatabaseModels/TelemetryIngestionKey.js.map +1 -1
  650. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupBatch.js +363 -0
  651. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupBatch.js.map +1 -0
  652. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupItem.js +402 -0
  653. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupItem.js.map +1 -0
  654. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupSetting.js +296 -0
  655. package/build/dist/Models/DatabaseModels/UserNotificationEmailRollupSetting.js.map +1 -0
  656. package/build/dist/Models/DatabaseModels/UserTelegram.js +0 -4
  657. package/build/dist/Models/DatabaseModels/UserTelegram.js.map +1 -1
  658. package/build/dist/Server/API/EnterpriseLicenseAPI.js +273 -60
  659. package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +1 -1
  660. package/build/dist/Server/API/LlmProviderAPI.js +108 -13
  661. package/build/dist/Server/API/LlmProviderAPI.js.map +1 -1
  662. package/build/dist/Server/API/TelemetryAPI.js +769 -109
  663. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  664. package/build/dist/Server/API/UserNotificationSettingAPI.js +35 -0
  665. package/build/dist/Server/API/UserNotificationSettingAPI.js.map +1 -0
  666. package/build/dist/Server/API/UserTelegramAPI.js +28 -6
  667. package/build/dist/Server/API/UserTelegramAPI.js.map +1 -1
  668. package/build/dist/Server/EnvironmentConfig.js +41 -2
  669. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  670. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790700000000-AddNetworkSiteTypeParentHierarchy.js +24 -0
  671. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790700000000-AddNetworkSiteTypeParentHierarchy.js.map +1 -0
  672. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddEnterpriseLicenseUsageProvenance.js +16 -0
  673. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddEnterpriseLicenseUsageProvenance.js.map +1 -0
  674. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddTelemetryExceptionErrorClass.js +111 -0
  675. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790900000000-AddTelemetryExceptionErrorClass.js.map +1 -0
  676. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791000000000-AddUserNotificationEmailRollup.js +77 -0
  677. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791000000000-AddUserNotificationEmailRollup.js.map +1 -0
  678. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791100000000-AddUserNotificationEmailRollupSetting.js +50 -0
  679. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791100000000-AddUserNotificationEmailRollupSetting.js.map +1 -0
  680. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791200000000-AddNetworkSnmpCredentialProfilesAndAlertPolicies.js +83 -0
  681. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791200000000-AddNetworkSnmpCredentialProfilesAndAlertPolicies.js.map +1 -0
  682. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791300000000-AddTelemetryIngestionKeyType.js +60 -0
  683. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791300000000-AddTelemetryIngestionKeyType.js.map +1 -0
  684. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791400000000-SessionReplayRecordEverySessionByDefault.js +53 -0
  685. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791400000000-SessionReplayRecordEverySessionByDefault.js.map +1 -0
  686. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791500000000-WidenCustomFieldDropdownOptions.js +82 -0
  687. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791500000000-WidenCustomFieldDropdownOptions.js.map +1 -0
  688. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791600000000-AddCustomFieldValueMapping.js +46 -0
  689. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791600000000-AddCustomFieldValueMapping.js.map +1 -0
  690. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +20 -0
  691. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  692. package/build/dist/Server/Infrastructure/QueueWorker.js +52 -12
  693. package/build/dist/Server/Infrastructure/QueueWorker.js.map +1 -1
  694. package/build/dist/Server/Infrastructure/Semaphore.js +1 -0
  695. package/build/dist/Server/Infrastructure/Semaphore.js.map +1 -1
  696. package/build/dist/Server/Middleware/BearerTokenAuthorization.js +12 -0
  697. package/build/dist/Server/Middleware/BearerTokenAuthorization.js.map +1 -1
  698. package/build/dist/Server/Middleware/ProjectAuthorization.js +11 -0
  699. package/build/dist/Server/Middleware/ProjectAuthorization.js.map +1 -1
  700. package/build/dist/Server/Middleware/SCIMAuthorization.js +12 -0
  701. package/build/dist/Server/Middleware/SCIMAuthorization.js.map +1 -1
  702. package/build/dist/Server/Middleware/TelemetryIngest.js +326 -8
  703. package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
  704. package/build/dist/Server/Services/AIBillingService.js +70 -16
  705. package/build/dist/Server/Services/AIBillingService.js.map +1 -1
  706. package/build/dist/Server/Services/AccessTokenService.js +1 -0
  707. package/build/dist/Server/Services/AccessTokenService.js.map +1 -1
  708. package/build/dist/Server/Services/AlertCustomFieldService.js +93 -0
  709. package/build/dist/Server/Services/AlertCustomFieldService.js.map +1 -1
  710. package/build/dist/Server/Services/AlertService.js +34 -0
  711. package/build/dist/Server/Services/AlertService.js.map +1 -1
  712. package/build/dist/Server/Services/ApiKeyPermissionService.js +331 -28
  713. package/build/dist/Server/Services/ApiKeyPermissionService.js.map +1 -1
  714. package/build/dist/Server/Services/CustomFieldMappingService.js +614 -0
  715. package/build/dist/Server/Services/CustomFieldMappingService.js.map +1 -0
  716. package/build/dist/Server/Services/EnterpriseLicenseInstanceService.js +167 -0
  717. package/build/dist/Server/Services/EnterpriseLicenseInstanceService.js.map +1 -1
  718. package/build/dist/Server/Services/EnterpriseLicenseService.js +39 -0
  719. package/build/dist/Server/Services/EnterpriseLicenseService.js.map +1 -1
  720. package/build/dist/Server/Services/GlobalConfigService.js +133 -0
  721. package/build/dist/Server/Services/GlobalConfigService.js.map +1 -1
  722. package/build/dist/Server/Services/IncidentCustomFieldService.js +93 -0
  723. package/build/dist/Server/Services/IncidentCustomFieldService.js.map +1 -1
  724. package/build/dist/Server/Services/IncidentService.js +32 -0
  725. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  726. package/build/dist/Server/Services/Index.js +10 -0
  727. package/build/dist/Server/Services/Index.js.map +1 -1
  728. package/build/dist/Server/Services/MetricService.js +163 -0
  729. package/build/dist/Server/Services/MetricService.js.map +1 -1
  730. package/build/dist/Server/Services/MonitorService.js +148 -21
  731. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  732. package/build/dist/Server/Services/MonitorStatusTimelineService.js +127 -8
  733. package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
  734. package/build/dist/Server/Services/MonitorTemplateService.js +162 -0
  735. package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
  736. package/build/dist/Server/Services/NetworkAlertPolicyEngineService.js +1683 -0
  737. package/build/dist/Server/Services/NetworkAlertPolicyEngineService.js.map +1 -0
  738. package/build/dist/Server/Services/NetworkAlertPolicyService.js +732 -0
  739. package/build/dist/Server/Services/NetworkAlertPolicyService.js.map +1 -0
  740. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +89 -36
  741. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -1
  742. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js +54 -11
  743. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js.map +1 -1
  744. package/build/dist/Server/Services/NetworkDeviceService.js +841 -70
  745. package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
  746. package/build/dist/Server/Services/NetworkSiteService.js +1145 -107
  747. package/build/dist/Server/Services/NetworkSiteService.js.map +1 -1
  748. package/build/dist/Server/Services/NetworkSiteTypeService.js +863 -0
  749. package/build/dist/Server/Services/NetworkSiteTypeService.js.map +1 -1
  750. package/build/dist/Server/Services/NetworkSnmpCredentialProfileService.js +217 -0
  751. package/build/dist/Server/Services/NetworkSnmpCredentialProfileService.js.map +1 -0
  752. package/build/dist/Server/Services/NotificationService.js +80 -17
  753. package/build/dist/Server/Services/NotificationService.js.map +1 -1
  754. package/build/dist/Server/Services/ProjectService.js +88 -30
  755. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  756. package/build/dist/Server/Services/RoutineEmailSettingsService.js +69 -0
  757. package/build/dist/Server/Services/RoutineEmailSettingsService.js.map +1 -0
  758. package/build/dist/Server/Services/RumSessionReplayViewService.js +86 -24
  759. package/build/dist/Server/Services/RumSessionReplayViewService.js.map +1 -1
  760. package/build/dist/Server/Services/ScheduledMaintenanceCustomFieldService.js +93 -0
  761. package/build/dist/Server/Services/ScheduledMaintenanceCustomFieldService.js.map +1 -1
  762. package/build/dist/Server/Services/ScheduledMaintenanceService.js +29 -0
  763. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  764. package/build/dist/Server/Services/StatusPagePrivateUserService.js +92 -2
  765. package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
  766. package/build/dist/Server/Services/TeamMemberService.js +62 -2
  767. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  768. package/build/dist/Server/Services/TeamPermissionService.js +166 -3
  769. package/build/dist/Server/Services/TeamPermissionService.js.map +1 -1
  770. package/build/dist/Server/Services/TelemetryIngestionKeyService.js +562 -18
  771. package/build/dist/Server/Services/TelemetryIngestionKeyService.js.map +1 -1
  772. package/build/dist/Server/Services/UserNotificationEmailRollupBatchService.js +76 -0
  773. package/build/dist/Server/Services/UserNotificationEmailRollupBatchService.js.map +1 -0
  774. package/build/dist/Server/Services/UserNotificationEmailRollupItemService.js +77 -0
  775. package/build/dist/Server/Services/UserNotificationEmailRollupItemService.js.map +1 -0
  776. package/build/dist/Server/Services/UserNotificationEmailRollupSettingService.js +111 -0
  777. package/build/dist/Server/Services/UserNotificationEmailRollupSettingService.js.map +1 -0
  778. package/build/dist/Server/Services/UserNotificationSettingService.js +66 -20
  779. package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
  780. package/build/dist/Server/Services/UserService.js +90 -0
  781. package/build/dist/Server/Services/UserService.js.map +1 -1
  782. package/build/dist/Server/Services/UserTelegramService.js +257 -4
  783. package/build/dist/Server/Services/UserTelegramService.js.map +1 -1
  784. package/build/dist/Server/Types/Database/QueryHelper.js +1 -1
  785. package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
  786. package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js +14 -3
  787. package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js.map +1 -1
  788. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js +10 -0
  789. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/ExceptionSpikeDetector.js.map +1 -1
  790. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js +10 -0
  791. package/build/dist/Server/Utils/AI/SRE/Insights/Detectors/NewExceptionDetector.js.map +1 -1
  792. package/build/dist/Server/Utils/AI/SRE/Insights/InsightTriageRunner.js +54 -1
  793. package/build/dist/Server/Utils/AI/SRE/Insights/InsightTriageRunner.js.map +1 -1
  794. package/build/dist/Server/Utils/AI/Toolbox/AlertTools.js +18 -4
  795. package/build/dist/Server/Utils/AI/Toolbox/AlertTools.js.map +1 -1
  796. package/build/dist/Server/Utils/APIKey/AccessPermission.js +2 -2
  797. package/build/dist/Server/Utils/APIKey/AccessPermission.js.map +1 -1
  798. package/build/dist/Server/Utils/Billing/BillingFailureNoticeThrottle.js +59 -0
  799. package/build/dist/Server/Utils/Billing/BillingFailureNoticeThrottle.js.map +1 -0
  800. package/build/dist/Server/Utils/CustomField/CustomFieldDefinitionMappingHooks.js +27 -0
  801. package/build/dist/Server/Utils/CustomField/CustomFieldDefinitionMappingHooks.js.map +1 -0
  802. package/build/dist/Server/Utils/CustomField/CustomFieldMappingRegistry.js +226 -0
  803. package/build/dist/Server/Utils/CustomField/CustomFieldMappingRegistry.js.map +1 -0
  804. package/build/dist/Server/Utils/CustomField/CustomFieldMappingValidator.js +189 -0
  805. package/build/dist/Server/Utils/CustomField/CustomFieldMappingValidator.js.map +1 -0
  806. package/build/dist/Server/Utils/DataSource/EgressGuard.js +121 -7
  807. package/build/dist/Server/Utils/DataSource/EgressGuard.js.map +1 -1
  808. package/build/dist/Server/Utils/DataSource/HttpFetch.js +2 -1
  809. package/build/dist/Server/Utils/DataSource/HttpFetch.js.map +1 -1
  810. package/build/dist/Server/Utils/EmailRollup/EmailRollupConstants.js +124 -0
  811. package/build/dist/Server/Utils/EmailRollup/EmailRollupConstants.js.map +1 -0
  812. package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js +733 -0
  813. package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js.map +1 -0
  814. package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js +497 -0
  815. package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js.map +1 -0
  816. package/build/dist/Server/Utils/EmailRollup/EmailRollupWriter.js +257 -0
  817. package/build/dist/Server/Utils/EmailRollup/EmailRollupWriter.js.map +1 -0
  818. package/build/dist/Server/Utils/FrontendEnvironment.js +33 -0
  819. package/build/dist/Server/Utils/FrontendEnvironment.js.map +1 -0
  820. package/build/dist/Server/Utils/LLM/LLMService.js +64 -1
  821. package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
  822. package/build/dist/Server/Utils/LogRedaction.js +28 -0
  823. package/build/dist/Server/Utils/LogRedaction.js.map +1 -1
  824. package/build/dist/Server/Utils/Logger.js +73 -1
  825. package/build/dist/Server/Utils/Logger.js.map +1 -1
  826. package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js +287 -68
  827. package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js.map +1 -1
  828. package/build/dist/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.js +141 -0
  829. package/build/dist/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.js.map +1 -0
  830. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js +8 -1
  831. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js.map +1 -1
  832. package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.js +20 -4
  833. package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.js.map +1 -1
  834. package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js +51 -1
  835. package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js.map +1 -1
  836. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +29 -6
  837. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  838. package/build/dist/Server/Utils/Monitor/MonitorCriteriaDataExtractor.js +7 -0
  839. package/build/dist/Server/Utils/Monitor/MonitorCriteriaDataExtractor.js.map +1 -1
  840. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +125 -13
  841. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  842. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js +158 -6
  843. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js.map +1 -1
  844. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +22 -6
  845. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  846. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +33 -0
  847. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
  848. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +54 -0
  849. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
  850. package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js +330 -21
  851. package/build/dist/Server/Utils/Monitor/NetworkDeviceHydrationUtil.js.map +1 -1
  852. package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js +55 -10
  853. package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js.map +1 -1
  854. package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js +178 -49
  855. package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js.map +1 -1
  856. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +119 -29
  857. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
  858. package/build/dist/Server/Utils/Monitor/SeriesContextEnricher.js +237 -0
  859. package/build/dist/Server/Utils/Monitor/SeriesContextEnricher.js.map +1 -0
  860. package/build/dist/Server/Utils/NetworkDevice/DeviceHealthAggregation.js +30 -17
  861. package/build/dist/Server/Utils/NetworkDevice/DeviceHealthAggregation.js.map +1 -1
  862. package/build/dist/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.js +158 -0
  863. package/build/dist/Server/Utils/NetworkSite/NetworkSiteHierarchyLock.js.map +1 -0
  864. package/build/dist/Server/Utils/OutboundUserAgent.js +123 -0
  865. package/build/dist/Server/Utils/OutboundUserAgent.js.map +1 -0
  866. package/build/dist/Server/Utils/SSRFProtection.js +136 -9
  867. package/build/dist/Server/Utils/SSRFProtection.js.map +1 -1
  868. package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCache.js +174 -89
  869. package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCache.js.map +1 -1
  870. package/build/dist/Server/Utils/SessionReplay/SessionReplayHealthCounters.js +223 -0
  871. package/build/dist/Server/Utils/SessionReplay/SessionReplayHealthCounters.js.map +1 -0
  872. package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js +945 -164
  873. package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js.map +1 -1
  874. package/build/dist/Server/Utils/StartServer.js +41 -28
  875. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  876. package/build/dist/Server/Utils/TelegramVerificationToken.js +129 -0
  877. package/build/dist/Server/Utils/TelegramVerificationToken.js.map +1 -0
  878. package/build/dist/Server/Utils/Telemetry/CaptureSpan.js +28 -8
  879. package/build/dist/Server/Utils/Telemetry/CaptureSpan.js.map +1 -1
  880. package/build/dist/Server/Utils/Telemetry/ErrorClassResolver.js +95 -0
  881. package/build/dist/Server/Utils/Telemetry/ErrorClassResolver.js.map +1 -0
  882. package/build/dist/Server/Utils/Telemetry/PinServiceName.js +163 -0
  883. package/build/dist/Server/Utils/Telemetry/PinServiceName.js.map +1 -0
  884. package/build/dist/Server/Utils/Telemetry/SpanUtil.js +29 -0
  885. package/build/dist/Server/Utils/Telemetry/SpanUtil.js.map +1 -1
  886. package/build/dist/Server/Utils/Telemetry/TelemetryFanInWriter.js +28 -15
  887. package/build/dist/Server/Utils/Telemetry/TelemetryFanInWriter.js.map +1 -1
  888. package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.js +64 -0
  889. package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.js.map +1 -0
  890. package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyRateLimiter.js +171 -0
  891. package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyRateLimiter.js.map +1 -0
  892. package/build/dist/Server/Utils/Telemetry.js +162 -46
  893. package/build/dist/Server/Utils/Telemetry.js.map +1 -1
  894. package/build/dist/Server/Utils/VM/VMAPI.js.map +1 -1
  895. package/build/dist/Server/Utils/VM/VMRunner.js +780 -69
  896. package/build/dist/Server/Utils/VM/VMRunner.js.map +1 -1
  897. package/build/dist/Types/AI/ExceptionAIClassification.js +10 -24
  898. package/build/dist/Types/AI/ExceptionAIClassification.js.map +1 -1
  899. package/build/dist/Types/CustomField/CustomFieldMappingCatalog.js +60 -0
  900. package/build/dist/Types/CustomField/CustomFieldMappingCatalog.js.map +1 -0
  901. package/build/dist/Types/CustomField/CustomFieldMappingSourceResource.js +20 -0
  902. package/build/dist/Types/CustomField/CustomFieldMappingSourceResource.js.map +1 -0
  903. package/build/dist/Types/CustomField/CustomFieldValueMapping.js +141 -0
  904. package/build/dist/Types/CustomField/CustomFieldValueMapping.js.map +1 -0
  905. package/build/dist/Types/Email/EmailTemplateType.js +1 -0
  906. package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
  907. package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUsageSnapshot.js +2 -0
  908. package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUsageSnapshot.js.map +1 -0
  909. package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUserCountSource.js +7 -0
  910. package/build/dist/Types/EnterpriseLicense/EnterpriseLicenseUserCountSource.js.map +1 -0
  911. package/build/dist/Types/Exception/ApiException.js +9 -0
  912. package/build/dist/Types/Exception/ApiException.js.map +1 -1
  913. package/build/dist/Types/Exception/BadDataException.js +10 -0
  914. package/build/dist/Types/Exception/BadDataException.js.map +1 -1
  915. package/build/dist/Types/Exception/BadRequestException.js +10 -0
  916. package/build/dist/Types/Exception/BadRequestException.js.map +1 -1
  917. package/build/dist/Types/Exception/Exception.js +56 -0
  918. package/build/dist/Types/Exception/Exception.js.map +1 -1
  919. package/build/dist/Types/Exception/ForbiddenException.js +9 -0
  920. package/build/dist/Types/Exception/ForbiddenException.js.map +1 -1
  921. package/build/dist/Types/Exception/NotAuthenticatedException.js +9 -0
  922. package/build/dist/Types/Exception/NotAuthenticatedException.js.map +1 -1
  923. package/build/dist/Types/Exception/NotAuthorizedException.js +9 -0
  924. package/build/dist/Types/Exception/NotAuthorizedException.js.map +1 -1
  925. package/build/dist/Types/Exception/NotFoundException.js +10 -0
  926. package/build/dist/Types/Exception/NotFoundException.js.map +1 -1
  927. package/build/dist/Types/Exception/PayloadTooLargeException.js +10 -0
  928. package/build/dist/Types/Exception/PayloadTooLargeException.js.map +1 -1
  929. package/build/dist/Types/Exception/PaymentRequiredException.js +9 -0
  930. package/build/dist/Types/Exception/PaymentRequiredException.js.map +1 -1
  931. package/build/dist/Types/Exception/ServiceUnavailableException.js +9 -0
  932. package/build/dist/Types/Exception/ServiceUnavailableException.js.map +1 -1
  933. package/build/dist/Types/Exception/SsoAuthorizationException.js +9 -0
  934. package/build/dist/Types/Exception/SsoAuthorizationException.js.map +1 -1
  935. package/build/dist/Types/Exception/TenantNotFoundException.js +10 -0
  936. package/build/dist/Types/Exception/TenantNotFoundException.js.map +1 -1
  937. package/build/dist/Types/Exception/TimeoutException.js +9 -0
  938. package/build/dist/Types/Exception/TimeoutException.js.map +1 -1
  939. package/build/dist/Types/Exception/TooManyRequestsException.js +9 -0
  940. package/build/dist/Types/Exception/TooManyRequestsException.js.map +1 -1
  941. package/build/dist/Types/Exception/UnableToReachServer.js +9 -0
  942. package/build/dist/Types/Exception/UnableToReachServer.js.map +1 -1
  943. package/build/dist/Types/Exception/WebsiteRequestException.js +9 -0
  944. package/build/dist/Types/Exception/WebsiteRequestException.js.map +1 -1
  945. package/build/dist/Types/Icon/IconProp.js +1 -0
  946. package/build/dist/Types/Icon/IconProp.js.map +1 -1
  947. package/build/dist/Types/JSONFunctions.js +118 -37
  948. package/build/dist/Types/JSONFunctions.js.map +1 -1
  949. package/build/dist/Types/Monitor/CephAlertTemplates.js +130 -171
  950. package/build/dist/Types/Monitor/CephAlertTemplates.js.map +1 -1
  951. package/build/dist/Types/Monitor/CriteriaFilter.js +45 -2
  952. package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
  953. package/build/dist/Types/Monitor/DatabaseMetricCatalog.js +594 -0
  954. package/build/dist/Types/Monitor/DatabaseMetricCatalog.js.map +1 -0
  955. package/build/dist/Types/Monitor/DatabaseMonitor/DatabaseMonitorResponse.js +21 -0
  956. package/build/dist/Types/Monitor/DatabaseMonitor/DatabaseMonitorResponse.js.map +1 -0
  957. package/build/dist/Types/Monitor/DockerAlertTemplates.js +286 -121
  958. package/build/dist/Types/Monitor/DockerAlertTemplates.js.map +1 -1
  959. package/build/dist/Types/Monitor/DockerSwarmAlertTemplates.js +84 -105
  960. package/build/dist/Types/Monitor/DockerSwarmAlertTemplates.js.map +1 -1
  961. package/build/dist/Types/Monitor/HostAlertTemplates.js +250 -122
  962. package/build/dist/Types/Monitor/HostAlertTemplates.js.map +1 -1
  963. package/build/dist/Types/Monitor/IotAlertTemplates.js +81 -81
  964. package/build/dist/Types/Monitor/IotAlertTemplates.js.map +1 -1
  965. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js +375 -215
  966. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js.map +1 -1
  967. package/build/dist/Types/Monitor/KubernetesMetricCatalog.js +19 -19
  968. package/build/dist/Types/Monitor/KubernetesMetricCatalog.js.map +1 -1
  969. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +70 -0
  970. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
  971. package/build/dist/Types/Monitor/MonitorMetricType.js +61 -0
  972. package/build/dist/Types/Monitor/MonitorMetricType.js.map +1 -1
  973. package/build/dist/Types/Monitor/MonitorStep.js +54 -0
  974. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  975. package/build/dist/Types/Monitor/MonitorStepDatabaseMonitor.js +122 -0
  976. package/build/dist/Types/Monitor/MonitorStepDatabaseMonitor.js.map +1 -0
  977. package/build/dist/Types/Monitor/MonitorStepSqlMonitor.js.map +1 -1
  978. package/build/dist/Types/Monitor/MonitorType.js +45 -1
  979. package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
  980. package/build/dist/Types/Monitor/PodmanAlertTemplates.js +104 -153
  981. package/build/dist/Types/Monitor/PodmanAlertTemplates.js.map +1 -1
  982. package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js +156 -91
  983. package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js.map +1 -1
  984. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js +67 -6
  985. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js.map +1 -1
  986. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js +38 -7
  987. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js.map +1 -1
  988. package/build/dist/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.js +261 -0
  989. package/build/dist/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.js.map +1 -0
  990. package/build/dist/Types/Monitor/RumAlertTemplates.js +46 -7
  991. package/build/dist/Types/Monitor/RumAlertTemplates.js.map +1 -1
  992. package/build/dist/Types/Monitor/SeriesContext/SeriesDebugHints.js +422 -0
  993. package/build/dist/Types/Monitor/SeriesContext/SeriesDebugHints.js.map +1 -0
  994. package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js +441 -0
  995. package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js.map +1 -0
  996. package/build/dist/Types/Monitor/ServiceAlertTemplates.js +79 -15
  997. package/build/dist/Types/Monitor/ServiceAlertTemplates.js.map +1 -1
  998. package/build/dist/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.js +21 -1
  999. package/build/dist/Types/Monitor/SnmpMonitor/NetworkDeviceAlertPack.js.map +1 -1
  1000. package/build/dist/Types/Monitor/SqlConnectionConfig.js +2 -0
  1001. package/build/dist/Types/Monitor/SqlConnectionConfig.js.map +1 -0
  1002. package/build/dist/Types/Monitor/UptimeHistoryLabels.js +17 -0
  1003. package/build/dist/Types/Monitor/UptimeHistoryLabels.js.map +1 -0
  1004. package/build/dist/Types/NetworkDevice/NetworkAlertPolicyScope.js +172 -0
  1005. package/build/dist/Types/NetworkDevice/NetworkAlertPolicyScope.js.map +1 -0
  1006. package/build/dist/Types/NetworkDevice/NetworkDeviceMonitoringMethod.js +40 -22
  1007. package/build/dist/Types/NetworkDevice/NetworkDeviceMonitoringMethod.js.map +1 -1
  1008. package/build/dist/Types/NetworkSite/DefaultNetworkSiteTypeHierarchy.js +26 -0
  1009. package/build/dist/Types/NetworkSite/DefaultNetworkSiteTypeHierarchy.js.map +1 -0
  1010. package/build/dist/Types/NotificationSetting/NotificationEmailRollupCategory.js +186 -0
  1011. package/build/dist/Types/NotificationSetting/NotificationEmailRollupCategory.js.map +1 -0
  1012. package/build/dist/Types/NotificationSetting/NotificationEmailRollupPolicy.js +87 -0
  1013. package/build/dist/Types/NotificationSetting/NotificationEmailRollupPolicy.js.map +1 -0
  1014. package/build/dist/Types/NotificationSetting/RoutineEmailEvents.js +29 -0
  1015. package/build/dist/Types/NotificationSetting/RoutineEmailEvents.js.map +1 -0
  1016. package/build/dist/Types/Permission.js +80 -0
  1017. package/build/dist/Types/Permission.js.map +1 -1
  1018. package/build/dist/Types/Rum/SessionReplay.js +117 -0
  1019. package/build/dist/Types/Rum/SessionReplay.js.map +1 -1
  1020. package/build/dist/Types/Rum/SessionReplayApi.js +181 -0
  1021. package/build/dist/Types/Rum/SessionReplayApi.js.map +1 -0
  1022. package/build/dist/Types/Rum/SessionReplayCaptureTrigger.js +21 -12
  1023. package/build/dist/Types/Rum/SessionReplayCaptureTrigger.js.map +1 -1
  1024. package/build/dist/Types/Rum/SessionReplayConsentMode.js +11 -7
  1025. package/build/dist/Types/Rum/SessionReplayConsentMode.js.map +1 -1
  1026. package/build/dist/Types/Rum/SessionReplayCustomEvents.js +172 -0
  1027. package/build/dist/Types/Rum/SessionReplayCustomEvents.js.map +1 -0
  1028. package/build/dist/Types/Rum/SessionReplayHealth.js +37 -0
  1029. package/build/dist/Types/Rum/SessionReplayHealth.js.map +1 -0
  1030. package/build/dist/Types/Telemetry/ErrorClass.js +216 -0
  1031. package/build/dist/Types/Telemetry/ErrorClass.js.map +1 -0
  1032. package/build/dist/Types/Telemetry/TelemetryIngestSurface.js +85 -0
  1033. package/build/dist/Types/Telemetry/TelemetryIngestSurface.js.map +1 -0
  1034. package/build/dist/Types/Telemetry/TelemetryIngestionKeyPolicy.js +15 -0
  1035. package/build/dist/Types/Telemetry/TelemetryIngestionKeyPolicy.js.map +1 -0
  1036. package/build/dist/Types/Telemetry/TelemetryIngestionKeyType.js +30 -0
  1037. package/build/dist/Types/Telemetry/TelemetryIngestionKeyType.js.map +1 -0
  1038. package/build/dist/Types/Telemetry/UnitOfWork.js +59 -0
  1039. package/build/dist/Types/Telemetry/UnitOfWork.js.map +1 -0
  1040. package/build/dist/Types/WebsiteRequest.js +55 -3
  1041. package/build/dist/Types/WebsiteRequest.js.map +1 -1
  1042. package/build/dist/UI/Components/Charts/Area/AreaChart.js +13 -2
  1043. package/build/dist/UI/Components/Charts/Area/AreaChart.js.map +1 -1
  1044. package/build/dist/UI/Components/Charts/Bar/BarChart.js +6 -2
  1045. package/build/dist/UI/Components/Charts/Bar/BarChart.js.map +1 -1
  1046. package/build/dist/UI/Components/Charts/Line/LineChart.js +13 -2
  1047. package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
  1048. package/build/dist/UI/Components/Charts/Types/XAxis/XAxis.js.map +1 -1
  1049. package/build/dist/UI/Components/Charts/Utils/DataPoint.js +15 -3
  1050. package/build/dist/UI/Components/Charts/Utils/DataPoint.js.map +1 -1
  1051. package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js +40 -9
  1052. package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js.map +1 -1
  1053. package/build/dist/UI/Components/Charts/Utils/XAxis.js +186 -0
  1054. package/build/dist/UI/Components/Charts/Utils/XAxis.js.map +1 -1
  1055. package/build/dist/UI/Components/CommandPalette/CommandPalette.js +2 -7
  1056. package/build/dist/UI/Components/CommandPalette/CommandPalette.js.map +1 -1
  1057. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +80 -6
  1058. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
  1059. package/build/dist/UI/Components/CustomFields/MapFromCustomFieldInput.js +118 -0
  1060. package/build/dist/UI/Components/CustomFields/MapFromCustomFieldInput.js.map +1 -0
  1061. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +3 -0
  1062. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  1063. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js +112 -7
  1064. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js.map +1 -1
  1065. package/build/dist/UI/Components/Graphs/UptimeBarTooltip.js +5 -162
  1066. package/build/dist/UI/Components/Graphs/UptimeBarTooltip.js.map +1 -1
  1067. package/build/dist/UI/Components/Graphs/UptimeDaySummary.js +181 -0
  1068. package/build/dist/UI/Components/Graphs/UptimeDaySummary.js.map +1 -0
  1069. package/build/dist/UI/Components/Header/Header.js +2 -3
  1070. package/build/dist/UI/Components/Header/Header.js.map +1 -1
  1071. package/build/dist/UI/Components/Header/IconDropdown/IconDropdownItem.js +2 -1
  1072. package/build/dist/UI/Components/Header/IconDropdown/IconDropdownItem.js.map +1 -1
  1073. package/build/dist/UI/Components/Header/IconDropdown/IconDropdownMenu.js +7 -1
  1074. package/build/dist/UI/Components/Header/IconDropdown/IconDropdownMenu.js.map +1 -1
  1075. package/build/dist/UI/Components/Header/ProjectPicker/ProjectPicker.js +7 -1
  1076. package/build/dist/UI/Components/Header/ProjectPicker/ProjectPicker.js.map +1 -1
  1077. package/build/dist/UI/Components/HeaderAlert/NotificationBell/NotificationBellDropdown.js +7 -1
  1078. package/build/dist/UI/Components/HeaderAlert/NotificationBell/NotificationBellDropdown.js.map +1 -1
  1079. package/build/dist/UI/Components/Icon/Icon.js +5 -0
  1080. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  1081. package/build/dist/UI/Components/JSONTable/JSONTable.js +2 -2
  1082. package/build/dist/UI/Components/JSONTable/JSONTable.js.map +1 -1
  1083. package/build/dist/UI/Components/KeyboardShortcut/KeyboardShortcutsModal.js +35 -0
  1084. package/build/dist/UI/Components/KeyboardShortcut/KeyboardShortcutsModal.js.map +1 -0
  1085. package/build/dist/UI/Components/Modal/Modal.js +2 -7
  1086. package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
  1087. package/build/dist/UI/Components/Monitor/SeriesDebugCommandsViewer.js +34 -0
  1088. package/build/dist/UI/Components/Monitor/SeriesDebugCommandsViewer.js.map +1 -0
  1089. package/build/dist/UI/Components/Monitor/SeriesLabelsViewer.js +49 -0
  1090. package/build/dist/UI/Components/Monitor/SeriesLabelsViewer.js.map +1 -0
  1091. package/build/dist/UI/Components/MonitorGraphs/Uptime.js +1 -1
  1092. package/build/dist/UI/Components/MonitorGraphs/Uptime.js.map +1 -1
  1093. package/build/dist/UI/Components/MonitorGraphs/UptimeBarDayModal.js +32 -6
  1094. package/build/dist/UI/Components/MonitorGraphs/UptimeBarDayModal.js.map +1 -1
  1095. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +77 -0
  1096. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
  1097. package/build/dist/UI/Components/ProgressBar/ProgressBar.js +12 -1
  1098. package/build/dist/UI/Components/ProgressBar/ProgressBar.js.map +1 -1
  1099. package/build/dist/UI/Components/RadioButtons/BasicRadioButtons.js +6 -6
  1100. package/build/dist/UI/Components/RadioButtons/BasicRadioButtons.js.map +1 -1
  1101. package/build/dist/UI/Components/SideMenu/SideMenu.js +67 -5
  1102. package/build/dist/UI/Components/SideMenu/SideMenu.js.map +1 -1
  1103. package/build/dist/UI/Components/SideMenu/SideMenuItem.js +49 -53
  1104. package/build/dist/UI/Components/SideMenu/SideMenuItem.js.map +1 -1
  1105. package/build/dist/UI/Components/SideMenu/SideMenuSection.js +25 -7
  1106. package/build/dist/UI/Components/SideMenu/SideMenuSection.js.map +1 -1
  1107. package/build/dist/UI/Components/SideOver/SideOver.js +5 -20
  1108. package/build/dist/UI/Components/SideOver/SideOver.js.map +1 -1
  1109. package/build/dist/UI/Components/StatusPage/ResourceGroupSection.js +22 -1
  1110. package/build/dist/UI/Components/StatusPage/ResourceGroupSection.js.map +1 -1
  1111. package/build/dist/UI/Components/Table/CellClassName.js +55 -0
  1112. package/build/dist/UI/Components/Table/CellClassName.js.map +1 -0
  1113. package/build/dist/UI/Components/Table/TableRow.js +16 -13
  1114. package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
  1115. package/build/dist/UI/Components/Table/TableSkeletonRows.js +9 -8
  1116. package/build/dist/UI/Components/Table/TableSkeletonRows.js.map +1 -1
  1117. package/build/dist/UI/Components/Tooltip/Tooltip.js +25 -1
  1118. package/build/dist/UI/Components/Tooltip/Tooltip.js.map +1 -1
  1119. package/build/dist/UI/Components/Workflow/ComponentsModal.js +47 -30
  1120. package/build/dist/UI/Components/Workflow/ComponentsModal.js.map +1 -1
  1121. package/build/dist/UI/Components/Workflow/NodePlacement.js +37 -0
  1122. package/build/dist/UI/Components/Workflow/NodePlacement.js.map +1 -0
  1123. package/build/dist/UI/Components/Workflow/Workflow.js +35 -18
  1124. package/build/dist/UI/Components/Workflow/Workflow.js.map +1 -1
  1125. package/build/dist/UI/Config.js +10 -20
  1126. package/build/dist/UI/Config.js.map +1 -1
  1127. package/build/dist/UI/Utils/GlobalKeyboardShortcut.js +138 -0
  1128. package/build/dist/UI/Utils/GlobalKeyboardShortcut.js.map +1 -0
  1129. package/build/dist/UI/Utils/PageScrollLock.js +31 -3
  1130. package/build/dist/UI/Utils/PageScrollLock.js.map +1 -1
  1131. package/build/dist/UI/Utils/PermissionGate.js +42 -1
  1132. package/build/dist/UI/Utils/PermissionGate.js.map +1 -1
  1133. package/build/dist/UI/Utils/SensitiveUrlToken.js +97 -0
  1134. package/build/dist/UI/Utils/SensitiveUrlToken.js.map +1 -0
  1135. package/build/dist/UI/Utils/Telemetry/BrowserTelemetryConfig.js +14 -0
  1136. package/build/dist/UI/Utils/Telemetry/BrowserTelemetryConfig.js.map +1 -0
  1137. package/build/dist/UI/Utils/Telemetry/Telemetry.js +7 -5
  1138. package/build/dist/UI/Utils/Telemetry/Telemetry.js.map +1 -1
  1139. package/build/dist/UI/Utils/TestLLMProvider.js +4 -5
  1140. package/build/dist/UI/Utils/TestLLMProvider.js.map +1 -1
  1141. package/build/dist/Utils/API.js +67 -5
  1142. package/build/dist/Utils/API.js.map +1 -1
  1143. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js +15 -0
  1144. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js.map +1 -1
  1145. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js +111 -9
  1146. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js.map +1 -1
  1147. package/build/dist/Utils/HTTPResponseBodyReader.js +157 -0
  1148. package/build/dist/Utils/HTTPResponseBodyReader.js.map +1 -0
  1149. package/build/dist/Utils/Monitor/MonitorMetricType.js +109 -1
  1150. package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
  1151. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +8 -3
  1152. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
  1153. package/build/dist/Utils/NetworkDevice/DeviceHealthStateUtil.js +27 -7
  1154. package/build/dist/Utils/NetworkDevice/DeviceHealthStateUtil.js.map +1 -1
  1155. package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js +7 -5
  1156. package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js.map +1 -1
  1157. package/build/dist/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.js +180 -0
  1158. package/build/dist/Utils/NetworkDevice/NetworkAlertPolicyBootstrapUtil.js.map +1 -0
  1159. package/build/dist/Utils/NetworkDevice/SnmpCredentialUtil.js +12 -0
  1160. package/build/dist/Utils/NetworkDevice/SnmpCredentialUtil.js.map +1 -0
  1161. package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js +15 -5
  1162. package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js.map +1 -1
  1163. package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js +44 -15
  1164. package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js.map +1 -1
  1165. package/build/dist/Utils/NetworkDiscovery/DiscoveryImportEligibility.js +52 -23
  1166. package/build/dist/Utils/NetworkDiscovery/DiscoveryImportEligibility.js.map +1 -1
  1167. package/build/dist/Utils/NetworkDiscovery/DiscoveryScanStatus.js +69 -0
  1168. package/build/dist/Utils/NetworkDiscovery/DiscoveryScanStatus.js.map +1 -0
  1169. package/build/dist/Utils/NetworkDiscovery/PingMonitorBuilder.js +85 -13
  1170. package/build/dist/Utils/NetworkDiscovery/PingMonitorBuilder.js.map +1 -1
  1171. package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js +30 -15
  1172. package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js.map +1 -1
  1173. package/build/dist/Utils/NetworkSite/TypeHierarchyUtil.js +191 -0
  1174. package/build/dist/Utils/NetworkSite/TypeHierarchyUtil.js.map +1 -0
  1175. package/build/dist/Utils/Rum/ChunkMath.js +76 -0
  1176. package/build/dist/Utils/Rum/ChunkMath.js.map +1 -1
  1177. package/build/dist/Utils/Rum/SessionReplayHealth.js +534 -0
  1178. package/build/dist/Utils/Rum/SessionReplayHealth.js.map +1 -0
  1179. package/build/dist/Utils/Rum/SessionReplayStringMap.js +165 -0
  1180. package/build/dist/Utils/Rum/SessionReplayStringMap.js.map +1 -0
  1181. package/build/dist/Utils/Schema/ModelSchema.js +1 -0
  1182. package/build/dist/Utils/Schema/ModelSchema.js.map +1 -1
  1183. package/build/dist/Utils/StatusPage/ResourceSearch.js +200 -0
  1184. package/build/dist/Utils/StatusPage/ResourceSearch.js.map +1 -0
  1185. package/build/dist/Utils/Telemetry/OriginAllowList.js +299 -0
  1186. package/build/dist/Utils/Telemetry/OriginAllowList.js.map +1 -0
  1187. package/build/dist/Utils/Uptime/DayUptimeGraphUtil.js +147 -0
  1188. package/build/dist/Utils/Uptime/DayUptimeGraphUtil.js.map +1 -0
  1189. package/build/dist/Utils/ValueFormatter.js +32 -1
  1190. package/build/dist/Utils/ValueFormatter.js.map +1 -1
  1191. package/package.json +2 -2
@@ -121,24 +121,48 @@ import SessionReplayIdentity from "../Utils/SessionReplay/SessionReplayIdentity"
121
121
  import SessionReplayTargeting from "../Utils/SessionReplay/SessionReplayTargeting";
122
122
  import SessionReplayUsage from "../Utils/SessionReplay/SessionReplayUsage";
123
123
  import RumSessionReplayView from "../../Models/DatabaseModels/RumSessionReplayView";
124
- import RumSessionReplayViewService from "../Services/RumSessionReplayViewService";
124
+ import RumSessionReplayViewService, {
125
+ normalizeSecondsWatched,
126
+ } from "../Services/RumSessionReplayViewService";
125
127
  import SessionReplayReadService, {
126
128
  DEFAULT_SESSION_REPLAY_LIST_LIMIT,
127
129
  MAX_SESSION_REPLAY_FOR_EXCEPTION_LIMIT,
128
- SessionReplayChunkPayload,
130
+ MAX_SESSION_REPLAY_LIST_LIMIT,
131
+ SESSION_REPLAY_EXCEPTION_WINDOW_PADDING_MS,
132
+ SessionReplayApplicationActivitySummary,
133
+ SessionReplayChunkReadResult,
129
134
  SessionReplayExceptionSession,
135
+ SessionReplayExpiredSessionInfo,
130
136
  SessionReplayListCursor,
131
137
  SessionReplayListFilters,
132
138
  SessionReplayListResult,
133
139
  SessionReplayManifest,
134
140
  SessionReplaySessionHeader,
141
+ SessionReplaySessionIdentity,
135
142
  } from "../Utils/SessionReplay/SessionReplayReadService";
143
+ import SessionReplayHealthCounters, {
144
+ SessionReplayDropCount,
145
+ } from "../Utils/SessionReplay/SessionReplayHealthCounters";
146
+ import { isSessionErased } from "../Utils/SessionReplay/SessionReplayErasureTombstone";
147
+ import NotFoundException from "../../Types/Exception/NotFoundException";
136
148
  import {
137
149
  DEFAULT_SESSION_REPLAY_MAX_BYTES_PER_PROJECT_PER_DAY,
138
150
  MAX_SESSION_REPLAY_CHUNKS_PER_READ,
139
151
  MAX_SESSION_REPLAY_READ_BYTES,
152
+ SESSION_REPLAY_LIST_SEARCH_MAX_LENGTH,
153
+ SESSION_REPLAY_LIST_SEARCH_MAX_WINDOW_DAYS,
154
+ SESSION_REPLAY_MAX_SESSION_MS,
155
+ SESSION_REPLAY_MAX_TAG_KEYS,
156
+ SESSION_REPLAY_MAX_TAG_KEY_LENGTH,
157
+ SESSION_REPLAY_MAX_TAG_VALUE_LENGTH,
140
158
  SESSION_REPLAY_MAX_USER_REF_LENGTH,
141
159
  } from "../../Types/Rum/SessionReplay";
160
+ import {
161
+ SESSION_REPLAY_SORT_BY_VALUES,
162
+ SessionReplaySortBy,
163
+ parseSessionReplayListCursor,
164
+ } from "../../Types/Rum/SessionReplayApi";
165
+ import { SessionReplayRefusalCount } from "../../Types/Rum/SessionReplayHealth";
142
166
 
143
167
  const router: ExpressRouter = Express.getRouter();
144
168
 
@@ -3834,24 +3858,92 @@ const isApplicationInSessionReplayScope: IsApplicationInSessionReplayScopeFuncti
3834
3858
  * Returns the application so callers that need its labels for a second,
3835
3859
  * narrower decision (the identity column) do not have to load it twice.
3836
3860
  */
3837
- type AssertSessionReplayApplicationAccessFunction = (data: {
3861
+ /*
3862
+ * Process-local memory of what the two playback hot paths re-derive on
3863
+ * every call: which application a session belongs to (a ClickHouse GROUP
3864
+ * BY over the header table) and which labels that application carries (a
3865
+ * Postgres lookup). A 480-chunk session is 60 chunk pages, and a live
3866
+ * player heartbeats every 15s; without this every one of those paid both
3867
+ * lookups again for an answer that had not changed.
3868
+ *
3869
+ * What is cached is the DATA, never the decision: the label intersection
3870
+ * is recomputed against the caller's current permissions on every
3871
+ * request, so a revoked grant takes effect immediately. A label edit on
3872
+ * the application, or a header re-resolution, lags by at most the TTL -
3873
+ * the same lag the ingest gate's policy cache already accepts. The
3874
+ * manifest route always resolves fresh (a live session's header changes)
3875
+ * and refills the entries the chunk and heartbeat routes then read.
3876
+ */
3877
+ const SESSION_REPLAY_AUTHORIZATION_CACHE_TTL_MS: number = 30 * 1000;
3878
+ const MAX_SESSION_REPLAY_AUTHORIZATION_CACHE_ENTRIES: number = 2000;
3879
+
3880
+ interface CachedRumApplication {
3881
+ application: RumApplication;
3882
+ expiresAt: number;
3883
+ }
3884
+
3885
+ interface CachedSessionHeader {
3886
+ header: SessionReplaySessionHeader;
3887
+ expiresAt: number;
3888
+ }
3889
+
3890
+ const rumApplicationCache: Map<string, CachedRumApplication> = new Map<
3891
+ string,
3892
+ CachedRumApplication
3893
+ >();
3894
+ const sessionHeaderCache: Map<string, CachedSessionHeader> = new Map<
3895
+ string,
3896
+ CachedSessionHeader
3897
+ >();
3898
+
3899
+ type BoundedCacheSetFunction = <TValue>(
3900
+ map: Map<string, TValue>,
3901
+ key: string,
3902
+ value: TValue,
3903
+ ) => void;
3904
+
3905
+ const boundedCacheSet: BoundedCacheSetFunction = <TValue>(
3906
+ map: Map<string, TValue>,
3907
+ key: string,
3908
+ value: TValue,
3909
+ ): void => {
3910
+ if (
3911
+ map.size >= MAX_SESSION_REPLAY_AUTHORIZATION_CACHE_ENTRIES &&
3912
+ !map.has(key)
3913
+ ) {
3914
+ const oldest: string | undefined = map.keys().next().value;
3915
+
3916
+ if (oldest !== undefined) {
3917
+ map.delete(oldest);
3918
+ }
3919
+ }
3920
+
3921
+ map.delete(key);
3922
+ map.set(key, value);
3923
+ };
3924
+
3925
+ type LoadRumApplicationForAccessFunction = (data: {
3838
3926
  projectId: ObjectID;
3839
3927
  rumApplicationId: ObjectID;
3840
- databaseProps: DatabaseCommonInteractionProps;
3841
- permissions: Array<Permission>;
3842
- }) => Promise<RumApplication>;
3928
+ allowCached: boolean;
3929
+ }) => Promise<RumApplication | null>;
3843
3930
 
3844
- const assertSessionReplayApplicationAccess: AssertSessionReplayApplicationAccessFunction =
3931
+ const loadRumApplicationForAccess: LoadRumApplicationForAccessFunction =
3845
3932
  async (data: {
3846
3933
  projectId: ObjectID;
3847
3934
  rumApplicationId: ObjectID;
3848
- databaseProps: DatabaseCommonInteractionProps;
3849
- permissions: Array<Permission>;
3850
- }): Promise<RumApplication> => {
3851
- const scope: SessionReplayScope = getSessionReplayLabelScope(
3852
- data.databaseProps,
3853
- data.permissions,
3854
- );
3935
+ allowCached: boolean;
3936
+ }): Promise<RumApplication | null> => {
3937
+ const cacheKey: string = `${data.projectId.toString()}:${data.rumApplicationId.toString()}`;
3938
+
3939
+ if (data.allowCached) {
3940
+ const cached: CachedRumApplication | undefined =
3941
+ rumApplicationCache.get(cacheKey);
3942
+
3943
+ if (cached && cached.expiresAt > Date.now()) {
3944
+ return cached.application;
3945
+ }
3946
+ }
3855
3947
 
3856
3948
  const application: RumApplication | null =
3857
3949
  await RumApplicationService.findOneBy({
@@ -3870,6 +3962,45 @@ const assertSessionReplayApplicationAccess: AssertSessionReplayApplicationAccess
3870
3962
  },
3871
3963
  });
3872
3964
 
3965
+ if (application) {
3966
+ boundedCacheSet(rumApplicationCache, cacheKey, {
3967
+ application: application,
3968
+ expiresAt: Date.now() + SESSION_REPLAY_AUTHORIZATION_CACHE_TTL_MS,
3969
+ });
3970
+ }
3971
+
3972
+ return application;
3973
+ };
3974
+
3975
+ type AssertSessionReplayApplicationAccessFunction = (data: {
3976
+ projectId: ObjectID;
3977
+ rumApplicationId: ObjectID;
3978
+ databaseProps: DatabaseCommonInteractionProps;
3979
+ permissions: Array<Permission>;
3980
+ /* Serve the application's labels from the short-lived cache. */
3981
+ allowCached?: boolean | undefined;
3982
+ }) => Promise<RumApplication>;
3983
+
3984
+ const assertSessionReplayApplicationAccess: AssertSessionReplayApplicationAccessFunction =
3985
+ async (data: {
3986
+ projectId: ObjectID;
3987
+ rumApplicationId: ObjectID;
3988
+ databaseProps: DatabaseCommonInteractionProps;
3989
+ permissions: Array<Permission>;
3990
+ allowCached?: boolean | undefined;
3991
+ }): Promise<RumApplication> => {
3992
+ const scope: SessionReplayScope = getSessionReplayLabelScope(
3993
+ data.databaseProps,
3994
+ data.permissions,
3995
+ );
3996
+
3997
+ const application: RumApplication | null =
3998
+ await loadRumApplicationForAccess({
3999
+ projectId: data.projectId,
4000
+ rumApplicationId: data.rumApplicationId,
4001
+ allowCached: data.allowCached === true,
4002
+ });
4003
+
3873
4004
  /*
3874
4005
  * An application that does not exist in this project is refused the
3875
4006
  * same way an out-of-scope one is, so the endpoint cannot be used to
@@ -4032,6 +4163,179 @@ const resolveAccessibleRumApplicationIds: ResolveAccessibleRumApplicationIdsFunc
4032
4163
  return { applicationIds: accessibleIds, isTruncated: isTruncated };
4033
4164
  };
4034
4165
 
4166
+ interface AuthorizedSession {
4167
+ header: SessionReplaySessionHeader;
4168
+ /*
4169
+ * The RumApplication the header was authorized against, with its
4170
+ * labels, so a caller that needs a second, narrower decision (the
4171
+ * identity columns) does not load it again.
4172
+ */
4173
+ application: RumApplication;
4174
+ }
4175
+
4176
+ /*
4177
+ * Why a sessionId has no playable header. Each answer carries a
4178
+ * different code word in its message so a client can tell them apart
4179
+ * without parsing prose, and each is a 404: the id was well-formed, there
4180
+ * is simply nothing at it.
4181
+ */
4182
+ const GENERIC_MISSING_SESSION_MESSAGE: string =
4183
+ "not-found: No session replay exists with this id in this project.";
4184
+
4185
+ /*
4186
+ * May this caller be told anything specific about a recording belonging to
4187
+ * the named application?
4188
+ *
4189
+ * Deliberately NOT assertSessionReplayApplicationAccess: this runs on the
4190
+ * path where the header row is already gone, so the application row may
4191
+ * legitimately be gone with it, and an unrestricted caller (a project
4192
+ * owner, or anyone holding an unscoped payload grant) must not lose the
4193
+ * "expired on <date>" answer because of a deleted application. Only a
4194
+ * label-scoped caller needs the row, and for them a row that cannot be
4195
+ * loaded is refused.
4196
+ */
4197
+ type IsApplicationInSessionReplayScopeByIdFunction = (data: {
4198
+ projectId: ObjectID;
4199
+ rumApplicationId: string;
4200
+ databaseProps: DatabaseCommonInteractionProps;
4201
+ }) => Promise<boolean>;
4202
+
4203
+ const isApplicationInSessionReplayScopeById: IsApplicationInSessionReplayScopeByIdFunction =
4204
+ async (data: {
4205
+ projectId: ObjectID;
4206
+ rumApplicationId: string;
4207
+ databaseProps: DatabaseCommonInteractionProps;
4208
+ }): Promise<boolean> => {
4209
+ let scope: SessionReplayScope;
4210
+
4211
+ try {
4212
+ scope = getSessionReplayLabelScope(
4213
+ data.databaseProps,
4214
+ SESSION_REPLAY_PAYLOAD_PERMISSIONS,
4215
+ );
4216
+ } catch {
4217
+ /* A scope this path cannot enforce is refused, never widened. */
4218
+ return false;
4219
+ }
4220
+
4221
+ if (scope.isUnrestricted) {
4222
+ return true;
4223
+ }
4224
+
4225
+ if (!ObjectID.isValidUUID(data.rumApplicationId)) {
4226
+ return false;
4227
+ }
4228
+
4229
+ const application: RumApplication | null =
4230
+ await loadRumApplicationForAccess({
4231
+ projectId: data.projectId,
4232
+ rumApplicationId: new ObjectID(data.rumApplicationId),
4233
+ allowCached: true,
4234
+ });
4235
+
4236
+ if (!application) {
4237
+ return false;
4238
+ }
4239
+
4240
+ return isApplicationInSessionReplayScope({
4241
+ scope: scope,
4242
+ application: application,
4243
+ });
4244
+ };
4245
+
4246
+ type ExplainMissingSessionFunction = (data: {
4247
+ projectId: ObjectID;
4248
+ sessionId: string;
4249
+ rumApplicationId: ObjectID | undefined;
4250
+ databaseProps: DatabaseCommonInteractionProps;
4251
+ }) => Promise<NotFoundException>;
4252
+
4253
+ const explainMissingSession: ExplainMissingSessionFunction = async (data: {
4254
+ projectId: ObjectID;
4255
+ sessionId: string;
4256
+ rumApplicationId: ObjectID | undefined;
4257
+ databaseProps: DatabaseCommonInteractionProps;
4258
+ }): Promise<NotFoundException> => {
4259
+ /*
4260
+ * The expired header is resolved FIRST, and not because it is the more
4261
+ * likely answer: it is the only lookup that names an application, and
4262
+ * nothing specific may be disclosed until that application has been
4263
+ * authorized.
4264
+ *
4265
+ * The expiry answer carries the recording's existence, when it started
4266
+ * and what retention the owning application runs. Answered before the
4267
+ * access check - which is where it used to sit, since this runs on the
4268
+ * path where getSessionHeader found nothing to authorize AGAINST - it let
4269
+ * a label-scoped reviewer probe session ids and learn all three for
4270
+ * applications outside their scope. That is precisely the existence
4271
+ * probing assertSessionReplayApplicationAccess refuses "the same way" for
4272
+ * a session that DOES exist.
4273
+ *
4274
+ * This read is deliberately retention-free (an expired row is the whole
4275
+ * point), so it is the one place a scope check has to be written out by
4276
+ * hand rather than inherited from resolveAuthorizedSession.
4277
+ */
4278
+ const expired: SessionReplayExpiredSessionInfo | null =
4279
+ await SessionReplayReadService.getExpiredSessionInfo({
4280
+ projectId: data.projectId,
4281
+ sessionId: data.sessionId,
4282
+ rumApplicationId: data.rumApplicationId,
4283
+ });
4284
+
4285
+ if (expired && expired.rumApplicationId) {
4286
+ if (
4287
+ !(await isApplicationInSessionReplayScopeById({
4288
+ projectId: data.projectId,
4289
+ rumApplicationId: expired.rumApplicationId,
4290
+ databaseProps: data.databaseProps,
4291
+ }))
4292
+ ) {
4293
+ return new NotFoundException(GENERIC_MISSING_SESSION_MESSAGE);
4294
+ }
4295
+ }
4296
+
4297
+ /*
4298
+ * Erasure is checked only once the caller is entitled to a specific
4299
+ * answer. An erased session may still have a header row until the
4300
+ * ClickHouse mutation lands, and "expired" would be the wrong story for
4301
+ * a recording that was deliberately destroyed - so it is reported ahead
4302
+ * of expiry. The tombstone throws when Redis cannot answer; that is a
4303
+ * "cannot tell", which falls through to the header-based answers.
4304
+ */
4305
+ let isErased: boolean = false;
4306
+
4307
+ try {
4308
+ isErased = await isSessionErased({
4309
+ projectId: data.projectId.toString(),
4310
+ sessionId: data.sessionId,
4311
+ });
4312
+ } catch {
4313
+ isErased = false;
4314
+ }
4315
+
4316
+ if (isErased) {
4317
+ return new NotFoundException(
4318
+ "erased: This recording was erased by a data subject request and cannot be played back.",
4319
+ );
4320
+ }
4321
+
4322
+ if (expired) {
4323
+ const retentionDays: number = Math.max(
4324
+ 1,
4325
+ Math.round(
4326
+ (expired.expiresAt.getTime() - expired.startTime.getTime()) /
4327
+ (24 * 60 * 60 * 1000),
4328
+ ),
4329
+ );
4330
+
4331
+ return new NotFoundException(
4332
+ `expired: This recording expired on ${expired.expiresAt.toISOString()} under the application's ${retentionDays}-day retention. Its session signals may still be available from logs, traces and exceptions.`,
4333
+ );
4334
+ }
4335
+
4336
+ return new NotFoundException(GENERIC_MISSING_SESSION_MESSAGE);
4337
+ };
4338
+
4035
4339
  /*
4036
4340
  * Resolve a caller-supplied sessionId to its header, scoped strictly to
4037
4341
  * the tenant, and authorize the owning application. Every payload-bearing
@@ -4042,34 +4346,172 @@ type ResolveAuthorizedSessionFunction = (data: {
4042
4346
  projectId: ObjectID;
4043
4347
  sessionId: string;
4044
4348
  databaseProps: DatabaseCommonInteractionProps;
4045
- }) => Promise<SessionReplaySessionHeader>;
4349
+ /*
4350
+ * Disambiguator only (see getSessionHeader): which application's
4351
+ * recording to read when the same sessionId exists under several. The
4352
+ * application the resolved header names is what gets authorized, so a
4353
+ * caller cannot widen access by naming one.
4354
+ */
4355
+ rumApplicationId?: ObjectID | undefined;
4356
+ /*
4357
+ * Serve the header and the application's labels from the short-lived
4358
+ * caches. For the chunk and heartbeat hot paths; the manifest resolves
4359
+ * fresh so a live session's header is never stale for a poll.
4360
+ */
4361
+ allowCached?: boolean | undefined;
4362
+ }) => Promise<AuthorizedSession>;
4046
4363
 
4047
4364
  const resolveAuthorizedSession: ResolveAuthorizedSessionFunction =
4048
4365
  async (data: {
4049
4366
  projectId: ObjectID;
4050
4367
  sessionId: string;
4051
4368
  databaseProps: DatabaseCommonInteractionProps;
4052
- }): Promise<SessionReplaySessionHeader> => {
4053
- const header: SessionReplaySessionHeader | null =
4054
- await SessionReplayReadService.getSessionHeader({
4369
+ rumApplicationId?: ObjectID | undefined;
4370
+ allowCached?: boolean | undefined;
4371
+ }): Promise<AuthorizedSession> => {
4372
+ const headerCacheKey: string = `${data.projectId.toString()}:${data.sessionId}:${
4373
+ data.rumApplicationId ? data.rumApplicationId.toString() : ""
4374
+ }`;
4375
+
4376
+ let header: SessionReplaySessionHeader | null = null;
4377
+
4378
+ if (data.allowCached) {
4379
+ const cached: CachedSessionHeader | undefined =
4380
+ sessionHeaderCache.get(headerCacheKey);
4381
+
4382
+ if (cached && cached.expiresAt > Date.now()) {
4383
+ header = cached.header;
4384
+ }
4385
+ }
4386
+
4387
+ if (!header) {
4388
+ header = await SessionReplayReadService.getSessionHeader({
4055
4389
  projectId: data.projectId,
4056
4390
  sessionId: data.sessionId,
4391
+ rumApplicationId: data.rumApplicationId,
4057
4392
  });
4058
4393
 
4394
+ if (header) {
4395
+ boundedCacheSet(sessionHeaderCache, headerCacheKey, {
4396
+ header: header,
4397
+ expiresAt: Date.now() + SESSION_REPLAY_AUTHORIZATION_CACHE_TTL_MS,
4398
+ });
4399
+ }
4400
+ }
4401
+
4059
4402
  if (!header) {
4060
- throw new BadDataException("Session replay not found.");
4403
+ throw await explainMissingSession({
4404
+ projectId: data.projectId,
4405
+ sessionId: data.sessionId,
4406
+ rumApplicationId: data.rumApplicationId,
4407
+ databaseProps: data.databaseProps,
4408
+ });
4061
4409
  }
4062
4410
 
4063
- await assertSessionReplayApplicationAccess({
4064
- projectId: data.projectId,
4065
- rumApplicationId: new ObjectID(header.rumApplicationId),
4066
- databaseProps: data.databaseProps,
4067
- permissions: SESSION_REPLAY_PAYLOAD_PERMISSIONS,
4068
- });
4411
+ const application: RumApplication =
4412
+ await assertSessionReplayApplicationAccess({
4413
+ projectId: data.projectId,
4414
+ rumApplicationId: new ObjectID(header.rumApplicationId),
4415
+ databaseProps: data.databaseProps,
4416
+ permissions: SESSION_REPLAY_PAYLOAD_PERMISSIONS,
4417
+ allowCached: data.allowCached,
4418
+ });
4069
4419
 
4070
- return header;
4420
+ return { header: header, application: application };
4071
4421
  };
4072
4422
 
4423
+ /*
4424
+ * An optional application id off the body: absent or empty means "not
4425
+ * given", anything else must be a well-formed id.
4426
+ */
4427
+ type ReadOptionalObjectIdFromBodyFunction = (
4428
+ body: JSONObject,
4429
+ key: string,
4430
+ ) => ObjectID | undefined;
4431
+
4432
+ const readOptionalObjectIdFromBody: ReadOptionalObjectIdFromBodyFunction = (
4433
+ body: JSONObject,
4434
+ key: string,
4435
+ ): ObjectID | undefined => {
4436
+ const value: unknown = body[key];
4437
+
4438
+ if (value === undefined || value === null || value === "") {
4439
+ return undefined;
4440
+ }
4441
+
4442
+ if (typeof value !== "string" || !ObjectID.isValidUUID(value)) {
4443
+ throw new BadDataException(`${key} is not a valid id`);
4444
+ }
4445
+
4446
+ return new ObjectID(value);
4447
+ };
4448
+
4449
+ /*
4450
+ * Optional ISO timestamps off the body. A value that is present but does
4451
+ * not parse is a bad request, not an Invalid Date bound into ClickHouse
4452
+ * (which surfaces as a driver error and a 500).
4453
+ */
4454
+ type ReadOptionalDateFromBodyFunction = (
4455
+ body: JSONObject,
4456
+ key: string,
4457
+ ) => Date | undefined;
4458
+
4459
+ const readOptionalDateFromBody: ReadOptionalDateFromBodyFunction = (
4460
+ body: JSONObject,
4461
+ key: string,
4462
+ ): Date | undefined => {
4463
+ const value: unknown = body[key];
4464
+
4465
+ if (value === undefined || value === null || value === "") {
4466
+ return undefined;
4467
+ }
4468
+
4469
+ if (typeof value !== "string" && typeof value !== "number") {
4470
+ throw new BadDataException(`${key} must be an ISO-8601 timestamp`);
4471
+ }
4472
+
4473
+ const parsed: Date =
4474
+ typeof value === "number"
4475
+ ? new Date(value)
4476
+ : OneUptimeDate.fromString(value);
4477
+
4478
+ if (!Number.isFinite(parsed.getTime())) {
4479
+ throw new BadDataException(`${key} must be an ISO-8601 timestamp`);
4480
+ }
4481
+
4482
+ return parsed;
4483
+ };
4484
+
4485
+ /*
4486
+ * A page size off the body: absent means the default; present means a
4487
+ * positive integer, because `LIMIT 2.5` is a driver error and a 500.
4488
+ */
4489
+ type ReadLimitFromBodyFunction = (
4490
+ body: JSONObject,
4491
+ defaultLimit: number,
4492
+ maxLimit: number,
4493
+ ) => number;
4494
+
4495
+ const readLimitFromBody: ReadLimitFromBodyFunction = (
4496
+ body: JSONObject,
4497
+ defaultLimit: number,
4498
+ maxLimit: number,
4499
+ ): number => {
4500
+ const value: unknown = body["limit"];
4501
+
4502
+ if (value === undefined || value === null) {
4503
+ return defaultLimit;
4504
+ }
4505
+
4506
+ if (typeof value !== "number" || !Number.isInteger(value) || value < 1) {
4507
+ throw new BadDataException(
4508
+ `limit must be a whole number between 1 and ${maxLimit}`,
4509
+ );
4510
+ }
4511
+
4512
+ return Math.min(value, maxLimit);
4513
+ };
4514
+
4073
4515
  /*
4074
4516
  * Object ids arrive as untrusted strings. They are always bound as query
4075
4517
  * parameters rather than interpolated, so a bad value cannot inject SQL -
@@ -4104,6 +4546,14 @@ const readObjectIdFromBody: ReadObjectIdFromBodyFunction = (
4104
4546
 
4105
4547
  type ReadSessionIdFromBodyFunction = (body: JSONObject) => string;
4106
4548
 
4549
+ /*
4550
+ * A session id is 32 hex characters minted in the browser. The cap is
4551
+ * generous rather than exact - older recorders and hand-written API
4552
+ * callers exist - but it is a cap: an unbounded caller-supplied string
4553
+ * reaches ClickHouse as a bound parameter on a hot path.
4554
+ */
4555
+ const MAX_SESSION_REPLAY_SESSION_ID_LENGTH: number = 128;
4556
+
4107
4557
  const readSessionIdFromBody: ReadSessionIdFromBodyFunction = (
4108
4558
  body: JSONObject,
4109
4559
  ): string => {
@@ -4113,9 +4563,34 @@ const readSessionIdFromBody: ReadSessionIdFromBodyFunction = (
4113
4563
  throw new BadDataException("sessionId is required");
4114
4564
  }
4115
4565
 
4566
+ if (sessionId.length > MAX_SESSION_REPLAY_SESSION_ID_LENGTH) {
4567
+ throw new BadDataException(
4568
+ `sessionId must be at most ${MAX_SESSION_REPLAY_SESSION_ID_LENGTH} characters.`,
4569
+ );
4570
+ }
4571
+
4116
4572
  return sessionId;
4117
4573
  };
4118
4574
 
4575
+ /*
4576
+ * Caps on the list's filter inputs.
4577
+ *
4578
+ * Every array filter becomes an `IN (...)` inside a HAVING, which
4579
+ * ClickHouse evaluates per GROUP over the whole window - so the cost of a
4580
+ * request is the caller's array length times the number of sessions in
4581
+ * range. Uncapped, one request carrying tens of thousands of browser names
4582
+ * is a cheap denial of service against the list for any holder of the list
4583
+ * permission. The limits are far above any real UI: the filter panel
4584
+ * offers a couple of dozen browsers, and no session has more than a
4585
+ * handful of routes.
4586
+ *
4587
+ * Values are TRUNCATED and the array is SLICED rather than refused: an
4588
+ * over-long value simply cannot match anything a bounded column holds, so
4589
+ * a 400 would add nothing but a confusing error.
4590
+ */
4591
+ const MAX_SESSION_REPLAY_FILTER_ARRAY_LENGTH: number = 50;
4592
+ const MAX_SESSION_REPLAY_FILTER_VALUE_LENGTH: number = 256;
4593
+
4119
4594
  type ReadStringArrayFromBodyFunction = (
4120
4595
  body: JSONObject,
4121
4596
  key: string,
@@ -4131,25 +4606,125 @@ const readStringArrayFromBody: ReadStringArrayFromBodyFunction = (
4131
4606
  return undefined;
4132
4607
  }
4133
4608
 
4134
- const strings: Array<string> = value.filter(
4135
- (item: unknown): item is string => {
4136
- return typeof item === "string" && item.length > 0;
4137
- },
4138
- );
4609
+ const strings: Array<string> = [];
4610
+
4611
+ for (const item of value) {
4612
+ if (typeof item !== "string" || item.length === 0) {
4613
+ continue;
4614
+ }
4615
+
4616
+ strings.push(item.substring(0, MAX_SESSION_REPLAY_FILTER_VALUE_LENGTH));
4617
+
4618
+ if (strings.length >= MAX_SESSION_REPLAY_FILTER_ARRAY_LENGTH) {
4619
+ break;
4620
+ }
4621
+ }
4139
4622
 
4140
4623
  return strings.length > 0 ? strings : undefined;
4141
4624
  };
4142
4625
 
4143
- // --- Session Replay List Endpoint ---
4626
+ /*
4627
+ * A single bounded string filter off the body. Same reasoning as the array
4628
+ * cap above: the value is compared per group, and nothing a column holds
4629
+ * is longer than this.
4630
+ */
4631
+ type ReadBoundedStringFromBodyFunction = (
4632
+ body: JSONObject,
4633
+ key: string,
4634
+ ) => string | undefined;
4144
4635
 
4145
- router.post(
4146
- "/telemetry/rum/session-replay/list",
4147
- ...requireSessionReplayListAccess,
4148
- async (
4149
- req: ExpressRequest,
4150
- res: ExpressResponse,
4151
- next: NextFunction,
4152
- ): Promise<void> => {
4636
+ const readBoundedStringFromBody: ReadBoundedStringFromBodyFunction = (
4637
+ body: JSONObject,
4638
+ key: string,
4639
+ ): string | undefined => {
4640
+ const value: unknown = body[key];
4641
+
4642
+ if (typeof value !== "string" || value.length === 0) {
4643
+ return undefined;
4644
+ }
4645
+
4646
+ return value.substring(0, MAX_SESSION_REPLAY_FILTER_VALUE_LENGTH);
4647
+ };
4648
+
4649
+ /*
4650
+ * The tag filter: a plain object of string pairs, each side bounded by the
4651
+ * same caps the ingest applied when it stored the map, so a filter can
4652
+ * never be longer than a value that could match it. Anything else reads
4653
+ * as "no tag filter".
4654
+ */
4655
+ type ReadTagFilterFromBodyFunction = (
4656
+ filters: JSONObject,
4657
+ ) => Record<string, string> | undefined;
4658
+
4659
+ const readTagFilterFromBody: ReadTagFilterFromBodyFunction = (
4660
+ filters: JSONObject,
4661
+ ): Record<string, string> | undefined => {
4662
+ const value: unknown = filters["tags"];
4663
+
4664
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
4665
+ return undefined;
4666
+ }
4667
+
4668
+ const tags: Record<string, string> = {};
4669
+ let count: number = 0;
4670
+
4671
+ for (const key of Object.keys(value as Record<string, unknown>)) {
4672
+ const entry: unknown = (value as Record<string, unknown>)[key];
4673
+
4674
+ if (typeof entry !== "string" || key.length === 0) {
4675
+ continue;
4676
+ }
4677
+
4678
+ if (count >= SESSION_REPLAY_MAX_TAG_KEYS) {
4679
+ break;
4680
+ }
4681
+
4682
+ tags[key.substring(0, SESSION_REPLAY_MAX_TAG_KEY_LENGTH)] = entry.substring(
4683
+ 0,
4684
+ SESSION_REPLAY_MAX_TAG_VALUE_LENGTH,
4685
+ );
4686
+ count++;
4687
+ }
4688
+
4689
+ return count > 0 ? tags : undefined;
4690
+ };
4691
+
4692
+ /*
4693
+ * Can this cursor's sortValue actually be bound into a query?
4694
+ *
4695
+ * parseSessionReplayListCursor only checks Number.isFinite, which admits
4696
+ * 1e300. For the startTime ordering that value becomes `new Date(1e300)` -
4697
+ * an Invalid Date, which renders as NaN text and is rejected by the
4698
+ * ClickHouse driver, so a crafted or corrupted cursor answered 500 instead
4699
+ * of the 400 the handler promises. For the aggregate orderings the value is
4700
+ * a count or a duration, and a negative one belongs to no page.
4701
+ */
4702
+ type IsBindableCursorSortValueFunction = (
4703
+ cursor: SessionReplayListCursor,
4704
+ sortBy: SessionReplaySortBy,
4705
+ ) => boolean;
4706
+
4707
+ const isBindableCursorSortValue: IsBindableCursorSortValueFunction = (
4708
+ cursor: SessionReplayListCursor,
4709
+ sortBy: SessionReplaySortBy,
4710
+ ): boolean => {
4711
+ if (sortBy === "startTime") {
4712
+ return Number.isFinite(new Date(cursor.sortValue).getTime());
4713
+ }
4714
+
4715
+ return cursor.sortValue >= 0;
4716
+ };
4717
+
4718
+ // --- Session Replay List Endpoint ---
4719
+
4720
+ router.post(
4721
+ "/telemetry/rum/session-replay/list",
4722
+ ...requireSessionReplayListAccess,
4723
+ async (
4724
+ req: ExpressRequest,
4725
+ res: ExpressResponse,
4726
+ next: NextFunction,
4727
+ ): Promise<void> => {
4153
4728
  try {
4154
4729
  const databaseProps: DatabaseCommonInteractionProps =
4155
4730
  await CommonAPI.getDatabaseCommonInteractionProps(req);
@@ -4186,13 +4761,56 @@ router.post(
4186
4761
  permissions: SESSION_REPLAY_LIST_PERMISSIONS,
4187
4762
  });
4188
4763
 
4189
- const startTime: Date = body["startTime"]
4190
- ? OneUptimeDate.fromString(body["startTime"] as string)
4191
- : OneUptimeDate.addRemoveDays(OneUptimeDate.getCurrentDate(), -7);
4764
+ const startTime: Date =
4765
+ readOptionalDateFromBody(body, "startTime") ||
4766
+ OneUptimeDate.addRemoveDays(OneUptimeDate.getCurrentDate(), -7);
4192
4767
 
4193
- const endTime: Date = body["endTime"]
4194
- ? OneUptimeDate.fromString(body["endTime"] as string)
4195
- : OneUptimeDate.getCurrentDate();
4768
+ const endTime: Date =
4769
+ readOptionalDateFromBody(body, "endTime") ||
4770
+ OneUptimeDate.getCurrentDate();
4771
+
4772
+ /*
4773
+ * An inverted window matches nothing, and an empty list with a 200
4774
+ * is exactly the answer a client cannot distinguish from "no
4775
+ * sessions" - so it is a 400 with the reason instead.
4776
+ */
4777
+ if (startTime.getTime() > endTime.getTime()) {
4778
+ return Response.sendErrorResponse(
4779
+ req,
4780
+ res,
4781
+ new BadDataException("startTime must not be after endTime"),
4782
+ );
4783
+ }
4784
+
4785
+ const limit: number = readLimitFromBody(
4786
+ body,
4787
+ DEFAULT_SESSION_REPLAY_LIST_LIMIT,
4788
+ MAX_SESSION_REPLAY_LIST_LIMIT,
4789
+ );
4790
+
4791
+ const rawSortBy: unknown = body["sortBy"];
4792
+
4793
+ if (
4794
+ rawSortBy !== undefined &&
4795
+ rawSortBy !== null &&
4796
+ (typeof rawSortBy !== "string" ||
4797
+ !(SESSION_REPLAY_SORT_BY_VALUES as ReadonlyArray<string>).includes(
4798
+ rawSortBy,
4799
+ ))
4800
+ ) {
4801
+ return Response.sendErrorResponse(
4802
+ req,
4803
+ res,
4804
+ new BadDataException(
4805
+ `sortBy must be one of ${SESSION_REPLAY_SORT_BY_VALUES.join(", ")}.`,
4806
+ ),
4807
+ );
4808
+ }
4809
+
4810
+ const sortBy: SessionReplaySortBy =
4811
+ typeof rawSortBy === "string"
4812
+ ? (rawSortBy as SessionReplaySortBy)
4813
+ : "startTime";
4196
4814
 
4197
4815
  /*
4198
4816
  * The narrower identity ACL, resolved BEFORE the filters are built.
@@ -4239,6 +4857,32 @@ router.post(
4239
4857
  );
4240
4858
  }
4241
4859
 
4860
+ /*
4861
+ * A filter the server understood but did not apply, named in the
4862
+ * response.
4863
+ *
4864
+ * The identity filter is gated on the narrower identity permission.
4865
+ * Dropping it silently is the dangerous half of that gate: the
4866
+ * request "show me jane@example.com's sessions" then answers 200 with
4867
+ * EVERY session in the application, and the caller has no way to tell
4868
+ * - least of all when the application has no sessions at all, where
4869
+ * even inspecting the rows cannot reveal it. A support engineer opens
4870
+ * the wrong recording, and each opening writes an audit row against a
4871
+ * real end user.
4872
+ *
4873
+ * Answered as data rather than as a 403 because the rest of the list
4874
+ * IS something the caller may read: the page renders the sessions and
4875
+ * says the filter was ignored, instead of failing outright.
4876
+ */
4877
+ const ignoredFilters: Array<string> = [];
4878
+
4879
+ if (
4880
+ !includeIdentifiedUserLabel &&
4881
+ SessionReplayIdentity.isUsableUserRef(rawFilters["identifiedUserRef"])
4882
+ ) {
4883
+ ignoredFilters.push("identifiedUserRef");
4884
+ }
4885
+
4242
4886
  const filters: SessionReplayListFilters = {
4243
4887
  ...(typeof rawFilters["hasError"] === "boolean" && {
4244
4888
  hasError: rawFilters["hasError"],
@@ -4294,33 +4938,116 @@ router.post(
4294
4938
  * not guessable and is already returned to every list-capable
4295
4939
  * caller, so it needs no identity gate of its own.
4296
4940
  */
4297
- ...(typeof rawFilters["identifiedUserKey"] === "string" &&
4941
+ ...(readBoundedStringFromBody(rawFilters, "identifiedUserKey") &&
4298
4942
  !SessionReplayIdentity.isUsableUserRef(
4299
4943
  rawFilters["identifiedUserRef"],
4300
4944
  ) && {
4301
- identifiedUserKey: rawFilters["identifiedUserKey"],
4945
+ identifiedUserKey: readBoundedStringFromBody(
4946
+ rawFilters,
4947
+ "identifiedUserKey",
4948
+ ),
4302
4949
  }),
4303
- ...(typeof rawFilters["route"] === "string" && {
4304
- route: rawFilters["route"],
4950
+ ...(readBoundedStringFromBody(rawFilters, "route") && {
4951
+ route: readBoundedStringFromBody(rawFilters, "route"),
4305
4952
  }),
4306
- ...(typeof rawFilters["minDurationMs"] === "number" && {
4307
- minDurationMs: rawFilters["minDurationMs"],
4953
+ ...(typeof rawFilters["minDurationMs"] === "number" &&
4954
+ Number.isFinite(rawFilters["minDurationMs"]) && {
4955
+ minDurationMs: rawFilters["minDurationMs"],
4956
+ }),
4957
+ ...(typeof rawFilters["hasIdentifiedUser"] === "boolean" && {
4958
+ hasIdentifiedUser: rawFilters["hasIdentifiedUser"],
4959
+ }),
4960
+ ...(typeof rawFilters["isPlayable"] === "boolean" && {
4961
+ isPlayable: rawFilters["isPlayable"],
4962
+ }),
4963
+ ...(typeof rawFilters["hasTraces"] === "boolean" && {
4964
+ hasTraces: rawFilters["hasTraces"],
4965
+ }),
4966
+ ...(typeof rawFilters["urlPrefix"] === "string" &&
4967
+ rawFilters["urlPrefix"].length > 0 && {
4968
+ urlPrefix: rawFilters["urlPrefix"].substring(
4969
+ 0,
4970
+ SESSION_REPLAY_LIST_SEARCH_MAX_LENGTH,
4971
+ ),
4972
+ }),
4973
+ ...(readTagFilterFromBody(rawFilters) && {
4974
+ tags: readTagFilterFromBody(rawFilters),
4308
4975
  }),
4309
4976
  };
4310
4977
 
4311
- const rawCursor: JSONObject | undefined = body["cursor"]
4312
- ? (body["cursor"] as JSONObject)
4313
- : undefined;
4978
+ /*
4979
+ * Free text is the one predicate that cannot use an index: it is a
4980
+ * substring scan of every header in the window. The string cap
4981
+ * keeps each comparison cheap; the window cap keeps the number of
4982
+ * comparisons bounded, and is answered with its own message so the
4983
+ * list can say "narrow the range" rather than "no sessions".
4984
+ */
4985
+ const rawSearch: unknown = rawFilters["search"];
4314
4986
 
4315
- const cursor: SessionReplayListCursor | undefined =
4316
- rawCursor &&
4317
- typeof rawCursor["startTimeUnixMs"] === "number" &&
4318
- typeof rawCursor["sessionId"] === "string"
4319
- ? {
4320
- startTimeUnixMs: rawCursor["startTimeUnixMs"],
4321
- sessionId: rawCursor["sessionId"],
4322
- }
4323
- : undefined;
4987
+ if (rawSearch !== undefined && rawSearch !== null && rawSearch !== "") {
4988
+ if (typeof rawSearch !== "string") {
4989
+ return Response.sendErrorResponse(
4990
+ req,
4991
+ res,
4992
+ new BadDataException("search must be a string"),
4993
+ );
4994
+ }
4995
+
4996
+ if (rawSearch.length > SESSION_REPLAY_LIST_SEARCH_MAX_LENGTH) {
4997
+ return Response.sendErrorResponse(
4998
+ req,
4999
+ res,
5000
+ new BadDataException(
5001
+ `search must be at most ${SESSION_REPLAY_LIST_SEARCH_MAX_LENGTH} characters.`,
5002
+ ),
5003
+ );
5004
+ }
5005
+
5006
+ const windowMs: number = endTime.getTime() - startTime.getTime();
5007
+
5008
+ if (
5009
+ windowMs >
5010
+ SESSION_REPLAY_LIST_SEARCH_MAX_WINDOW_DAYS * 24 * 60 * 60 * 1000
5011
+ ) {
5012
+ return Response.sendErrorResponse(
5013
+ req,
5014
+ res,
5015
+ new BadDataException(
5016
+ `Search covers at most ${SESSION_REPLAY_LIST_SEARCH_MAX_WINDOW_DAYS} days at a time. Narrow the range to search it.`,
5017
+ ),
5018
+ );
5019
+ }
5020
+
5021
+ if (rawSearch.trim().length > 0) {
5022
+ filters.search = rawSearch.trim();
5023
+ }
5024
+ }
5025
+
5026
+ /*
5027
+ * Both cursor shapes are accepted: the legacy {startTimeUnixMs,
5028
+ * sessionId} one an older Dashboard or a bookmark still sends (it
5029
+ * means "newest first"), and the sorted one. A cursor for a
5030
+ * different ordering than the one requested is refused by the
5031
+ * service rather than silently mis-paged.
5032
+ */
5033
+ const cursor: SessionReplayListCursor | null =
5034
+ body["cursor"] !== undefined && body["cursor"] !== null
5035
+ ? parseSessionReplayListCursor(body["cursor"])
5036
+ : null;
5037
+
5038
+ if (
5039
+ body["cursor"] !== undefined &&
5040
+ body["cursor"] !== null &&
5041
+ (cursor === null || !isBindableCursorSortValue(cursor, sortBy))
5042
+ ) {
5043
+ return Response.sendErrorResponse(
5044
+ req,
5045
+ res,
5046
+ new BadDataException(
5047
+ "cursor must be the nextCursor of a previous page.",
5048
+ ),
5049
+ );
5050
+ }
4324
5051
 
4325
5052
  const result: SessionReplayListResult =
4326
5053
  await SessionReplayReadService.listSessions({
@@ -4329,17 +5056,39 @@ router.post(
4329
5056
  startTime: startTime,
4330
5057
  endTime: endTime,
4331
5058
  filters: filters,
4332
- limit:
4333
- typeof body["limit"] === "number"
4334
- ? (body["limit"] as number)
4335
- : DEFAULT_SESSION_REPLAY_LIST_LIMIT,
4336
- ...(cursor !== undefined && { cursor }),
5059
+ limit: limit,
5060
+ sortBy: sortBy,
5061
+ ...(cursor !== null && { cursor }),
4337
5062
  includeIdentifiedUserLabel: includeIdentifiedUserLabel,
4338
5063
  });
4339
5064
 
5065
+ /*
5066
+ * The legacy cursor shape is still EMITTED for the newest-first sort
5067
+ * so an older Dashboard keeps paging; every other sort emits the
5068
+ * generalised shape, which such a client never asks for.
5069
+ */
5070
+ const nextCursor: JSONObject | null = result.nextCursor
5071
+ ? sortBy === "startTime"
5072
+ ? {
5073
+ startTimeUnixMs: result.nextCursor.sortValue,
5074
+ sessionId: result.nextCursor.sessionId,
5075
+ }
5076
+ : {
5077
+ sortBy: result.nextCursor.sortBy,
5078
+ sortValue: result.nextCursor.sortValue,
5079
+ sessionId: result.nextCursor.sessionId,
5080
+ }
5081
+ : null;
5082
+
4340
5083
  return Response.sendJsonObjectResponse(req, res, {
4341
5084
  sessions: result.sessions as unknown as JSONObject,
4342
- nextCursor: result.nextCursor as unknown as JSONObject,
5085
+ nextCursor: nextCursor,
5086
+ /*
5087
+ * Always present, empty when everything asked for was applied, so a
5088
+ * client can read it without having to distinguish "no ignored
5089
+ * filters" from "an older server that never said".
5090
+ */
5091
+ ignoredFilters: ignoredFilters as unknown as JSONArray,
4343
5092
  });
4344
5093
  } catch (err: unknown) {
4345
5094
  next(err);
@@ -4375,13 +5124,21 @@ router.post(
4375
5124
  const body: JSONObject = req.body as JSONObject;
4376
5125
  const sessionId: string = readSessionIdFromBody(body);
4377
5126
 
4378
- const header: SessionReplaySessionHeader = await resolveAuthorizedSession(
4379
- {
4380
- projectId: projectId,
4381
- sessionId: sessionId,
4382
- databaseProps: databaseProps,
4383
- },
4384
- );
5127
+ /*
5128
+ * Optional disambiguator, validated but NOT trusted: the header it
5129
+ * selects still names the application that gets authorized.
5130
+ */
5131
+ const requestedApplicationId: ObjectID | undefined =
5132
+ readOptionalObjectIdFromBody(body, "rumApplicationId");
5133
+
5134
+ const authorized: AuthorizedSession = await resolveAuthorizedSession({
5135
+ projectId: projectId,
5136
+ sessionId: sessionId,
5137
+ databaseProps: databaseProps,
5138
+ rumApplicationId: requestedApplicationId,
5139
+ });
5140
+
5141
+ const header: SessionReplaySessionHeader = authorized.header;
4385
5142
 
4386
5143
  /*
4387
5144
  * The authorized application, resolved server-side from the header.
@@ -4395,52 +5152,135 @@ router.post(
4395
5152
  );
4396
5153
 
4397
5154
  /*
4398
- * The audit row is written BEFORE the manifest is built, not after.
4399
- * A read that fails halfway through still happened, and an audit
4400
- * that only records successful reads is an audit an attacker can
4401
- * evade by aborting the request.
5155
+ * A live-session poll reuses the view row the first read created.
5156
+ *
5157
+ * The player re-fetches the manifest every 30s while a session is
5158
+ * still recording, and each of those is the same person continuing
5159
+ * the same viewing, not a new disclosure. Writing a row per poll
5160
+ * would turn one viewing into dozens of audit entries and bury the
5161
+ * signal the audit exists for. The row is reused ONLY when the
5162
+ * caller proves it is theirs (looked up by viewedByUserId) AND it
5163
+ * is for this session; anything else - somebody else's viewId, a
5164
+ * different session, an id that no longer exists - is a fresh
5165
+ * recordView, exactly as if isRefresh had not been sent.
4402
5166
  */
4403
- const view: RumSessionReplayView =
4404
- await RumSessionReplayViewService.recordView({
5167
+ let viewId: string | null = null;
5168
+
5169
+ const isRefresh: boolean = body["isRefresh"] === true;
5170
+ const refreshViewId: ObjectID | undefined = isRefresh
5171
+ ? readOptionalObjectIdFromBody(body, "viewId")
5172
+ : undefined;
5173
+
5174
+ if (refreshViewId && databaseProps.userId) {
5175
+ const ownView: RumSessionReplayView | null =
5176
+ await RumSessionReplayViewService.findOwnView({
5177
+ viewId: refreshViewId,
5178
+ projectId: projectId,
5179
+ viewedByUserId: databaseProps.userId,
5180
+ sessionId: sessionId,
5181
+ });
5182
+
5183
+ if (
5184
+ ownView &&
5185
+ ownView.id &&
5186
+ ownView.rumApplicationId &&
5187
+ ownView.rumApplicationId.toString() ===
5188
+ authorizedApplicationId.toString()
5189
+ ) {
5190
+ viewId = ownView.id.toString();
5191
+ }
5192
+ }
5193
+
5194
+ if (viewId === null) {
5195
+ /*
5196
+ * The audit row is written BEFORE the manifest is built, not
5197
+ * after. A read that fails halfway through still happened, and
5198
+ * an audit that only records successful reads is an audit an
5199
+ * attacker can evade by aborting the request.
5200
+ *
5201
+ * linkedIncidentId is validated rather than constructed blindly:
5202
+ * ObjectID's constructor checks nothing, and a malformed id would
5203
+ * fail the audit insert - and with it the playback it audits. A
5204
+ * bad link is dropped; the view is still recorded.
5205
+ */
5206
+ const rawLinkedIncidentId: unknown = body["linkedIncidentId"];
5207
+
5208
+ const view: RumSessionReplayView =
5209
+ await RumSessionReplayViewService.recordView({
5210
+ projectId: projectId,
5211
+ rumApplicationId: authorizedApplicationId,
5212
+ sessionId: sessionId,
5213
+ viewedByUserId: databaseProps.userId,
5214
+ ipAddress: getClientIp(req),
5215
+ userAgent:
5216
+ typeof req.headers["user-agent"] === "string"
5217
+ ? req.headers["user-agent"]
5218
+ : undefined,
5219
+ accessReason:
5220
+ typeof body["accessReason"] === "string"
5221
+ ? (body["accessReason"] as string)
5222
+ : undefined,
5223
+ linkedIncidentId:
5224
+ typeof rawLinkedIncidentId === "string" &&
5225
+ ObjectID.isValidUUID(rawLinkedIncidentId)
5226
+ ? new ObjectID(rawLinkedIncidentId)
5227
+ : undefined,
5228
+ linkedExceptionFingerprint:
5229
+ typeof body["linkedExceptionFingerprint"] === "string" &&
5230
+ body["linkedExceptionFingerprint"].length > 0
5231
+ ? (body["linkedExceptionFingerprint"] as string)
5232
+ : undefined,
5233
+ });
5234
+
5235
+ viewId = view.id ? view.id.toString() : null;
5236
+ }
5237
+
5238
+ const manifest: SessionReplayManifest =
5239
+ await SessionReplayReadService.getManifest({
5240
+ header: header,
4405
5241
  projectId: projectId,
4406
5242
  rumApplicationId: authorizedApplicationId,
4407
5243
  sessionId: sessionId,
4408
- viewedByUserId: databaseProps.userId,
4409
- ipAddress: getClientIp(req),
4410
- userAgent:
4411
- typeof req.headers["user-agent"] === "string"
4412
- ? req.headers["user-agent"]
4413
- : undefined,
4414
- accessReason:
4415
- typeof body["accessReason"] === "string"
4416
- ? (body["accessReason"] as string)
4417
- : undefined,
4418
- linkedIncidentId:
4419
- typeof body["linkedIncidentId"] === "string" &&
4420
- body["linkedIncidentId"].length > 0
4421
- ? new ObjectID(body["linkedIncidentId"])
4422
- : undefined,
4423
- linkedExceptionFingerprint:
4424
- typeof body["linkedExceptionFingerprint"] === "string"
4425
- ? (body["linkedExceptionFingerprint"] as string)
4426
- : undefined,
4427
5244
  });
4428
5245
 
4429
- const manifest: SessionReplayManifest =
4430
- await SessionReplayReadService.getManifest({
4431
- header: header,
5246
+ /*
5247
+ * The identity columns are read by a SEPARATE statement that runs
5248
+ * only after the narrower identity check passes for the application
5249
+ * the caller was just authorized against. Nothing above named them,
5250
+ * so a caller without the permission never causes a statement that
5251
+ * touches identifiedUserLabel or identifiedUserTraits to exist.
5252
+ */
5253
+ let identity: SessionReplaySessionIdentity | null = null;
5254
+
5255
+ if (
5256
+ canReadIdentifiedUserLabel({
5257
+ databaseProps: databaseProps,
5258
+ application: authorized.application,
5259
+ })
5260
+ ) {
5261
+ identity = await SessionReplayReadService.getSessionIdentity({
4432
5262
  projectId: projectId,
4433
5263
  rumApplicationId: authorizedApplicationId,
4434
5264
  sessionId: sessionId,
4435
5265
  });
5266
+ }
5267
+
5268
+ const responseHeader: SessionReplaySessionHeader = identity
5269
+ ? {
5270
+ ...manifest.header,
5271
+ identifiedUserLabel: identity.identifiedUserLabel,
5272
+ identifiedUserTraits: identity.identifiedUserTraits,
5273
+ }
5274
+ : manifest.header;
4436
5275
 
4437
5276
  return Response.sendJsonObjectResponse(req, res, {
4438
5277
  /*
4439
5278
  * viewId is echoed back so the player's heartbeat can advance the
4440
- * very row this read created, instead of guessing at one.
5279
+ * very row this read created (or reused), instead of guessing at
5280
+ * one.
4441
5281
  */
4442
- viewId: view.id ? view.id.toString() : null,
4443
- header: manifest.header as unknown as JSONObject,
5282
+ viewId: viewId,
5283
+ header: responseHeader as unknown as JSONObject,
4444
5284
  tabs: manifest.tabs as unknown as JSONObject,
4445
5285
  isChunkIndexTruncated: manifest.isChunkIndexTruncated,
4446
5286
  });
@@ -4532,15 +5372,27 @@ router.post(
4532
5372
  );
4533
5373
  }
4534
5374
 
4535
- const header: SessionReplaySessionHeader = await resolveAuthorizedSession(
4536
- {
4537
- projectId: projectId,
4538
- sessionId: sessionId,
4539
- databaseProps: databaseProps,
4540
- },
4541
- );
5375
+ /*
5376
+ * Served from the 30s authorization cache: a session is 60 chunk
5377
+ * pages at most, and re-aggregating its header plus re-loading the
5378
+ * application's labels for every one of them is what made seeks
5379
+ * stutter. The label decision itself is still made against the
5380
+ * caller's current permissions on every request.
5381
+ */
5382
+ const authorized: AuthorizedSession = await resolveAuthorizedSession({
5383
+ projectId: projectId,
5384
+ sessionId: sessionId,
5385
+ databaseProps: databaseProps,
5386
+ rumApplicationId: readOptionalObjectIdFromBody(
5387
+ body,
5388
+ "rumApplicationId",
5389
+ ),
5390
+ allowCached: true,
5391
+ });
5392
+
5393
+ const header: SessionReplaySessionHeader = authorized.header;
4542
5394
 
4543
- const chunks: Array<SessionReplayChunkPayload> =
5395
+ const read: SessionReplayChunkReadResult =
4544
5396
  await SessionReplayReadService.getChunks({
4545
5397
  projectId: projectId,
4546
5398
  /* Always the application the caller was authorized against. */
@@ -4563,28 +5415,33 @@ router.post(
4563
5415
 
4564
5416
  /*
4565
5417
  * The byte cap is re-checked here against the bytes actually being
4566
- * framed, not only against what the pre-check in the read service
4567
- * believed. This is the last place the size of the response is
4568
- * knowable, so it is the one place a cap on the response can be
4569
- * absolute regardless of how stored size was estimated upstream.
5418
+ * framed, not only against what the read service believed. This is
5419
+ * the last place the size of the response is knowable, so it is the
5420
+ * one place a cap on the response can be absolute regardless of how
5421
+ * stored size was estimated upstream. Like the service, it answers
5422
+ * with the prefix that fits rather than refusing - and never with
5423
+ * nothing: a single chunk is bounded by the ingest cap, and a chunk
5424
+ * that could never be served would dead-end playback at it forever.
4570
5425
  */
4571
5426
  let responseBytes: number = 0;
5427
+ const omittedChunkIndexes: Array<number> = [...read.omittedChunkIndexes];
4572
5428
 
4573
- for (const chunk of chunks) {
5429
+ for (const chunk of read.chunks) {
4574
5430
  const payloadBuffer: Buffer = Buffer.from(chunk.payload, "utf8");
4575
5431
 
4576
- responseBytes += payloadBuffer.length + 8;
5432
+ const framedBytes: number = payloadBuffer.length + 8;
4577
5433
 
4578
- if (responseBytes > MAX_SESSION_REPLAY_READ_BYTES) {
4579
- return Response.sendErrorResponse(
4580
- req,
4581
- res,
4582
- new BadDataException(
4583
- `The requested chunks exceed the ${MAX_SESSION_REPLAY_READ_BYTES} byte limit for a single read. Request fewer chunks.`,
4584
- ),
4585
- );
5434
+ if (
5435
+ frames.length > 0 &&
5436
+ (responseBytes + framedBytes > MAX_SESSION_REPLAY_READ_BYTES ||
5437
+ omittedChunkIndexes.length > 0)
5438
+ ) {
5439
+ omittedChunkIndexes.push(chunk.chunkIndex);
5440
+ continue;
4586
5441
  }
4587
5442
 
5443
+ responseBytes += framedBytes;
5444
+
4588
5445
  const headerBuffer: Buffer = Buffer.alloc(8);
4589
5446
  headerBuffer.writeUInt32LE(chunk.chunkIndex, 0);
4590
5447
  headerBuffer.writeUInt32LE(payloadBuffer.length, 4);
@@ -4595,6 +5452,22 @@ router.post(
4595
5452
 
4596
5453
  res.setHeader("Content-Type", "application/octet-stream");
4597
5454
  res.setHeader("Content-Length", responseBody.length.toString());
5455
+
5456
+ /*
5457
+ * Which requested chunks exist but were left out for size, so a
5458
+ * client that cares can ask for them in a smaller page instead of
5459
+ * reading their absence as a gap in the recording.
5460
+ */
5461
+ if (omittedChunkIndexes.length > 0) {
5462
+ res.setHeader(
5463
+ "X-OneUptime-Replay-Omitted-Chunks",
5464
+ omittedChunkIndexes
5465
+ .sort((a: number, b: number): number => {
5466
+ return a - b;
5467
+ })
5468
+ .join(","),
5469
+ );
5470
+ }
4598
5471
  /*
4599
5472
  * A recording is personal data. Nothing about it may sit in a
4600
5473
  * shared cache, and the browser should not keep it on disk either.
@@ -4650,14 +5523,16 @@ router.post(
4650
5523
  }
4651
5524
 
4652
5525
  /*
4653
- * Floored to the 15s heartbeat cadence. recordSecondsWatched is
4654
- * monotonic and returns without writing when the value does not
4655
- * advance, so flooring here turns a chatty client into at most one
4656
- * UPDATE per 15 seconds watched without any server-side timer or
4657
- * cross-pod throttle state.
5526
+ * SEMANTICS: secondsWatched is the cumulative seconds of footage the
5527
+ * player has PLAYED for this view (accumulated client-side while
5528
+ * playback runs, scaled by speed), not the furthest offset reached.
5529
+ * Floored to the 15s heartbeat cadence and clamped by the service,
5530
+ * which is monotonic and writes nothing when the value does not
5531
+ * advance, so a chatty client costs at most one UPDATE per 15
5532
+ * seconds watched without any server-side timer or cross-pod
5533
+ * throttle state.
4658
5534
  */
4659
- const throttledSeconds: number =
4660
- Math.floor(Math.max(0, secondsWatched) / 15) * 15;
5535
+ const throttledSeconds: number = normalizeSecondsWatched(secondsWatched);
4661
5536
 
4662
5537
  /*
4663
5538
  * secondsWatched is a privacy control, not telemetry: it is shown on
@@ -4671,7 +5546,8 @@ router.post(
4671
5546
  * viewId belonging to anyone else matches nothing and is refused
4672
5547
  * indistinguishably from one that does not exist - and the
4673
5548
  * application it points at is authorized exactly as a payload read
4674
- * would be.
5549
+ * would be. That ONE lookup also carries the row's current figure,
5550
+ * so a heartbeat that does not advance it ends here with no write.
4675
5551
  */
4676
5552
  if (!databaseProps.userId) {
4677
5553
  return Response.sendErrorResponse(
@@ -4684,19 +5560,10 @@ router.post(
4684
5560
  }
4685
5561
 
4686
5562
  const view: RumSessionReplayView | null =
4687
- await RumSessionReplayViewService.findOneBy({
4688
- query: {
4689
- _id: viewId.toString(),
4690
- projectId: projectId,
4691
- viewedByUserId: databaseProps.userId,
4692
- },
4693
- select: {
4694
- _id: true,
4695
- rumApplicationId: true,
4696
- },
4697
- props: {
4698
- isRoot: true,
4699
- },
5563
+ await RumSessionReplayViewService.findOwnView({
5564
+ viewId: viewId,
5565
+ projectId: projectId,
5566
+ viewedByUserId: databaseProps.userId,
4700
5567
  });
4701
5568
 
4702
5569
  if (!view || !view.rumApplicationId) {
@@ -4714,16 +5581,116 @@ router.post(
4714
5581
  rumApplicationId: view.rumApplicationId,
4715
5582
  databaseProps: databaseProps,
4716
5583
  permissions: SESSION_REPLAY_PAYLOAD_PERMISSIONS,
5584
+ allowCached: true,
4717
5585
  });
4718
5586
 
5587
+ const currentSecondsWatched: number = view.secondsWatched || 0;
5588
+
4719
5589
  await RumSessionReplayViewService.recordSecondsWatched({
4720
5590
  viewId: viewId,
4721
5591
  projectId: projectId,
4722
5592
  secondsWatched: throttledSeconds,
5593
+ currentSecondsWatched: currentSecondsWatched,
4723
5594
  });
4724
5595
 
4725
5596
  return Response.sendJsonObjectResponse(req, res, {
4726
- secondsWatched: throttledSeconds,
5597
+ secondsWatched: Math.max(currentSecondsWatched, throttledSeconds),
5598
+ });
5599
+ } catch (err: unknown) {
5600
+ next(err);
5601
+ }
5602
+ },
5603
+ );
5604
+
5605
+ // --- Session Replay Views Endpoint ---
5606
+
5607
+ /*
5608
+ * Who has watched this recording. The audit table has been written on
5609
+ * every manifest read since the feature shipped and nothing surfaced it;
5610
+ * the player header now can. Payload permission, because the list of
5611
+ * viewers is a fact about a recording of a real person and belongs to
5612
+ * the people who may watch it. Pinned to the application the session was
5613
+ * authorized under: sessionId is only unique within an application.
5614
+ */
5615
+ const MAX_SESSION_REPLAY_VIEWS_LIMIT: number = 50;
5616
+
5617
+ router.post(
5618
+ "/telemetry/rum/session-replay/views",
5619
+ ...requireSessionReplayPayloadAccess,
5620
+ async (
5621
+ req: ExpressRequest,
5622
+ res: ExpressResponse,
5623
+ next: NextFunction,
5624
+ ): Promise<void> => {
5625
+ try {
5626
+ const databaseProps: DatabaseCommonInteractionProps =
5627
+ await CommonAPI.getDatabaseCommonInteractionProps(req);
5628
+
5629
+ if (!databaseProps?.tenantId) {
5630
+ return Response.sendErrorResponse(
5631
+ req,
5632
+ res,
5633
+ new BadDataException("Invalid Project ID"),
5634
+ );
5635
+ }
5636
+
5637
+ assertSessionReplayPlan(databaseProps);
5638
+
5639
+ const projectId: ObjectID = databaseProps.tenantId;
5640
+ const body: JSONObject = req.body as JSONObject;
5641
+ const sessionId: string = readSessionIdFromBody(body);
5642
+
5643
+ const authorized: AuthorizedSession = await resolveAuthorizedSession({
5644
+ projectId: projectId,
5645
+ sessionId: sessionId,
5646
+ databaseProps: databaseProps,
5647
+ rumApplicationId: readOptionalObjectIdFromBody(
5648
+ body,
5649
+ "rumApplicationId",
5650
+ ),
5651
+ allowCached: true,
5652
+ });
5653
+
5654
+ const views: Array<RumSessionReplayView> =
5655
+ await RumSessionReplayViewService.getViewsForSession({
5656
+ projectId: projectId,
5657
+ rumApplicationId: new ObjectID(authorized.header.rumApplicationId),
5658
+ sessionId: sessionId,
5659
+ limit: readLimitFromBody(
5660
+ body,
5661
+ MAX_SESSION_REPLAY_VIEWS_LIMIT,
5662
+ MAX_SESSION_REPLAY_VIEWS_LIMIT,
5663
+ ),
5664
+ });
5665
+
5666
+ return Response.sendJsonObjectResponse(req, res, {
5667
+ views: views.map((view: RumSessionReplayView): JSONObject => {
5668
+ return {
5669
+ id: view.id ? view.id.toString() : null,
5670
+ viewedAt: view.viewedAt ? view.viewedAt.toISOString() : null,
5671
+ secondsWatched: view.secondsWatched ?? 0,
5672
+ accessReason: view.accessReason || "",
5673
+ viewedByUserId: view.viewedByUserId
5674
+ ? view.viewedByUserId.toString()
5675
+ : null,
5676
+ viewedByUser: view.viewedByUser
5677
+ ? {
5678
+ id: view.viewedByUser.id
5679
+ ? view.viewedByUser.id.toString()
5680
+ : null,
5681
+ name: view.viewedByUser.name
5682
+ ? view.viewedByUser.name.toString()
5683
+ : "",
5684
+ email: view.viewedByUser.email
5685
+ ? view.viewedByUser.email.toString()
5686
+ : "",
5687
+ profilePictureId: view.viewedByUser.profilePictureId
5688
+ ? view.viewedByUser.profilePictureId.toString()
5689
+ : null,
5690
+ }
5691
+ : null,
5692
+ };
5693
+ }) as unknown as JSONObject,
4727
5694
  });
4728
5695
  } catch (err: unknown) {
4729
5696
  next(err);
@@ -4780,13 +5747,49 @@ router.post(
4780
5747
  permissions: SESSION_REPLAY_LIST_PERMISSIONS,
4781
5748
  });
4782
5749
 
4783
- const startTime: Date | undefined = body["startTime"]
4784
- ? OneUptimeDate.fromString(body["startTime"] as string)
4785
- : undefined;
5750
+ let startTime: Date | undefined = readOptionalDateFromBody(
5751
+ body,
5752
+ "startTime",
5753
+ );
5754
+ let endTime: Date | undefined = readOptionalDateFromBody(body, "endTime");
4786
5755
 
4787
- const endTime: Date | undefined = body["endTime"]
4788
- ? OneUptimeDate.fromString(body["endTime"] as string)
4789
- : undefined;
5756
+ /*
5757
+ * The exception page knows WHEN the error happened. A session that
5758
+ * contains that moment started at most one maximum session length
5759
+ * before it (plus skew padding), so the window is derived from the
5760
+ * moment rather than left to the 30-day default - a fraction of
5761
+ * the partitions, and the card finds the session of THIS instance
5762
+ * rather than the newest session that ever hit the fingerprint.
5763
+ */
5764
+ const rawErrorTime: unknown = body["errorTimeUnixMs"];
5765
+
5766
+ if (
5767
+ startTime === undefined &&
5768
+ endTime === undefined &&
5769
+ typeof rawErrorTime === "number" &&
5770
+ Number.isFinite(rawErrorTime) &&
5771
+ rawErrorTime > 0
5772
+ ) {
5773
+ startTime = new Date(
5774
+ rawErrorTime -
5775
+ SESSION_REPLAY_MAX_SESSION_MS -
5776
+ SESSION_REPLAY_EXCEPTION_WINDOW_PADDING_MS,
5777
+ );
5778
+ endTime = new Date(
5779
+ rawErrorTime + SESSION_REPLAY_EXCEPTION_WINDOW_PADDING_MS,
5780
+ );
5781
+ }
5782
+
5783
+ if (startTime && endTime && startTime.getTime() > endTime.getTime()) {
5784
+ return Response.sendErrorResponse(
5785
+ req,
5786
+ res,
5787
+ new BadDataException("startTime must not be after endTime"),
5788
+ );
5789
+ }
5790
+
5791
+ /* Pin to the session the caller already knows threw, when it does. */
5792
+ const pinnedSessionId: unknown = body["sessionId"];
4790
5793
 
4791
5794
  const sessions: Array<SessionReplayExceptionSession> =
4792
5795
  await SessionReplayReadService.getSessionsForException({
@@ -4795,10 +5798,13 @@ router.post(
4795
5798
  accessibleRumApplicationIds: accessibleApplications.applicationIds,
4796
5799
  ...(startTime !== undefined && { startTime }),
4797
5800
  ...(endTime !== undefined && { endTime }),
4798
- limit:
4799
- typeof body["limit"] === "number"
4800
- ? (body["limit"] as number)
4801
- : MAX_SESSION_REPLAY_FOR_EXCEPTION_LIMIT,
5801
+ ...(typeof pinnedSessionId === "string" &&
5802
+ pinnedSessionId.length > 0 && { sessionId: pinnedSessionId }),
5803
+ limit: readLimitFromBody(
5804
+ body,
5805
+ MAX_SESSION_REPLAY_FOR_EXCEPTION_LIMIT,
5806
+ MAX_SESSION_REPLAY_FOR_EXCEPTION_LIMIT,
5807
+ ),
4802
5808
  });
4803
5809
 
4804
5810
  return Response.sendJsonObjectResponse(req, res, {
@@ -4890,9 +5896,20 @@ router.post(
4890
5896
  sessionReplayAllowedOrigins: true,
4891
5897
  sessionReplaySamplePercentage: true,
4892
5898
  sessionReplayCaptureTrigger: true,
5899
+ sessionReplayConsentMode: true,
5900
+ sessionReplayMaskingMode: true,
5901
+ sessionReplayRetentionInDays: true,
4893
5902
  sessionReplayMonthlyBudgetInGB: true,
4894
5903
  sessionReplayLastChunkReceivedAt: true,
4895
5904
  sessionReplayBudgetExceededAt: true,
5905
+ /*
5906
+ * Stamped by the /config route on every recorder load (through
5907
+ * the throttled updateLastSeen path), so this is "when did the
5908
+ * recorder last run on the customer's site" - the fact that
5909
+ * separates "never installed" from "installed but uploading
5910
+ * nothing".
5911
+ */
5912
+ lastSeenAt: true,
4896
5913
  },
4897
5914
  props: {
4898
5915
  isRoot: true,
@@ -4919,15 +5936,51 @@ router.post(
4919
5936
  },
4920
5937
  });
4921
5938
 
4922
- const [projectBytesUsedToday, applicationBytesUsedThisMonth]: [
5939
+ const appIdentifier: string = String(
5940
+ (application as unknown as JSONObject)["appIdentifier"] || "",
5941
+ );
5942
+
5943
+ /*
5944
+ * Every counter below is independent and every one answers null on
5945
+ * its own failure: the Redis-backed ones when Redis is down, the
5946
+ * ClickHouse-backed summary when the query fails. null is rendered
5947
+ * as "unknown", never as 0 - "nothing was refused" and "we could
5948
+ * not count" are different diagnoses.
5949
+ */
5950
+ const [
5951
+ projectBytesUsedToday,
5952
+ applicationBytesUsedThisMonth,
5953
+ refusalsLast24h,
5954
+ dropsLast24h,
5955
+ activity,
5956
+ ]: [
4923
5957
  number | null,
4924
5958
  number | null,
5959
+ Array<SessionReplayRefusalCount> | null,
5960
+ Array<SessionReplayDropCount> | null,
5961
+ SessionReplayApplicationActivitySummary,
4925
5962
  ] = await Promise.all([
4926
5963
  SessionReplayUsage.getProjectBytesUsedToday(projectId),
4927
5964
  SessionReplayUsage.getApplicationBytesUsedThisMonth({
4928
5965
  projectId: projectId,
4929
5966
  rumApplicationId: rumApplicationId,
4930
5967
  }),
5968
+ appIdentifier
5969
+ ? SessionReplayHealthCounters.readRefusalsLast24h({
5970
+ projectId: projectId,
5971
+ appIdentifier: appIdentifier,
5972
+ })
5973
+ : Promise.resolve(null),
5974
+ appIdentifier
5975
+ ? SessionReplayHealthCounters.readDropsLast24h({
5976
+ projectId: projectId,
5977
+ appIdentifier: appIdentifier,
5978
+ })
5979
+ : Promise.resolve(null),
5980
+ SessionReplayReadService.getApplicationActivitySummary({
5981
+ projectId: projectId,
5982
+ rumApplicationId: rumApplicationId,
5983
+ }),
4931
5984
  ]);
4932
5985
 
4933
5986
  /*
@@ -4947,6 +6000,27 @@ router.post(
4947
6000
 
4948
6001
  const applicationView: JSONObject = application as unknown as JSONObject;
4949
6002
 
6003
+ const toIsoOrNull: (value: unknown) => string | null = (
6004
+ value: unknown,
6005
+ ): string | null => {
6006
+ if (value instanceof Date) {
6007
+ return Number.isFinite(value.getTime()) ? value.toISOString() : null;
6008
+ }
6009
+
6010
+ if (typeof value === "string" && value.length > 0) {
6011
+ const parsed: number = Date.parse(value);
6012
+
6013
+ return Number.isFinite(parsed)
6014
+ ? new Date(parsed).toISOString()
6015
+ : null;
6016
+ }
6017
+
6018
+ return null;
6019
+ };
6020
+
6021
+ const retentionInDays: unknown =
6022
+ applicationView["sessionReplayRetentionInDays"];
6023
+
4950
6024
  return Response.sendJsonObjectResponse(req, res, {
4951
6025
  isProjectAllowed: Boolean(
4952
6026
  (project as unknown as JSONObject | null)?.["isSessionReplayAllowed"],
@@ -4954,7 +6028,7 @@ router.post(
4954
6028
  isApplicationEnabled: Boolean(
4955
6029
  applicationView["isSessionReplayEnabled"],
4956
6030
  ),
4957
- appIdentifier: String(applicationView["appIdentifier"] || ""),
6031
+ appIdentifier: appIdentifier,
4958
6032
  allowedOrigins: (applicationView["sessionReplayAllowedOrigins"] ||
4959
6033
  []) as JSONArray,
4960
6034
  samplePercentage: Number(
@@ -4974,6 +6048,52 @@ router.post(
4974
6048
  applicationBytesUsedThisMonth: applicationBytesUsedThisMonth,
4975
6049
  monthlyBudgetInGB:
4976
6050
  (applicationView["sessionReplayMonthlyBudgetInGB"] as number) ?? null,
6051
+
6052
+ /*
6053
+ * ---- Additive: the rest of RecordingHealthStatus. ----
6054
+ * Every timestamp is ISO-8601 or null; every counter is a number
6055
+ * or null (unknown). The Dashboard parses this with
6056
+ * parseRecordingHealthStatus and diagnoses it with
6057
+ * diagnoseRecordingHealth.
6058
+ */
6059
+ consentMode: String(applicationView["sessionReplayConsentMode"] || ""),
6060
+ maskingMode: String(applicationView["sessionReplayMaskingMode"] || ""),
6061
+ retentionInDays:
6062
+ typeof retentionInDays === "number" &&
6063
+ Number.isFinite(retentionInDays)
6064
+ ? retentionInDays
6065
+ : null,
6066
+ publishedRecorderVersion:
6067
+ SessionReplayReadService.getPublishedRecorderVersion(),
6068
+ lastConfigFetchAt: toIsoOrNull(applicationView["lastSeenAt"]),
6069
+ lastSessionStartedAt: activity.lastSessionStartedAt
6070
+ ? activity.lastSessionStartedAt.toISOString()
6071
+ : null,
6072
+ sessionsLast24h: activity.sessionsLast24h,
6073
+ playableSessionsLast24h: activity.playableSessionsLast24h,
6074
+ /*
6075
+ * What the newest session's recorder said it could capture.
6076
+ *
6077
+ * This is the row the docs point operators at for spotting a stale
6078
+ * cached recorder artifact ("click labels: no"); without it the
6079
+ * health card and the installation test both said "not reported
6080
+ * yet" for every application forever, which reads as a bug rather
6081
+ * than as information. null (not []) when there is no session, when
6082
+ * the newest one predates the attribute, or when the query failed -
6083
+ * all three are "we cannot say", never "this recorder can do
6084
+ * nothing". It rides on the last-session query the summary already
6085
+ * runs, so the row costs no extra ClickHouse round trip.
6086
+ */
6087
+ recorderCapabilities:
6088
+ activity.recorderCapabilities as unknown as JSONArray | null,
6089
+ refusalsLast24h: refusalsLast24h as unknown as JSONArray | null,
6090
+ /*
6091
+ * Kept apart from refusals: a refusal was answered to the
6092
+ * recorder, a drop happened after a 202 inside the worker. "12
6093
+ * chunks dropped after acceptance: scrub-incomplete" is a
6094
+ * different sentence from "212 uploads refused".
6095
+ */
6096
+ dropsLast24h: dropsLast24h as unknown as JSONArray | null,
4977
6097
  });
4978
6098
  } catch (err: unknown) {
4979
6099
  next(err);