@oneuptime/common 11.7.1 → 11.7.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 (285) hide show
  1. package/Models/AnalyticsModels/KubernetesCostAllocation.ts +103 -0
  2. package/Models/DatabaseModels/DashboardDomain.ts +1 -0
  3. package/Models/DatabaseModels/Incident.ts +2 -0
  4. package/Models/DatabaseModels/IncidentEpisode.ts +1 -0
  5. package/Models/DatabaseModels/IncidentEpisodePublicNote.ts +1 -0
  6. package/Models/DatabaseModels/IncidentEpisodeStateTimeline.ts +1 -0
  7. package/Models/DatabaseModels/IncidentPublicNote.ts +1 -0
  8. package/Models/DatabaseModels/IncidentStateTimeline.ts +1 -0
  9. package/Models/DatabaseModels/Monitor.ts +1 -0
  10. package/Models/DatabaseModels/MonitorStatusTimeline.ts +1 -0
  11. package/Models/DatabaseModels/NetworkSite.ts +1 -0
  12. package/Models/DatabaseModels/NetworkSiteStatusTimeline.ts +1 -0
  13. package/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.ts +1 -0
  14. package/Models/DatabaseModels/OnCallDutyPolicySchedule.ts +2 -0
  15. package/Models/DatabaseModels/Probe.ts +13 -13
  16. package/Models/DatabaseModels/ScheduledMaintenance.ts +1 -0
  17. package/Models/DatabaseModels/ScheduledMaintenancePublicNote.ts +1 -0
  18. package/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.ts +1 -0
  19. package/Models/DatabaseModels/ScheduledMaintenanceTemplate.ts +1 -0
  20. package/Models/DatabaseModels/StatusPage.ts +1 -0
  21. package/Models/DatabaseModels/StatusPageAnnouncement.ts +1 -0
  22. package/Models/DatabaseModels/StatusPageDomain.ts +1 -0
  23. package/Models/DatabaseModels/TableView.ts +40 -0
  24. package/Models/DatabaseModels/WorkspaceNotificationSummary.ts +1 -0
  25. package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +11 -0
  26. package/Server/API/BaseAPI.ts +17 -1
  27. package/Server/API/CommonAPI.ts +32 -0
  28. package/Server/API/MicrosoftTeamsAPI.ts +99 -2
  29. package/Server/API/ProbeAPI.ts +2 -0
  30. package/Server/API/SlackAPI.ts +62 -0
  31. package/Server/API/StatusPageAPI.ts +157 -192
  32. package/Server/Infrastructure/Postgres/SchemaMigrations/1785140242697-AddHotQueryIndexes.ts +89 -0
  33. package/Server/Infrastructure/Postgres/SchemaMigrations/1785148065137-AddHotQueryIndexesSecondPass.ts +61 -0
  34. package/Server/Infrastructure/Postgres/SchemaMigrations/1785240000000-RepairCrossProjectMonitorStatusReferences.ts +280 -0
  35. package/Server/Infrastructure/Postgres/SchemaMigrations/1785241000000-AddColumnsToTableView.ts +13 -0
  36. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
  37. package/Server/Services/DatabaseService.ts +11 -3
  38. package/Server/Services/MonitorGroupService.ts +145 -0
  39. package/Server/Services/MonitorService.ts +231 -30
  40. package/Server/Services/ProbeService.ts +319 -16
  41. package/Server/Services/StatusPageService.ts +72 -42
  42. package/Server/Services/WorkspaceNotificationRuleService.ts +232 -2
  43. package/Server/Utils/Database/PostgresErrorTranslator.ts +131 -0
  44. package/Server/Utils/Monitor/MonitorResource.ts +88 -35
  45. package/Server/Utils/Monitor/MonitorStatusTimeline.ts +21 -1
  46. package/Server/Utils/Monitor/MonitorStepsProjectValidator.ts +158 -0
  47. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +706 -6
  48. package/Tests/Models/AnalyticsModels/KubernetesCostAllocation.test.ts +16 -0
  49. package/Tests/Models/DatabaseModels/ProbeColumnAccessControl.test.ts +103 -0
  50. package/Tests/Server/API/BaseAPIUpdateNoOp.test.ts +135 -0
  51. package/Tests/Server/API/CommonAPIAuthGuard.test.ts +317 -0
  52. package/Tests/Server/API/MicrosoftTeamsManifest.test.ts +228 -0
  53. package/Tests/Server/API/ProbeAPI.test.ts +6 -0
  54. package/Tests/Server/API/ZZVerifyChatsAuth.test.ts +167 -0
  55. package/Tests/Server/Services/AddHotQueryIndexesMigration.test.ts +255 -0
  56. package/Tests/Server/Services/AddHotQueryIndexesSecondPassMigration.test.ts +258 -0
  57. package/Tests/Server/Services/DatabaseServiceSanitizeUpdateData.test.ts +1 -1
  58. package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +121 -0
  59. package/Tests/Server/Services/HeartbeatWriteFastPathSafety.test.ts +200 -0
  60. package/Tests/Server/Services/HookFreeWriteSafetySecondPass.test.ts +181 -0
  61. package/Tests/Server/Services/MonitorGroupServiceBatchedStatuses.test.ts +513 -0
  62. package/Tests/Server/Services/MonitorResourceProbeAgreementReuse.test.ts +492 -0
  63. package/Tests/Server/Services/MonitorServiceProbeSelection.test.ts +401 -0
  64. package/Tests/Server/Services/MonitorStatusTimelineFastPath.test.ts +453 -0
  65. package/Tests/Server/Services/ProbeAuthKeyCacheAndHeartbeat.test.ts +679 -0
  66. package/Tests/Server/Services/ServiceLevelObjectiveService.test.ts +3 -3
  67. package/Tests/Server/Services/StatusPageDomainResolutionCache.test.ts +245 -0
  68. package/Tests/Server/Services/StatusPageOverviewTimelineWindow.test.ts +283 -0
  69. package/Tests/Server/Services/StatusPageServiceMcp.test.ts +17 -1
  70. package/Tests/Server/Services/StatusPageServiceMonitorGroupBatching.test.ts +331 -0
  71. package/Tests/Server/Services/UserOnCallLogClaimNotificationRule.test.ts +12 -12
  72. package/Tests/Server/Services/WorkspaceNotificationRuleChats.test.ts +1390 -0
  73. package/Tests/Server/Utils/AI/Insights/InsightFixRouting.test.ts +4 -4
  74. package/Tests/Server/Utils/AI/Insights/InsightScanner.test.ts +2 -2
  75. package/Tests/Server/Utils/AI/Insights/InsightStore.test.ts +1 -3
  76. package/Tests/Server/Utils/AI/Insights/InsightStoreHardening.test.ts +1 -3
  77. package/Tests/Server/Utils/AI/Insights/InsightTriage.test.ts +1 -1
  78. package/Tests/Server/Utils/AI/Insights/InsightTriageRunner.test.ts +5 -5
  79. package/Tests/Server/Utils/Alert/AlertPrivacyFilter.test.ts +187 -0
  80. package/Tests/Server/Utils/AlertEpisode/AlertEpisodePrivacyFilter.test.ts +170 -0
  81. package/Tests/Server/Utils/Database/PostgresErrorTranslator.test.ts +125 -0
  82. package/Tests/Server/Utils/Incident/IncidentPrivacyFilter.test.ts +264 -0
  83. package/Tests/Server/Utils/IncidentEpisode/IncidentEpisodePrivacyFilter.test.ts +175 -0
  84. package/Tests/Server/Utils/Monitor/MonitorStepsProjectValidator.test.ts +181 -0
  85. package/Tests/Server/Utils/Monitor/NetworkDeviceWalkUtil.test.ts +1 -1
  86. package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +2 -2
  87. package/Tests/Server/Utils/Workspace/MicrosoftTeamsChannelsList.test.ts +341 -0
  88. package/Tests/Server/Utils/Workspace/MicrosoftTeamsChats.test.ts +2175 -0
  89. package/Tests/Server/Utils/Workspace/SlackChannelsList.test.ts +585 -0
  90. package/Tests/Types/Billing/MeteredPlan.test.ts +46 -0
  91. package/Tests/Types/JSONFunctions.test.ts +103 -1
  92. package/Tests/Types/Workspace/NotificationRules/NotificationRuleCondition.test.ts +219 -1
  93. package/Tests/UI/Components/BulkUpdateForm.test.tsx +174 -0
  94. package/Tests/UI/Components/CardModelDetailEdit.test.tsx +315 -0
  95. package/Tests/UI/Components/ModelDetailSelect.test.tsx +229 -0
  96. package/Tests/UI/Components/ModelTable/BaseModelTableBulkSelectAll.test.tsx +1258 -0
  97. package/Tests/UI/Components/ModelTable/BaseModelTableColumnCustomization.test.tsx +679 -0
  98. package/Tests/UI/Components/ModelTable/ColumnCustomizationModal.test.tsx +572 -0
  99. package/Tests/UI/Components/ModelTable/ColumnPreference.test.ts +1678 -0
  100. package/Tests/UI/Components/ModelTable/CustomFieldColumns.test.tsx +1094 -0
  101. package/Tests/UI/Components/ModelTableExportFromColumns.test.ts +153 -0
  102. package/Tests/UI/Components/MonacoLoader.test.ts +67 -0
  103. package/Tests/UI/Components/MonacoRuntime.test.ts +121 -0
  104. package/Tests/UI/Components/TableBulkCsvExport.test.tsx +212 -3
  105. package/Tests/UI/Utils/Project.test.ts +809 -0
  106. package/Tests/UI/Utils/TableColumnsToCsv.test.ts +360 -0
  107. package/Tests/Utils/Alerts/AlertMetricType.test.ts +143 -0
  108. package/Tests/Utils/Dashboard/VariableUrlState.test.ts +219 -0
  109. package/Tests/Utils/Incident/IncidentMetricType.test.ts +174 -0
  110. package/Tests/Utils/Monitor/MonitorProbeSelectionUtil.test.ts +145 -0
  111. package/Tests/Utils/StatusPage/ResourceUptime.test.ts +263 -0
  112. package/Tests/Utils/UserPreferences.test.ts +563 -0
  113. package/Types/JSONFunctions.ts +7 -2
  114. package/Types/Kubernetes/KubernetesCostIngest.ts +37 -1
  115. package/Types/Workspace/NotificationRules/BaseNotificationRule.ts +4 -0
  116. package/Types/Workspace/NotificationRules/NotificationRuleCondition.ts +25 -10
  117. package/Types/Workspace/WorkspaceMessagePayload.ts +1 -0
  118. package/UI/Components/BulkUpdate/BulkUpdateForm.tsx +63 -8
  119. package/UI/Components/CodeEditor/CodeEditor.tsx +3 -0
  120. package/UI/Components/CodeEditor/MonacoLoader.ts +36 -0
  121. package/UI/Components/Forms/ModelForm.tsx +41 -18
  122. package/UI/Components/MasterPage/MasterPage.tsx +65 -0
  123. package/UI/Components/ModelDetail/CardModelDetail.tsx +23 -1
  124. package/UI/Components/ModelDetail/ModelDetail.tsx +46 -1
  125. package/UI/Components/ModelTable/BaseModelTable.tsx +687 -34
  126. package/UI/Components/ModelTable/Column.ts +29 -0
  127. package/UI/Components/ModelTable/ColumnCustomizationModal.tsx +420 -0
  128. package/UI/Components/ModelTable/ColumnPreference.ts +482 -0
  129. package/UI/Components/ModelTable/CustomFieldColumns.tsx +326 -0
  130. package/UI/Components/ModelTable/ExportFromColumns.ts +57 -0
  131. package/UI/Components/ModelTable/TableView.tsx +24 -2
  132. package/UI/Components/ModelTable/useCustomFieldColumns.ts +150 -0
  133. package/UI/Components/Navbar/NavBar.tsx +66 -1
  134. package/UI/Components/SideMenu/SideMenu.tsx +24 -4
  135. package/UI/Components/Table/Table.tsx +66 -14
  136. package/UI/Components/Table/TableRow.tsx +180 -175
  137. package/UI/Components/Table/Types/Column.ts +20 -0
  138. package/UI/Utils/Project.ts +214 -18
  139. package/UI/Utils/TableColumnsToCsv.ts +86 -6
  140. package/UI/esbuild-config.js +34 -0
  141. package/Utils/Monitor/MonitorProbeSelectionUtil.ts +72 -0
  142. package/Utils/UserPreferences.ts +53 -0
  143. package/build/dist/Models/AnalyticsModels/KubernetesCostAllocation.js +86 -0
  144. package/build/dist/Models/AnalyticsModels/KubernetesCostAllocation.js.map +1 -1
  145. package/build/dist/Models/DatabaseModels/DashboardDomain.js +1 -0
  146. package/build/dist/Models/DatabaseModels/DashboardDomain.js.map +1 -1
  147. package/build/dist/Models/DatabaseModels/Incident.js +2 -0
  148. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  149. package/build/dist/Models/DatabaseModels/IncidentEpisode.js +1 -0
  150. package/build/dist/Models/DatabaseModels/IncidentEpisode.js.map +1 -1
  151. package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js +1 -0
  152. package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js.map +1 -1
  153. package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js +1 -0
  154. package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js.map +1 -1
  155. package/build/dist/Models/DatabaseModels/IncidentPublicNote.js +1 -0
  156. package/build/dist/Models/DatabaseModels/IncidentPublicNote.js.map +1 -1
  157. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js +1 -0
  158. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js.map +1 -1
  159. package/build/dist/Models/DatabaseModels/Monitor.js +1 -0
  160. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  161. package/build/dist/Models/DatabaseModels/MonitorStatusTimeline.js +1 -0
  162. package/build/dist/Models/DatabaseModels/MonitorStatusTimeline.js.map +1 -1
  163. package/build/dist/Models/DatabaseModels/NetworkSite.js +1 -0
  164. package/build/dist/Models/DatabaseModels/NetworkSite.js.map +1 -1
  165. package/build/dist/Models/DatabaseModels/NetworkSiteStatusTimeline.js +1 -0
  166. package/build/dist/Models/DatabaseModels/NetworkSiteStatusTimeline.js.map +1 -1
  167. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.js +1 -0
  168. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyExecutionLog.js.map +1 -1
  169. package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js +2 -0
  170. package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js.map +1 -1
  171. package/build/dist/Models/DatabaseModels/Probe.js +13 -13
  172. package/build/dist/Models/DatabaseModels/Probe.js.map +1 -1
  173. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js +1 -0
  174. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
  175. package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js +1 -0
  176. package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js.map +1 -1
  177. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js +1 -0
  178. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js.map +1 -1
  179. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplate.js +1 -0
  180. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplate.js.map +1 -1
  181. package/build/dist/Models/DatabaseModels/StatusPage.js +1 -0
  182. package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
  183. package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js +1 -0
  184. package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js.map +1 -1
  185. package/build/dist/Models/DatabaseModels/StatusPageDomain.js +1 -0
  186. package/build/dist/Models/DatabaseModels/StatusPageDomain.js.map +1 -1
  187. package/build/dist/Models/DatabaseModels/TableView.js +40 -0
  188. package/build/dist/Models/DatabaseModels/TableView.js.map +1 -1
  189. package/build/dist/Models/DatabaseModels/WorkspaceNotificationSummary.js +1 -0
  190. package/build/dist/Models/DatabaseModels/WorkspaceNotificationSummary.js.map +1 -1
  191. package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
  192. package/build/dist/Server/API/BaseAPI.js +12 -1
  193. package/build/dist/Server/API/BaseAPI.js.map +1 -1
  194. package/build/dist/Server/API/CommonAPI.js +21 -0
  195. package/build/dist/Server/API/CommonAPI.js.map +1 -1
  196. package/build/dist/Server/API/MicrosoftTeamsAPI.js +72 -2
  197. package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -1
  198. package/build/dist/Server/API/ProbeAPI.js +2 -0
  199. package/build/dist/Server/API/ProbeAPI.js.map +1 -1
  200. package/build/dist/Server/API/SlackAPI.js +44 -0
  201. package/build/dist/Server/API/SlackAPI.js.map +1 -1
  202. package/build/dist/Server/API/StatusPageAPI.js +98 -152
  203. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  204. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785140242697-AddHotQueryIndexes.js +36 -0
  205. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785140242697-AddHotQueryIndexes.js.map +1 -0
  206. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785148065137-AddHotQueryIndexesSecondPass.js +26 -0
  207. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785148065137-AddHotQueryIndexesSecondPass.js.map +1 -0
  208. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785240000000-RepairCrossProjectMonitorStatusReferences.js +254 -0
  209. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785240000000-RepairCrossProjectMonitorStatusReferences.js.map +1 -0
  210. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785241000000-AddColumnsToTableView.js +12 -0
  211. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785241000000-AddColumnsToTableView.js.map +1 -0
  212. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
  213. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  214. package/build/dist/Server/Services/DatabaseService.js +10 -2
  215. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  216. package/build/dist/Server/Services/MonitorGroupService.js +118 -0
  217. package/build/dist/Server/Services/MonitorGroupService.js.map +1 -1
  218. package/build/dist/Server/Services/MonitorService.js +198 -24
  219. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  220. package/build/dist/Server/Services/ProbeService.js +238 -9
  221. package/build/dist/Server/Services/ProbeService.js.map +1 -1
  222. package/build/dist/Server/Services/StatusPageService.js +46 -39
  223. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  224. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +178 -3
  225. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
  226. package/build/dist/Server/Utils/Database/PostgresErrorTranslator.js +80 -0
  227. package/build/dist/Server/Utils/Database/PostgresErrorTranslator.js.map +1 -0
  228. package/build/dist/Server/Utils/Monitor/MonitorResource.js +67 -29
  229. package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
  230. package/build/dist/Server/Utils/Monitor/MonitorStatusTimeline.js +31 -14
  231. package/build/dist/Server/Utils/Monitor/MonitorStatusTimeline.js.map +1 -1
  232. package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js +117 -0
  233. package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js.map +1 -0
  234. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +549 -7
  235. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  236. package/build/dist/Types/JSONFunctions.js +8 -3
  237. package/build/dist/Types/JSONFunctions.js.map +1 -1
  238. package/build/dist/Types/Kubernetes/KubernetesCostIngest.js.map +1 -1
  239. package/build/dist/Types/Workspace/NotificationRules/NotificationRuleCondition.js +17 -7
  240. package/build/dist/Types/Workspace/NotificationRules/NotificationRuleCondition.js.map +1 -1
  241. package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js +37 -11
  242. package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js.map +1 -1
  243. package/build/dist/UI/Components/CodeEditor/CodeEditor.js +2 -0
  244. package/build/dist/UI/Components/CodeEditor/CodeEditor.js.map +1 -1
  245. package/build/dist/UI/Components/CodeEditor/MonacoLoader.js +34 -0
  246. package/build/dist/UI/Components/CodeEditor/MonacoLoader.js.map +1 -0
  247. package/build/dist/UI/Components/Forms/ModelForm.js +37 -17
  248. package/build/dist/UI/Components/Forms/ModelForm.js.map +1 -1
  249. package/build/dist/UI/Components/MasterPage/MasterPage.js +50 -1
  250. package/build/dist/UI/Components/MasterPage/MasterPage.js.map +1 -1
  251. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js +22 -1
  252. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js.map +1 -1
  253. package/build/dist/UI/Components/ModelDetail/ModelDetail.js +31 -1
  254. package/build/dist/UI/Components/ModelDetail/ModelDetail.js.map +1 -1
  255. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +472 -27
  256. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  257. package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js +189 -0
  258. package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js.map +1 -0
  259. package/build/dist/UI/Components/ModelTable/ColumnPreference.js +258 -0
  260. package/build/dist/UI/Components/ModelTable/ColumnPreference.js.map +1 -0
  261. package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js +168 -0
  262. package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js.map +1 -0
  263. package/build/dist/UI/Components/ModelTable/ExportFromColumns.js +30 -0
  264. package/build/dist/UI/Components/ModelTable/ExportFromColumns.js.map +1 -0
  265. package/build/dist/UI/Components/ModelTable/TableView.js +13 -2
  266. package/build/dist/UI/Components/ModelTable/TableView.js.map +1 -1
  267. package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js +84 -0
  268. package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js.map +1 -0
  269. package/build/dist/UI/Components/Navbar/NavBar.js +39 -1
  270. package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
  271. package/build/dist/UI/Components/SideMenu/SideMenu.js +15 -5
  272. package/build/dist/UI/Components/SideMenu/SideMenu.js.map +1 -1
  273. package/build/dist/UI/Components/Table/Table.js +46 -13
  274. package/build/dist/UI/Components/Table/Table.js.map +1 -1
  275. package/build/dist/UI/Components/Table/TableRow.js +11 -6
  276. package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
  277. package/build/dist/UI/Utils/Project.js +161 -15
  278. package/build/dist/UI/Utils/Project.js.map +1 -1
  279. package/build/dist/UI/Utils/TableColumnsToCsv.js +67 -6
  280. package/build/dist/UI/Utils/TableColumnsToCsv.js.map +1 -1
  281. package/build/dist/Utils/Monitor/MonitorProbeSelectionUtil.js +52 -0
  282. package/build/dist/Utils/Monitor/MonitorProbeSelectionUtil.js.map +1 -0
  283. package/build/dist/Utils/UserPreferences.js +33 -0
  284. package/build/dist/Utils/UserPreferences.js.map +1 -1
  285. package/package.json +4 -3
@@ -348,6 +348,12 @@ export default class KubernetesCostAllocation extends AnalyticsBaseModel {
348
348
  title: "CPU Core Usage Average",
349
349
  description: "Average CPU cores actually used over the window.",
350
350
  },
351
+ {
352
+ key: "cpuCoreLimitAverage",
353
+ title: "CPU Core Limit Average",
354
+ description:
355
+ "Average CPU core limit over the window. 0 when no limit is set — which is also what a row ingested before this column reads back.",
356
+ },
351
357
  {
352
358
  key: "cpuCost",
353
359
  title: "CPU Cost",
@@ -378,6 +384,18 @@ export default class KubernetesCostAllocation extends AnalyticsBaseModel {
378
384
  title: "RAM Bytes Usage Average",
379
385
  description: "Average RAM bytes actually used over the window.",
380
386
  },
387
+ {
388
+ key: "ramBytesLimitAverage",
389
+ title: "RAM Bytes Limit Average",
390
+ description:
391
+ "Average RAM byte limit over the window. 0 when no limit is set — which is also what a row ingested before this column reads back.",
392
+ },
393
+ {
394
+ key: "ramBytesUsageMax",
395
+ title: "RAM Bytes Usage Max",
396
+ description:
397
+ "Peak RAM bytes used during the window, from Prometheus rather than the cost engine — the engine only reports averages, and an hourly mean hides the burst that OOMKills a container. 0 when the agent has no Prometheus configured, when the scrape had no data, or on rows ingested before this column; treat 0 as 'unknown', never as a real peak.",
398
+ },
381
399
  {
382
400
  key: "ramCost",
383
401
  title: "RAM Cost",
@@ -472,6 +490,49 @@ export default class KubernetesCostAllocation extends AnalyticsBaseModel {
472
490
  },
473
491
  });
474
492
 
493
+ /*
494
+ * Delivery bookkeeping, not workload data. A window wider than the
495
+ * agent's batch size arrives as several independent ingest jobs, so the
496
+ * ingest service needs to tell "another chunk of the delivery I am
497
+ * already ingesting" (accept) from "a window a previous delivery already
498
+ * ingested" (drop, or a restarted agent double-counts spend). shipmentId
499
+ * is the agent's content hash of the window — identical across restarts,
500
+ * different when the engine's answer for that window changed.
501
+ *
502
+ * Empty / 0 on rows written before these columns existed and on rows
503
+ * from agents older than the shipment contract; the ingest service falls
504
+ * back to the whole-window guard for those.
505
+ */
506
+ const shipmentIdColumn: AnalyticsTableColumn = new AnalyticsTableColumn({
507
+ key: "shipmentId",
508
+ title: "Shipment ID",
509
+ description:
510
+ "Content hash identifying the agent delivery this row arrived in. Used to deduplicate re-shipped windows; empty for rows ingested before the shipment contract.",
511
+ required: true,
512
+ defaultValue: "",
513
+ type: TableColumnType.Text,
514
+ accessControl: {
515
+ read: readPermissions,
516
+ create: createPermissions,
517
+ update: [],
518
+ },
519
+ });
520
+
521
+ const shipmentChunkColumn: AnalyticsTableColumn = new AnalyticsTableColumn({
522
+ key: "shipmentChunk",
523
+ title: "Shipment Chunk",
524
+ description:
525
+ "Index of the request within its shipment that carried this row. 0 for single-request shipments and for rows ingested before the shipment contract.",
526
+ required: true,
527
+ defaultValue: 0,
528
+ type: TableColumnType.Number,
529
+ accessControl: {
530
+ read: readPermissions,
531
+ create: createPermissions,
532
+ update: [],
533
+ },
534
+ });
535
+
475
536
  const retentionDateColumn: AnalyticsTableColumn = new AnalyticsTableColumn({
476
537
  key: "retentionDate",
477
538
  codec: [{ codec: "DoubleDelta" }, { codec: "ZSTD", level: 1 }],
@@ -517,6 +578,8 @@ export default class KubernetesCostAllocation extends AnalyticsBaseModel {
517
578
  labelKeysColumn,
518
579
  ...measureColumns,
519
580
  currencyColumn,
581
+ shipmentIdColumn,
582
+ shipmentChunkColumn,
520
583
  retentionDateColumn,
521
584
  ],
522
585
  sortKeys: [
@@ -688,6 +751,14 @@ export default class KubernetesCostAllocation extends AnalyticsBaseModel {
688
751
  this.setColumnValue("cpuCoreUsageAverage", v);
689
752
  }
690
753
 
754
+ public get cpuCoreLimitAverage(): number | undefined {
755
+ return this.getColumnValue("cpuCoreLimitAverage") as number | undefined;
756
+ }
757
+
758
+ public set cpuCoreLimitAverage(v: number | undefined) {
759
+ this.setColumnValue("cpuCoreLimitAverage", v);
760
+ }
761
+
691
762
  public get cpuCost(): number | undefined {
692
763
  return this.getColumnValue("cpuCost") as number | undefined;
693
764
  }
@@ -736,6 +807,22 @@ export default class KubernetesCostAllocation extends AnalyticsBaseModel {
736
807
  this.setColumnValue("ramBytesUsageAverage", v);
737
808
  }
738
809
 
810
+ public get ramBytesLimitAverage(): number | undefined {
811
+ return this.getColumnValue("ramBytesLimitAverage") as number | undefined;
812
+ }
813
+
814
+ public set ramBytesLimitAverage(v: number | undefined) {
815
+ this.setColumnValue("ramBytesLimitAverage", v);
816
+ }
817
+
818
+ public get ramBytesUsageMax(): number | undefined {
819
+ return this.getColumnValue("ramBytesUsageMax") as number | undefined;
820
+ }
821
+
822
+ public set ramBytesUsageMax(v: number | undefined) {
823
+ this.setColumnValue("ramBytesUsageMax", v);
824
+ }
825
+
739
826
  public get ramCost(): number | undefined {
740
827
  return this.getColumnValue("ramCost") as number | undefined;
741
828
  }
@@ -832,6 +919,22 @@ export default class KubernetesCostAllocation extends AnalyticsBaseModel {
832
919
  this.setColumnValue("currency", v);
833
920
  }
834
921
 
922
+ public get shipmentId(): string | undefined {
923
+ return this.getColumnValue("shipmentId") as string | undefined;
924
+ }
925
+
926
+ public set shipmentId(v: string | undefined) {
927
+ this.setColumnValue("shipmentId", v);
928
+ }
929
+
930
+ public get shipmentChunk(): number | undefined {
931
+ return this.getColumnValue("shipmentChunk") as number | undefined;
932
+ }
933
+
934
+ public set shipmentChunk(v: number | undefined) {
935
+ this.setColumnValue("shipmentChunk", v);
936
+ }
937
+
835
938
  public get retentionDate(): Date | undefined {
836
939
  return this.getColumnValue("retentionDate") as Date | undefined;
837
940
  }
@@ -379,6 +379,7 @@ export default class DashboardDomain extends BaseModel {
379
379
  "Full domain of your dashboard (like dashboard.acmeinc.com). This is autogenerated and is derived from subdomain and domain.",
380
380
  example: "dashboard.acmeinc.com",
381
381
  })
382
+ @Index()
382
383
  @Column({
383
384
  nullable: false,
384
385
  type: ColumnType.ShortText,
@@ -1678,6 +1678,7 @@ export default class Incident extends BaseModel {
1678
1678
  "Status of notification sent to subscribers about this incident",
1679
1679
  defaultValue: StatusPageSubscriberNotificationStatus.Pending,
1680
1680
  })
1681
+ @Index()
1681
1682
  @Column({
1682
1683
  type: ColumnType.ShortText,
1683
1684
  default: StatusPageSubscriberNotificationStatus.Pending,
@@ -1764,6 +1765,7 @@ export default class Incident extends BaseModel {
1764
1765
  "Status of notification sent to subscribers about this incident postmortem",
1765
1766
  defaultValue: StatusPageSubscriberNotificationStatus.Pending,
1766
1767
  })
1768
+ @Index()
1767
1769
  @Column({
1768
1770
  type: ColumnType.ShortText,
1769
1771
  default: StatusPageSubscriberNotificationStatus.Pending,
@@ -1657,6 +1657,7 @@ export default class IncidentEpisode extends BaseModel {
1657
1657
  "Status of notification sent to subscribers when this episode was created",
1658
1658
  defaultValue: StatusPageSubscriberNotificationStatus.Pending,
1659
1659
  })
1660
+ @Index()
1660
1661
  @Column({
1661
1662
  type: ColumnType.ShortText,
1662
1663
  default: StatusPageSubscriberNotificationStatus.Pending,
@@ -504,6 +504,7 @@ export default class IncidentEpisodePublicNote extends BaseModel {
504
504
  description: "Status of notification sent to subscribers about this note",
505
505
  defaultValue: StatusPageSubscriberNotificationStatus.Pending,
506
506
  })
507
+ @Index()
507
508
  @Column({
508
509
  type: ColumnType.ShortText,
509
510
  default: StatusPageSubscriberNotificationStatus.Pending,
@@ -671,6 +671,7 @@ export default class IncidentEpisodeStateTimeline extends BaseModel {
671
671
  "Status of notification sent to subscribers about this state change",
672
672
  defaultValue: StatusPageSubscriberNotificationStatus.Pending,
673
673
  })
674
+ @Index()
674
675
  @Column({
675
676
  type: ColumnType.ShortText,
676
677
  default: StatusPageSubscriberNotificationStatus.Pending,
@@ -507,6 +507,7 @@ export default class IncidentPublicNote extends BaseModel {
507
507
  description: "Status of notification sent to subscribers about this note",
508
508
  defaultValue: StatusPageSubscriberNotificationStatus.Pending,
509
509
  })
510
+ @Index()
510
511
  @Column({
511
512
  type: ColumnType.ShortText,
512
513
  default: StatusPageSubscriberNotificationStatus.Pending,
@@ -506,6 +506,7 @@ export default class IncidentStateTimeline extends BaseModel {
506
506
  defaultValue: StatusPageSubscriberNotificationStatus.Pending,
507
507
  example: "Sent",
508
508
  })
509
+ @Index()
509
510
  @Column({
510
511
  type: ColumnType.ShortText,
511
512
  default: StatusPageSubscriberNotificationStatus.Pending,
@@ -595,6 +595,7 @@ export default class Monitor extends BaseModel {
595
595
  example: "API",
596
596
  canReadOnRelationQuery: true,
597
597
  })
598
+ @Index()
598
599
  @Column({
599
600
  nullable: false,
600
601
  type: ColumnType.ShortText,
@@ -418,6 +418,7 @@ export default class MonitorStatusTimeline extends BaseModel {
418
418
  {
419
419
  eager: false,
420
420
  nullable: true,
421
+ onDelete: "CASCADE",
421
422
  orphanedRowAction: "nullify",
422
423
  },
423
424
  )
@@ -839,6 +839,7 @@ export default class NetworkSite extends BaseModel {
839
839
  title: "Last Rollup At",
840
840
  description: "When the health rollup for this site was last computed",
841
841
  })
842
+ @Index()
842
843
  @Column({
843
844
  nullable: true,
844
845
  type: ColumnType.Date,
@@ -276,6 +276,7 @@ export default class NetworkSiteStatusTimeline extends BaseModel {
276
276
  {
277
277
  eager: false,
278
278
  nullable: true,
279
+ onDelete: "CASCADE",
279
280
  orphanedRowAction: "nullify",
280
281
  },
281
282
  )
@@ -593,6 +593,7 @@ export default class OnCallDutyPolicyExecutionLog extends BaseModel {
593
593
  canReadOnRelationQuery: false,
594
594
  example: "Executing",
595
595
  })
596
+ @Index()
596
597
  @Column({
597
598
  nullable: false,
598
599
  type: ColumnType.ShortText,
@@ -690,6 +690,7 @@ export default class OnCallDutyPolicySchedule extends BaseModel {
690
690
  "When does the roster handoff occur for this schedule for the current user?",
691
691
  example: "2024-01-15T18:00:00.000Z",
692
692
  })
693
+ @Index()
693
694
  @Column({
694
695
  type: ColumnType.Date,
695
696
  nullable: true,
@@ -744,6 +745,7 @@ export default class OnCallDutyPolicySchedule extends BaseModel {
744
745
  "When does the next event start for this schedule for the next user?",
745
746
  example: "2024-01-22T09:00:00.000Z",
746
747
  })
748
+ @Index()
747
749
  @Column({
748
750
  type: ColumnType.Date,
749
751
  nullable: true,
@@ -285,7 +285,7 @@ export default class Probe extends BaseModel {
285
285
  Permission.ProjectMember,
286
286
  Permission.SettingsAdmin,
287
287
  Permission.SettingsMember,
288
- Permission.CreateProjectStatusPage,
288
+ Permission.CreateProjectProbe,
289
289
  ],
290
290
  read: [
291
291
  Permission.ProjectOwner,
@@ -295,7 +295,7 @@ export default class Probe extends BaseModel {
295
295
  Permission.SettingsAdmin,
296
296
  Permission.SettingsMember,
297
297
  Permission.SettingsViewer,
298
- Permission.ReadProjectStatusPage,
298
+ Permission.ReadProjectProbe,
299
299
  ],
300
300
  update: [
301
301
  Permission.ProjectOwner,
@@ -303,7 +303,7 @@ export default class Probe extends BaseModel {
303
303
  Permission.ProjectMember,
304
304
  Permission.SettingsAdmin,
305
305
  Permission.SettingsMember,
306
- Permission.EditProjectStatusPage,
306
+ Permission.EditProjectProbe,
307
307
  ],
308
308
  })
309
309
  @TableColumn({
@@ -334,7 +334,7 @@ export default class Probe extends BaseModel {
334
334
  Permission.ProjectMember,
335
335
  Permission.SettingsAdmin,
336
336
  Permission.SettingsMember,
337
- Permission.CreateProjectStatusPage,
337
+ Permission.CreateProjectProbe,
338
338
  ],
339
339
  read: [
340
340
  Permission.ProjectOwner,
@@ -344,7 +344,7 @@ export default class Probe extends BaseModel {
344
344
  Permission.SettingsAdmin,
345
345
  Permission.SettingsMember,
346
346
  Permission.SettingsViewer,
347
- Permission.ReadProjectStatusPage,
347
+ Permission.ReadProjectProbe,
348
348
  ],
349
349
  update: [
350
350
  Permission.ProjectOwner,
@@ -352,7 +352,7 @@ export default class Probe extends BaseModel {
352
352
  Permission.ProjectMember,
353
353
  Permission.SettingsAdmin,
354
354
  Permission.SettingsMember,
355
- Permission.EditProjectStatusPage,
355
+ Permission.EditProjectProbe,
356
356
  ],
357
357
  })
358
358
  @TableColumn({
@@ -546,7 +546,7 @@ export default class Probe extends BaseModel {
546
546
  Permission.ProjectMember,
547
547
  Permission.SettingsAdmin,
548
548
  Permission.SettingsMember,
549
- Permission.CreateProjectStatusPage,
549
+ Permission.CreateProjectProbe,
550
550
  ],
551
551
  read: [
552
552
  Permission.ProjectOwner,
@@ -556,7 +556,7 @@ export default class Probe extends BaseModel {
556
556
  Permission.SettingsAdmin,
557
557
  Permission.SettingsMember,
558
558
  Permission.SettingsViewer,
559
- Permission.ReadProjectStatusPage,
559
+ Permission.ReadProjectProbe,
560
560
  ],
561
561
  update: [
562
562
  Permission.ProjectOwner,
@@ -564,7 +564,7 @@ export default class Probe extends BaseModel {
564
564
  Permission.ProjectMember,
565
565
  Permission.SettingsAdmin,
566
566
  Permission.SettingsMember,
567
- Permission.EditProjectStatusPage,
567
+ Permission.EditProjectProbe,
568
568
  ],
569
569
  })
570
570
  @TableColumn({
@@ -592,7 +592,7 @@ export default class Probe extends BaseModel {
592
592
  Permission.SettingsAdmin,
593
593
  Permission.SettingsMember,
594
594
  Permission.SettingsViewer,
595
- Permission.ReadProjectStatusPage,
595
+ Permission.ReadProjectProbe,
596
596
  ],
597
597
  update: [],
598
598
  })
@@ -618,7 +618,7 @@ export default class Probe extends BaseModel {
618
618
  Permission.ProjectMember,
619
619
  Permission.SettingsAdmin,
620
620
  Permission.SettingsMember,
621
- Permission.CreateProjectStatusPage,
621
+ Permission.CreateProjectProbe,
622
622
  ],
623
623
  read: [
624
624
  Permission.ProjectOwner,
@@ -628,7 +628,7 @@ export default class Probe extends BaseModel {
628
628
  Permission.SettingsAdmin,
629
629
  Permission.SettingsMember,
630
630
  Permission.SettingsViewer,
631
- Permission.ReadProjectStatusPage,
631
+ Permission.ReadProjectProbe,
632
632
  ],
633
633
  update: [
634
634
  Permission.ProjectOwner,
@@ -636,7 +636,7 @@ export default class Probe extends BaseModel {
636
636
  Permission.ProjectMember,
637
637
  Permission.SettingsAdmin,
638
638
  Permission.SettingsMember,
639
- Permission.EditProjectStatusPage,
639
+ Permission.EditProjectProbe,
640
640
  ],
641
641
  })
642
642
  @TableColumn({
@@ -1389,6 +1389,7 @@ export default class ScheduledMaintenance extends BaseModel {
1389
1389
  "Status of notification sent to subscribers when event was scheduled",
1390
1390
  defaultValue: StatusPageSubscriberNotificationStatus.Pending,
1391
1391
  })
1392
+ @Index()
1392
1393
  @Column({
1393
1394
  type: ColumnType.ShortText,
1394
1395
  default: StatusPageSubscriberNotificationStatus.Pending,
@@ -507,6 +507,7 @@ export default class ScheduledMaintenancePublicNote extends BaseModel {
507
507
  defaultValue: StatusPageSubscriberNotificationStatus.Pending,
508
508
  example: "Sent",
509
509
  })
510
+ @Index()
510
511
  @Column({
511
512
  type: ColumnType.ShortText,
512
513
  default: StatusPageSubscriberNotificationStatus.Pending,
@@ -503,6 +503,7 @@ export default class ScheduledMaintenanceStateTimeline extends BaseModel {
503
503
  defaultValue: StatusPageSubscriberNotificationStatus.Pending,
504
504
  example: "Sent",
505
505
  })
506
+ @Index()
506
507
  @Column({
507
508
  type: ColumnType.ShortText,
508
509
  default: StatusPageSubscriberNotificationStatus.Pending,
@@ -1285,6 +1285,7 @@ export default class ScheduledMaintenanceTemplate extends BaseModel {
1285
1285
  description: "When is the next event scheduled?",
1286
1286
  example: "2024-03-29T02:00:00.000Z",
1287
1287
  })
1288
+ @Index()
1288
1289
  @Column({
1289
1290
  type: ColumnType.Date,
1290
1291
  nullable: true,
@@ -2575,6 +2575,7 @@ export default class StatusPage extends BaseModel {
2575
2575
  title: "Send Next Report By",
2576
2576
  description: "When should the next report be sent?",
2577
2577
  })
2578
+ @Index()
2578
2579
  @Column({
2579
2580
  type: ColumnType.Date,
2580
2581
  nullable: true,
@@ -676,6 +676,7 @@ export default class StatusPageAnnouncement extends BaseModel {
676
676
  type: TableColumnType.ShortText,
677
677
  defaultValue: StatusPageSubscriberNotificationStatus.Pending,
678
678
  })
679
+ @Index()
679
680
  @Column({
680
681
  type: ColumnType.ShortText,
681
682
  default: StatusPageSubscriberNotificationStatus.Pending,
@@ -380,6 +380,7 @@ export default class StatusPageDomain extends BaseModel {
380
380
  "Full domain of your status page (like status.acmeinc.com). This is autogenerated and is derived from subdomain and domain.",
381
381
  example: "status.acmeinc.com",
382
382
  })
383
+ @Index()
383
384
  @Column({
384
385
  nullable: false,
385
386
  type: ColumnType.ShortText,
@@ -555,4 +555,44 @@ export default class TableView extends BaseModel {
555
555
  nullable: true,
556
556
  })
557
557
  public facets?: JSONObject = undefined;
558
+
559
+ @ColumnAccessControl({
560
+ create: [
561
+ Permission.ProjectOwner,
562
+ Permission.ProjectAdmin,
563
+ Permission.CreateTableView,
564
+ ],
565
+ read: [
566
+ Permission.ProjectOwner,
567
+ Permission.ProjectAdmin,
568
+ Permission.ProjectMember,
569
+ Permission.Viewer,
570
+ Permission.SettingsAdmin,
571
+ Permission.SettingsMember,
572
+ Permission.SettingsViewer,
573
+ Permission.ReadTableView,
574
+ ],
575
+ update: [
576
+ Permission.ProjectOwner,
577
+ Permission.ProjectAdmin,
578
+ Permission.EditTableView,
579
+ ],
580
+ })
581
+ @TableColumn({
582
+ title: "Columns",
583
+ required: false,
584
+ unique: false,
585
+ type: TableColumnType.JSON,
586
+ canReadOnRelationQuery: true,
587
+ description:
588
+ "Which columns are shown, and in what order, for this table view",
589
+ example:
590
+ '{"order": ["name", "currentMonitorStatus"], "hidden": ["labels"]}',
591
+ })
592
+ @Column({
593
+ type: ColumnType.JSON,
594
+ unique: false,
595
+ nullable: true,
596
+ })
597
+ public columns?: JSONObject = undefined;
558
598
  }
@@ -698,6 +698,7 @@ class WorkspaceNotificationSummary extends BaseModel {
698
698
  title: "Next Send At",
699
699
  description: "When the next summary should be sent",
700
700
  })
701
+ @Index()
701
702
  @Column({
702
703
  type: ColumnType.Date,
703
704
  nullable: true,
@@ -26,6 +26,16 @@ export interface MicrosoftTeamsTeam {
26
26
  name: string;
27
27
  }
28
28
 
29
+ export type MicrosoftTeamsChatType = "personal" | "groupChat";
30
+
31
+ export interface MicrosoftTeamsChat {
32
+ id: string; // Teams conversation id (e.g. 19:...@thread.v2)
33
+ name: string;
34
+ chatType: MicrosoftTeamsChatType;
35
+ serviceUrl?: string | undefined; // Bot Framework service URL captured when the bot was added.
36
+ addedAt?: string | undefined;
37
+ }
38
+
29
39
  export interface SlackMiscData extends MiscData {
30
40
  teamId: string;
31
41
  teamName: string;
@@ -51,6 +61,7 @@ export interface MicrosoftTeamsMiscData extends MiscData {
51
61
  adminConsentGrantedBy?: string;
52
62
  availableTeams?: Record<string, MicrosoftTeamsTeam>;
53
63
  appAccessTokenExpiresAt?: string;
64
+ availableChats?: Record<string, MicrosoftTeamsChat>; // keyed by chat id. Chats the OneUptime app has been added to.
54
65
  }
55
66
 
56
67
  export type WorkspaceMiscData = SlackMiscData | MicrosoftTeamsMiscData;
@@ -23,6 +23,7 @@ import {
23
23
  } from "../../Types/Database/LimitMax";
24
24
  import PartialEntity from "../../Types/Database/PartialEntity";
25
25
  import BadRequestException from "../../Types/Exception/BadRequestException";
26
+ import NotAuthorizedException from "../../Types/Exception/NotAuthorizedException";
26
27
  import { JSONObject } from "../../Types/JSON";
27
28
  import JSONFunctions from "../../Types/JSONFunctions";
28
29
  import ObjectID from "../../Types/ObjectID";
@@ -406,12 +407,27 @@ export default class BaseAPI<
406
407
  delete (item as any)["createdAt"];
407
408
  delete (item as any)["updatedAt"];
408
409
 
409
- await this.service.updateOneById({
410
+ const numberOfDocsAffected: number = await this.service.updateOneById({
410
411
  id: new ObjectID(objectIdString),
411
412
  data: item,
412
413
  props: await CommonAPI.getDatabaseCommonInteractionProps(req),
413
414
  });
414
415
 
416
+ /*
417
+ * The permission layer narrows the update query after we build it (tenant
418
+ * scope, access-control labels, owned scope), so it is possible to match
419
+ * no rows at all. Reporting 200 for that told the client the edit was
420
+ * saved when nothing was written - the change then "disappeared" on the
421
+ * next page load with no error anywhere.
422
+ */
423
+ if (numberOfDocsAffected === 0) {
424
+ throw new NotAuthorizedException(
425
+ `Unable to update this ${(
426
+ new this.entityType().singularName || "item"
427
+ ).toLowerCase()}. It either does not exist, has been deleted, or you do not have permission to update it.`,
428
+ );
429
+ }
430
+
415
431
  return Response.sendEmptySuccessResponse(req, res);
416
432
  }
417
433
 
@@ -6,8 +6,40 @@ import { PlanType } from "../../Types/Billing/SubscriptionPlan";
6
6
  import UserType from "../../Types/UserType";
7
7
  import CaptureSpan from "../Utils/Telemetry/CaptureSpan";
8
8
  import SpanUtil from "../Utils/Telemetry/SpanUtil";
9
+ import ObjectID from "../../Types/ObjectID";
10
+ import BadDataException from "../../Types/Exception/BadDataException";
11
+ import NotAuthorizedException from "../../Types/Exception/NotAuthorizedException";
9
12
 
10
13
  export default class CommonAPI {
14
+ /*
15
+ * getUserMiddleware lets unauthenticated requests through as "public" and
16
+ * takes the tenant id from a caller-supplied header — custom endpoints
17
+ * that disclose project data must require an authenticated member of the
18
+ * project themselves. Returns the project id when authorized, throws
19
+ * otherwise.
20
+ */
21
+ public static assertAuthenticatedProjectMember(
22
+ databaseProps: DatabaseCommonInteractionProps,
23
+ ): ObjectID {
24
+ const projectId: ObjectID | undefined = databaseProps.tenantId;
25
+
26
+ if (!projectId) {
27
+ throw new BadDataException("Project ID is required");
28
+ }
29
+
30
+ if (
31
+ !databaseProps.userId ||
32
+ !databaseProps.userTenantAccessPermission ||
33
+ !databaseProps.userTenantAccessPermission[projectId.toString()]
34
+ ) {
35
+ throw new NotAuthorizedException(
36
+ "You are not authorized to access this project's data.",
37
+ );
38
+ }
39
+
40
+ return projectId;
41
+ }
42
+
11
43
  @CaptureSpan()
12
44
  public static async getDatabaseCommonInteractionProps(
13
45
  req: ExpressRequest,