@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,8 +1,24 @@
1
1
  import { describe, expect, it } from "@jest/globals";
2
- import { SessionReplayChunkManifestEntry } from "../../../Types/Rum/SessionReplay";
2
+ import {
3
+ MAX_SESSION_REPLAY_CHUNKS_PER_READ,
4
+ SessionReplayChunkManifestEntry,
5
+ } from "../../../Types/Rum/SessionReplay";
6
+ import { MAX_PREFETCH_PAGES_AHEAD } from "../../../../App/FeatureSet/Dashboard/src/Components/SessionReplay/ReplayPlaybackIntent";
3
7
  import ChunkLoader, {
8
+ ChunkLoadError,
9
+ DEFAULT_MAX_DECODED_CHUNKS,
10
+ RRWEB_EVENT_TYPE_META,
11
+ RRWEB_MOUSE_INTERACTION_CLICK,
12
+ RRWEB_MOUSE_INTERACTION_TOUCH_START,
13
+ RRWEB_SOURCE_MOUSE_INTERACTION,
14
+ RRWEB_SOURCE_MOUSE_MOVE,
15
+ RRWEB_SOURCE_SCROLL,
4
16
  SessionReplayRecordedEvent,
5
17
  } from "../../../../App/FeatureSet/Dashboard/src/Components/SessionReplay/ChunkLoader";
18
+ import {
19
+ REPLAY_TIMELINE_EXTRACTION_CAPS,
20
+ ReplayTimelineEvent,
21
+ } from "../../../../App/FeatureSet/Dashboard/src/Components/SessionReplay/ReplayTimelineTypes";
6
22
 
7
23
  /*
8
24
  * ChunkLoader lives in the Dashboard but is tested from Common, because it is
@@ -716,6 +732,76 @@ describe("ChunkLoader timeline events", () => {
716
732
  expect(extracted[3]!.message).toBe("");
717
733
  });
718
734
 
735
+ it("carries a network event's trace id through to the panel row", () => {
736
+ /*
737
+ * The link from "this request failed" to the backend trace of the
738
+ * request. The recorder has always put traceId on the network payload
739
+ * (NetworkRecorder.record), and the extractor used to drop it on the
740
+ * floor, so a player that had already downloaded and decoded the id
741
+ * could not offer the one click that makes the correlation useful.
742
+ */
743
+ const extracted: Array<{ kind: string; traceId?: string }> =
744
+ ChunkLoader.extractTimelineEvents(makeEntry(0), [
745
+ { type: 2, timestamp: baseTs, data: {} },
746
+ customEvent(
747
+ "oneuptime.network",
748
+ {
749
+ method: "GET",
750
+ url: "https://api.example.com/cart",
751
+ status: 500,
752
+ durationMs: 40,
753
+ responseBytes: 0,
754
+ traceId: "4bf92f3577b34da6a3ce929d0e0e4736",
755
+ },
756
+ baseTs + 100,
757
+ ) as never,
758
+ ]);
759
+
760
+ expect(extracted[0]!.kind).toBe("network");
761
+ expect(extracted[0]!.traceId).toBe("4bf92f3577b34da6a3ce929d0e0e4736");
762
+ });
763
+
764
+ it("leaves traceId absent rather than empty when there is none", () => {
765
+ /*
766
+ * Absent, not "" — the panel renders a trace link on the presence of
767
+ * the key, and an empty string would put a dead link on every row of
768
+ * an application with no trace propagation configured. An empty or
769
+ * non-string value on the wire has to reach the same absence as a
770
+ * missing one.
771
+ */
772
+ const rows: Array<{ traceId?: string }> = [
773
+ ChunkLoader.extractTimelineEvents(makeEntry(0), [
774
+ { type: 2, timestamp: baseTs, data: {} },
775
+ customEvent(
776
+ "oneuptime.network",
777
+ { method: "GET", url: "/a", status: 200 },
778
+ baseTs + 1,
779
+ ) as never,
780
+ ])[0]!,
781
+ ChunkLoader.extractTimelineEvents(makeEntry(0), [
782
+ { type: 2, timestamp: baseTs, data: {} },
783
+ customEvent(
784
+ "oneuptime.network",
785
+ { method: "GET", url: "/b", status: 200, traceId: "" },
786
+ baseTs + 1,
787
+ ) as never,
788
+ ])[0]!,
789
+ ChunkLoader.extractTimelineEvents(makeEntry(0), [
790
+ { type: 2, timestamp: baseTs, data: {} },
791
+ customEvent(
792
+ "oneuptime.network",
793
+ { method: "GET", url: "/c", status: 200, traceId: 12345 },
794
+ baseTs + 1,
795
+ ) as never,
796
+ ])[0]!,
797
+ ];
798
+
799
+ for (const row of rows) {
800
+ expect(row.traceId).toBeUndefined();
801
+ expect("traceId" in row).toBe(false);
802
+ }
803
+ });
804
+
719
805
  it("clamps a skewed timestamp inside its chunk's window", () => {
720
806
  const extracted: Array<{ offsetMs: number }> =
721
807
  ChunkLoader.extractTimelineEvents(makeEntry(1), [
@@ -784,7 +870,955 @@ describe("ChunkLoader timeline events", () => {
784
870
 
785
871
  await loader.loadPage(0);
786
872
 
787
- expect(loader.getTimelineEvents()).toHaveLength(2000);
873
+ /*
874
+ * Per KIND, not per session: 2100 console lines hit the console cap
875
+ * (1500) and the loader says which kind was cut, so a page that logs in
876
+ * a loop can never push the network or error rows out of the rail.
877
+ */
878
+ expect(loader.getTimelineEvents()).toHaveLength(
879
+ REPLAY_TIMELINE_EXTRACTION_CAPS.console,
880
+ );
788
881
  expect(loader.areTimelineEventsTruncated()).toBe(true);
882
+ expect(loader.getExtractionStats().truncatedKinds).toEqual(["console"]);
883
+ expect(loader.getExtractionStats().countsByKind.console).toBe(
884
+ REPLAY_TIMELINE_EXTRACTION_CAPS.console,
885
+ );
886
+ });
887
+ });
888
+
889
+ /*
890
+ * The upgrades the engine relies on: the priority pair, page-aligned
891
+ * prefetching, retries and timeouts, abort on dispose, terminator rows,
892
+ * live-session appends, stable ids, per-kind caps, every recorder tag,
893
+ * rrweb-derived rows and activity intervals.
894
+ */
895
+
896
+ const CUSTOM_BASE_TS: number = 1_700_000_000_000;
897
+
898
+ function custom(
899
+ tag: string,
900
+ payload: Record<string, unknown>,
901
+ timestamp: number,
902
+ ): SessionReplayRecordedEvent {
903
+ return {
904
+ type: 5,
905
+ timestamp: timestamp,
906
+ data: { tag: tag, payload: payload },
907
+ };
908
+ }
909
+
910
+ function incremental(
911
+ data: Record<string, unknown>,
912
+ timestamp: number,
913
+ ): SessionReplayRecordedEvent {
914
+ return { type: 3, timestamp: timestamp, data: data };
915
+ }
916
+
917
+ /* Lets the loader's own un-awaited follow-up work (loadFirst's page) finish. */
918
+ async function settle(): Promise<void> {
919
+ for (let i: number = 0; i < 4; i++) {
920
+ await new Promise<void>((resolve: () => void) => {
921
+ setTimeout(resolve, 0);
922
+ });
923
+ }
924
+ }
925
+
926
+ function sequentialEntries(
927
+ count: number,
928
+ ): Array<SessionReplayChunkManifestEntry> {
929
+ return Array.from(
930
+ { length: count },
931
+ (_unused: unknown, index: number): SessionReplayChunkManifestEntry => {
932
+ return makeEntry(index, { hasFullSnapshot: index === 0 });
933
+ },
934
+ );
935
+ }
936
+
937
+ describe("ChunkLoader first paint and prefetch", () => {
938
+ it("requests the anchor plus one neighbour first, then the rest of the page", async () => {
939
+ const fetcher: RecordingFetcher = makeFetcher();
940
+ const loader: ChunkLoader = makeLoader(sequentialEntries(24), fetcher);
941
+
942
+ const decoded: Array<number> = await loader.loadFirst(0);
943
+
944
+ expect(decoded).toEqual([0, 1]);
945
+ expect(fetcher.requests[0]).toEqual([0, 1]);
946
+
947
+ /* The page fill-in is queued behind the pair, and never re-asks for it. */
948
+ await new Promise<void>((resolve: () => void) => {
949
+ setTimeout(resolve, 0);
950
+ });
951
+
952
+ expect(fetcher.requests[1]).toEqual([2, 3, 4, 5, 6, 7]);
953
+ });
954
+
955
+ it("borrows the previous chunk when the anchor has none after it", async () => {
956
+ /*
957
+ * A lone oversized FullSnapshot at the end of a tab: the Meta rrweb
958
+ * needs to show the iframe lives in the chunk before it.
959
+ */
960
+ const fetcher: RecordingFetcher = makeFetcher();
961
+ const loader: ChunkLoader = makeLoader(
962
+ [makeEntry(0), makeEntry(1, { hasFullSnapshot: true })],
963
+ fetcher,
964
+ );
965
+
966
+ await loader.loadFirst(1);
967
+
968
+ expect(fetcher.requests[0]).toEqual([0, 1]);
969
+ });
970
+
971
+ it("prefetches in page-aligned requests, never one chunk per fed chunk", async () => {
972
+ /*
973
+ * The old prefetchAfter planned relative to the FED chunk, so the
974
+ * requests degenerated into one single-chunk POST per 15 seconds of
975
+ * footage plus overlapping duplicates right after every rebuild.
976
+ */
977
+ const fetcher: RecordingFetcher = makeFetcher();
978
+ const loader: ChunkLoader = makeLoader(sequentialEntries(24), fetcher);
979
+
980
+ await loader.loadFirst(0);
981
+ await loader.loadPage(0);
982
+ await loader.prefetchAhead(1, 2);
983
+
984
+ /* Feeding chunks one by one asks for nothing new: it is all resident. */
985
+ for (let fed: number = 2; fed < 20; fed++) {
986
+ await loader.ensureChunk(fed);
987
+ await loader.prefetchAhead(fed, 2);
988
+ }
989
+
990
+ expect(fetcher.requests).toEqual([
991
+ [0, 1],
992
+ [2, 3, 4, 5, 6, 7],
993
+ [8, 9, 10, 11, 12, 13, 14, 15],
994
+ [16, 17, 18, 19, 20, 21, 22, 23],
995
+ ]);
996
+ });
997
+
998
+ it("holds enough decoded chunks for the pages the player prefetches", () => {
999
+ /*
1000
+ * The two numbers are not independent. A cache smaller than the
1001
+ * priority pair plus the page being fed plus every page prefetched
1002
+ * past it evicts footage that has been downloaded but not yet fed,
1003
+ * and the feed loop fetches it straight back.
1004
+ */
1005
+ expect(DEFAULT_MAX_DECODED_CHUNKS).toBeGreaterThanOrEqual(
1006
+ 2 + MAX_SESSION_REPLAY_CHUNKS_PER_READ * (1 + MAX_PREFETCH_PAGES_AHEAD),
1007
+ );
1008
+ });
1009
+
1010
+ it("never re-fetches a chunk during a straight playthrough longer than the cache", async () => {
1011
+ /*
1012
+ * The 12x request amplification. With a 24-chunk cache, the priority
1013
+ * pair plus one 8-chunk page plus the two pages prefetched after every
1014
+ * feed filled it exactly, so the next admit evicted the chunks about
1015
+ * to be fed and ensureChunk fetched them again - 95 page requests for a
1016
+ * 60-chunk session, one chunk fetched 17 times, and periodic stalls
1017
+ * because the junk prefetches shared the connection with the fetch on
1018
+ * the critical path.
1019
+ *
1020
+ * 60 entries, deliberately more than the cache holds, fed in order the
1021
+ * way the engine feeds them.
1022
+ */
1023
+ const fetcher: RecordingFetcher = makeFetcher();
1024
+ const loader: ChunkLoader = makeLoader(sequentialEntries(60), fetcher);
1025
+
1026
+ await loader.loadFirst(0);
1027
+ await settle();
1028
+
1029
+ for (let fed: number = 0; fed < 60; fed++) {
1030
+ loader.setFedThrough(fed - 1);
1031
+
1032
+ const events: Array<SessionReplayRecordedEvent> | null =
1033
+ await loader.ensureChunk(fed);
1034
+
1035
+ expect(events).not.toBeNull();
1036
+
1037
+ loader.setFedThrough(fed);
1038
+ /* 4 pages: what the loader must survive at 4x and above. */
1039
+ await loader.prefetchAhead(fed, MAX_PREFETCH_PAGES_AHEAD);
1040
+ }
1041
+
1042
+ const timesRequested: Map<number, number> = new Map<number, number>();
1043
+
1044
+ for (const request of fetcher.requests) {
1045
+ for (const chunkIndex of request) {
1046
+ timesRequested.set(
1047
+ chunkIndex,
1048
+ (timesRequested.get(chunkIndex) ?? 0) + 1,
1049
+ );
1050
+ }
1051
+ }
1052
+
1053
+ const refetched: Array<number> = [...timesRequested.entries()]
1054
+ .filter((pair: [number, number]): boolean => {
1055
+ return pair[1] > 1;
1056
+ })
1057
+ .map((pair: [number, number]): number => {
1058
+ return pair[0];
1059
+ });
1060
+
1061
+ expect(refetched).toEqual([]);
1062
+ /* 60 chunks in 8-chunk pages, plus the priority pair's own request. */
1063
+ expect(fetcher.requests.length).toBeLessThanOrEqual(10);
1064
+ });
1065
+
1066
+ it("evicts footage that has been fed before footage that has not", async () => {
1067
+ /*
1068
+ * Reading a chunk makes it the most recently USED, so once playback
1069
+ * has fed chunks 0..3 the least recently used entries are exactly the
1070
+ * prefetched ones it is about to need. Plain LRU therefore threw away
1071
+ * 4..7 to make room for 8..15 and fetched 4..7 straight back.
1072
+ */
1073
+ const fetcher: RecordingFetcher = makeFetcher();
1074
+ const loader: ChunkLoader = makeLoader(sequentialEntries(20), fetcher, {
1075
+ maxDecodedChunks: 12,
1076
+ });
1077
+
1078
+ await loader.loadPage(0);
1079
+
1080
+ for (let fed: number = 0; fed <= 3; fed++) {
1081
+ loader.getDecodedChunk(fed);
1082
+ }
1083
+
1084
+ loader.setFedThrough(3);
1085
+ await loader.loadPage(8);
1086
+
1087
+ const decoded: Array<number> = loader.getDecodedChunkIndexes();
1088
+
1089
+ expect(decoded).toEqual([4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]);
1090
+ /* The four the player has already watched are the four that went. */
1091
+ expect(decoded).not.toContain(0);
1092
+ });
1093
+
1094
+ it("stops prefetching rather than fetching a page the cache cannot hold", async () => {
1095
+ const fetcher: RecordingFetcher = makeFetcher();
1096
+ const loader: ChunkLoader = makeLoader(sequentialEntries(40), fetcher, {
1097
+ maxDecodedChunks: 16,
1098
+ });
1099
+
1100
+ await loader.loadPage(0);
1101
+ loader.setFedThrough(3);
1102
+ await loader.prefetchAhead(3, 4);
1103
+
1104
+ /*
1105
+ * One more page fits alongside the four chunks still waiting to be
1106
+ * fed; a second would evict the first before anything played it, so
1107
+ * it is left for the moment playback actually asks.
1108
+ */
1109
+ expect(fetcher.requests).toEqual([
1110
+ [0, 1, 2, 3, 4, 5, 6, 7],
1111
+ [8, 9, 10, 11, 12, 13, 14, 15],
1112
+ ]);
1113
+ expect(loader.getDecodedChunkIndexes().length).toBeLessThanOrEqual(16);
1114
+ });
1115
+
1116
+ it("waits for an in-flight request covering the same chunks instead of re-fetching them", async () => {
1117
+ let release: (() => void) | null = null;
1118
+ const gate: Promise<void> = new Promise<void>((resolve: () => void) => {
1119
+ release = resolve;
1120
+ });
1121
+ const requests: Array<Array<number>> = [];
1122
+
1123
+ const loader: ChunkLoader = new ChunkLoader({
1124
+ sessionId: "sess-1",
1125
+ tabId: "tab-1",
1126
+ entries: sequentialEntries(16),
1127
+ fetcher: async (request: {
1128
+ chunkIndexes: Array<number>;
1129
+ }): Promise<ArrayBuffer> => {
1130
+ requests.push([...request.chunkIndexes]);
1131
+ await gate;
1132
+ return encodeFrames(
1133
+ request.chunkIndexes.map(
1134
+ (chunkIndex: number): { chunkIndex: number; body: string } => {
1135
+ return { chunkIndex: chunkIndex, body: bodyFor(chunkIndex) };
1136
+ },
1137
+ ),
1138
+ );
1139
+ },
1140
+ });
1141
+
1142
+ /* Page from 8 overlaps the page from 10 on [10..15]. */
1143
+ const first: Promise<Array<number>> = loader.loadPage(8);
1144
+ const second: Promise<Array<number>> = loader.loadPage(10);
1145
+
1146
+ expect(loader.isChunkInFlight(12)).toBe(true);
1147
+
1148
+ release!();
1149
+ await Promise.all([first, second]);
1150
+
1151
+ expect(requests).toEqual([[8, 9, 10, 11, 12, 13, 14, 15]]);
1152
+ expect(await second).toEqual([10, 11, 12, 13, 14, 15]);
1153
+ expect(loader.isChunkInFlight(12)).toBe(false);
1154
+ });
1155
+ });
1156
+
1157
+ describe("ChunkLoader transport failures", () => {
1158
+ it("retries a failing fetch twice with the configured back-off, then throws a ChunkLoadError", async () => {
1159
+ let attempts: number = 0;
1160
+
1161
+ const loader: ChunkLoader = new ChunkLoader({
1162
+ sessionId: "sess-1",
1163
+ tabId: "tab-1",
1164
+ entries: [makeEntry(0, { hasFullSnapshot: true })],
1165
+ retryDelaysMs: [1, 1],
1166
+ fetcher: (): Promise<ArrayBuffer> => {
1167
+ attempts += 1;
1168
+ return Promise.reject(
1169
+ new Error("Could not load recording data (HTTP 503)."),
1170
+ );
1171
+ },
1172
+ });
1173
+
1174
+ let caught: unknown = null;
1175
+
1176
+ try {
1177
+ await loader.ensureChunk(0);
1178
+ } catch (err) {
1179
+ caught = err;
1180
+ }
1181
+
1182
+ expect(attempts).toBe(3);
1183
+ expect(caught).toBeInstanceOf(ChunkLoadError);
1184
+ expect((caught as ChunkLoadError).attempts).toBe(3);
1185
+ expect((caught as ChunkLoadError).isTimeout).toBe(false);
1186
+ expect((caught as ChunkLoadError).chunkIndexes).toEqual([0]);
1187
+ expect((caught as ChunkLoadError).message).toContain("after 3 attempts");
1188
+ expect((caught as ChunkLoadError).message).toContain("HTTP 503");
1189
+ });
1190
+
1191
+ it("recovers when a retry succeeds", async () => {
1192
+ let attempts: number = 0;
1193
+
1194
+ const loader: ChunkLoader = new ChunkLoader({
1195
+ sessionId: "sess-1",
1196
+ tabId: "tab-1",
1197
+ entries: [makeEntry(0, { hasFullSnapshot: true })],
1198
+ retryDelaysMs: [1, 1],
1199
+ fetcher: (request: {
1200
+ chunkIndexes: Array<number>;
1201
+ }): Promise<ArrayBuffer> => {
1202
+ attempts += 1;
1203
+
1204
+ if (attempts === 1) {
1205
+ return Promise.reject(new Error("blip"));
1206
+ }
1207
+
1208
+ return Promise.resolve(
1209
+ encodeFrames(
1210
+ request.chunkIndexes.map(
1211
+ (chunkIndex: number): { chunkIndex: number; body: string } => {
1212
+ return { chunkIndex: chunkIndex, body: bodyFor(chunkIndex) };
1213
+ },
1214
+ ),
1215
+ ),
1216
+ );
1217
+ },
1218
+ });
1219
+
1220
+ const events: Array<SessionReplayRecordedEvent> | null =
1221
+ await loader.ensureChunk(0);
1222
+
1223
+ expect(attempts).toBe(2);
1224
+ expect(events).not.toBeNull();
1225
+ expect(loader.getDecodedChunkIndexes()).toEqual([0]);
1226
+ });
1227
+
1228
+ it("times out a hung request, even when the transport ignores the signal", async () => {
1229
+ let attempts: number = 0;
1230
+
1231
+ const loader: ChunkLoader = new ChunkLoader({
1232
+ sessionId: "sess-1",
1233
+ tabId: "tab-1",
1234
+ entries: [makeEntry(0, { hasFullSnapshot: true })],
1235
+ fetchTimeoutMs: 5,
1236
+ retryDelaysMs: [1, 1],
1237
+ fetcher: (): Promise<ArrayBuffer> => {
1238
+ attempts += 1;
1239
+ return new Promise<ArrayBuffer>((): void => {
1240
+ // Never resolves.
1241
+ });
1242
+ },
1243
+ });
1244
+
1245
+ let caught: unknown = null;
1246
+
1247
+ try {
1248
+ await loader.ensureChunk(0);
1249
+ } catch (err) {
1250
+ caught = err;
1251
+ }
1252
+
1253
+ expect(attempts).toBe(3);
1254
+ expect((caught as ChunkLoadError).isTimeout).toBe(true);
1255
+ expect((caught as ChunkLoadError).message).toContain("no response within");
1256
+ });
1257
+
1258
+ it("hands the transport an abort signal and fires it on dispose", async () => {
1259
+ const signals: Array<AbortSignal> = [];
1260
+
1261
+ const loader: ChunkLoader = new ChunkLoader({
1262
+ sessionId: "sess-1",
1263
+ tabId: "tab-1",
1264
+ entries: [makeEntry(0, { hasFullSnapshot: true })],
1265
+ fetcher: (request: { signal?: AbortSignal }): Promise<ArrayBuffer> => {
1266
+ if (request.signal) {
1267
+ signals.push(request.signal);
1268
+ }
1269
+
1270
+ return new Promise<ArrayBuffer>((): void => {
1271
+ // Never resolves; dispose is what ends it.
1272
+ });
1273
+ },
1274
+ });
1275
+
1276
+ const pending: Promise<Array<number>> = loader.loadPage(0);
1277
+
1278
+ expect(signals.length).toBe(1);
1279
+ expect(signals[0]!.aborted).toBe(false);
1280
+
1281
+ loader.dispose();
1282
+
1283
+ expect(signals[0]!.aborted).toBe(true);
1284
+ /* Aborted by the viewer leaving: quiet, not an error. */
1285
+ await expect(pending).resolves.toEqual([]);
1286
+ });
1287
+ });
1288
+
1289
+ describe("ChunkLoader terminators and appends", () => {
1290
+ it("treats a zero-event closing chunk as the end of footage, not as a chunk to feed", () => {
1291
+ /*
1292
+ * The recorder emits `[]` with eventCount 0 at tab close and at the
1293
+ * chunk cap, stamped with the close time. It used to reach the feeder
1294
+ * as "undecodable" and end most sessions with an error banner.
1295
+ */
1296
+ const loader: ChunkLoader = makeLoader(
1297
+ [
1298
+ makeEntry(0, { hasFullSnapshot: true }),
1299
+ makeEntry(1),
1300
+ { ...makeEntry(2), eventCount: 0, chunkEndOffsetMs: 10 * CHUNK_MS },
1301
+ ],
1302
+ makeFetcher(),
1303
+ );
1304
+
1305
+ expect(loader.getNextChunk(1)).toBeNull();
1306
+ expect(loader.getDurationMs()).toBe(2 * CHUNK_MS);
1307
+ expect(loader.getRecordedEndMs()).toBe(10 * CHUNK_MS);
1308
+ expect(loader.planPage(0)).toEqual([0, 1]);
1309
+ expect(loader.getPlayableEntries()).toHaveLength(2);
1310
+ expect(
1311
+ loader
1312
+ .getTerminatorEntries()
1313
+ .map((e: SessionReplayChunkManifestEntry): number => {
1314
+ return e.chunkIndex;
1315
+ }),
1316
+ ).toEqual([2]);
1317
+ expect(loader.getChunkIndexForOffset(5 * CHUNK_MS)).toBe(1);
1318
+ });
1319
+
1320
+ it("steps over an empty chunk in the middle without reporting a gap", () => {
1321
+ const loader: ChunkLoader = makeLoader(
1322
+ [
1323
+ makeEntry(0, { hasFullSnapshot: true }),
1324
+ { ...makeEntry(1), eventCount: 0 },
1325
+ makeEntry(2),
1326
+ ],
1327
+ makeFetcher(),
1328
+ );
1329
+
1330
+ expect(loader.getNextChunk(0)).toEqual({ chunkIndex: 2, skippedGap: null });
1331
+ expect(loader.getGaps()).toEqual([]);
1332
+ });
1333
+
1334
+ it("resolves null for a terminator rather than fetching it", async () => {
1335
+ const fetcher: RecordingFetcher = makeFetcher();
1336
+ const loader: ChunkLoader = makeLoader(
1337
+ [
1338
+ makeEntry(0, { hasFullSnapshot: true }),
1339
+ { ...makeEntry(1), eventCount: 0 },
1340
+ ],
1341
+ fetcher,
1342
+ );
1343
+
1344
+ await expect(loader.ensureChunk(1)).resolves.toBeNull();
1345
+ expect(fetcher.requests).toEqual([]);
1346
+ });
1347
+
1348
+ it("appends live manifest rows in order and recomputes gaps and duration", () => {
1349
+ const loader: ChunkLoader = makeLoader(
1350
+ [makeEntry(0, { hasFullSnapshot: true }), makeEntry(1)],
1351
+ makeFetcher(),
1352
+ );
1353
+
1354
+ expect(loader.getDurationMs()).toBe(2 * CHUNK_MS);
1355
+ expect(loader.getNextChunk(1)).toBeNull();
1356
+
1357
+ const added: number = loader.appendEntries([
1358
+ makeEntry(4, { hasFullSnapshot: true }),
1359
+ makeEntry(2),
1360
+ makeEntry(1),
1361
+ ]);
1362
+
1363
+ expect(added).toBe(2);
1364
+ expect(
1365
+ loader
1366
+ .getEntries()
1367
+ .map((entry: SessionReplayChunkManifestEntry): number => {
1368
+ return entry.chunkIndex;
1369
+ }),
1370
+ ).toEqual([0, 1, 2, 4]);
1371
+ expect(loader.getDurationMs()).toBe(5 * CHUNK_MS);
1372
+ expect(loader.getGaps()).toEqual([
1373
+ { fromIndex: 2, toIndex: 4, missingMs: CHUNK_MS },
1374
+ ]);
1375
+ expect(loader.getFullSnapshotChunkIndexes()).toEqual([0, 4]);
1376
+ expect(loader.getNextChunk(1)).toEqual({ chunkIndex: 2, skippedGap: null });
1377
+ });
1378
+ });
1379
+
1380
+ describe("ChunkLoader signal extraction", () => {
1381
+ it("assigns stable rec:<chunk>:<ordinal> ids that survive eviction and re-admission", async () => {
1382
+ const fetcher: RecordingFetcher = makeFetcher({
1383
+ payloadFor: (): string => {
1384
+ return JSON.stringify([
1385
+ { type: 2, timestamp: CUSTOM_BASE_TS, data: {} },
1386
+ custom(
1387
+ "oneuptime.console",
1388
+ { level: "warn", message: "a" },
1389
+ CUSTOM_BASE_TS + 100,
1390
+ ),
1391
+ custom(
1392
+ "oneuptime.console",
1393
+ { level: "error", message: "b" },
1394
+ CUSTOM_BASE_TS + 200,
1395
+ ),
1396
+ ]);
1397
+ },
1398
+ });
1399
+ const loader: ChunkLoader = makeLoader(
1400
+ [makeEntry(0, { hasFullSnapshot: true }), makeEntry(3)],
1401
+ fetcher,
1402
+ );
1403
+
1404
+ await loader.loadPage(0);
1405
+
1406
+ const before: Array<string> = loader
1407
+ .getTimelineEvents()
1408
+ .map((event: ReplayTimelineEvent): string => {
1409
+ return event.id;
1410
+ });
1411
+
1412
+ expect(before).toEqual(["rec:0:0", "rec:0:1", "rec:3:0", "rec:3:1"]);
1413
+
1414
+ loader.evictOutsideWindow(99, 0);
1415
+ await loader.loadPage(0);
1416
+
1417
+ expect(
1418
+ loader.getTimelineEvents().map((event: ReplayTimelineEvent): string => {
1419
+ return event.id;
1420
+ }),
1421
+ ).toEqual(before);
1422
+ });
1423
+
1424
+ it("extracts every recorder tag with its payload fields", () => {
1425
+ const rows: Array<ReplayTimelineEvent> = ChunkLoader.extractTimelineEvents(
1426
+ makeEntry(0),
1427
+ [
1428
+ { type: 2, timestamp: CUSTOM_BASE_TS, data: {} },
1429
+ custom(
1430
+ "oneuptime.error",
1431
+ {
1432
+ kind: "unhandledrejection",
1433
+ message: "boom",
1434
+ source: "app.js",
1435
+ lineNumber: 12,
1436
+ columnNumber: 4,
1437
+ stack: "Error: boom\n at x",
1438
+ occurredAtUnixMs: CUSTOM_BASE_TS - 5000,
1439
+ },
1440
+ CUSTOM_BASE_TS + 10,
1441
+ ),
1442
+ custom(
1443
+ "oneuptime.frustration",
1444
+ {
1445
+ kind: "rage-click",
1446
+ atUnixMs: CUSTOM_BASE_TS + 20,
1447
+ x: 10,
1448
+ y: 20,
1449
+ clickCount: 5,
1450
+ },
1451
+ CUSTOM_BASE_TS + 20,
1452
+ ),
1453
+ custom(
1454
+ "oneuptime.performance",
1455
+ { kind: "lcp", durationMs: 4800, budgetMs: 4000, url: "/checkout" },
1456
+ CUSTOM_BASE_TS + 30,
1457
+ ),
1458
+ custom(
1459
+ "oneuptime.performance",
1460
+ { kind: "web-vital", metric: "INP", value: 320, rating: "poor" },
1461
+ CUSTOM_BASE_TS + 40,
1462
+ ),
1463
+ custom(
1464
+ "oneuptime.click",
1465
+ {
1466
+ selector: "button.pay",
1467
+ text: "Pay now",
1468
+ x: 1,
1469
+ y: 2,
1470
+ atUnixMs: CUSTOM_BASE_TS + 50,
1471
+ },
1472
+ CUSTOM_BASE_TS + 50,
1473
+ ),
1474
+ custom("oneuptime.click-dropped", { count: 7 }, CUSTOM_BASE_TS + 60),
1475
+ custom(
1476
+ "oneuptime.visibility",
1477
+ { state: "hidden", atUnixMs: CUSTOM_BASE_TS + 70 },
1478
+ CUSTOM_BASE_TS + 70,
1479
+ ),
1480
+ custom(
1481
+ "oneuptime.custom",
1482
+ { name: "checkout_started", properties: { plan: "pro" } },
1483
+ CUSTOM_BASE_TS + 80,
1484
+ ),
1485
+ custom("oneuptime.custom-dropped", { count: 3 }, CUSTOM_BASE_TS + 90),
1486
+ custom("oneuptime.identify", { hasTraits: true }, CUSTOM_BASE_TS + 100),
1487
+ custom(
1488
+ "oneuptime.tags",
1489
+ { tags: { tenant: "acme" } },
1490
+ CUSTOM_BASE_TS + 110,
1491
+ ),
1492
+ custom(
1493
+ "oneuptime.network",
1494
+ {
1495
+ method: "POST",
1496
+ url: "/api/orders",
1497
+ status: 500,
1498
+ durationMs: 220,
1499
+ responseBytes: 512,
1500
+ requestBytes: 64,
1501
+ isError: true,
1502
+ initiator: "fetch",
1503
+ traceId: "abc",
1504
+ },
1505
+ CUSTOM_BASE_TS + 120,
1506
+ ),
1507
+ custom(
1508
+ "oneuptime.route",
1509
+ { from: "/cart", to: "/checkout", kind: "pushState" },
1510
+ CUSTOM_BASE_TS + 130,
1511
+ ),
1512
+ ],
1513
+ );
1514
+
1515
+ const byKind: Map<string, ReplayTimelineEvent> = new Map<
1516
+ string,
1517
+ ReplayTimelineEvent
1518
+ >();
1519
+
1520
+ for (const row of rows) {
1521
+ if (!byKind.has(row.kind)) {
1522
+ byKind.set(row.kind, row);
1523
+ }
1524
+ }
1525
+
1526
+ expect([...byKind.keys()].sort()).toEqual(
1527
+ [
1528
+ "error",
1529
+ "frustration",
1530
+ "performance",
1531
+ "click",
1532
+ "click-dropped",
1533
+ "visibility",
1534
+ "custom",
1535
+ "custom-dropped",
1536
+ "identify",
1537
+ "tags",
1538
+ "network",
1539
+ "route",
1540
+ ].sort(),
1541
+ );
1542
+
1543
+ expect(byKind.get("error")).toEqual(
1544
+ expect.objectContaining({
1545
+ errorKind: "unhandledrejection",
1546
+ lineNumber: 12,
1547
+ columnNumber: 4,
1548
+ stack: "Error: boom\n at x",
1549
+ atUnixMs: CUSTOM_BASE_TS - 5000,
1550
+ }),
1551
+ );
1552
+ expect(byKind.get("frustration")).toEqual(
1553
+ expect.objectContaining({
1554
+ frustrationKind: "rage-click",
1555
+ x: 10,
1556
+ y: 20,
1557
+ clickCount: 5,
1558
+ }),
1559
+ );
1560
+ expect(byKind.get("performance")).toEqual(
1561
+ expect.objectContaining({
1562
+ performanceKind: "lcp",
1563
+ durationMs: 4800,
1564
+ budgetMs: 4000,
1565
+ url: "/checkout",
1566
+ }),
1567
+ );
1568
+ expect(
1569
+ rows.find((row: ReplayTimelineEvent): boolean => {
1570
+ return row.metric === "INP";
1571
+ }),
1572
+ ).toEqual(
1573
+ expect.objectContaining({
1574
+ performanceKind: "web-vital",
1575
+ value: 320,
1576
+ rating: "poor",
1577
+ }),
1578
+ );
1579
+ expect(byKind.get("click")).toEqual(
1580
+ expect.objectContaining({
1581
+ selector: "button.pay",
1582
+ text: "Pay now",
1583
+ x: 1,
1584
+ y: 2,
1585
+ }),
1586
+ );
1587
+ expect(byKind.get("click-dropped")?.droppedCount).toBe(7);
1588
+ expect(byKind.get("visibility")?.visibilityState).toBe("hidden");
1589
+ expect(byKind.get("custom")).toEqual(
1590
+ expect.objectContaining({
1591
+ name: "checkout_started",
1592
+ properties: { plan: "pro" },
1593
+ }),
1594
+ );
1595
+ expect(byKind.get("custom-dropped")?.droppedCount).toBe(3);
1596
+ expect(byKind.get("identify")?.hasTraits).toBe(true);
1597
+ expect(byKind.get("tags")?.tags).toEqual({ tenant: "acme" });
1598
+ expect(byKind.get("network")).toEqual(
1599
+ expect.objectContaining({
1600
+ requestBytes: 64,
1601
+ isError: true,
1602
+ initiator: "fetch",
1603
+ traceId: "abc",
1604
+ }),
1605
+ );
1606
+ expect(byKind.get("route")?.routeKind).toBe("pushState");
1607
+ });
1608
+
1609
+ it("places a performance row when the entry happened, not when the recorder emitted it", () => {
1610
+ /*
1611
+ * Performance entries are delivered late by design: a buffered LCP
1612
+ * arrives at its observer callback, a long task after it ends, and
1613
+ * CLS/INP only settle at page hide. Placing the row at the rrweb
1614
+ * event's timestamp put the marker wherever the event queue flushed,
1615
+ * which for a web vital is the end of the recording rather than the
1616
+ * moment the number describes.
1617
+ */
1618
+ const rows: Array<ReplayTimelineEvent> = ChunkLoader.extractTimelineEvents(
1619
+ makeEntry(0),
1620
+ [
1621
+ { type: 2, timestamp: CUSTOM_BASE_TS, data: {} },
1622
+ custom(
1623
+ "oneuptime.performance",
1624
+ {
1625
+ kind: "web-vital",
1626
+ metric: "LCP",
1627
+ value: 2400,
1628
+ rating: "poor",
1629
+ occurredAtUnixMs: CUSTOM_BASE_TS + 2400,
1630
+ },
1631
+ /* Reported 12 seconds later, at page hide. */
1632
+ CUSTOM_BASE_TS + 12000,
1633
+ ),
1634
+ custom(
1635
+ "oneuptime.performance",
1636
+ { kind: "long-task", durationMs: 180, budgetMs: 50 },
1637
+ CUSTOM_BASE_TS + 9000,
1638
+ ),
1639
+ ],
1640
+ );
1641
+
1642
+ const vital: ReplayTimelineEvent | undefined = rows.find(
1643
+ (row: ReplayTimelineEvent): boolean => {
1644
+ return row.metric === "LCP";
1645
+ },
1646
+ );
1647
+ const longTask: ReplayTimelineEvent | undefined = rows.find(
1648
+ (row: ReplayTimelineEvent): boolean => {
1649
+ return row.performanceKind === "long-task";
1650
+ },
1651
+ );
1652
+
1653
+ expect(vital?.offsetMs).toBe(2400);
1654
+ /* No occurredAtUnixMs: the event's own timestamp still stands. */
1655
+ expect(longTask?.offsetMs).toBe(9000);
1656
+ });
1657
+
1658
+ it("turns rrweb Meta events into navigation rows carrying the viewport", () => {
1659
+ const rows: Array<ReplayTimelineEvent> = ChunkLoader.extractTimelineEvents(
1660
+ makeEntry(0),
1661
+ [
1662
+ {
1663
+ type: RRWEB_EVENT_TYPE_META,
1664
+ timestamp: CUSTOM_BASE_TS,
1665
+ data: {
1666
+ href: "https://app.example.com/start",
1667
+ width: 1440,
1668
+ height: 900,
1669
+ },
1670
+ },
1671
+ { type: 2, timestamp: CUSTOM_BASE_TS + 1, data: {} },
1672
+ ],
1673
+ );
1674
+
1675
+ expect(rows).toEqual([
1676
+ {
1677
+ id: "rec:0:0",
1678
+ kind: "navigation",
1679
+ chunkIndex: 0,
1680
+ offsetMs: 0,
1681
+ to: "https://app.example.com/start",
1682
+ viewportWidth: 1440,
1683
+ viewportHeight: 900,
1684
+ },
1685
+ ]);
1686
+ });
1687
+
1688
+ it("derives click rows from rrweb MouseInteraction only when the chunk carries no oneuptime.click", () => {
1689
+ const rrwebClick: SessionReplayRecordedEvent = incremental(
1690
+ {
1691
+ source: RRWEB_SOURCE_MOUSE_INTERACTION,
1692
+ type: RRWEB_MOUSE_INTERACTION_CLICK,
1693
+ id: 4,
1694
+ x: 30,
1695
+ y: 40,
1696
+ },
1697
+ CUSTOM_BASE_TS + 100,
1698
+ );
1699
+ const rrwebTouch: SessionReplayRecordedEvent = incremental(
1700
+ {
1701
+ source: RRWEB_SOURCE_MOUSE_INTERACTION,
1702
+ type: RRWEB_MOUSE_INTERACTION_TOUCH_START,
1703
+ id: 4,
1704
+ x: 5,
1705
+ y: 6,
1706
+ },
1707
+ CUSTOM_BASE_TS + 200,
1708
+ );
1709
+
1710
+ /* An old recording: only rrweb's own interactions. */
1711
+ const legacy: Array<ReplayTimelineEvent> =
1712
+ ChunkLoader.extractTimelineEvents(makeEntry(0), [
1713
+ { type: 2, timestamp: CUSTOM_BASE_TS, data: {} },
1714
+ rrwebClick,
1715
+ rrwebTouch,
1716
+ ]);
1717
+
1718
+ expect(
1719
+ legacy.map(
1720
+ (
1721
+ row: ReplayTimelineEvent,
1722
+ ): [string, number | undefined, number | undefined] => {
1723
+ return [row.kind, row.x, row.y];
1724
+ },
1725
+ ),
1726
+ ).toEqual([
1727
+ ["click", 30, 40],
1728
+ ["click", 5, 6],
1729
+ ]);
1730
+ expect(legacy[0]?.selector).toBeUndefined();
1731
+
1732
+ /* A current recording: the labelled click wins, the fallback is dropped. */
1733
+ const labelled: Array<ReplayTimelineEvent> =
1734
+ ChunkLoader.extractTimelineEvents(makeEntry(0), [
1735
+ { type: 2, timestamp: CUSTOM_BASE_TS, data: {} },
1736
+ rrwebClick,
1737
+ custom(
1738
+ "oneuptime.click",
1739
+ { selector: "a.nav", x: 30, y: 40, atUnixMs: CUSTOM_BASE_TS + 100 },
1740
+ CUSTOM_BASE_TS + 100,
1741
+ ),
1742
+ ]);
1743
+
1744
+ expect(labelled).toHaveLength(1);
1745
+ expect(labelled[0]?.selector).toBe("a.nav");
1746
+ });
1747
+
1748
+ it("builds activity intervals from user-input sources and recorder activity tags", () => {
1749
+ const { activityIntervals } = ChunkLoader.extractChunk(makeEntry(2), [
1750
+ { type: 2, timestamp: CUSTOM_BASE_TS, data: {} },
1751
+ incremental({ source: RRWEB_SOURCE_MOUSE_MOVE }, CUSTOM_BASE_TS + 1000),
1752
+ incremental({ source: RRWEB_SOURCE_SCROLL }, CUSTOM_BASE_TS + 2000),
1753
+ /* A mutation is the page doing something, not the user. */
1754
+ incremental({ source: 0 }, CUSTOM_BASE_TS + 6000),
1755
+ custom(
1756
+ "oneuptime.route",
1757
+ { from: "/a", to: "/b", kind: "pushState" },
1758
+ CUSTOM_BASE_TS + 9000,
1759
+ ),
1760
+ incremental({ source: RRWEB_SOURCE_MOUSE_MOVE }, CUSTOM_BASE_TS + 13000),
1761
+ ]);
1762
+
1763
+ /*
1764
+ * Chunk 2 starts at 30s. 1s and 2s are one stretch; 9s is 7s later, so
1765
+ * a new one; 13s is within the 5s threshold of 9s, so it extends it.
1766
+ */
1767
+ expect(activityIntervals).toEqual([
1768
+ {
1769
+ startMs: 2 * CHUNK_MS + 1000,
1770
+ endMs: 2 * CHUNK_MS + 2000,
1771
+ chunkIndex: 2,
1772
+ },
1773
+ {
1774
+ startMs: 2 * CHUNK_MS + 9000,
1775
+ endMs: 2 * CHUNK_MS + 13000,
1776
+ chunkIndex: 2,
1777
+ },
1778
+ ]);
1779
+ });
1780
+
1781
+ it("reports per-kind counts and activity through the extraction stats", async () => {
1782
+ const fetcher: RecordingFetcher = makeFetcher({
1783
+ payloadFor: (): string => {
1784
+ return JSON.stringify([
1785
+ { type: 2, timestamp: CUSTOM_BASE_TS, data: {} },
1786
+ incremental(
1787
+ { source: RRWEB_SOURCE_MOUSE_MOVE },
1788
+ CUSTOM_BASE_TS + 500,
1789
+ ),
1790
+ custom(
1791
+ "oneuptime.console",
1792
+ { level: "warn", message: "x" },
1793
+ CUSTOM_BASE_TS + 600,
1794
+ ),
1795
+ ]);
1796
+ },
1797
+ });
1798
+ const loader: ChunkLoader = makeLoader(
1799
+ [makeEntry(0, { hasFullSnapshot: true }), makeEntry(1)],
1800
+ fetcher,
1801
+ );
1802
+
1803
+ await loader.loadPage(0);
1804
+
1805
+ const stats: {
1806
+ countsByKind: Partial<Record<string, number>>;
1807
+ truncatedKinds: Array<string>;
1808
+ activityIntervals: Array<{ chunkIndex: number }>;
1809
+ } = loader.getExtractionStats();
1810
+
1811
+ expect(stats.countsByKind["console"]).toBe(2);
1812
+ expect(stats.truncatedKinds).toEqual([]);
1813
+ expect(
1814
+ stats.activityIntervals.map(
1815
+ (interval: { chunkIndex: number }): number => {
1816
+ return interval.chunkIndex;
1817
+ },
1818
+ ),
1819
+ ).toEqual([0, 1]);
1820
+ expect(loader.getActivityIntervalsForChunk(1)).toHaveLength(1);
1821
+ expect(loader.getActivityIntervalsForChunk(5)).toBeNull();
1822
+ expect(loader.getTimelineEventsForChunk(0)).toHaveLength(1);
789
1823
  });
790
1824
  });