@oneuptime/common 12.0.6 → 12.0.7

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 (424) hide show
  1. package/Models/DatabaseModels/AIInsight.ts +1 -1
  2. package/Models/DatabaseModels/DatabaseBaseModel/FileModel.ts +2 -3
  3. package/Models/DatabaseModels/DeletedProject.ts +595 -0
  4. package/Models/DatabaseModels/Index.ts +2 -0
  5. package/Models/DatabaseModels/Monitor.ts +111 -0
  6. package/Models/DatabaseModels/Project.ts +3 -3
  7. package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +19 -1
  8. package/Server/API/FileAPI.ts +15 -2
  9. package/Server/API/MicrosoftTeamsAPI.ts +6 -1
  10. package/Server/API/ProjectAPI.ts +214 -0
  11. package/Server/API/StatusPageAPI.ts +39 -6
  12. package/Server/Infrastructure/Postgres/SchemaMigrations/1786446545142-MigrationName.ts +50 -0
  13. package/Server/Infrastructure/Postgres/SchemaMigrations/1786449497966-AddMonitorDependency.ts +67 -0
  14. package/Server/Infrastructure/Postgres/SchemaMigrations/1786461136170-AddDeletedProjectTable.ts +39 -0
  15. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
  16. package/Server/Services/AIAgentService.ts +20 -0
  17. package/Server/Services/DashboardDomainService.ts +73 -28
  18. package/Server/Services/DatabaseService.ts +1 -0
  19. package/Server/Services/DeletedProjectService.ts +138 -0
  20. package/Server/Services/FileService.ts +61 -0
  21. package/Server/Services/IncidentEpisodePublicNoteService.ts +18 -0
  22. package/Server/Services/IncidentPublicNoteService.ts +18 -0
  23. package/Server/Services/Index.ts +2 -0
  24. package/Server/Services/MonitorService.ts +311 -0
  25. package/Server/Services/ProbeService.ts +20 -0
  26. package/Server/Services/ProjectService.ts +297 -1
  27. package/Server/Services/PushNotificationService.ts +71 -0
  28. package/Server/Services/ScheduledMaintenancePublicNoteService.ts +18 -0
  29. package/Server/Services/StatusPageAnnouncementService.ts +53 -0
  30. package/Server/Services/StatusPageDomainService.ts +73 -28
  31. package/Server/Services/TeamMemberService.ts +117 -12
  32. package/Server/Services/TelemetryIngestionKeyService.ts +1 -0
  33. package/Server/Services/UserWebhookService.ts +34 -109
  34. package/Server/Services/WorkspaceNotificationRuleService.ts +69 -0
  35. package/Server/Services/WorkspaceProjectAuthTokenService.ts +37 -1
  36. package/Server/Types/Database/DeleteById.ts +2 -0
  37. package/Server/Types/Database/DeleteOneBy.ts +6 -0
  38. package/Server/Types/Domain.ts +41 -0
  39. package/Server/Types/Workflow/Components/API/Delete.ts +2 -1
  40. package/Server/Types/Workflow/Components/API/Get.ts +2 -1
  41. package/Server/Types/Workflow/Components/API/Patch.ts +2 -1
  42. package/Server/Types/Workflow/Components/API/Post.ts +2 -1
  43. package/Server/Types/Workflow/Components/API/Put.ts +2 -1
  44. package/Server/Types/Workflow/Components/API/Utils.ts +41 -2
  45. package/Server/Types/Workflow/Components/BaseModel/CreateManyBaseModel.ts +25 -19
  46. package/Server/Types/Workflow/Components/BaseModel/CreateOneBaseModel.ts +6 -5
  47. package/Server/Types/Workflow/Components/BaseModel/DeleteManyBaseModel.ts +32 -14
  48. package/Server/Types/Workflow/Components/BaseModel/DeleteOneBaseModel.ts +31 -13
  49. package/Server/Types/Workflow/Components/BaseModel/FindManyBaseModel.ts +29 -20
  50. package/Server/Types/Workflow/Components/BaseModel/FindOneBaseModel.ts +28 -21
  51. package/Server/Types/Workflow/Components/BaseModel/LogComponentError.ts +89 -0
  52. package/Server/Types/Workflow/Components/BaseModel/ModelArguments.ts +208 -0
  53. package/Server/Types/Workflow/Components/BaseModel/OnTriggerBaseModel.ts +11 -0
  54. package/Server/Types/Workflow/Components/BaseModel/UpdateManyBaseModel.ts +41 -18
  55. package/Server/Types/Workflow/Components/BaseModel/UpdateOneBaseModel.ts +45 -19
  56. package/Server/Types/Workflow/Components/Discord/SendMessageToChannel.ts +16 -9
  57. package/Server/Types/Workflow/Components/IncomingWebhookUtils.ts +66 -0
  58. package/Server/Types/Workflow/Components/MicrosoftTeams/SendMessageToChannel.ts +15 -9
  59. package/Server/Types/Workflow/Components/Slack/SendMessageToChannel.ts +17 -0
  60. package/Server/Utils/AI/Chat/ObservabilityChatPrompt.ts +1 -1
  61. package/Server/Utils/AI/CodeFix/CodeAgentWorkspaceGuard.ts +171 -0
  62. package/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.ts +3 -3
  63. package/Server/Utils/AI/SRE/Insights/FixRouting.ts +3 -2
  64. package/Server/Utils/AI/SRE/TelemetryImprovementTaskTrigger.ts +1 -1
  65. package/Server/Utils/AI/Toolbox/CodeWriteTools.ts +6 -6
  66. package/Server/Utils/CodeRepository/GitHub/GitHub.ts +43 -5
  67. package/Server/Utils/DataSource/EgressGuard.ts +176 -16
  68. package/Server/Utils/DataSource/HttpFetch.ts +6 -45
  69. package/Server/Utils/Execute.ts +8 -0
  70. package/Server/Utils/InlineImageAccessTokenSync.ts +23 -0
  71. package/Server/Utils/LLM/LLMService.ts +57 -12
  72. package/Server/Utils/Monitor/MonitorAlert.ts +40 -0
  73. package/Server/Utils/Monitor/MonitorDependencySuppression.ts +192 -0
  74. package/Server/Utils/Monitor/MonitorIncident.ts +40 -0
  75. package/Server/Utils/Monitor/MonitorResource.ts +36 -0
  76. package/Server/Utils/Response.ts +142 -6
  77. package/Server/Utils/SSRFProtection.ts +273 -60
  78. package/Server/Utils/StartServer.ts +8 -0
  79. package/Server/Utils/VM/VMRunner.ts +88 -1
  80. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +555 -49
  81. package/Server/Utils/Workspace/Slack/Slack.ts +25 -2
  82. package/Server/Utils/Workspace/WorkspaceBase.ts +6 -0
  83. package/Tests/App/Dashboard/DangerZone.test.tsx +334 -0
  84. package/Tests/App/Dashboard/DashboardVariableAllContract.test.tsx +539 -0
  85. package/Tests/App/Dashboard/DashboardVariableSelector.test.tsx +678 -0
  86. package/Tests/App/Dashboard/DashboardVariablesDiscard.test.tsx +706 -0
  87. package/Tests/App/Dashboard/DashboardVariablesModal.test.tsx +508 -0
  88. package/Tests/App/PublicDashboard/DashboardVariableSelector.test.tsx +470 -0
  89. package/Tests/App/StatusPage/StatusPageDetailPagesNotFound.test.tsx +308 -0
  90. package/Tests/Models/DatabaseModels/DeletedProjectModel.test.ts +251 -0
  91. package/Tests/Models/DatabaseModels/SavedViewJSONColumnTuples.test.ts +115 -0
  92. package/Tests/Server/API/FileAPIAccessControl.test.ts +316 -0
  93. package/Tests/Server/API/ProjectAPI.test.ts +299 -1
  94. package/Tests/Server/API/ProjectAPIAdjustBalance.test.ts +459 -0
  95. package/Tests/Server/API/ProjectAPIAdjustBalanceBillingDisabled.test.ts +177 -0
  96. package/Tests/Server/Services/DatabaseServiceDeletionReason.test.ts +123 -0
  97. package/Tests/Server/Services/DeletedProjectService.test.ts +415 -0
  98. package/Tests/Server/Services/DeletedProjectServiceSelfHosted.test.ts +70 -0
  99. package/Tests/Server/Services/DomainSubdomainHooks.test.ts +94 -0
  100. package/Tests/Server/Services/FileIsPublicBooleanMigration.test.ts +244 -0
  101. package/Tests/Server/Services/FileServiceMimeType.test.ts +89 -0
  102. package/Tests/Server/Services/MonitorServiceDependencyValidation.test.ts +702 -0
  103. package/Tests/Server/Services/ProjectServiceAdjustBalance.test.ts +615 -0
  104. package/Tests/Server/Services/ProjectServiceDeleteAudit.test.ts +406 -0
  105. package/Tests/Server/Services/PublishTimeImageVisibility.test.ts +450 -0
  106. package/Tests/Server/Services/TeamMemberAutoAcceptInvitation.test.ts +669 -0
  107. package/Tests/Server/Services/UserWebhookSSRF.test.ts +174 -0
  108. package/Tests/Server/Services/WebPushEndpointAllowlist.test.ts +133 -0
  109. package/Tests/Server/Services/WorkspaceProjectAuthTokenRepoint.test.ts +618 -0
  110. package/Tests/Server/Types/Workflow/Components/ApiComponentErrorPort.test.ts +26 -1
  111. package/Tests/Server/Types/Workflow/Components/ApiComponentSsrf.test.ts +215 -0
  112. package/Tests/Server/Types/Workflow/Components/BaseModelDatabaseComponents.test.ts +742 -0
  113. package/Tests/Server/Types/Workflow/Components/ChatWebhookComponents.test.ts +256 -0
  114. package/Tests/Server/Types/Workflow/Components/ModelArguments.test.ts +371 -0
  115. package/Tests/Server/Utils/AI/CodeAgentCommandGuard.test.ts +204 -0
  116. package/Tests/Server/Utils/AI/CodeAgentWriteLimits.test.ts +213 -0
  117. package/Tests/Server/Utils/AI/CodeWriteTools.test.ts +52 -5
  118. package/Tests/Server/Utils/AI/LLMServiceBaseUrl.test.ts +3 -0
  119. package/Tests/Server/Utils/AI/LLMServiceEgressGuard.test.ts +315 -0
  120. package/Tests/Server/Utils/AI/LLMServiceModelCompatibility.test.ts +3 -0
  121. package/Tests/Server/Utils/AI/LLMServiceRequestPolicy.test.ts +17 -5
  122. package/Tests/Server/Utils/AI/LLMServiceToolCalling.test.ts +14 -1
  123. package/Tests/Server/Utils/AI/ObservabilityChatPrompt.test.ts +35 -0
  124. package/Tests/Server/Utils/AI/StubLLMEgressGuard.ts +25 -0
  125. package/Tests/Server/Utils/Dashboard/PublicDashboardResourceListPolicy.test.ts +62 -7
  126. package/Tests/Server/Utils/DataSource/EgressGuard.test.ts +69 -0
  127. package/Tests/Server/Utils/DataSource/EgressGuardPinning.test.ts +330 -0
  128. package/Tests/Server/Utils/GitHubCreatePullRequestWithToken.test.ts +393 -0
  129. package/Tests/Server/Utils/InlineImageAccessTokenSync.test.ts +202 -0
  130. package/Tests/Server/Utils/Monitor/MonitorDependencySuppression.test.ts +811 -0
  131. package/Tests/Server/Utils/Monitor/MonitorDependencySuppressionCreatorSkip.test.ts +604 -0
  132. package/Tests/Server/Utils/ResponseSendFileResponse.test.ts +192 -0
  133. package/Tests/Server/Utils/SSRFProtectionBypasses.test.ts +406 -0
  134. package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +194 -0
  135. package/Tests/Server/Utils/Workspace/MicrosoftTeamsChannelSend.test.ts +1169 -0
  136. package/Tests/Server/Utils/Workspace/MicrosoftTeamsChannelsList.test.ts +2 -0
  137. package/Tests/Server/Utils/Workspace/MicrosoftTeamsTeamInstalls.test.ts +1605 -0
  138. package/Tests/Server/Utils/Workspace/MicrosoftTeamsTenantResolution.test.ts +1218 -0
  139. package/Tests/Types/AI/AIChatMessageStatus.test.ts +79 -0
  140. package/Tests/Types/AI/AIInsightStatus.test.ts +40 -0
  141. package/Tests/Types/API/HostnameAuthorityParsing.test.ts +157 -0
  142. package/Tests/Types/Dashboard/DashboardTemplateInvariants.test.ts +27 -0
  143. package/Tests/Types/DataSource/DataSourceLimits.test.ts +71 -0
  144. package/Tests/Types/DataSource/DataSourceType.test.ts +181 -0
  145. package/Tests/Types/DomainSubdomainValidation.test.ts +90 -0
  146. package/Tests/Types/JSONFunctions.test.ts +252 -1
  147. package/Tests/Types/Monitor/SnmpMonitor/SnmpAuthProtocol.test.ts +61 -0
  148. package/Tests/Types/Monitor/SnmpMonitor/SnmpPrivProtocol.test.ts +62 -0
  149. package/Tests/Types/Monitor/SnmpMonitor/SnmpSecurityLevel.test.ts +68 -0
  150. package/Tests/Types/Monitor/SnmpMonitor/SnmpVersion.test.ts +51 -0
  151. package/Tests/UI/Components/404.test.tsx +1 -1
  152. package/Tests/UI/Components/Alert.test.tsx +1 -1
  153. package/Tests/UI/Components/Badge.test.tsx +1 -1
  154. package/Tests/UI/Components/BasicForm.test.tsx +39 -10
  155. package/Tests/UI/Components/Button.test.tsx +1 -1
  156. package/Tests/UI/Components/Card.test.tsx +1 -1
  157. package/Tests/UI/Components/Charts/AxisTickColor.test.tsx +1 -1
  158. package/Tests/UI/Components/ColorViewer.test.tsx +1 -1
  159. package/Tests/UI/Components/ComponentsModal.test.tsx +7 -1
  160. package/Tests/UI/Components/DictionaryOfStrings.test.tsx +1 -1
  161. package/Tests/UI/Components/Dropdown.test.tsx +1 -1
  162. package/Tests/UI/Components/FilePicker.test.tsx +1 -1
  163. package/Tests/UI/Components/HiddenText.test.tsx +1 -1
  164. package/Tests/UI/Components/Input.test.tsx +1 -1
  165. package/Tests/UI/Components/Loader.test.tsx +1 -1
  166. package/Tests/UI/Components/LogTimeRangePicker.test.tsx +1 -1
  167. package/Tests/UI/Components/MasterPage.test.tsx +1 -1
  168. package/Tests/UI/Components/ModalPortalDismissal.test.tsx +489 -0
  169. package/Tests/UI/Components/ModelDelete.test.tsx +214 -0
  170. package/Tests/UI/Components/ModelTable/BaseModelTableBulkSelectAll.test.tsx +1 -1
  171. package/Tests/UI/Components/ModelTable/BaseModelTableColumnCustomization.test.tsx +1 -1
  172. package/Tests/UI/Components/ModelTable/BaseModelTableSearchLabels.test.tsx +1 -1
  173. package/Tests/UI/Components/ModelTable/BaseModelTableUrlState.test.tsx +1 -1
  174. package/Tests/UI/Components/ModelTable/CustomFieldColumns.test.tsx +1 -1
  175. package/Tests/UI/Components/NavBar.test.tsx +1 -1
  176. package/Tests/UI/Components/OperatorSelectorKeyboard.test.tsx +1 -1
  177. package/Tests/UI/Components/Pagination.test.tsx +1 -1
  178. package/Tests/UI/Components/Pill.test.tsx +1 -1
  179. package/Tests/UI/Components/Probe.test.tsx +1 -1
  180. package/Tests/UI/Components/ProgressBar.test.tsx +1 -1
  181. package/Tests/UI/Components/RadioButtons.test.tsx +1 -1
  182. package/Tests/UI/Components/SideMenuItem.test.tsx +1 -1
  183. package/Tests/UI/Components/SideOver.test.tsx +500 -6
  184. package/Tests/UI/Components/Tabs.test.tsx +1 -1
  185. package/Tests/UI/Components/TelemetrySearchBar.test.tsx +1 -1
  186. package/Tests/UI/Components/TelemetryTimeRangePicker.test.tsx +1 -1
  187. package/Tests/UI/Components/TextArea.test.tsx +1 -1
  188. package/Tests/UI/Components/Toast.test.tsx +1 -1
  189. package/Tests/UI/Components/Toggle.test.tsx +1 -1
  190. package/Tests/UI/Components/TopSection.test.tsx +1 -1
  191. package/Tests/UI/Components/UseLiveLogsRefresh.test.tsx +1 -1
  192. package/Tests/UI/Rum/ReplayScrubber.test.tsx +1 -1
  193. package/Tests/UI/Rum/ReplayStage.test.tsx +1 -1
  194. package/Tests/UI/Telemetry/TelemetrySnapshotWindowAlert.test.tsx +1 -1
  195. package/Tests/UI/Utils/LocalStorageArrayRoundTrip.test.ts +72 -0
  196. package/Tests/Utils/Dashboard/HtmlWidgetDocument.test.ts +19 -2
  197. package/Tests/Utils/Dashboard/ModelQueryVariableInterpolation.test.ts +44 -0
  198. package/Tests/Utils/Dashboard/VariableInterpolation.test.ts +288 -5
  199. package/Tests/Utils/Dashboard/VariableUrlState.test.ts +42 -0
  200. package/Tests/Utils/DataSource/DataSourceQueryText.test.ts +27 -0
  201. package/Tests/Utils/LegacySerializedArray.test.ts +139 -0
  202. package/Tests/Utils/Monitor/MonitorDependencyRule.test.ts +190 -0
  203. package/Tests/Utils/Realtime.test.ts +78 -0
  204. package/Tests/Utils/Telemetry/SavedViewFilters.test.ts +246 -0
  205. package/Tests/__mocks__/i18next-browser-languagedetector.js +21 -0
  206. package/Types/AI/FixPullRequestCiStatus.ts +1 -1
  207. package/Types/AI/FixVerificationStatus.ts +2 -2
  208. package/Types/API/Hostname.ts +92 -4
  209. package/Types/API/URL.ts +43 -25
  210. package/Types/Billing/BalanceAdjustmentType.ts +14 -0
  211. package/Types/Billing/ProjectBalanceType.ts +13 -0
  212. package/Types/Domain.ts +26 -0
  213. package/Types/File/MimeType.ts +11 -0
  214. package/Types/JSONFunctions.ts +15 -0
  215. package/Types/Telemetry/TelemetrySavedViewState.ts +9 -1
  216. package/Types/Workflow/Components/BaseModel.ts +92 -28
  217. package/Typings/Index.d.ts +12 -0
  218. package/UI/Components/GanttChart/ChartContainer.tsx +4 -3
  219. package/UI/Components/Modal/ConfirmModal.tsx +10 -5
  220. package/UI/Components/Modal/Modal.tsx +27 -47
  221. package/UI/Components/ModelDelete/ModelDelete.tsx +23 -6
  222. package/UI/Components/SideOver/SideOver.tsx +195 -68
  223. package/UI/Utils/PageScrollLock.ts +66 -0
  224. package/Utils/Dashboard/HtmlWidgetDocument.ts +4 -2
  225. package/Utils/Dashboard/VariableInterpolation.ts +19 -1
  226. package/Utils/LegacySerializedArray.ts +60 -0
  227. package/Utils/Monitor/MonitorDependencyRule.ts +88 -0
  228. package/Utils/Telemetry/SavedViewFilters.ts +88 -0
  229. package/build/dist/Models/DatabaseModels/AIInsight.js +1 -1
  230. package/build/dist/Models/DatabaseModels/AIInsight.js.map +1 -1
  231. package/build/dist/Models/DatabaseModels/DatabaseBaseModel/FileModel.js +2 -3
  232. package/build/dist/Models/DatabaseModels/DatabaseBaseModel/FileModel.js.map +1 -1
  233. package/build/dist/Models/DatabaseModels/DeletedProject.js +640 -0
  234. package/build/dist/Models/DatabaseModels/DeletedProject.js.map +1 -0
  235. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  236. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  237. package/build/dist/Models/DatabaseModels/Monitor.js +106 -0
  238. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  239. package/build/dist/Models/DatabaseModels/Project.js +3 -3
  240. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  241. package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
  242. package/build/dist/Server/API/FileAPI.js +14 -2
  243. package/build/dist/Server/API/FileAPI.js.map +1 -1
  244. package/build/dist/Server/API/MicrosoftTeamsAPI.js +6 -1
  245. package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -1
  246. package/build/dist/Server/API/ProjectAPI.js +157 -4
  247. package/build/dist/Server/API/ProjectAPI.js.map +1 -1
  248. package/build/dist/Server/API/StatusPageAPI.js +27 -3
  249. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  250. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786446545142-MigrationName.js +34 -0
  251. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786446545142-MigrationName.js.map +1 -0
  252. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786449497966-AddMonitorDependency.js +30 -0
  253. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786449497966-AddMonitorDependency.js.map +1 -0
  254. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786461136170-AddDeletedProjectTable.js +20 -0
  255. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786461136170-AddDeletedProjectTable.js.map +1 -0
  256. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
  257. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  258. package/build/dist/Server/Services/AIAgentService.js +17 -0
  259. package/build/dist/Server/Services/AIAgentService.js.map +1 -1
  260. package/build/dist/Server/Services/DashboardDomainService.js +55 -18
  261. package/build/dist/Server/Services/DashboardDomainService.js.map +1 -1
  262. package/build/dist/Server/Services/DatabaseService.js +1 -0
  263. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  264. package/build/dist/Server/Services/DeletedProjectService.js +124 -0
  265. package/build/dist/Server/Services/DeletedProjectService.js.map +1 -0
  266. package/build/dist/Server/Services/FileService.js +52 -0
  267. package/build/dist/Server/Services/FileService.js.map +1 -1
  268. package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js +10 -1
  269. package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js.map +1 -1
  270. package/build/dist/Server/Services/IncidentPublicNoteService.js +10 -1
  271. package/build/dist/Server/Services/IncidentPublicNoteService.js.map +1 -1
  272. package/build/dist/Server/Services/Index.js +2 -0
  273. package/build/dist/Server/Services/Index.js.map +1 -1
  274. package/build/dist/Server/Services/MonitorService.js +232 -0
  275. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  276. package/build/dist/Server/Services/ProbeService.js +17 -0
  277. package/build/dist/Server/Services/ProbeService.js.map +1 -1
  278. package/build/dist/Server/Services/ProjectService.js +228 -6
  279. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  280. package/build/dist/Server/Services/PushNotificationService.js +56 -0
  281. package/build/dist/Server/Services/PushNotificationService.js.map +1 -1
  282. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js +10 -1
  283. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js.map +1 -1
  284. package/build/dist/Server/Services/StatusPageAnnouncementService.js +54 -0
  285. package/build/dist/Server/Services/StatusPageAnnouncementService.js.map +1 -1
  286. package/build/dist/Server/Services/StatusPageDomainService.js +55 -18
  287. package/build/dist/Server/Services/StatusPageDomainService.js.map +1 -1
  288. package/build/dist/Server/Services/TeamMemberService.js +97 -6
  289. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  290. package/build/dist/Server/Services/TelemetryIngestionKeyService.js +1 -0
  291. package/build/dist/Server/Services/TelemetryIngestionKeyService.js.map +1 -1
  292. package/build/dist/Server/Services/UserWebhookService.js +31 -87
  293. package/build/dist/Server/Services/UserWebhookService.js.map +1 -1
  294. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +65 -0
  295. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
  296. package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js +23 -0
  297. package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js.map +1 -1
  298. package/build/dist/Server/Types/Domain.js +37 -0
  299. package/build/dist/Server/Types/Domain.js.map +1 -1
  300. package/build/dist/Server/Types/Workflow/Components/API/Delete.js +2 -1
  301. package/build/dist/Server/Types/Workflow/Components/API/Delete.js.map +1 -1
  302. package/build/dist/Server/Types/Workflow/Components/API/Get.js +2 -1
  303. package/build/dist/Server/Types/Workflow/Components/API/Get.js.map +1 -1
  304. package/build/dist/Server/Types/Workflow/Components/API/Patch.js +2 -1
  305. package/build/dist/Server/Types/Workflow/Components/API/Patch.js.map +1 -1
  306. package/build/dist/Server/Types/Workflow/Components/API/Post.js +2 -1
  307. package/build/dist/Server/Types/Workflow/Components/API/Post.js.map +1 -1
  308. package/build/dist/Server/Types/Workflow/Components/API/Put.js +2 -1
  309. package/build/dist/Server/Types/Workflow/Components/API/Put.js.map +1 -1
  310. package/build/dist/Server/Types/Workflow/Components/API/Utils.js +35 -2
  311. package/build/dist/Server/Types/Workflow/Components/API/Utils.js.map +1 -1
  312. package/build/dist/Server/Types/Workflow/Components/BaseModel/CreateManyBaseModel.js +15 -11
  313. package/build/dist/Server/Types/Workflow/Components/BaseModel/CreateManyBaseModel.js.map +1 -1
  314. package/build/dist/Server/Types/Workflow/Components/BaseModel/CreateOneBaseModel.js +2 -3
  315. package/build/dist/Server/Types/Workflow/Components/BaseModel/CreateOneBaseModel.js.map +1 -1
  316. package/build/dist/Server/Types/Workflow/Components/BaseModel/DeleteManyBaseModel.js +21 -10
  317. package/build/dist/Server/Types/Workflow/Components/BaseModel/DeleteManyBaseModel.js.map +1 -1
  318. package/build/dist/Server/Types/Workflow/Components/BaseModel/DeleteOneBaseModel.js +21 -10
  319. package/build/dist/Server/Types/Workflow/Components/BaseModel/DeleteOneBaseModel.js.map +1 -1
  320. package/build/dist/Server/Types/Workflow/Components/BaseModel/FindManyBaseModel.js +18 -13
  321. package/build/dist/Server/Types/Workflow/Components/BaseModel/FindManyBaseModel.js.map +1 -1
  322. package/build/dist/Server/Types/Workflow/Components/BaseModel/FindOneBaseModel.js +18 -13
  323. package/build/dist/Server/Types/Workflow/Components/BaseModel/FindOneBaseModel.js.map +1 -1
  324. package/build/dist/Server/Types/Workflow/Components/BaseModel/LogComponentError.js +43 -0
  325. package/build/dist/Server/Types/Workflow/Components/BaseModel/LogComponentError.js.map +1 -0
  326. package/build/dist/Server/Types/Workflow/Components/BaseModel/ModelArguments.js +116 -0
  327. package/build/dist/Server/Types/Workflow/Components/BaseModel/ModelArguments.js.map +1 -0
  328. package/build/dist/Server/Types/Workflow/Components/BaseModel/OnTriggerBaseModel.js +7 -0
  329. package/build/dist/Server/Types/Workflow/Components/BaseModel/OnTriggerBaseModel.js.map +1 -1
  330. package/build/dist/Server/Types/Workflow/Components/BaseModel/UpdateManyBaseModel.js +24 -13
  331. package/build/dist/Server/Types/Workflow/Components/BaseModel/UpdateManyBaseModel.js.map +1 -1
  332. package/build/dist/Server/Types/Workflow/Components/BaseModel/UpdateOneBaseModel.js +27 -13
  333. package/build/dist/Server/Types/Workflow/Components/BaseModel/UpdateOneBaseModel.js.map +1 -1
  334. package/build/dist/Server/Types/Workflow/Components/Discord/SendMessageToChannel.js +14 -6
  335. package/build/dist/Server/Types/Workflow/Components/Discord/SendMessageToChannel.js.map +1 -1
  336. package/build/dist/Server/Types/Workflow/Components/IncomingWebhookUtils.js +42 -0
  337. package/build/dist/Server/Types/Workflow/Components/IncomingWebhookUtils.js.map +1 -0
  338. package/build/dist/Server/Types/Workflow/Components/MicrosoftTeams/SendMessageToChannel.js +15 -6
  339. package/build/dist/Server/Types/Workflow/Components/MicrosoftTeams/SendMessageToChannel.js.map +1 -1
  340. package/build/dist/Server/Types/Workflow/Components/Slack/SendMessageToChannel.js +10 -2
  341. package/build/dist/Server/Types/Workflow/Components/Slack/SendMessageToChannel.js.map +1 -1
  342. package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js +1 -1
  343. package/build/dist/Server/Utils/AI/CodeFix/CodeAgentWorkspaceGuard.js +141 -0
  344. package/build/dist/Server/Utils/AI/CodeFix/CodeAgentWorkspaceGuard.js.map +1 -1
  345. package/build/dist/Server/Utils/AI/SRE/Insights/FixRouting.js.map +1 -1
  346. package/build/dist/Server/Utils/AI/SRE/TelemetryImprovementTaskTrigger.js +1 -1
  347. package/build/dist/Server/Utils/AI/Toolbox/CodeWriteTools.js +6 -6
  348. package/build/dist/Server/Utils/AI/Toolbox/CodeWriteTools.js.map +1 -1
  349. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js +39 -5
  350. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js.map +1 -1
  351. package/build/dist/Server/Utils/DataSource/EgressGuard.js +94 -10
  352. package/build/dist/Server/Utils/DataSource/EgressGuard.js.map +1 -1
  353. package/build/dist/Server/Utils/DataSource/HttpFetch.js +1 -19
  354. package/build/dist/Server/Utils/DataSource/HttpFetch.js.map +1 -1
  355. package/build/dist/Server/Utils/Execute.js +2 -2
  356. package/build/dist/Server/Utils/Execute.js.map +1 -1
  357. package/build/dist/Server/Utils/InlineImageAccessTokenSync.js +13 -0
  358. package/build/dist/Server/Utils/InlineImageAccessTokenSync.js.map +1 -1
  359. package/build/dist/Server/Utils/LLM/LLMService.js +43 -12
  360. package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
  361. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +44 -24
  362. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  363. package/build/dist/Server/Utils/Monitor/MonitorDependencySuppression.js +158 -0
  364. package/build/dist/Server/Utils/Monitor/MonitorDependencySuppression.js.map +1 -0
  365. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +50 -30
  366. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  367. package/build/dist/Server/Utils/Monitor/MonitorResource.js +32 -0
  368. package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
  369. package/build/dist/Server/Utils/Response.js +112 -5
  370. package/build/dist/Server/Utils/Response.js.map +1 -1
  371. package/build/dist/Server/Utils/SSRFProtection.js +219 -53
  372. package/build/dist/Server/Utils/SSRFProtection.js.map +1 -1
  373. package/build/dist/Server/Utils/StartServer.js +7 -0
  374. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  375. package/build/dist/Server/Utils/VM/VMRunner.js +73 -1
  376. package/build/dist/Server/Utils/VM/VMRunner.js.map +1 -1
  377. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +445 -43
  378. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  379. package/build/dist/Server/Utils/Workspace/Slack/Slack.js +18 -1
  380. package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
  381. package/build/dist/Server/Utils/Workspace/WorkspaceBase.js.map +1 -1
  382. package/build/dist/Types/AI/FixPullRequestCiStatus.js +1 -1
  383. package/build/dist/Types/AI/FixVerificationStatus.js +2 -2
  384. package/build/dist/Types/API/Hostname.js +73 -4
  385. package/build/dist/Types/API/Hostname.js.map +1 -1
  386. package/build/dist/Types/API/URL.js +42 -24
  387. package/build/dist/Types/API/URL.js.map +1 -1
  388. package/build/dist/Types/Billing/BalanceAdjustmentType.js +15 -0
  389. package/build/dist/Types/Billing/BalanceAdjustmentType.js.map +1 -0
  390. package/build/dist/Types/Billing/ProjectBalanceType.js +14 -0
  391. package/build/dist/Types/Billing/ProjectBalanceType.js.map +1 -0
  392. package/build/dist/Types/Domain.js +22 -0
  393. package/build/dist/Types/Domain.js.map +1 -1
  394. package/build/dist/Types/File/MimeType.js +11 -0
  395. package/build/dist/Types/File/MimeType.js.map +1 -1
  396. package/build/dist/Types/JSONFunctions.js +14 -0
  397. package/build/dist/Types/JSONFunctions.js.map +1 -1
  398. package/build/dist/Types/Workflow/Components/BaseModel.js +83 -28
  399. package/build/dist/Types/Workflow/Components/BaseModel.js.map +1 -1
  400. package/build/dist/UI/Components/GanttChart/ChartContainer.js +4 -3
  401. package/build/dist/UI/Components/GanttChart/ChartContainer.js.map +1 -1
  402. package/build/dist/UI/Components/Modal/ConfirmModal.js +3 -1
  403. package/build/dist/UI/Components/Modal/ConfirmModal.js.map +1 -1
  404. package/build/dist/UI/Components/Modal/Modal.js +24 -34
  405. package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
  406. package/build/dist/UI/Components/ModelDelete/ModelDelete.js +11 -6
  407. package/build/dist/UI/Components/ModelDelete/ModelDelete.js.map +1 -1
  408. package/build/dist/UI/Components/SideOver/SideOver.js +105 -30
  409. package/build/dist/UI/Components/SideOver/SideOver.js.map +1 -1
  410. package/build/dist/UI/Utils/PageScrollLock.js +52 -0
  411. package/build/dist/UI/Utils/PageScrollLock.js.map +1 -0
  412. package/build/dist/Utils/Dashboard/HtmlWidgetDocument.js +4 -2
  413. package/build/dist/Utils/Dashboard/HtmlWidgetDocument.js.map +1 -1
  414. package/build/dist/Utils/Dashboard/VariableInterpolation.js +19 -1
  415. package/build/dist/Utils/Dashboard/VariableInterpolation.js.map +1 -1
  416. package/build/dist/Utils/LegacySerializedArray.js +51 -0
  417. package/build/dist/Utils/LegacySerializedArray.js.map +1 -0
  418. package/build/dist/Utils/Monitor/MonitorDependencyRule.js +47 -0
  419. package/build/dist/Utils/Monitor/MonitorDependencyRule.js.map +1 -0
  420. package/build/dist/Utils/Telemetry/SavedViewFilters.js +52 -0
  421. package/build/dist/Utils/Telemetry/SavedViewFilters.js.map +1 -0
  422. package/jest.config.json +3 -0
  423. package/package.json +1 -1
  424. package/tsconfig.json +3 -1
@@ -479,6 +479,117 @@ export default class Monitor extends BaseModel {
479
479
  })
480
480
  public labels?: Array<Label> = undefined;
481
481
 
482
+ @ColumnAccessControl({
483
+ create: [
484
+ Permission.ProjectOwner,
485
+ Permission.ProjectAdmin,
486
+ Permission.ProjectMember,
487
+ Permission.MonitorAdmin,
488
+ Permission.MonitorMember,
489
+ Permission.CreateProjectMonitor,
490
+ ],
491
+ read: [
492
+ Permission.ProjectOwner,
493
+ Permission.ProjectAdmin,
494
+ Permission.ProjectMember,
495
+ Permission.Viewer,
496
+ Permission.MonitorAdmin,
497
+ Permission.MonitorMember,
498
+ Permission.MonitorViewer,
499
+ Permission.ReadProjectMonitor,
500
+ ],
501
+ update: [
502
+ Permission.ProjectOwner,
503
+ Permission.ProjectAdmin,
504
+ Permission.ProjectMember,
505
+ Permission.MonitorAdmin,
506
+ Permission.MonitorMember,
507
+ Permission.EditProjectMonitor,
508
+ ],
509
+ })
510
+ @TableColumn({
511
+ required: false,
512
+ type: TableColumnType.EntityArray,
513
+ modelType: Monitor,
514
+ title: "Depends On Monitors",
515
+ description:
516
+ "Parent monitors this monitor depends on. When a parent is offline (or in one of the configured suppression statuses), alerts and incidents from this monitor are suppressed at creation time — the monitor keeps evaluating and its status timeline still updates.",
517
+ })
518
+ @ManyToMany(
519
+ () => {
520
+ return Monitor;
521
+ },
522
+ { eager: false },
523
+ )
524
+ @JoinTable({
525
+ name: "MonitorDependency",
526
+ inverseJoinColumn: {
527
+ name: "dependsOnMonitorId",
528
+ referencedColumnName: "_id",
529
+ },
530
+ joinColumn: {
531
+ name: "monitorId",
532
+ referencedColumnName: "_id",
533
+ },
534
+ })
535
+ public dependsOnMonitors?: Array<Monitor> = undefined;
536
+
537
+ @ColumnAccessControl({
538
+ create: [
539
+ Permission.ProjectOwner,
540
+ Permission.ProjectAdmin,
541
+ Permission.ProjectMember,
542
+ Permission.MonitorAdmin,
543
+ Permission.MonitorMember,
544
+ Permission.CreateProjectMonitor,
545
+ ],
546
+ read: [
547
+ Permission.ProjectOwner,
548
+ Permission.ProjectAdmin,
549
+ Permission.ProjectMember,
550
+ Permission.Viewer,
551
+ Permission.MonitorAdmin,
552
+ Permission.MonitorMember,
553
+ Permission.MonitorViewer,
554
+ Permission.ReadProjectMonitor,
555
+ ],
556
+ update: [
557
+ Permission.ProjectOwner,
558
+ Permission.ProjectAdmin,
559
+ Permission.ProjectMember,
560
+ Permission.MonitorAdmin,
561
+ Permission.MonitorMember,
562
+ Permission.EditProjectMonitor,
563
+ ],
564
+ })
565
+ @TableColumn({
566
+ required: false,
567
+ type: TableColumnType.EntityArray,
568
+ modelType: MonitorStatus,
569
+ title: "Suppress Alerts When Parent Monitor Status Is",
570
+ description:
571
+ "Parent monitor statuses that suppress this monitor's alerts and incidents. When empty, statuses flagged as offline suppress (the default). Only used when Depends On Monitors is set.",
572
+ })
573
+ @ManyToMany(
574
+ () => {
575
+ return MonitorStatus;
576
+ },
577
+ { eager: false },
578
+ )
579
+ @JoinTable({
580
+ name: "MonitorDependencySuppressionStatus",
581
+ inverseJoinColumn: {
582
+ name: "monitorStatusId",
583
+ referencedColumnName: "_id",
584
+ },
585
+ joinColumn: {
586
+ name: "monitorId",
587
+ referencedColumnName: "_id",
588
+ },
589
+ })
590
+ public suppressAlertsWhenParentMonitorStatuses?: Array<MonitorStatus> =
591
+ undefined;
592
+
482
593
  @ColumnAccessControl({
483
594
  create: [
484
595
  Permission.ProjectOwner,
@@ -1654,7 +1654,7 @@ export default class Project extends TenantModel {
1654
1654
  type: TableColumnType.Boolean,
1655
1655
  title: "Enable Automatic Incident Code Fixes",
1656
1656
  description:
1657
- "When enabled, an incident AI investigation that ends with a confident, evidenced root cause analysis and recommends a repository code change automatically queues an AI agent task that opens a draft fix pull request from that analysis — the automatic form of the 'Open Fix PR from this analysis' button. Operational, infrastructure, external, user-error and inconclusive findings do not offer or open code-fix pull requests. Requires a repository connected through the GitHub App and a Runner with the code-fix capability. Pull requests are always human-reviewed — nothing merges automatically.",
1657
+ "When enabled, an incident AI investigation that ends with a confident, evidenced root cause analysis and recommends a repository code change automatically queues an AI agent task that opens a fix pull request, ready for review, from that analysis — the automatic form of the 'Open Fix PR from this analysis' button. Operational, infrastructure, external, user-error and inconclusive findings do not offer or open code-fix pull requests. Requires a repository connected through the GitHub App and a Runner with the code-fix capability. Pull requests are always human-reviewed — nothing merges automatically.",
1658
1658
  defaultValue: false,
1659
1659
  example: true,
1660
1660
  })
@@ -1684,7 +1684,7 @@ export default class Project extends TenantModel {
1684
1684
  type: TableColumnType.Boolean,
1685
1685
  title: "Enable Automatic Alert Code Fixes",
1686
1686
  description:
1687
- "When enabled, an alert AI investigation that ends with a confident, evidenced root cause analysis and recommends a repository code change automatically queues an AI agent task that opens a draft fix pull request from that analysis — the automatic form of the 'Open Fix PR from this analysis' button. Operational, infrastructure, external, user-error and inconclusive findings do not offer or open code-fix pull requests. Requires a repository connected through the GitHub App and a Runner with the code-fix capability. Pull requests are always human-reviewed — nothing merges automatically.",
1687
+ "When enabled, an alert AI investigation that ends with a confident, evidenced root cause analysis and recommends a repository code change automatically queues an AI agent task that opens a fix pull request, ready for review, from that analysis — the automatic form of the 'Open Fix PR from this analysis' button. Operational, infrastructure, external, user-error and inconclusive findings do not offer or open code-fix pull requests. Requires a repository connected through the GitHub App and a Runner with the code-fix capability. Pull requests are always human-reviewed — nothing merges automatically.",
1688
1688
  defaultValue: false,
1689
1689
  example: true,
1690
1690
  })
@@ -1744,7 +1744,7 @@ export default class Project extends TenantModel {
1744
1744
  type: TableColumnType.Boolean,
1745
1745
  title: "Enable Insight Fix Tasks",
1746
1746
  description:
1747
- "When enabled, insights whose deterministic evidence points at code (new or spiking exceptions with a resolvable repository, trace-latency regressions with span-tree findings) automatically queue an AI agent task that opens a draft pull request with a proposed fix. Honors the daily fix task budget and per-repository open-PR caps. Pull requests are always human-reviewed — nothing merges automatically.",
1747
+ "When enabled, insights whose deterministic evidence points at code (new or spiking exceptions with a resolvable repository, trace-latency regressions with span-tree findings) automatically queue an AI agent task that opens a pull request with a proposed fix, ready for review. Honors the daily fix task budget and per-repository open-PR caps. Pull requests are always human-reviewed — nothing merges automatically.",
1748
1748
  defaultValue: false,
1749
1749
  example: true,
1750
1750
  })
@@ -36,6 +36,23 @@ export interface MicrosoftTeamsChat {
36
36
  addedAt?: string | undefined;
37
37
  }
38
38
 
39
+ /*
40
+ * A team the OneUptime app has actually been installed into, captured from the
41
+ * bot's install / conversationUpdate events.
42
+ *
43
+ * Graph can list every team in the tenant with app-only permissions, but the
44
+ * Bot Framework will only accept a proactive post into a team the app is a
45
+ * roster member of. Listing a team is therefore NOT evidence that we can post
46
+ * to it — this record is, which is why channel sends check it before calling
47
+ * the Bot Framework.
48
+ */
49
+ export interface MicrosoftTeamsInstalledTeam {
50
+ id: string; // Teams team (group) id.
51
+ name?: string | undefined;
52
+ serviceUrl?: string | undefined; // Bot Framework service URL captured on install. Required for GCC/DoD.
53
+ addedAt?: string | undefined;
54
+ }
55
+
39
56
  export interface SlackMiscData extends MiscData {
40
57
  teamId: string;
41
58
  teamName: string;
@@ -59,9 +76,10 @@ export interface MicrosoftTeamsMiscData extends MiscData {
59
76
  lastAppTokenIssuedAt?: string;
60
77
  adminConsentGrantedAt?: string;
61
78
  adminConsentGrantedBy?: string;
62
- availableTeams?: Record<string, MicrosoftTeamsTeam>;
79
+ availableTeams?: Record<string, MicrosoftTeamsTeam>; // keyed by team id. Every team Graph can see in the tenant.
63
80
  appAccessTokenExpiresAt?: string;
64
81
  availableChats?: Record<string, MicrosoftTeamsChat>; // keyed by chat id. Chats the OneUptime app has been added to.
82
+ installedTeams?: Record<string, MicrosoftTeamsInstalledTeam>; // keyed by team id. Teams the OneUptime app has been added to.
65
83
  }
66
84
 
67
85
  export type WorkspaceMiscData = SlackMiscData | MicrosoftTeamsMiscData;
@@ -32,6 +32,17 @@ const isAuthenticatedRequest: (req: ExpressRequest) => boolean = (
32
32
  }
33
33
  };
34
34
 
35
+ /*
36
+ * isPublic is a real boolean column, but this stays deliberately strict.
37
+ * It was created as a varchar, so every row held the STRING 'true'/'false'
38
+ * — and 'false' is truthy, which silently disabled both gates below. Treat
39
+ * anything that is not exactly `true` as private so a loose value can never
40
+ * re-open them.
41
+ */
42
+ const isFilePublic: (file: File) => boolean = (file: File): boolean => {
43
+ return (file.isPublic as unknown) === true;
44
+ };
45
+
35
46
  export default class FileAPI extends BaseAPI<File, FileServiceType> {
36
47
  public constructor() {
37
48
  super(File, FileService);
@@ -74,6 +85,7 @@ export default class FileAPI extends BaseAPI<File, FileServiceType> {
74
85
  file: true,
75
86
  fileType: true,
76
87
  isPublic: true,
88
+ name: true,
77
89
  },
78
90
  });
79
91
 
@@ -85,7 +97,7 @@ export default class FileAPI extends BaseAPI<File, FileServiceType> {
85
97
  );
86
98
  }
87
99
 
88
- if (!file.isPublic && !isAuthenticatedRequest(req)) {
100
+ if (!isFilePublic(file) && !isAuthenticatedRequest(req)) {
89
101
  return Response.sendErrorResponse(
90
102
  req,
91
103
  res,
@@ -120,10 +132,11 @@ export default class FileAPI extends BaseAPI<File, FileServiceType> {
120
132
  file: true,
121
133
  fileType: true,
122
134
  isPublic: true,
135
+ name: true,
123
136
  },
124
137
  });
125
138
 
126
- if (!file || !file.file || !file.fileType || !file.isPublic) {
139
+ if (!file || !file.file || !file.fileType || !isFilePublic(file)) {
127
140
  return Response.sendErrorResponse(
128
141
  req,
129
142
  res,
@@ -799,7 +799,12 @@ export default class MicrosoftTeamsAPI {
799
799
  id: t["id"] as string,
800
800
  name: (t["displayName"] as string) || "Unnamed Team",
801
801
  };
802
- acc[team.name] = team;
802
+ /*
803
+ * Keyed by id, not display name — Teams allows duplicate
804
+ * team names, and keying by name silently collapsed them so
805
+ * only the last one of each name was selectable.
806
+ */
807
+ acc[team.id] = team;
803
808
  return acc;
804
809
  },
805
810
  {} as Record<string, MicrosoftTeamsTeam>,
@@ -3,6 +3,7 @@ import MasterAdminAuthorization from "../Middleware/MasterAdminAuthorization";
3
3
  import UserMiddleware from "../Middleware/UserAuthorization";
4
4
  import ProjectService, {
5
5
  ProjectService as ProjectServiceType,
6
+ ProjectBalanceAdjustmentResult,
6
7
  } from "../Services/ProjectService";
7
8
  import ResellerService from "../Services/ResellerService";
8
9
  import TeamMemberService from "../Services/TeamMemberService";
@@ -17,6 +18,7 @@ import {
17
18
  import JSONWebToken from "../Utils/JsonWebToken";
18
19
  import Response from "../Utils/Response";
19
20
  import BaseAPI from "./BaseAPI";
21
+ import CommonAPI from "./CommonAPI";
20
22
  import BillingService from "../Services/BillingService";
21
23
  import Errors from "../Utils/Errors";
22
24
  import { LIMIT_PER_PROJECT } from "../../Types/Database/LimitMax";
@@ -28,9 +30,17 @@ import TeamMember from "../../Models/DatabaseModels/TeamMember";
28
30
  import BadDataException from "../../Types/Exception/BadDataException";
29
31
  import OneUptimeDate from "../../Types/Date";
30
32
  import Permission, { UserPermission } from "../../Types/Permission";
33
+ import ProjectBalanceType from "../../Types/Billing/ProjectBalanceType";
34
+ import BalanceAdjustmentType from "../../Types/Billing/BalanceAdjustmentType";
31
35
  import ObjectID from "../../Types/ObjectID";
32
36
  import { JSONObject, JSONValue } from "../../Types/JSON";
33
37
 
38
+ /*
39
+ * The reason is free text a customer types into the delete confirmation. The
40
+ * column is unbounded text, so the cap is here.
41
+ */
42
+ export const MAX_DELETION_REASON_LENGTH: number = 5000;
43
+
34
44
  export default class ProjectAPI extends BaseAPI<Project, ProjectServiceType> {
35
45
  public constructor() {
36
46
  super(Project, ProjectService);
@@ -137,6 +147,76 @@ export default class ProjectAPI extends BaseAPI<Project, ProjectServiceType> {
137
147
  },
138
148
  );
139
149
 
150
+ /*
151
+ * Deletes a project, carrying the reason the customer gave for deleting it.
152
+ * The plain DELETE /project/:id route still works and still records the
153
+ * deletion - this one exists only because a DELETE has nowhere to put the
154
+ * answer to "why are you deleting this project?".
155
+ *
156
+ * The delete itself goes through deleteOneById with the caller's own props,
157
+ * so ModelPermission enforces ProjectOwner / DeleteProject exactly as it
158
+ * does on the plain route.
159
+ */
160
+ this.router.post(
161
+ `${new this.entityType().getCrudApiPath()?.toString()}/:id/delete-project`,
162
+ UserMiddleware.getUserMiddleware,
163
+ async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
164
+ try {
165
+ const idParam: string = req.params["id"] as string;
166
+ ObjectID.validateUUID(idParam);
167
+ const projectId: ObjectID = new ObjectID(idParam);
168
+
169
+ /*
170
+ * Same guard as change-plan: permissions are resolved for the
171
+ * authenticated tenant, so the project in the URL has to be that
172
+ * tenant or permissions on one project would authorize deleting
173
+ * another.
174
+ */
175
+ const tenantId: ObjectID | null = this.getTenantId(req);
176
+
177
+ if (!tenantId || tenantId.toString() !== projectId.toString()) {
178
+ throw new BadDataException(
179
+ "Project ID in the URL does not match the project the request is authenticated for",
180
+ );
181
+ }
182
+
183
+ const body: JSONObject = (req.body as JSONObject) || {};
184
+ const data: JSONObject = (body["data"] as JSONObject) || {};
185
+ const deletionReasonValue: JSONValue = data["deletionReason"];
186
+
187
+ let deletionReason: string | undefined = undefined;
188
+
189
+ if (typeof deletionReasonValue === "string") {
190
+ /*
191
+ * Free text from a form field. Bound what a client can store, and
192
+ * drop NUL bytes: Postgres rejects them in a text column, and the
193
+ * write that fails here is the audit record of a project that has
194
+ * already been deleted - there is no second chance at it.
195
+ */
196
+ const cleaned: string = deletionReasonValue
197
+ // eslint-disable-next-line no-control-regex
198
+ .replace(/\u0000/g, "")
199
+ .trim()
200
+ .substring(0, MAX_DELETION_REASON_LENGTH);
201
+
202
+ if (cleaned) {
203
+ deletionReason = cleaned;
204
+ }
205
+ }
206
+
207
+ await ProjectService.deleteOneById({
208
+ id: projectId,
209
+ deletionReason: deletionReason,
210
+ props: await CommonAPI.getDatabaseCommonInteractionProps(req),
211
+ });
212
+
213
+ return Response.sendEmptySuccessResponse(req, res);
214
+ } catch (err) {
215
+ next(err);
216
+ }
217
+ },
218
+ );
219
+
140
220
  /*
141
221
  * Extends a project's trial. Master-admin only: this hands out free
142
222
  * service and moves the customer's next invoice, so it is deliberately not
@@ -212,6 +292,140 @@ export default class ProjectAPI extends BaseAPI<Project, ProjectServiceType> {
212
292
  },
213
293
  );
214
294
 
295
+ /*
296
+ * Manually corrects a project's SMS/Call or AI balance. Master-admin only,
297
+ * for the same reason extend-trial is: it hands out (or claws back) paid
298
+ * service with no payment behind it, so project-level billing permissions
299
+ * must not reach it - only OneUptime staff acting from the Admin
300
+ * Dashboard.
301
+ */
302
+ this.router.put(
303
+ `${new this.entityType().getCrudApiPath()?.toString()}/:id/adjust-balance`,
304
+ MasterAdminAuthorization.isAuthorizedMasterAdminMiddleware,
305
+ async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
306
+ try {
307
+ if (!IsBillingEnabled) {
308
+ throw new BadDataException(
309
+ "Billing is not enabled for this server",
310
+ );
311
+ }
312
+
313
+ const projectId: ObjectID = new ObjectID(req.params["id"] as string);
314
+
315
+ const body: JSONObject = (req.body as JSONObject) || {};
316
+ const data: JSONObject = (body["data"] as JSONObject) || {};
317
+
318
+ const balanceTypeValue: JSONValue = data["balanceType"];
319
+ const adjustmentTypeValue: JSONValue = data["adjustmentType"];
320
+ const amountInUSDValue: JSONValue = data["amountInUSD"];
321
+ const reasonValue: JSONValue = data["reason"];
322
+
323
+ if (
324
+ !balanceTypeValue ||
325
+ typeof balanceTypeValue !== "string" ||
326
+ !Object.values(ProjectBalanceType).includes(
327
+ balanceTypeValue as ProjectBalanceType,
328
+ )
329
+ ) {
330
+ throw new BadDataException(
331
+ `Balance type must be one of: ${Object.values(
332
+ ProjectBalanceType,
333
+ ).join(", ")}`,
334
+ );
335
+ }
336
+
337
+ if (
338
+ !adjustmentTypeValue ||
339
+ typeof adjustmentTypeValue !== "string" ||
340
+ !Object.values(BalanceAdjustmentType).includes(
341
+ adjustmentTypeValue as BalanceAdjustmentType,
342
+ )
343
+ ) {
344
+ throw new BadDataException(
345
+ `Adjustment type must be one of: ${Object.values(
346
+ BalanceAdjustmentType,
347
+ ).join(", ")}`,
348
+ );
349
+ }
350
+
351
+ /*
352
+ * The form posts dollars because that is what staff think in, but
353
+ * the column is cents. A JSON body can carry a numeric string, so
354
+ * accept both and reject anything that does not parse - Number("")
355
+ * and Number([]) are 0, which would otherwise read as a real
356
+ * "set to zero" instruction.
357
+ */
358
+ if (
359
+ typeof amountInUSDValue !== "number" &&
360
+ typeof amountInUSDValue !== "string"
361
+ ) {
362
+ throw new BadDataException("Amount is not a valid number");
363
+ }
364
+
365
+ const amountInUSD: number =
366
+ typeof amountInUSDValue === "number"
367
+ ? amountInUSDValue
368
+ : Number(amountInUSDValue.trim());
369
+
370
+ if (
371
+ !Number.isFinite(amountInUSD) ||
372
+ (typeof amountInUSDValue === "string" &&
373
+ amountInUSDValue.trim() === "")
374
+ ) {
375
+ throw new BadDataException("Amount is not a valid number");
376
+ }
377
+
378
+ if (typeof reasonValue !== "string" || !reasonValue.trim()) {
379
+ throw new BadDataException(
380
+ "A reason is required to adjust the balance",
381
+ );
382
+ }
383
+
384
+ /*
385
+ * Dollars carry at most two decimal places, and floating point
386
+ * multiplication does not (20.15 * 100 is 2014.9999...). Round to
387
+ * the nearest cent so the stored amount is the one that was typed.
388
+ */
389
+ const amountInUSDCents: number = Math.round(amountInUSD * 100);
390
+
391
+ /*
392
+ * The master admin middleware verifies the token but does not put
393
+ * the decoded payload on the request, so read it again here - who
394
+ * moved the balance is the only audit trail this action has.
395
+ */
396
+ let adjustedByUserId: ObjectID | undefined = undefined;
397
+
398
+ try {
399
+ const accessToken: string | undefined =
400
+ UserMiddleware.getAccessTokenFromExpressRequest(req);
401
+
402
+ if (accessToken) {
403
+ adjustedByUserId = JSONWebToken.decode(accessToken).userId;
404
+ }
405
+ } catch {
406
+ // Only used for the log line - never block the adjustment on it.
407
+ }
408
+
409
+ const result: ProjectBalanceAdjustmentResult =
410
+ await ProjectService.adjustBalance({
411
+ projectId: projectId,
412
+ balanceType: balanceTypeValue as ProjectBalanceType,
413
+ adjustmentType: adjustmentTypeValue as BalanceAdjustmentType,
414
+ amountInUSDCents: amountInUSDCents,
415
+ reason: reasonValue,
416
+ adjustedByUserId: adjustedByUserId,
417
+ });
418
+
419
+ return Response.sendJsonObjectResponse(req, res, {
420
+ previousBalanceInUSDCents: result.previousBalanceInUSDCents,
421
+ newBalanceInUSDCents: result.newBalanceInUSDCents,
422
+ });
423
+ } catch (err) {
424
+ next(err);
425
+ }
426
+ },
427
+ );
428
+
215
429
  /*
216
430
  * This API lists all the projects where user is its team member.
217
431
  * This API is usually used to show project selector dropdown in the UI
@@ -113,6 +113,23 @@ import StatusPageSubscriberNotificationTemplateService, {
113
113
  Service as StatusPageSubscriberNotificationTemplateServiceClass,
114
114
  } from "../Services/StatusPageSubscriberNotificationTemplateService";
115
115
 
116
+ type EscapeXmlFunction = (text: string) => string;
117
+
118
+ /*
119
+ * The status badge is hand-built SVG served as image/svg+xml, and SVG is a
120
+ * document - anything interpolated into it is markup, not text. A monitor
121
+ * status named `</text><script>...` would otherwise run on the status page
122
+ * origin for anyone who opens the badge URL directly.
123
+ */
124
+ const escapeXml: EscapeXmlFunction = (text: string): string => {
125
+ return text
126
+ .replace(/&/g, "&amp;")
127
+ .replace(/</g, "&lt;")
128
+ .replace(/>/g, "&gt;")
129
+ .replace(/"/g, "&quot;")
130
+ .replace(/'/g, "&apos;");
131
+ };
132
+
116
133
  type ResolveStatusPageIdOrThrowFunction = (
117
134
  statusPageIdOrDomain: string,
118
135
  ) => Promise<ObjectID>;
@@ -531,9 +548,12 @@ export default class StatusPageAPI extends BaseAPI<
531
548
  });
532
549
 
533
550
  // Generate SVG badge
534
- const statusName: string = overallStatus?.name || "Unknown";
535
- const statusColor: string =
536
- overallStatus?.color?.toString() || "#808080";
551
+ const statusName: string = escapeXml(
552
+ overallStatus?.name || "Unknown",
553
+ );
554
+ const statusColor: string = escapeXml(
555
+ overallStatus?.color?.toString() || "#808080",
556
+ );
537
557
 
538
558
  const svg: string = `<svg xmlns="http://www.w3.org/2000/svg" width="150" height="20">
539
559
  <linearGradient id="b" x2="0" y2="100%">
@@ -558,6 +578,17 @@ export default class StatusPageAPI extends BaseAPI<
558
578
 
559
579
  res.setHeader("Content-Type", "image/svg+xml");
560
580
  res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
581
+ /*
582
+ * The badge is only ever loaded through <img>, which ignores both of
583
+ * these. They exist for the case where someone opens the badge URL
584
+ * as a top-level document, where the SVG would otherwise be a
585
+ * scriptable document on this origin.
586
+ */
587
+ res.setHeader("X-Content-Type-Options", "nosniff");
588
+ res.setHeader(
589
+ "Content-Security-Policy",
590
+ "sandbox; script-src 'none'; object-src 'none'",
591
+ );
561
592
  return res.send(svg);
562
593
  } catch (err) {
563
594
  logger.error(err, getLogAttributesFromRequest(req as any));
@@ -786,9 +817,11 @@ export default class StatusPageAPI extends BaseAPI<
786
817
  UserMiddleware.getUserMiddleware,
787
818
  async (req: ExpressRequest, res: ExpressResponse, next: NextFunction) => {
788
819
  try {
789
- const objectId: ObjectID = new ObjectID(
790
- req.params["statusPageId"] as string,
791
- );
820
+ const statusPageIdParam: string = req.params[
821
+ "statusPageId"
822
+ ] as string;
823
+ ObjectID.validateUUID(statusPageIdParam);
824
+ const objectId: ObjectID = new ObjectID(statusPageIdParam);
792
825
 
793
826
  const select: Select<StatusPage> = {
794
827
  _id: true,
@@ -0,0 +1,50 @@
1
+ import { MigrationInterface, QueryRunner } from "typeorm";
2
+
3
+ export class MigrationName1786446545142 implements MigrationInterface {
4
+ public name = "MigrationName1786446545142";
5
+
6
+ public async up(queryRunner: QueryRunner): Promise<void> {
7
+ /*
8
+ * "File"."isPublic" backs a `boolean` field but was created as varchar,
9
+ * so every row holds the STRING 'true'/'false' and every server-side
10
+ * `!file.isPublic` gate was inert — 'false' is truthy in JS.
11
+ *
12
+ * Convert in place. TypeORM generates a DROP COLUMN + ADD COLUMN for
13
+ * this change, which would discard every stored value and re-default
14
+ * the whole table to public — the exact opposite of the fix.
15
+ */
16
+ await queryRunner.query(
17
+ `ALTER TABLE "File" ALTER COLUMN "isPublic" DROP DEFAULT`,
18
+ );
19
+ await queryRunner.query(
20
+ `ALTER TABLE "File" ALTER COLUMN "isPublic" TYPE boolean USING (lower("isPublic") IN ('true', 't', 'yes', 'y', '1'))`,
21
+ );
22
+ await queryRunner.query(
23
+ `ALTER TABLE "File" ALTER COLUMN "isPublic" SET DEFAULT true`,
24
+ );
25
+
26
+ /*
27
+ * Probe and AI agent icons are the only consumers of the id-based
28
+ * image route, which serves public files only. Both upload through the
29
+ * file picker, which marks uploads private, so every icon attached
30
+ * before this migration would 404 once the gate starts working.
31
+ * ProbeService/AIAgentService now flip the icon public on attach; this
32
+ * backfills the rows attached before that hook existed.
33
+ */
34
+ await queryRunner.query(
35
+ `UPDATE "File" SET "isPublic" = true WHERE "_id" IN (SELECT "iconFileId" FROM "Probe" WHERE "iconFileId" IS NOT NULL UNION SELECT "iconFileId" FROM "AIAgent" WHERE "iconFileId" IS NOT NULL)`,
36
+ );
37
+ }
38
+
39
+ public async down(queryRunner: QueryRunner): Promise<void> {
40
+ await queryRunner.query(
41
+ `ALTER TABLE "File" ALTER COLUMN "isPublic" DROP DEFAULT`,
42
+ );
43
+ await queryRunner.query(
44
+ `ALTER TABLE "File" ALTER COLUMN "isPublic" TYPE character varying(100) USING (CASE WHEN "isPublic" THEN 'true' ELSE 'false' END)`,
45
+ );
46
+ await queryRunner.query(
47
+ `ALTER TABLE "File" ALTER COLUMN "isPublic" SET DEFAULT true`,
48
+ );
49
+ }
50
+ }