@oneuptime/common 12.0.33 → 13.0.0

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 (877) hide show
  1. package/Models/AnalyticsModels/RumSession.ts +117 -1
  2. package/Models/AnalyticsModels/RumSessionChunk.ts +13 -0
  3. package/Models/DatabaseModels/AlertCustomField.ts +77 -3
  4. package/Models/DatabaseModels/ApiKeyPermission.ts +3 -27
  5. package/Models/DatabaseModels/GlobalConfig.ts +12 -12
  6. package/Models/DatabaseModels/IncidentCustomField.ts +77 -3
  7. package/Models/DatabaseModels/InventoryItem.ts +44 -1
  8. package/Models/DatabaseModels/InventoryItemCustomField.ts +77 -3
  9. package/Models/DatabaseModels/MonitorCustomField.ts +77 -3
  10. package/Models/DatabaseModels/NetworkDevice.ts +126 -0
  11. package/Models/DatabaseModels/OnCallDutyPolicyCustomField.ts +77 -3
  12. package/Models/DatabaseModels/RumApplication.ts +6 -6
  13. package/Models/DatabaseModels/ScheduledMaintenanceCustomField.ts +77 -3
  14. package/Models/DatabaseModels/StatusPageCustomField.ts +77 -3
  15. package/Models/DatabaseModels/TeamCustomField.ts +77 -3
  16. package/Models/DatabaseModels/TeamMember.ts +0 -9
  17. package/Models/DatabaseModels/TeamMemberCustomField.ts +77 -3
  18. package/Models/DatabaseModels/TeamPermission.ts +3 -24
  19. package/Models/DatabaseModels/TelemetryIngestionKey.ts +260 -0
  20. package/Models/DatabaseModels/UserTelegram.ts +0 -4
  21. package/Scripts/benchmark-fanin-capacity.js +181 -0
  22. package/Server/API/TelemetryAPI.ts +1284 -164
  23. package/Server/API/UserNotificationSettingAPI.ts +55 -0
  24. package/Server/API/UserTelegramAPI.ts +48 -4
  25. package/Server/EnvironmentConfig.ts +82 -18
  26. package/Server/Infrastructure/Postgres/SchemaMigrations/1791300000000-AddTelemetryIngestionKeyType.ts +91 -0
  27. package/Server/Infrastructure/Postgres/SchemaMigrations/1791400000000-SessionReplayRecordEverySessionByDefault.ts +67 -0
  28. package/Server/Infrastructure/Postgres/SchemaMigrations/1791500000000-WidenCustomFieldDropdownOptions.ts +139 -0
  29. package/Server/Infrastructure/Postgres/SchemaMigrations/1791600000000-AddCustomFieldValueMapping.ts +121 -0
  30. package/Server/Infrastructure/Postgres/SchemaMigrations/1791700000000-AddMacAddressToNetworkDevice.ts +25 -0
  31. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +10 -0
  32. package/Server/Infrastructure/QueueWorker.ts +20 -14
  33. package/Server/Infrastructure/Redis.ts +8 -8
  34. package/Server/Infrastructure/Semaphore.ts +2 -0
  35. package/Server/Infrastructure/Status.ts +10 -4
  36. package/Server/Middleware/TelemetryIngest.ts +453 -7
  37. package/Server/Services/AccessTokenService.ts +1 -0
  38. package/Server/Services/AlertCustomFieldService.ts +98 -0
  39. package/Server/Services/AlertService.ts +37 -0
  40. package/Server/Services/ApiKeyPermissionService.ts +461 -29
  41. package/Server/Services/CustomFieldMappingService.ts +879 -0
  42. package/Server/Services/DatabaseService.ts +65 -13
  43. package/Server/Services/GlobalConfigService.ts +194 -0
  44. package/Server/Services/IncidentCustomFieldService.ts +98 -0
  45. package/Server/Services/IncidentService.ts +35 -0
  46. package/Server/Services/InventoryItemService.ts +31 -1
  47. package/Server/Services/MetricService.ts +194 -0
  48. package/Server/Services/MonitorService.ts +32 -0
  49. package/Server/Services/MonitorTemplateService.ts +140 -19
  50. package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +427 -66
  51. package/Server/Services/NetworkDeviceDiscoveryScanService.ts +87 -2
  52. package/Server/Services/NetworkDeviceService.ts +69 -0
  53. package/Server/Services/ProjectService.ts +22 -0
  54. package/Server/Services/RoutineEmailSettingsService.ts +73 -0
  55. package/Server/Services/RumSessionReplayViewService.ts +104 -24
  56. package/Server/Services/ScheduledMaintenanceCustomFieldService.ts +98 -0
  57. package/Server/Services/ScheduledMaintenanceService.ts +32 -0
  58. package/Server/Services/TeamMemberService.ts +78 -0
  59. package/Server/Services/TeamPermissionService.ts +235 -3
  60. package/Server/Services/TelemetryIngestionKeyService.ts +722 -19
  61. package/Server/Services/UserNotificationRuleService.ts +76 -25
  62. package/Server/Services/UserNotificationSettingService.ts +34 -6
  63. package/Server/Services/UserTelegramService.ts +326 -5
  64. package/Server/Types/Database/Permissions/ReadPermission.ts +45 -5
  65. package/Server/Types/Database/QueryHelper.ts +2 -0
  66. package/Server/Types/Database/QueryUtil.ts +56 -0
  67. package/Server/Types/Markdown.ts +93 -1
  68. package/Server/Utils/APIKey/AccessPermission.ts +5 -2
  69. package/Server/Utils/CustomField/CustomFieldDefinitionMappingHooks.ts +54 -0
  70. package/Server/Utils/CustomField/CustomFieldMappingRegistry.ts +415 -0
  71. package/Server/Utils/CustomField/CustomFieldMappingValidator.ts +335 -0
  72. package/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.ts +82 -17
  73. package/Server/Utils/DataSource/EgressGuard.ts +177 -8
  74. package/Server/Utils/EmailRollup/EmailRollupConstants.ts +38 -5
  75. package/Server/Utils/EmailRollup/EmailRollupFlushRunner.ts +67 -5
  76. package/Server/Utils/EmailRollup/EmailRollupRenderer.ts +2 -2
  77. package/Server/Utils/FrontendEnvironment.ts +40 -0
  78. package/Server/Utils/LogRedaction.ts +20 -0
  79. package/Server/Utils/Logger.ts +11 -0
  80. package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +394 -86
  81. package/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.ts +30 -4
  82. package/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.ts +31 -5
  83. package/Server/Utils/Monitor/MonitorAlert.ts +29 -6
  84. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +312 -52
  85. package/Server/Utils/Monitor/MonitorCriteriaExpectationBuilder.ts +82 -9
  86. package/Server/Utils/Monitor/MonitorCriteriaMessageBuilder.ts +16 -7
  87. package/Server/Utils/Monitor/MonitorCriteriaMessageFormatter.ts +29 -17
  88. package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +107 -48
  89. package/Server/Utils/Monitor/MonitorIncident.ts +22 -6
  90. package/Server/Utils/Monitor/MonitorTemplateUtil.ts +29 -0
  91. package/Server/Utils/Monitor/NetworkDeviceMacLearningUtil.ts +158 -0
  92. package/Server/Utils/Monitor/NetworkInventoryUtil.ts +27 -0
  93. package/Server/Utils/Monitor/SeriesContextEnricher.ts +304 -0
  94. package/Server/Utils/SSRFProtection.ts +217 -10
  95. package/Server/Utils/SessionReplay/SessionReplayGateCache.ts +239 -138
  96. package/Server/Utils/SessionReplay/SessionReplayHealthCounters.ts +305 -0
  97. package/Server/Utils/SessionReplay/SessionReplayReadService.ts +1430 -289
  98. package/Server/Utils/StartServer.ts +2 -17
  99. package/Server/Utils/TelegramVerificationToken.ts +185 -0
  100. package/Server/Utils/Telemetry/EntityRegistry.ts +11 -1
  101. package/Server/Utils/Telemetry/PinServiceName.ts +197 -0
  102. package/Server/Utils/Telemetry/TelemetryEntity.ts +83 -9
  103. package/Server/Utils/Telemetry/TelemetryFanInWriter.ts +38 -16
  104. package/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.ts +92 -0
  105. package/Server/Utils/Telemetry/TelemetryIngestionKeyRateLimiter.ts +217 -0
  106. package/Server/Utils/VM/VMAPI.ts +1 -0
  107. package/Server/Utils/VM/VMRunner.ts +975 -95
  108. package/Tests/App/AdminDashboard/AdminHeaderSmallScreens.test.tsx +202 -0
  109. package/Tests/App/Dashboard/AddNeighborToMonitoringModal.test.tsx +32 -0
  110. package/Tests/App/Dashboard/AdoptedDeviceDrawer.test.tsx +374 -0
  111. package/Tests/App/Dashboard/DashboardHeaderSmallScreens.test.tsx +404 -0
  112. package/Tests/App/Dashboard/DashboardLabelVariables.test.tsx +580 -0
  113. package/Tests/App/Dashboard/DashboardMonitorLabelVariable.test.tsx +438 -0
  114. package/Tests/App/Dashboard/DashboardVariableAllContract.test.tsx +5 -2
  115. package/Tests/App/Dashboard/DeviceAttachmentCard.test.tsx +273 -0
  116. package/Tests/App/Dashboard/DiscoveryReviewInventoryRefresh.test.tsx +505 -0
  117. package/Tests/App/Dashboard/DiscoveryScanWizardValidation.test.tsx +468 -0
  118. package/Tests/App/Dashboard/EntityDetailPanel.test.tsx +163 -0
  119. package/Tests/App/Dashboard/InfrastructureExplorer.test.tsx +401 -0
  120. package/Tests/App/Dashboard/InfrastructureGraph.test.tsx +232 -0
  121. package/Tests/App/Dashboard/InventoryItems.test.tsx +201 -0
  122. package/Tests/App/Dashboard/InventoryTypeAndStatusFacets.test.tsx +798 -0
  123. package/Tests/App/Dashboard/NetworkTopologyLiveView.test.tsx +320 -0
  124. package/Tests/App/Dashboard/NetworkTopologyToolbar.test.tsx +275 -0
  125. package/Tests/App/Dashboard/OnCallCalendarFeedEmptyState.test.tsx +975 -0
  126. package/Tests/App/Dashboard/OnCallCalendarFeedPlanGate.test.tsx +63 -0
  127. package/Tests/App/Dashboard/ServiceMapGraph.test.tsx +626 -0
  128. package/Tests/App/Dashboard/TopologyDataLoading.test.tsx +348 -0
  129. package/Tests/App/Dashboard/TopologyPageNavigation.test.tsx +331 -0
  130. package/Tests/App/Dashboard/UserSettingsEmailPreferences.test.tsx +603 -0
  131. package/Tests/App/Dashboard/UserSettingsNotificationSettings.test.tsx +324 -0
  132. package/Tests/App/PublicDashboard/DashboardVariableSelector.test.tsx +13 -4
  133. package/Tests/App/StatusPage/StatusPageLastUpdated.test.tsx +263 -0
  134. package/Tests/App/StatusPage/StatusPageOidcOrigin.test.tsx +223 -0
  135. package/Tests/App/StatusPage/StatusPageOverviewLiveAndSearch.test.tsx +753 -0
  136. package/Tests/App/StatusPage/StatusPageResourceSearchBox.test.tsx +224 -0
  137. package/Tests/Models/AnalyticsModels/RumSessionReplayColumns.test.ts +262 -0
  138. package/Tests/Models/CustomFieldMappingColumns.test.ts +166 -0
  139. package/Tests/Models/DatabaseModels/SessionReplayModels.test.ts +20 -6
  140. package/Tests/Models/InventoryItemStatus.test.ts +147 -0
  141. package/Tests/Models/NetworkDeviceMacAddressColumn.test.ts +294 -0
  142. package/Tests/ResponsiveVisibility.test.ts +115 -0
  143. package/Tests/ResponsiveVisibility.ts +183 -0
  144. package/Tests/Server/API/DashboardPublicResourceListAPI.test.ts +129 -0
  145. package/Tests/Server/API/SessionReplayAPI.test.ts +1940 -216
  146. package/Tests/Server/API/UserNotificationSettingAPI.test.ts +186 -0
  147. package/Tests/Server/API/UserTelegramAPISecurity.test.ts +231 -0
  148. package/Tests/Server/EnvironmentConfigFrontendSecurity.test.ts +234 -0
  149. package/Tests/Server/EnvironmentConfigValkey.test.ts +227 -0
  150. package/Tests/Server/Infrastructure/Postgres/AddMacAddressToNetworkDeviceMigration.test.ts +365 -0
  151. package/Tests/Server/Infrastructure/Postgres/CustomFieldValueMappingMigration.test.ts +241 -0
  152. package/Tests/Server/Infrastructure/Postgres/InventoryItemArchiveMigration.test.ts +41 -0
  153. package/Tests/Server/Infrastructure/Postgres/SessionReplayRecordEverySessionByDefaultMigration.test.ts +169 -0
  154. package/Tests/Server/Infrastructure/QueueWorkerTimeout.test.ts +210 -0
  155. package/Tests/Server/Infrastructure/TelemetryExporterDeploymentConfig.test.ts +130 -0
  156. package/Tests/Server/Infrastructure/ValkeyDeploymentConfig.test.ts +265 -0
  157. package/Tests/Server/Middleware/HttpMetricsMiddleware.test.ts +382 -0
  158. package/Tests/Server/Middleware/ProjectAuthorizationApiKeyMiddleware.test.ts +4 -1
  159. package/Tests/Server/Middleware/SCIMAuthorization.test.ts +525 -0
  160. package/Tests/Server/Middleware/TelemetryIngestBrowserKey.test.ts +1163 -0
  161. package/Tests/Server/Middleware/TelemetryIngestTokenLog.test.ts +5 -3
  162. package/Tests/Server/Services/AddTelemetryIngestionKeyTypeMigration.test.ts +555 -0
  163. package/Tests/Server/Services/ApiKeyPermissionSecurity.test.ts +678 -0
  164. package/Tests/Server/Services/ApiKeyPermissionService.test.ts +276 -28
  165. package/Tests/Server/Services/CustomFieldDropdownOptionsColumnWidth.test.ts +431 -0
  166. package/Tests/Server/Services/CustomFieldMappingService.test.ts +850 -0
  167. package/Tests/Server/Services/DatabaseServiceAggregateBy.test.ts +291 -56
  168. package/Tests/Server/Services/DatabaseServiceSortTiebreaker.test.ts +151 -0
  169. package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +32 -0
  170. package/Tests/Server/Services/GlobalConfigService.test.ts +414 -1
  171. package/Tests/Server/Services/InventoryItemManualCreate.test.ts +105 -0
  172. package/Tests/Server/Services/InventoryItemPromotionGate.test.ts +178 -0
  173. package/Tests/Server/Services/MetricRawEntityKeyPrune.test.ts +592 -0
  174. package/Tests/Server/Services/MonitorTemplateServiceCustomFieldSync.test.ts +502 -0
  175. package/Tests/Server/Services/NetworkDeviceAutoImportRuleEngineService.test.ts +1351 -74
  176. package/Tests/Server/Services/NetworkDeviceDiscoveryScanRegistration.test.ts +520 -0
  177. package/Tests/Server/Services/NetworkDeviceMacAddressNormalization.test.ts +572 -0
  178. package/Tests/Server/Services/RoutineEmailSettingsPostgres.test.ts +329 -0
  179. package/Tests/Server/Services/RumSessionReplayViewService.test.ts +267 -0
  180. package/Tests/Server/Services/TeamMemberAutoAcceptInvitation.test.ts +9 -0
  181. package/Tests/Server/Services/TeamMemberInviteRegistrationToken.test.ts +9 -0
  182. package/Tests/Server/Services/TeamPrivilegeEscalation.test.ts +834 -0
  183. package/Tests/Server/Services/TelemetryIngestionKeyPolicyResolution.test.ts +814 -0
  184. package/Tests/Server/Services/TelemetryIngestionKeyValidation.test.ts +998 -0
  185. package/Tests/Server/Services/UserNotificationSettingRollupRouting.test.ts +141 -0
  186. package/Tests/Server/Services/UserNotificationSettingWorkspaceChannels.test.ts +18 -10
  187. package/Tests/Server/Services/UserTelegramVerificationSecurity.test.ts +688 -0
  188. package/Tests/Server/Types/Database/InventoryStatusPostgres.test.ts +368 -0
  189. package/Tests/Server/Types/Database/Permissions/ReadBlockPermission.test.ts +261 -14
  190. package/Tests/Server/Types/Database/QueryUtilIncludesAnyOfGroups.test.ts +169 -0
  191. package/Tests/Server/Types/Database/QueryUtilIncludesAnyOfGroupsPostgres.test.ts +297 -0
  192. package/Tests/Server/Types/Markdown.test.ts +194 -1
  193. package/Tests/Server/Types/Workflow/Components/IncomingWebhookUtils.test.ts +279 -0
  194. package/Tests/Server/Types/Workflow/Components/TextToJson.test.ts +212 -0
  195. package/Tests/Server/Utils/AI/SRE/Insights/FixRouting.test.ts +497 -0
  196. package/Tests/Server/Utils/AI/Toolbox/Serializer.test.ts +383 -0
  197. package/Tests/Server/Utils/APIKey/AccessPermission.test.ts +7 -3
  198. package/Tests/Server/Utils/AnalyticsDatabase/ClusterConfig.test.ts +315 -0
  199. package/Tests/Server/Utils/CustomField/CustomFieldMappingRegistry.test.ts +436 -0
  200. package/Tests/Server/Utils/CustomField/CustomFieldMappingValidator.test.ts +437 -0
  201. package/Tests/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.test.ts +214 -0
  202. package/Tests/Server/Utils/DataSource/EgressGuard.test.ts +300 -11
  203. package/Tests/Server/Utils/EmailRollup/EmailRollupBurstWindow.test.ts +83 -0
  204. package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerBehaviour.test.ts +2 -2
  205. package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerPreferences.test.ts +362 -0
  206. package/Tests/Server/Utils/EmailRollup/EmailRollupRenderer.test.ts +10 -3
  207. package/Tests/Server/Utils/EmailRollup/EmailRollupTestHarness.ts +77 -1
  208. package/Tests/Server/Utils/EventLoop.test.ts +359 -0
  209. package/Tests/Server/Utils/FrontendEnvironment.test.ts +190 -0
  210. package/Tests/Server/Utils/JsonWebToken.test.ts +30 -0
  211. package/Tests/Server/Utils/LogRedaction.test.ts +26 -0
  212. package/Tests/Server/Utils/LoggerCredentialLeak.test.ts +23 -9
  213. package/Tests/Server/Utils/Monitor/Criteria/CompareCriteria.test.ts +242 -0
  214. package/Tests/Server/Utils/Monitor/Criteria/CompareCriteriaAggregation.test.ts +590 -0
  215. package/Tests/Server/Utils/Monitor/Criteria/DatabaseMonitorCriteria.test.ts +29 -0
  216. package/Tests/Server/Utils/Monitor/Criteria/IncomingRequestHeaderCriteria.test.ts +236 -0
  217. package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.test.ts +30 -6
  218. package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteriaAnomalyUnits.test.ts +246 -0
  219. package/Tests/Server/Utils/Monitor/MonitorCriteriaEmailEvalLogAgreement.test.ts +280 -0
  220. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +659 -8
  221. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorMetricUnits.test.ts +570 -0
  222. package/Tests/Server/Utils/Monitor/MonitorCriteriaExpectationBuilderUnits.test.ts +30 -5
  223. package/Tests/Server/Utils/Monitor/MonitorCriteriaMessageBuilderUnits.test.ts +68 -21
  224. package/Tests/Server/Utils/Monitor/MonitorCriteriaObservationBuilderUnits.test.ts +36 -19
  225. package/Tests/Server/Utils/Monitor/MonitorTemplateUtilSeriesContext.test.ts +176 -0
  226. package/Tests/Server/Utils/Monitor/NetworkDeviceMacLearningUtil.test.ts +573 -0
  227. package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +317 -0
  228. package/Tests/Server/Utils/Monitor/SeriesContextEnricher.test.ts +356 -0
  229. package/Tests/Server/Utils/SSRFProtectionCloudServiceAddresses.test.ts +595 -0
  230. package/Tests/Server/Utils/SessionReplay/SessionReplayGateCachePolicy.test.ts +198 -1
  231. package/Tests/Server/Utils/SessionReplay/SessionReplayHealthCounters.test.ts +453 -0
  232. package/Tests/Server/Utils/SessionReplay/SessionReplayReadServiceQueries.test.ts +1378 -0
  233. package/Tests/Server/Utils/SessionReplayOriginAllowListRefactor.test.ts +420 -0
  234. package/Tests/Server/Utils/TelegramVerificationToken.test.ts +253 -0
  235. package/Tests/Server/Utils/Telemetry/ContextSpanProcessor.test.ts +281 -0
  236. package/Tests/Server/Utils/Telemetry/InventoryDuplicateIdentity.test.ts +316 -0
  237. package/Tests/Server/Utils/Telemetry/PinServiceName.test.ts +666 -0
  238. package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +111 -8
  239. package/Tests/Server/Utils/Telemetry/TelemetryFanInWriterCapacity.test.ts +458 -0
  240. package/Tests/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.test.ts +424 -0
  241. package/Tests/Server/Utils/Telemetry/TelemetryIngestionKeyRateLimiter.test.ts +528 -0
  242. package/Tests/Server/Utils/TelemetryExporterEnvironment.test.ts +56 -0
  243. package/Tests/Server/Utils/VM/VMRunnerHostBridgeLatency.test.ts +74 -0
  244. package/Tests/Server/Utils/VM/VMRunnerPrivateNetworkWiring.test.ts +100 -7
  245. package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +1176 -6
  246. package/Tests/Types/CustomField/CustomFieldMappingCatalog.test.ts +220 -0
  247. package/Tests/Types/CustomField/CustomFieldValueMapping.test.ts +348 -0
  248. package/Tests/Types/Database/IncludesAnyOfGroups.test.ts +106 -0
  249. package/Tests/Types/JSONFunctions.test.ts +300 -0
  250. package/Tests/Types/Monitor/CephAlertTemplates.test.ts +422 -53
  251. package/Tests/Types/Monitor/DockerAlertTemplates.test.ts +495 -15
  252. package/Tests/Types/Monitor/DockerSwarmAlertTemplates.test.ts +191 -45
  253. package/Tests/Types/Monitor/HostAlertTemplates.test.ts +370 -42
  254. package/Tests/Types/Monitor/IotAlertTemplates.test.ts +375 -20
  255. package/Tests/Types/Monitor/KubernetesAlertTemplates.test.ts +636 -42
  256. package/Tests/Types/Monitor/KubernetesMetricCatalog.test.ts +189 -0
  257. package/Tests/Types/Monitor/KubernetesTemplateGroupByKeys.test.ts +95 -14
  258. package/Tests/Types/Monitor/PodmanAlertTemplates.test.ts +190 -21
  259. package/Tests/Types/Monitor/ProxmoxAlertTemplates.test.ts +352 -22
  260. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationAlertDebuggability.test.ts +363 -0
  261. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +93 -18
  262. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.test.ts +259 -0
  263. package/Tests/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.test.ts +476 -0
  264. package/Tests/Types/Monitor/RumAlertTemplates.test.ts +136 -0
  265. package/Tests/Types/Monitor/SeriesContext/SeriesDebugHints.test.ts +661 -0
  266. package/Tests/Types/Monitor/SeriesContext/SeriesLabelDisplay.test.ts +507 -0
  267. package/Tests/Types/Monitor/ServiceAlertTemplates.test.ts +270 -0
  268. package/Tests/Types/Monitor/TemplateGroupByKeys.test.ts +38 -10
  269. package/Tests/Types/Monitor/Utils/RecommendationCriteriaAssertions.ts +102 -0
  270. package/Tests/Types/NetworkAutomation/AutoImportRunMerge.test.ts +235 -0
  271. package/Tests/Types/NetworkAutomation/RuleRunResult.test.ts +66 -0
  272. package/Tests/Types/NetworkAutomation/RuleRunResultDescribe.test.ts +309 -1
  273. package/Tests/Types/NotificationSetting/RoutineEmailEvents.test.ts +47 -0
  274. package/Tests/Types/Rum/SessionReplayApiContracts.test.ts +608 -0
  275. package/Tests/Types/Rum/SessionReplayCustomEvents.test.ts +434 -0
  276. package/Tests/Types/Telemetry/InventoryLiveness.test.ts +99 -0
  277. package/Tests/Types/WebsiteRequest.test.ts +285 -3
  278. package/Tests/UI/Components/Charts/ChartBucketIdentity.test.ts +16 -3
  279. package/Tests/UI/Components/Charts/ChartTrailingBucketGap.test.ts +691 -0
  280. package/Tests/UI/Components/ComponentsModal.test.tsx +12 -4
  281. package/Tests/UI/Components/ComponentsModalUsability.test.tsx +518 -0
  282. package/Tests/UI/Components/CustomFields/CustomFieldsDetail.test.tsx +160 -0
  283. package/Tests/UI/Components/CustomFields/CustomFieldsDetailMapping.test.tsx +324 -0
  284. package/Tests/UI/Components/CustomFields/MapFromCustomFieldInput.test.tsx +176 -0
  285. package/Tests/UI/Components/Graphs/DayUptimeGraph.test.tsx +484 -0
  286. package/Tests/UI/Components/HeaderRightRail.test.tsx +157 -0
  287. package/Tests/UI/Components/IconDropdownItem.test.tsx +102 -0
  288. package/Tests/UI/Components/JSONTablePrototypePollution.test.tsx +117 -0
  289. package/Tests/UI/Components/KeyboardShortcutsModal.test.tsx +214 -0
  290. package/Tests/UI/Components/ModelTable/ModelTableWrapContent.test.tsx +561 -0
  291. package/Tests/UI/Components/MonitorGraphs/UptimeBarDayModal.test.tsx +302 -0
  292. package/Tests/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.test.ts +28 -12
  293. package/Tests/UI/Components/ShortcutDialogGuard.test.tsx +74 -0
  294. package/Tests/UI/Components/StatusPage/ResourceGroupSectionAutoExpand.test.tsx +248 -0
  295. package/Tests/UI/Components/TableCellWrapping.test.tsx +625 -0
  296. package/Tests/UI/Components/TableLoadingStates.test.tsx +205 -0
  297. package/Tests/UI/Components/Workflow/NodePlacement.test.ts +148 -0
  298. package/Tests/UI/Components/Workflow/Workflow.test.tsx +981 -0
  299. package/Tests/UI/ConfigBrowserTelemetry.test.ts +70 -0
  300. package/Tests/UI/ReactRouterSingletonBuild.test.ts +133 -0
  301. package/Tests/UI/Rum/ChunkLoader.test.ts +1036 -2
  302. package/Tests/UI/Rum/FidelityNotices.test.ts +187 -0
  303. package/Tests/UI/Rum/InactivityMap.test.ts +341 -0
  304. package/Tests/UI/Rum/PrivacySummaryCard.test.tsx +259 -0
  305. package/Tests/UI/Rum/RecordingHealthCard.test.tsx +855 -0
  306. package/Tests/UI/Rum/RecordingHealthStrip.test.tsx +594 -0
  307. package/Tests/UI/Rum/ReplayCard.test.tsx +451 -0
  308. package/Tests/UI/Rum/ReplayCorrelationPanel.test.tsx +536 -0
  309. package/Tests/UI/Rum/ReplayEngine.test.ts +2503 -0
  310. package/Tests/UI/Rum/ReplayEngineTypes.test.ts +171 -0
  311. package/Tests/UI/Rum/ReplayHeader.test.tsx +719 -0
  312. package/Tests/UI/Rum/ReplayLink.test.tsx +119 -0
  313. package/Tests/UI/Rum/ReplayPinControl.test.tsx +408 -0
  314. package/Tests/UI/Rum/ReplayPlaybackIntent.test.ts +152 -0
  315. package/Tests/UI/Rum/ReplayPlayerChrome.test.tsx +514 -0
  316. package/Tests/UI/Rum/ReplayRail.test.tsx +1296 -0
  317. package/Tests/UI/Rum/ReplayRailDetail.test.tsx +900 -0
  318. package/Tests/UI/Rum/ReplayScrubber.test.tsx +763 -147
  319. package/Tests/UI/Rum/ReplaySignalTypes.test.ts +189 -0
  320. package/Tests/UI/Rum/ReplaySignals.test.ts +1579 -0
  321. package/Tests/UI/Rum/ReplayStage.test.tsx +396 -473
  322. package/Tests/UI/Rum/ReplayStageOverlays.test.tsx +918 -0
  323. package/Tests/UI/Rum/ReplayTimeFormat.test.ts +94 -0
  324. package/Tests/UI/Rum/ReplayTimeline.test.tsx +696 -0
  325. package/Tests/UI/Rum/ReplayUi.test.tsx +559 -0
  326. package/Tests/UI/Rum/SessionReplayEmptyState.test.tsx +499 -0
  327. package/Tests/UI/Rum/SessionReplaySearchBar.test.tsx +346 -0
  328. package/Tests/UI/Rum/SessionReplaySetupGuide.test.tsx +545 -0
  329. package/Tests/UI/Rum/SessionReplayTable.test.tsx +991 -0
  330. package/Tests/UI/Rum/TargetedCapturePanel.test.tsx +254 -0
  331. package/Tests/UI/Telemetry/BrowserExporterIsolation.test.ts +71 -0
  332. package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +5 -0
  333. package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +1 -0
  334. package/Tests/UI/Utils/GlobalKeyboardShortcut.test.ts +344 -0
  335. package/Tests/Utils/API.test.ts +308 -0
  336. package/Tests/Utils/Dashboard/Components/DashboardMonitorListComponent.test.ts +11 -1
  337. package/Tests/Utils/Dashboard/LabelVariable.test.ts +257 -0
  338. package/Tests/Utils/Dashboard/VariableUrlState.test.ts +144 -14
  339. package/Tests/Utils/HTTPResponseBodyReader.test.ts +323 -0
  340. package/Tests/Utils/MetricUnitUtil.test.ts +81 -0
  341. package/Tests/Utils/Monitor/DeviceMacLearningUtil.test.ts +497 -0
  342. package/Tests/Utils/Monitor/MetricValueFormatter.test.ts +546 -0
  343. package/Tests/Utils/Monitor/MonitorTemplateCustomFieldUtil.test.ts +218 -0
  344. package/Tests/Utils/Monitor/NetworkTopologyEndpointAdoption.test.ts +1755 -0
  345. package/Tests/Utils/NetworkAutomation/AutoImportRunChain.test.ts +320 -0
  346. package/Tests/Utils/NetworkDiscovery/DiscoveryScanStatus.test.ts +117 -0
  347. package/Tests/Utils/Rum/ChunkMath.test.ts +83 -0
  348. package/Tests/Utils/Rum/SessionReplayHealthDiagnosis.test.ts +993 -0
  349. package/Tests/Utils/Rum/SessionReplayStringMap.test.ts +245 -0
  350. package/Tests/Utils/StatusPage/ResourceSearch.test.ts +631 -0
  351. package/Tests/Utils/Telemetry/OriginAllowList.test.ts +633 -0
  352. package/Tests/Utils/Uptime/DayUptimeGraphUtil.test.ts +461 -0
  353. package/Tests/Utils/ValueFormatter.test.ts +148 -0
  354. package/Types/BaseDatabase/IncludesAnyOfGroups.ts +77 -0
  355. package/Types/CustomField/CustomFieldMappingCatalog.ts +161 -0
  356. package/Types/CustomField/CustomFieldMappingSourceResource.ts +19 -0
  357. package/Types/CustomField/CustomFieldValueMapping.ts +288 -0
  358. package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +1 -0
  359. package/Types/Dashboard/DashboardComponents/DashboardMonitorListComponent.ts +1 -0
  360. package/Types/Dashboard/DashboardVariable.ts +8 -0
  361. package/Types/Icon/IconProp.ts +1 -0
  362. package/Types/JSON.ts +4 -0
  363. package/Types/JSONFunctions.ts +205 -43
  364. package/Types/Monitor/CephAlertTemplates.ts +157 -195
  365. package/Types/Monitor/DockerAlertTemplates.ts +338 -128
  366. package/Types/Monitor/DockerSwarmAlertTemplates.ts +95 -112
  367. package/Types/Monitor/HostAlertTemplates.ts +302 -130
  368. package/Types/Monitor/IotAlertTemplates.ts +112 -104
  369. package/Types/Monitor/KubernetesAlertTemplates.ts +415 -224
  370. package/Types/Monitor/KubernetesMetricCatalog.ts +23 -19
  371. package/Types/Monitor/PodmanAlertTemplates.ts +116 -163
  372. package/Types/Monitor/ProxmoxAlertTemplates.ts +217 -99
  373. package/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.ts +98 -6
  374. package/Types/Monitor/Recommendation/MonitorRecommendationUtil.ts +44 -7
  375. package/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.ts +383 -0
  376. package/Types/Monitor/RumAlertTemplates.ts +46 -7
  377. package/Types/Monitor/SeriesContext/SeriesDebugHints.ts +596 -0
  378. package/Types/Monitor/SeriesContext/SeriesLabelDisplay.ts +554 -0
  379. package/Types/Monitor/ServiceAlertTemplates.ts +98 -11
  380. package/Types/Monitor/SnmpMonitor/NetworkTopology.ts +13 -0
  381. package/Types/Monitor/UptimeHistoryLabels.ts +56 -0
  382. package/Types/NetworkAutomation/RuleRunResult.ts +402 -13
  383. package/Types/NotificationSetting/RoutineEmailEvents.ts +30 -0
  384. package/Types/Rum/SessionReplay.ts +209 -0
  385. package/Types/Rum/SessionReplayApi.ts +722 -0
  386. package/Types/Rum/SessionReplayCaptureTrigger.ts +21 -12
  387. package/Types/Rum/SessionReplayConsentMode.ts +11 -7
  388. package/Types/Rum/SessionReplayCustomEvents.ts +549 -0
  389. package/Types/Rum/SessionReplayHealth.ts +238 -0
  390. package/Types/SerializableObjectDictionary.ts +4 -0
  391. package/Types/Telemetry/InventoryLiveness.ts +56 -0
  392. package/Types/Telemetry/TelemetryIngestSurface.ts +95 -0
  393. package/Types/Telemetry/TelemetryIngestionKeyPolicy.ts +75 -0
  394. package/Types/Telemetry/TelemetryIngestionKeyType.ts +29 -0
  395. package/Types/WebsiteRequest.ts +85 -3
  396. package/UI/Components/CSVFileUpload/CSVFileUpload.tsx +9 -2
  397. package/UI/Components/Charts/Area/AreaChart.tsx +13 -2
  398. package/UI/Components/Charts/Bar/BarChart.tsx +6 -2
  399. package/UI/Components/Charts/Line/LineChart.tsx +13 -2
  400. package/UI/Components/Charts/Types/XAxis/XAxis.ts +29 -0
  401. package/UI/Components/Charts/Utils/DataPoint.ts +22 -3
  402. package/UI/Components/Charts/Utils/TimeAnnotation.ts +76 -9
  403. package/UI/Components/Charts/Utils/XAxis.ts +217 -0
  404. package/UI/Components/CustomFields/CustomFieldsDetail.tsx +189 -46
  405. package/UI/Components/CustomFields/MapFromCustomFieldInput.tsx +216 -0
  406. package/UI/Components/Dashboard/DashboardVariableControl.tsx +285 -0
  407. package/UI/Components/Graphs/DayUptimeGraph.tsx +173 -8
  408. package/UI/Components/Graphs/UptimeBarTooltip.tsx +22 -278
  409. package/UI/Components/Graphs/UptimeDaySummary.tsx +327 -0
  410. package/UI/Components/Header/Header.tsx +25 -9
  411. package/UI/Components/Header/IconDropdown/IconDropdownItem.tsx +10 -1
  412. package/UI/Components/Header/IconDropdown/IconDropdownMenu.tsx +6 -1
  413. package/UI/Components/Header/ProjectPicker/ProjectPicker.tsx +6 -1
  414. package/UI/Components/HeaderAlert/NotificationBell/NotificationBellDropdown.tsx +6 -1
  415. package/UI/Components/Icon/Icon.tsx +11 -0
  416. package/UI/Components/JSONTable/JSONTable.tsx +2 -2
  417. package/UI/Components/KeyboardShortcut/KeyboardShortcutsModal.tsx +125 -0
  418. package/UI/Components/KeyboardShortcut/Screenshots/README.md +19 -0
  419. package/UI/Components/KeyboardShortcut/Screenshots/keyboard-shortcuts-command-palette.png +0 -0
  420. package/UI/Components/KeyboardShortcut/Screenshots/keyboard-shortcuts-dialog-dark.png +0 -0
  421. package/UI/Components/KeyboardShortcut/Screenshots/keyboard-shortcuts-dialog.png +0 -0
  422. package/UI/Components/KeyboardShortcut/Screenshots/keyboard-shortcuts-help-menu.png +0 -0
  423. package/UI/Components/KeyboardShortcut/Screenshots/keyboard-shortcuts-narrow.png +0 -0
  424. package/UI/Components/ModelTable/Column.ts +15 -0
  425. package/UI/Components/Monitor/SeriesDebugCommandsViewer.tsx +64 -0
  426. package/UI/Components/Monitor/SeriesLabelsViewer.tsx +93 -0
  427. package/UI/Components/MonitorGraphs/Uptime.tsx +14 -2
  428. package/UI/Components/MonitorGraphs/UptimeBarDayModal.tsx +63 -10
  429. package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +44 -0
  430. package/UI/Components/StatusPage/ResourceGroupSection.tsx +40 -0
  431. package/UI/Components/Table/CellClassName.ts +81 -0
  432. package/UI/Components/Table/TableRow.tsx +20 -14
  433. package/UI/Components/Table/TableSkeletonRows.tsx +9 -9
  434. package/UI/Components/Table/Types/Column.ts +36 -0
  435. package/UI/Components/Tooltip/Tooltip.tsx +11 -1
  436. package/UI/Components/Workflow/ComponentsModal.tsx +60 -39
  437. package/UI/Components/Workflow/NodePlacement.ts +57 -0
  438. package/UI/Components/Workflow/Workflow.tsx +47 -18
  439. package/UI/Config.ts +15 -33
  440. package/UI/Utils/GlobalKeyboardShortcut.ts +208 -0
  441. package/UI/Utils/Telemetry/BrowserTelemetryConfig.ts +28 -0
  442. package/UI/Utils/Telemetry/Telemetry.ts +10 -8
  443. package/UI/esbuild-config.js +6 -0
  444. package/Utils/API.ts +129 -3
  445. package/Utils/Dashboard/Components/DashboardMonitorListComponent.ts +12 -1
  446. package/Utils/Dashboard/LabelVariable.ts +152 -0
  447. package/Utils/Dashboard/VariableUrlState.ts +27 -5
  448. package/Utils/HTTPResponseBodyReader.ts +221 -0
  449. package/Utils/MetricUnitUtil.ts +34 -0
  450. package/Utils/Monitor/DeviceMacLearningUtil.ts +177 -0
  451. package/Utils/Monitor/MetricValueFormatter.ts +342 -0
  452. package/Utils/Monitor/MonitorTemplateCustomFieldUtil.ts +124 -0
  453. package/Utils/Monitor/NetworkDeviceMonitorTemplateUtil.ts +7 -2
  454. package/Utils/Monitor/NetworkTopologyUtil.ts +693 -0
  455. package/Utils/NetworkAutomation/AutoImportRunChain.ts +138 -0
  456. package/Utils/NetworkDiscovery/DiscoveryScanStatus.ts +77 -0
  457. package/Utils/Rum/ChunkMath.ts +106 -0
  458. package/Utils/Rum/SessionReplayHealth.ts +732 -0
  459. package/Utils/Rum/SessionReplayStringMap.ts +226 -0
  460. package/Utils/Schema/ModelSchema.ts +1 -0
  461. package/Utils/StatusPage/ResourceSearch.ts +290 -0
  462. package/Utils/Telemetry/OriginAllowList.ts +355 -0
  463. package/Utils/Uptime/DayUptimeGraphUtil.ts +205 -0
  464. package/Utils/ValueFormatter.ts +35 -1
  465. package/build/dist/Models/AnalyticsModels/RumSession.js +102 -19
  466. package/build/dist/Models/AnalyticsModels/RumSession.js.map +1 -1
  467. package/build/dist/Models/AnalyticsModels/RumSessionChunk.js +11 -9
  468. package/build/dist/Models/AnalyticsModels/RumSessionChunk.js.map +1 -1
  469. package/build/dist/Models/DatabaseModels/AlertCustomField.js +79 -3
  470. package/build/dist/Models/DatabaseModels/AlertCustomField.js.map +1 -1
  471. package/build/dist/Models/DatabaseModels/ApiKeyPermission.js +3 -27
  472. package/build/dist/Models/DatabaseModels/ApiKeyPermission.js.map +1 -1
  473. package/build/dist/Models/DatabaseModels/GlobalConfig.js +12 -12
  474. package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
  475. package/build/dist/Models/DatabaseModels/IncidentCustomField.js +79 -3
  476. package/build/dist/Models/DatabaseModels/IncidentCustomField.js.map +1 -1
  477. package/build/dist/Models/DatabaseModels/InventoryItem.js +34 -1
  478. package/build/dist/Models/DatabaseModels/InventoryItem.js.map +1 -1
  479. package/build/dist/Models/DatabaseModels/InventoryItemCustomField.js +79 -3
  480. package/build/dist/Models/DatabaseModels/InventoryItemCustomField.js.map +1 -1
  481. package/build/dist/Models/DatabaseModels/MonitorCustomField.js +79 -3
  482. package/build/dist/Models/DatabaseModels/MonitorCustomField.js.map +1 -1
  483. package/build/dist/Models/DatabaseModels/NetworkDevice.js +128 -0
  484. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
  485. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyCustomField.js +79 -3
  486. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyCustomField.js.map +1 -1
  487. package/build/dist/Models/DatabaseModels/RumApplication.js +6 -6
  488. package/build/dist/Models/DatabaseModels/RumApplication.js.map +1 -1
  489. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceCustomField.js +79 -3
  490. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceCustomField.js.map +1 -1
  491. package/build/dist/Models/DatabaseModels/StatusPageCustomField.js +79 -3
  492. package/build/dist/Models/DatabaseModels/StatusPageCustomField.js.map +1 -1
  493. package/build/dist/Models/DatabaseModels/TeamCustomField.js +79 -3
  494. package/build/dist/Models/DatabaseModels/TeamCustomField.js.map +1 -1
  495. package/build/dist/Models/DatabaseModels/TeamMember.js +0 -9
  496. package/build/dist/Models/DatabaseModels/TeamMember.js.map +1 -1
  497. package/build/dist/Models/DatabaseModels/TeamMemberCustomField.js +79 -3
  498. package/build/dist/Models/DatabaseModels/TeamMemberCustomField.js.map +1 -1
  499. package/build/dist/Models/DatabaseModels/TeamPermission.js +3 -24
  500. package/build/dist/Models/DatabaseModels/TeamPermission.js.map +1 -1
  501. package/build/dist/Models/DatabaseModels/TelemetryIngestionKey.js +267 -0
  502. package/build/dist/Models/DatabaseModels/TelemetryIngestionKey.js.map +1 -1
  503. package/build/dist/Models/DatabaseModels/UserTelegram.js +0 -4
  504. package/build/dist/Models/DatabaseModels/UserTelegram.js.map +1 -1
  505. package/build/dist/Server/API/TelemetryAPI.js +769 -109
  506. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  507. package/build/dist/Server/API/UserNotificationSettingAPI.js +35 -0
  508. package/build/dist/Server/API/UserNotificationSettingAPI.js.map +1 -0
  509. package/build/dist/Server/API/UserTelegramAPI.js +28 -6
  510. package/build/dist/Server/API/UserTelegramAPI.js.map +1 -1
  511. package/build/dist/Server/EnvironmentConfig.js +73 -14
  512. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  513. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791300000000-AddTelemetryIngestionKeyType.js +60 -0
  514. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791300000000-AddTelemetryIngestionKeyType.js.map +1 -0
  515. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791400000000-SessionReplayRecordEverySessionByDefault.js +53 -0
  516. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791400000000-SessionReplayRecordEverySessionByDefault.js.map +1 -0
  517. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791500000000-WidenCustomFieldDropdownOptions.js +82 -0
  518. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791500000000-WidenCustomFieldDropdownOptions.js.map +1 -0
  519. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791600000000-AddCustomFieldValueMapping.js +46 -0
  520. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791600000000-AddCustomFieldValueMapping.js.map +1 -0
  521. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791700000000-AddMacAddressToNetworkDevice.js +14 -0
  522. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791700000000-AddMacAddressToNetworkDevice.js.map +1 -0
  523. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +10 -0
  524. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  525. package/build/dist/Server/Infrastructure/QueueWorker.js +19 -7
  526. package/build/dist/Server/Infrastructure/QueueWorker.js.map +1 -1
  527. package/build/dist/Server/Infrastructure/Redis.js +8 -8
  528. package/build/dist/Server/Infrastructure/Redis.js.map +1 -1
  529. package/build/dist/Server/Infrastructure/Semaphore.js +1 -0
  530. package/build/dist/Server/Infrastructure/Semaphore.js.map +1 -1
  531. package/build/dist/Server/Infrastructure/Status.js +10 -4
  532. package/build/dist/Server/Infrastructure/Status.js.map +1 -1
  533. package/build/dist/Server/Middleware/TelemetryIngest.js +315 -8
  534. package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
  535. package/build/dist/Server/Services/AccessTokenService.js +1 -0
  536. package/build/dist/Server/Services/AccessTokenService.js.map +1 -1
  537. package/build/dist/Server/Services/AlertCustomFieldService.js +93 -0
  538. package/build/dist/Server/Services/AlertCustomFieldService.js.map +1 -1
  539. package/build/dist/Server/Services/AlertService.js +34 -0
  540. package/build/dist/Server/Services/AlertService.js.map +1 -1
  541. package/build/dist/Server/Services/ApiKeyPermissionService.js +331 -28
  542. package/build/dist/Server/Services/ApiKeyPermissionService.js.map +1 -1
  543. package/build/dist/Server/Services/CustomFieldMappingService.js +614 -0
  544. package/build/dist/Server/Services/CustomFieldMappingService.js.map +1 -0
  545. package/build/dist/Server/Services/DatabaseService.js +58 -13
  546. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  547. package/build/dist/Server/Services/GlobalConfigService.js +133 -0
  548. package/build/dist/Server/Services/GlobalConfigService.js.map +1 -1
  549. package/build/dist/Server/Services/IncidentCustomFieldService.js +93 -0
  550. package/build/dist/Server/Services/IncidentCustomFieldService.js.map +1 -1
  551. package/build/dist/Server/Services/IncidentService.js +32 -0
  552. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  553. package/build/dist/Server/Services/InventoryItemService.js +28 -1
  554. package/build/dist/Server/Services/InventoryItemService.js.map +1 -1
  555. package/build/dist/Server/Services/MetricService.js +163 -0
  556. package/build/dist/Server/Services/MetricService.js.map +1 -1
  557. package/build/dist/Server/Services/MonitorService.js +29 -0
  558. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  559. package/build/dist/Server/Services/MonitorTemplateService.js +116 -17
  560. package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
  561. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +349 -64
  562. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -1
  563. package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js +65 -0
  564. package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js.map +1 -1
  565. package/build/dist/Server/Services/NetworkDeviceService.js +54 -0
  566. package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
  567. package/build/dist/Server/Services/ProjectService.js +22 -0
  568. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  569. package/build/dist/Server/Services/RoutineEmailSettingsService.js +69 -0
  570. package/build/dist/Server/Services/RoutineEmailSettingsService.js.map +1 -0
  571. package/build/dist/Server/Services/RumSessionReplayViewService.js +86 -24
  572. package/build/dist/Server/Services/RumSessionReplayViewService.js.map +1 -1
  573. package/build/dist/Server/Services/ScheduledMaintenanceCustomFieldService.js +93 -0
  574. package/build/dist/Server/Services/ScheduledMaintenanceCustomFieldService.js.map +1 -1
  575. package/build/dist/Server/Services/ScheduledMaintenanceService.js +29 -0
  576. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  577. package/build/dist/Server/Services/TeamMemberService.js +62 -2
  578. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  579. package/build/dist/Server/Services/TeamPermissionService.js +166 -3
  580. package/build/dist/Server/Services/TeamPermissionService.js.map +1 -1
  581. package/build/dist/Server/Services/TelemetryIngestionKeyService.js +562 -18
  582. package/build/dist/Server/Services/TelemetryIngestionKeyService.js.map +1 -1
  583. package/build/dist/Server/Services/UserNotificationRuleService.js +60 -25
  584. package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
  585. package/build/dist/Server/Services/UserNotificationSettingService.js +26 -6
  586. package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
  587. package/build/dist/Server/Services/UserTelegramService.js +257 -4
  588. package/build/dist/Server/Services/UserTelegramService.js.map +1 -1
  589. package/build/dist/Server/Types/Database/Permissions/ReadPermission.js +29 -4
  590. package/build/dist/Server/Types/Database/Permissions/ReadPermission.js.map +1 -1
  591. package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
  592. package/build/dist/Server/Types/Database/QueryUtil.js +36 -0
  593. package/build/dist/Server/Types/Database/QueryUtil.js.map +1 -1
  594. package/build/dist/Server/Types/Markdown.js +75 -0
  595. package/build/dist/Server/Types/Markdown.js.map +1 -1
  596. package/build/dist/Server/Utils/APIKey/AccessPermission.js +2 -2
  597. package/build/dist/Server/Utils/APIKey/AccessPermission.js.map +1 -1
  598. package/build/dist/Server/Utils/CustomField/CustomFieldDefinitionMappingHooks.js +27 -0
  599. package/build/dist/Server/Utils/CustomField/CustomFieldDefinitionMappingHooks.js.map +1 -0
  600. package/build/dist/Server/Utils/CustomField/CustomFieldMappingRegistry.js +226 -0
  601. package/build/dist/Server/Utils/CustomField/CustomFieldMappingRegistry.js.map +1 -0
  602. package/build/dist/Server/Utils/CustomField/CustomFieldMappingValidator.js +189 -0
  603. package/build/dist/Server/Utils/CustomField/CustomFieldMappingValidator.js.map +1 -0
  604. package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js +53 -18
  605. package/build/dist/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.js.map +1 -1
  606. package/build/dist/Server/Utils/DataSource/EgressGuard.js +121 -7
  607. package/build/dist/Server/Utils/DataSource/EgressGuard.js.map +1 -1
  608. package/build/dist/Server/Utils/EmailRollup/EmailRollupConstants.js +38 -5
  609. package/build/dist/Server/Utils/EmailRollup/EmailRollupConstants.js.map +1 -1
  610. package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js +54 -3
  611. package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js.map +1 -1
  612. package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js +2 -2
  613. package/build/dist/Server/Utils/EmailRollup/EmailRollupRenderer.js.map +1 -1
  614. package/build/dist/Server/Utils/FrontendEnvironment.js +33 -0
  615. package/build/dist/Server/Utils/FrontendEnvironment.js.map +1 -0
  616. package/build/dist/Server/Utils/LogRedaction.js +20 -0
  617. package/build/dist/Server/Utils/LogRedaction.js.map +1 -1
  618. package/build/dist/Server/Utils/Logger.js +10 -0
  619. package/build/dist/Server/Utils/Logger.js.map +1 -1
  620. package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js +323 -81
  621. package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js.map +1 -1
  622. package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.js +20 -4
  623. package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.js.map +1 -1
  624. package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js +29 -5
  625. package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js.map +1 -1
  626. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +29 -6
  627. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  628. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +254 -48
  629. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  630. package/build/dist/Server/Utils/Monitor/MonitorCriteriaExpectationBuilder.js +58 -9
  631. package/build/dist/Server/Utils/Monitor/MonitorCriteriaExpectationBuilder.js.map +1 -1
  632. package/build/dist/Server/Utils/Monitor/MonitorCriteriaMessageBuilder.js +9 -3
  633. package/build/dist/Server/Utils/Monitor/MonitorCriteriaMessageBuilder.js.map +1 -1
  634. package/build/dist/Server/Utils/Monitor/MonitorCriteriaMessageFormatter.js +26 -12
  635. package/build/dist/Server/Utils/Monitor/MonitorCriteriaMessageFormatter.js.map +1 -1
  636. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js +74 -33
  637. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js.map +1 -1
  638. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +22 -6
  639. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  640. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +22 -0
  641. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
  642. package/build/dist/Server/Utils/Monitor/NetworkDeviceMacLearningUtil.js +114 -0
  643. package/build/dist/Server/Utils/Monitor/NetworkDeviceMacLearningUtil.js.map +1 -0
  644. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +25 -0
  645. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
  646. package/build/dist/Server/Utils/Monitor/SeriesContextEnricher.js +237 -0
  647. package/build/dist/Server/Utils/Monitor/SeriesContextEnricher.js.map +1 -0
  648. package/build/dist/Server/Utils/SSRFProtection.js +136 -9
  649. package/build/dist/Server/Utils/SSRFProtection.js.map +1 -1
  650. package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCache.js +174 -89
  651. package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCache.js.map +1 -1
  652. package/build/dist/Server/Utils/SessionReplay/SessionReplayHealthCounters.js +223 -0
  653. package/build/dist/Server/Utils/SessionReplay/SessionReplayHealthCounters.js.map +1 -0
  654. package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js +945 -164
  655. package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js.map +1 -1
  656. package/build/dist/Server/Utils/StartServer.js +3 -14
  657. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  658. package/build/dist/Server/Utils/TelegramVerificationToken.js +129 -0
  659. package/build/dist/Server/Utils/TelegramVerificationToken.js.map +1 -0
  660. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +9 -1
  661. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
  662. package/build/dist/Server/Utils/Telemetry/PinServiceName.js +163 -0
  663. package/build/dist/Server/Utils/Telemetry/PinServiceName.js.map +1 -0
  664. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +70 -13
  665. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -1
  666. package/build/dist/Server/Utils/Telemetry/TelemetryFanInWriter.js +28 -15
  667. package/build/dist/Server/Utils/Telemetry/TelemetryFanInWriter.js.map +1 -1
  668. package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.js +64 -0
  669. package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.js.map +1 -0
  670. package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyRateLimiter.js +171 -0
  671. package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyRateLimiter.js.map +1 -0
  672. package/build/dist/Server/Utils/VM/VMAPI.js.map +1 -1
  673. package/build/dist/Server/Utils/VM/VMRunner.js +780 -69
  674. package/build/dist/Server/Utils/VM/VMRunner.js.map +1 -1
  675. package/build/dist/Types/BaseDatabase/IncludesAnyOfGroups.js +54 -0
  676. package/build/dist/Types/BaseDatabase/IncludesAnyOfGroups.js.map +1 -0
  677. package/build/dist/Types/CustomField/CustomFieldMappingCatalog.js +60 -0
  678. package/build/dist/Types/CustomField/CustomFieldMappingCatalog.js.map +1 -0
  679. package/build/dist/Types/CustomField/CustomFieldMappingSourceResource.js +20 -0
  680. package/build/dist/Types/CustomField/CustomFieldMappingSourceResource.js.map +1 -0
  681. package/build/dist/Types/CustomField/CustomFieldValueMapping.js +141 -0
  682. package/build/dist/Types/CustomField/CustomFieldValueMapping.js.map +1 -0
  683. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js +1 -0
  684. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js.map +1 -1
  685. package/build/dist/Types/Dashboard/DashboardVariable.js +1 -0
  686. package/build/dist/Types/Dashboard/DashboardVariable.js.map +1 -1
  687. package/build/dist/Types/Icon/IconProp.js +1 -0
  688. package/build/dist/Types/Icon/IconProp.js.map +1 -1
  689. package/build/dist/Types/JSON.js +1 -0
  690. package/build/dist/Types/JSON.js.map +1 -1
  691. package/build/dist/Types/JSONFunctions.js +131 -37
  692. package/build/dist/Types/JSONFunctions.js.map +1 -1
  693. package/build/dist/Types/Monitor/CephAlertTemplates.js +130 -171
  694. package/build/dist/Types/Monitor/CephAlertTemplates.js.map +1 -1
  695. package/build/dist/Types/Monitor/DockerAlertTemplates.js +286 -121
  696. package/build/dist/Types/Monitor/DockerAlertTemplates.js.map +1 -1
  697. package/build/dist/Types/Monitor/DockerSwarmAlertTemplates.js +84 -105
  698. package/build/dist/Types/Monitor/DockerSwarmAlertTemplates.js.map +1 -1
  699. package/build/dist/Types/Monitor/HostAlertTemplates.js +250 -122
  700. package/build/dist/Types/Monitor/HostAlertTemplates.js.map +1 -1
  701. package/build/dist/Types/Monitor/IotAlertTemplates.js +81 -81
  702. package/build/dist/Types/Monitor/IotAlertTemplates.js.map +1 -1
  703. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js +375 -215
  704. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js.map +1 -1
  705. package/build/dist/Types/Monitor/KubernetesMetricCatalog.js +19 -19
  706. package/build/dist/Types/Monitor/KubernetesMetricCatalog.js.map +1 -1
  707. package/build/dist/Types/Monitor/PodmanAlertTemplates.js +104 -153
  708. package/build/dist/Types/Monitor/PodmanAlertTemplates.js.map +1 -1
  709. package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js +156 -91
  710. package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js.map +1 -1
  711. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js +67 -6
  712. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js.map +1 -1
  713. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js +38 -7
  714. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js.map +1 -1
  715. package/build/dist/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.js +261 -0
  716. package/build/dist/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.js.map +1 -0
  717. package/build/dist/Types/Monitor/RumAlertTemplates.js +46 -7
  718. package/build/dist/Types/Monitor/RumAlertTemplates.js.map +1 -1
  719. package/build/dist/Types/Monitor/SeriesContext/SeriesDebugHints.js +422 -0
  720. package/build/dist/Types/Monitor/SeriesContext/SeriesDebugHints.js.map +1 -0
  721. package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js +441 -0
  722. package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js.map +1 -0
  723. package/build/dist/Types/Monitor/ServiceAlertTemplates.js +79 -15
  724. package/build/dist/Types/Monitor/ServiceAlertTemplates.js.map +1 -1
  725. package/build/dist/Types/Monitor/UptimeHistoryLabels.js +17 -0
  726. package/build/dist/Types/Monitor/UptimeHistoryLabels.js.map +1 -0
  727. package/build/dist/Types/NetworkAutomation/RuleRunResult.js +291 -6
  728. package/build/dist/Types/NetworkAutomation/RuleRunResult.js.map +1 -1
  729. package/build/dist/Types/NotificationSetting/RoutineEmailEvents.js +29 -0
  730. package/build/dist/Types/NotificationSetting/RoutineEmailEvents.js.map +1 -0
  731. package/build/dist/Types/Rum/SessionReplay.js +117 -0
  732. package/build/dist/Types/Rum/SessionReplay.js.map +1 -1
  733. package/build/dist/Types/Rum/SessionReplayApi.js +181 -0
  734. package/build/dist/Types/Rum/SessionReplayApi.js.map +1 -0
  735. package/build/dist/Types/Rum/SessionReplayCaptureTrigger.js +21 -12
  736. package/build/dist/Types/Rum/SessionReplayCaptureTrigger.js.map +1 -1
  737. package/build/dist/Types/Rum/SessionReplayConsentMode.js +11 -7
  738. package/build/dist/Types/Rum/SessionReplayConsentMode.js.map +1 -1
  739. package/build/dist/Types/Rum/SessionReplayCustomEvents.js +172 -0
  740. package/build/dist/Types/Rum/SessionReplayCustomEvents.js.map +1 -0
  741. package/build/dist/Types/Rum/SessionReplayHealth.js +37 -0
  742. package/build/dist/Types/Rum/SessionReplayHealth.js.map +1 -0
  743. package/build/dist/Types/SerializableObjectDictionary.js +4 -0
  744. package/build/dist/Types/SerializableObjectDictionary.js.map +1 -1
  745. package/build/dist/Types/Telemetry/InventoryLiveness.js +37 -0
  746. package/build/dist/Types/Telemetry/InventoryLiveness.js.map +1 -0
  747. package/build/dist/Types/Telemetry/TelemetryIngestSurface.js +85 -0
  748. package/build/dist/Types/Telemetry/TelemetryIngestSurface.js.map +1 -0
  749. package/build/dist/Types/Telemetry/TelemetryIngestionKeyPolicy.js +15 -0
  750. package/build/dist/Types/Telemetry/TelemetryIngestionKeyPolicy.js.map +1 -0
  751. package/build/dist/Types/Telemetry/TelemetryIngestionKeyType.js +30 -0
  752. package/build/dist/Types/Telemetry/TelemetryIngestionKeyType.js.map +1 -0
  753. package/build/dist/Types/WebsiteRequest.js +55 -3
  754. package/build/dist/Types/WebsiteRequest.js.map +1 -1
  755. package/build/dist/UI/Components/CSVFileUpload/CSVFileUpload.js +7 -0
  756. package/build/dist/UI/Components/CSVFileUpload/CSVFileUpload.js.map +1 -1
  757. package/build/dist/UI/Components/Charts/Area/AreaChart.js +13 -2
  758. package/build/dist/UI/Components/Charts/Area/AreaChart.js.map +1 -1
  759. package/build/dist/UI/Components/Charts/Bar/BarChart.js +6 -2
  760. package/build/dist/UI/Components/Charts/Bar/BarChart.js.map +1 -1
  761. package/build/dist/UI/Components/Charts/Line/LineChart.js +13 -2
  762. package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
  763. package/build/dist/UI/Components/Charts/Types/XAxis/XAxis.js.map +1 -1
  764. package/build/dist/UI/Components/Charts/Utils/DataPoint.js +15 -3
  765. package/build/dist/UI/Components/Charts/Utils/DataPoint.js.map +1 -1
  766. package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js +40 -9
  767. package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js.map +1 -1
  768. package/build/dist/UI/Components/Charts/Utils/XAxis.js +186 -0
  769. package/build/dist/UI/Components/Charts/Utils/XAxis.js.map +1 -1
  770. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +89 -8
  771. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
  772. package/build/dist/UI/Components/CustomFields/MapFromCustomFieldInput.js +118 -0
  773. package/build/dist/UI/Components/CustomFields/MapFromCustomFieldInput.js.map +1 -0
  774. package/build/dist/UI/Components/Dashboard/DashboardVariableControl.js +137 -0
  775. package/build/dist/UI/Components/Dashboard/DashboardVariableControl.js.map +1 -0
  776. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js +112 -7
  777. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js.map +1 -1
  778. package/build/dist/UI/Components/Graphs/UptimeBarTooltip.js +5 -162
  779. package/build/dist/UI/Components/Graphs/UptimeBarTooltip.js.map +1 -1
  780. package/build/dist/UI/Components/Graphs/UptimeDaySummary.js +181 -0
  781. package/build/dist/UI/Components/Graphs/UptimeDaySummary.js.map +1 -0
  782. package/build/dist/UI/Components/Header/Header.js +2 -3
  783. package/build/dist/UI/Components/Header/Header.js.map +1 -1
  784. package/build/dist/UI/Components/Header/IconDropdown/IconDropdownItem.js +2 -1
  785. package/build/dist/UI/Components/Header/IconDropdown/IconDropdownItem.js.map +1 -1
  786. package/build/dist/UI/Components/Header/IconDropdown/IconDropdownMenu.js +7 -1
  787. package/build/dist/UI/Components/Header/IconDropdown/IconDropdownMenu.js.map +1 -1
  788. package/build/dist/UI/Components/Header/ProjectPicker/ProjectPicker.js +7 -1
  789. package/build/dist/UI/Components/Header/ProjectPicker/ProjectPicker.js.map +1 -1
  790. package/build/dist/UI/Components/HeaderAlert/NotificationBell/NotificationBellDropdown.js +7 -1
  791. package/build/dist/UI/Components/HeaderAlert/NotificationBell/NotificationBellDropdown.js.map +1 -1
  792. package/build/dist/UI/Components/Icon/Icon.js +5 -0
  793. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  794. package/build/dist/UI/Components/JSONTable/JSONTable.js +2 -2
  795. package/build/dist/UI/Components/JSONTable/JSONTable.js.map +1 -1
  796. package/build/dist/UI/Components/KeyboardShortcut/KeyboardShortcutsModal.js +35 -0
  797. package/build/dist/UI/Components/KeyboardShortcut/KeyboardShortcutsModal.js.map +1 -0
  798. package/build/dist/UI/Components/Monitor/SeriesDebugCommandsViewer.js +34 -0
  799. package/build/dist/UI/Components/Monitor/SeriesDebugCommandsViewer.js.map +1 -0
  800. package/build/dist/UI/Components/Monitor/SeriesLabelsViewer.js +49 -0
  801. package/build/dist/UI/Components/Monitor/SeriesLabelsViewer.js.map +1 -0
  802. package/build/dist/UI/Components/MonitorGraphs/Uptime.js +1 -1
  803. package/build/dist/UI/Components/MonitorGraphs/Uptime.js.map +1 -1
  804. package/build/dist/UI/Components/MonitorGraphs/UptimeBarDayModal.js +32 -6
  805. package/build/dist/UI/Components/MonitorGraphs/UptimeBarDayModal.js.map +1 -1
  806. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +38 -0
  807. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
  808. package/build/dist/UI/Components/StatusPage/ResourceGroupSection.js +22 -1
  809. package/build/dist/UI/Components/StatusPage/ResourceGroupSection.js.map +1 -1
  810. package/build/dist/UI/Components/Table/CellClassName.js +55 -0
  811. package/build/dist/UI/Components/Table/CellClassName.js.map +1 -0
  812. package/build/dist/UI/Components/Table/TableRow.js +16 -13
  813. package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
  814. package/build/dist/UI/Components/Table/TableSkeletonRows.js +9 -8
  815. package/build/dist/UI/Components/Table/TableSkeletonRows.js.map +1 -1
  816. package/build/dist/UI/Components/Tooltip/Tooltip.js +25 -1
  817. package/build/dist/UI/Components/Tooltip/Tooltip.js.map +1 -1
  818. package/build/dist/UI/Components/Workflow/ComponentsModal.js +47 -30
  819. package/build/dist/UI/Components/Workflow/ComponentsModal.js.map +1 -1
  820. package/build/dist/UI/Components/Workflow/NodePlacement.js +37 -0
  821. package/build/dist/UI/Components/Workflow/NodePlacement.js.map +1 -0
  822. package/build/dist/UI/Components/Workflow/Workflow.js +35 -18
  823. package/build/dist/UI/Components/Workflow/Workflow.js.map +1 -1
  824. package/build/dist/UI/Config.js +10 -20
  825. package/build/dist/UI/Config.js.map +1 -1
  826. package/build/dist/UI/Utils/GlobalKeyboardShortcut.js +138 -0
  827. package/build/dist/UI/Utils/GlobalKeyboardShortcut.js.map +1 -0
  828. package/build/dist/UI/Utils/Telemetry/BrowserTelemetryConfig.js +14 -0
  829. package/build/dist/UI/Utils/Telemetry/BrowserTelemetryConfig.js.map +1 -0
  830. package/build/dist/UI/Utils/Telemetry/Telemetry.js +7 -5
  831. package/build/dist/UI/Utils/Telemetry/Telemetry.js.map +1 -1
  832. package/build/dist/Utils/API.js +67 -5
  833. package/build/dist/Utils/API.js.map +1 -1
  834. package/build/dist/Utils/Dashboard/Components/DashboardMonitorListComponent.js +9 -1
  835. package/build/dist/Utils/Dashboard/Components/DashboardMonitorListComponent.js.map +1 -1
  836. package/build/dist/Utils/Dashboard/LabelVariable.js +96 -0
  837. package/build/dist/Utils/Dashboard/LabelVariable.js.map +1 -0
  838. package/build/dist/Utils/Dashboard/VariableUrlState.js +19 -4
  839. package/build/dist/Utils/Dashboard/VariableUrlState.js.map +1 -1
  840. package/build/dist/Utils/HTTPResponseBodyReader.js +157 -0
  841. package/build/dist/Utils/HTTPResponseBodyReader.js.map +1 -0
  842. package/build/dist/Utils/MetricUnitUtil.js +26 -0
  843. package/build/dist/Utils/MetricUnitUtil.js.map +1 -1
  844. package/build/dist/Utils/Monitor/DeviceMacLearningUtil.js +112 -0
  845. package/build/dist/Utils/Monitor/DeviceMacLearningUtil.js.map +1 -0
  846. package/build/dist/Utils/Monitor/MetricValueFormatter.js +276 -0
  847. package/build/dist/Utils/Monitor/MetricValueFormatter.js.map +1 -0
  848. package/build/dist/Utils/Monitor/MonitorTemplateCustomFieldUtil.js +101 -0
  849. package/build/dist/Utils/Monitor/MonitorTemplateCustomFieldUtil.js.map +1 -0
  850. package/build/dist/Utils/Monitor/NetworkDeviceMonitorTemplateUtil.js +7 -2
  851. package/build/dist/Utils/Monitor/NetworkDeviceMonitorTemplateUtil.js.map +1 -1
  852. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +484 -0
  853. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
  854. package/build/dist/Utils/NetworkAutomation/AutoImportRunChain.js +59 -0
  855. package/build/dist/Utils/NetworkAutomation/AutoImportRunChain.js.map +1 -0
  856. package/build/dist/Utils/NetworkDiscovery/DiscoveryScanStatus.js +69 -0
  857. package/build/dist/Utils/NetworkDiscovery/DiscoveryScanStatus.js.map +1 -0
  858. package/build/dist/Utils/Rum/ChunkMath.js +76 -0
  859. package/build/dist/Utils/Rum/ChunkMath.js.map +1 -1
  860. package/build/dist/Utils/Rum/SessionReplayHealth.js +534 -0
  861. package/build/dist/Utils/Rum/SessionReplayHealth.js.map +1 -0
  862. package/build/dist/Utils/Rum/SessionReplayStringMap.js +165 -0
  863. package/build/dist/Utils/Rum/SessionReplayStringMap.js.map +1 -0
  864. package/build/dist/Utils/Schema/ModelSchema.js +1 -0
  865. package/build/dist/Utils/Schema/ModelSchema.js.map +1 -1
  866. package/build/dist/Utils/StatusPage/ResourceSearch.js +200 -0
  867. package/build/dist/Utils/StatusPage/ResourceSearch.js.map +1 -0
  868. package/build/dist/Utils/Telemetry/OriginAllowList.js +299 -0
  869. package/build/dist/Utils/Telemetry/OriginAllowList.js.map +1 -0
  870. package/build/dist/Utils/Uptime/DayUptimeGraphUtil.js +147 -0
  871. package/build/dist/Utils/Uptime/DayUptimeGraphUtil.js.map +1 -0
  872. package/build/dist/Utils/ValueFormatter.js +32 -1
  873. package/build/dist/Utils/ValueFormatter.js.map +1 -1
  874. package/jest.config.json +2 -0
  875. package/package.json +1 -1
  876. package/test-setup.sh +9 -9
  877. package/tsconfig.json +51 -11
@@ -33,9 +33,13 @@ import ProjectService from "../Services/ProjectService";
33
33
  import SessionReplayIdentity from "../Utils/SessionReplay/SessionReplayIdentity";
34
34
  import SessionReplayTargeting from "../Utils/SessionReplay/SessionReplayTargeting";
35
35
  import SessionReplayUsage from "../Utils/SessionReplay/SessionReplayUsage";
36
- import RumSessionReplayViewService from "../Services/RumSessionReplayViewService";
37
- import SessionReplayReadService, { DEFAULT_SESSION_REPLAY_LIST_LIMIT, MAX_SESSION_REPLAY_FOR_EXCEPTION_LIMIT, } from "../Utils/SessionReplay/SessionReplayReadService";
38
- import { DEFAULT_SESSION_REPLAY_MAX_BYTES_PER_PROJECT_PER_DAY, MAX_SESSION_REPLAY_CHUNKS_PER_READ, MAX_SESSION_REPLAY_READ_BYTES, SESSION_REPLAY_MAX_USER_REF_LENGTH, } from "../../Types/Rum/SessionReplay";
36
+ import RumSessionReplayViewService, { normalizeSecondsWatched, } from "../Services/RumSessionReplayViewService";
37
+ import SessionReplayReadService, { DEFAULT_SESSION_REPLAY_LIST_LIMIT, MAX_SESSION_REPLAY_FOR_EXCEPTION_LIMIT, MAX_SESSION_REPLAY_LIST_LIMIT, SESSION_REPLAY_EXCEPTION_WINDOW_PADDING_MS, } from "../Utils/SessionReplay/SessionReplayReadService";
38
+ import SessionReplayHealthCounters from "../Utils/SessionReplay/SessionReplayHealthCounters";
39
+ import { isSessionErased } from "../Utils/SessionReplay/SessionReplayErasureTombstone";
40
+ import NotFoundException from "../../Types/Exception/NotFoundException";
41
+ import { DEFAULT_SESSION_REPLAY_MAX_BYTES_PER_PROJECT_PER_DAY, MAX_SESSION_REPLAY_CHUNKS_PER_READ, MAX_SESSION_REPLAY_READ_BYTES, SESSION_REPLAY_LIST_SEARCH_MAX_LENGTH, SESSION_REPLAY_LIST_SEARCH_MAX_WINDOW_DAYS, SESSION_REPLAY_MAX_SESSION_MS, SESSION_REPLAY_MAX_TAG_KEYS, SESSION_REPLAY_MAX_TAG_KEY_LENGTH, SESSION_REPLAY_MAX_TAG_VALUE_LENGTH, SESSION_REPLAY_MAX_USER_REF_LENGTH, } from "../../Types/Rum/SessionReplay";
42
+ import { SESSION_REPLAY_SORT_BY_VALUES, parseSessionReplayListCursor, } from "../../Types/Rum/SessionReplayApi";
39
43
  const router = Express.getRouter();
40
44
  const createTelemetryReadAccessGuard = (signalReadPermission) => {
41
45
  return [
@@ -2269,8 +2273,49 @@ const isApplicationInSessionReplayScope = (data) => {
2269
2273
  return applicationLabelIds.includes(labelId.toString());
2270
2274
  });
2271
2275
  };
2272
- const assertSessionReplayApplicationAccess = async (data) => {
2273
- const scope = getSessionReplayLabelScope(data.databaseProps, data.permissions);
2276
+ /*
2277
+ * Returns the application so callers that need its labels for a second,
2278
+ * narrower decision (the identity column) do not have to load it twice.
2279
+ */
2280
+ /*
2281
+ * Process-local memory of what the two playback hot paths re-derive on
2282
+ * every call: which application a session belongs to (a ClickHouse GROUP
2283
+ * BY over the header table) and which labels that application carries (a
2284
+ * Postgres lookup). A 480-chunk session is 60 chunk pages, and a live
2285
+ * player heartbeats every 15s; without this every one of those paid both
2286
+ * lookups again for an answer that had not changed.
2287
+ *
2288
+ * What is cached is the DATA, never the decision: the label intersection
2289
+ * is recomputed against the caller's current permissions on every
2290
+ * request, so a revoked grant takes effect immediately. A label edit on
2291
+ * the application, or a header re-resolution, lags by at most the TTL -
2292
+ * the same lag the ingest gate's policy cache already accepts. The
2293
+ * manifest route always resolves fresh (a live session's header changes)
2294
+ * and refills the entries the chunk and heartbeat routes then read.
2295
+ */
2296
+ const SESSION_REPLAY_AUTHORIZATION_CACHE_TTL_MS = 30 * 1000;
2297
+ const MAX_SESSION_REPLAY_AUTHORIZATION_CACHE_ENTRIES = 2000;
2298
+ const rumApplicationCache = new Map();
2299
+ const sessionHeaderCache = new Map();
2300
+ const boundedCacheSet = (map, key, value) => {
2301
+ if (map.size >= MAX_SESSION_REPLAY_AUTHORIZATION_CACHE_ENTRIES &&
2302
+ !map.has(key)) {
2303
+ const oldest = map.keys().next().value;
2304
+ if (oldest !== undefined) {
2305
+ map.delete(oldest);
2306
+ }
2307
+ }
2308
+ map.delete(key);
2309
+ map.set(key, value);
2310
+ };
2311
+ const loadRumApplicationForAccess = async (data) => {
2312
+ const cacheKey = `${data.projectId.toString()}:${data.rumApplicationId.toString()}`;
2313
+ if (data.allowCached) {
2314
+ const cached = rumApplicationCache.get(cacheKey);
2315
+ if (cached && cached.expiresAt > Date.now()) {
2316
+ return cached.application;
2317
+ }
2318
+ }
2274
2319
  const application = await RumApplicationService.findOneBy({
2275
2320
  query: {
2276
2321
  _id: data.rumApplicationId.toString(),
@@ -2286,6 +2331,21 @@ const assertSessionReplayApplicationAccess = async (data) => {
2286
2331
  isRoot: true,
2287
2332
  },
2288
2333
  });
2334
+ if (application) {
2335
+ boundedCacheSet(rumApplicationCache, cacheKey, {
2336
+ application: application,
2337
+ expiresAt: Date.now() + SESSION_REPLAY_AUTHORIZATION_CACHE_TTL_MS,
2338
+ });
2339
+ }
2340
+ return application;
2341
+ };
2342
+ const assertSessionReplayApplicationAccess = async (data) => {
2343
+ const scope = getSessionReplayLabelScope(data.databaseProps, data.permissions);
2344
+ const application = await loadRumApplicationForAccess({
2345
+ projectId: data.projectId,
2346
+ rumApplicationId: data.rumApplicationId,
2347
+ allowCached: data.allowCached === true,
2348
+ });
2289
2349
  /*
2290
2350
  * An application that does not exist in this project is refused the
2291
2351
  * same way an out-of-scope one is, so the endpoint cannot be used to
@@ -2367,21 +2427,177 @@ const resolveAccessibleRumApplicationIds = async (data) => {
2367
2427
  }
2368
2428
  return { applicationIds: accessibleIds, isTruncated: isTruncated };
2369
2429
  };
2370
- const resolveAuthorizedSession = async (data) => {
2371
- const header = await SessionReplayReadService.getSessionHeader({
2430
+ /*
2431
+ * Why a sessionId has no playable header. Each answer carries a
2432
+ * different code word in its message so a client can tell them apart
2433
+ * without parsing prose, and each is a 404: the id was well-formed, there
2434
+ * is simply nothing at it.
2435
+ */
2436
+ const GENERIC_MISSING_SESSION_MESSAGE = "not-found: No session replay exists with this id in this project.";
2437
+ const isApplicationInSessionReplayScopeById = async (data) => {
2438
+ let scope;
2439
+ try {
2440
+ scope = getSessionReplayLabelScope(data.databaseProps, SESSION_REPLAY_PAYLOAD_PERMISSIONS);
2441
+ }
2442
+ catch (_a) {
2443
+ /* A scope this path cannot enforce is refused, never widened. */
2444
+ return false;
2445
+ }
2446
+ if (scope.isUnrestricted) {
2447
+ return true;
2448
+ }
2449
+ if (!ObjectID.isValidUUID(data.rumApplicationId)) {
2450
+ return false;
2451
+ }
2452
+ const application = await loadRumApplicationForAccess({
2453
+ projectId: data.projectId,
2454
+ rumApplicationId: new ObjectID(data.rumApplicationId),
2455
+ allowCached: true,
2456
+ });
2457
+ if (!application) {
2458
+ return false;
2459
+ }
2460
+ return isApplicationInSessionReplayScope({
2461
+ scope: scope,
2462
+ application: application,
2463
+ });
2464
+ };
2465
+ const explainMissingSession = async (data) => {
2466
+ /*
2467
+ * The expired header is resolved FIRST, and not because it is the more
2468
+ * likely answer: it is the only lookup that names an application, and
2469
+ * nothing specific may be disclosed until that application has been
2470
+ * authorized.
2471
+ *
2472
+ * The expiry answer carries the recording's existence, when it started
2473
+ * and what retention the owning application runs. Answered before the
2474
+ * access check - which is where it used to sit, since this runs on the
2475
+ * path where getSessionHeader found nothing to authorize AGAINST - it let
2476
+ * a label-scoped reviewer probe session ids and learn all three for
2477
+ * applications outside their scope. That is precisely the existence
2478
+ * probing assertSessionReplayApplicationAccess refuses "the same way" for
2479
+ * a session that DOES exist.
2480
+ *
2481
+ * This read is deliberately retention-free (an expired row is the whole
2482
+ * point), so it is the one place a scope check has to be written out by
2483
+ * hand rather than inherited from resolveAuthorizedSession.
2484
+ */
2485
+ const expired = await SessionReplayReadService.getExpiredSessionInfo({
2372
2486
  projectId: data.projectId,
2373
2487
  sessionId: data.sessionId,
2488
+ rumApplicationId: data.rumApplicationId,
2374
2489
  });
2490
+ if (expired && expired.rumApplicationId) {
2491
+ if (!(await isApplicationInSessionReplayScopeById({
2492
+ projectId: data.projectId,
2493
+ rumApplicationId: expired.rumApplicationId,
2494
+ databaseProps: data.databaseProps,
2495
+ }))) {
2496
+ return new NotFoundException(GENERIC_MISSING_SESSION_MESSAGE);
2497
+ }
2498
+ }
2499
+ /*
2500
+ * Erasure is checked only once the caller is entitled to a specific
2501
+ * answer. An erased session may still have a header row until the
2502
+ * ClickHouse mutation lands, and "expired" would be the wrong story for
2503
+ * a recording that was deliberately destroyed - so it is reported ahead
2504
+ * of expiry. The tombstone throws when Redis cannot answer; that is a
2505
+ * "cannot tell", which falls through to the header-based answers.
2506
+ */
2507
+ let isErased = false;
2508
+ try {
2509
+ isErased = await isSessionErased({
2510
+ projectId: data.projectId.toString(),
2511
+ sessionId: data.sessionId,
2512
+ });
2513
+ }
2514
+ catch (_a) {
2515
+ isErased = false;
2516
+ }
2517
+ if (isErased) {
2518
+ return new NotFoundException("erased: This recording was erased by a data subject request and cannot be played back.");
2519
+ }
2520
+ if (expired) {
2521
+ const retentionDays = Math.max(1, Math.round((expired.expiresAt.getTime() - expired.startTime.getTime()) /
2522
+ (24 * 60 * 60 * 1000)));
2523
+ return new NotFoundException(`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.`);
2524
+ }
2525
+ return new NotFoundException(GENERIC_MISSING_SESSION_MESSAGE);
2526
+ };
2527
+ const resolveAuthorizedSession = async (data) => {
2528
+ const headerCacheKey = `${data.projectId.toString()}:${data.sessionId}:${data.rumApplicationId ? data.rumApplicationId.toString() : ""}`;
2529
+ let header = null;
2530
+ if (data.allowCached) {
2531
+ const cached = sessionHeaderCache.get(headerCacheKey);
2532
+ if (cached && cached.expiresAt > Date.now()) {
2533
+ header = cached.header;
2534
+ }
2535
+ }
2375
2536
  if (!header) {
2376
- throw new BadDataException("Session replay not found.");
2537
+ header = await SessionReplayReadService.getSessionHeader({
2538
+ projectId: data.projectId,
2539
+ sessionId: data.sessionId,
2540
+ rumApplicationId: data.rumApplicationId,
2541
+ });
2542
+ if (header) {
2543
+ boundedCacheSet(sessionHeaderCache, headerCacheKey, {
2544
+ header: header,
2545
+ expiresAt: Date.now() + SESSION_REPLAY_AUTHORIZATION_CACHE_TTL_MS,
2546
+ });
2547
+ }
2377
2548
  }
2378
- await assertSessionReplayApplicationAccess({
2549
+ if (!header) {
2550
+ throw await explainMissingSession({
2551
+ projectId: data.projectId,
2552
+ sessionId: data.sessionId,
2553
+ rumApplicationId: data.rumApplicationId,
2554
+ databaseProps: data.databaseProps,
2555
+ });
2556
+ }
2557
+ const application = await assertSessionReplayApplicationAccess({
2379
2558
  projectId: data.projectId,
2380
2559
  rumApplicationId: new ObjectID(header.rumApplicationId),
2381
2560
  databaseProps: data.databaseProps,
2382
2561
  permissions: SESSION_REPLAY_PAYLOAD_PERMISSIONS,
2562
+ allowCached: data.allowCached,
2383
2563
  });
2384
- return header;
2564
+ return { header: header, application: application };
2565
+ };
2566
+ const readOptionalObjectIdFromBody = (body, key) => {
2567
+ const value = body[key];
2568
+ if (value === undefined || value === null || value === "") {
2569
+ return undefined;
2570
+ }
2571
+ if (typeof value !== "string" || !ObjectID.isValidUUID(value)) {
2572
+ throw new BadDataException(`${key} is not a valid id`);
2573
+ }
2574
+ return new ObjectID(value);
2575
+ };
2576
+ const readOptionalDateFromBody = (body, key) => {
2577
+ const value = body[key];
2578
+ if (value === undefined || value === null || value === "") {
2579
+ return undefined;
2580
+ }
2581
+ if (typeof value !== "string" && typeof value !== "number") {
2582
+ throw new BadDataException(`${key} must be an ISO-8601 timestamp`);
2583
+ }
2584
+ const parsed = typeof value === "number"
2585
+ ? new Date(value)
2586
+ : OneUptimeDate.fromString(value);
2587
+ if (!Number.isFinite(parsed.getTime())) {
2588
+ throw new BadDataException(`${key} must be an ISO-8601 timestamp`);
2589
+ }
2590
+ return parsed;
2591
+ };
2592
+ const readLimitFromBody = (body, defaultLimit, maxLimit) => {
2593
+ const value = body["limit"];
2594
+ if (value === undefined || value === null) {
2595
+ return defaultLimit;
2596
+ }
2597
+ if (typeof value !== "number" || !Number.isInteger(value) || value < 1) {
2598
+ throw new BadDataException(`limit must be a whole number between 1 and ${maxLimit}`);
2599
+ }
2600
+ return Math.min(value, maxLimit);
2385
2601
  };
2386
2602
  const readObjectIdFromBody = (body, key) => {
2387
2603
  const value = body[key];
@@ -2393,23 +2609,91 @@ const readObjectIdFromBody = (body, key) => {
2393
2609
  }
2394
2610
  return new ObjectID(value);
2395
2611
  };
2612
+ /*
2613
+ * A session id is 32 hex characters minted in the browser. The cap is
2614
+ * generous rather than exact - older recorders and hand-written API
2615
+ * callers exist - but it is a cap: an unbounded caller-supplied string
2616
+ * reaches ClickHouse as a bound parameter on a hot path.
2617
+ */
2618
+ const MAX_SESSION_REPLAY_SESSION_ID_LENGTH = 128;
2396
2619
  const readSessionIdFromBody = (body) => {
2397
2620
  const sessionId = body["sessionId"];
2398
2621
  if (typeof sessionId !== "string" || sessionId.length === 0) {
2399
2622
  throw new BadDataException("sessionId is required");
2400
2623
  }
2624
+ if (sessionId.length > MAX_SESSION_REPLAY_SESSION_ID_LENGTH) {
2625
+ throw new BadDataException(`sessionId must be at most ${MAX_SESSION_REPLAY_SESSION_ID_LENGTH} characters.`);
2626
+ }
2401
2627
  return sessionId;
2402
2628
  };
2629
+ /*
2630
+ * Caps on the list's filter inputs.
2631
+ *
2632
+ * Every array filter becomes an `IN (...)` inside a HAVING, which
2633
+ * ClickHouse evaluates per GROUP over the whole window - so the cost of a
2634
+ * request is the caller's array length times the number of sessions in
2635
+ * range. Uncapped, one request carrying tens of thousands of browser names
2636
+ * is a cheap denial of service against the list for any holder of the list
2637
+ * permission. The limits are far above any real UI: the filter panel
2638
+ * offers a couple of dozen browsers, and no session has more than a
2639
+ * handful of routes.
2640
+ *
2641
+ * Values are TRUNCATED and the array is SLICED rather than refused: an
2642
+ * over-long value simply cannot match anything a bounded column holds, so
2643
+ * a 400 would add nothing but a confusing error.
2644
+ */
2645
+ const MAX_SESSION_REPLAY_FILTER_ARRAY_LENGTH = 50;
2646
+ const MAX_SESSION_REPLAY_FILTER_VALUE_LENGTH = 256;
2403
2647
  const readStringArrayFromBody = (body, key) => {
2404
2648
  const value = body[key];
2405
2649
  if (!Array.isArray(value)) {
2406
2650
  return undefined;
2407
2651
  }
2408
- const strings = value.filter((item) => {
2409
- return typeof item === "string" && item.length > 0;
2410
- });
2652
+ const strings = [];
2653
+ for (const item of value) {
2654
+ if (typeof item !== "string" || item.length === 0) {
2655
+ continue;
2656
+ }
2657
+ strings.push(item.substring(0, MAX_SESSION_REPLAY_FILTER_VALUE_LENGTH));
2658
+ if (strings.length >= MAX_SESSION_REPLAY_FILTER_ARRAY_LENGTH) {
2659
+ break;
2660
+ }
2661
+ }
2411
2662
  return strings.length > 0 ? strings : undefined;
2412
2663
  };
2664
+ const readBoundedStringFromBody = (body, key) => {
2665
+ const value = body[key];
2666
+ if (typeof value !== "string" || value.length === 0) {
2667
+ return undefined;
2668
+ }
2669
+ return value.substring(0, MAX_SESSION_REPLAY_FILTER_VALUE_LENGTH);
2670
+ };
2671
+ const readTagFilterFromBody = (filters) => {
2672
+ const value = filters["tags"];
2673
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
2674
+ return undefined;
2675
+ }
2676
+ const tags = {};
2677
+ let count = 0;
2678
+ for (const key of Object.keys(value)) {
2679
+ const entry = value[key];
2680
+ if (typeof entry !== "string" || key.length === 0) {
2681
+ continue;
2682
+ }
2683
+ if (count >= SESSION_REPLAY_MAX_TAG_KEYS) {
2684
+ break;
2685
+ }
2686
+ tags[key.substring(0, SESSION_REPLAY_MAX_TAG_KEY_LENGTH)] = entry.substring(0, SESSION_REPLAY_MAX_TAG_VALUE_LENGTH);
2687
+ count++;
2688
+ }
2689
+ return count > 0 ? tags : undefined;
2690
+ };
2691
+ const isBindableCursorSortValue = (cursor, sortBy) => {
2692
+ if (sortBy === "startTime") {
2693
+ return Number.isFinite(new Date(cursor.sortValue).getTime());
2694
+ }
2695
+ return cursor.sortValue >= 0;
2696
+ };
2413
2697
  // --- Session Replay List Endpoint ---
2414
2698
  router.post("/telemetry/rum/session-replay/list", ...requireSessionReplayListAccess, async (req, res, next) => {
2415
2699
  try {
@@ -2433,12 +2717,29 @@ router.post("/telemetry/rum/session-replay/list", ...requireSessionReplayListAcc
2433
2717
  databaseProps: databaseProps,
2434
2718
  permissions: SESSION_REPLAY_LIST_PERMISSIONS,
2435
2719
  });
2436
- const startTime = body["startTime"]
2437
- ? OneUptimeDate.fromString(body["startTime"])
2438
- : OneUptimeDate.addRemoveDays(OneUptimeDate.getCurrentDate(), -7);
2439
- const endTime = body["endTime"]
2440
- ? OneUptimeDate.fromString(body["endTime"])
2441
- : OneUptimeDate.getCurrentDate();
2720
+ const startTime = readOptionalDateFromBody(body, "startTime") ||
2721
+ OneUptimeDate.addRemoveDays(OneUptimeDate.getCurrentDate(), -7);
2722
+ const endTime = readOptionalDateFromBody(body, "endTime") ||
2723
+ OneUptimeDate.getCurrentDate();
2724
+ /*
2725
+ * An inverted window matches nothing, and an empty list with a 200
2726
+ * is exactly the answer a client cannot distinguish from "no
2727
+ * sessions" - so it is a 400 with the reason instead.
2728
+ */
2729
+ if (startTime.getTime() > endTime.getTime()) {
2730
+ return Response.sendErrorResponse(req, res, new BadDataException("startTime must not be after endTime"));
2731
+ }
2732
+ const limit = readLimitFromBody(body, DEFAULT_SESSION_REPLAY_LIST_LIMIT, MAX_SESSION_REPLAY_LIST_LIMIT);
2733
+ const rawSortBy = body["sortBy"];
2734
+ if (rawSortBy !== undefined &&
2735
+ rawSortBy !== null &&
2736
+ (typeof rawSortBy !== "string" ||
2737
+ !SESSION_REPLAY_SORT_BY_VALUES.includes(rawSortBy))) {
2738
+ return Response.sendErrorResponse(req, res, new BadDataException(`sortBy must be one of ${SESSION_REPLAY_SORT_BY_VALUES.join(", ")}.`));
2739
+ }
2740
+ const sortBy = typeof rawSortBy === "string"
2741
+ ? rawSortBy
2742
+ : "startTime";
2442
2743
  /*
2443
2744
  * The narrower identity ACL, resolved BEFORE the filters are built.
2444
2745
  *
@@ -2473,7 +2774,29 @@ router.post("/telemetry/rum/session-replay/list", ...requireSessionReplayListAcc
2473
2774
  !SessionReplayIdentity.isUsableUserRef(rawFilters["identifiedUserRef"])) {
2474
2775
  return Response.sendErrorResponse(req, res, new BadDataException(`identifiedUserRef must be a non-empty string of at most ${SESSION_REPLAY_MAX_USER_REF_LENGTH} characters.`));
2475
2776
  }
2476
- const filters = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, (typeof rawFilters["hasError"] === "boolean" && {
2777
+ /*
2778
+ * A filter the server understood but did not apply, named in the
2779
+ * response.
2780
+ *
2781
+ * The identity filter is gated on the narrower identity permission.
2782
+ * Dropping it silently is the dangerous half of that gate: the
2783
+ * request "show me jane@example.com's sessions" then answers 200 with
2784
+ * EVERY session in the application, and the caller has no way to tell
2785
+ * - least of all when the application has no sessions at all, where
2786
+ * even inspecting the rows cannot reveal it. A support engineer opens
2787
+ * the wrong recording, and each opening writes an audit row against a
2788
+ * real end user.
2789
+ *
2790
+ * Answered as data rather than as a 403 because the rest of the list
2791
+ * IS something the caller may read: the page renders the sessions and
2792
+ * says the filter was ignored, instead of failing outright.
2793
+ */
2794
+ const ignoredFilters = [];
2795
+ if (!includeIdentifiedUserLabel &&
2796
+ SessionReplayIdentity.isUsableUserRef(rawFilters["identifiedUserRef"])) {
2797
+ ignoredFilters.push("identifiedUserRef");
2798
+ }
2799
+ const filters = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, (typeof rawFilters["hasError"] === "boolean" && {
2477
2800
  hasError: rawFilters["hasError"],
2478
2801
  })), (typeof rawFilters["hasFrustration"] === "boolean" && {
2479
2802
  hasFrustration: rawFilters["hasFrustration"],
@@ -2495,31 +2818,92 @@ router.post("/telemetry/rum/session-replay/list", ...requireSessionReplayListAcc
2495
2818
  projectId: projectId,
2496
2819
  userRef: rawFilters["identifiedUserRef"],
2497
2820
  }),
2498
- })), (typeof rawFilters["identifiedUserKey"] === "string" &&
2821
+ })), (readBoundedStringFromBody(rawFilters, "identifiedUserKey") &&
2499
2822
  !SessionReplayIdentity.isUsableUserRef(rawFilters["identifiedUserRef"]) && {
2500
- identifiedUserKey: rawFilters["identifiedUserKey"],
2501
- })), (typeof rawFilters["route"] === "string" && {
2502
- route: rawFilters["route"],
2503
- })), (typeof rawFilters["minDurationMs"] === "number" && {
2823
+ identifiedUserKey: readBoundedStringFromBody(rawFilters, "identifiedUserKey"),
2824
+ })), (readBoundedStringFromBody(rawFilters, "route") && {
2825
+ route: readBoundedStringFromBody(rawFilters, "route"),
2826
+ })), (typeof rawFilters["minDurationMs"] === "number" &&
2827
+ Number.isFinite(rawFilters["minDurationMs"]) && {
2504
2828
  minDurationMs: rawFilters["minDurationMs"],
2829
+ })), (typeof rawFilters["hasIdentifiedUser"] === "boolean" && {
2830
+ hasIdentifiedUser: rawFilters["hasIdentifiedUser"],
2831
+ })), (typeof rawFilters["isPlayable"] === "boolean" && {
2832
+ isPlayable: rawFilters["isPlayable"],
2833
+ })), (typeof rawFilters["hasTraces"] === "boolean" && {
2834
+ hasTraces: rawFilters["hasTraces"],
2835
+ })), (typeof rawFilters["urlPrefix"] === "string" &&
2836
+ rawFilters["urlPrefix"].length > 0 && {
2837
+ urlPrefix: rawFilters["urlPrefix"].substring(0, SESSION_REPLAY_LIST_SEARCH_MAX_LENGTH),
2838
+ })), (readTagFilterFromBody(rawFilters) && {
2839
+ tags: readTagFilterFromBody(rawFilters),
2505
2840
  }));
2506
- const rawCursor = body["cursor"]
2507
- ? body["cursor"]
2508
- : undefined;
2509
- const cursor = rawCursor &&
2510
- typeof rawCursor["startTimeUnixMs"] === "number" &&
2511
- typeof rawCursor["sessionId"] === "string"
2512
- ? {
2513
- startTimeUnixMs: rawCursor["startTimeUnixMs"],
2514
- sessionId: rawCursor["sessionId"],
2841
+ /*
2842
+ * Free text is the one predicate that cannot use an index: it is a
2843
+ * substring scan of every header in the window. The string cap
2844
+ * keeps each comparison cheap; the window cap keeps the number of
2845
+ * comparisons bounded, and is answered with its own message so the
2846
+ * list can say "narrow the range" rather than "no sessions".
2847
+ */
2848
+ const rawSearch = rawFilters["search"];
2849
+ if (rawSearch !== undefined && rawSearch !== null && rawSearch !== "") {
2850
+ if (typeof rawSearch !== "string") {
2851
+ return Response.sendErrorResponse(req, res, new BadDataException("search must be a string"));
2515
2852
  }
2516
- : undefined;
2517
- const result = await SessionReplayReadService.listSessions(Object.assign(Object.assign({ projectId: projectId, rumApplicationId: rumApplicationId, startTime: startTime, endTime: endTime, filters: filters, limit: typeof body["limit"] === "number"
2518
- ? body["limit"]
2519
- : DEFAULT_SESSION_REPLAY_LIST_LIMIT }, (cursor !== undefined && { cursor })), { includeIdentifiedUserLabel: includeIdentifiedUserLabel }));
2853
+ if (rawSearch.length > SESSION_REPLAY_LIST_SEARCH_MAX_LENGTH) {
2854
+ return Response.sendErrorResponse(req, res, new BadDataException(`search must be at most ${SESSION_REPLAY_LIST_SEARCH_MAX_LENGTH} characters.`));
2855
+ }
2856
+ const windowMs = endTime.getTime() - startTime.getTime();
2857
+ if (windowMs >
2858
+ SESSION_REPLAY_LIST_SEARCH_MAX_WINDOW_DAYS * 24 * 60 * 60 * 1000) {
2859
+ return Response.sendErrorResponse(req, res, new BadDataException(`Search covers at most ${SESSION_REPLAY_LIST_SEARCH_MAX_WINDOW_DAYS} days at a time. Narrow the range to search it.`));
2860
+ }
2861
+ if (rawSearch.trim().length > 0) {
2862
+ filters.search = rawSearch.trim();
2863
+ }
2864
+ }
2865
+ /*
2866
+ * Both cursor shapes are accepted: the legacy {startTimeUnixMs,
2867
+ * sessionId} one an older Dashboard or a bookmark still sends (it
2868
+ * means "newest first"), and the sorted one. A cursor for a
2869
+ * different ordering than the one requested is refused by the
2870
+ * service rather than silently mis-paged.
2871
+ */
2872
+ const cursor = body["cursor"] !== undefined && body["cursor"] !== null
2873
+ ? parseSessionReplayListCursor(body["cursor"])
2874
+ : null;
2875
+ if (body["cursor"] !== undefined &&
2876
+ body["cursor"] !== null &&
2877
+ (cursor === null || !isBindableCursorSortValue(cursor, sortBy))) {
2878
+ return Response.sendErrorResponse(req, res, new BadDataException("cursor must be the nextCursor of a previous page."));
2879
+ }
2880
+ const result = await SessionReplayReadService.listSessions(Object.assign(Object.assign({ projectId: projectId, rumApplicationId: rumApplicationId, startTime: startTime, endTime: endTime, filters: filters, limit: limit, sortBy: sortBy }, (cursor !== null && { cursor })), { includeIdentifiedUserLabel: includeIdentifiedUserLabel }));
2881
+ /*
2882
+ * The legacy cursor shape is still EMITTED for the newest-first sort
2883
+ * so an older Dashboard keeps paging; every other sort emits the
2884
+ * generalised shape, which such a client never asks for.
2885
+ */
2886
+ const nextCursor = result.nextCursor
2887
+ ? sortBy === "startTime"
2888
+ ? {
2889
+ startTimeUnixMs: result.nextCursor.sortValue,
2890
+ sessionId: result.nextCursor.sessionId,
2891
+ }
2892
+ : {
2893
+ sortBy: result.nextCursor.sortBy,
2894
+ sortValue: result.nextCursor.sortValue,
2895
+ sessionId: result.nextCursor.sessionId,
2896
+ }
2897
+ : null;
2520
2898
  return Response.sendJsonObjectResponse(req, res, {
2521
2899
  sessions: result.sessions,
2522
- nextCursor: result.nextCursor,
2900
+ nextCursor: nextCursor,
2901
+ /*
2902
+ * Always present, empty when everything asked for was applied, so a
2903
+ * client can read it without having to distinguish "no ignored
2904
+ * filters" from "an older server that never said".
2905
+ */
2906
+ ignoredFilters: ignoredFilters,
2523
2907
  });
2524
2908
  }
2525
2909
  catch (err) {
@@ -2537,11 +2921,18 @@ router.post("/telemetry/rum/session-replay/manifest", ...requireSessionReplayPay
2537
2921
  const projectId = databaseProps.tenantId;
2538
2922
  const body = req.body;
2539
2923
  const sessionId = readSessionIdFromBody(body);
2540
- const header = await resolveAuthorizedSession({
2924
+ /*
2925
+ * Optional disambiguator, validated but NOT trusted: the header it
2926
+ * selects still names the application that gets authorized.
2927
+ */
2928
+ const requestedApplicationId = readOptionalObjectIdFromBody(body, "rumApplicationId");
2929
+ const authorized = await resolveAuthorizedSession({
2541
2930
  projectId: projectId,
2542
2931
  sessionId: sessionId,
2543
2932
  databaseProps: databaseProps,
2933
+ rumApplicationId: requestedApplicationId,
2544
2934
  });
2935
+ const header = authorized.header;
2545
2936
  /*
2546
2937
  * The authorized application, resolved server-side from the header.
2547
2938
  * Every chunk-table read below is pinned to it: that table's replace
@@ -2551,44 +2942,108 @@ router.post("/telemetry/rum/session-replay/manifest", ...requireSessionReplayPay
2551
2942
  */
2552
2943
  const authorizedApplicationId = new ObjectID(header.rumApplicationId);
2553
2944
  /*
2554
- * The audit row is written BEFORE the manifest is built, not after.
2555
- * A read that fails halfway through still happened, and an audit
2556
- * that only records successful reads is an audit an attacker can
2557
- * evade by aborting the request.
2945
+ * A live-session poll reuses the view row the first read created.
2946
+ *
2947
+ * The player re-fetches the manifest every 30s while a session is
2948
+ * still recording, and each of those is the same person continuing
2949
+ * the same viewing, not a new disclosure. Writing a row per poll
2950
+ * would turn one viewing into dozens of audit entries and bury the
2951
+ * signal the audit exists for. The row is reused ONLY when the
2952
+ * caller proves it is theirs (looked up by viewedByUserId) AND it
2953
+ * is for this session; anything else - somebody else's viewId, a
2954
+ * different session, an id that no longer exists - is a fresh
2955
+ * recordView, exactly as if isRefresh had not been sent.
2558
2956
  */
2559
- const view = await RumSessionReplayViewService.recordView({
2560
- projectId: projectId,
2561
- rumApplicationId: authorizedApplicationId,
2562
- sessionId: sessionId,
2563
- viewedByUserId: databaseProps.userId,
2564
- ipAddress: getClientIp(req),
2565
- userAgent: typeof req.headers["user-agent"] === "string"
2566
- ? req.headers["user-agent"]
2567
- : undefined,
2568
- accessReason: typeof body["accessReason"] === "string"
2569
- ? body["accessReason"]
2570
- : undefined,
2571
- linkedIncidentId: typeof body["linkedIncidentId"] === "string" &&
2572
- body["linkedIncidentId"].length > 0
2573
- ? new ObjectID(body["linkedIncidentId"])
2574
- : undefined,
2575
- linkedExceptionFingerprint: typeof body["linkedExceptionFingerprint"] === "string"
2576
- ? body["linkedExceptionFingerprint"]
2577
- : undefined,
2578
- });
2957
+ let viewId = null;
2958
+ const isRefresh = body["isRefresh"] === true;
2959
+ const refreshViewId = isRefresh
2960
+ ? readOptionalObjectIdFromBody(body, "viewId")
2961
+ : undefined;
2962
+ if (refreshViewId && databaseProps.userId) {
2963
+ const ownView = await RumSessionReplayViewService.findOwnView({
2964
+ viewId: refreshViewId,
2965
+ projectId: projectId,
2966
+ viewedByUserId: databaseProps.userId,
2967
+ sessionId: sessionId,
2968
+ });
2969
+ if (ownView &&
2970
+ ownView.id &&
2971
+ ownView.rumApplicationId &&
2972
+ ownView.rumApplicationId.toString() ===
2973
+ authorizedApplicationId.toString()) {
2974
+ viewId = ownView.id.toString();
2975
+ }
2976
+ }
2977
+ if (viewId === null) {
2978
+ /*
2979
+ * The audit row is written BEFORE the manifest is built, not
2980
+ * after. A read that fails halfway through still happened, and
2981
+ * an audit that only records successful reads is an audit an
2982
+ * attacker can evade by aborting the request.
2983
+ *
2984
+ * linkedIncidentId is validated rather than constructed blindly:
2985
+ * ObjectID's constructor checks nothing, and a malformed id would
2986
+ * fail the audit insert - and with it the playback it audits. A
2987
+ * bad link is dropped; the view is still recorded.
2988
+ */
2989
+ const rawLinkedIncidentId = body["linkedIncidentId"];
2990
+ const view = await RumSessionReplayViewService.recordView({
2991
+ projectId: projectId,
2992
+ rumApplicationId: authorizedApplicationId,
2993
+ sessionId: sessionId,
2994
+ viewedByUserId: databaseProps.userId,
2995
+ ipAddress: getClientIp(req),
2996
+ userAgent: typeof req.headers["user-agent"] === "string"
2997
+ ? req.headers["user-agent"]
2998
+ : undefined,
2999
+ accessReason: typeof body["accessReason"] === "string"
3000
+ ? body["accessReason"]
3001
+ : undefined,
3002
+ linkedIncidentId: typeof rawLinkedIncidentId === "string" &&
3003
+ ObjectID.isValidUUID(rawLinkedIncidentId)
3004
+ ? new ObjectID(rawLinkedIncidentId)
3005
+ : undefined,
3006
+ linkedExceptionFingerprint: typeof body["linkedExceptionFingerprint"] === "string" &&
3007
+ body["linkedExceptionFingerprint"].length > 0
3008
+ ? body["linkedExceptionFingerprint"]
3009
+ : undefined,
3010
+ });
3011
+ viewId = view.id ? view.id.toString() : null;
3012
+ }
2579
3013
  const manifest = await SessionReplayReadService.getManifest({
2580
3014
  header: header,
2581
3015
  projectId: projectId,
2582
3016
  rumApplicationId: authorizedApplicationId,
2583
3017
  sessionId: sessionId,
2584
3018
  });
3019
+ /*
3020
+ * The identity columns are read by a SEPARATE statement that runs
3021
+ * only after the narrower identity check passes for the application
3022
+ * the caller was just authorized against. Nothing above named them,
3023
+ * so a caller without the permission never causes a statement that
3024
+ * touches identifiedUserLabel or identifiedUserTraits to exist.
3025
+ */
3026
+ let identity = null;
3027
+ if (canReadIdentifiedUserLabel({
3028
+ databaseProps: databaseProps,
3029
+ application: authorized.application,
3030
+ })) {
3031
+ identity = await SessionReplayReadService.getSessionIdentity({
3032
+ projectId: projectId,
3033
+ rumApplicationId: authorizedApplicationId,
3034
+ sessionId: sessionId,
3035
+ });
3036
+ }
3037
+ const responseHeader = identity
3038
+ ? Object.assign(Object.assign({}, manifest.header), { identifiedUserLabel: identity.identifiedUserLabel, identifiedUserTraits: identity.identifiedUserTraits }) : manifest.header;
2585
3039
  return Response.sendJsonObjectResponse(req, res, {
2586
3040
  /*
2587
3041
  * viewId is echoed back so the player's heartbeat can advance the
2588
- * very row this read created, instead of guessing at one.
3042
+ * very row this read created (or reused), instead of guessing at
3043
+ * one.
2589
3044
  */
2590
- viewId: view.id ? view.id.toString() : null,
2591
- header: manifest.header,
3045
+ viewId: viewId,
3046
+ header: responseHeader,
2592
3047
  tabs: manifest.tabs,
2593
3048
  isChunkIndexTruncated: manifest.isChunkIndexTruncated,
2594
3049
  });
@@ -2631,12 +3086,22 @@ router.post("/telemetry/rum/session-replay/chunks", ...requireSessionReplayPaylo
2631
3086
  if (chunkIndexes.length > MAX_SESSION_REPLAY_CHUNKS_PER_READ) {
2632
3087
  return Response.sendErrorResponse(req, res, new BadDataException(`A maximum of ${MAX_SESSION_REPLAY_CHUNKS_PER_READ} chunks may be requested at a time.`));
2633
3088
  }
2634
- const header = await resolveAuthorizedSession({
3089
+ /*
3090
+ * Served from the 30s authorization cache: a session is 60 chunk
3091
+ * pages at most, and re-aggregating its header plus re-loading the
3092
+ * application's labels for every one of them is what made seeks
3093
+ * stutter. The label decision itself is still made against the
3094
+ * caller's current permissions on every request.
3095
+ */
3096
+ const authorized = await resolveAuthorizedSession({
2635
3097
  projectId: projectId,
2636
3098
  sessionId: sessionId,
2637
3099
  databaseProps: databaseProps,
3100
+ rumApplicationId: readOptionalObjectIdFromBody(body, "rumApplicationId"),
3101
+ allowCached: true,
2638
3102
  });
2639
- const chunks = await SessionReplayReadService.getChunks({
3103
+ const header = authorized.header;
3104
+ const read = await SessionReplayReadService.getChunks({
2640
3105
  projectId: projectId,
2641
3106
  /* Always the application the caller was authorized against. */
2642
3107
  rumApplicationId: new ObjectID(header.rumApplicationId),
@@ -2656,18 +3121,26 @@ router.post("/telemetry/rum/session-replay/chunks", ...requireSessionReplayPaylo
2656
3121
  const frames = [];
2657
3122
  /*
2658
3123
  * The byte cap is re-checked here against the bytes actually being
2659
- * framed, not only against what the pre-check in the read service
2660
- * believed. This is the last place the size of the response is
2661
- * knowable, so it is the one place a cap on the response can be
2662
- * absolute regardless of how stored size was estimated upstream.
3124
+ * framed, not only against what the read service believed. This is
3125
+ * the last place the size of the response is knowable, so it is the
3126
+ * one place a cap on the response can be absolute regardless of how
3127
+ * stored size was estimated upstream. Like the service, it answers
3128
+ * with the prefix that fits rather than refusing - and never with
3129
+ * nothing: a single chunk is bounded by the ingest cap, and a chunk
3130
+ * that could never be served would dead-end playback at it forever.
2663
3131
  */
2664
3132
  let responseBytes = 0;
2665
- for (const chunk of chunks) {
3133
+ const omittedChunkIndexes = [...read.omittedChunkIndexes];
3134
+ for (const chunk of read.chunks) {
2666
3135
  const payloadBuffer = Buffer.from(chunk.payload, "utf8");
2667
- responseBytes += payloadBuffer.length + 8;
2668
- if (responseBytes > MAX_SESSION_REPLAY_READ_BYTES) {
2669
- return Response.sendErrorResponse(req, res, new BadDataException(`The requested chunks exceed the ${MAX_SESSION_REPLAY_READ_BYTES} byte limit for a single read. Request fewer chunks.`));
3136
+ const framedBytes = payloadBuffer.length + 8;
3137
+ if (frames.length > 0 &&
3138
+ (responseBytes + framedBytes > MAX_SESSION_REPLAY_READ_BYTES ||
3139
+ omittedChunkIndexes.length > 0)) {
3140
+ omittedChunkIndexes.push(chunk.chunkIndex);
3141
+ continue;
2670
3142
  }
3143
+ responseBytes += framedBytes;
2671
3144
  const headerBuffer = Buffer.alloc(8);
2672
3145
  headerBuffer.writeUInt32LE(chunk.chunkIndex, 0);
2673
3146
  headerBuffer.writeUInt32LE(payloadBuffer.length, 4);
@@ -2676,6 +3149,18 @@ router.post("/telemetry/rum/session-replay/chunks", ...requireSessionReplayPaylo
2676
3149
  const responseBody = Buffer.concat(frames);
2677
3150
  res.setHeader("Content-Type", "application/octet-stream");
2678
3151
  res.setHeader("Content-Length", responseBody.length.toString());
3152
+ /*
3153
+ * Which requested chunks exist but were left out for size, so a
3154
+ * client that cares can ask for them in a smaller page instead of
3155
+ * reading their absence as a gap in the recording.
3156
+ */
3157
+ if (omittedChunkIndexes.length > 0) {
3158
+ res.setHeader("X-OneUptime-Replay-Omitted-Chunks", omittedChunkIndexes
3159
+ .sort((a, b) => {
3160
+ return a - b;
3161
+ })
3162
+ .join(","));
3163
+ }
2679
3164
  /*
2680
3165
  * A recording is personal data. Nothing about it may sit in a
2681
3166
  * shared cache, and the browser should not keep it on disk either.
@@ -2704,13 +3189,16 @@ router.post("/telemetry/rum/session-replay/heartbeat", ...requireSessionReplayPa
2704
3189
  return Response.sendErrorResponse(req, res, new BadDataException("secondsWatched must be a number"));
2705
3190
  }
2706
3191
  /*
2707
- * Floored to the 15s heartbeat cadence. recordSecondsWatched is
2708
- * monotonic and returns without writing when the value does not
2709
- * advance, so flooring here turns a chatty client into at most one
2710
- * UPDATE per 15 seconds watched without any server-side timer or
2711
- * cross-pod throttle state.
3192
+ * SEMANTICS: secondsWatched is the cumulative seconds of footage the
3193
+ * player has PLAYED for this view (accumulated client-side while
3194
+ * playback runs, scaled by speed), not the furthest offset reached.
3195
+ * Floored to the 15s heartbeat cadence and clamped by the service,
3196
+ * which is monotonic and writes nothing when the value does not
3197
+ * advance, so a chatty client costs at most one UPDATE per 15
3198
+ * seconds watched without any server-side timer or cross-pod
3199
+ * throttle state.
2712
3200
  */
2713
- const throttledSeconds = Math.floor(Math.max(0, secondsWatched) / 15) * 15;
3201
+ const throttledSeconds = normalizeSecondsWatched(secondsWatched);
2714
3202
  /*
2715
3203
  * secondsWatched is a privacy control, not telemetry: it is shown on
2716
3204
  * the player as "who watched how much of this recording". Scoping
@@ -2723,24 +3211,16 @@ router.post("/telemetry/rum/session-replay/heartbeat", ...requireSessionReplayPa
2723
3211
  * viewId belonging to anyone else matches nothing and is refused
2724
3212
  * indistinguishably from one that does not exist - and the
2725
3213
  * application it points at is authorized exactly as a payload read
2726
- * would be.
3214
+ * would be. That ONE lookup also carries the row's current figure,
3215
+ * so a heartbeat that does not advance it ends here with no write.
2727
3216
  */
2728
3217
  if (!databaseProps.userId) {
2729
3218
  return Response.sendErrorResponse(req, res, new NotAuthorizedException("You do not have access to this session replay view."));
2730
3219
  }
2731
- const view = await RumSessionReplayViewService.findOneBy({
2732
- query: {
2733
- _id: viewId.toString(),
2734
- projectId: projectId,
2735
- viewedByUserId: databaseProps.userId,
2736
- },
2737
- select: {
2738
- _id: true,
2739
- rumApplicationId: true,
2740
- },
2741
- props: {
2742
- isRoot: true,
2743
- },
3220
+ const view = await RumSessionReplayViewService.findOwnView({
3221
+ viewId: viewId,
3222
+ projectId: projectId,
3223
+ viewedByUserId: databaseProps.userId,
2744
3224
  });
2745
3225
  if (!view || !view.rumApplicationId) {
2746
3226
  return Response.sendErrorResponse(req, res, new NotAuthorizedException("You do not have access to this session replay view."));
@@ -2750,14 +3230,85 @@ router.post("/telemetry/rum/session-replay/heartbeat", ...requireSessionReplayPa
2750
3230
  rumApplicationId: view.rumApplicationId,
2751
3231
  databaseProps: databaseProps,
2752
3232
  permissions: SESSION_REPLAY_PAYLOAD_PERMISSIONS,
3233
+ allowCached: true,
2753
3234
  });
3235
+ const currentSecondsWatched = view.secondsWatched || 0;
2754
3236
  await RumSessionReplayViewService.recordSecondsWatched({
2755
3237
  viewId: viewId,
2756
3238
  projectId: projectId,
2757
3239
  secondsWatched: throttledSeconds,
3240
+ currentSecondsWatched: currentSecondsWatched,
2758
3241
  });
2759
3242
  return Response.sendJsonObjectResponse(req, res, {
2760
- secondsWatched: throttledSeconds,
3243
+ secondsWatched: Math.max(currentSecondsWatched, throttledSeconds),
3244
+ });
3245
+ }
3246
+ catch (err) {
3247
+ next(err);
3248
+ }
3249
+ });
3250
+ // --- Session Replay Views Endpoint ---
3251
+ /*
3252
+ * Who has watched this recording. The audit table has been written on
3253
+ * every manifest read since the feature shipped and nothing surfaced it;
3254
+ * the player header now can. Payload permission, because the list of
3255
+ * viewers is a fact about a recording of a real person and belongs to
3256
+ * the people who may watch it. Pinned to the application the session was
3257
+ * authorized under: sessionId is only unique within an application.
3258
+ */
3259
+ const MAX_SESSION_REPLAY_VIEWS_LIMIT = 50;
3260
+ router.post("/telemetry/rum/session-replay/views", ...requireSessionReplayPayloadAccess, async (req, res, next) => {
3261
+ try {
3262
+ const databaseProps = await CommonAPI.getDatabaseCommonInteractionProps(req);
3263
+ if (!(databaseProps === null || databaseProps === void 0 ? void 0 : databaseProps.tenantId)) {
3264
+ return Response.sendErrorResponse(req, res, new BadDataException("Invalid Project ID"));
3265
+ }
3266
+ assertSessionReplayPlan(databaseProps);
3267
+ const projectId = databaseProps.tenantId;
3268
+ const body = req.body;
3269
+ const sessionId = readSessionIdFromBody(body);
3270
+ const authorized = await resolveAuthorizedSession({
3271
+ projectId: projectId,
3272
+ sessionId: sessionId,
3273
+ databaseProps: databaseProps,
3274
+ rumApplicationId: readOptionalObjectIdFromBody(body, "rumApplicationId"),
3275
+ allowCached: true,
3276
+ });
3277
+ const views = await RumSessionReplayViewService.getViewsForSession({
3278
+ projectId: projectId,
3279
+ rumApplicationId: new ObjectID(authorized.header.rumApplicationId),
3280
+ sessionId: sessionId,
3281
+ limit: readLimitFromBody(body, MAX_SESSION_REPLAY_VIEWS_LIMIT, MAX_SESSION_REPLAY_VIEWS_LIMIT),
3282
+ });
3283
+ return Response.sendJsonObjectResponse(req, res, {
3284
+ views: views.map((view) => {
3285
+ var _a;
3286
+ return {
3287
+ id: view.id ? view.id.toString() : null,
3288
+ viewedAt: view.viewedAt ? view.viewedAt.toISOString() : null,
3289
+ secondsWatched: (_a = view.secondsWatched) !== null && _a !== void 0 ? _a : 0,
3290
+ accessReason: view.accessReason || "",
3291
+ viewedByUserId: view.viewedByUserId
3292
+ ? view.viewedByUserId.toString()
3293
+ : null,
3294
+ viewedByUser: view.viewedByUser
3295
+ ? {
3296
+ id: view.viewedByUser.id
3297
+ ? view.viewedByUser.id.toString()
3298
+ : null,
3299
+ name: view.viewedByUser.name
3300
+ ? view.viewedByUser.name.toString()
3301
+ : "",
3302
+ email: view.viewedByUser.email
3303
+ ? view.viewedByUser.email.toString()
3304
+ : "",
3305
+ profilePictureId: view.viewedByUser.profilePictureId
3306
+ ? view.viewedByUser.profilePictureId.toString()
3307
+ : null,
3308
+ }
3309
+ : null,
3310
+ };
3311
+ }),
2761
3312
  });
2762
3313
  }
2763
3314
  catch (err) {
@@ -2788,15 +3339,34 @@ router.post("/telemetry/rum/session-replay/for-exception", ...requireSessionRepl
2788
3339
  databaseProps: databaseProps,
2789
3340
  permissions: SESSION_REPLAY_LIST_PERMISSIONS,
2790
3341
  });
2791
- const startTime = body["startTime"]
2792
- ? OneUptimeDate.fromString(body["startTime"])
2793
- : undefined;
2794
- const endTime = body["endTime"]
2795
- ? OneUptimeDate.fromString(body["endTime"])
2796
- : undefined;
2797
- const sessions = await SessionReplayReadService.getSessionsForException(Object.assign(Object.assign(Object.assign({ projectId: projectId, exceptionFingerprint: fingerprint, accessibleRumApplicationIds: accessibleApplications.applicationIds }, (startTime !== undefined && { startTime })), (endTime !== undefined && { endTime })), { limit: typeof body["limit"] === "number"
2798
- ? body["limit"]
2799
- : MAX_SESSION_REPLAY_FOR_EXCEPTION_LIMIT }));
3342
+ let startTime = readOptionalDateFromBody(body, "startTime");
3343
+ let endTime = readOptionalDateFromBody(body, "endTime");
3344
+ /*
3345
+ * The exception page knows WHEN the error happened. A session that
3346
+ * contains that moment started at most one maximum session length
3347
+ * before it (plus skew padding), so the window is derived from the
3348
+ * moment rather than left to the 30-day default - a fraction of
3349
+ * the partitions, and the card finds the session of THIS instance
3350
+ * rather than the newest session that ever hit the fingerprint.
3351
+ */
3352
+ const rawErrorTime = body["errorTimeUnixMs"];
3353
+ if (startTime === undefined &&
3354
+ endTime === undefined &&
3355
+ typeof rawErrorTime === "number" &&
3356
+ Number.isFinite(rawErrorTime) &&
3357
+ rawErrorTime > 0) {
3358
+ startTime = new Date(rawErrorTime -
3359
+ SESSION_REPLAY_MAX_SESSION_MS -
3360
+ SESSION_REPLAY_EXCEPTION_WINDOW_PADDING_MS);
3361
+ endTime = new Date(rawErrorTime + SESSION_REPLAY_EXCEPTION_WINDOW_PADDING_MS);
3362
+ }
3363
+ if (startTime && endTime && startTime.getTime() > endTime.getTime()) {
3364
+ return Response.sendErrorResponse(req, res, new BadDataException("startTime must not be after endTime"));
3365
+ }
3366
+ /* Pin to the session the caller already knows threw, when it does. */
3367
+ const pinnedSessionId = body["sessionId"];
3368
+ const sessions = await SessionReplayReadService.getSessionsForException(Object.assign(Object.assign(Object.assign(Object.assign({ projectId: projectId, exceptionFingerprint: fingerprint, accessibleRumApplicationIds: accessibleApplications.applicationIds }, (startTime !== undefined && { startTime })), (endTime !== undefined && { endTime })), (typeof pinnedSessionId === "string" &&
3369
+ pinnedSessionId.length > 0 && { sessionId: pinnedSessionId })), { limit: readLimitFromBody(body, MAX_SESSION_REPLAY_FOR_EXCEPTION_LIMIT, MAX_SESSION_REPLAY_FOR_EXCEPTION_LIMIT) }));
2800
3370
  return Response.sendJsonObjectResponse(req, res, {
2801
3371
  sessions: sessions,
2802
3372
  /*
@@ -2863,9 +3433,20 @@ router.post("/telemetry/rum/session-replay/ingest-status", ...requireSessionRepl
2863
3433
  sessionReplayAllowedOrigins: true,
2864
3434
  sessionReplaySamplePercentage: true,
2865
3435
  sessionReplayCaptureTrigger: true,
3436
+ sessionReplayConsentMode: true,
3437
+ sessionReplayMaskingMode: true,
3438
+ sessionReplayRetentionInDays: true,
2866
3439
  sessionReplayMonthlyBudgetInGB: true,
2867
3440
  sessionReplayLastChunkReceivedAt: true,
2868
3441
  sessionReplayBudgetExceededAt: true,
3442
+ /*
3443
+ * Stamped by the /config route on every recorder load (through
3444
+ * the throttled updateLastSeen path), so this is "when did the
3445
+ * recorder last run on the customer's site" - the fact that
3446
+ * separates "never installed" from "installed but uploading
3447
+ * nothing".
3448
+ */
3449
+ lastSeenAt: true,
2869
3450
  },
2870
3451
  props: {
2871
3452
  isRoot: true,
@@ -2885,12 +3466,36 @@ router.post("/telemetry/rum/session-replay/ingest-status", ...requireSessionRepl
2885
3466
  isRoot: true,
2886
3467
  },
2887
3468
  });
2888
- const [projectBytesUsedToday, applicationBytesUsedThisMonth] = await Promise.all([
3469
+ const appIdentifier = String(application["appIdentifier"] || "");
3470
+ /*
3471
+ * Every counter below is independent and every one answers null on
3472
+ * its own failure: the Redis-backed ones when Redis is down, the
3473
+ * ClickHouse-backed summary when the query fails. null is rendered
3474
+ * as "unknown", never as 0 - "nothing was refused" and "we could
3475
+ * not count" are different diagnoses.
3476
+ */
3477
+ const [projectBytesUsedToday, applicationBytesUsedThisMonth, refusalsLast24h, dropsLast24h, activity,] = await Promise.all([
2889
3478
  SessionReplayUsage.getProjectBytesUsedToday(projectId),
2890
3479
  SessionReplayUsage.getApplicationBytesUsedThisMonth({
2891
3480
  projectId: projectId,
2892
3481
  rumApplicationId: rumApplicationId,
2893
3482
  }),
3483
+ appIdentifier
3484
+ ? SessionReplayHealthCounters.readRefusalsLast24h({
3485
+ projectId: projectId,
3486
+ appIdentifier: appIdentifier,
3487
+ })
3488
+ : Promise.resolve(null),
3489
+ appIdentifier
3490
+ ? SessionReplayHealthCounters.readDropsLast24h({
3491
+ projectId: projectId,
3492
+ appIdentifier: appIdentifier,
3493
+ })
3494
+ : Promise.resolve(null),
3495
+ SessionReplayReadService.getApplicationActivitySummary({
3496
+ projectId: projectId,
3497
+ rumApplicationId: rumApplicationId,
3498
+ }),
2894
3499
  ]);
2895
3500
  /*
2896
3501
  * Same env var, same default, as the value the ingest gate enforces
@@ -2902,10 +3507,23 @@ router.post("/telemetry/rum/session-replay/ingest-status", ...requireSessionRepl
2902
3507
  ? dailyCapEnv
2903
3508
  : DEFAULT_SESSION_REPLAY_MAX_BYTES_PER_PROJECT_PER_DAY;
2904
3509
  const applicationView = application;
3510
+ const toIsoOrNull = (value) => {
3511
+ if (value instanceof Date) {
3512
+ return Number.isFinite(value.getTime()) ? value.toISOString() : null;
3513
+ }
3514
+ if (typeof value === "string" && value.length > 0) {
3515
+ const parsed = Date.parse(value);
3516
+ return Number.isFinite(parsed)
3517
+ ? new Date(parsed).toISOString()
3518
+ : null;
3519
+ }
3520
+ return null;
3521
+ };
3522
+ const retentionInDays = applicationView["sessionReplayRetentionInDays"];
2905
3523
  return Response.sendJsonObjectResponse(req, res, {
2906
3524
  isProjectAllowed: Boolean(project === null || project === void 0 ? void 0 : project["isSessionReplayAllowed"]),
2907
3525
  isApplicationEnabled: Boolean(applicationView["isSessionReplayEnabled"]),
2908
- appIdentifier: String(applicationView["appIdentifier"] || ""),
3526
+ appIdentifier: appIdentifier,
2909
3527
  allowedOrigins: (applicationView["sessionReplayAllowedOrigins"] ||
2910
3528
  []),
2911
3529
  samplePercentage: Number(applicationView["sessionReplaySamplePercentage"] || 0),
@@ -2918,6 +3536,48 @@ router.post("/telemetry/rum/session-replay/ingest-status", ...requireSessionRepl
2918
3536
  dailyByteLimit: dailyByteLimit,
2919
3537
  applicationBytesUsedThisMonth: applicationBytesUsedThisMonth,
2920
3538
  monthlyBudgetInGB: (_a = applicationView["sessionReplayMonthlyBudgetInGB"]) !== null && _a !== void 0 ? _a : null,
3539
+ /*
3540
+ * ---- Additive: the rest of RecordingHealthStatus. ----
3541
+ * Every timestamp is ISO-8601 or null; every counter is a number
3542
+ * or null (unknown). The Dashboard parses this with
3543
+ * parseRecordingHealthStatus and diagnoses it with
3544
+ * diagnoseRecordingHealth.
3545
+ */
3546
+ consentMode: String(applicationView["sessionReplayConsentMode"] || ""),
3547
+ maskingMode: String(applicationView["sessionReplayMaskingMode"] || ""),
3548
+ retentionInDays: typeof retentionInDays === "number" &&
3549
+ Number.isFinite(retentionInDays)
3550
+ ? retentionInDays
3551
+ : null,
3552
+ publishedRecorderVersion: SessionReplayReadService.getPublishedRecorderVersion(),
3553
+ lastConfigFetchAt: toIsoOrNull(applicationView["lastSeenAt"]),
3554
+ lastSessionStartedAt: activity.lastSessionStartedAt
3555
+ ? activity.lastSessionStartedAt.toISOString()
3556
+ : null,
3557
+ sessionsLast24h: activity.sessionsLast24h,
3558
+ playableSessionsLast24h: activity.playableSessionsLast24h,
3559
+ /*
3560
+ * What the newest session's recorder said it could capture.
3561
+ *
3562
+ * This is the row the docs point operators at for spotting a stale
3563
+ * cached recorder artifact ("click labels: no"); without it the
3564
+ * health card and the installation test both said "not reported
3565
+ * yet" for every application forever, which reads as a bug rather
3566
+ * than as information. null (not []) when there is no session, when
3567
+ * the newest one predates the attribute, or when the query failed -
3568
+ * all three are "we cannot say", never "this recorder can do
3569
+ * nothing". It rides on the last-session query the summary already
3570
+ * runs, so the row costs no extra ClickHouse round trip.
3571
+ */
3572
+ recorderCapabilities: activity.recorderCapabilities,
3573
+ refusalsLast24h: refusalsLast24h,
3574
+ /*
3575
+ * Kept apart from refusals: a refusal was answered to the
3576
+ * recorder, a drop happened after a 202 inside the worker. "12
3577
+ * chunks dropped after acceptance: scrub-incomplete" is a
3578
+ * different sentence from "212 uploads refused".
3579
+ */
3580
+ dropsLast24h: dropsLast24h,
2921
3581
  });
2922
3582
  }
2923
3583
  catch (err) {