@oneuptime/common 12.0.30 → 12.0.31

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 (489) hide show
  1. package/Models/AnalyticsModels/SecurityEvent.ts +48 -16
  2. package/Models/AnalyticsModels/ThreatIntelIndicator.ts +10 -5
  3. package/Models/DatabaseModels/AlertSeverity.ts +44 -0
  4. package/Models/DatabaseModels/DetectionRule.ts +16 -5
  5. package/Models/DatabaseModels/GoogleSecOpsConnection.ts +14 -5
  6. package/Models/DatabaseModels/IncidentSeverity.ts +44 -0
  7. package/Models/DatabaseModels/Index.ts +2 -0
  8. package/Models/DatabaseModels/NetworkDevice.ts +113 -3
  9. package/Models/DatabaseModels/NetworkDeviceAutoImportRule.ts +88 -0
  10. package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +22 -0
  11. package/Models/DatabaseModels/NetworkDeviceOidTemplate.ts +499 -0
  12. package/Models/DatabaseModels/ThreatIntelFeed.ts +16 -5
  13. package/Server/API/GlobalConfigAPI.ts +362 -183
  14. package/Server/API/TelemetryAPI.ts +42 -4
  15. package/Server/EnvironmentConfig.ts +112 -0
  16. package/Server/Infrastructure/Postgres/SchemaMigrations/1790500000000-AddNetworkDeviceOidTemplate.ts +59 -0
  17. package/Server/Infrastructure/Postgres/SchemaMigrations/1790600000000-AddAutoImportRuleOidTemplate.ts +25 -0
  18. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
  19. package/Server/Middleware/MultipartFormData.ts +118 -32
  20. package/Server/Services/AlertEpisodeLabelRuleEngineService.ts +9 -1
  21. package/Server/Services/AlertEpisodeOnCallRuleEngineService.ts +9 -1
  22. package/Server/Services/AlertEpisodeOwnerRuleEngineService.ts +9 -1
  23. package/Server/Services/AlertEpisodePrivacyRuleEngineService.ts +9 -1
  24. package/Server/Services/AlertGroupingEngineService.ts +9 -1
  25. package/Server/Services/AlertLabelRuleEngineService.ts +9 -1
  26. package/Server/Services/AlertOnCallRuleEngineService.ts +9 -1
  27. package/Server/Services/AlertOwnerRuleEngineService.ts +9 -1
  28. package/Server/Services/AlertPrivacyRuleEngineService.ts +9 -1
  29. package/Server/Services/AlertReminderRuleService.ts +9 -1
  30. package/Server/Services/AutoRemediationRuleEngineService.ts +9 -1
  31. package/Server/Services/CephClusterLabelRuleEngineService.ts +9 -1
  32. package/Server/Services/CephClusterOwnerRuleEngineService.ts +9 -1
  33. package/Server/Services/CloudResourceLabelRuleEngineService.ts +9 -1
  34. package/Server/Services/CloudResourceOwnerRuleEngineService.ts +9 -1
  35. package/Server/Services/DashboardLabelRuleEngineService.ts +9 -1
  36. package/Server/Services/DashboardOwnerRuleEngineService.ts +9 -1
  37. package/Server/Services/DockerHostLabelRuleEngineService.ts +9 -1
  38. package/Server/Services/DockerHostOwnerRuleEngineService.ts +9 -1
  39. package/Server/Services/DockerSwarmClusterLabelRuleEngineService.ts +9 -1
  40. package/Server/Services/DockerSwarmClusterOwnerRuleEngineService.ts +9 -1
  41. package/Server/Services/HostLabelRuleEngineService.ts +9 -1
  42. package/Server/Services/HostOwnerRuleEngineService.ts +9 -1
  43. package/Server/Services/IncidentEpisodeLabelRuleEngineService.ts +9 -1
  44. package/Server/Services/IncidentEpisodeOnCallRuleEngineService.ts +9 -1
  45. package/Server/Services/IncidentEpisodeOwnerRuleEngineService.ts +9 -1
  46. package/Server/Services/IncidentEpisodePrivacyRuleEngineService.ts +9 -1
  47. package/Server/Services/IncidentGroupingEngineService.ts +9 -1
  48. package/Server/Services/IncidentLabelRuleEngineService.ts +9 -1
  49. package/Server/Services/IncidentOnCallRuleEngineService.ts +9 -1
  50. package/Server/Services/IncidentOwnerRuleEngineService.ts +9 -1
  51. package/Server/Services/IncidentPrivacyRuleEngineService.ts +9 -1
  52. package/Server/Services/IncidentReminderRuleService.ts +9 -1
  53. package/Server/Services/IncidentSlaRuleService.ts +9 -1
  54. package/Server/Services/IncomingCallPolicyLabelRuleEngineService.ts +9 -1
  55. package/Server/Services/IncomingCallPolicyOwnerRuleEngineService.ts +9 -1
  56. package/Server/Services/Index.ts +2 -0
  57. package/Server/Services/IoTFleetLabelRuleEngineService.ts +9 -1
  58. package/Server/Services/IoTFleetOwnerRuleEngineService.ts +9 -1
  59. package/Server/Services/KubernetesClusterLabelRuleEngineService.ts +9 -1
  60. package/Server/Services/KubernetesClusterOwnerRuleEngineService.ts +9 -1
  61. package/Server/Services/KubernetesResourceService.ts +5 -1
  62. package/Server/Services/MonitorLabelRuleEngineService.ts +9 -1
  63. package/Server/Services/MonitorOwnerRuleEngineService.ts +9 -1
  64. package/Server/Services/NetworkDeviceAutoImportRuleEngineService.ts +35 -0
  65. package/Server/Services/NetworkDeviceAutoImportRuleService.ts +96 -0
  66. package/Server/Services/NetworkDeviceLabelRuleEngineService.ts +9 -1
  67. package/Server/Services/NetworkDeviceOidTemplateService.ts +201 -0
  68. package/Server/Services/NetworkDeviceOwnerRuleEngineService.ts +9 -1
  69. package/Server/Services/NetworkDeviceService.ts +209 -1
  70. package/Server/Services/OnCallDutyPolicyLabelRuleEngineService.ts +9 -1
  71. package/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.ts +9 -1
  72. package/Server/Services/OnCallDutyPolicyScheduleLabelRuleEngineService.ts +9 -1
  73. package/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.ts +9 -1
  74. package/Server/Services/PodmanHostLabelRuleEngineService.ts +9 -1
  75. package/Server/Services/PodmanHostOwnerRuleEngineService.ts +9 -1
  76. package/Server/Services/ProxmoxClusterLabelRuleEngineService.ts +9 -1
  77. package/Server/Services/ProxmoxClusterOwnerRuleEngineService.ts +9 -1
  78. package/Server/Services/RumApplicationLabelRuleEngineService.ts +9 -1
  79. package/Server/Services/RumApplicationOwnerRuleEngineService.ts +9 -1
  80. package/Server/Services/RunbookLabelRuleEngineService.ts +9 -1
  81. package/Server/Services/RunbookOwnerRuleEngineService.ts +9 -1
  82. package/Server/Services/RunbookRuleEngineService.ts +9 -1
  83. package/Server/Services/ScheduledMaintenanceLabelRuleEngineService.ts +9 -1
  84. package/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.ts +9 -1
  85. package/Server/Services/ScheduledMaintenanceReminderRuleService.ts +9 -1
  86. package/Server/Services/ServerlessFunctionLabelRuleEngineService.ts +9 -1
  87. package/Server/Services/ServerlessFunctionOwnerRuleEngineService.ts +9 -1
  88. package/Server/Services/ServiceLabelRuleEngineService.ts +9 -1
  89. package/Server/Services/ServiceOwnerRuleEngineService.ts +9 -1
  90. package/Server/Services/StatusPageLabelRuleEngineService.ts +9 -1
  91. package/Server/Services/StatusPageMonitorRuleEngineService.ts +7 -0
  92. package/Server/Services/StatusPageOwnerRuleEngineService.ts +9 -1
  93. package/Server/Services/TelemetrySourceMapService.ts +266 -23
  94. package/Server/Services/UserService.ts +27 -0
  95. package/Server/Services/WorkflowLabelRuleEngineService.ts +9 -1
  96. package/Server/Services/WorkflowOwnerRuleEngineService.ts +9 -1
  97. package/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.ts +186 -0
  98. package/Server/Utils/Monitor/CapturedMetricAttributeUtil.ts +245 -0
  99. package/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.ts +21 -2
  100. package/Server/Utils/Monitor/MonitorMetricUtil.ts +55 -21
  101. package/Server/Utils/Monitor/MonitorTemplateUtil.ts +32 -0
  102. package/Server/Utils/Monitor/NetworkDeviceMetricUtil.ts +15 -2
  103. package/Server/Utils/Monitor/NetworkDeviceWalkUtil.ts +18 -1
  104. package/Server/Utils/Monitor/NetworkInventoryUtil.ts +10 -0
  105. package/Server/Utils/Monitor/SeriesResourceLabels.ts +34 -0
  106. package/Server/Utils/Rules/RuleEngineRuleRead.ts +48 -0
  107. package/Server/Utils/Telemetry/ExceptionSanitizer.ts +14 -1
  108. package/Server/Utils/Telemetry/LogExceptionExtractor.ts +14 -2
  109. package/Server/Utils/Telemetry/SourceMapResolver.ts +16 -5
  110. package/Server/Utils/Telemetry/StackTraceParser.ts +399 -0
  111. package/Tests/App/Dashboard/EventOverlayHook.test.tsx +125 -0
  112. package/Tests/App/Dashboard/HeaderImageAssets.test.tsx +93 -0
  113. package/Tests/App/Dashboard/OnCallReadinessSurfaces.test.tsx +3 -3
  114. package/Tests/App/Dashboard/UserElementEmail.test.tsx +12 -4
  115. package/Tests/App/Dashboard/UserEmailCallSites.test.tsx +1 -1
  116. package/Tests/Models/DatabaseModels/DomainRoleTierCoverage.test.ts +14 -0
  117. package/Tests/Models/DatabaseModels/ModelRegistryInvariants.test.ts +469 -0
  118. package/Tests/Models/SecurityDomainAccessControl.test.ts +429 -0
  119. package/Tests/Server/API/GlobalConfigLicense.test.ts +657 -0
  120. package/Tests/Server/API/SecurityEventAttributesAPI.test.ts +84 -6
  121. package/Tests/Server/API/TelemetryResolveStackTraceAPI.test.ts +805 -0
  122. package/Tests/Server/Infrastructure/Postgres/AddOnCallCalendarFeedsMigration.test.ts +32 -7
  123. package/Tests/Server/Middleware/IdentityRateLimit.test.ts +1144 -0
  124. package/Tests/Server/Middleware/MultipartFormData.test.ts +618 -3
  125. package/Tests/Server/Services/MonitorLabelRuleEngineScale.test.ts +520 -0
  126. package/Tests/Server/Services/NetworkDeviceOidTemplateService.test.ts +332 -0
  127. package/Tests/Server/Services/NetworkDeviceOidTemplateWriteGuards.test.ts +409 -0
  128. package/Tests/Server/Services/RuleEngineRuleFetchLimit.test.ts +239 -0
  129. package/Tests/Server/Services/TelemetrySourceMapService.test.ts +1210 -2
  130. package/Tests/Server/Services/UserServiceSeatLimit.test.ts +182 -0
  131. package/Tests/Server/Types/AnalyticsDatabase/SecurityEventModelPermission.test.ts +255 -0
  132. package/Tests/Server/Types/Database/Permissions/ReadBlockPermission.test.ts +212 -0
  133. package/Tests/Server/Types/Database/Permissions/SecurityRoleAccess.test.ts +413 -0
  134. package/Tests/Server/Utils/CodeRepository.test.ts +689 -0
  135. package/Tests/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.test.ts +495 -0
  136. package/Tests/Server/Utils/ExceptionSanitizer.test.ts +77 -0
  137. package/Tests/Server/Utils/Monitor/CapturedMetricAttributeUtil.test.ts +284 -0
  138. package/Tests/Server/Utils/Monitor/MonitorCustomMetricAttributes.test.ts +503 -0
  139. package/Tests/Server/Utils/Monitor/MonitorTemplatePrototypePollution.test.ts +106 -0
  140. package/Tests/Server/Utils/Monitor/NetworkDeviceWalkLogWritePath.test.ts +33 -4
  141. package/Tests/Server/Utils/Monitor/NetworkDeviceWalkUtil.test.ts +14 -4
  142. package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +44 -0
  143. package/Tests/Server/Utils/OpenAPISpec.test.ts +536 -0
  144. package/Tests/Server/Utils/Rules/RuleEngineRuleRead.test.ts +115 -0
  145. package/Tests/Server/Utils/StackTraceParser.test.ts +610 -0
  146. package/Tests/Server/Utils/Telemetry/LogExceptionExtractor.test.ts +0 -0
  147. package/Tests/Server/Utils/Telemetry/SourceMapLimits.test.ts +656 -0
  148. package/Tests/Server/Utils/Telemetry/SourceMapResolver.test.ts +100 -0
  149. package/Tests/Types/Monitor/SnmpMonitor/SnmpOidListUtil.test.ts +454 -0
  150. package/Tests/Types/SecurityRolePermissions.test.ts +193 -0
  151. package/Tests/UI/Components/Charts/AnnotationLayout.test.ts +773 -0
  152. package/Tests/UI/Components/Charts/ChartAnnotationRail.test.tsx +789 -0
  153. package/Tests/UI/Components/Charts/ChartBucketIdentity.test.ts +254 -0
  154. package/Tests/UI/Components/Charts/TimeAnnotation.test.ts +471 -0
  155. package/Tests/UI/Components/EditionLabelLicenseRefresh.test.tsx +405 -0
  156. package/Tests/UI/Components/ErrorMessageRefreshControl.test.tsx +83 -0
  157. package/Tests/UI/Components/MarkdownConverters.test.ts +686 -0
  158. package/Tests/UI/Components/ModelTable/BaseModelTableDeleteAndEmptyStates.test.tsx +341 -0
  159. package/Tests/UI/Components/OrderedStatesList.test.tsx +5 -5
  160. package/Tests/UI/Components/PendingProjectInvitations.test.tsx +1 -1
  161. package/Tests/UI/Components/TableSortAndMobileColumns.test.tsx +195 -0
  162. package/Tests/UI/Components/XAxis.test.ts +270 -5
  163. package/Tests/UI/Components/XAxisDaylightSaving.test.ts +113 -0
  164. package/Tests/UI/Styles/ChartFocusRing.test.ts +153 -0
  165. package/Tests/UI/Styles/ChartFocusRingCoverage.test.tsx +377 -0
  166. package/Tests/UI/Styles/ThemeStylesheet.ts +162 -0
  167. package/Tests/Utils/EnterpriseLicenseSeats.test.ts +507 -0
  168. package/Tests/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.test.ts +951 -1
  169. package/Tests/Utils/NetworkDiscovery/DiscoveredHostUtil.test.ts +238 -0
  170. package/Tests/Utils/NetworkDiscovery/DiscoveryReverseDnsChain.test.ts +1056 -0
  171. package/Tests/Utils/NetworkDiscovery/ReverseDnsNameUtil.test.ts +882 -0
  172. package/Types/Date.ts +39 -0
  173. package/Types/Monitor/SnmpMonitor/SnmpOidListUtil.ts +333 -0
  174. package/Types/Permission.ts +96 -0
  175. package/Types/Rum/SessionReplay.ts +21 -0
  176. package/Types/Telemetry/SourceMap.ts +8 -0
  177. package/UI/Components/Charts/ChartLibrary/Annotations/AnnotationHoverCard.tsx +176 -0
  178. package/UI/Components/Charts/ChartLibrary/Annotations/AnnotationLayout.ts +745 -0
  179. package/UI/Components/Charts/ChartLibrary/Annotations/ChartAnnotationLayer.tsx +576 -0
  180. package/UI/Components/Charts/ChartLibrary/Annotations/UseChartAnnotations.tsx +204 -0
  181. package/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.tsx +491 -544
  182. package/UI/Components/Charts/ChartLibrary/BarChart/BarChart.tsx +324 -372
  183. package/UI/Components/Charts/ChartLibrary/LineChart/LineChart.tsx +487 -540
  184. package/UI/Components/Charts/ChartLibrary/Types/FormattedReferenceRegion.ts +7 -3
  185. package/UI/Components/Charts/ChartLibrary/Types/FormattedTimeReferenceLine.ts +14 -3
  186. package/UI/Components/Charts/Types/ChartEventKind.ts +13 -0
  187. package/UI/Components/Charts/Types/ReferenceRegionProps.ts +6 -0
  188. package/UI/Components/Charts/Types/TimeReferenceLineProps.ts +20 -3
  189. package/UI/Components/Charts/Utils/TimeAnnotation.ts +69 -35
  190. package/UI/Components/Charts/Utils/XAxis.ts +125 -18
  191. package/UI/Components/EditionLabel/EditionLabel.tsx +280 -26
  192. package/UI/Components/ErrorMessage/ErrorMessage.tsx +21 -10
  193. package/UI/Components/Feed/FeedItem.tsx +4 -5
  194. package/UI/Components/Header/HeaderIconDropdownButton.tsx +1 -2
  195. package/UI/Components/Header/UserProfile/UserProfile.tsx +1 -2
  196. package/UI/Components/Image/Image.tsx +20 -3
  197. package/UI/Components/Markdown.tsx/MarkdownConverters.ts +0 -0
  198. package/UI/Components/MemberRoleAssignment/MemberRoleAssignment.tsx +1 -2
  199. package/UI/Components/ModelTable/BaseModelTable.tsx +150 -24
  200. package/UI/Components/Table/TableHeader.tsx +64 -48
  201. package/UI/Components/Table/TableRow.tsx +13 -3
  202. package/UI/Styles/Theme.css +38 -0
  203. package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +271 -0
  204. package/Utils/NetworkDiscovery/AutoImportRuleMatcher.ts +6 -0
  205. package/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.ts +141 -10
  206. package/Utils/NetworkDiscovery/DiscoveredHostUtil.ts +55 -3
  207. package/Utils/NetworkDiscovery/ReverseDnsNameUtil.ts +151 -0
  208. package/Utils/Rules/RuleEngineLimits.ts +32 -0
  209. package/build/dist/Models/AnalyticsModels/SecurityEvent.js +48 -16
  210. package/build/dist/Models/AnalyticsModels/SecurityEvent.js.map +1 -1
  211. package/build/dist/Models/AnalyticsModels/ThreatIntelIndicator.js +10 -5
  212. package/build/dist/Models/AnalyticsModels/ThreatIntelIndicator.js.map +1 -1
  213. package/build/dist/Models/DatabaseModels/AlertSeverity.js +46 -1
  214. package/build/dist/Models/DatabaseModels/AlertSeverity.js.map +1 -1
  215. package/build/dist/Models/DatabaseModels/DetectionRule.js +16 -5
  216. package/build/dist/Models/DatabaseModels/DetectionRule.js.map +1 -1
  217. package/build/dist/Models/DatabaseModels/GoogleSecOpsConnection.js +14 -5
  218. package/build/dist/Models/DatabaseModels/GoogleSecOpsConnection.js.map +1 -1
  219. package/build/dist/Models/DatabaseModels/IncidentSeverity.js +46 -1
  220. package/build/dist/Models/DatabaseModels/IncidentSeverity.js.map +1 -1
  221. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  222. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  223. package/build/dist/Models/DatabaseModels/NetworkDevice.js +115 -3
  224. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
  225. package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js +88 -0
  226. package/build/dist/Models/DatabaseModels/NetworkDeviceAutoImportRule.js.map +1 -1
  227. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
  228. package/build/dist/Models/DatabaseModels/NetworkDeviceOidTemplate.js +519 -0
  229. package/build/dist/Models/DatabaseModels/NetworkDeviceOidTemplate.js.map +1 -0
  230. package/build/dist/Models/DatabaseModels/ThreatIntelFeed.js +16 -5
  231. package/build/dist/Models/DatabaseModels/ThreatIntelFeed.js.map +1 -1
  232. package/build/dist/Server/API/GlobalConfigAPI.js +293 -176
  233. package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
  234. package/build/dist/Server/API/TelemetryAPI.js +31 -3
  235. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  236. package/build/dist/Server/EnvironmentConfig.js +83 -0
  237. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  238. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790500000000-AddNetworkDeviceOidTemplate.js +26 -0
  239. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790500000000-AddNetworkDeviceOidTemplate.js.map +1 -0
  240. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790600000000-AddAutoImportRuleOidTemplate.js +14 -0
  241. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1790600000000-AddAutoImportRuleOidTemplate.js.map +1 -0
  242. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
  243. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  244. package/build/dist/Server/Middleware/MultipartFormData.js +93 -28
  245. package/build/dist/Server/Middleware/MultipartFormData.js.map +1 -1
  246. package/build/dist/Server/Services/AlertEpisodeLabelRuleEngineService.js +8 -1
  247. package/build/dist/Server/Services/AlertEpisodeLabelRuleEngineService.js.map +1 -1
  248. package/build/dist/Server/Services/AlertEpisodeOnCallRuleEngineService.js +8 -1
  249. package/build/dist/Server/Services/AlertEpisodeOnCallRuleEngineService.js.map +1 -1
  250. package/build/dist/Server/Services/AlertEpisodeOwnerRuleEngineService.js +8 -1
  251. package/build/dist/Server/Services/AlertEpisodeOwnerRuleEngineService.js.map +1 -1
  252. package/build/dist/Server/Services/AlertEpisodePrivacyRuleEngineService.js +8 -1
  253. package/build/dist/Server/Services/AlertEpisodePrivacyRuleEngineService.js.map +1 -1
  254. package/build/dist/Server/Services/AlertGroupingEngineService.js +8 -1
  255. package/build/dist/Server/Services/AlertGroupingEngineService.js.map +1 -1
  256. package/build/dist/Server/Services/AlertLabelRuleEngineService.js +8 -1
  257. package/build/dist/Server/Services/AlertLabelRuleEngineService.js.map +1 -1
  258. package/build/dist/Server/Services/AlertOnCallRuleEngineService.js +8 -1
  259. package/build/dist/Server/Services/AlertOnCallRuleEngineService.js.map +1 -1
  260. package/build/dist/Server/Services/AlertOwnerRuleEngineService.js +8 -1
  261. package/build/dist/Server/Services/AlertOwnerRuleEngineService.js.map +1 -1
  262. package/build/dist/Server/Services/AlertPrivacyRuleEngineService.js +8 -1
  263. package/build/dist/Server/Services/AlertPrivacyRuleEngineService.js.map +1 -1
  264. package/build/dist/Server/Services/AlertReminderRuleService.js +8 -1
  265. package/build/dist/Server/Services/AlertReminderRuleService.js.map +1 -1
  266. package/build/dist/Server/Services/AutoRemediationRuleEngineService.js +8 -1
  267. package/build/dist/Server/Services/AutoRemediationRuleEngineService.js.map +1 -1
  268. package/build/dist/Server/Services/CephClusterLabelRuleEngineService.js +8 -1
  269. package/build/dist/Server/Services/CephClusterLabelRuleEngineService.js.map +1 -1
  270. package/build/dist/Server/Services/CephClusterOwnerRuleEngineService.js +8 -1
  271. package/build/dist/Server/Services/CephClusterOwnerRuleEngineService.js.map +1 -1
  272. package/build/dist/Server/Services/CloudResourceLabelRuleEngineService.js +8 -1
  273. package/build/dist/Server/Services/CloudResourceLabelRuleEngineService.js.map +1 -1
  274. package/build/dist/Server/Services/CloudResourceOwnerRuleEngineService.js +8 -1
  275. package/build/dist/Server/Services/CloudResourceOwnerRuleEngineService.js.map +1 -1
  276. package/build/dist/Server/Services/DashboardLabelRuleEngineService.js +8 -1
  277. package/build/dist/Server/Services/DashboardLabelRuleEngineService.js.map +1 -1
  278. package/build/dist/Server/Services/DashboardOwnerRuleEngineService.js +8 -1
  279. package/build/dist/Server/Services/DashboardOwnerRuleEngineService.js.map +1 -1
  280. package/build/dist/Server/Services/DockerHostLabelRuleEngineService.js +8 -1
  281. package/build/dist/Server/Services/DockerHostLabelRuleEngineService.js.map +1 -1
  282. package/build/dist/Server/Services/DockerHostOwnerRuleEngineService.js +8 -1
  283. package/build/dist/Server/Services/DockerHostOwnerRuleEngineService.js.map +1 -1
  284. package/build/dist/Server/Services/DockerSwarmClusterLabelRuleEngineService.js +8 -1
  285. package/build/dist/Server/Services/DockerSwarmClusterLabelRuleEngineService.js.map +1 -1
  286. package/build/dist/Server/Services/DockerSwarmClusterOwnerRuleEngineService.js +8 -1
  287. package/build/dist/Server/Services/DockerSwarmClusterOwnerRuleEngineService.js.map +1 -1
  288. package/build/dist/Server/Services/HostLabelRuleEngineService.js +8 -1
  289. package/build/dist/Server/Services/HostLabelRuleEngineService.js.map +1 -1
  290. package/build/dist/Server/Services/HostOwnerRuleEngineService.js +8 -1
  291. package/build/dist/Server/Services/HostOwnerRuleEngineService.js.map +1 -1
  292. package/build/dist/Server/Services/IncidentEpisodeLabelRuleEngineService.js +8 -1
  293. package/build/dist/Server/Services/IncidentEpisodeLabelRuleEngineService.js.map +1 -1
  294. package/build/dist/Server/Services/IncidentEpisodeOnCallRuleEngineService.js +8 -1
  295. package/build/dist/Server/Services/IncidentEpisodeOnCallRuleEngineService.js.map +1 -1
  296. package/build/dist/Server/Services/IncidentEpisodeOwnerRuleEngineService.js +8 -1
  297. package/build/dist/Server/Services/IncidentEpisodeOwnerRuleEngineService.js.map +1 -1
  298. package/build/dist/Server/Services/IncidentEpisodePrivacyRuleEngineService.js +8 -1
  299. package/build/dist/Server/Services/IncidentEpisodePrivacyRuleEngineService.js.map +1 -1
  300. package/build/dist/Server/Services/IncidentGroupingEngineService.js +8 -1
  301. package/build/dist/Server/Services/IncidentGroupingEngineService.js.map +1 -1
  302. package/build/dist/Server/Services/IncidentLabelRuleEngineService.js +8 -1
  303. package/build/dist/Server/Services/IncidentLabelRuleEngineService.js.map +1 -1
  304. package/build/dist/Server/Services/IncidentOnCallRuleEngineService.js +8 -1
  305. package/build/dist/Server/Services/IncidentOnCallRuleEngineService.js.map +1 -1
  306. package/build/dist/Server/Services/IncidentOwnerRuleEngineService.js +8 -1
  307. package/build/dist/Server/Services/IncidentOwnerRuleEngineService.js.map +1 -1
  308. package/build/dist/Server/Services/IncidentPrivacyRuleEngineService.js +8 -1
  309. package/build/dist/Server/Services/IncidentPrivacyRuleEngineService.js.map +1 -1
  310. package/build/dist/Server/Services/IncidentReminderRuleService.js +8 -1
  311. package/build/dist/Server/Services/IncidentReminderRuleService.js.map +1 -1
  312. package/build/dist/Server/Services/IncidentSlaRuleService.js +8 -1
  313. package/build/dist/Server/Services/IncidentSlaRuleService.js.map +1 -1
  314. package/build/dist/Server/Services/IncomingCallPolicyLabelRuleEngineService.js +8 -1
  315. package/build/dist/Server/Services/IncomingCallPolicyLabelRuleEngineService.js.map +1 -1
  316. package/build/dist/Server/Services/IncomingCallPolicyOwnerRuleEngineService.js +8 -1
  317. package/build/dist/Server/Services/IncomingCallPolicyOwnerRuleEngineService.js.map +1 -1
  318. package/build/dist/Server/Services/Index.js +2 -0
  319. package/build/dist/Server/Services/Index.js.map +1 -1
  320. package/build/dist/Server/Services/IoTFleetLabelRuleEngineService.js +8 -1
  321. package/build/dist/Server/Services/IoTFleetLabelRuleEngineService.js.map +1 -1
  322. package/build/dist/Server/Services/IoTFleetOwnerRuleEngineService.js +8 -1
  323. package/build/dist/Server/Services/IoTFleetOwnerRuleEngineService.js.map +1 -1
  324. package/build/dist/Server/Services/KubernetesClusterLabelRuleEngineService.js +8 -1
  325. package/build/dist/Server/Services/KubernetesClusterLabelRuleEngineService.js.map +1 -1
  326. package/build/dist/Server/Services/KubernetesClusterOwnerRuleEngineService.js +8 -1
  327. package/build/dist/Server/Services/KubernetesClusterOwnerRuleEngineService.js.map +1 -1
  328. package/build/dist/Server/Services/KubernetesResourceService.js +5 -1
  329. package/build/dist/Server/Services/KubernetesResourceService.js.map +1 -1
  330. package/build/dist/Server/Services/MonitorLabelRuleEngineService.js +8 -1
  331. package/build/dist/Server/Services/MonitorLabelRuleEngineService.js.map +1 -1
  332. package/build/dist/Server/Services/MonitorOwnerRuleEngineService.js +8 -1
  333. package/build/dist/Server/Services/MonitorOwnerRuleEngineService.js.map +1 -1
  334. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js +30 -21
  335. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleEngineService.js.map +1 -1
  336. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js +64 -0
  337. package/build/dist/Server/Services/NetworkDeviceAutoImportRuleService.js.map +1 -1
  338. package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js +8 -1
  339. package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js.map +1 -1
  340. package/build/dist/Server/Services/NetworkDeviceOidTemplateService.js +180 -0
  341. package/build/dist/Server/Services/NetworkDeviceOidTemplateService.js.map +1 -0
  342. package/build/dist/Server/Services/NetworkDeviceOwnerRuleEngineService.js +8 -1
  343. package/build/dist/Server/Services/NetworkDeviceOwnerRuleEngineService.js.map +1 -1
  344. package/build/dist/Server/Services/NetworkDeviceService.js +154 -1
  345. package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
  346. package/build/dist/Server/Services/OnCallDutyPolicyLabelRuleEngineService.js +8 -1
  347. package/build/dist/Server/Services/OnCallDutyPolicyLabelRuleEngineService.js.map +1 -1
  348. package/build/dist/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.js +8 -1
  349. package/build/dist/Server/Services/OnCallDutyPolicyOwnerRuleEngineService.js.map +1 -1
  350. package/build/dist/Server/Services/OnCallDutyPolicyScheduleLabelRuleEngineService.js +8 -1
  351. package/build/dist/Server/Services/OnCallDutyPolicyScheduleLabelRuleEngineService.js.map +1 -1
  352. package/build/dist/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.js +8 -1
  353. package/build/dist/Server/Services/OnCallDutyPolicyScheduleOwnerRuleEngineService.js.map +1 -1
  354. package/build/dist/Server/Services/PodmanHostLabelRuleEngineService.js +8 -1
  355. package/build/dist/Server/Services/PodmanHostLabelRuleEngineService.js.map +1 -1
  356. package/build/dist/Server/Services/PodmanHostOwnerRuleEngineService.js +8 -1
  357. package/build/dist/Server/Services/PodmanHostOwnerRuleEngineService.js.map +1 -1
  358. package/build/dist/Server/Services/ProxmoxClusterLabelRuleEngineService.js +8 -1
  359. package/build/dist/Server/Services/ProxmoxClusterLabelRuleEngineService.js.map +1 -1
  360. package/build/dist/Server/Services/ProxmoxClusterOwnerRuleEngineService.js +8 -1
  361. package/build/dist/Server/Services/ProxmoxClusterOwnerRuleEngineService.js.map +1 -1
  362. package/build/dist/Server/Services/RumApplicationLabelRuleEngineService.js +8 -1
  363. package/build/dist/Server/Services/RumApplicationLabelRuleEngineService.js.map +1 -1
  364. package/build/dist/Server/Services/RumApplicationOwnerRuleEngineService.js +8 -1
  365. package/build/dist/Server/Services/RumApplicationOwnerRuleEngineService.js.map +1 -1
  366. package/build/dist/Server/Services/RunbookLabelRuleEngineService.js +8 -1
  367. package/build/dist/Server/Services/RunbookLabelRuleEngineService.js.map +1 -1
  368. package/build/dist/Server/Services/RunbookOwnerRuleEngineService.js +8 -1
  369. package/build/dist/Server/Services/RunbookOwnerRuleEngineService.js.map +1 -1
  370. package/build/dist/Server/Services/RunbookRuleEngineService.js +8 -1
  371. package/build/dist/Server/Services/RunbookRuleEngineService.js.map +1 -1
  372. package/build/dist/Server/Services/ScheduledMaintenanceLabelRuleEngineService.js +8 -1
  373. package/build/dist/Server/Services/ScheduledMaintenanceLabelRuleEngineService.js.map +1 -1
  374. package/build/dist/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.js +8 -1
  375. package/build/dist/Server/Services/ScheduledMaintenanceOwnerRuleEngineService.js.map +1 -1
  376. package/build/dist/Server/Services/ScheduledMaintenanceReminderRuleService.js +8 -1
  377. package/build/dist/Server/Services/ScheduledMaintenanceReminderRuleService.js.map +1 -1
  378. package/build/dist/Server/Services/ServerlessFunctionLabelRuleEngineService.js +8 -1
  379. package/build/dist/Server/Services/ServerlessFunctionLabelRuleEngineService.js.map +1 -1
  380. package/build/dist/Server/Services/ServerlessFunctionOwnerRuleEngineService.js +8 -1
  381. package/build/dist/Server/Services/ServerlessFunctionOwnerRuleEngineService.js.map +1 -1
  382. package/build/dist/Server/Services/ServiceLabelRuleEngineService.js +8 -1
  383. package/build/dist/Server/Services/ServiceLabelRuleEngineService.js.map +1 -1
  384. package/build/dist/Server/Services/ServiceOwnerRuleEngineService.js +8 -1
  385. package/build/dist/Server/Services/ServiceOwnerRuleEngineService.js.map +1 -1
  386. package/build/dist/Server/Services/StatusPageLabelRuleEngineService.js +8 -1
  387. package/build/dist/Server/Services/StatusPageLabelRuleEngineService.js.map +1 -1
  388. package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js +6 -0
  389. package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js.map +1 -1
  390. package/build/dist/Server/Services/StatusPageOwnerRuleEngineService.js +8 -1
  391. package/build/dist/Server/Services/StatusPageOwnerRuleEngineService.js.map +1 -1
  392. package/build/dist/Server/Services/TelemetrySourceMapService.js +213 -19
  393. package/build/dist/Server/Services/TelemetrySourceMapService.js.map +1 -1
  394. package/build/dist/Server/Services/UserService.js +25 -0
  395. package/build/dist/Server/Services/UserService.js.map +1 -1
  396. package/build/dist/Server/Services/WorkflowLabelRuleEngineService.js +8 -1
  397. package/build/dist/Server/Services/WorkflowLabelRuleEngineService.js.map +1 -1
  398. package/build/dist/Server/Services/WorkflowOwnerRuleEngineService.js +8 -1
  399. package/build/dist/Server/Services/WorkflowOwnerRuleEngineService.js.map +1 -1
  400. package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js +145 -0
  401. package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js.map +1 -0
  402. package/build/dist/Server/Utils/Monitor/CapturedMetricAttributeUtil.js +201 -0
  403. package/build/dist/Server/Utils/Monitor/CapturedMetricAttributeUtil.js.map +1 -0
  404. package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js +19 -2
  405. package/build/dist/Server/Utils/Monitor/Criteria/SnmpMonitorCriteria.js.map +1 -1
  406. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +42 -23
  407. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
  408. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +29 -0
  409. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
  410. package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js +11 -2
  411. package/build/dist/Server/Utils/Monitor/NetworkDeviceMetricUtil.js.map +1 -1
  412. package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js +16 -1
  413. package/build/dist/Server/Utils/Monitor/NetworkDeviceWalkUtil.js.map +1 -1
  414. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +10 -0
  415. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
  416. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +33 -0
  417. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -1
  418. package/build/dist/Server/Utils/Rules/RuleEngineRuleRead.js +37 -0
  419. package/build/dist/Server/Utils/Rules/RuleEngineRuleRead.js.map +1 -0
  420. package/build/dist/Server/Utils/Telemetry/ExceptionSanitizer.js +12 -1
  421. package/build/dist/Server/Utils/Telemetry/ExceptionSanitizer.js.map +1 -1
  422. package/build/dist/Server/Utils/Telemetry/LogExceptionExtractor.js +14 -2
  423. package/build/dist/Server/Utils/Telemetry/LogExceptionExtractor.js.map +1 -1
  424. package/build/dist/Server/Utils/Telemetry/SourceMapResolver.js +15 -5
  425. package/build/dist/Server/Utils/Telemetry/SourceMapResolver.js.map +1 -1
  426. package/build/dist/Server/Utils/Telemetry/StackTraceParser.js +307 -0
  427. package/build/dist/Server/Utils/Telemetry/StackTraceParser.js.map +1 -1
  428. package/build/dist/Types/Date.js +27 -0
  429. package/build/dist/Types/Date.js.map +1 -1
  430. package/build/dist/Types/Monitor/SnmpMonitor/SnmpOidListUtil.js +253 -0
  431. package/build/dist/Types/Monitor/SnmpMonitor/SnmpOidListUtil.js.map +1 -0
  432. package/build/dist/Types/Permission.js +86 -0
  433. package/build/dist/Types/Permission.js.map +1 -1
  434. package/build/dist/Types/Rum/SessionReplay.js +19 -0
  435. package/build/dist/Types/Rum/SessionReplay.js.map +1 -1
  436. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationHoverCard.js +83 -0
  437. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationHoverCard.js.map +1 -0
  438. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationLayout.js +531 -0
  439. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/AnnotationLayout.js.map +1 -0
  440. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/ChartAnnotationLayer.js +264 -0
  441. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/ChartAnnotationLayer.js.map +1 -0
  442. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/UseChartAnnotations.js +122 -0
  443. package/build/dist/UI/Components/Charts/ChartLibrary/Annotations/UseChartAnnotations.js.map +1 -0
  444. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js +213 -233
  445. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js.map +1 -1
  446. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js +139 -152
  447. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js.map +1 -1
  448. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js +212 -232
  449. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js.map +1 -1
  450. package/build/dist/UI/Components/Charts/Types/ChartEventKind.js +14 -0
  451. package/build/dist/UI/Components/Charts/Types/ChartEventKind.js.map +1 -0
  452. package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js +57 -28
  453. package/build/dist/UI/Components/Charts/Utils/TimeAnnotation.js.map +1 -1
  454. package/build/dist/UI/Components/Charts/Utils/XAxis.js +103 -17
  455. package/build/dist/UI/Components/Charts/Utils/XAxis.js.map +1 -1
  456. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +198 -23
  457. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  458. package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js +15 -5
  459. package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js.map +1 -1
  460. package/build/dist/UI/Components/Feed/FeedItem.js +4 -5
  461. package/build/dist/UI/Components/Feed/FeedItem.js.map +1 -1
  462. package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js +1 -2
  463. package/build/dist/UI/Components/Header/HeaderIconDropdownButton.js.map +1 -1
  464. package/build/dist/UI/Components/Header/UserProfile/UserProfile.js.map +1 -1
  465. package/build/dist/UI/Components/Image/Image.js +6 -1
  466. package/build/dist/UI/Components/Image/Image.js.map +1 -1
  467. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js +0 -0
  468. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js.map +1 -1
  469. package/build/dist/UI/Components/MemberRoleAssignment/MemberRoleAssignment.js +1 -2
  470. package/build/dist/UI/Components/MemberRoleAssignment/MemberRoleAssignment.js.map +1 -1
  471. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +104 -23
  472. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  473. package/build/dist/UI/Components/Table/TableHeader.js +20 -22
  474. package/build/dist/UI/Components/Table/TableHeader.js.map +1 -1
  475. package/build/dist/UI/Components/Table/TableRow.js +13 -4
  476. package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
  477. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js +153 -0
  478. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js.map +1 -0
  479. package/build/dist/Utils/NetworkDiscovery/AutoImportRuleMatcher.js.map +1 -1
  480. package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js +127 -7
  481. package/build/dist/Utils/NetworkDiscovery/DiscoveredDeviceBuilder.js.map +1 -1
  482. package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js +50 -3
  483. package/build/dist/Utils/NetworkDiscovery/DiscoveredHostUtil.js.map +1 -1
  484. package/build/dist/Utils/NetworkDiscovery/ReverseDnsNameUtil.js +132 -0
  485. package/build/dist/Utils/NetworkDiscovery/ReverseDnsNameUtil.js.map +1 -0
  486. package/build/dist/Utils/Rules/RuleEngineLimits.js +31 -0
  487. package/build/dist/Utils/Rules/RuleEngineLimits.js.map +1 -0
  488. package/jest.config.json +1 -0
  489. package/package.json +2 -2
@@ -204,6 +204,18 @@ export function sanitizeExceptionMessage(message: string): string {
204
204
  // Frame lines are indented; header/message lines are not.
205
205
  const INDENTED_FRAME_LINE_REGEX: RegExp = /^\s/;
206
206
 
207
+ /*
208
+ * ...except in Firefox and Safari, which indent nothing: SpiderMonkey and
209
+ * JavaScriptCore write `fn@source:line:col` flush against column 0 and emit no
210
+ * header line at all. Without this second test every browser frame takes the
211
+ * header branch, where rule 19 rewrites the content hash in
212
+ * `entry.a1b2c3d4.js` to `<HEX_ID>` and rule 22 rewrites `:1:98217` to
213
+ * `:<LINE>:<COL>)` — destroying for Firefox and Safari exactly the file:line
214
+ * references the comment above promises to keep for V8 ones.
215
+ */
216
+ const BROWSER_FRAME_LINE_REGEX: RegExp =
217
+ /^[^@:\n]{0,256}@(?:\[(?:native|wasm) code\]|self-hosted:\d{1,9}(?::\d{1,9})?|[A-Za-z][A-Za-z0-9+.-]{0,31}:[^\s]{1,2048}:\d{1,9}(?::\d{1,9})?)\r?$/;
218
+
207
219
  export function sanitizeStackTrace(stackTrace: string): string {
208
220
  if (!stackTrace) {
209
221
  return "";
@@ -212,7 +224,8 @@ export function sanitizeStackTrace(stackTrace: string): string {
212
224
  const normalized: string = stackTrace
213
225
  .split("\n")
214
226
  .map((line: string): string => {
215
- return INDENTED_FRAME_LINE_REGEX.test(line)
227
+ return INDENTED_FRAME_LINE_REGEX.test(line) ||
228
+ BROWSER_FRAME_LINE_REGEX.test(line)
216
229
  ? line
217
230
  : normalizeExceptionText(line);
218
231
  })
@@ -56,10 +56,22 @@ const MAX_MESSAGE_LENGTH: number = 1024;
56
56
  * Single pre-compiled signature for "this body plausibly contains a stack
57
57
  * trace". Evaluated once before the (more expensive) multi-language parser.
58
58
  * Covers: Python traceback header, JS/Java `at file:line`, Go panic/goroutine,
59
- * Python `File "...", line N`, and a typed `SomethingException`/`SomethingError`.
59
+ * Python `File "...", line N`, a Firefox/Safari `fn@url:line:col` frame, and a
60
+ * typed `SomethingException`/`SomethingError`.
61
+ *
62
+ * The `fn@url:line` alternative mirrors the shape StackTraceParser's browser
63
+ * parser accepts and must stay in step with it. Without it a SpiderMonkey or
64
+ * JavaScriptCore stack reaches this gate with no `at ` frame and — unless the
65
+ * app happened to log a `*Error`/`*Exception` token above it — is rejected
66
+ * here, before the parser ever runs. The name class admits spaces (Safari's
67
+ * `global code@…`, Firefox's `promise callback*fn@…`) but never a colon, which
68
+ * is what keeps ordinary `key: value` log prose out. It also absorbs a log
69
+ * body's leading indentation, so do NOT prepend a `[ \t]*` — space and tab are
70
+ * already in the class, and the two overlapping quantifiers backtrack
71
+ * quadratically (a hostile 16 KB body measured 11 ms against 0.1 ms without).
60
72
  */
61
73
  const LOOKS_LIKE_STACK_TRACE: RegExp =
62
- /(?:Traceback \(most recent call last\)|\n\s+at\s+.+:\d+|\bpanic:\s|goroutine\s+\d+\s+\[|\n\s*File\s+"[^"]+",\s+line\s+\d+|\b[A-Za-z_][\w.$]*(?:Exception|Error)\b)/;
74
+ /(?:Traceback \(most recent call last\)|\n\s+at\s+.+:\d+|\bpanic:\s|goroutine\s+\d+\s+\[|\n\s*File\s+"[^"]+",\s+line\s+\d+|(?:^|\n)[^@:\n]{0,256}@[A-Za-z][A-Za-z0-9+.-]{0,31}:[^\s]{1,2048}:\d{1,9}|\b[A-Za-z_][\w.$]*(?:Exception|Error)\b)/;
63
75
 
64
76
  // Header parsers for deriving exceptionType + message from a raw body.
65
77
  const PYTHON_TRACEBACK_HEADER: RegExp = /^Traceback \(most recent call last\):/;
@@ -14,6 +14,7 @@ import {
14
14
  SourceCodeSnippet,
15
15
  } from "../../../Types/Telemetry/SourceMap";
16
16
  import BadDataException from "../../../Types/Exception/BadDataException";
17
+ import { SourceMapMaxFileSizeInBytes } from "../../EnvironmentConfig";
17
18
  import {
18
19
  AnyMap,
19
20
  TraceMap,
@@ -28,11 +29,12 @@ export interface SourceMapBundle {
28
29
  }
29
30
 
30
31
  /*
31
- * Hard ceiling on one map. Matches MAX_MULTIPART_FILE_BYTES on the upload
32
- * path; also enforced on the decoded string (invalid UTF-8 bytes expand to
33
- * 3-byte U+FFFD on decode, so the string can outgrow the raw file).
32
+ * Hard ceiling on one map, from SOURCE_MAP_MAX_FILE_SIZE_BYTES. Clamped to
33
+ * MAX_MULTIPART_FILE_BYTES on the upload path by the config layer; also
34
+ * enforced on the decoded string (invalid UTF-8 bytes expand to 3-byte
35
+ * U+FFFD on decode, so the string can outgrow the raw file).
34
36
  */
35
- export const MAX_SOURCE_MAP_SIZE_IN_BYTES: number = 50 * 1024 * 1024;
37
+ export const MAX_SOURCE_MAP_SIZE_IN_BYTES: number = SourceMapMaxFileSizeInBytes;
36
38
 
37
39
  /** Lines of context shown on each side of the resolved line. */
38
40
  const SNIPPET_CONTEXT_LINES: number = 3;
@@ -51,7 +53,16 @@ const MAX_SNIPPET_LINE_LENGTH: number = 512;
51
53
  * through unresolved so the output length always equals the input length,
52
54
  * which the dashboard overlay relies on.
53
55
  */
54
- const MAX_FRAMES_TO_RESOLVE: number = 500;
56
+ export const MAX_FRAMES_TO_RESOLVE: number = 500;
57
+
58
+ /*
59
+ * Hard ceiling on the frames array ONE resolve request may carry. Well above
60
+ * anything a runtime produces — browsers truncate stack traces long before
61
+ * this — so it never rejects a real trace; it exists so the request body
62
+ * cannot be used to drive work proportional to a caller-chosen length. The
63
+ * per-call resolution cap above is the tighter, non-rejecting bound.
64
+ */
65
+ export const MAX_FRAMES_PER_RESOLVE_REQUEST: number = 10000;
55
66
 
56
67
  interface ParsedBundle {
57
68
  bundlePath: string;
@@ -1,6 +1,11 @@
1
1
  /**
2
2
  * Stack trace parser that transforms raw stack trace strings into structured frames.
3
3
  * Supports JavaScript/Node.js, Python, Java, Go, Ruby, C#/.NET, and PHP stack traces.
4
+ *
5
+ * JavaScript is covered twice, because the engines do not agree on a format:
6
+ * V8 (Chrome, Edge, Node) writes `at fn (file:line:col)`, while SpiderMonkey
7
+ * (Firefox) and JavaScriptCore (Safari) write `fn@source:line:col`. See
8
+ * parseJavaScript and parseJavaScriptBrowser respectively.
4
9
  */
5
10
 
6
11
  export interface StackFrame {
@@ -66,8 +71,160 @@ const LIBRARY_PATTERNS: Array<RegExp> = [
66
71
  // PHP
67
72
  /\/vendor\//,
68
73
  /^phar:\/\//,
74
+ /*
75
+ * Browser engines and extensions. Frames sourced from an extension, from a
76
+ * `resource:`/`chrome:` internal, from a WebAssembly module or from one of
77
+ * SpiderMonkey's / JavaScriptCore's pseudo-sources are never the page's own
78
+ * code, so they must not be highlighted as in-app.
79
+ */
80
+ /^moz-extension:/,
81
+ /^chrome-extension:/,
82
+ /^safari-web-extension:/,
83
+ /^safari-extension:/,
84
+ /^ms-browser-extension:/,
85
+ /^resource:/,
86
+ /^chrome:/,
87
+ /^about:/,
88
+ /^jar:/,
89
+ /^wasm:/,
90
+ /^self-hosted$/,
91
+ /^\[native code\]$/,
92
+ /^\[wasm code\]$/,
69
93
  ];
70
94
 
95
+ /*
96
+ * ---------------------------------------------------------------------------
97
+ * Firefox (SpiderMonkey) / Safari (JavaScriptCore) frame grammar.
98
+ *
99
+ * Neither engine writes V8's `at fn (file:line:col)`. Both write
100
+ *
101
+ * [asyncCause*]functionName@source:line[:column]
102
+ *
103
+ * with the function name optional (`@https://…` is every Firefox top-level
104
+ * frame) and the location sometimes absent entirely (`map@[native code]` in
105
+ * Safari). Because the source is a URL it carries colons of its own — the
106
+ * `https:`, a `:port`, a nested `blob:https:` — so the line and column are
107
+ * peeled off the RIGHT, never by splitting on the first colon.
108
+ *
109
+ * These constants are the grammar; parseBrowserFrame() composes them.
110
+ * ---------------------------------------------------------------------------
111
+ */
112
+
113
+ /*
114
+ * The longest source a browser reports is a data: URL. Longer lines are
115
+ * skipped rather than handed to the regex engine — exception.stacktrace is
116
+ * attacker-influenceable and reaches this parser on the ingest hot path.
117
+ */
118
+ const BROWSER_MAX_FRAME_LINE_LENGTH: number = 4096;
119
+ const BROWSER_MAX_FUNCTION_NAME_LENGTH: number = 256;
120
+
121
+ /*
122
+ * A real frame has one `@`, but a URL may carry userinfo (`https://u:p@cdn/…`)
123
+ * and a name may be a quoted property key (`obj["a@b"]`), so the split point is
124
+ * found by trying each `@` left to right until one yields a valid source. The
125
+ * bound keeps a line of nothing but `@` off the retry loop.
126
+ */
127
+ const BROWSER_MAX_AT_SPLITS: number = 8;
128
+
129
+ // V8 frames belong to parseJavaScript. Never double-claim one.
130
+ const V8_FRAME_PREFIX: RegExp = /^at\s/;
131
+
132
+ /*
133
+ * Schemes a browser can legitimately name as a frame source. An allowlist on
134
+ * purpose: together with BROWSER_FUNCTION_NAME it is the clause that stops
135
+ * ordinary log prose from reading as a stack frame — `git@github.com:22:1`,
136
+ * `deploy@prod:8080:1` and `/app/node_modules/@scope/pkg/index.js:10:5` all
137
+ * fail here because what follows the `@` names no scheme. Extend it when a new
138
+ * engine or embedder scheme shows up in the wild.
139
+ */
140
+ const BROWSER_SOURCE_SCHEME: RegExp =
141
+ /^(?:https?|file|blob|data|webpack(?:-internal)?|moz-extension|chrome-extension|safari-web-extension|safari-extension|ms-browser-extension|resource|chrome|about|jar|view-source|capacitor|ionic|wasm):/i;
142
+
143
+ /*
144
+ * `scheme://authority` with no path left — what remains when a URL's `:port`
145
+ * is peeled as if it were a line number (`@http://127.0.0.1:8080`). A real
146
+ * frame always has a path after the host, so this shape is always a mis-peel.
147
+ */
148
+ const BROWSER_BARE_AUTHORITY: RegExp =
149
+ /^[A-Za-z][A-Za-z0-9+.-]{0,31}:\/\/[^/]*$/;
150
+
151
+ /*
152
+ * JavaScriptCore's native pseudo-source. A real frame, but it has no location
153
+ * and can never be matched to a bundle.
154
+ */
155
+ const BROWSER_NATIVE_SOURCE: RegExp = /^\[(?:native|wasm) code\]$/;
156
+
157
+ // SpiderMonkey's source for a self-hosted builtin: `next@self-hosted:1154:9`.
158
+ const BROWSER_SELF_HOSTED_SOURCE: string = "self-hosted";
159
+
160
+ /*
161
+ * Peel `:line:column` — or just `:line` — off the RIGHT of the source. `(.*)`
162
+ * is greedy, so it keeps every earlier colon (the `https:`, the `:port`, the
163
+ * colons inside a data: URL) and only the trailing numeric groups are taken.
164
+ * Both groups are digit-bounded, so neither can backtrack across the line.
165
+ */
166
+ const BROWSER_LOCATION_WITH_COLUMN: RegExp = /^(.*):(\d{1,9}):(\d{1,9})$/;
167
+ const BROWSER_LOCATION_LINE_ONLY: RegExp = /^(.*):(\d{1,9})$/;
168
+
169
+ /*
170
+ * Firefox <= 29 and Safari <= 6 emitted `fn@url:line` with no column — which
171
+ * is also the shape of a logged URL that merely ends in a number
172
+ * (`notify@https://hooks.slack.com/services/T000:200`). Requiring the source
173
+ * to name a script is what tells the two apart.
174
+ */
175
+ const BROWSER_SCRIPT_EXTENSION: RegExp =
176
+ /\.(?:m?js|cjs|jsx|m?ts|tsx|html?|vue|svelte|astro)(?:[?#]|$)/i;
177
+
178
+ /*
179
+ * Firefox decorates the source of code introduced by another script:
180
+ * `<introducer> line <N> > <kind>`, nested for nested evals, e.g.
181
+ * `https://x/app.js line 12 > eval line 1 > eval`. The FIRST occurrence is the
182
+ * boundary: everything before it is the real file and its N is the line in
183
+ * that file, which is the only position a source map can resolve. A URL cannot
184
+ * contain a literal space, so this can never fire on an ordinary source.
185
+ */
186
+ const BROWSER_EVAL_INTRODUCER: RegExp = / line (\d{1,9}) > /;
187
+
188
+ /*
189
+ * The function-name field — everything before the `@`.
190
+ *
191
+ * Firefox prefixes an async frame with `<cause>*`, where the cause may contain
192
+ * spaces (`promise callback*fetchAll`, `setTimeout handler*poll`), and that
193
+ * prefix composes with any name — including an accessor, which is why the
194
+ * prefix is a separate optional group rather than its own alternative. A
195
+ * getter that registers a promise callback really does arrive as
196
+ * `promise callback*get profile@…`.
197
+ *
198
+ * The name itself is JavaScriptCore's `global code` family, an ES2015 accessor
199
+ * or bound name (`get fullName`, `bound save`), or any single whitespace-free
200
+ * token — which is what carries Firefox's composed display names
201
+ * (`Foo.prototype.render`, `initGrid/</<`, `[16]</Grid.prototype.draw/<`). It
202
+ * is optional so that an anonymous async frame (`async*@url:1:1`) still parses.
203
+ *
204
+ * No alternative admits a colon, and only the accessor, `… code` and async
205
+ * forms admit a space. Those two exclusions are load-bearing — they are what
206
+ * reject `notified on-call engineer jane@https://status.example.com/app.js:1:2`
207
+ * (spaces) and `Connection string: svc@https://db.example.com/app.js:1:1`
208
+ * (colon), both of which name a perfectly valid source.
209
+ */
210
+ const BROWSER_FUNCTION_NAME: RegExp =
211
+ /^(?:[A-Za-z][A-Za-z0-9 ]{0,31}\*)?(?:(?:global|module|eval|function) code|(?:get|set|bound) [^\s:]{1,200}|[^\s:]{1,256})?$/;
212
+
213
+ /**
214
+ * A parsed Firefox/Safari frame plus the evidence parseJavaScriptBrowser needs
215
+ * to decide whether the stack as a whole really is a browser stack.
216
+ */
217
+ interface BrowserFrameCandidate {
218
+ frame: StackFrame;
219
+ /*
220
+ * True only for a frame that could not plausibly be anything else: an
221
+ * explicit `@`, a source with a real URL scheme, and a line number. A
222
+ * pseudo-source frame (`map@[native code]`) is not an anchor — it carries no
223
+ * URL and no digits, so on its own it is far too easy to forge.
224
+ */
225
+ isAnchor: boolean;
226
+ }
227
+
71
228
  export default class StackTraceParser {
72
229
  /**
73
230
  * Parse a raw stack trace string into structured frames.
@@ -91,6 +248,13 @@ export default class StackTraceParser {
91
248
  StackTraceParser.parseRuby,
92
249
  StackTraceParser.parseCSharp,
93
250
  StackTraceParser.parsePHP,
251
+ /*
252
+ * Firefox/Safari must stay LAST. The election below keeps the first
253
+ * parser to reach a given frame count, so a parser at the end can only
254
+ * win by producing strictly more frames than every language before it —
255
+ * it can never take a tie away from the incumbent.
256
+ */
257
+ StackTraceParser.parseJavaScriptBrowser,
94
258
  ];
95
259
 
96
260
  let bestFrames: StackFrame[] = [];
@@ -420,4 +584,239 @@ export default class StackTraceParser {
420
584
 
421
585
  return frames;
422
586
  }
587
+ /**
588
+ * Parse Firefox (SpiderMonkey) / Safari (JavaScriptCore) stack traces.
589
+ * Format: `functionName@source:line:col`, `@source:line:col` (anonymous),
590
+ * `fn@[native code]` (Safari), `async*fn@source:line:col` (Firefox async).
591
+ *
592
+ * Registered LAST in parse()'s parsers array on purpose. That election keeps
593
+ * the first parser to reach a frame count, so a parser appended at the end
594
+ * can only win by producing strictly more frames than every language before
595
+ * it — it can never take a tie away from the incumbent. A Ruby stack with a
596
+ * couple of browser-shaped lines in it therefore stays Ruby.
597
+ *
598
+ * Deliberately NOT accepted, because each one is indistinguishable from
599
+ * ordinary log text and this parser is fed arbitrary ERROR log bodies:
600
+ * - a bare `url:line:col` with no `@` (Safari <= 9 top-level frames), and
601
+ * bare `[native code]` / `global code` lines carrying no `@` at all;
602
+ * - a source naming no scheme, which is the shape of React Native's
603
+ * JavaScriptCore bundles and of `//# sourceURL=` pragma names;
604
+ * - a scheme outside BROWSER_SOURCE_SCHEME, such as Angular JIT's `ng:///`.
605
+ */
606
+ private static parseJavaScriptBrowser(lines: string[]): StackFrame[] {
607
+ const frames: StackFrame[] = [];
608
+ let anchorCount: number = 0;
609
+
610
+ for (const line of lines) {
611
+ if (line.length === 0 || line.length > BROWSER_MAX_FRAME_LINE_LENGTH) {
612
+ continue;
613
+ }
614
+
615
+ if (V8_FRAME_PREFIX.test(line)) {
616
+ continue;
617
+ }
618
+
619
+ const candidate: BrowserFrameCandidate | null =
620
+ StackTraceParser.parseBrowserFrame(line);
621
+
622
+ if (!candidate) {
623
+ continue;
624
+ }
625
+
626
+ if (candidate.isAnchor) {
627
+ anchorCount++;
628
+ }
629
+
630
+ frames.push(candidate.frame);
631
+ }
632
+
633
+ /*
634
+ * A pseudo-source frame carries no URL and no digits, so two forged
635
+ * `x@[native code]` lines must not be able to out-count and evict a real
636
+ * Ruby or Python stack in parse()'s election. Nothing is trusted until the
637
+ * stack has produced at least one unambiguous `name@<url>:line` frame.
638
+ */
639
+ if (anchorCount === 0) {
640
+ return [];
641
+ }
642
+
643
+ return frames;
644
+ }
645
+
646
+ /**
647
+ * Split one Firefox/Safari frame line at its `@` and parse the source.
648
+ *
649
+ * The split point is searched left to right rather than taken at the first
650
+ * or last `@`, because both sides may legitimately contain one: a URL may
651
+ * carry userinfo (`send@https://user:pw@cdn.example.com/sdk.js:1:9033`) and
652
+ * a name may be a quoted property key (`obj["a@b"]@https://x/app.js:3:11`).
653
+ * The first split whose right-hand side parses as a source wins.
654
+ */
655
+ private static parseBrowserFrame(line: string): BrowserFrameCandidate | null {
656
+ let searchFrom: number = 0;
657
+
658
+ for (let attempt: number = 0; attempt < BROWSER_MAX_AT_SPLITS; attempt++) {
659
+ const atIndex: number = line.indexOf("@", searchFrom);
660
+
661
+ if (atIndex < 0) {
662
+ return null;
663
+ }
664
+
665
+ searchFrom = atIndex + 1;
666
+
667
+ const functionName: string = line.substring(0, atIndex);
668
+ const source: string = line.substring(atIndex + 1);
669
+
670
+ if (functionName.length > BROWSER_MAX_FUNCTION_NAME_LENGTH) {
671
+ continue;
672
+ }
673
+
674
+ // An empty name is the anonymous/top-level frame Firefox emits as `@url`.
675
+ if (
676
+ functionName.length > 0 &&
677
+ !BROWSER_FUNCTION_NAME.test(functionName)
678
+ ) {
679
+ continue;
680
+ }
681
+
682
+ const candidate: BrowserFrameCandidate | null =
683
+ StackTraceParser.parseBrowserSource(functionName, source);
684
+
685
+ if (candidate) {
686
+ return candidate;
687
+ }
688
+ }
689
+
690
+ return null;
691
+ }
692
+
693
+ /**
694
+ * Turn the right-hand side of a browser frame into a StackFrame, or return
695
+ * null when it does not name a location a browser could have reported.
696
+ */
697
+ private static parseBrowserSource(
698
+ functionName: string,
699
+ source: string,
700
+ ): BrowserFrameCandidate | null {
701
+ /*
702
+ * The async cause and the closure suffixes are kept verbatim
703
+ * (`async*loadUser`, `initGrid/<`): they are what distinguishes two
704
+ * otherwise identical rows in the frame viewer, they match the raw stack
705
+ * rendered beside it, and StackFrame has no field to move them to.
706
+ */
707
+ const displayName: string =
708
+ functionName.length > 0 ? functionName : "<anonymous>";
709
+
710
+ // Safari: `map@[native code]` — a real frame with no location at all.
711
+ if (BROWSER_NATIVE_SOURCE.test(source)) {
712
+ return {
713
+ frame: {
714
+ functionName: displayName,
715
+ fileName: source,
716
+ /*
717
+ * StackFrame.lineNumber is not optional, and 0 is already the
718
+ * file-less sentinel parseJava uses for `(Native Method)`.
719
+ * SourceMapResolver skips any frame with lineNumber < 1, so this
720
+ * frame renders but is never probed against a source map.
721
+ */
722
+ lineNumber: 0,
723
+ inApp: false,
724
+ },
725
+ isAnchor: false,
726
+ };
727
+ }
728
+
729
+ let fileName: string = "";
730
+ let lineNumber: number = 0;
731
+ let columnNumber: number | undefined = undefined;
732
+
733
+ const withColumn: RegExpMatchArray | null = source.match(
734
+ BROWSER_LOCATION_WITH_COLUMN,
735
+ );
736
+
737
+ if (withColumn) {
738
+ fileName = withColumn[1]!;
739
+ lineNumber = parseInt(withColumn[2]!, 10);
740
+ columnNumber = parseInt(withColumn[3]!, 10);
741
+ } else {
742
+ const lineOnly: RegExpMatchArray | null = source.match(
743
+ BROWSER_LOCATION_LINE_ONLY,
744
+ );
745
+
746
+ if (!lineOnly) {
747
+ return null;
748
+ }
749
+
750
+ fileName = lineOnly[1]!;
751
+ lineNumber = parseInt(lineOnly[2]!, 10);
752
+ }
753
+
754
+ /*
755
+ * Firefox: `https://x/app.js line 12 > eval:1:5`. The eval'd text has no
756
+ * URL and no source map of its own; the only resolvable position is the
757
+ * introducer's — app.js line 12. The inner column belongs to the eval'd
758
+ * text, so it is dropped rather than reported against the wrong file.
759
+ */
760
+ const introducer: RegExpMatchArray | null = fileName.match(
761
+ BROWSER_EVAL_INTRODUCER,
762
+ );
763
+ let fromEvalIntroducer: boolean = false;
764
+
765
+ if (introducer && introducer.index !== undefined) {
766
+ lineNumber = parseInt(introducer[1]!, 10);
767
+ columnNumber = undefined;
768
+ fileName = fileName.substring(0, introducer.index);
769
+ fromEvalIntroducer = true;
770
+ }
771
+
772
+ if (lineNumber < 1) {
773
+ return null;
774
+ }
775
+
776
+ // Firefox self-hosted builtins: `next@self-hosted:1154:9`.
777
+ if (fileName === BROWSER_SELF_HOSTED_SOURCE) {
778
+ return {
779
+ frame: {
780
+ functionName: displayName,
781
+ fileName: fileName,
782
+ lineNumber: lineNumber,
783
+ ...(columnNumber === undefined ? {} : { columnNumber: columnNumber }),
784
+ inApp: false,
785
+ },
786
+ isAnchor: false,
787
+ };
788
+ }
789
+
790
+ if (
791
+ !BROWSER_SOURCE_SCHEME.test(fileName) ||
792
+ BROWSER_BARE_AUTHORITY.test(fileName)
793
+ ) {
794
+ return null;
795
+ }
796
+
797
+ /*
798
+ * A column-less frame is either a Firefox <= 29 / Safari <= 6 frame or a
799
+ * URL that happens to end in a number, and only the source can tell them
800
+ * apart. The `line N >` decoration is already unmistakable, so a frame that
801
+ * lost its column to an eval introducer is exempt.
802
+ */
803
+ if (
804
+ columnNumber === undefined &&
805
+ !fromEvalIntroducer &&
806
+ !BROWSER_SCRIPT_EXTENSION.test(fileName)
807
+ ) {
808
+ return null;
809
+ }
810
+
811
+ return {
812
+ frame: {
813
+ functionName: displayName,
814
+ fileName: fileName,
815
+ lineNumber: lineNumber,
816
+ ...(columnNumber === undefined ? {} : { columnNumber: columnNumber }),
817
+ inApp: StackTraceParser.isAppCode(fileName),
818
+ },
819
+ isAnchor: true,
820
+ };
821
+ }
423
822
  }
@@ -63,7 +63,9 @@ jest.mock(
63
63
  );
64
64
 
65
65
  import useEventTimeReferenceLines, {
66
+ EVENT_MARKER_TITLE_MAX_LENGTH,
66
67
  EventTimeReferenceLines,
68
+ truncateEventMarkerTitle,
67
69
  } from "../../../../App/FeatureSet/Dashboard/src/Components/Metrics/Utils/UseEventTimeReferenceLines";
68
70
  import ChartTimeReferenceLineProps from "../../../UI/Components/Charts/Types/TimeReferenceLineProps";
69
71
  import InBetween from "../../../Types/BaseDatabase/InBetween";
@@ -100,6 +102,8 @@ function Probe(props: {
100
102
  data-color={line.color}
101
103
  data-dash={line.strokeDasharray || "solid"}
102
104
  data-clickable={line.onClick ? "yes" : "no"}
105
+ data-kind={line.kind || "none"}
106
+ data-subtitle={line.subtitle || ""}
103
107
  >
104
108
  {line.label}
105
109
  </div>
@@ -194,6 +198,127 @@ describe("useEventTimeReferenceLines", () => {
194
198
  expect(deploy.dataset["clickable"]).toBe("no");
195
199
  });
196
200
 
201
+ test("markers carry the kind and subtitle the rail chip reads", async () => {
202
+ /*
203
+ * `kind` is what lets a chip holding a deploy AND an incident paint
204
+ * itself as the incident; `subtitle` is the card's second line. Both
205
+ * are additions — the label strings the surfaces reverse-engineer are
206
+ * deliberately unchanged.
207
+ */
208
+ getListMock.mockImplementation((args: { modelType: { name: string } }) => {
209
+ if (args.modelType.name === "Incident") {
210
+ return Promise.resolve({
211
+ data: [
212
+ {
213
+ id: new ObjectID("11111111-0000-4000-8000-000000000001"),
214
+ createdAt: "2026-08-20T10:10:00.000Z",
215
+ title: "API is down",
216
+ incidentSeverity: { name: "Sev1", color: "#123456" },
217
+ },
218
+ ],
219
+ });
220
+ }
221
+ return Promise.resolve({
222
+ data: [
223
+ {
224
+ id: new ObjectID("22222222-0000-4000-8000-000000000002"),
225
+ createdAt: "2026-08-20T10:20:00.000Z",
226
+ title: "High latency",
227
+ alertSeverity: { name: "Warning" },
228
+ },
229
+ ],
230
+ });
231
+ });
232
+ analyticsGetListMock.mockResolvedValue({
233
+ data: [
234
+ {
235
+ time: "2026-08-20T10:03:00.000Z",
236
+ title: "v2.31.0",
237
+ eventType: "deployment",
238
+ },
239
+ ],
240
+ });
241
+
242
+ render(<Probe enabled={true} window={WINDOW} />);
243
+
244
+ await waitFor(() => {
245
+ expect(screen.getByTestId("marker-count").textContent).toBe("3");
246
+ });
247
+
248
+ const markers: Array<HTMLElement> = screen.getAllByTestId("marker");
249
+ const byLabel: (needle: string) => HTMLElement = (
250
+ needle: string,
251
+ ): HTMLElement => {
252
+ const found: HTMLElement | undefined = markers.find(
253
+ (marker: HTMLElement) => {
254
+ return (marker.textContent || "").includes(needle);
255
+ },
256
+ );
257
+ if (!found) {
258
+ throw new Error(`no marker containing ${needle}`);
259
+ }
260
+ return found;
261
+ };
262
+
263
+ const incident: HTMLElement = byLabel("Incident: API is down");
264
+ expect(incident.dataset["kind"]).toBe("incident");
265
+ expect(incident.dataset["subtitle"]).toBe("Incident · Sev1");
266
+
267
+ const alert: HTMLElement = byLabel("Alert: High latency");
268
+ expect(alert.dataset["kind"]).toBe("alert");
269
+ expect(alert.dataset["subtitle"]).toBe("Alert · Warning");
270
+
271
+ const deploy: HTMLElement = byLabel("Deploy: v2.31.0");
272
+ expect(deploy.dataset["kind"]).toBe("change");
273
+ expect(deploy.dataset["subtitle"]).toBe("Change event");
274
+ });
275
+
276
+ test("a severity with no name still names the marker's kind", async () => {
277
+ getListMock.mockImplementation((args: { modelType: { name: string } }) => {
278
+ if (args.modelType.name === "Incident") {
279
+ return Promise.resolve({
280
+ data: [
281
+ {
282
+ id: new ObjectID("11111111-0000-4000-8000-000000000001"),
283
+ createdAt: "2026-08-20T10:10:00.000Z",
284
+ title: "API is down",
285
+ incidentSeverity: undefined,
286
+ },
287
+ ],
288
+ });
289
+ }
290
+ return Promise.resolve({ data: [] });
291
+ });
292
+ analyticsGetListMock.mockResolvedValue({ data: [] });
293
+
294
+ render(<Probe enabled={true} window={WINDOW} />);
295
+
296
+ await waitFor(() => {
297
+ expect(screen.getByTestId("marker-count").textContent).toBe("1");
298
+ });
299
+
300
+ const marker: HTMLElement = screen.getAllByTestId("marker")[0]!;
301
+ expect(marker.dataset["kind"]).toBe("incident");
302
+ expect(marker.dataset["subtitle"]).toBe("Incident");
303
+ });
304
+
305
+ test("a long title keeps enough of itself to be recognisable", () => {
306
+ /*
307
+ * The cap exists so a card listing a dozen clustered events stays
308
+ * scannable, not because the label has to fit inside the plot any
309
+ * more — it is generous now, and only bites well past a real title.
310
+ */
311
+ const ordinary: string = "Checkout API p99 latency breached its SLO";
312
+ expect(truncateEventMarkerTitle(ordinary)).toBe(ordinary);
313
+
314
+ const overlong: string = "x".repeat(EVENT_MARKER_TITLE_MAX_LENGTH + 20);
315
+ const truncated: string = truncateEventMarkerTitle(overlong);
316
+ expect(truncated.endsWith("…")).toBe(true);
317
+ expect(truncated.length).toBeLessThanOrEqual(
318
+ EVENT_MARKER_TITLE_MAX_LENGTH + 1,
319
+ );
320
+ });
321
+
197
322
  test("one source failing never takes the others down", async () => {
198
323
  getListMock.mockImplementation((args: { modelType: { name: string } }) => {
199
324
  if (args.modelType.name === "Incident") {