@oneuptime/common 12.0.1 → 12.0.3

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 (385) hide show
  1. package/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.ts +14 -0
  2. package/Models/DatabaseModels/Host.ts +12 -4
  3. package/Models/DatabaseModels/Index.ts +2 -0
  4. package/Models/DatabaseModels/KubernetesContainer.ts +5 -4
  5. package/Models/DatabaseModels/KubernetesResource.ts +8 -7
  6. package/Models/DatabaseModels/LogDropFilter.ts +9 -20
  7. package/Models/DatabaseModels/PodmanResource.ts +6 -6
  8. package/Models/DatabaseModels/ServiceLevelObjective.ts +91 -0
  9. package/Models/DatabaseModels/StatusPage.ts +95 -0
  10. package/Models/DatabaseModels/StatusPageMonitorRule.ts +911 -0
  11. package/Models/DatabaseModels/StatusPageResource.ts +73 -0
  12. package/Models/DatabaseModels/TraceDropFilter.ts +9 -20
  13. package/Server/API/BaseAPI.ts +13 -2
  14. package/Server/API/DashboardAPI.ts +39 -0
  15. package/Server/API/TeamMemberAPI.ts +85 -0
  16. package/Server/EnvironmentConfig.ts +31 -1
  17. package/Server/Infrastructure/GlobalCache.ts +115 -0
  18. package/Server/Infrastructure/Postgres/DataSourceOptions.ts +16 -0
  19. package/Server/Infrastructure/Postgres/SchemaMigrations/1785900000000-AddSloMonitorLabelRule.ts +84 -0
  20. package/Server/Infrastructure/Postgres/SchemaMigrations/1785915638551-IncreaseHostIpAddressesLength.ts +40 -0
  21. package/Server/Infrastructure/Postgres/SchemaMigrations/1785930000000-WidenInventoryResourceNameColumns.ts +131 -0
  22. package/Server/Infrastructure/Postgres/SchemaMigrations/1785930709405-AddStatusPageReportPeriod.ts +25 -0
  23. package/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.ts +123 -0
  24. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +10 -0
  25. package/Server/Middleware/ProjectAuthorization.ts +66 -4
  26. package/Server/Services/AlertStateTimelineService.ts +20 -0
  27. package/Server/Services/BillingService.ts +600 -51
  28. package/Server/Services/CephClusterService.ts +27 -45
  29. package/Server/Services/CephResourceService.ts +43 -4
  30. package/Server/Services/CloudResourceService.ts +24 -42
  31. package/Server/Services/DatabaseService.ts +198 -6
  32. package/Server/Services/DockerHostService.ts +20 -38
  33. package/Server/Services/DockerResourceService.ts +62 -8
  34. package/Server/Services/DockerSwarmClusterService.ts +28 -46
  35. package/Server/Services/DockerSwarmResourceService.ts +53 -4
  36. package/Server/Services/HostService.ts +47 -57
  37. package/Server/Services/IncidentStateTimelineService.ts +20 -0
  38. package/Server/Services/Index.ts +2 -0
  39. package/Server/Services/IoTDeviceService.ts +1 -17
  40. package/Server/Services/IoTFleetService.ts +20 -38
  41. package/Server/Services/KubernetesClusterService.ts +18 -36
  42. package/Server/Services/KubernetesContainerService.ts +50 -9
  43. package/Server/Services/KubernetesResourceService.ts +53 -7
  44. package/Server/Services/LabelService.ts +153 -1
  45. package/Server/Services/MetricTypeService.ts +84 -0
  46. package/Server/Services/MonitorService.ts +146 -14
  47. package/Server/Services/MonitorStatusTimelineService.ts +29 -0
  48. package/Server/Services/MonitorTemplateService.ts +65 -0
  49. package/Server/Services/PodmanHostService.ts +20 -38
  50. package/Server/Services/PodmanResourceService.ts +62 -8
  51. package/Server/Services/ProjectService.ts +165 -35
  52. package/Server/Services/ProxmoxClusterService.ts +24 -42
  53. package/Server/Services/ProxmoxResourceService.ts +43 -4
  54. package/Server/Services/RumApplicationService.ts +20 -38
  55. package/Server/Services/ScheduledMaintenanceStateTimelineService.ts +21 -0
  56. package/Server/Services/ServerlessFunctionService.ts +25 -43
  57. package/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.ts +426 -0
  58. package/Server/Services/ServiceLevelObjectiveService.ts +39 -0
  59. package/Server/Services/ServiceService.ts +299 -73
  60. package/Server/Services/StatusPageMonitorRuleEngineService.ts +752 -0
  61. package/Server/Services/StatusPageMonitorRuleService.ts +471 -0
  62. package/Server/Services/StatusPageService.ts +95 -36
  63. package/Server/Services/StatusPageSubscriberNotificationTemplateService.ts +18 -1
  64. package/Server/Services/StatusPageSubscriberService.ts +3 -0
  65. package/Server/Services/TelemetryEntityRelationshipService.ts +1 -0
  66. package/Server/Services/TelemetryEntityService.ts +1 -0
  67. package/Server/Types/Database/JSONColumnQuery.ts +621 -0
  68. package/Server/Types/Database/Permissions/PublicPermission.ts +9 -2
  69. package/Server/Types/Database/QueryHelper.ts +17 -32
  70. package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +170 -39
  71. package/Server/Utils/Database/TruncateColumnValue.ts +84 -0
  72. package/Server/Utils/Monitor/MonitorResource.ts +63 -36
  73. package/Server/Utils/Monitor/MonitorStatusTimeline.ts +36 -0
  74. package/Server/Utils/Monitor/MonitorStepsProjectValidator.ts +148 -127
  75. package/Server/Utils/Monitor/MonitorStepsReferenceExtractor.ts +434 -0
  76. package/Server/Utils/SingleFlight.ts +83 -0
  77. package/Server/Utils/StatusPage/MonitorRulePatternValidator.ts +46 -0
  78. package/Server/Utils/Telemetry/EntityRegistry.ts +107 -26
  79. package/Server/Utils/Telemetry/ResourceHeartbeat.ts +314 -0
  80. package/Server/Utils/Telemetry/Telemetry.ts +351 -122
  81. package/Tests/App/Dashboard/UsersTableGroupsByPerson.test.tsx +448 -0
  82. package/Tests/App/Dashboard/WidgetCatalog.test.ts +2 -0
  83. package/Tests/Models/DatabaseModels/ColumnTransformerInvariants.test.ts +306 -0
  84. package/Tests/Models/DatabaseModels/NumberColumnDeserialization.test.ts +333 -0
  85. package/Tests/Models/DatabaseModels/StatusPageMonitorRuleModel.test.ts +190 -0
  86. package/Tests/Server/API/BaseAPIApiKeyAuth.test.ts +704 -0
  87. package/Tests/Server/API/DashboardPublicResourceListAPI.test.ts +26 -0
  88. package/Tests/Server/API/TeamMemberRemoveUserFromProjectAPI.test.ts +303 -0
  89. package/Tests/Server/Infrastructure/GlobalCache.test.ts +226 -0
  90. package/Tests/Server/Infrastructure/PostgresLockTimeoutOptions.test.ts +181 -0
  91. package/Tests/Server/Middleware/MasterAdminAuthorization.test.ts +350 -0
  92. package/Tests/Server/Middleware/ProjectAuthorizationApiKeyHeader.test.ts +362 -0
  93. package/Tests/Server/Middleware/ProjectAuthorizationApiKeyMiddleware.test.ts +687 -0
  94. package/Tests/Server/Services/BillingService.test.ts +78 -3
  95. package/Tests/Server/Services/BillingServiceChangePlanCancel.test.ts +645 -0
  96. package/Tests/Server/Services/BillingServiceTrialPlanChange.test.ts +1005 -0
  97. package/Tests/Server/Services/DatabaseServiceUpdateColumnsIfUnlocked.test.ts +342 -0
  98. package/Tests/Server/Services/DropFilterSaveValidation.test.ts +245 -0
  99. package/Tests/Server/Services/HookFreeWriteLengthClamp.test.ts +503 -0
  100. package/Tests/Server/Services/HostIpAddressesColumnWidth.test.ts +198 -0
  101. package/Tests/Server/Services/HostServiceUpdateLastSeen.test.ts +658 -0
  102. package/Tests/Server/Services/InventoryResourceNameColumnWidth.test.ts +500 -0
  103. package/Tests/Server/Services/InventoryUpsertSchemaParity.test.ts +586 -0
  104. package/Tests/Server/Services/InventoryUpsertTruncationGuard.test.ts +1242 -0
  105. package/Tests/Server/Services/MetricTypeAttachServices.test.ts +222 -0
  106. package/Tests/Server/Services/MissingReferenceWriteGuard.test.ts +614 -0
  107. package/Tests/Server/Services/MonitorStatusTimelineFastPath.test.ts +23 -0
  108. package/Tests/Server/Services/ProjectServiceChangePlan.test.ts +650 -0
  109. package/Tests/Server/Services/ProjectServiceExtendTrial.test.ts +1 -0
  110. package/Tests/Server/Services/ResourceUpdateLastSeenLivenessFallback.test.ts +636 -0
  111. package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.test.ts +770 -0
  112. package/Tests/Server/Services/ServiceLevelObjectiveService.test.ts +130 -0
  113. package/Tests/Server/Services/ServiceUpdateLastSeenSplitGates.test.ts +705 -0
  114. package/Tests/Server/Services/SloMonitorLabelRuleHooks.test.ts +352 -0
  115. package/Tests/Server/Services/StatusPageMonitorRuleEngineService.test.ts +1719 -0
  116. package/Tests/Server/Services/StatusPageMonitorRuleHooks.test.ts +1212 -0
  117. package/Tests/Server/Services/StatusPageMonitorRuleMonitorCreateHook.test.ts +228 -0
  118. package/Tests/Server/Services/StatusPageSubscriberReport.test.ts +29 -13
  119. package/Tests/Server/TestingUtils/Services/BillingServiceHelper.ts +69 -8
  120. package/Tests/Server/Types/Database/JSONColumnQuery.test.ts +593 -0
  121. package/Tests/Server/Types/Database/Permissions/PublicPermission.test.ts +495 -0
  122. package/Tests/Server/Types/Database/QueryUtil.test.ts +113 -0
  123. package/Tests/Server/Utils/APIKey/AccessPermission.test.ts +267 -0
  124. package/Tests/Server/Utils/Database/ProjectScopedReferenceValidator.test.ts +260 -13
  125. package/Tests/Server/Utils/Database/TruncateColumnValue.test.ts +179 -0
  126. package/Tests/Server/Utils/EntityRegistryRowFence.test.ts +302 -0
  127. package/Tests/Server/Utils/MetricTypeIndexConvergence.test.ts +598 -0
  128. package/Tests/Server/Utils/Monitor/MonitorStatusTimelineUnusableStatus.test.ts +154 -0
  129. package/Tests/Server/Utils/Monitor/MonitorStepsProjectValidator.test.ts +638 -92
  130. package/Tests/Server/Utils/Monitor/MonitorStepsReferenceExtractor.test.ts +724 -0
  131. package/Tests/Server/Utils/SingleFlight.test.ts +221 -0
  132. package/Tests/Types/Dashboard/NetworkDashboardTemplate.test.ts +793 -0
  133. package/Tests/Types/Database/BigIntColumnTransformer.test.ts +147 -0
  134. package/Tests/Types/Database/DatabasePropertyTransformer.test.ts +140 -0
  135. package/Tests/Types/Database/NumericColumnValue.test.ts +127 -0
  136. package/Tests/Types/Decimal.test.ts +37 -0
  137. package/Tests/Types/Events/Recurring.test.ts +157 -0
  138. package/Tests/Types/Monitor/SnmpVersionParsing.test.ts +152 -0
  139. package/Tests/Types/Port.test.ts +38 -0
  140. package/Tests/UI/Components/LogsHistogram.test.tsx +276 -0
  141. package/Tests/UI/Components/ModelTable/ModelTableGroupsProjectUsers.test.tsx +375 -0
  142. package/Tests/UI/Components/ModelTable/useCustomFieldColumns.test.tsx +196 -0
  143. package/Tests/UI/Components/UseLiveLogsRefresh.test.tsx +489 -0
  144. package/Tests/UI/Components/UseLogsHistogram.test.tsx +500 -0
  145. package/Tests/UI/Utils/ProjectUsersModelAPI.test.ts +739 -0
  146. package/Tests/UI/Utils/TeamMembersByUser.test.ts +633 -0
  147. package/Tests/Utils/Dashboard/Components/DashboardComponentsUtil.test.ts +120 -0
  148. package/Tests/Utils/Dashboard/DashboardNetworkMapComponent.test.ts +327 -0
  149. package/Tests/Utils/StatusPage/ReportPeriod.test.ts +218 -0
  150. package/Tests/Utils/Telemetry/HostIpAddresses.test.ts +291 -0
  151. package/Types/CustomField/CustomFieldDefinition.ts +24 -0
  152. package/Types/Dashboard/DashboardComponentType.ts +1 -0
  153. package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +1 -0
  154. package/Types/Dashboard/DashboardComponents/DashboardNetworkMapComponent.ts +40 -0
  155. package/Types/Dashboard/DashboardTemplates.ts +397 -0
  156. package/Types/Database/BigIntColumnTransformer.ts +74 -0
  157. package/Types/Database/DatabaseProperty.ts +26 -0
  158. package/Types/Database/NumericColumnValue.ts +128 -0
  159. package/Types/Date.ts +112 -0
  160. package/Types/Decimal.ts +16 -4
  161. package/Types/Events/Recurring.ts +99 -1
  162. package/Types/Permission.ts +48 -0
  163. package/Types/Port.ts +16 -4
  164. package/Types/StatusPage/StatusPageReport.ts +11 -0
  165. package/Types/StatusPage/StatusPageReportPeriodType.ts +21 -0
  166. package/UI/Components/LogsViewer/useLiveLogsRefresh.ts +86 -0
  167. package/UI/Components/LogsViewer/useLogsHistogram.ts +113 -0
  168. package/UI/Components/ModelTable/CustomFieldColumns.tsx +2 -6
  169. package/UI/Components/ModelTable/useCustomFieldColumns.ts +21 -2
  170. package/UI/Utils/ModelAPI/ProjectUsersModelAPI.ts +305 -0
  171. package/UI/Utils/TeamMembersByUser.ts +302 -0
  172. package/Utils/Dashboard/Components/DashboardNetworkMapComponent.ts +136 -0
  173. package/Utils/Dashboard/Components/Index.ts +7 -0
  174. package/Utils/StatusPage/ReportPeriod.ts +236 -0
  175. package/Utils/Telemetry/HostIpAddresses.ts +98 -0
  176. package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js +12 -0
  177. package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js.map +1 -1
  178. package/build/dist/Models/DatabaseModels/Host.js +12 -4
  179. package/build/dist/Models/DatabaseModels/Host.js.map +1 -1
  180. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  181. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  182. package/build/dist/Models/DatabaseModels/KubernetesContainer.js +4 -4
  183. package/build/dist/Models/DatabaseModels/KubernetesContainer.js.map +1 -1
  184. package/build/dist/Models/DatabaseModels/KubernetesResource.js +7 -7
  185. package/build/dist/Models/DatabaseModels/KubernetesResource.js.map +1 -1
  186. package/build/dist/Models/DatabaseModels/LogDropFilter.js +9 -20
  187. package/build/dist/Models/DatabaseModels/LogDropFilter.js.map +1 -1
  188. package/build/dist/Models/DatabaseModels/PodmanResource.js +6 -6
  189. package/build/dist/Models/DatabaseModels/PodmanResource.js.map +1 -1
  190. package/build/dist/Models/DatabaseModels/ServiceLevelObjective.js +87 -0
  191. package/build/dist/Models/DatabaseModels/ServiceLevelObjective.js.map +1 -1
  192. package/build/dist/Models/DatabaseModels/StatusPage.js +98 -0
  193. package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
  194. package/build/dist/Models/DatabaseModels/StatusPageMonitorRule.js +925 -0
  195. package/build/dist/Models/DatabaseModels/StatusPageMonitorRule.js.map +1 -0
  196. package/build/dist/Models/DatabaseModels/StatusPageResource.js +72 -0
  197. package/build/dist/Models/DatabaseModels/StatusPageResource.js.map +1 -1
  198. package/build/dist/Models/DatabaseModels/TraceDropFilter.js +9 -20
  199. package/build/dist/Models/DatabaseModels/TraceDropFilter.js.map +1 -1
  200. package/build/dist/Server/API/BaseAPI.js +11 -1
  201. package/build/dist/Server/API/BaseAPI.js.map +1 -1
  202. package/build/dist/Server/API/DashboardAPI.js +39 -0
  203. package/build/dist/Server/API/DashboardAPI.js.map +1 -1
  204. package/build/dist/Server/API/TeamMemberAPI.js +57 -2
  205. package/build/dist/Server/API/TeamMemberAPI.js.map +1 -1
  206. package/build/dist/Server/EnvironmentConfig.js +27 -1
  207. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  208. package/build/dist/Server/Infrastructure/GlobalCache.js +91 -0
  209. package/build/dist/Server/Infrastructure/GlobalCache.js.map +1 -1
  210. package/build/dist/Server/Infrastructure/Postgres/DataSourceOptions.js +5 -3
  211. package/build/dist/Server/Infrastructure/Postgres/DataSourceOptions.js.map +1 -1
  212. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785900000000-AddSloMonitorLabelRule.js +45 -0
  213. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785900000000-AddSloMonitorLabelRule.js.map +1 -0
  214. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785915638551-IncreaseHostIpAddressesLength.js +31 -0
  215. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785915638551-IncreaseHostIpAddressesLength.js.map +1 -0
  216. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785930000000-WidenInventoryResourceNameColumns.js +90 -0
  217. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785930000000-WidenInventoryResourceNameColumns.js.map +1 -0
  218. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785930709405-AddStatusPageReportPeriod.js +14 -0
  219. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785930709405-AddStatusPageReportPeriod.js.map +1 -0
  220. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.js +48 -0
  221. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.js.map +1 -0
  222. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +10 -0
  223. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  224. package/build/dist/Server/Middleware/ProjectAuthorization.js +59 -4
  225. package/build/dist/Server/Middleware/ProjectAuthorization.js.map +1 -1
  226. package/build/dist/Server/Services/AlertStateTimelineService.js +19 -0
  227. package/build/dist/Server/Services/AlertStateTimelineService.js.map +1 -1
  228. package/build/dist/Server/Services/BillingService.js +466 -36
  229. package/build/dist/Server/Services/BillingService.js.map +1 -1
  230. package/build/dist/Server/Services/CephClusterService.js +26 -39
  231. package/build/dist/Server/Services/CephClusterService.js.map +1 -1
  232. package/build/dist/Server/Services/CephResourceService.js +28 -3
  233. package/build/dist/Server/Services/CephResourceService.js.map +1 -1
  234. package/build/dist/Server/Services/CloudResourceService.js +23 -36
  235. package/build/dist/Server/Services/CloudResourceService.js.map +1 -1
  236. package/build/dist/Server/Services/DatabaseService.js +155 -2
  237. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  238. package/build/dist/Server/Services/DockerHostService.js +19 -32
  239. package/build/dist/Server/Services/DockerHostService.js.map +1 -1
  240. package/build/dist/Server/Services/DockerResourceService.js +34 -4
  241. package/build/dist/Server/Services/DockerResourceService.js.map +1 -1
  242. package/build/dist/Server/Services/DockerSwarmClusterService.js +27 -40
  243. package/build/dist/Server/Services/DockerSwarmClusterService.js.map +1 -1
  244. package/build/dist/Server/Services/DockerSwarmResourceService.js +28 -3
  245. package/build/dist/Server/Services/DockerSwarmResourceService.js.map +1 -1
  246. package/build/dist/Server/Services/HostService.js +58 -64
  247. package/build/dist/Server/Services/HostService.js.map +1 -1
  248. package/build/dist/Server/Services/IncidentStateTimelineService.js +19 -0
  249. package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
  250. package/build/dist/Server/Services/Index.js +2 -0
  251. package/build/dist/Server/Services/Index.js.map +1 -1
  252. package/build/dist/Server/Services/IoTDeviceService.js +1 -8
  253. package/build/dist/Server/Services/IoTDeviceService.js.map +1 -1
  254. package/build/dist/Server/Services/IoTFleetService.js +19 -32
  255. package/build/dist/Server/Services/IoTFleetService.js.map +1 -1
  256. package/build/dist/Server/Services/KubernetesClusterService.js +17 -30
  257. package/build/dist/Server/Services/KubernetesClusterService.js.map +1 -1
  258. package/build/dist/Server/Services/KubernetesContainerService.js +29 -3
  259. package/build/dist/Server/Services/KubernetesContainerService.js.map +1 -1
  260. package/build/dist/Server/Services/KubernetesResourceService.js +32 -4
  261. package/build/dist/Server/Services/KubernetesResourceService.js.map +1 -1
  262. package/build/dist/Server/Services/LabelService.js +127 -0
  263. package/build/dist/Server/Services/LabelService.js.map +1 -1
  264. package/build/dist/Server/Services/MetricTypeService.js +74 -0
  265. package/build/dist/Server/Services/MetricTypeService.js.map +1 -1
  266. package/build/dist/Server/Services/MonitorService.js +128 -9
  267. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  268. package/build/dist/Server/Services/MonitorStatusTimelineService.js +28 -0
  269. package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
  270. package/build/dist/Server/Services/MonitorTemplateService.js +60 -0
  271. package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
  272. package/build/dist/Server/Services/PodmanHostService.js +19 -32
  273. package/build/dist/Server/Services/PodmanHostService.js.map +1 -1
  274. package/build/dist/Server/Services/PodmanResourceService.js +34 -4
  275. package/build/dist/Server/Services/PodmanResourceService.js.map +1 -1
  276. package/build/dist/Server/Services/ProjectService.js +135 -21
  277. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  278. package/build/dist/Server/Services/ProxmoxClusterService.js +23 -36
  279. package/build/dist/Server/Services/ProxmoxClusterService.js.map +1 -1
  280. package/build/dist/Server/Services/ProxmoxResourceService.js +28 -3
  281. package/build/dist/Server/Services/ProxmoxResourceService.js.map +1 -1
  282. package/build/dist/Server/Services/RumApplicationService.js +19 -32
  283. package/build/dist/Server/Services/RumApplicationService.js.map +1 -1
  284. package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js +20 -0
  285. package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js.map +1 -1
  286. package/build/dist/Server/Services/ServerlessFunctionService.js +24 -37
  287. package/build/dist/Server/Services/ServerlessFunctionService.js.map +1 -1
  288. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js +347 -0
  289. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js.map +1 -0
  290. package/build/dist/Server/Services/ServiceLevelObjectiveService.js +33 -1
  291. package/build/dist/Server/Services/ServiceLevelObjectiveService.js.map +1 -1
  292. package/build/dist/Server/Services/ServiceService.js +236 -61
  293. package/build/dist/Server/Services/ServiceService.js.map +1 -1
  294. package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js +603 -0
  295. package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js.map +1 -0
  296. package/build/dist/Server/Services/StatusPageMonitorRuleService.js +401 -0
  297. package/build/dist/Server/Services/StatusPageMonitorRuleService.js.map +1 -0
  298. package/build/dist/Server/Services/StatusPageService.js +69 -46
  299. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  300. package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js +17 -1
  301. package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js.map +1 -1
  302. package/build/dist/Server/Services/StatusPageSubscriberService.js +3 -0
  303. package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
  304. package/build/dist/Server/Services/TelemetryEntityRelationshipService.js +1 -0
  305. package/build/dist/Server/Services/TelemetryEntityRelationshipService.js.map +1 -1
  306. package/build/dist/Server/Services/TelemetryEntityService.js +1 -0
  307. package/build/dist/Server/Services/TelemetryEntityService.js.map +1 -1
  308. package/build/dist/Server/Types/Database/JSONColumnQuery.js +402 -0
  309. package/build/dist/Server/Types/Database/JSONColumnQuery.js.map +1 -0
  310. package/build/dist/Server/Types/Database/Permissions/PublicPermission.js +9 -2
  311. package/build/dist/Server/Types/Database/Permissions/PublicPermission.js.map +1 -1
  312. package/build/dist/Server/Types/Database/QueryHelper.js +17 -27
  313. package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
  314. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +105 -29
  315. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -1
  316. package/build/dist/Server/Utils/Database/TruncateColumnValue.js +32 -0
  317. package/build/dist/Server/Utils/Database/TruncateColumnValue.js.map +1 -0
  318. package/build/dist/Server/Utils/Monitor/MonitorResource.js +56 -32
  319. package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
  320. package/build/dist/Server/Utils/Monitor/MonitorStatusTimeline.js +30 -3
  321. package/build/dist/Server/Utils/Monitor/MonitorStatusTimeline.js.map +1 -1
  322. package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js +110 -98
  323. package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js.map +1 -1
  324. package/build/dist/Server/Utils/Monitor/MonitorStepsReferenceExtractor.js +312 -0
  325. package/build/dist/Server/Utils/Monitor/MonitorStepsReferenceExtractor.js.map +1 -0
  326. package/build/dist/Server/Utils/SingleFlight.js +76 -0
  327. package/build/dist/Server/Utils/SingleFlight.js.map +1 -0
  328. package/build/dist/Server/Utils/StatusPage/MonitorRulePatternValidator.js +29 -0
  329. package/build/dist/Server/Utils/StatusPage/MonitorRulePatternValidator.js.map +1 -0
  330. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +78 -19
  331. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
  332. package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js +160 -0
  333. package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js.map +1 -0
  334. package/build/dist/Server/Utils/Telemetry/Telemetry.js +279 -104
  335. package/build/dist/Server/Utils/Telemetry/Telemetry.js.map +1 -1
  336. package/build/dist/Types/CustomField/CustomFieldDefinition.js +2 -0
  337. package/build/dist/Types/CustomField/CustomFieldDefinition.js.map +1 -0
  338. package/build/dist/Types/Dashboard/DashboardComponentType.js +1 -0
  339. package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
  340. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js +1 -0
  341. package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js.map +1 -1
  342. package/build/dist/Types/Dashboard/DashboardComponents/DashboardNetworkMapComponent.js +2 -0
  343. package/build/dist/Types/Dashboard/DashboardComponents/DashboardNetworkMapComponent.js.map +1 -0
  344. package/build/dist/Types/Dashboard/DashboardTemplates.js +368 -0
  345. package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
  346. package/build/dist/Types/Database/BigIntColumnTransformer.js +66 -0
  347. package/build/dist/Types/Database/BigIntColumnTransformer.js.map +1 -0
  348. package/build/dist/Types/Database/DatabaseProperty.js +25 -0
  349. package/build/dist/Types/Database/DatabaseProperty.js.map +1 -1
  350. package/build/dist/Types/Database/NumericColumnValue.js +97 -0
  351. package/build/dist/Types/Database/NumericColumnValue.js.map +1 -0
  352. package/build/dist/Types/Date.js +68 -0
  353. package/build/dist/Types/Date.js.map +1 -1
  354. package/build/dist/Types/Decimal.js +14 -3
  355. package/build/dist/Types/Decimal.js.map +1 -1
  356. package/build/dist/Types/Events/Recurring.js +63 -0
  357. package/build/dist/Types/Events/Recurring.js.map +1 -1
  358. package/build/dist/Types/Permission.js +42 -0
  359. package/build/dist/Types/Permission.js.map +1 -1
  360. package/build/dist/Types/Port.js +15 -5
  361. package/build/dist/Types/Port.js.map +1 -1
  362. package/build/dist/Types/StatusPage/StatusPageReportPeriodType.js +22 -0
  363. package/build/dist/Types/StatusPage/StatusPageReportPeriodType.js.map +1 -0
  364. package/build/dist/UI/Components/LogsViewer/useLiveLogsRefresh.js +44 -0
  365. package/build/dist/UI/Components/LogsViewer/useLiveLogsRefresh.js.map +1 -0
  366. package/build/dist/UI/Components/LogsViewer/useLogsHistogram.js +75 -0
  367. package/build/dist/UI/Components/LogsViewer/useLogsHistogram.js.map +1 -0
  368. package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js.map +1 -1
  369. package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js +18 -2
  370. package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js.map +1 -1
  371. package/build/dist/UI/Utils/ModelAPI/ProjectUsersModelAPI.js +213 -0
  372. package/build/dist/UI/Utils/ModelAPI/ProjectUsersModelAPI.js.map +1 -0
  373. package/build/dist/UI/Utils/TeamMembersByUser.js +195 -0
  374. package/build/dist/UI/Utils/TeamMembersByUser.js.map +1 -0
  375. package/build/dist/Utils/Dashboard/Components/DashboardNetworkMapComponent.js +114 -0
  376. package/build/dist/Utils/Dashboard/Components/DashboardNetworkMapComponent.js.map +1 -0
  377. package/build/dist/Utils/Dashboard/Components/Index.js +4 -0
  378. package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
  379. package/build/dist/Utils/StatusPage/ReportPeriod.js +131 -0
  380. package/build/dist/Utils/StatusPage/ReportPeriod.js.map +1 -0
  381. package/build/dist/Utils/Telemetry/HostIpAddresses.js +82 -0
  382. package/build/dist/Utils/Telemetry/HostIpAddresses.js.map +1 -0
  383. package/jest.config.json +2 -0
  384. package/package.json +1 -1
  385. package/tsconfig.json +12 -1
@@ -0,0 +1,362 @@
1
+ import ProjectMiddleware from "../../../Server/Middleware/ProjectAuthorization";
2
+ import { ExpressRequest } from "../../../Server/Utils/Express";
3
+ import ObjectID from "../../../Types/ObjectID";
4
+ import { describe, expect, test } from "@jest/globals";
5
+
6
+ /*
7
+ * The `apikey` request header, from raw string to resolved key.
8
+ *
9
+ * A caller sent a real project API key and got back
10
+ * HTTP 401 "A user should be logged in to read record of Log Pipeline."
11
+ * (issue #3004; issue #1754 was the same string on a different model). The
12
+ * model was innocent and RBAC was fine — the request simply never reached the
13
+ * API-key branch, because `hasApiKey` used to be `Boolean(getApiKey(req))`.
14
+ * Anything the key parser could not turn into an ObjectID — an empty value
15
+ * from an unset shell variable, a stray quote, duplicate headers — looked
16
+ * exactly like a request that had sent no header at all, so the caller fell
17
+ * through to the anonymous path and was told to log in.
18
+ *
19
+ * The fix splits presence from usability:
20
+ * hasApiKey -> was the header sent? (claims the request)
21
+ * getApiKey -> is it a usable key? (null unless it is UUID-shaped)
22
+ * Those two deliberately DISAGREE for every present-but-unusable value, and
23
+ * that disagreement is what turns the misleading 401 into `Invalid API Key`.
24
+ *
25
+ * getApiKey's UUID check also keeps malformed values out of the `apiKey`
26
+ * Postgres `uuid` column, where they raised a raw QueryFailedError — not a
27
+ * OneUptime Exception, so it escaped the error translator and answered 500.
28
+ */
29
+
30
+ type ApiKeyHeaderValue = string | Array<string> | undefined;
31
+
32
+ type RequestWithApiKeyHeaderFunction = (
33
+ apiKeyHeader: ApiKeyHeaderValue,
34
+ ) => ExpressRequest;
35
+
36
+ const requestWithApiKeyHeader: RequestWithApiKeyHeaderFunction = (
37
+ apiKeyHeader: ApiKeyHeaderValue,
38
+ ): ExpressRequest => {
39
+ return {
40
+ headers: { apikey: apiKeyHeader },
41
+ } as unknown as ExpressRequest;
42
+ };
43
+
44
+ const VALID_UUID: string = "550e8400-e29b-41d4-a716-446655440000";
45
+ const SECOND_VALID_UUID: string = "7c9e6679-7425-40de-944b-e07fc1f90ae7";
46
+ const NIL_UUID: string = "00000000-0000-0000-0000-000000000000";
47
+
48
+ /*
49
+ * Every value a caller can put in the header that is NOT a usable key but IS
50
+ * unmistakably an attempt to authenticate by key. Each of these produced the
51
+ * misleading "should be logged in" 401 before the fix.
52
+ *
53
+ * Typed as `string | Array<string>` rather than ApiKeyHeaderValue on purpose:
54
+ * `undefined` means the header was never sent, which is the one shape that
55
+ * belongs in the "absent" block. Letting it into this list would quietly make
56
+ * the presence assertions below contradictory.
57
+ */
58
+ const PRESENT_BUT_UNUSABLE_HEADERS: Array<[string, string | Array<string>]> = [
59
+ // The literal #3004 shape: `-H "ApiKey: $ONEUPTIME_API_KEY"` with the variable unset.
60
+ ["empty string", ""],
61
+ ["spaces only", " "],
62
+ ["a single tab", "\t"],
63
+ ["a newline", "\n"],
64
+ ["mixed whitespace", " \t\n "],
65
+ ["arbitrary garbage", "garbage"],
66
+ ["a hyphenated non-uuid", "not-a-uuid"],
67
+ ["a bare number", "12345"],
68
+ /*
69
+ * The rest of the unset-credential family, all seen in the wild alongside
70
+ * the empty string. A shell that does not expand the variable sends its
71
+ * name; a JS client that does `ApiKey: String(process.env.KEY)` sends the
72
+ * literal "undefined". Each is a caller who meant to send a key, so each
73
+ * must be claimed by the API-key branch rather than treated as anonymous.
74
+ */
75
+ ["an unexpanded shell variable", "$ONEUPTIME_API_KEY"],
76
+ ["the literal string undefined", "undefined"],
77
+ ["the literal string null", "null"],
78
+ // A caller who pasted an Authorization-header value into the apikey header.
79
+ ["a uuid with a Bearer prefix", `Bearer ${VALID_UUID}`],
80
+ ["a uuid missing a segment", "550e8400-e29b-41d4-446655440000"],
81
+ ["a uuid with an extra segment", "550e8400-e29b-41d4-a716-a716-446655440000"],
82
+ [
83
+ "a uuid containing a non-hex character",
84
+ "550e8400-e29b-41d4-a716-44665544000g",
85
+ ],
86
+ ["a uuid with a short segment", "550e840-e29b-41d4-a716-446655440000"],
87
+ ["a uuid with no hyphens", "550e8400e29b41d4a716446655440000"],
88
+ ["a uuid wrapped in braces", "{550e8400-e29b-41d4-a716-446655440000}"],
89
+ ["a uuid with trailing text", `${VALID_UUID}extra`],
90
+ ["a quoted uuid", `"${VALID_UUID}"`],
91
+ ["a bare SQL injection attempt", "' OR 1=1 --"],
92
+ ["a uuid with SQL appended", `${VALID_UUID}'; DROP TABLE "ApiKey"; --`],
93
+ ["a very long value", "a".repeat(8192)],
94
+ ["a very long digit string", "9".repeat(4096)],
95
+ /*
96
+ * Node collapses duplicate `apikey` headers into an array, which the raw
97
+ * reader joins with "," — a shape no uuid column will ever accept. The old
98
+ * getApiKey handed that comma-joined string straight to the query layer,
99
+ * where Postgres answered 22P02 and the caller got a 500.
100
+ */
101
+ ["duplicate headers joined by node", [VALID_UUID, SECOND_VALID_UUID]],
102
+ ["duplicate empty headers", ["", ""]],
103
+ ];
104
+
105
+ /*
106
+ * Values that are UUID-shaped, so getApiKey resolves them. Shape is all that
107
+ * is checked here — whether the key exists or is still live is ApiKeyService's
108
+ * job, and answering `Invalid API Key` for an unknown-but-well-formed key is
109
+ * the same 400 either way.
110
+ */
111
+ const RESOLVABLE_HEADERS: Array<[string, string | Array<string>, string]> = [
112
+ ["a lowercase uuid", VALID_UUID, VALID_UUID],
113
+ [
114
+ "an uppercase uuid (the regex is case-insensitive)",
115
+ VALID_UUID.toUpperCase(),
116
+ VALID_UUID.toUpperCase(),
117
+ ],
118
+ [
119
+ "a mixed-case uuid",
120
+ "550E8400-e29b-41D4-a716-446655440000",
121
+ "550E8400-e29b-41D4-a716-446655440000",
122
+ ],
123
+ ["a uuid padded with spaces", ` ${VALID_UUID} `, VALID_UUID],
124
+ ["a uuid padded with a tab and a newline", `\t${VALID_UUID}\n`, VALID_UUID],
125
+ // Shape, not liveness: the nil uuid is well-formed, so it reaches the lookup.
126
+ ["the nil uuid", NIL_UUID, NIL_UUID],
127
+ // Not a v4 uuid — the regex is version-agnostic on purpose.
128
+ [
129
+ "a v1-shaped uuid",
130
+ "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
131
+ "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
132
+ ],
133
+ /*
134
+ * The other half of the array case, and the one that pins HOW arrays are
135
+ * handled. A one-element array is what Node hands over when a proxy rebuilds
136
+ * a single header; joining it yields the key unchanged, so it must resolve.
137
+ * Rejecting every array outright would pass the two-element test below and
138
+ * fail this one; taking rawHeader[0] instead of joining would pass this one
139
+ * and silently authenticate with the first of two conflicting keys.
140
+ */
141
+ ["a single-element duplicate header array", [VALID_UUID], VALID_UUID],
142
+ ];
143
+
144
+ describe("ProjectMiddleware apikey header handling", () => {
145
+ describe("header genuinely absent", () => {
146
+ /*
147
+ * The only shape that may reach the anonymous path. Answering true here
148
+ * would claim every unauthenticated browser request as an API-key request
149
+ * and break session auth outright.
150
+ */
151
+ test("no headers object at all", () => {
152
+ const req: ExpressRequest = {} as unknown as ExpressRequest;
153
+
154
+ expect(ProjectMiddleware.hasApiKey(req)).toStrictEqual(false);
155
+ expect(ProjectMiddleware.getApiKey(req)).toBeNull();
156
+ });
157
+
158
+ test("empty headers object", () => {
159
+ const req: ExpressRequest = { headers: {} } as unknown as ExpressRequest;
160
+
161
+ expect(ProjectMiddleware.hasApiKey(req)).toStrictEqual(false);
162
+ expect(ProjectMiddleware.getApiKey(req)).toBeNull();
163
+ });
164
+
165
+ test("apikey explicitly undefined", () => {
166
+ const req: ExpressRequest = requestWithApiKeyHeader(undefined);
167
+
168
+ expect(ProjectMiddleware.hasApiKey(req)).toStrictEqual(false);
169
+ expect(ProjectMiddleware.getApiKey(req)).toBeNull();
170
+ });
171
+
172
+ // Other headers present must not be mistaken for an apikey header.
173
+ test("only unrelated headers present", () => {
174
+ const req: ExpressRequest = {
175
+ headers: { tenantid: VALID_UUID, "content-type": "application/json" },
176
+ } as unknown as ExpressRequest;
177
+
178
+ expect(ProjectMiddleware.hasApiKey(req)).toStrictEqual(false);
179
+ expect(ProjectMiddleware.getApiKey(req)).toBeNull();
180
+ });
181
+ });
182
+
183
+ describe("hasApiKey is presence, not usability", () => {
184
+ /*
185
+ * This is the #3004 fix. Each of these used to answer false, which sent
186
+ * the request down the anonymous path and produced a 401 about being
187
+ * logged in. They must all answer true so the request is claimed by the
188
+ * API-key branch and fails as `Invalid API Key` (400) instead.
189
+ */
190
+ test.each(PRESENT_BUT_UNUSABLE_HEADERS)(
191
+ "returns true for %s",
192
+ (_description: string, headerValue: string | Array<string>) => {
193
+ expect(
194
+ ProjectMiddleware.hasApiKey(requestWithApiKeyHeader(headerValue)),
195
+ ).toStrictEqual(true);
196
+ },
197
+ );
198
+
199
+ test.each(RESOLVABLE_HEADERS)(
200
+ "returns true for %s",
201
+ (_description: string, headerValue: string | Array<string>) => {
202
+ expect(
203
+ ProjectMiddleware.hasApiKey(requestWithApiKeyHeader(headerValue)),
204
+ ).toStrictEqual(true);
205
+ },
206
+ );
207
+ });
208
+
209
+ describe("getApiKey rejects anything that is not uuid-shaped", () => {
210
+ /*
211
+ * `ApiKey.apiKey` is a Postgres uuid column. Before the shape check these
212
+ * values were passed straight into the query and raised a raw
213
+ * QueryFailedError (22P02), which is not a OneUptime Exception and so
214
+ * escaped the error translator as an HTTP 500 on a malformed request.
215
+ */
216
+ test.each(PRESENT_BUT_UNUSABLE_HEADERS)(
217
+ "returns null for %s",
218
+ (_description: string, headerValue: string | Array<string>) => {
219
+ expect(
220
+ ProjectMiddleware.getApiKey(requestWithApiKeyHeader(headerValue)),
221
+ ).toBeNull();
222
+ },
223
+ );
224
+ });
225
+
226
+ describe("getApiKey resolves uuid-shaped values", () => {
227
+ test.each(RESOLVABLE_HEADERS)(
228
+ "resolves %s",
229
+ (
230
+ _description: string,
231
+ headerValue: string | Array<string>,
232
+ expectedValue: string,
233
+ ) => {
234
+ const apiKey: ObjectID | null = ProjectMiddleware.getApiKey(
235
+ requestWithApiKeyHeader(headerValue),
236
+ );
237
+
238
+ expect(apiKey).toBeInstanceOf(ObjectID);
239
+ /*
240
+ * The value must survive verbatim apart from trimming — lower-casing
241
+ * or otherwise normalising it here would stop the key matching the row
242
+ * that was actually issued.
243
+ */
244
+ expect(apiKey?.toString()).toStrictEqual(expectedValue);
245
+ },
246
+ );
247
+
248
+ // Padding is stripped, so a copy-pasted key with stray spaces still works.
249
+ test("a padded uuid resolves to the same key as the unpadded one", () => {
250
+ const padded: ObjectID | null = ProjectMiddleware.getApiKey(
251
+ requestWithApiKeyHeader(` ${VALID_UUID} \t`),
252
+ );
253
+ const unpadded: ObjectID | null = ProjectMiddleware.getApiKey(
254
+ requestWithApiKeyHeader(VALID_UUID),
255
+ );
256
+
257
+ expect(padded).not.toBeNull();
258
+ expect(unpadded).not.toBeNull();
259
+ expect(padded!.equals(unpadded!)).toStrictEqual(true);
260
+ });
261
+ });
262
+
263
+ /*
264
+ * The invariant the whole fix rests on.
265
+ *
266
+ * hasApiKey used to be `Boolean(this.getApiKey(req))`, i.e. the two always
267
+ * agreed. Making them agree again — by deriving hasApiKey from getApiKey, or
268
+ * by having getApiKey fall back to a non-null ObjectID for unusable input —
269
+ * reintroduces #3004: getUserMiddleware would stop routing these requests
270
+ * into the API-key branch and they would once again die on the anonymous
271
+ * path with a 401 about logging in.
272
+ */
273
+ test("for present-but-unusable headers hasApiKey and getApiKey deliberately disagree", () => {
274
+ const disagreements: Array<string> = [];
275
+
276
+ for (const [description, headerValue] of PRESENT_BUT_UNUSABLE_HEADERS) {
277
+ const req: ExpressRequest = requestWithApiKeyHeader(headerValue);
278
+
279
+ if (
280
+ ProjectMiddleware.hasApiKey(req) === true &&
281
+ ProjectMiddleware.getApiKey(req) === null
282
+ ) {
283
+ continue;
284
+ }
285
+
286
+ disagreements.push(description);
287
+ }
288
+
289
+ expect(disagreements).toEqual([]);
290
+ // Guard against the list itself being emptied and the assertion going vacuous.
291
+ expect(PRESENT_BUT_UNUSABLE_HEADERS.length).toBeGreaterThan(10);
292
+ });
293
+
294
+ /*
295
+ * The converse: when the header IS usable the two agree, and when it is
296
+ * absent they agree the other way. Only the middle case is asymmetric.
297
+ */
298
+ test("hasApiKey and getApiKey agree for usable and for absent headers", () => {
299
+ for (const [, headerValue] of RESOLVABLE_HEADERS) {
300
+ const req: ExpressRequest = requestWithApiKeyHeader(headerValue);
301
+
302
+ expect(ProjectMiddleware.hasApiKey(req)).toStrictEqual(true);
303
+ expect(ProjectMiddleware.getApiKey(req)).not.toBeNull();
304
+ }
305
+
306
+ const absent: ExpressRequest = requestWithApiKeyHeader(undefined);
307
+
308
+ expect(ProjectMiddleware.hasApiKey(absent)).toStrictEqual(false);
309
+ expect(ProjectMiddleware.getApiKey(absent)).toBeNull();
310
+ });
311
+
312
+ describe("reading the header does not mutate the request", () => {
313
+ // Trimming must be local: express handlers downstream still read req.headers.
314
+ test("the raw header value is left exactly as it arrived", () => {
315
+ const req: ExpressRequest = requestWithApiKeyHeader(` ${VALID_UUID} `);
316
+
317
+ expect(ProjectMiddleware.hasApiKey(req)).toStrictEqual(true);
318
+ expect(ProjectMiddleware.getApiKey(req)?.toString()).toStrictEqual(
319
+ VALID_UUID,
320
+ );
321
+
322
+ // The trim happened on a local copy, not on the header itself.
323
+ expect(req.headers["apikey"]).toStrictEqual(` ${VALID_UUID} `);
324
+ });
325
+
326
+ /*
327
+ * Reading the header is side-effect free, so the answer cannot depend on
328
+ * how many middlewares asked. getUserMiddleware calls hasApiKey and then
329
+ * isValidProjectIdAndApiKeyMiddleware calls both again on the same request.
330
+ */
331
+ test("repeated reads of the same request give the same answer", () => {
332
+ const req: ExpressRequest = requestWithApiKeyHeader(VALID_UUID);
333
+
334
+ expect(ProjectMiddleware.hasApiKey(req)).toStrictEqual(true);
335
+ expect(ProjectMiddleware.getApiKey(req)?.toString()).toStrictEqual(
336
+ VALID_UUID,
337
+ );
338
+ expect(ProjectMiddleware.hasApiKey(req)).toStrictEqual(true);
339
+ expect(ProjectMiddleware.getApiKey(req)?.toString()).toStrictEqual(
340
+ VALID_UUID,
341
+ );
342
+
343
+ const unusable: ExpressRequest = requestWithApiKeyHeader("");
344
+
345
+ expect(ProjectMiddleware.hasApiKey(unusable)).toStrictEqual(true);
346
+ expect(ProjectMiddleware.getApiKey(unusable)).toBeNull();
347
+ expect(ProjectMiddleware.hasApiKey(unusable)).toStrictEqual(true);
348
+ expect(ProjectMiddleware.getApiKey(unusable)).toBeNull();
349
+ });
350
+
351
+ test("duplicate headers are left as an array on the request", () => {
352
+ const req: ExpressRequest = requestWithApiKeyHeader([
353
+ VALID_UUID,
354
+ SECOND_VALID_UUID,
355
+ ]);
356
+
357
+ expect(ProjectMiddleware.hasApiKey(req)).toStrictEqual(true);
358
+ expect(ProjectMiddleware.getApiKey(req)).toBeNull();
359
+ expect(req.headers["apikey"]).toEqual([VALID_UUID, SECOND_VALID_UUID]);
360
+ });
361
+ });
362
+ });