@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,18 +1,35 @@
1
1
  import CreateBy from "../Types/Database/CreateBy";
2
2
  import DeleteBy from "../Types/Database/DeleteBy";
3
+ import Query from "../Types/Database/Query";
3
4
  import UpdateBy from "../Types/Database/UpdateBy";
4
5
  import { OnCreate, OnDelete, OnUpdate } from "../Types/Database/Hooks";
5
6
  import DatabaseService from "./DatabaseService";
6
7
  import ObjectID from "../../Types/ObjectID";
8
+ import OneUptimeDate from "../../Types/Date";
7
9
  import Model from "../../Models/DatabaseModels/TelemetryIngestionKey";
8
10
  import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
9
11
  import InMemoryTTLCache from "../Infrastructure/InMemoryTTLCache";
12
+ import BadDataException from "../../Types/Exception/BadDataException";
13
+ import ColumnLength from "../../Types/Database/ColumnLength";
14
+ import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
15
+ import TelemetryIngestionKeyPolicy from "../../Types/Telemetry/TelemetryIngestionKeyPolicy";
16
+ import TelemetryIngestionKeyType from "../../Types/Telemetry/TelemetryIngestionKeyType";
17
+ import OriginAllowList from "../../Utils/Telemetry/OriginAllowList";
18
+ import logger from "../Utils/Logger";
10
19
  import { createHash } from "crypto";
11
20
 
12
21
  /*
13
22
  * 60s is the worst-case staleness on any single API node after a key is
14
23
  * revoked from the dashboard. We invalidate in-process immediately on
15
24
  * delete/update; this TTL is the upper bound for *other* processes.
25
+ *
26
+ * This bound now covers more than "which project does this token belong to":
27
+ * it also covers the kill switch, the expiry, the origin allowlist and the
28
+ * rate limit. That is a deliberate trade. Turning a compromised key off still
29
+ * takes effect within a minute everywhere, which is fast enough for a control
30
+ * whose whole point is to stop a leak that has already happened, and paying a
31
+ * Postgres round trip per ingest request to shave that to zero would cost far
32
+ * more than it buys on a path that runs thousands of times a second.
16
33
  */
17
34
  const POSITIVE_TTL_MS: number = 60 * 1000;
18
35
  /*
@@ -21,10 +38,82 @@ const POSITIVE_TTL_MS: number = 60 * 1000;
21
38
  */
22
39
  const NEGATIVE_TTL_MS: number = 10 * 1000;
23
40
 
41
+ /*
42
+ * How often a single key's lastUsedAt column may be rewritten, per process.
43
+ *
44
+ * lastUsedAt answers one question - "is anything still using this key, so can
45
+ * I rotate or delete it?" - and five minutes of resolution answers it
46
+ * perfectly. Writing on every ingest request would put a single-row UPDATE on
47
+ * the hottest path in the product and turn the busiest keys into a Postgres
48
+ * lock convoy, which is a real outage in exchange for a column nobody reads
49
+ * more than once a quarter.
50
+ */
51
+ const LAST_USED_THROTTLE_MS: number = 5 * 60 * 1000;
52
+
53
+ /*
54
+ * Ceiling on the number of distinct key ids the throttle map tracks.
55
+ *
56
+ * Only ids that resolved from a real row ever reach markUsed, so this map
57
+ * cannot be grown by an attacker throwing junk tokens at the ingest endpoint -
58
+ * those never authenticate. It is bounded anyway because "the input is
59
+ * trusted" is exactly the assumption that ages badly: a future caller that
60
+ * stamps on a different id, or an installation with an unusual number of keys,
61
+ * must not be able to turn a bookkeeping optimisation into an unbounded
62
+ * process-lifetime leak. Overflowing the bound costs one extra UPDATE per
63
+ * evicted key, which is nothing.
64
+ */
65
+ const LAST_USED_THROTTLE_MAX_KEYS: number = 5000;
66
+
67
+ /*
68
+ * Postgres `integer` upper bound. requestsPerMinuteLimit is a Number column,
69
+ * so anything above this is a database-level error; catching it here turns an
70
+ * ugly 500 into a sentence the customer can act on.
71
+ */
72
+ const MAX_REQUESTS_PER_MINUTE_LIMIT: number = 2147483647;
73
+
74
+ /*
75
+ * What actually lives in the cache: a flat, primitive-only snapshot rather
76
+ * than the policy object itself.
77
+ *
78
+ * Two reasons, both learned from the previous shape of this cache (which
79
+ * stored `projectId.toString()` and rebuilt an ObjectID on read, for the same
80
+ * reason):
81
+ *
82
+ * 1. Callers get a fresh object every time, so nothing on the ingest path
83
+ * can mutate a cached entry - pushing onto `allowedOrigins`, say - and
84
+ * silently change the policy every other request on that pod sees for the
85
+ * next minute.
86
+ * 2. It keeps the entries small and free of live model instances, so a
87
+ * cached policy cannot accidentally keep a whole hydrated entity (or a
88
+ * column nobody meant to expose, such as the secret) alive in memory.
89
+ */
90
+ interface CachedIngestionKeyPolicy {
91
+ ingestionKeyId: string;
92
+ projectId: string;
93
+ keyType: TelemetryIngestionKeyType;
94
+ allowedOrigins: Array<string>;
95
+ pinnedServiceName: string | null;
96
+ isEnabled: boolean;
97
+ expiresAtIso: string | null;
98
+ requestsPerMinuteLimit: number | null;
99
+ }
100
+
24
101
  export class Service extends DatabaseService<Model> {
25
- private projectIdCache: InMemoryTTLCache<string | null> =
102
+ private policyCache: InMemoryTTLCache<CachedIngestionKeyPolicy | null> =
26
103
  new InMemoryTTLCache(10_000);
27
104
 
105
+ /*
106
+ * Per-key throttle for the lastUsedAt stamp. Deliberately in-process rather
107
+ * than in GlobalCache/Redis (which is how RumApplicationService throttles
108
+ * its equivalent health columns): the cost of getting it wrong here is one
109
+ * extra single-row UPDATE per pod per five minutes, and that is not worth
110
+ * putting a Redis round trip - or a Redis dependency - in front of a
111
+ * bookkeeping write on the ingest path. The ingest path must keep working
112
+ * when Redis is down.
113
+ */
114
+ private lastUsedWriteThrottle: InMemoryTTLCache<boolean> =
115
+ new InMemoryTTLCache(LAST_USED_THROTTLE_MAX_KEYS);
116
+
28
117
  public constructor() {
29
118
  super(Model);
30
119
  }
@@ -37,6 +126,69 @@ export class Service extends DatabaseService<Model> {
37
126
  createBy.data.secretKey = ObjectID.generate();
38
127
  }
39
128
 
129
+ /*
130
+ * The typed model surface (PartialEntity/QueryDeepPartialEntity) widens
131
+ * every property into a union with `() => string` and `null`, which makes
132
+ * reading a value for validation a pile of casts at each site. Read the
133
+ * payload once as an untyped bag instead; every value is checked before it
134
+ * is used, and every value written back is the checked, normalised one.
135
+ */
136
+ const data: Record<string, unknown> = createBy.data as unknown as Record<
137
+ string,
138
+ unknown
139
+ >;
140
+
141
+ const keyType: TelemetryIngestionKeyType = this.resolveKeyTypeForCreate(
142
+ data["keyType"],
143
+ );
144
+ data["keyType"] = keyType;
145
+
146
+ const allowedOrigins: Array<string> = this.validateAllowedOrigins(
147
+ data["allowedOrigins"],
148
+ );
149
+
150
+ /*
151
+ * A Browser key with no origin allowlist is precisely the credential this
152
+ * feature exists to stop shipping: a bearer token sitting in public page
153
+ * source that anyone who views source may write telemetry with. There is
154
+ * no permissive default that would be safe, so it is refused at creation
155
+ * rather than defaulted to one.
156
+ *
157
+ * A Server key keeps the historical behaviour - no origin binding at all,
158
+ * because a collector or a backend process does not send an Origin header
159
+ * in the first place - but its patterns are still validated so that a list
160
+ * typed in "for later" is not quietly full of entries that can never
161
+ * match.
162
+ */
163
+ if (
164
+ keyType === TelemetryIngestionKeyType.Browser &&
165
+ allowedOrigins.length === 0
166
+ ) {
167
+ throw new BadDataException(
168
+ "A Browser ingestion key must list at least one allowed origin. A key that is published in a web page can be copied by anyone who views the source, so the origins it may be used from are the only thing that makes it safe to publish.",
169
+ );
170
+ }
171
+
172
+ if (Object.prototype.hasOwnProperty.call(data, "allowedOrigins")) {
173
+ data["allowedOrigins"] = allowedOrigins;
174
+ }
175
+
176
+ if (Object.prototype.hasOwnProperty.call(data, "pinnedServiceName")) {
177
+ data["pinnedServiceName"] = this.validatePinnedServiceName(
178
+ data["pinnedServiceName"],
179
+ );
180
+ }
181
+
182
+ if (Object.prototype.hasOwnProperty.call(data, "requestsPerMinuteLimit")) {
183
+ data["requestsPerMinuteLimit"] = this.validateRequestsPerMinuteLimit(
184
+ data["requestsPerMinuteLimit"],
185
+ );
186
+ }
187
+
188
+ if (Object.prototype.hasOwnProperty.call(data, "expiresAt")) {
189
+ data["expiresAt"] = this.validateExpiresAt(data["expiresAt"]);
190
+ }
191
+
40
192
  return { createBy, carryForward: null };
41
193
  }
42
194
 
@@ -48,7 +200,7 @@ export class Service extends DatabaseService<Model> {
48
200
  * We don't know which secretKey(s) are being deleted without an extra
49
201
  * query; clear the whole cache. Key deletes are rare so this is cheap.
50
202
  */
51
- this.projectIdCache.clear();
203
+ this.policyCache.clear();
52
204
  return { deleteBy, carryForward: null };
53
205
  }
54
206
 
@@ -56,31 +208,115 @@ export class Service extends DatabaseService<Model> {
56
208
  protected override async onBeforeUpdate(
57
209
  updateBy: UpdateBy<Model>,
58
210
  ): Promise<OnUpdate<Model>> {
211
+ const data: Record<string, unknown> = updateBy.data as unknown as Record<
212
+ string,
213
+ unknown
214
+ >;
215
+
216
+ /*
217
+ * "Touched" means the property is present in the patch with a value that
218
+ * is not `undefined`. An explicit `null` IS a touch - it is how a cleared
219
+ * form field arrives - and must be validated and normalised like any other
220
+ * value, not skipped as if it were absent.
221
+ */
222
+ const isTouched: (key: string) => boolean = (key: string): boolean => {
223
+ return (
224
+ Object.prototype.hasOwnProperty.call(data, key) &&
225
+ data[key] !== undefined
226
+ );
227
+ };
228
+
229
+ /*
230
+ * Service-layer backstop for the immutability of keyType.
231
+ *
232
+ * @ColumnAccessControl already declares `update: []` on the column, but
233
+ * that is an API-layer control: it stops a dashboard or API caller, not an
234
+ * internal service that reaches for updateOneById directly. Since flipping
235
+ * a live key's type silently changes what a credential already deployed in
236
+ * production is allowed to do - in either direction, and in the
237
+ * Browser -> Server direction it strips the origin binding off a key that
238
+ * is still sitting in a public page - the rule is enforced here too, where
239
+ * every write path passes through and where it can be tested.
240
+ */
241
+ if (isTouched("keyType")) {
242
+ throw new BadDataException(
243
+ "The key type cannot be changed after the key is created. Create a new ingestion key instead.",
244
+ );
245
+ }
246
+
247
+ if (isTouched("allowedOrigins")) {
248
+ const allowedOrigins: Array<string> = this.validateAllowedOrigins(
249
+ data["allowedOrigins"],
250
+ );
251
+
252
+ /*
253
+ * Only an EMPTY new list needs to know what kind of keys are being
254
+ * updated, so the extra read is paid for only then. A non-empty list is
255
+ * valid on both key types, and the overwhelmingly common update (rename,
256
+ * toggle isEnabled, set an expiry) does not touch allowedOrigins at all
257
+ * and therefore reads nothing extra.
258
+ */
259
+ if (allowedOrigins.length === 0) {
260
+ await this.assertNoBrowserKeyIsBeingUpdated(updateBy);
261
+ }
262
+
263
+ data["allowedOrigins"] = allowedOrigins;
264
+ }
265
+
266
+ if (isTouched("pinnedServiceName")) {
267
+ data["pinnedServiceName"] = this.validatePinnedServiceName(
268
+ data["pinnedServiceName"],
269
+ );
270
+ }
271
+
272
+ if (isTouched("requestsPerMinuteLimit")) {
273
+ data["requestsPerMinuteLimit"] = this.validateRequestsPerMinuteLimit(
274
+ data["requestsPerMinuteLimit"],
275
+ );
276
+ }
277
+
278
+ if (isTouched("expiresAt")) {
279
+ data["expiresAt"] = this.validateExpiresAt(data["expiresAt"]);
280
+ }
281
+
59
282
  /*
60
- * Same reasoning as onBeforeDelete. secretKey is not user-editable today
61
- * but projectId could change, so be conservative.
283
+ * Same reasoning as onBeforeDelete. The cached policy now carries the kill
284
+ * switch, the expiry, the origin allowlist and the rate limit, so almost
285
+ * any edit to this table invalidates it - clearing wholesale stays the
286
+ * right call, and doing it after validation avoids churning the cache for
287
+ * an update that is about to be rejected.
62
288
  */
63
- this.projectIdCache.clear();
289
+ this.policyCache.clear();
64
290
  return { updateBy, carryForward: null };
65
291
  }
66
292
 
67
293
  /**
68
- * Resolve an ingestion token to its projectId, with a short-lived
69
- * in-process cache to keep the hot ingest path off Postgres. Returns null
70
- * for unknown, malformed, or revoked tokens (also cached, for a shorter
71
- * TTL).
294
+ * Resolve an ingestion token to the full policy the ingest guards need,
295
+ * with a short-lived in-process cache to keep the hot ingest path off
296
+ * Postgres. Returns null for unknown or malformed tokens (also cached, for a
297
+ * shorter TTL).
298
+ *
299
+ * A returned policy is NOT a decision: a disabled or expired key still
300
+ * resolves. Enforcement belongs to the caller, which knows which ingest
301
+ * surface it is and can therefore say *why* a request was refused.
72
302
  */
73
303
  @CaptureSpan()
74
- public async getProjectIdFromSecretKey(
304
+ public async getPolicyFromSecretKey(
75
305
  secretKey: string,
76
- ): Promise<ObjectID | null> {
306
+ ): Promise<TelemetryIngestionKeyPolicy | null> {
307
+ /*
308
+ * The cache is keyed on a hash of the token, never the token itself. An
309
+ * in-memory map is dumped by a heap snapshot, a core file or a debugger,
310
+ * and a live ingestion secret is not something to leave lying in one.
311
+ */
77
312
  const cacheKey: string = createHash("sha256")
78
313
  .update(secretKey)
79
314
  .digest("hex");
80
315
 
81
- const cached: string | null | undefined = this.projectIdCache.get(cacheKey);
316
+ const cached: CachedIngestionKeyPolicy | null | undefined =
317
+ this.policyCache.get(cacheKey);
82
318
  if (cached !== undefined) {
83
- return cached === null ? null : new ObjectID(cached);
319
+ return cached === null ? null : this.hydratePolicy(cached);
84
320
  }
85
321
 
86
322
  let secretKeyObjectId: ObjectID;
@@ -88,13 +324,22 @@ export class Service extends DatabaseService<Model> {
88
324
  ObjectID.validateUUID(secretKey);
89
325
  secretKeyObjectId = new ObjectID(secretKey);
90
326
  } catch {
91
- this.projectIdCache.set(cacheKey, null, NEGATIVE_TTL_MS);
327
+ this.policyCache.set(cacheKey, null, NEGATIVE_TTL_MS);
92
328
  return null;
93
329
  }
94
330
 
95
331
  const token: Model | null = await this.findOneBy({
96
332
  query: { secretKey: secretKeyObjectId },
97
- select: { projectId: true },
333
+ select: {
334
+ _id: true,
335
+ projectId: true,
336
+ keyType: true,
337
+ allowedOrigins: true,
338
+ pinnedServiceName: true,
339
+ isEnabled: true,
340
+ expiresAt: true,
341
+ requestsPerMinuteLimit: true,
342
+ },
98
343
  props: { isRoot: true },
99
344
  });
100
345
 
@@ -102,13 +347,471 @@ export class Service extends DatabaseService<Model> {
102
347
  | ObjectID
103
348
  | undefined;
104
349
 
105
- if (!projectId) {
106
- this.projectIdCache.set(cacheKey, null, NEGATIVE_TTL_MS);
350
+ if (!token || !projectId) {
351
+ this.policyCache.set(cacheKey, null, NEGATIVE_TTL_MS);
352
+ return null;
353
+ }
354
+
355
+ const snapshot: CachedIngestionKeyPolicy = this.toCachedPolicy(
356
+ token,
357
+ projectId,
358
+ );
359
+
360
+ this.policyCache.set(cacheKey, snapshot, POSITIVE_TTL_MS);
361
+ return this.hydratePolicy(snapshot);
362
+ }
363
+
364
+ /**
365
+ * Resolve an ingestion token to its projectId.
366
+ *
367
+ * Unchanged in signature and in meaning: it is a LOOKUP, and it answers
368
+ * "which project owns this token" for any token that exists. It deliberately
369
+ * does NOT enforce the kill switch or the expiry.
370
+ *
371
+ * That restraint is the point. Several callers (gRPC, MQTT, session replay,
372
+ * OTLP) use this to decide whether a connection is authenticated at all, and
373
+ * each of them refuses disabled/expired keys explicitly, with a message that
374
+ * names the surface. Quietly folding those checks into a method whose name
375
+ * promises only a lookup would make "key not found" and "key switched off"
376
+ * indistinguishable in every one of those call sites - and would change the
377
+ * behaviour of any caller that has not been updated yet.
378
+ */
379
+ @CaptureSpan()
380
+ public async getProjectIdFromSecretKey(
381
+ secretKey: string,
382
+ ): Promise<ObjectID | null> {
383
+ const policy: TelemetryIngestionKeyPolicy | null =
384
+ await this.getPolicyFromSecretKey(secretKey);
385
+
386
+ if (!policy) {
387
+ return null;
388
+ }
389
+
390
+ return policy.projectId;
391
+ }
392
+
393
+ /**
394
+ * Record that this key was just used, at most once per key per
395
+ * LAST_USED_THROTTLE_MS per process.
396
+ *
397
+ * Fire-and-forget in the strongest sense: it swallows every error it can
398
+ * produce. A failure to write a bookkeeping timestamp must never be able to
399
+ * reject telemetry that was otherwise accepted - dropped spans are not
400
+ * replayed, so turning "the UPDATE failed" into "the customer lost data" is
401
+ * the worst possible trade for a column that exists to help with key
402
+ * rotation hygiene.
403
+ *
404
+ * Modelled on RumApplicationService.markSessionReplayChunkReceived, with the
405
+ * same three properties: throttled, hook-free, and updatedAt-preserving.
406
+ */
407
+ @CaptureSpan()
408
+ public async markUsed(ingestionKeyId: ObjectID): Promise<void> {
409
+ if (!ingestionKeyId) {
410
+ return;
411
+ }
412
+
413
+ const throttleKey: string = ingestionKeyId.toString();
414
+
415
+ try {
416
+ if (this.lastUsedWriteThrottle.get(throttleKey) !== undefined) {
417
+ return; // written recently by this process
418
+ }
419
+
420
+ /*
421
+ * Claim the throttle slot BEFORE the write, not after. Ingest is
422
+ * concurrent, so a dozen requests for the same key can be in this method
423
+ * at once; claiming first means they collapse to one UPDATE instead of a
424
+ * dozen. If the write then fails, the cost is a missing stamp for five
425
+ * minutes, which is exactly the resolution this column has anyway.
426
+ */
427
+ this.lastUsedWriteThrottle.set(throttleKey, true, LAST_USED_THROTTLE_MS);
428
+
429
+ /*
430
+ * Hook-free single-statement UPDATE:
431
+ *
432
+ * - no hooks, so this does not clear the policy cache. That is
433
+ * deliberate: lastUsedAt is not part of the policy, and invalidating
434
+ * every cached key every five minutes because of a passive stamp
435
+ * would send the ingest path back to Postgres for nothing.
436
+ * - skipUpdateDateColumn, so a liveness stamp does not masquerade as a
437
+ * configuration change to anything watching updatedAt.
438
+ */
439
+ await this.updateColumnsByIdWithoutHooks({
440
+ id: ingestionKeyId,
441
+ data: {
442
+ lastUsedAt: OneUptimeDate.getCurrentDate(),
443
+ },
444
+ skipUpdateDateColumn: true,
445
+ });
446
+ } catch (err) {
447
+ logger.warn(
448
+ `TelemetryIngestionKeyService: could not stamp lastUsedAt for ingestion key ${throttleKey}`,
449
+ );
450
+ logger.warn(err);
451
+ }
452
+ }
453
+
454
+ /*
455
+ * Build the cacheable snapshot from a row.
456
+ *
457
+ * Every field is normalised here rather than at the point of use, so there
458
+ * is exactly one place that decides what a missing or malformed column
459
+ * means, and so the ingest guards can be written against a total type
460
+ * instead of a pile of optionals.
461
+ */
462
+ private toCachedPolicy(
463
+ token: Model,
464
+ projectId: ObjectID,
465
+ ): CachedIngestionKeyPolicy {
466
+ /*
467
+ * THE BACKWARDS-COMPATIBILITY HINGE.
468
+ *
469
+ * Every TelemetryIngestionKey that exists today was written before the
470
+ * keyType column did, so it reads back as NULL (or, on a node whose model
471
+ * metadata is momentarily behind a rolling deploy, as absent). Anything
472
+ * that is not exactly "Browser" resolves to Server, which is the
473
+ * historical behaviour in full: no origin checks, every ingest surface, no
474
+ * default rate limit, no pinned service name.
475
+ *
476
+ * Written as an allowlist of the ONE restrictive value rather than a
477
+ * lookup that falls back on failure, so that a typo, a truncated column, a
478
+ * partially applied migration or a hand-edited row can never accidentally
479
+ * relax a Browser key into a Server key. The failure direction here is
480
+ * always towards "behaves like it always did", never towards "quietly
481
+ * gained privileges".
482
+ */
483
+ const keyType: TelemetryIngestionKeyType =
484
+ token.keyType === TelemetryIngestionKeyType.Browser
485
+ ? TelemetryIngestionKeyType.Browser
486
+ : TelemetryIngestionKeyType.Server;
487
+
488
+ /*
489
+ * Blank entries are dropped, not just non-strings. OriginAllowList.matches
490
+ * skips a blank pattern, so a list of [""] would match nothing while still
491
+ * being non-empty - and "non-empty" is what the ingest guard checks before
492
+ * it decides a Browser key is configured at all. Dropping blanks here
493
+ * makes those two agree: a non-empty list always contains at least one
494
+ * pattern that can actually match.
495
+ */
496
+ const rawAllowedOrigins: unknown = token.allowedOrigins;
497
+ const allowedOrigins: Array<string> = Array.isArray(rawAllowedOrigins)
498
+ ? (rawAllowedOrigins as Array<unknown>)
499
+ .filter((entry: unknown): boolean => {
500
+ return typeof entry === "string" && entry.trim().length > 0;
501
+ })
502
+ .map((entry: unknown): string => {
503
+ return entry as string;
504
+ })
505
+ : [];
506
+
507
+ const rawPinnedServiceName: unknown = token.pinnedServiceName;
508
+ const pinnedServiceName: string | null =
509
+ typeof rawPinnedServiceName === "string" &&
510
+ rawPinnedServiceName.trim().length > 0
511
+ ? rawPinnedServiceName.trim()
512
+ : null;
513
+
514
+ /*
515
+ * Only an explicit `false` disables a key. A row that predates the column
516
+ * reads back NULL and must stay enabled - the alternative would take every
517
+ * existing installation's telemetry offline the moment this ships, which
518
+ * is the one outcome this whole change is not allowed to have.
519
+ */
520
+ const isEnabled: boolean = token.isEnabled !== false;
521
+
522
+ /*
523
+ * A value that will not parse is treated as "no expiry" rather than "expired".
524
+ * It cannot arise from a TIMESTAMPTZ column, so the only way to get here is
525
+ * a corrupt or hand-written row, and refusing a customer's live telemetry
526
+ * because a date column is unreadable is a worse failure than honouring the
527
+ * historical never-expires behaviour.
528
+ */
529
+ let expiresAtIso: string | null = null;
530
+ if (token.expiresAt) {
531
+ const expiresAt: Date = OneUptimeDate.fromString(token.expiresAt);
532
+ if (expiresAt instanceof Date && !Number.isNaN(expiresAt.getTime())) {
533
+ expiresAtIso = expiresAt.toISOString();
534
+ }
535
+ }
536
+
537
+ /*
538
+ * 0, a negative number or garbage all resolve to null - "no explicit limit
539
+ * configured" - not to "block everything". Neither can be written through
540
+ * this service (create/update reject them), so reaching here means a
541
+ * legacy or hand-edited row, and reading such a row as a total block would
542
+ * silently black out a customer's ingest. Null instead means a Browser key
543
+ * falls back to the shipped default and a Server key stays unlimited,
544
+ * which is what the column's own documentation promises.
545
+ */
546
+ const rawRequestsPerMinuteLimit: unknown = token.requestsPerMinuteLimit;
547
+ const requestsPerMinuteLimit: number | null =
548
+ typeof rawRequestsPerMinuteLimit === "number" &&
549
+ Number.isFinite(rawRequestsPerMinuteLimit) &&
550
+ rawRequestsPerMinuteLimit > 0
551
+ ? Math.floor(rawRequestsPerMinuteLimit)
552
+ : null;
553
+
554
+ /*
555
+ * `_id` is the primary key and is always selected, so a row without one
556
+ * cannot come back from a real query. The resolver still has to be total,
557
+ * though, and returning null for a row that plainly exists would turn a
558
+ * shape surprise into a complete ingest outage for that key. Falling back
559
+ * to the zero id keeps the key working and degrades only the two things
560
+ * that are keyed on the id: the rate-limit bucket (which would be shared)
561
+ * and the lastUsedAt stamp (whose UPDATE would match no row). Neither is a
562
+ * security control - the kill switch, the expiry and the origin allowlist
563
+ * all come from the row's own columns.
564
+ */
565
+ const ingestionKeyId: string = token._id
566
+ ? token._id.toString()
567
+ : ObjectID.getZeroObjectID().toString();
568
+
569
+ return {
570
+ ingestionKeyId: ingestionKeyId,
571
+ projectId: projectId.toString(),
572
+ keyType: keyType,
573
+ allowedOrigins: allowedOrigins,
574
+ pinnedServiceName: pinnedServiceName,
575
+ isEnabled: isEnabled,
576
+ expiresAtIso: expiresAtIso,
577
+ requestsPerMinuteLimit: requestsPerMinuteLimit,
578
+ };
579
+ }
580
+
581
+ /*
582
+ * Rebuild a live policy from a snapshot. The array is copied and the
583
+ * ObjectIDs/Date are reconstructed so that a caller holding a policy cannot
584
+ * reach back into the cache and mutate what every other request on this pod
585
+ * will see for the rest of the TTL.
586
+ */
587
+ private hydratePolicy(
588
+ cached: CachedIngestionKeyPolicy,
589
+ ): TelemetryIngestionKeyPolicy {
590
+ return {
591
+ ingestionKeyId: new ObjectID(cached.ingestionKeyId),
592
+ projectId: new ObjectID(cached.projectId),
593
+ keyType: cached.keyType,
594
+ allowedOrigins: [...cached.allowedOrigins],
595
+ pinnedServiceName: cached.pinnedServiceName,
596
+ isEnabled: cached.isEnabled,
597
+ expiresAt: cached.expiresAtIso ? new Date(cached.expiresAtIso) : null,
598
+ requestsPerMinuteLimit: cached.requestsPerMinuteLimit,
599
+ };
600
+ }
601
+
602
+ /*
603
+ * Unlike the read path - which forgives anything, because an existing row
604
+ * must keep working - the write path is strict. A key type it does not
605
+ * recognise is refused rather than silently coerced to Server, because
606
+ * "I asked for a Browser key and got a Server key" is a security surprise,
607
+ * not a typo the system should paper over.
608
+ */
609
+ private resolveKeyTypeForCreate(value: unknown): TelemetryIngestionKeyType {
610
+ if (value === undefined || value === null || value === "") {
611
+ return TelemetryIngestionKeyType.Server;
612
+ }
613
+
614
+ if (value === TelemetryIngestionKeyType.Browser) {
615
+ return TelemetryIngestionKeyType.Browser;
616
+ }
617
+
618
+ if (value === TelemetryIngestionKeyType.Server) {
619
+ return TelemetryIngestionKeyType.Server;
620
+ }
621
+
622
+ throw new BadDataException(
623
+ `"${String(value)}" is not a valid ingestion key type. Use "${
624
+ TelemetryIngestionKeyType.Server
625
+ }" or "${TelemetryIngestionKeyType.Browser}".`,
626
+ );
627
+ }
628
+
629
+ /*
630
+ * Validate and canonicalise an allowlist.
631
+ *
632
+ * Entries are stored in the same normalised form the matcher compares
633
+ * against (trimmed, lowercased, no trailing slash) and exact duplicates are
634
+ * collapsed, so what the customer sees listed in the dashboard is exactly
635
+ * what will be matched at ingest time. An origin's scheme and host are
636
+ * case-insensitive, so lowercasing changes nothing about what the entry
637
+ * means - it only removes a class of "why doesn't this match?" support
638
+ * question that has no visible cause.
639
+ */
640
+ private validateAllowedOrigins(value: unknown): Array<string> {
641
+ if (value === undefined || value === null) {
642
+ return [];
643
+ }
644
+
645
+ if (!Array.isArray(value)) {
646
+ throw new BadDataException(
647
+ 'Allowed origins must be a list of origins, for example ["https://app.example.com"].',
648
+ );
649
+ }
650
+
651
+ const normalized: Array<string> = [];
652
+ const seen: Set<string> = new Set();
653
+
654
+ for (const entry of value as Array<unknown>) {
655
+ if (typeof entry !== "string") {
656
+ throw new BadDataException(
657
+ "Every allowed origin must be text, with one origin per entry.",
658
+ );
659
+ }
660
+
661
+ if (!entry.trim()) {
662
+ continue;
663
+ }
664
+
665
+ const validationError: string | null =
666
+ OriginAllowList.validateOriginPattern(entry);
667
+
668
+ if (validationError) {
669
+ throw new BadDataException(validationError);
670
+ }
671
+
672
+ const canonical: string = OriginAllowList.normalizeOrigin(entry);
673
+
674
+ if (seen.has(canonical)) {
675
+ continue;
676
+ }
677
+
678
+ seen.add(canonical);
679
+ normalized.push(canonical);
680
+ }
681
+
682
+ return normalized;
683
+ }
684
+
685
+ /*
686
+ * Blank means "clear it", not "reject it". An emptied text field arrives as
687
+ * "" or null, and refusing that would leave a customer who pinned a service
688
+ * name unable to ever unpin it through the dashboard. Anything non-blank has
689
+ * to fit the column, since a silently truncated service name would pin
690
+ * telemetry to a name that matches nothing the customer expects.
691
+ */
692
+ private validatePinnedServiceName(value: unknown): string | null {
693
+ if (value === undefined || value === null) {
694
+ return null;
695
+ }
696
+
697
+ if (typeof value !== "string") {
698
+ throw new BadDataException("The pinned service name must be text.");
699
+ }
700
+
701
+ const trimmed: string = value.trim();
702
+
703
+ if (!trimmed) {
107
704
  return null;
108
705
  }
109
706
 
110
- this.projectIdCache.set(cacheKey, projectId.toString(), POSITIVE_TTL_MS);
111
- return projectId;
707
+ if (trimmed.length > ColumnLength.ShortText) {
708
+ throw new BadDataException(
709
+ `The pinned service name cannot be longer than ${ColumnLength.ShortText} characters.`,
710
+ );
711
+ }
712
+
713
+ return trimmed;
714
+ }
715
+
716
+ private validateRequestsPerMinuteLimit(value: unknown): number | null {
717
+ if (value === undefined || value === null || value === "") {
718
+ return null;
719
+ }
720
+
721
+ const limit: number = typeof value === "number" ? value : Number(value);
722
+
723
+ if (!Number.isFinite(limit) || !Number.isInteger(limit) || limit <= 0) {
724
+ throw new BadDataException(
725
+ "The requests per minute limit must be a whole number greater than 0. Leave it empty to use the default for the key type.",
726
+ );
727
+ }
728
+
729
+ if (limit > MAX_REQUESTS_PER_MINUTE_LIMIT) {
730
+ throw new BadDataException(
731
+ `The requests per minute limit cannot be greater than ${MAX_REQUESTS_PER_MINUTE_LIMIT}.`,
732
+ );
733
+ }
734
+
735
+ return limit;
736
+ }
737
+
738
+ private validateExpiresAt(value: unknown): Date | null {
739
+ if (value === undefined || value === null || value === "") {
740
+ return null;
741
+ }
742
+
743
+ let expiresAt: Date;
744
+
745
+ try {
746
+ expiresAt = OneUptimeDate.fromString(value as string | Date);
747
+ } catch {
748
+ throw new BadDataException("The expiry date is not a valid date.");
749
+ }
750
+
751
+ if (!(expiresAt instanceof Date) || Number.isNaN(expiresAt.getTime())) {
752
+ throw new BadDataException("The expiry date is not a valid date.");
753
+ }
754
+
755
+ /*
756
+ * Refused rather than accepted-and-immediately-dead. Saving an expiry in
757
+ * the past silently bricks the key, and the symptom - telemetry stops
758
+ * arriving, with a key that still looks fine in the list - is exactly the
759
+ * kind of failure that costs an afternoon to diagnose.
760
+ */
761
+ if (!OneUptimeDate.isInTheFuture(expiresAt)) {
762
+ throw new BadDataException(
763
+ "The expiry date must be in the future. A key that expires in the past would stop accepting telemetry as soon as it is saved.",
764
+ );
765
+ }
766
+
767
+ return expiresAt;
768
+ }
769
+
770
+ /*
771
+ * Refuse to empty the allowlist when any row the update matches is a Browser
772
+ * key.
773
+ *
774
+ * The database cannot express "non-empty only when keyType is Browser", and
775
+ * an update patch does not carry the key type (it cannot - keyType is
776
+ * immutable and therefore never in the patch), so the affected rows have to
777
+ * be read. Only _id and keyType are selected; nothing here needs anything
778
+ * else.
779
+ *
780
+ * The read runs as root because it is a policy check, not a data return: it
781
+ * must see every row the update will actually touch, including ones the
782
+ * caller could not read. The caller's tenant is still applied when the query
783
+ * does not name a project itself, so a broad query cannot be tricked into
784
+ * failing this check because of some other project's key.
785
+ */
786
+ private async assertNoBrowserKeyIsBeingUpdated(
787
+ updateBy: UpdateBy<Model>,
788
+ ): Promise<void> {
789
+ const query: Query<Model> = { ...updateBy.query };
790
+
791
+ if (!query.projectId && updateBy.props.tenantId) {
792
+ query.projectId = updateBy.props.tenantId;
793
+ }
794
+
795
+ const affectedKeys: Array<Model> = await this.findBy({
796
+ query: query,
797
+ select: {
798
+ _id: true,
799
+ keyType: true,
800
+ },
801
+ props: {
802
+ isRoot: true,
803
+ },
804
+ skip: 0,
805
+ limit: LIMIT_PER_PROJECT,
806
+ });
807
+
808
+ for (const affectedKey of affectedKeys) {
809
+ if (affectedKey.keyType === TelemetryIngestionKeyType.Browser) {
810
+ throw new BadDataException(
811
+ `A Browser ingestion key must keep at least one allowed origin. Clearing the list would stop the key accepting any telemetry - turn the key off or delete it instead. (Key ID: ${affectedKey._id})`,
812
+ );
813
+ }
814
+ }
112
815
  }
113
816
  }
114
817