@oneuptime/common 12.0.33 → 12.0.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (652) 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/IncidentCustomField.ts +77 -3
  6. package/Models/DatabaseModels/InventoryItemCustomField.ts +77 -3
  7. package/Models/DatabaseModels/MonitorCustomField.ts +77 -3
  8. package/Models/DatabaseModels/OnCallDutyPolicyCustomField.ts +77 -3
  9. package/Models/DatabaseModels/RumApplication.ts +6 -6
  10. package/Models/DatabaseModels/ScheduledMaintenanceCustomField.ts +77 -3
  11. package/Models/DatabaseModels/StatusPageCustomField.ts +77 -3
  12. package/Models/DatabaseModels/TeamCustomField.ts +77 -3
  13. package/Models/DatabaseModels/TeamMember.ts +0 -9
  14. package/Models/DatabaseModels/TeamMemberCustomField.ts +77 -3
  15. package/Models/DatabaseModels/TeamPermission.ts +3 -24
  16. package/Models/DatabaseModels/TelemetryIngestionKey.ts +260 -0
  17. package/Models/DatabaseModels/UserTelegram.ts +0 -4
  18. package/Scripts/benchmark-fanin-capacity.js +181 -0
  19. package/Server/API/TelemetryAPI.ts +1284 -164
  20. package/Server/API/UserNotificationSettingAPI.ts +55 -0
  21. package/Server/API/UserTelegramAPI.ts +48 -4
  22. package/Server/EnvironmentConfig.ts +35 -2
  23. package/Server/Infrastructure/Postgres/SchemaMigrations/1791300000000-AddTelemetryIngestionKeyType.ts +91 -0
  24. package/Server/Infrastructure/Postgres/SchemaMigrations/1791400000000-SessionReplayRecordEverySessionByDefault.ts +67 -0
  25. package/Server/Infrastructure/Postgres/SchemaMigrations/1791500000000-WidenCustomFieldDropdownOptions.ts +139 -0
  26. package/Server/Infrastructure/Postgres/SchemaMigrations/1791600000000-AddCustomFieldValueMapping.ts +121 -0
  27. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
  28. package/Server/Infrastructure/QueueWorker.ts +20 -14
  29. package/Server/Infrastructure/Semaphore.ts +2 -0
  30. package/Server/Middleware/TelemetryIngest.ts +453 -7
  31. package/Server/Services/AccessTokenService.ts +1 -0
  32. package/Server/Services/AlertCustomFieldService.ts +98 -0
  33. package/Server/Services/AlertService.ts +37 -0
  34. package/Server/Services/ApiKeyPermissionService.ts +461 -29
  35. package/Server/Services/CustomFieldMappingService.ts +879 -0
  36. package/Server/Services/GlobalConfigService.ts +194 -0
  37. package/Server/Services/IncidentCustomFieldService.ts +98 -0
  38. package/Server/Services/IncidentService.ts +35 -0
  39. package/Server/Services/MetricService.ts +194 -0
  40. package/Server/Services/MonitorService.ts +32 -0
  41. package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +78 -25
  42. package/Server/Services/ProjectService.ts +22 -0
  43. package/Server/Services/RoutineEmailSettingsService.ts +73 -0
  44. package/Server/Services/RumSessionReplayViewService.ts +104 -24
  45. package/Server/Services/ScheduledMaintenanceCustomFieldService.ts +98 -0
  46. package/Server/Services/ScheduledMaintenanceService.ts +32 -0
  47. package/Server/Services/TeamMemberService.ts +78 -0
  48. package/Server/Services/TeamPermissionService.ts +235 -3
  49. package/Server/Services/TelemetryIngestionKeyService.ts +722 -19
  50. package/Server/Services/UserNotificationSettingService.ts +34 -6
  51. package/Server/Services/UserTelegramService.ts +326 -5
  52. package/Server/Types/Database/QueryHelper.ts +2 -0
  53. package/Server/Utils/APIKey/AccessPermission.ts +5 -2
  54. package/Server/Utils/CustomField/CustomFieldDefinitionMappingHooks.ts +54 -0
  55. package/Server/Utils/CustomField/CustomFieldMappingRegistry.ts +415 -0
  56. package/Server/Utils/CustomField/CustomFieldMappingValidator.ts +335 -0
  57. package/Server/Utils/DataSource/EgressGuard.ts +177 -8
  58. package/Server/Utils/EmailRollup/EmailRollupConstants.ts +38 -5
  59. package/Server/Utils/EmailRollup/EmailRollupFlushRunner.ts +57 -4
  60. package/Server/Utils/FrontendEnvironment.ts +40 -0
  61. package/Server/Utils/LogRedaction.ts +20 -0
  62. package/Server/Utils/Logger.ts +11 -0
  63. package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +338 -77
  64. package/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.ts +30 -4
  65. package/Server/Utils/Monitor/MonitorAlert.ts +29 -6
  66. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +110 -15
  67. package/Server/Utils/Monitor/MonitorIncident.ts +22 -6
  68. package/Server/Utils/Monitor/MonitorTemplateUtil.ts +29 -0
  69. package/Server/Utils/Monitor/SeriesContextEnricher.ts +304 -0
  70. package/Server/Utils/SSRFProtection.ts +217 -10
  71. package/Server/Utils/SessionReplay/SessionReplayGateCache.ts +239 -138
  72. package/Server/Utils/SessionReplay/SessionReplayHealthCounters.ts +305 -0
  73. package/Server/Utils/SessionReplay/SessionReplayReadService.ts +1430 -289
  74. package/Server/Utils/StartServer.ts +2 -17
  75. package/Server/Utils/TelegramVerificationToken.ts +185 -0
  76. package/Server/Utils/Telemetry/PinServiceName.ts +197 -0
  77. package/Server/Utils/Telemetry/TelemetryFanInWriter.ts +38 -16
  78. package/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.ts +92 -0
  79. package/Server/Utils/Telemetry/TelemetryIngestionKeyRateLimiter.ts +217 -0
  80. package/Server/Utils/VM/VMAPI.ts +1 -0
  81. package/Server/Utils/VM/VMRunner.ts +975 -95
  82. package/Tests/App/AdminDashboard/AdminHeaderSmallScreens.test.tsx +202 -0
  83. package/Tests/App/Dashboard/DashboardHeaderSmallScreens.test.tsx +404 -0
  84. package/Tests/App/Dashboard/DiscoveryScanWizardValidation.test.tsx +468 -0
  85. package/Tests/App/Dashboard/NotificationEmailPreferences.test.tsx +399 -0
  86. package/Tests/App/StatusPage/StatusPageLastUpdated.test.tsx +263 -0
  87. package/Tests/App/StatusPage/StatusPageOverviewLiveAndSearch.test.tsx +753 -0
  88. package/Tests/App/StatusPage/StatusPageResourceSearchBox.test.tsx +224 -0
  89. package/Tests/Models/AnalyticsModels/RumSessionReplayColumns.test.ts +262 -0
  90. package/Tests/Models/CustomFieldMappingColumns.test.ts +166 -0
  91. package/Tests/Models/DatabaseModels/SessionReplayModels.test.ts +20 -6
  92. package/Tests/ResponsiveVisibility.test.ts +115 -0
  93. package/Tests/ResponsiveVisibility.ts +183 -0
  94. package/Tests/Server/API/SessionReplayAPI.test.ts +1940 -216
  95. package/Tests/Server/API/UserNotificationSettingAPI.test.ts +186 -0
  96. package/Tests/Server/API/UserTelegramAPISecurity.test.ts +231 -0
  97. package/Tests/Server/EnvironmentConfigFrontendSecurity.test.ts +234 -0
  98. package/Tests/Server/Infrastructure/Postgres/CustomFieldValueMappingMigration.test.ts +202 -0
  99. package/Tests/Server/Infrastructure/Postgres/InventoryItemArchiveMigration.test.ts +41 -0
  100. package/Tests/Server/Infrastructure/Postgres/SessionReplayRecordEverySessionByDefaultMigration.test.ts +169 -0
  101. package/Tests/Server/Infrastructure/QueueWorkerTimeout.test.ts +210 -0
  102. package/Tests/Server/Infrastructure/TelemetryExporterDeploymentConfig.test.ts +130 -0
  103. package/Tests/Server/Middleware/ProjectAuthorizationApiKeyMiddleware.test.ts +4 -1
  104. package/Tests/Server/Middleware/TelemetryIngestBrowserKey.test.ts +1163 -0
  105. package/Tests/Server/Middleware/TelemetryIngestTokenLog.test.ts +5 -3
  106. package/Tests/Server/Services/AddTelemetryIngestionKeyTypeMigration.test.ts +555 -0
  107. package/Tests/Server/Services/ApiKeyPermissionSecurity.test.ts +678 -0
  108. package/Tests/Server/Services/ApiKeyPermissionService.test.ts +276 -28
  109. package/Tests/Server/Services/CustomFieldDropdownOptionsColumnWidth.test.ts +431 -0
  110. package/Tests/Server/Services/CustomFieldMappingService.test.ts +850 -0
  111. package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +32 -0
  112. package/Tests/Server/Services/GlobalConfigService.test.ts +414 -1
  113. package/Tests/Server/Services/MetricRawEntityKeyPrune.test.ts +592 -0
  114. package/Tests/Server/Services/NetworkDeviceAutoImportRuleEngineService.test.ts +226 -1
  115. package/Tests/Server/Services/RoutineEmailSettingsPostgres.test.ts +329 -0
  116. package/Tests/Server/Services/RumSessionReplayViewService.test.ts +267 -0
  117. package/Tests/Server/Services/TeamMemberAutoAcceptInvitation.test.ts +9 -0
  118. package/Tests/Server/Services/TeamMemberInviteRegistrationToken.test.ts +9 -0
  119. package/Tests/Server/Services/TeamPrivilegeEscalation.test.ts +834 -0
  120. package/Tests/Server/Services/TelemetryIngestionKeyPolicyResolution.test.ts +814 -0
  121. package/Tests/Server/Services/TelemetryIngestionKeyValidation.test.ts +998 -0
  122. package/Tests/Server/Services/UserNotificationSettingRollupRouting.test.ts +141 -0
  123. package/Tests/Server/Services/UserNotificationSettingWorkspaceChannels.test.ts +18 -10
  124. package/Tests/Server/Services/UserTelegramVerificationSecurity.test.ts +688 -0
  125. package/Tests/Server/Utils/AI/SRE/Insights/FixRouting.test.ts +497 -0
  126. package/Tests/Server/Utils/AI/Toolbox/Serializer.test.ts +383 -0
  127. package/Tests/Server/Utils/APIKey/AccessPermission.test.ts +7 -3
  128. package/Tests/Server/Utils/AnalyticsDatabase/ClusterConfig.test.ts +315 -0
  129. package/Tests/Server/Utils/CustomField/CustomFieldMappingValidator.test.ts +437 -0
  130. package/Tests/Server/Utils/DataSource/EgressGuard.test.ts +300 -11
  131. package/Tests/Server/Utils/EmailRollup/EmailRollupBurstWindow.test.ts +83 -0
  132. package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerBehaviour.test.ts +1 -1
  133. package/Tests/Server/Utils/EmailRollup/EmailRollupFlushRunnerPreferences.test.ts +362 -0
  134. package/Tests/Server/Utils/EmailRollup/EmailRollupTestHarness.ts +77 -1
  135. package/Tests/Server/Utils/FrontendEnvironment.test.ts +190 -0
  136. package/Tests/Server/Utils/LogRedaction.test.ts +26 -0
  137. package/Tests/Server/Utils/LoggerCredentialLeak.test.ts +23 -9
  138. package/Tests/Server/Utils/Monitor/Criteria/CompareCriteriaAggregation.test.ts +584 -0
  139. package/Tests/Server/Utils/Monitor/Criteria/IncomingRequestHeaderCriteria.test.ts +236 -0
  140. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +437 -0
  141. package/Tests/Server/Utils/Monitor/MonitorTemplateUtilSeriesContext.test.ts +176 -0
  142. package/Tests/Server/Utils/Monitor/SeriesContextEnricher.test.ts +356 -0
  143. package/Tests/Server/Utils/SSRFProtectionCloudServiceAddresses.test.ts +595 -0
  144. package/Tests/Server/Utils/SessionReplay/SessionReplayGateCachePolicy.test.ts +198 -1
  145. package/Tests/Server/Utils/SessionReplay/SessionReplayHealthCounters.test.ts +453 -0
  146. package/Tests/Server/Utils/SessionReplay/SessionReplayReadServiceQueries.test.ts +1378 -0
  147. package/Tests/Server/Utils/SessionReplayOriginAllowListRefactor.test.ts +420 -0
  148. package/Tests/Server/Utils/TelegramVerificationToken.test.ts +253 -0
  149. package/Tests/Server/Utils/Telemetry/PinServiceName.test.ts +666 -0
  150. package/Tests/Server/Utils/Telemetry/TelemetryFanInWriterCapacity.test.ts +458 -0
  151. package/Tests/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.test.ts +424 -0
  152. package/Tests/Server/Utils/Telemetry/TelemetryIngestionKeyRateLimiter.test.ts +528 -0
  153. package/Tests/Server/Utils/TelemetryExporterEnvironment.test.ts +56 -0
  154. package/Tests/Server/Utils/VM/VMRunnerHostBridgeLatency.test.ts +74 -0
  155. package/Tests/Server/Utils/VM/VMRunnerPrivateNetworkWiring.test.ts +100 -7
  156. package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +1176 -6
  157. package/Tests/Types/CustomField/CustomFieldMappingCatalog.test.ts +220 -0
  158. package/Tests/Types/CustomField/CustomFieldValueMapping.test.ts +348 -0
  159. package/Tests/Types/JSONFunctions.test.ts +260 -0
  160. package/Tests/Types/Monitor/CephAlertTemplates.test.ts +422 -53
  161. package/Tests/Types/Monitor/DockerAlertTemplates.test.ts +495 -15
  162. package/Tests/Types/Monitor/DockerSwarmAlertTemplates.test.ts +191 -45
  163. package/Tests/Types/Monitor/HostAlertTemplates.test.ts +370 -42
  164. package/Tests/Types/Monitor/IotAlertTemplates.test.ts +375 -20
  165. package/Tests/Types/Monitor/KubernetesAlertTemplates.test.ts +636 -42
  166. package/Tests/Types/Monitor/KubernetesMetricCatalog.test.ts +189 -0
  167. package/Tests/Types/Monitor/KubernetesTemplateGroupByKeys.test.ts +95 -14
  168. package/Tests/Types/Monitor/PodmanAlertTemplates.test.ts +190 -21
  169. package/Tests/Types/Monitor/ProxmoxAlertTemplates.test.ts +352 -22
  170. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationAlertDebuggability.test.ts +363 -0
  171. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +93 -18
  172. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.test.ts +259 -0
  173. package/Tests/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.test.ts +476 -0
  174. package/Tests/Types/Monitor/RumAlertTemplates.test.ts +136 -0
  175. package/Tests/Types/Monitor/SeriesContext/SeriesDebugHints.test.ts +661 -0
  176. package/Tests/Types/Monitor/SeriesContext/SeriesLabelDisplay.test.ts +507 -0
  177. package/Tests/Types/Monitor/ServiceAlertTemplates.test.ts +270 -0
  178. package/Tests/Types/Monitor/TemplateGroupByKeys.test.ts +38 -10
  179. package/Tests/Types/Monitor/Utils/RecommendationCriteriaAssertions.ts +102 -0
  180. package/Tests/Types/NotificationSetting/RoutineEmailEvents.test.ts +47 -0
  181. package/Tests/Types/Rum/SessionReplayApiContracts.test.ts +608 -0
  182. package/Tests/Types/Rum/SessionReplayCustomEvents.test.ts +434 -0
  183. package/Tests/Types/WebsiteRequest.test.ts +285 -3
  184. package/Tests/UI/Components/Charts/ChartBucketIdentity.test.ts +16 -3
  185. package/Tests/UI/Components/Charts/ChartTrailingBucketGap.test.ts +691 -0
  186. package/Tests/UI/Components/ComponentsModal.test.tsx +12 -4
  187. package/Tests/UI/Components/ComponentsModalUsability.test.tsx +518 -0
  188. package/Tests/UI/Components/CustomFields/CustomFieldsDetailMapping.test.tsx +324 -0
  189. package/Tests/UI/Components/CustomFields/MapFromCustomFieldInput.test.tsx +176 -0
  190. package/Tests/UI/Components/Graphs/DayUptimeGraph.test.tsx +484 -0
  191. package/Tests/UI/Components/HeaderRightRail.test.tsx +157 -0
  192. package/Tests/UI/Components/IconDropdownItem.test.tsx +102 -0
  193. package/Tests/UI/Components/JSONTablePrototypePollution.test.tsx +117 -0
  194. package/Tests/UI/Components/KeyboardShortcutsModal.test.tsx +214 -0
  195. package/Tests/UI/Components/ModelTable/ModelTableWrapContent.test.tsx +561 -0
  196. package/Tests/UI/Components/MonitorGraphs/UptimeBarDayModal.test.tsx +302 -0
  197. package/Tests/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.test.ts +28 -12
  198. package/Tests/UI/Components/ShortcutDialogGuard.test.tsx +74 -0
  199. package/Tests/UI/Components/StatusPage/ResourceGroupSectionAutoExpand.test.tsx +248 -0
  200. package/Tests/UI/Components/TableCellWrapping.test.tsx +625 -0
  201. package/Tests/UI/Components/TableLoadingStates.test.tsx +205 -0
  202. package/Tests/UI/Components/Workflow/NodePlacement.test.ts +148 -0
  203. package/Tests/UI/Components/Workflow/Workflow.test.tsx +981 -0
  204. package/Tests/UI/ConfigBrowserTelemetry.test.ts +70 -0
  205. package/Tests/UI/Rum/ChunkLoader.test.ts +1036 -2
  206. package/Tests/UI/Rum/FidelityNotices.test.ts +187 -0
  207. package/Tests/UI/Rum/InactivityMap.test.ts +341 -0
  208. package/Tests/UI/Rum/PrivacySummaryCard.test.tsx +259 -0
  209. package/Tests/UI/Rum/RecordingHealthCard.test.tsx +855 -0
  210. package/Tests/UI/Rum/RecordingHealthStrip.test.tsx +594 -0
  211. package/Tests/UI/Rum/ReplayCard.test.tsx +451 -0
  212. package/Tests/UI/Rum/ReplayCorrelationPanel.test.tsx +536 -0
  213. package/Tests/UI/Rum/ReplayEngine.test.ts +2503 -0
  214. package/Tests/UI/Rum/ReplayEngineTypes.test.ts +171 -0
  215. package/Tests/UI/Rum/ReplayHeader.test.tsx +711 -0
  216. package/Tests/UI/Rum/ReplayLink.test.tsx +119 -0
  217. package/Tests/UI/Rum/ReplayPinControl.test.tsx +408 -0
  218. package/Tests/UI/Rum/ReplayPlaybackIntent.test.ts +152 -0
  219. package/Tests/UI/Rum/ReplayRail.test.tsx +1296 -0
  220. package/Tests/UI/Rum/ReplayRailDetail.test.tsx +900 -0
  221. package/Tests/UI/Rum/ReplayScrubber.test.tsx +763 -147
  222. package/Tests/UI/Rum/ReplaySignalTypes.test.ts +189 -0
  223. package/Tests/UI/Rum/ReplaySignals.test.ts +1579 -0
  224. package/Tests/UI/Rum/ReplayStage.test.tsx +396 -473
  225. package/Tests/UI/Rum/ReplayStageOverlays.test.tsx +918 -0
  226. package/Tests/UI/Rum/ReplayTimeline.test.tsx +696 -0
  227. package/Tests/UI/Rum/SessionReplayEmptyState.test.tsx +499 -0
  228. package/Tests/UI/Rum/SessionReplaySearchBar.test.tsx +346 -0
  229. package/Tests/UI/Rum/SessionReplaySetupGuide.test.tsx +545 -0
  230. package/Tests/UI/Rum/SessionReplayTable.test.tsx +991 -0
  231. package/Tests/UI/Rum/TargetedCapturePanel.test.tsx +254 -0
  232. package/Tests/UI/Telemetry/BrowserExporterIsolation.test.ts +71 -0
  233. package/Tests/UI/Utils/GlobalKeyboardShortcut.test.ts +344 -0
  234. package/Tests/Utils/API.test.ts +308 -0
  235. package/Tests/Utils/HTTPResponseBodyReader.test.ts +323 -0
  236. package/Tests/Utils/NetworkDiscovery/DiscoveryScanStatus.test.ts +117 -0
  237. package/Tests/Utils/Rum/ChunkMath.test.ts +83 -0
  238. package/Tests/Utils/Rum/SessionReplayHealthDiagnosis.test.ts +993 -0
  239. package/Tests/Utils/Rum/SessionReplayStringMap.test.ts +245 -0
  240. package/Tests/Utils/StatusPage/ResourceSearch.test.ts +631 -0
  241. package/Tests/Utils/Telemetry/OriginAllowList.test.ts +633 -0
  242. package/Tests/Utils/Uptime/DayUptimeGraphUtil.test.ts +461 -0
  243. package/Tests/Utils/ValueFormatter.test.ts +148 -0
  244. package/Types/CustomField/CustomFieldMappingCatalog.ts +161 -0
  245. package/Types/CustomField/CustomFieldMappingSourceResource.ts +19 -0
  246. package/Types/CustomField/CustomFieldValueMapping.ts +288 -0
  247. package/Types/Icon/IconProp.ts +1 -0
  248. package/Types/JSONFunctions.ts +189 -43
  249. package/Types/Monitor/CephAlertTemplates.ts +157 -195
  250. package/Types/Monitor/DockerAlertTemplates.ts +338 -128
  251. package/Types/Monitor/DockerSwarmAlertTemplates.ts +95 -112
  252. package/Types/Monitor/HostAlertTemplates.ts +302 -130
  253. package/Types/Monitor/IotAlertTemplates.ts +112 -104
  254. package/Types/Monitor/KubernetesAlertTemplates.ts +415 -224
  255. package/Types/Monitor/KubernetesMetricCatalog.ts +23 -19
  256. package/Types/Monitor/PodmanAlertTemplates.ts +116 -163
  257. package/Types/Monitor/ProxmoxAlertTemplates.ts +217 -99
  258. package/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.ts +98 -6
  259. package/Types/Monitor/Recommendation/MonitorRecommendationUtil.ts +44 -7
  260. package/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.ts +383 -0
  261. package/Types/Monitor/RumAlertTemplates.ts +46 -7
  262. package/Types/Monitor/SeriesContext/SeriesDebugHints.ts +596 -0
  263. package/Types/Monitor/SeriesContext/SeriesLabelDisplay.ts +554 -0
  264. package/Types/Monitor/ServiceAlertTemplates.ts +98 -11
  265. package/Types/Monitor/UptimeHistoryLabels.ts +56 -0
  266. package/Types/NotificationSetting/RoutineEmailEvents.ts +30 -0
  267. package/Types/Rum/SessionReplay.ts +209 -0
  268. package/Types/Rum/SessionReplayApi.ts +722 -0
  269. package/Types/Rum/SessionReplayCaptureTrigger.ts +21 -12
  270. package/Types/Rum/SessionReplayConsentMode.ts +11 -7
  271. package/Types/Rum/SessionReplayCustomEvents.ts +549 -0
  272. package/Types/Rum/SessionReplayHealth.ts +238 -0
  273. package/Types/Telemetry/TelemetryIngestSurface.ts +95 -0
  274. package/Types/Telemetry/TelemetryIngestionKeyPolicy.ts +75 -0
  275. package/Types/Telemetry/TelemetryIngestionKeyType.ts +29 -0
  276. package/Types/WebsiteRequest.ts +85 -3
  277. package/UI/Components/Charts/Area/AreaChart.tsx +13 -2
  278. package/UI/Components/Charts/Bar/BarChart.tsx +6 -2
  279. package/UI/Components/Charts/Line/LineChart.tsx +13 -2
  280. package/UI/Components/Charts/Types/XAxis/XAxis.ts +29 -0
  281. package/UI/Components/Charts/Utils/DataPoint.ts +22 -3
  282. package/UI/Components/Charts/Utils/TimeAnnotation.ts +76 -9
  283. package/UI/Components/Charts/Utils/XAxis.ts +217 -0
  284. package/UI/Components/CustomFields/CustomFieldsDetail.tsx +143 -25
  285. package/UI/Components/CustomFields/MapFromCustomFieldInput.tsx +216 -0
  286. package/UI/Components/Graphs/DayUptimeGraph.tsx +173 -8
  287. package/UI/Components/Graphs/UptimeBarTooltip.tsx +22 -278
  288. package/UI/Components/Graphs/UptimeDaySummary.tsx +327 -0
  289. package/UI/Components/Header/Header.tsx +25 -9
  290. package/UI/Components/Header/IconDropdown/IconDropdownItem.tsx +10 -1
  291. package/UI/Components/Header/IconDropdown/IconDropdownMenu.tsx +6 -1
  292. package/UI/Components/Header/ProjectPicker/ProjectPicker.tsx +6 -1
  293. package/UI/Components/HeaderAlert/NotificationBell/NotificationBellDropdown.tsx +6 -1
  294. package/UI/Components/Icon/Icon.tsx +11 -0
  295. package/UI/Components/JSONTable/JSONTable.tsx +2 -2
  296. package/UI/Components/KeyboardShortcut/KeyboardShortcutsModal.tsx +125 -0
  297. package/UI/Components/KeyboardShortcut/Screenshots/README.md +19 -0
  298. package/UI/Components/KeyboardShortcut/Screenshots/keyboard-shortcuts-command-palette.png +0 -0
  299. package/UI/Components/KeyboardShortcut/Screenshots/keyboard-shortcuts-dialog-dark.png +0 -0
  300. package/UI/Components/KeyboardShortcut/Screenshots/keyboard-shortcuts-dialog.png +0 -0
  301. package/UI/Components/KeyboardShortcut/Screenshots/keyboard-shortcuts-help-menu.png +0 -0
  302. package/UI/Components/KeyboardShortcut/Screenshots/keyboard-shortcuts-narrow.png +0 -0
  303. package/UI/Components/ModelTable/Column.ts +15 -0
  304. package/UI/Components/Monitor/SeriesDebugCommandsViewer.tsx +64 -0
  305. package/UI/Components/Monitor/SeriesLabelsViewer.tsx +93 -0
  306. package/UI/Components/MonitorGraphs/Uptime.tsx +14 -2
  307. package/UI/Components/MonitorGraphs/UptimeBarDayModal.tsx +63 -10
  308. package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +44 -0
  309. package/UI/Components/StatusPage/ResourceGroupSection.tsx +40 -0
  310. package/UI/Components/Table/CellClassName.ts +81 -0
  311. package/UI/Components/Table/TableRow.tsx +20 -14
  312. package/UI/Components/Table/TableSkeletonRows.tsx +9 -9
  313. package/UI/Components/Table/Types/Column.ts +36 -0
  314. package/UI/Components/Tooltip/Tooltip.tsx +11 -1
  315. package/UI/Components/Workflow/ComponentsModal.tsx +60 -39
  316. package/UI/Components/Workflow/NodePlacement.ts +57 -0
  317. package/UI/Components/Workflow/Workflow.tsx +47 -18
  318. package/UI/Config.ts +15 -33
  319. package/UI/Utils/GlobalKeyboardShortcut.ts +208 -0
  320. package/UI/Utils/Telemetry/BrowserTelemetryConfig.ts +28 -0
  321. package/UI/Utils/Telemetry/Telemetry.ts +10 -8
  322. package/Utils/API.ts +129 -3
  323. package/Utils/HTTPResponseBodyReader.ts +221 -0
  324. package/Utils/NetworkDiscovery/DiscoveryScanStatus.ts +77 -0
  325. package/Utils/Rum/ChunkMath.ts +106 -0
  326. package/Utils/Rum/SessionReplayHealth.ts +732 -0
  327. package/Utils/Rum/SessionReplayStringMap.ts +226 -0
  328. package/Utils/Schema/ModelSchema.ts +1 -0
  329. package/Utils/StatusPage/ResourceSearch.ts +290 -0
  330. package/Utils/Telemetry/OriginAllowList.ts +355 -0
  331. package/Utils/Uptime/DayUptimeGraphUtil.ts +205 -0
  332. package/Utils/ValueFormatter.ts +35 -1
  333. package/build/dist/Models/AnalyticsModels/RumSession.js +102 -19
  334. package/build/dist/Models/AnalyticsModels/RumSession.js.map +1 -1
  335. package/build/dist/Models/AnalyticsModels/RumSessionChunk.js +11 -9
  336. package/build/dist/Models/AnalyticsModels/RumSessionChunk.js.map +1 -1
  337. package/build/dist/Models/DatabaseModels/AlertCustomField.js +79 -3
  338. package/build/dist/Models/DatabaseModels/AlertCustomField.js.map +1 -1
  339. package/build/dist/Models/DatabaseModels/ApiKeyPermission.js +3 -27
  340. package/build/dist/Models/DatabaseModels/ApiKeyPermission.js.map +1 -1
  341. package/build/dist/Models/DatabaseModels/IncidentCustomField.js +79 -3
  342. package/build/dist/Models/DatabaseModels/IncidentCustomField.js.map +1 -1
  343. package/build/dist/Models/DatabaseModels/InventoryItemCustomField.js +79 -3
  344. package/build/dist/Models/DatabaseModels/InventoryItemCustomField.js.map +1 -1
  345. package/build/dist/Models/DatabaseModels/MonitorCustomField.js +79 -3
  346. package/build/dist/Models/DatabaseModels/MonitorCustomField.js.map +1 -1
  347. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyCustomField.js +79 -3
  348. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyCustomField.js.map +1 -1
  349. package/build/dist/Models/DatabaseModels/RumApplication.js +6 -6
  350. package/build/dist/Models/DatabaseModels/RumApplication.js.map +1 -1
  351. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceCustomField.js +79 -3
  352. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceCustomField.js.map +1 -1
  353. package/build/dist/Models/DatabaseModels/StatusPageCustomField.js +79 -3
  354. package/build/dist/Models/DatabaseModels/StatusPageCustomField.js.map +1 -1
  355. package/build/dist/Models/DatabaseModels/TeamCustomField.js +79 -3
  356. package/build/dist/Models/DatabaseModels/TeamCustomField.js.map +1 -1
  357. package/build/dist/Models/DatabaseModels/TeamMember.js +0 -9
  358. package/build/dist/Models/DatabaseModels/TeamMember.js.map +1 -1
  359. package/build/dist/Models/DatabaseModels/TeamMemberCustomField.js +79 -3
  360. package/build/dist/Models/DatabaseModels/TeamMemberCustomField.js.map +1 -1
  361. package/build/dist/Models/DatabaseModels/TeamPermission.js +3 -24
  362. package/build/dist/Models/DatabaseModels/TeamPermission.js.map +1 -1
  363. package/build/dist/Models/DatabaseModels/TelemetryIngestionKey.js +267 -0
  364. package/build/dist/Models/DatabaseModels/TelemetryIngestionKey.js.map +1 -1
  365. package/build/dist/Models/DatabaseModels/UserTelegram.js +0 -4
  366. package/build/dist/Models/DatabaseModels/UserTelegram.js.map +1 -1
  367. package/build/dist/Server/API/TelemetryAPI.js +769 -109
  368. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  369. package/build/dist/Server/API/UserNotificationSettingAPI.js +35 -0
  370. package/build/dist/Server/API/UserNotificationSettingAPI.js.map +1 -0
  371. package/build/dist/Server/API/UserTelegramAPI.js +28 -6
  372. package/build/dist/Server/API/UserTelegramAPI.js.map +1 -1
  373. package/build/dist/Server/EnvironmentConfig.js +29 -2
  374. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  375. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791300000000-AddTelemetryIngestionKeyType.js +60 -0
  376. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791300000000-AddTelemetryIngestionKeyType.js.map +1 -0
  377. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791400000000-SessionReplayRecordEverySessionByDefault.js +53 -0
  378. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791400000000-SessionReplayRecordEverySessionByDefault.js.map +1 -0
  379. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791500000000-WidenCustomFieldDropdownOptions.js +82 -0
  380. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791500000000-WidenCustomFieldDropdownOptions.js.map +1 -0
  381. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791600000000-AddCustomFieldValueMapping.js +46 -0
  382. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1791600000000-AddCustomFieldValueMapping.js.map +1 -0
  383. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
  384. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  385. package/build/dist/Server/Infrastructure/QueueWorker.js +19 -7
  386. package/build/dist/Server/Infrastructure/QueueWorker.js.map +1 -1
  387. package/build/dist/Server/Infrastructure/Semaphore.js +1 -0
  388. package/build/dist/Server/Infrastructure/Semaphore.js.map +1 -1
  389. package/build/dist/Server/Middleware/TelemetryIngest.js +315 -8
  390. package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
  391. package/build/dist/Server/Services/AccessTokenService.js +1 -0
  392. package/build/dist/Server/Services/AccessTokenService.js.map +1 -1
  393. package/build/dist/Server/Services/AlertCustomFieldService.js +93 -0
  394. package/build/dist/Server/Services/AlertCustomFieldService.js.map +1 -1
  395. package/build/dist/Server/Services/AlertService.js +34 -0
  396. package/build/dist/Server/Services/AlertService.js.map +1 -1
  397. package/build/dist/Server/Services/ApiKeyPermissionService.js +331 -28
  398. package/build/dist/Server/Services/ApiKeyPermissionService.js.map +1 -1
  399. package/build/dist/Server/Services/CustomFieldMappingService.js +614 -0
  400. package/build/dist/Server/Services/CustomFieldMappingService.js.map +1 -0
  401. package/build/dist/Server/Services/GlobalConfigService.js +133 -0
  402. package/build/dist/Server/Services/GlobalConfigService.js.map +1 -1
  403. package/build/dist/Server/Services/IncidentCustomFieldService.js +93 -0
  404. package/build/dist/Server/Services/IncidentCustomFieldService.js.map +1 -1
  405. package/build/dist/Server/Services/IncidentService.js +32 -0
  406. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  407. package/build/dist/Server/Services/MetricService.js +163 -0
  408. package/build/dist/Server/Services/MetricService.js.map +1 -1
  409. package/build/dist/Server/Services/MonitorService.js +29 -0
  410. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  411. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +79 -27
  412. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -1
  413. package/build/dist/Server/Services/ProjectService.js +22 -0
  414. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  415. package/build/dist/Server/Services/RoutineEmailSettingsService.js +69 -0
  416. package/build/dist/Server/Services/RoutineEmailSettingsService.js.map +1 -0
  417. package/build/dist/Server/Services/RumSessionReplayViewService.js +86 -24
  418. package/build/dist/Server/Services/RumSessionReplayViewService.js.map +1 -1
  419. package/build/dist/Server/Services/ScheduledMaintenanceCustomFieldService.js +93 -0
  420. package/build/dist/Server/Services/ScheduledMaintenanceCustomFieldService.js.map +1 -1
  421. package/build/dist/Server/Services/ScheduledMaintenanceService.js +29 -0
  422. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  423. package/build/dist/Server/Services/TeamMemberService.js +62 -2
  424. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  425. package/build/dist/Server/Services/TeamPermissionService.js +166 -3
  426. package/build/dist/Server/Services/TeamPermissionService.js.map +1 -1
  427. package/build/dist/Server/Services/TelemetryIngestionKeyService.js +562 -18
  428. package/build/dist/Server/Services/TelemetryIngestionKeyService.js.map +1 -1
  429. package/build/dist/Server/Services/UserNotificationSettingService.js +26 -6
  430. package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
  431. package/build/dist/Server/Services/UserTelegramService.js +257 -4
  432. package/build/dist/Server/Services/UserTelegramService.js.map +1 -1
  433. package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
  434. package/build/dist/Server/Utils/APIKey/AccessPermission.js +2 -2
  435. package/build/dist/Server/Utils/APIKey/AccessPermission.js.map +1 -1
  436. package/build/dist/Server/Utils/CustomField/CustomFieldDefinitionMappingHooks.js +27 -0
  437. package/build/dist/Server/Utils/CustomField/CustomFieldDefinitionMappingHooks.js.map +1 -0
  438. package/build/dist/Server/Utils/CustomField/CustomFieldMappingRegistry.js +226 -0
  439. package/build/dist/Server/Utils/CustomField/CustomFieldMappingRegistry.js.map +1 -0
  440. package/build/dist/Server/Utils/CustomField/CustomFieldMappingValidator.js +189 -0
  441. package/build/dist/Server/Utils/CustomField/CustomFieldMappingValidator.js.map +1 -0
  442. package/build/dist/Server/Utils/DataSource/EgressGuard.js +121 -7
  443. package/build/dist/Server/Utils/DataSource/EgressGuard.js.map +1 -1
  444. package/build/dist/Server/Utils/EmailRollup/EmailRollupConstants.js +38 -5
  445. package/build/dist/Server/Utils/EmailRollup/EmailRollupConstants.js.map +1 -1
  446. package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js +44 -2
  447. package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js.map +1 -1
  448. package/build/dist/Server/Utils/FrontendEnvironment.js +33 -0
  449. package/build/dist/Server/Utils/FrontendEnvironment.js.map +1 -0
  450. package/build/dist/Server/Utils/LogRedaction.js +20 -0
  451. package/build/dist/Server/Utils/LogRedaction.js.map +1 -1
  452. package/build/dist/Server/Utils/Logger.js +10 -0
  453. package/build/dist/Server/Utils/Logger.js.map +1 -1
  454. package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js +287 -68
  455. package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js.map +1 -1
  456. package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.js +20 -4
  457. package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.js.map +1 -1
  458. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +29 -6
  459. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  460. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +88 -13
  461. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  462. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +22 -6
  463. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  464. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +22 -0
  465. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
  466. package/build/dist/Server/Utils/Monitor/SeriesContextEnricher.js +237 -0
  467. package/build/dist/Server/Utils/Monitor/SeriesContextEnricher.js.map +1 -0
  468. package/build/dist/Server/Utils/SSRFProtection.js +136 -9
  469. package/build/dist/Server/Utils/SSRFProtection.js.map +1 -1
  470. package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCache.js +174 -89
  471. package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCache.js.map +1 -1
  472. package/build/dist/Server/Utils/SessionReplay/SessionReplayHealthCounters.js +223 -0
  473. package/build/dist/Server/Utils/SessionReplay/SessionReplayHealthCounters.js.map +1 -0
  474. package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js +945 -164
  475. package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js.map +1 -1
  476. package/build/dist/Server/Utils/StartServer.js +3 -14
  477. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  478. package/build/dist/Server/Utils/TelegramVerificationToken.js +129 -0
  479. package/build/dist/Server/Utils/TelegramVerificationToken.js.map +1 -0
  480. package/build/dist/Server/Utils/Telemetry/PinServiceName.js +163 -0
  481. package/build/dist/Server/Utils/Telemetry/PinServiceName.js.map +1 -0
  482. package/build/dist/Server/Utils/Telemetry/TelemetryFanInWriter.js +28 -15
  483. package/build/dist/Server/Utils/Telemetry/TelemetryFanInWriter.js.map +1 -1
  484. package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.js +64 -0
  485. package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.js.map +1 -0
  486. package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyRateLimiter.js +171 -0
  487. package/build/dist/Server/Utils/Telemetry/TelemetryIngestionKeyRateLimiter.js.map +1 -0
  488. package/build/dist/Server/Utils/VM/VMAPI.js.map +1 -1
  489. package/build/dist/Server/Utils/VM/VMRunner.js +780 -69
  490. package/build/dist/Server/Utils/VM/VMRunner.js.map +1 -1
  491. package/build/dist/Types/CustomField/CustomFieldMappingCatalog.js +60 -0
  492. package/build/dist/Types/CustomField/CustomFieldMappingCatalog.js.map +1 -0
  493. package/build/dist/Types/CustomField/CustomFieldMappingSourceResource.js +20 -0
  494. package/build/dist/Types/CustomField/CustomFieldMappingSourceResource.js.map +1 -0
  495. package/build/dist/Types/CustomField/CustomFieldValueMapping.js +141 -0
  496. package/build/dist/Types/CustomField/CustomFieldValueMapping.js.map +1 -0
  497. package/build/dist/Types/Icon/IconProp.js +1 -0
  498. package/build/dist/Types/Icon/IconProp.js.map +1 -1
  499. package/build/dist/Types/JSONFunctions.js +118 -37
  500. package/build/dist/Types/JSONFunctions.js.map +1 -1
  501. package/build/dist/Types/Monitor/CephAlertTemplates.js +130 -171
  502. package/build/dist/Types/Monitor/CephAlertTemplates.js.map +1 -1
  503. package/build/dist/Types/Monitor/DockerAlertTemplates.js +286 -121
  504. package/build/dist/Types/Monitor/DockerAlertTemplates.js.map +1 -1
  505. package/build/dist/Types/Monitor/DockerSwarmAlertTemplates.js +84 -105
  506. package/build/dist/Types/Monitor/DockerSwarmAlertTemplates.js.map +1 -1
  507. package/build/dist/Types/Monitor/HostAlertTemplates.js +250 -122
  508. package/build/dist/Types/Monitor/HostAlertTemplates.js.map +1 -1
  509. package/build/dist/Types/Monitor/IotAlertTemplates.js +81 -81
  510. package/build/dist/Types/Monitor/IotAlertTemplates.js.map +1 -1
  511. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js +375 -215
  512. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js.map +1 -1
  513. package/build/dist/Types/Monitor/KubernetesMetricCatalog.js +19 -19
  514. package/build/dist/Types/Monitor/KubernetesMetricCatalog.js.map +1 -1
  515. package/build/dist/Types/Monitor/PodmanAlertTemplates.js +104 -153
  516. package/build/dist/Types/Monitor/PodmanAlertTemplates.js.map +1 -1
  517. package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js +156 -91
  518. package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js.map +1 -1
  519. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js +67 -6
  520. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js.map +1 -1
  521. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js +38 -7
  522. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js.map +1 -1
  523. package/build/dist/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.js +261 -0
  524. package/build/dist/Types/Monitor/Recommendation/RecommendationCriteriaBuilder.js.map +1 -0
  525. package/build/dist/Types/Monitor/RumAlertTemplates.js +46 -7
  526. package/build/dist/Types/Monitor/RumAlertTemplates.js.map +1 -1
  527. package/build/dist/Types/Monitor/SeriesContext/SeriesDebugHints.js +422 -0
  528. package/build/dist/Types/Monitor/SeriesContext/SeriesDebugHints.js.map +1 -0
  529. package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js +441 -0
  530. package/build/dist/Types/Monitor/SeriesContext/SeriesLabelDisplay.js.map +1 -0
  531. package/build/dist/Types/Monitor/ServiceAlertTemplates.js +79 -15
  532. package/build/dist/Types/Monitor/ServiceAlertTemplates.js.map +1 -1
  533. package/build/dist/Types/Monitor/UptimeHistoryLabels.js +17 -0
  534. package/build/dist/Types/Monitor/UptimeHistoryLabels.js.map +1 -0
  535. package/build/dist/Types/NotificationSetting/RoutineEmailEvents.js +29 -0
  536. package/build/dist/Types/NotificationSetting/RoutineEmailEvents.js.map +1 -0
  537. package/build/dist/Types/Rum/SessionReplay.js +117 -0
  538. package/build/dist/Types/Rum/SessionReplay.js.map +1 -1
  539. package/build/dist/Types/Rum/SessionReplayApi.js +181 -0
  540. package/build/dist/Types/Rum/SessionReplayApi.js.map +1 -0
  541. package/build/dist/Types/Rum/SessionReplayCaptureTrigger.js +21 -12
  542. package/build/dist/Types/Rum/SessionReplayCaptureTrigger.js.map +1 -1
  543. package/build/dist/Types/Rum/SessionReplayConsentMode.js +11 -7
  544. package/build/dist/Types/Rum/SessionReplayConsentMode.js.map +1 -1
  545. package/build/dist/Types/Rum/SessionReplayCustomEvents.js +172 -0
  546. package/build/dist/Types/Rum/SessionReplayCustomEvents.js.map +1 -0
  547. package/build/dist/Types/Rum/SessionReplayHealth.js +37 -0
  548. package/build/dist/Types/Rum/SessionReplayHealth.js.map +1 -0
  549. package/build/dist/Types/Telemetry/TelemetryIngestSurface.js +85 -0
  550. package/build/dist/Types/Telemetry/TelemetryIngestSurface.js.map +1 -0
  551. package/build/dist/Types/Telemetry/TelemetryIngestionKeyPolicy.js +15 -0
  552. package/build/dist/Types/Telemetry/TelemetryIngestionKeyPolicy.js.map +1 -0
  553. package/build/dist/Types/Telemetry/TelemetryIngestionKeyType.js +30 -0
  554. package/build/dist/Types/Telemetry/TelemetryIngestionKeyType.js.map +1 -0
  555. package/build/dist/Types/WebsiteRequest.js +55 -3
  556. package/build/dist/Types/WebsiteRequest.js.map +1 -1
  557. package/build/dist/UI/Components/Charts/Area/AreaChart.js +13 -2
  558. package/build/dist/UI/Components/Charts/Area/AreaChart.js.map +1 -1
  559. package/build/dist/UI/Components/Charts/Bar/BarChart.js +6 -2
  560. package/build/dist/UI/Components/Charts/Bar/BarChart.js.map +1 -1
  561. package/build/dist/UI/Components/Charts/Line/LineChart.js +13 -2
  562. package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
  563. package/build/dist/UI/Components/Charts/Types/XAxis/XAxis.js.map +1 -1
  564. package/build/dist/UI/Components/Charts/Utils/DataPoint.js +15 -3
  565. package/build/dist/UI/Components/Charts/Utils/DataPoint.js.map +1 -1
  566. package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js +40 -9
  567. package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js.map +1 -1
  568. package/build/dist/UI/Components/Charts/Utils/XAxis.js +186 -0
  569. package/build/dist/UI/Components/Charts/Utils/XAxis.js.map +1 -1
  570. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +80 -6
  571. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
  572. package/build/dist/UI/Components/CustomFields/MapFromCustomFieldInput.js +118 -0
  573. package/build/dist/UI/Components/CustomFields/MapFromCustomFieldInput.js.map +1 -0
  574. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js +112 -7
  575. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js.map +1 -1
  576. package/build/dist/UI/Components/Graphs/UptimeBarTooltip.js +5 -162
  577. package/build/dist/UI/Components/Graphs/UptimeBarTooltip.js.map +1 -1
  578. package/build/dist/UI/Components/Graphs/UptimeDaySummary.js +181 -0
  579. package/build/dist/UI/Components/Graphs/UptimeDaySummary.js.map +1 -0
  580. package/build/dist/UI/Components/Header/Header.js +2 -3
  581. package/build/dist/UI/Components/Header/Header.js.map +1 -1
  582. package/build/dist/UI/Components/Header/IconDropdown/IconDropdownItem.js +2 -1
  583. package/build/dist/UI/Components/Header/IconDropdown/IconDropdownItem.js.map +1 -1
  584. package/build/dist/UI/Components/Header/IconDropdown/IconDropdownMenu.js +7 -1
  585. package/build/dist/UI/Components/Header/IconDropdown/IconDropdownMenu.js.map +1 -1
  586. package/build/dist/UI/Components/Header/ProjectPicker/ProjectPicker.js +7 -1
  587. package/build/dist/UI/Components/Header/ProjectPicker/ProjectPicker.js.map +1 -1
  588. package/build/dist/UI/Components/HeaderAlert/NotificationBell/NotificationBellDropdown.js +7 -1
  589. package/build/dist/UI/Components/HeaderAlert/NotificationBell/NotificationBellDropdown.js.map +1 -1
  590. package/build/dist/UI/Components/Icon/Icon.js +5 -0
  591. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  592. package/build/dist/UI/Components/JSONTable/JSONTable.js +2 -2
  593. package/build/dist/UI/Components/JSONTable/JSONTable.js.map +1 -1
  594. package/build/dist/UI/Components/KeyboardShortcut/KeyboardShortcutsModal.js +35 -0
  595. package/build/dist/UI/Components/KeyboardShortcut/KeyboardShortcutsModal.js.map +1 -0
  596. package/build/dist/UI/Components/Monitor/SeriesDebugCommandsViewer.js +34 -0
  597. package/build/dist/UI/Components/Monitor/SeriesDebugCommandsViewer.js.map +1 -0
  598. package/build/dist/UI/Components/Monitor/SeriesLabelsViewer.js +49 -0
  599. package/build/dist/UI/Components/Monitor/SeriesLabelsViewer.js.map +1 -0
  600. package/build/dist/UI/Components/MonitorGraphs/Uptime.js +1 -1
  601. package/build/dist/UI/Components/MonitorGraphs/Uptime.js.map +1 -1
  602. package/build/dist/UI/Components/MonitorGraphs/UptimeBarDayModal.js +32 -6
  603. package/build/dist/UI/Components/MonitorGraphs/UptimeBarDayModal.js.map +1 -1
  604. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +38 -0
  605. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
  606. package/build/dist/UI/Components/StatusPage/ResourceGroupSection.js +22 -1
  607. package/build/dist/UI/Components/StatusPage/ResourceGroupSection.js.map +1 -1
  608. package/build/dist/UI/Components/Table/CellClassName.js +55 -0
  609. package/build/dist/UI/Components/Table/CellClassName.js.map +1 -0
  610. package/build/dist/UI/Components/Table/TableRow.js +16 -13
  611. package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
  612. package/build/dist/UI/Components/Table/TableSkeletonRows.js +9 -8
  613. package/build/dist/UI/Components/Table/TableSkeletonRows.js.map +1 -1
  614. package/build/dist/UI/Components/Tooltip/Tooltip.js +25 -1
  615. package/build/dist/UI/Components/Tooltip/Tooltip.js.map +1 -1
  616. package/build/dist/UI/Components/Workflow/ComponentsModal.js +47 -30
  617. package/build/dist/UI/Components/Workflow/ComponentsModal.js.map +1 -1
  618. package/build/dist/UI/Components/Workflow/NodePlacement.js +37 -0
  619. package/build/dist/UI/Components/Workflow/NodePlacement.js.map +1 -0
  620. package/build/dist/UI/Components/Workflow/Workflow.js +35 -18
  621. package/build/dist/UI/Components/Workflow/Workflow.js.map +1 -1
  622. package/build/dist/UI/Config.js +10 -20
  623. package/build/dist/UI/Config.js.map +1 -1
  624. package/build/dist/UI/Utils/GlobalKeyboardShortcut.js +138 -0
  625. package/build/dist/UI/Utils/GlobalKeyboardShortcut.js.map +1 -0
  626. package/build/dist/UI/Utils/Telemetry/BrowserTelemetryConfig.js +14 -0
  627. package/build/dist/UI/Utils/Telemetry/BrowserTelemetryConfig.js.map +1 -0
  628. package/build/dist/UI/Utils/Telemetry/Telemetry.js +7 -5
  629. package/build/dist/UI/Utils/Telemetry/Telemetry.js.map +1 -1
  630. package/build/dist/Utils/API.js +67 -5
  631. package/build/dist/Utils/API.js.map +1 -1
  632. package/build/dist/Utils/HTTPResponseBodyReader.js +157 -0
  633. package/build/dist/Utils/HTTPResponseBodyReader.js.map +1 -0
  634. package/build/dist/Utils/NetworkDiscovery/DiscoveryScanStatus.js +69 -0
  635. package/build/dist/Utils/NetworkDiscovery/DiscoveryScanStatus.js.map +1 -0
  636. package/build/dist/Utils/Rum/ChunkMath.js +76 -0
  637. package/build/dist/Utils/Rum/ChunkMath.js.map +1 -1
  638. package/build/dist/Utils/Rum/SessionReplayHealth.js +534 -0
  639. package/build/dist/Utils/Rum/SessionReplayHealth.js.map +1 -0
  640. package/build/dist/Utils/Rum/SessionReplayStringMap.js +165 -0
  641. package/build/dist/Utils/Rum/SessionReplayStringMap.js.map +1 -0
  642. package/build/dist/Utils/Schema/ModelSchema.js +1 -0
  643. package/build/dist/Utils/Schema/ModelSchema.js.map +1 -1
  644. package/build/dist/Utils/StatusPage/ResourceSearch.js +200 -0
  645. package/build/dist/Utils/StatusPage/ResourceSearch.js.map +1 -0
  646. package/build/dist/Utils/Telemetry/OriginAllowList.js +299 -0
  647. package/build/dist/Utils/Telemetry/OriginAllowList.js.map +1 -0
  648. package/build/dist/Utils/Uptime/DayUptimeGraphUtil.js +147 -0
  649. package/build/dist/Utils/Uptime/DayUptimeGraphUtil.js.map +1 -0
  650. package/build/dist/Utils/ValueFormatter.js +32 -1
  651. package/build/dist/Utils/ValueFormatter.js.map +1 -1
  652. package/package.json +1 -1
@@ -1,7 +1,14 @@
1
1
  import "@testing-library/jest-dom";
2
- import { fireEvent, render, screen } from "@testing-library/react";
2
+ import { act, fireEvent, render, screen } from "@testing-library/react";
3
3
  import * as React from "react";
4
- import { describe, expect, it } from "@jest/globals";
4
+ import {
5
+ afterEach,
6
+ beforeEach,
7
+ describe,
8
+ expect,
9
+ it,
10
+ jest,
11
+ } from "@jest/globals";
5
12
  /*
6
13
  * The Dashboard resolves its own copy of react, which would give the component
7
14
  * a different hook dispatcher than the one react-dom renders with. Pinned in
@@ -9,228 +16,837 @@ import { describe, expect, it } from "@jest/globals";
9
16
  * see ReplayStage.test.tsx for why the path-based version broke CI.
10
17
  */
11
18
  import ReplayScrubber, {
19
+ REPLAY_SPEEDS,
12
20
  ReplayScrubberProps,
13
21
  } from "../../../../App/FeatureSet/Dashboard/src/Components/SessionReplay/ReplayScrubber";
22
+ import {
23
+ ReplayEngineSnapshot,
24
+ derivePhase,
25
+ } from "../../../../App/FeatureSet/Dashboard/src/Components/SessionReplay/Engine/ReplayEngineTypes";
26
+ import {
27
+ ReplayTimelineMarker,
28
+ buildExactMarkers,
29
+ } from "../../../../App/FeatureSet/Dashboard/src/Components/SessionReplay/ReplayTimelineMath";
30
+ import { ReplaySignal } from "../../../../App/FeatureSet/Dashboard/src/Components/SessionReplay/Rail/ReplaySignalTypes";
14
31
 
15
32
  /*
16
- * The scrubber's two expensive mistakes are both invisible in a screenshot:
17
- * seeking on every pointermove (each one re-instantiates the Replayer and
18
- * POSTs /chunks), and swallowing Space from focused buttons (which makes the
19
- * player unusable with a keyboard). Both are pinned here.
33
+ * The composition: controls + timeline + one keyboard listener + the "?"
34
+ * sheet. The timeline's own gestures are covered in ReplayTimeline.test.tsx;
35
+ * here the subject is the glue - prev/next error stepping whose enabled
36
+ * state and behaviour share one rule, the speed control, the toggle, and
37
+ * the keyboard rules the old scrubber got wrong (focused buttons killed
38
+ * the arrows, auto-repeat seeked per repeat, Alt+Left was swallowed, the
39
+ * listener churned every tick).
20
40
  */
21
41
 
22
42
  const DURATION_MS: number = 600000;
23
- const TRACK_WIDTH: number = 1000;
24
43
 
25
- function makeProps(
26
- overrides?: Partial<ReplayScrubberProps>,
27
- ): ReplayScrubberProps {
44
+ function makeSnapshot(
45
+ overrides?: Partial<ReplayEngineSnapshot>,
46
+ ): ReplayEngineSnapshot {
47
+ const buffer: ReplayEngineSnapshot["buffer"] = overrides?.buffer ?? "ok";
48
+ const intent: ReplayEngineSnapshot["intent"] = overrides?.intent ?? "paused";
49
+
28
50
  return {
29
- durationMs: DURATION_MS,
51
+ phase: derivePhase(buffer, intent),
52
+ intent: intent,
53
+ buffer: buffer,
30
54
  currentTimeMs: 0,
31
- isPlaying: false,
55
+ durationMs: DURATION_MS,
32
56
  speed: 1,
33
57
  skipInactive: false,
58
+ fedRange: { fromMs: 0, toMs: 60000 },
59
+ loadedChunkIndexes: [0, 1, 2, 3],
60
+ activeTabId: "tab-1",
61
+ recordedSize: null,
62
+ bufferingSinceMs: null,
63
+ lastGap: null,
64
+ lastIdleSkip: null,
65
+ error: null,
66
+ pendingSeekMs: null,
67
+ generation: 1,
68
+ ...overrides,
69
+ };
70
+ }
71
+
72
+ function signal(
73
+ overrides: Partial<ReplaySignal> & { id: string },
74
+ ): ReplaySignal {
75
+ return {
76
+ kind: "client-error",
77
+ source: "recording",
78
+ offsetMs: 0,
79
+ severity: "error",
80
+ title: overrides.id,
81
+ links: {},
82
+ detail: {},
83
+ ...overrides,
84
+ };
85
+ }
86
+
87
+ function makeProps(
88
+ overrides?: Partial<ReplayScrubberProps>,
89
+ ): ReplayScrubberProps {
90
+ return {
91
+ snapshot: makeSnapshot(),
34
92
  bands: [],
35
- frustrationMarkers: [],
36
- errorMarkers: [],
37
- networkMarkers: [],
38
- routeMarkers: [],
93
+ markers: [],
39
94
  onSeek: (): void => {
40
95
  // overridden per test
41
96
  },
42
- onPlayPauseToggle: (): void => {
97
+ onPlayPause: (): void => {
43
98
  // overridden per test
44
99
  },
45
100
  onSpeedChange: (): void => {
46
- // not asserted here
101
+ // overridden per test
47
102
  },
48
103
  onSkipInactiveChange: (): void => {
49
- // not asserted here
50
- },
51
- onJumpToNextError: (): void => {
52
- // not asserted here
104
+ // overridden per test
53
105
  },
54
106
  ...overrides,
55
107
  };
56
108
  }
57
109
 
58
- /*
59
- * jsdom gives every element a zero-size rect, so the track has to be told how
60
- * wide it is before clientX can mean anything.
61
- */
62
- function stubTrackRect(track: HTMLElement): void {
63
- track.getBoundingClientRect = (): DOMRect => {
64
- return {
65
- x: 0,
66
- y: 0,
67
- left: 0,
68
- top: 0,
69
- right: TRACK_WIDTH,
70
- bottom: 24,
71
- width: TRACK_WIDTH,
72
- height: 24,
73
- toJSON: (): unknown => {
74
- return {};
75
- },
76
- } as DOMRect;
77
- };
78
- }
79
-
80
- function getTrack(): HTMLElement {
81
- const track: HTMLElement = screen.getByRole("slider", {
82
- name: "Replay position",
110
+ const ERROR_MARKERS: Array<ReplayTimelineMarker> = buildExactMarkers([
111
+ signal({ id: "rec:1:0", offsetMs: 20000, title: "first" }),
112
+ signal({ id: "rec:1:1", offsetMs: 21000, title: "second" }),
113
+ signal({ id: "rec:4:0", offsetMs: 60000, title: "third" }),
114
+ ]);
115
+
116
+ describe("ReplayScrubber controls", () => {
117
+ it("renders the clock with tenths while paused and whole seconds while playing", () => {
118
+ const { rerender } = render(
119
+ <ReplayScrubber
120
+ {...makeProps({ snapshot: makeSnapshot({ currentTimeMs: 12340 }) })}
121
+ />,
122
+ );
123
+
124
+ expect(screen.getByTestId("replay-time")).toHaveTextContent(
125
+ "0:12.3 / 10:00",
126
+ );
127
+
128
+ rerender(
129
+ <ReplayScrubber
130
+ {...makeProps({
131
+ snapshot: makeSnapshot({ currentTimeMs: 12340, intent: "playing" }),
132
+ })}
133
+ />,
134
+ );
135
+
136
+ expect(screen.getByTestId("replay-time")).toHaveTextContent("0:12 / 10:00");
83
137
  });
84
138
 
85
- stubTrackRect(track);
86
-
87
- // jsdom implements neither pointer capture nor PointerEvent.
88
- track.setPointerCapture = (): void => {
89
- // no-op
90
- };
91
- track.hasPointerCapture = (): boolean => {
92
- return false;
93
- };
139
+ it("names the play button by phase, never by a bare boolean", () => {
140
+ const cases: Array<[Partial<ReplayEngineSnapshot>, string, string]> = [
141
+ [{ buffer: "ok", intent: "paused" }, "paused", "Play (Space)"],
142
+ [{ buffer: "ok", intent: "playing" }, "playing", "Pause (Space)"],
143
+ [{ buffer: "stalled", intent: "playing" }, "buffering", "Pause (Space)"],
144
+ [{ buffer: "empty" }, "loading", "Loading footage"],
145
+ [{ buffer: "ended" }, "ended", "Watch again (Space)"],
146
+ [{ buffer: "halted" }, "error", "Retry"],
147
+ ];
148
+
149
+ for (const [overrides, phase, label] of cases) {
150
+ const { unmount } = render(
151
+ <ReplayScrubber
152
+ {...makeProps({ snapshot: makeSnapshot(overrides) })}
153
+ />,
154
+ );
155
+
156
+ const button: HTMLElement = screen.getByTestId("replay-play-pause");
157
+
158
+ expect(button.getAttribute("data-phase")).toBe(phase);
159
+ expect(button.getAttribute("aria-label")).toBe(label);
160
+ expect(button.hasAttribute("disabled")).toBe(phase === "loading");
161
+
162
+ unmount();
163
+ }
164
+ });
94
165
 
95
- return track;
96
- }
166
+ it("routes the error-phase button to onRetry and shows the domain message", () => {
167
+ let retries: number = 0;
168
+ let toggles: number = 0;
97
169
 
98
- /*
99
- * fireEvent.pointerDown builds a bare Event in jsdom, which drops clientX and
100
- * makes every offset NaN. A MouseEvent carries the coordinates and React
101
- * dispatches purely on the type name.
102
- */
103
- function firePointer(
104
- track: HTMLElement,
105
- type: "pointerdown" | "pointermove" | "pointerup",
106
- clientX: number,
107
- ): void {
108
- fireEvent(
109
- track,
110
- new MouseEvent(type, {
111
- clientX: clientX,
112
- bubbles: true,
113
- cancelable: true,
114
- }),
115
- );
116
- }
170
+ render(
171
+ <ReplayScrubber
172
+ {...makeProps({
173
+ snapshot: makeSnapshot({
174
+ buffer: "halted",
175
+ error: { message: "Chunk 4 could not be fetched", retryable: true },
176
+ }),
177
+ onRetry: (): void => {
178
+ retries++;
179
+ },
180
+ onPlayPause: (): void => {
181
+ toggles++;
182
+ },
183
+ })}
184
+ />,
185
+ );
186
+
187
+ expect(screen.getByTestId("replay-error-pill")).toHaveTextContent(
188
+ "Chunk 4 could not be fetched",
189
+ );
190
+
191
+ fireEvent.click(screen.getByTestId("replay-play-pause"));
192
+
193
+ expect(retries).toBe(1);
194
+ expect(toggles).toBe(0);
195
+ });
117
196
 
118
- describe("ReplayScrubber dragging", () => {
119
- it("seeks exactly once per drag, on release, with the final position", () => {
120
- /*
121
- * Seeking per pointermove is what makes the stage strobe: every call
122
- * bumps the player's seek token, and any target across a snapshot anchor
123
- * destroys the Replayer, drops the decoded LRU and issues a fresh
124
- * authenticated POST to /chunks. One drag would be dozens of each.
125
- */
126
- const seeks: Array<number> = [];
127
- const props: ReplayScrubberProps = makeProps({
128
- onSeek: (offsetMs: number): void => {
129
- seeks.push(offsetMs);
130
- },
131
- });
197
+ it("offers every REPLAY_SPEEDS value, including 1.5x and 3x, from a radiogroup", () => {
198
+ const speeds: Array<number> = [];
132
199
 
133
- render(<ReplayScrubber {...props} />);
200
+ render(
201
+ <ReplayScrubber
202
+ {...makeProps({
203
+ onSpeedChange: (speed: number): void => {
204
+ speeds.push(speed);
205
+ },
206
+ })}
207
+ />,
208
+ );
134
209
 
135
- const track: HTMLElement = getTrack();
210
+ expect(REPLAY_SPEEDS).toContain(1.5);
211
+ expect(REPLAY_SPEEDS).toContain(3);
136
212
 
137
- firePointer(track, "pointerdown", 100);
138
- firePointer(track, "pointermove", 200);
139
- firePointer(track, "pointermove", 400);
140
- firePointer(track, "pointermove", 750);
213
+ const trigger: HTMLElement = screen.getByTestId("replay-speed");
141
214
 
142
- // Nothing committed yet.
143
- expect(seeks).toEqual([]);
215
+ expect(trigger).toHaveTextContent("1x");
216
+ expect(trigger.getAttribute("aria-expanded")).toBe("false");
144
217
 
145
- firePointer(track, "pointerup", 750);
218
+ fireEvent.click(trigger);
146
219
 
147
- expect(seeks).toEqual([0.75 * DURATION_MS]);
220
+ const group: HTMLElement = screen.getByRole("radiogroup", {
221
+ name: "Playback speed",
222
+ });
223
+ const radios: Array<HTMLElement> = screen.getAllByRole("radio");
224
+
225
+ expect(
226
+ radios.map((radio: HTMLElement) => {
227
+ return radio.textContent;
228
+ }),
229
+ ).toEqual(
230
+ REPLAY_SPEEDS.map((speed: number) => {
231
+ return `${speed}x`;
232
+ }),
233
+ );
234
+ expect(
235
+ radios.find((radio: HTMLElement) => {
236
+ return radio.getAttribute("aria-checked") === "true";
237
+ })?.textContent,
238
+ ).toBe("1x");
239
+
240
+ fireEvent.click(screen.getByTestId("replay-speed-option-2"));
241
+
242
+ expect(speeds).toEqual([2]);
243
+ expect(group).not.toBeInTheDocument();
148
244
  });
149
245
 
150
- it("moves the playhead while dragging even though it has not seeked", () => {
151
- const props: ReplayScrubberProps = makeProps({ currentTimeMs: 0 });
246
+ it("emits the skip-idle toggle", () => {
247
+ const values: Array<boolean> = [];
152
248
 
153
- render(<ReplayScrubber {...props} />);
249
+ render(
250
+ <ReplayScrubber
251
+ {...makeProps({
252
+ onSkipInactiveChange: (isEnabled: boolean): void => {
253
+ values.push(isEnabled);
254
+ },
255
+ })}
256
+ />,
257
+ );
154
258
 
155
- const track: HTMLElement = getTrack();
259
+ const toggle: HTMLElement = screen.getByTestId("replay-skip-idle");
156
260
 
157
- firePointer(track, "pointerdown", 500);
158
- firePointer(track, "pointermove", 500);
261
+ expect(toggle.getAttribute("aria-checked")).toBe("false");
159
262
 
160
- expect(track.getAttribute("aria-valuenow")).toBe(String(0.5 * DURATION_MS));
263
+ fireEvent.click(toggle);
264
+
265
+ expect(values).toEqual([true]);
161
266
  });
162
267
 
163
- it("still seeks on a plain click with no movement", () => {
268
+ it("seeks +-10s from the buttons relative to the latest playhead", () => {
164
269
  const seeks: Array<number> = [];
165
- const props: ReplayScrubberProps = makeProps({
166
- onSeek: (offsetMs: number): void => {
167
- seeks.push(offsetMs);
168
- },
169
- });
170
270
 
171
- render(<ReplayScrubber {...props} />);
271
+ render(
272
+ <ReplayScrubber
273
+ {...makeProps({
274
+ snapshot: makeSnapshot({ currentTimeMs: 5000 }),
275
+ onSeek: (offsetMs: number): void => {
276
+ seeks.push(offsetMs);
277
+ },
278
+ })}
279
+ />,
280
+ );
281
+
282
+ fireEvent.click(screen.getByTestId("replay-seek-back"));
283
+ fireEvent.click(screen.getByTestId("replay-seek-forward"));
284
+
285
+ expect(seeks).toEqual([0, 15000]);
286
+ });
287
+ });
172
288
 
173
- const track: HTMLElement = getTrack();
289
+ describe("ReplayScrubber error stepping", () => {
290
+ it("disables prev at the start and next at the end", () => {
291
+ const { rerender } = render(
292
+ <ReplayScrubber {...makeProps({ markers: ERROR_MARKERS })} />,
293
+ );
294
+
295
+ expect(screen.getByTestId("replay-prev-error")).toBeDisabled();
296
+ expect(screen.getByTestId("replay-next-error")).toBeEnabled();
297
+
298
+ rerender(
299
+ <ReplayScrubber
300
+ {...makeProps({
301
+ markers: ERROR_MARKERS,
302
+ snapshot: makeSnapshot({ currentTimeMs: 60000 }),
303
+ })}
304
+ />,
305
+ );
306
+
307
+ expect(screen.getByTestId("replay-prev-error")).toBeEnabled();
308
+ expect(screen.getByTestId("replay-next-error")).toBeDisabled();
309
+ });
174
310
 
175
- firePointer(track, "pointerdown", 250);
176
- firePointer(track, "pointerup", 250);
311
+ it("advances through every error, landing a second early, and selects each row", () => {
312
+ /*
313
+ * Regression for scrubber-devtools-2 / player-shell-1: the old button
314
+ * landed 10s before the marker and then re-found the same marker on
315
+ * the next press because it was still ahead of the playhead.
316
+ */
317
+ const seeks: Array<number> = [];
318
+ const selected: Array<string> = [];
319
+ let snapshot: ReplayEngineSnapshot = makeSnapshot();
320
+
321
+ const renderAt: (currentTimeMs: number) => ReplayScrubberProps = (
322
+ currentTimeMs: number,
323
+ ): ReplayScrubberProps => {
324
+ snapshot = makeSnapshot({ currentTimeMs: currentTimeMs });
325
+
326
+ return makeProps({
327
+ markers: ERROR_MARKERS,
328
+ snapshot: snapshot,
329
+ onSeek: (offsetMs: number): void => {
330
+ seeks.push(offsetMs);
331
+ },
332
+ onSelectSignal: (signalId: string): void => {
333
+ selected.push(signalId);
334
+ },
335
+ });
336
+ };
337
+
338
+ const { rerender } = render(<ReplayScrubber {...renderAt(0)} />);
339
+
340
+ fireEvent.click(screen.getByTestId("replay-next-error"));
341
+ rerender(<ReplayScrubber {...renderAt(seeks[seeks.length - 1]!)} />);
342
+ fireEvent.click(screen.getByTestId("replay-next-error"));
343
+ rerender(<ReplayScrubber {...renderAt(seeks[seeks.length - 1]!)} />);
344
+ fireEvent.click(screen.getByTestId("replay-next-error"));
345
+ rerender(<ReplayScrubber {...renderAt(seeks[seeks.length - 1]!)} />);
346
+
347
+ expect(seeks).toEqual([19000, 20000, 59000]);
348
+ expect(selected).toEqual(["rec:1:0", "rec:1:1", "rec:4:0"]);
349
+ expect(screen.getByTestId("replay-next-error")).toBeDisabled();
350
+
351
+ fireEvent.click(screen.getByTestId("replay-prev-error"));
352
+
353
+ expect(seeks[seeks.length - 1]).toBe(20000);
354
+ expect(selected[selected.length - 1]).toBe("rec:1:1");
355
+ });
177
356
 
178
- expect(seeks).toEqual([0.25 * DURATION_MS]);
357
+ it("steps frustration markers with the same rule", () => {
358
+ const seeks: Array<number> = [];
359
+ const markers: Array<ReplayTimelineMarker> = buildExactMarkers([
360
+ signal({
361
+ id: "rec:2:0",
362
+ kind: "frustration",
363
+ severity: "warn",
364
+ offsetMs: 45000,
365
+ }),
366
+ ]);
367
+
368
+ render(
369
+ <ReplayScrubber
370
+ {...makeProps({
371
+ markers: markers,
372
+ onSeek: (offsetMs: number): void => {
373
+ seeks.push(offsetMs);
374
+ },
375
+ })}
376
+ />,
377
+ );
378
+
379
+ fireEvent.click(screen.getByTestId("replay-next-frustration"));
380
+
381
+ expect(seeks).toEqual([44000]);
179
382
  });
180
383
  });
181
384
 
182
385
  describe("ReplayScrubber keyboard shortcuts", () => {
183
386
  it("toggles play/pause on Space when nothing focusable owns the key", () => {
184
387
  let toggles: number = 0;
185
- const props: ReplayScrubberProps = makeProps({
186
- onPlayPauseToggle: (): void => {
187
- toggles++;
188
- },
189
- });
190
388
 
191
- render(<ReplayScrubber {...props} />);
389
+ render(
390
+ <ReplayScrubber
391
+ {...makeProps({
392
+ onPlayPause: (): void => {
393
+ toggles++;
394
+ },
395
+ })}
396
+ />,
397
+ );
192
398
 
193
399
  fireEvent.keyDown(document.body, { key: " " });
194
400
 
195
401
  expect(toggles).toBe(1);
196
402
  });
197
403
 
198
- it("leaves Space alone when a button has focus", () => {
404
+ it("leaves Space alone when a button has focus but still answers the arrows there", () => {
199
405
  /*
200
- * The handler is bound to window for the scrubber's whole lifetime. If it
201
- * swallows Space from a focused control, a keyboard-only user cannot
202
- * press "Session details", a speed button, a tab or an error marker
203
- * anywhere on the player page.
406
+ * Finding scrubber-devtools-1. Clicking Play leaves the button
407
+ * focused; Space must activate the button (not double-fire), while
408
+ * ArrowRight must still seek - the most common gesture in the player.
204
409
  */
205
410
  let toggles: number = 0;
206
- const props: ReplayScrubberProps = makeProps({
207
- onPlayPauseToggle: (): void => {
208
- toggles++;
209
- },
210
- });
411
+ const seeks: Array<number> = [];
211
412
 
212
- render(<ReplayScrubber {...props} />);
413
+ render(
414
+ <ReplayScrubber
415
+ {...makeProps({
416
+ snapshot: makeSnapshot({ currentTimeMs: 30000 }),
417
+ onPlayPause: (): void => {
418
+ toggles++;
419
+ },
420
+ onSeek: (offsetMs: number): void => {
421
+ seeks.push(offsetMs);
422
+ },
423
+ })}
424
+ />,
425
+ );
426
+
427
+ const playButton: HTMLElement = screen.getByTestId("replay-play-pause");
428
+
429
+ fireEvent.keyDown(playButton, { key: " " });
430
+ fireEvent.keyDown(playButton, { key: "ArrowRight" });
431
+ fireEvent.keyDown(playButton, { key: "," });
432
+ fireEvent.keyDown(playButton, { key: "k" });
213
433
 
214
- const speedButton: HTMLElement = screen.getByText("4x");
215
- fireEvent.keyDown(speedButton, { key: " " });
434
+ expect(toggles).toBe(1);
435
+ expect(seeks).toEqual([35000, 29000]);
436
+ });
437
+
438
+ it("never steals keys from a text field", () => {
439
+ let toggles: number = 0;
440
+ const seeks: Array<number> = [];
441
+
442
+ render(
443
+ <div>
444
+ <input data-testid="search" />
445
+ <ReplayScrubber
446
+ {...makeProps({
447
+ onPlayPause: (): void => {
448
+ toggles++;
449
+ },
450
+ onSeek: (offsetMs: number): void => {
451
+ seeks.push(offsetMs);
452
+ },
453
+ })}
454
+ />
455
+ </div>,
456
+ );
457
+
458
+ const input: HTMLElement = screen.getByTestId("search");
459
+
460
+ fireEvent.keyDown(input, { key: " " });
461
+ fireEvent.keyDown(input, { key: "ArrowRight" });
462
+ fireEvent.keyDown(input, { key: "e" });
216
463
 
217
464
  expect(toggles).toBe(0);
465
+ expect(seeks).toEqual([]);
218
466
  });
219
467
 
220
- it("still moves the playhead with the arrow keys", () => {
468
+ it("leaves Alt/Ctrl/Meta chords to the browser", () => {
221
469
  const seeks: Array<number> = [];
222
- const props: ReplayScrubberProps = makeProps({
223
- currentTimeMs: 30000,
224
- onSeek: (offsetMs: number): void => {
225
- seeks.push(offsetMs);
226
- },
470
+ let copies: number = 0;
471
+
472
+ render(
473
+ <ReplayScrubber
474
+ {...makeProps({
475
+ snapshot: makeSnapshot({ currentTimeMs: 30000 }),
476
+ onSeek: (offsetMs: number): void => {
477
+ seeks.push(offsetMs);
478
+ },
479
+ onCopyLink: (): void => {
480
+ copies++;
481
+ },
482
+ })}
483
+ />,
484
+ );
485
+
486
+ const alt: KeyboardEvent = new KeyboardEvent("keydown", {
487
+ key: "ArrowLeft",
488
+ altKey: true,
489
+ bubbles: true,
490
+ cancelable: true,
227
491
  });
228
492
 
229
- render(<ReplayScrubber {...props} />);
493
+ fireEvent(document.body, alt);
494
+ fireEvent.keyDown(document.body, { key: "c", metaKey: true });
495
+
496
+ expect(seeks).toEqual([]);
497
+ expect(copies).toBe(0);
498
+ expect(alt.defaultPrevented).toBe(false);
499
+ });
500
+
501
+ it("commits a held arrow key as one seek at press and one at release", () => {
502
+ /*
503
+ * Finding scrubber-devtools-10: auto-repeat used to seek per repeat,
504
+ * one Replayer rebuild each. Press seeks immediately; repeats
505
+ * accumulate; keyup commits the accumulated delta once.
506
+ */
507
+ const seeks: Array<number> = [];
508
+
509
+ render(
510
+ <ReplayScrubber
511
+ {...makeProps({
512
+ snapshot: makeSnapshot({ currentTimeMs: 30000 }),
513
+ onSeek: (offsetMs: number): void => {
514
+ seeks.push(offsetMs);
515
+ },
516
+ })}
517
+ />,
518
+ );
230
519
 
231
- fireEvent.keyDown(document.body, { key: "ArrowLeft" });
232
520
  fireEvent.keyDown(document.body, { key: "ArrowRight" });
521
+ fireEvent.keyDown(document.body, { key: "ArrowRight", repeat: true });
522
+ fireEvent.keyDown(document.body, { key: "ArrowRight", repeat: true });
523
+ fireEvent.keyDown(document.body, { key: "ArrowRight", repeat: true });
524
+
525
+ expect(seeks).toEqual([35000]);
526
+
527
+ fireEvent.keyUp(document.body, { key: "ArrowRight" });
528
+
529
+ /* 3 repeats x 5s, applied to the latest playhead the parent reported. */
530
+ expect(seeks).toEqual([35000, 45000]);
531
+ });
532
+
533
+ it("ignores auto-repeat for one-shot keys like Space", () => {
534
+ let toggles: number = 0;
535
+
536
+ render(
537
+ <ReplayScrubber
538
+ {...makeProps({
539
+ onPlayPause: (): void => {
540
+ toggles++;
541
+ },
542
+ })}
543
+ />,
544
+ );
545
+
546
+ fireEvent.keyDown(document.body, { key: " " });
547
+ fireEvent.keyDown(document.body, { key: " ", repeat: true });
548
+ fireEvent.keyDown(document.body, { key: " ", repeat: true });
549
+
550
+ expect(toggles).toBe(1);
551
+ });
552
+
553
+ it("covers the full vocabulary: j/l, digits, Home/End, speed, skip idle, errors, view keys", () => {
554
+ const seeks: Array<number> = [];
555
+ const speeds: Array<number> = [];
556
+ const skips: Array<boolean> = [];
557
+ const calls: Array<string> = [];
558
+ const record: (name: string) => () => void = (
559
+ name: string,
560
+ ): (() => void) => {
561
+ return (): void => {
562
+ calls.push(name);
563
+ };
564
+ };
565
+
566
+ render(
567
+ <ReplayScrubber
568
+ {...makeProps({
569
+ snapshot: makeSnapshot({ currentTimeMs: 30000, speed: 2 }),
570
+ markers: ERROR_MARKERS,
571
+ onSeek: (offsetMs: number): void => {
572
+ seeks.push(offsetMs);
573
+ },
574
+ onSpeedChange: (speed: number): void => {
575
+ speeds.push(speed);
576
+ },
577
+ onSkipInactiveChange: (isEnabled: boolean): void => {
578
+ skips.push(isEnabled);
579
+ },
580
+ onSkipIdleJump: record("skip-idle-jump"),
581
+ onNextSignal: record("next-signal"),
582
+ onPrevSignal: record("prev-signal"),
583
+ onToggleTheater: record("theater"),
584
+ onToggleWide: record("wide"),
585
+ onFollowChange: (isEnabled: boolean): void => {
586
+ calls.push(`follow:${isEnabled}`);
587
+ },
588
+ onFocusRailSearch: record("rail-search"),
589
+ onCopyLink: record("copy"),
590
+ onToggleDetails: record("details"),
591
+ onEscape: record("escape"),
592
+ })}
593
+ />,
594
+ );
595
+
596
+ fireEvent.keyDown(document.body, { key: "j" });
597
+ fireEvent.keyUp(document.body, { key: "j" });
598
+ fireEvent.keyDown(document.body, { key: "l" });
599
+ fireEvent.keyUp(document.body, { key: "l" });
600
+ fireEvent.keyDown(document.body, { key: "5" });
601
+ fireEvent.keyDown(document.body, { key: "Home" });
602
+ fireEvent.keyDown(document.body, { key: "End" });
603
+ fireEvent.keyDown(document.body, { key: "e" });
604
+
605
+ expect(seeks).toEqual([20000, 40000, 300000, 0, DURATION_MS, 59000]);
606
+
607
+ fireEvent.keyDown(document.body, { key: ">", shiftKey: true });
608
+ fireEvent.keyDown(document.body, { key: "<", shiftKey: true });
609
+
610
+ expect(speeds).toEqual([3, 1.5]);
611
+
612
+ fireEvent.keyDown(document.body, { key: "S", shiftKey: true });
613
+
614
+ expect(skips).toEqual([true]);
615
+
616
+ fireEvent.keyDown(document.body, { key: "s" });
617
+ fireEvent.keyDown(document.body, { key: "]" });
618
+ fireEvent.keyDown(document.body, { key: "[" });
619
+ fireEvent.keyDown(document.body, { key: "f" });
620
+ fireEvent.keyDown(document.body, { key: "w" });
621
+ fireEvent.keyDown(document.body, { key: "m" });
622
+ fireEvent.keyDown(document.body, { key: "/" });
623
+ fireEvent.keyDown(document.body, { key: "c" });
624
+ fireEvent.keyDown(document.body, { key: "i" });
625
+ fireEvent.keyDown(document.body, { key: "Escape" });
626
+
627
+ expect(calls).toEqual([
628
+ "skip-idle-jump",
629
+ "next-signal",
630
+ "prev-signal",
631
+ "theater",
632
+ "wide",
633
+ "follow:true",
634
+ "rail-search",
635
+ "copy",
636
+ "details",
637
+ "escape",
638
+ ]);
639
+ });
640
+
641
+ it("uses the rail vocabulary when the scope says the rail has focus", () => {
642
+ const calls: Array<string> = [];
643
+
644
+ render(
645
+ <ReplayScrubber
646
+ {...makeProps({
647
+ keyboardScope: "rail",
648
+ onRailRowDown: (): void => {
649
+ calls.push("down");
650
+ },
651
+ onRailRowUp: (): void => {
652
+ calls.push("up");
653
+ },
654
+ onRailSeekSelected: (): void => {
655
+ calls.push("seek");
656
+ },
657
+ onRailClear: (): void => {
658
+ calls.push("clear");
659
+ },
660
+ })}
661
+ />,
662
+ );
663
+
664
+ fireEvent.keyDown(document.body, { key: "j" });
665
+ fireEvent.keyDown(document.body, { key: "k" });
666
+ fireEvent.keyDown(document.body, { key: "Enter" });
667
+ fireEvent.keyDown(document.body, { key: "Escape" });
668
+
669
+ expect(calls).toEqual(["down", "up", "seek", "clear"]);
670
+ });
671
+
672
+ it("does nothing while shortcuts are disabled", () => {
673
+ let toggles: number = 0;
674
+
675
+ render(
676
+ <ReplayScrubber
677
+ {...makeProps({
678
+ areShortcutsEnabled: false,
679
+ onPlayPause: (): void => {
680
+ toggles++;
681
+ },
682
+ })}
683
+ />,
684
+ );
685
+
686
+ fireEvent.keyDown(document.body, { key: " " });
687
+
688
+ expect(toggles).toBe(0);
689
+ });
690
+
691
+ it("registers one window keydown listener for its lifetime, not one per tick", () => {
692
+ /*
693
+ * Finding scrubber-devtools-20: the old effect depended on
694
+ * currentTimeMs and re-subscribed five times a second.
695
+ */
696
+ const added: Array<string> = [];
697
+ const original: typeof window.addEventListener = window.addEventListener;
698
+
699
+ window.addEventListener = ((
700
+ type: string,
701
+ listener: EventListenerOrEventListenerObject,
702
+ options?: boolean | AddEventListenerOptions,
703
+ ): void => {
704
+ added.push(type);
705
+ original.call(window, type, listener, options);
706
+ }) as typeof window.addEventListener;
707
+
708
+ try {
709
+ const { rerender } = render(
710
+ <ReplayScrubber
711
+ {...makeProps({ snapshot: makeSnapshot({ currentTimeMs: 0 }) })}
712
+ />,
713
+ );
714
+
715
+ const keydownsAfterMount: number = added.filter((type: string) => {
716
+ return type === "keydown";
717
+ }).length;
718
+
719
+ for (let tick: number = 1; tick <= 5; tick++) {
720
+ rerender(
721
+ <ReplayScrubber
722
+ {...makeProps({
723
+ snapshot: makeSnapshot({ currentTimeMs: tick * 200 }),
724
+ })}
725
+ />,
726
+ );
727
+ }
728
+
729
+ const keydownsAfterTicks: number = added.filter((type: string) => {
730
+ return type === "keydown";
731
+ }).length;
732
+
733
+ expect(keydownsAfterMount).toBeGreaterThanOrEqual(1);
734
+ expect(keydownsAfterTicks).toBe(keydownsAfterMount);
735
+ } finally {
736
+ window.addEventListener = original;
737
+ }
738
+ });
739
+ });
740
+
741
+ describe("ReplayScrubber shortcuts sheet", () => {
742
+ it("opens on ? and from the button, and closes on Escape", () => {
743
+ let escapes: number = 0;
744
+
745
+ render(
746
+ <ReplayScrubber
747
+ {...makeProps({
748
+ onEscape: (): void => {
749
+ escapes++;
750
+ },
751
+ })}
752
+ />,
753
+ );
754
+
755
+ expect(screen.queryByTestId("keyboard-shortcuts-modal")).toBeNull();
756
+
757
+ fireEvent.keyDown(document.body, { key: "?", shiftKey: true });
758
+
759
+ expect(screen.getByTestId("keyboard-shortcuts-modal")).toBeInTheDocument();
760
+ expect(screen.getByTestId("shortcut-group-playback")).toBeInTheDocument();
761
+ expect(screen.getByTestId("shortcut-next-error")).toHaveTextContent(
762
+ "Next error",
763
+ );
764
+
765
+ fireEvent.keyDown(document.body, { key: "Escape" });
766
+
767
+ expect(screen.queryByTestId("keyboard-shortcuts-modal")).toBeNull();
768
+ /* Escape closed the sheet; it did not also reach the page. */
769
+ expect(escapes).toBe(0);
770
+
771
+ fireEvent.click(screen.getByTestId("replay-shortcuts-button"));
772
+
773
+ expect(screen.getByTestId("keyboard-shortcuts-modal")).toBeInTheDocument();
774
+ });
775
+ });
776
+
777
+ describe("ReplayScrubber buffering pill", () => {
778
+ beforeEach(() => {
779
+ jest.useFakeTimers();
780
+ });
781
+
782
+ afterEach(() => {
783
+ jest.useRealTimers();
784
+ });
785
+
786
+ it("appears only after the grace period and offers Retry after the hint delay", () => {
787
+ let retries: number = 0;
788
+
789
+ render(
790
+ <ReplayScrubber
791
+ {...makeProps({
792
+ snapshot: makeSnapshot({ buffer: "stalled", intent: "playing" }),
793
+ onRetry: (): void => {
794
+ retries++;
795
+ },
796
+ })}
797
+ />,
798
+ );
799
+
800
+ expect(screen.queryByTestId("replay-buffering-pill")).toBeNull();
801
+
802
+ act((): void => {
803
+ jest.advanceTimersByTime(300);
804
+ });
805
+
806
+ const pill: HTMLElement = screen.getByTestId("replay-buffering-pill");
807
+
808
+ expect(pill).toHaveTextContent("Loading footage");
809
+
810
+ act((): void => {
811
+ jest.advanceTimersByTime(8000);
812
+ });
813
+
814
+ expect(screen.getByTestId("replay-buffering-pill")).toHaveTextContent(
815
+ "Still loading",
816
+ );
817
+
818
+ /*
819
+ * ux-18: the stage overlay announces the phase and owns the Retry.
820
+ * The controls pill is the same words in a second place, so it is
821
+ * visual only - not a live region, and without a duplicate Retry
822
+ * button that a screen reader would read as a second offer.
823
+ */
824
+ expect(pill).not.toHaveAttribute("role", "status");
825
+ expect(pill).toHaveAttribute("aria-hidden", "true");
826
+ expect(screen.queryByTestId("replay-buffering-retry")).toBeNull();
827
+ expect(retries).toBe(0);
828
+ });
829
+
830
+ it("names the seek target while seeking", () => {
831
+ render(
832
+ <ReplayScrubber
833
+ {...makeProps({
834
+ snapshot: makeSnapshot({
835
+ buffer: "building",
836
+ intent: "paused",
837
+ currentTimeMs: 72000,
838
+ pendingSeekMs: 72000,
839
+ }),
840
+ })}
841
+ />,
842
+ );
843
+
844
+ act((): void => {
845
+ jest.advanceTimersByTime(300);
846
+ });
233
847
 
234
- expect(seeks).toEqual([20000, 40000]);
848
+ expect(screen.getByTestId("replay-buffering-pill")).toHaveTextContent(
849
+ "Seeking to 1:12",
850
+ );
235
851
  });
236
852
  });