@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
@@ -0,0 +1,742 @@
1
+ import {
2
+ RunOptions,
3
+ RunReturnType,
4
+ } from "../../../../../Server/Types/Workflow/ComponentCode";
5
+ import CreateManyBaseModel from "../../../../../Server/Types/Workflow/Components/BaseModel/CreateManyBaseModel";
6
+ import CreateOneBaseModel from "../../../../../Server/Types/Workflow/Components/BaseModel/CreateOneBaseModel";
7
+ import DeleteManyBaseModel from "../../../../../Server/Types/Workflow/Components/BaseModel/DeleteManyBaseModel";
8
+ import DeleteOneBaseModel from "../../../../../Server/Types/Workflow/Components/BaseModel/DeleteOneBaseModel";
9
+ import FindManyBaseModel from "../../../../../Server/Types/Workflow/Components/BaseModel/FindManyBaseModel";
10
+ import FindOneBaseModel from "../../../../../Server/Types/Workflow/Components/BaseModel/FindOneBaseModel";
11
+ import UpdateManyBaseModel from "../../../../../Server/Types/Workflow/Components/BaseModel/UpdateManyBaseModel";
12
+ import UpdateOneBaseModel from "../../../../../Server/Types/Workflow/Components/BaseModel/UpdateOneBaseModel";
13
+ import DatabaseService from "../../../../../Server/Services/DatabaseService";
14
+ import Monitor from "../../../../../Models/DatabaseModels/Monitor";
15
+ import Exception from "../../../../../Types/Exception/Exception";
16
+ import { JSONObject } from "../../../../../Types/JSON";
17
+ import ObjectID from "../../../../../Types/ObjectID";
18
+ import { afterEach, describe, expect, test } from "@jest/globals";
19
+
20
+ /*
21
+ * https://github.com/OneUptime/oneuptime/issues/3132 - "Update One Monitor"
22
+ * with a query of {"id": "<uuid>"} logged
23
+ * `Property "id" was not found in "Monitor". Make sure your query is correct.`
24
+ * and took the Error port, because the persisted primary key column is "_id"
25
+ * and "id" is only a TypeScript accessor on the model.
26
+ *
27
+ * These tests drive the real components and assert on the query object that
28
+ * actually reaches DatabaseService, which is the seam the bug lived in. They
29
+ * also pin three things found alongside it: Update Many dropped the tenant
30
+ * filter on its way to the database, the write components discarded the
31
+ * affected-row count, and Create Many created nothing at all for a model
32
+ * without a tenant column.
33
+ */
34
+
35
+ const MONITOR_ID: string = "09dc4d63-2fc3-4757-a509-5f688ae38ffd";
36
+ const MONITOR_STATUS_ID: string = "dfadda01-fdf6-4cdd-921d-73edcfd71124";
37
+
38
+ interface OptionsFixture {
39
+ options: RunOptions;
40
+ log: jest.Mock;
41
+ onError: jest.Mock;
42
+ projectId: ObjectID;
43
+ }
44
+
45
+ function makeOptions(): OptionsFixture {
46
+ const log: jest.Mock = jest.fn();
47
+ const onError: jest.Mock = jest.fn((exception: Exception): Exception => {
48
+ return exception;
49
+ });
50
+ const projectId: ObjectID = ObjectID.generate();
51
+
52
+ return {
53
+ log,
54
+ onError,
55
+ projectId,
56
+ options: {
57
+ log: log as RunOptions["log"],
58
+ workflowLogId: ObjectID.generate(),
59
+ workflowId: ObjectID.generate(),
60
+ projectId: projectId,
61
+ onError: onError as RunOptions["onError"],
62
+ executeWorkflow: async (): Promise<void> => {},
63
+ },
64
+ };
65
+ }
66
+
67
+ function makeMonitorService(): DatabaseService<Monitor> {
68
+ return new DatabaseService<Monitor>(Monitor);
69
+ }
70
+
71
+ /*
72
+ * Every component calls exactly one DatabaseService method, so the assertions
73
+ * read the first argument of that one call.
74
+ */
75
+ function firstCallArgument(mocked: unknown): JSONObject {
76
+ const calls: Array<Array<unknown>> = (mocked as jest.Mock).mock.calls;
77
+ return calls[0]![0] as JSONObject;
78
+ }
79
+
80
+ function loggedLines(log: jest.Mock): string {
81
+ return log.mock.calls
82
+ .flat()
83
+ .map((line: unknown): string => {
84
+ return String(line);
85
+ })
86
+ .join("\n");
87
+ }
88
+
89
+ afterEach(() => {
90
+ jest.restoreAllMocks();
91
+ });
92
+
93
+ describe("Update One - the component reported in issue 3132", () => {
94
+ test('accepts a query keyed on "id" and queries the "_id" column', async () => {
95
+ const service: DatabaseService<Monitor> = makeMonitorService();
96
+ jest.spyOn(service, "updateOneBy").mockResolvedValue(1 as never);
97
+
98
+ const fixture: OptionsFixture = makeOptions();
99
+ const component: UpdateOneBaseModel<Monitor> =
100
+ new UpdateOneBaseModel<Monitor>(service);
101
+
102
+ const result: RunReturnType = await component.run(
103
+ {
104
+ query: { id: MONITOR_ID },
105
+ data: { currentMonitorStatusId: MONITOR_STATUS_ID },
106
+ },
107
+ fixture.options,
108
+ );
109
+
110
+ const query: JSONObject = firstCallArgument(service.updateOneBy)[
111
+ "query"
112
+ ] as JSONObject;
113
+
114
+ expect(result.executePort?.id).toBe("success");
115
+ expect(query["_id"]).toBe(MONITOR_ID);
116
+ expect(query["id"]).toBeUndefined();
117
+ });
118
+
119
+ test("still accepts a query keyed on _id", async () => {
120
+ const service: DatabaseService<Monitor> = makeMonitorService();
121
+ jest.spyOn(service, "updateOneBy").mockResolvedValue(1 as never);
122
+
123
+ const fixture: OptionsFixture = makeOptions();
124
+ const component: UpdateOneBaseModel<Monitor> =
125
+ new UpdateOneBaseModel<Monitor>(service);
126
+
127
+ const result: RunReturnType = await component.run(
128
+ { query: { _id: MONITOR_ID }, data: { isEnabled: true } },
129
+ fixture.options,
130
+ );
131
+
132
+ const query: JSONObject = firstCallArgument(service.updateOneBy)[
133
+ "query"
134
+ ] as JSONObject;
135
+
136
+ expect(result.executePort?.id).toBe("success");
137
+ expect(query["_id"]).toBe(MONITOR_ID);
138
+ });
139
+
140
+ test('accepts "id" in the Data argument too', async () => {
141
+ const service: DatabaseService<Monitor> = makeMonitorService();
142
+ jest.spyOn(service, "updateOneBy").mockResolvedValue(1 as never);
143
+
144
+ const fixture: OptionsFixture = makeOptions();
145
+ const component: UpdateOneBaseModel<Monitor> =
146
+ new UpdateOneBaseModel<Monitor>(service);
147
+
148
+ await component.run(
149
+ { query: { _id: MONITOR_ID }, data: { id: MONITOR_ID } },
150
+ fixture.options,
151
+ );
152
+
153
+ const data: JSONObject = firstCallArgument(service.updateOneBy)[
154
+ "data"
155
+ ] as JSONObject;
156
+
157
+ expect(data["_id"]).toBe(MONITOR_ID);
158
+ expect(data["id"]).toBeUndefined();
159
+ });
160
+
161
+ test("accepts the JSON strings the workflow runner really passes", async () => {
162
+ const service: DatabaseService<Monitor> = makeMonitorService();
163
+ jest.spyOn(service, "updateOneBy").mockResolvedValue(1 as never);
164
+
165
+ const fixture: OptionsFixture = makeOptions();
166
+ const component: UpdateOneBaseModel<Monitor> =
167
+ new UpdateOneBaseModel<Monitor>(service);
168
+
169
+ const result: RunReturnType = await component.run(
170
+ {
171
+ query: JSON.stringify({ id: MONITOR_ID }),
172
+ data: JSON.stringify({ currentMonitorStatusId: MONITOR_STATUS_ID }),
173
+ },
174
+ fixture.options,
175
+ );
176
+
177
+ const query: JSONObject = firstCallArgument(service.updateOneBy)[
178
+ "query"
179
+ ] as JSONObject;
180
+
181
+ expect(result.executePort?.id).toBe("success");
182
+ expect(query["_id"]).toBe(MONITOR_ID);
183
+ });
184
+
185
+ test("scopes the query to the running project", async () => {
186
+ const service: DatabaseService<Monitor> = makeMonitorService();
187
+ jest.spyOn(service, "updateOneBy").mockResolvedValue(1 as never);
188
+
189
+ const fixture: OptionsFixture = makeOptions();
190
+ const component: UpdateOneBaseModel<Monitor> =
191
+ new UpdateOneBaseModel<Monitor>(service);
192
+
193
+ await component.run(
194
+ { query: { id: MONITOR_ID }, data: { isEnabled: true } },
195
+ fixture.options,
196
+ );
197
+
198
+ const query: JSONObject = firstCallArgument(service.updateOneBy)[
199
+ "query"
200
+ ] as JSONObject;
201
+
202
+ expect(query["projectId"]).toBe(fixture.projectId);
203
+ });
204
+
205
+ test("reports how many records it updated", async () => {
206
+ const service: DatabaseService<Monitor> = makeMonitorService();
207
+ jest.spyOn(service, "updateOneBy").mockResolvedValue(1 as never);
208
+
209
+ const fixture: OptionsFixture = makeOptions();
210
+ const component: UpdateOneBaseModel<Monitor> =
211
+ new UpdateOneBaseModel<Monitor>(service);
212
+
213
+ const result: RunReturnType = await component.run(
214
+ { query: { id: MONITOR_ID }, data: { isEnabled: true } },
215
+ fixture.options,
216
+ );
217
+
218
+ expect(result.returnValues["items-updated"]).toBe(1);
219
+ expect(loggedLines(fixture.log)).toContain("Updated 1 Monitor(s).");
220
+ });
221
+
222
+ test("says so when the query matched nothing, instead of a bare success", async () => {
223
+ const service: DatabaseService<Monitor> = makeMonitorService();
224
+ jest.spyOn(service, "updateOneBy").mockResolvedValue(0 as never);
225
+
226
+ const fixture: OptionsFixture = makeOptions();
227
+ const component: UpdateOneBaseModel<Monitor> =
228
+ new UpdateOneBaseModel<Monitor>(service);
229
+
230
+ const result: RunReturnType = await component.run(
231
+ { query: { id: MONITOR_ID }, data: { isEnabled: true } },
232
+ fixture.options,
233
+ );
234
+
235
+ expect(result.executePort?.id).toBe("success");
236
+ expect(result.returnValues["items-updated"]).toBe(0);
237
+ expect(loggedLines(fixture.log)).toContain("Updated 0 Monitor(s).");
238
+ });
239
+
240
+ test("takes the error port and explains an unknown column", async () => {
241
+ const service: DatabaseService<Monitor> = makeMonitorService();
242
+ jest
243
+ .spyOn(service, "updateOneBy")
244
+ .mockRejectedValue(
245
+ new Error(
246
+ 'Property "currentStatus" was not found in "Monitor". Make sure your query is correct.',
247
+ ) as never,
248
+ );
249
+
250
+ const fixture: OptionsFixture = makeOptions();
251
+ const component: UpdateOneBaseModel<Monitor> =
252
+ new UpdateOneBaseModel<Monitor>(service);
253
+
254
+ const result: RunReturnType = await component.run(
255
+ { query: { currentStatus: "up" }, data: { isEnabled: true } },
256
+ fixture.options,
257
+ );
258
+
259
+ const logs: string = loggedLines(fixture.log);
260
+
261
+ expect(result.executePort?.id).toBe("error");
262
+ expect(logs).toContain("Error running component");
263
+ expect(logs).toContain('"currentStatus" is not a column on Monitor');
264
+ expect(logs).toContain("currentMonitorStatusId");
265
+ });
266
+
267
+ test("cannot move the record into another project via the project relation", async () => {
268
+ /*
269
+ * Monitor.project is @JoinColumn({name: "projectId"}), the same physical
270
+ * column the tenant stamp writes, and TypeORM reads the relation property
271
+ * first. A Data payload naming another project therefore used to beat the
272
+ * stamp and re-home the row.
273
+ */
274
+ const service: DatabaseService<Monitor> = makeMonitorService();
275
+ jest.spyOn(service, "updateOneBy").mockResolvedValue(1 as never);
276
+
277
+ const fixture: OptionsFixture = makeOptions();
278
+ const component: UpdateOneBaseModel<Monitor> =
279
+ new UpdateOneBaseModel<Monitor>(service);
280
+
281
+ await component.run(
282
+ {
283
+ query: { id: MONITOR_ID },
284
+ data: {
285
+ isEnabled: true,
286
+ project: "11111111-1111-1111-1111-111111111111",
287
+ },
288
+ },
289
+ fixture.options,
290
+ );
291
+
292
+ const data: JSONObject = firstCallArgument(service.updateOneBy)[
293
+ "data"
294
+ ] as JSONObject;
295
+
296
+ expect(data["project"]).toBeUndefined();
297
+ expect(data["projectId"]).toBe(fixture.projectId);
298
+ expect(data["isEnabled"]).toBe(true);
299
+ });
300
+
301
+ test("cannot move the record via the project relation written as an object", async () => {
302
+ const service: DatabaseService<Monitor> = makeMonitorService();
303
+ jest.spyOn(service, "updateOneBy").mockResolvedValue(1 as never);
304
+
305
+ const fixture: OptionsFixture = makeOptions();
306
+ const component: UpdateOneBaseModel<Monitor> =
307
+ new UpdateOneBaseModel<Monitor>(service);
308
+
309
+ await component.run(
310
+ {
311
+ query: { id: MONITOR_ID },
312
+ data: { project: { id: "11111111-1111-1111-1111-111111111111" } },
313
+ },
314
+ fixture.options,
315
+ );
316
+
317
+ const data: JSONObject = firstCallArgument(service.updateOneBy)[
318
+ "data"
319
+ ] as JSONObject;
320
+
321
+ expect(data["project"]).toBeUndefined();
322
+ expect(data["projectId"]).toBe(fixture.projectId);
323
+ });
324
+
325
+ test("routes a missing query to the error port without crashing", async () => {
326
+ const service: DatabaseService<Monitor> = makeMonitorService();
327
+ const updateOneBy: jest.Mock = jest
328
+ .spyOn(service, "updateOneBy")
329
+ .mockResolvedValue(1 as never) as unknown as jest.Mock;
330
+
331
+ const fixture: OptionsFixture = makeOptions();
332
+ const component: UpdateOneBaseModel<Monitor> =
333
+ new UpdateOneBaseModel<Monitor>(service);
334
+
335
+ const result: RunReturnType = await component.run(
336
+ { data: { isEnabled: true } },
337
+ fixture.options,
338
+ );
339
+
340
+ expect(result.executePort?.id).toBe("error");
341
+ expect(updateOneBy).not.toHaveBeenCalled();
342
+ });
343
+ });
344
+
345
+ describe("Update Many", () => {
346
+ test('accepts a query keyed on "id"', async () => {
347
+ const service: DatabaseService<Monitor> = makeMonitorService();
348
+ jest.spyOn(service, "updateBy").mockResolvedValue(2 as never);
349
+
350
+ const fixture: OptionsFixture = makeOptions();
351
+ const component: UpdateManyBaseModel<Monitor> =
352
+ new UpdateManyBaseModel<Monitor>(service);
353
+
354
+ const result: RunReturnType = await component.run(
355
+ { query: { id: MONITOR_ID }, data: { isEnabled: true } },
356
+ fixture.options,
357
+ );
358
+
359
+ const query: JSONObject = firstCallArgument(service.updateBy)[
360
+ "query"
361
+ ] as JSONObject;
362
+
363
+ expect(result.executePort?.id).toBe("success");
364
+ expect(query["_id"]).toBe(MONITOR_ID);
365
+ expect(query["id"]).toBeUndefined();
366
+ });
367
+
368
+ test("scopes the query to the running project", async () => {
369
+ /*
370
+ * Regression test. The tenant column was written to args["query"] after
371
+ * JSONFunctions.deserialize had already copied it into a new object, so
372
+ * the query that reached the database carried no projectId - and an update
373
+ * running as root is not re-scoped by the permission layer, which put rows
374
+ * in other projects in reach of a broad Update Many.
375
+ */
376
+ const service: DatabaseService<Monitor> = makeMonitorService();
377
+ jest.spyOn(service, "updateBy").mockResolvedValue(2 as never);
378
+
379
+ const fixture: OptionsFixture = makeOptions();
380
+ const component: UpdateManyBaseModel<Monitor> =
381
+ new UpdateManyBaseModel<Monitor>(service);
382
+
383
+ await component.run(
384
+ { query: { monitorType: "Website" }, data: { isEnabled: true } },
385
+ fixture.options,
386
+ );
387
+
388
+ const query: JSONObject = firstCallArgument(service.updateBy)[
389
+ "query"
390
+ ] as JSONObject;
391
+
392
+ expect(query["projectId"]).toBe(fixture.projectId);
393
+ expect(query["monitorType"]).toBe("Website");
394
+ });
395
+
396
+ test("cannot move records into another project via the project relation", async () => {
397
+ const service: DatabaseService<Monitor> = makeMonitorService();
398
+ jest.spyOn(service, "updateBy").mockResolvedValue(2 as never);
399
+
400
+ const fixture: OptionsFixture = makeOptions();
401
+ const component: UpdateManyBaseModel<Monitor> =
402
+ new UpdateManyBaseModel<Monitor>(service);
403
+
404
+ await component.run(
405
+ {
406
+ query: { monitorType: "Website" },
407
+ data: { project: "11111111-1111-1111-1111-111111111111" },
408
+ },
409
+ fixture.options,
410
+ );
411
+
412
+ const data: JSONObject = firstCallArgument(service.updateBy)[
413
+ "data"
414
+ ] as JSONObject;
415
+
416
+ expect(data["project"]).toBeUndefined();
417
+ expect(data["projectId"]).toBe(fixture.projectId);
418
+ });
419
+
420
+ test("reports how many records it updated", async () => {
421
+ const service: DatabaseService<Monitor> = makeMonitorService();
422
+ jest.spyOn(service, "updateBy").mockResolvedValue(7 as never);
423
+
424
+ const fixture: OptionsFixture = makeOptions();
425
+ const component: UpdateManyBaseModel<Monitor> =
426
+ new UpdateManyBaseModel<Monitor>(service);
427
+
428
+ const result: RunReturnType = await component.run(
429
+ { query: { monitorType: "Website" }, data: { isEnabled: true } },
430
+ fixture.options,
431
+ );
432
+
433
+ expect(result.returnValues["items-updated"]).toBe(7);
434
+ expect(loggedLines(fixture.log)).toContain("Updated 7 Monitor(s).");
435
+ });
436
+ });
437
+
438
+ describe("Delete One", () => {
439
+ test('accepts a query keyed on "id"', async () => {
440
+ const service: DatabaseService<Monitor> = makeMonitorService();
441
+ jest.spyOn(service, "deleteOneBy").mockResolvedValue(1 as never);
442
+
443
+ const fixture: OptionsFixture = makeOptions();
444
+ const component: DeleteOneBaseModel<Monitor> =
445
+ new DeleteOneBaseModel<Monitor>(service);
446
+
447
+ const result: RunReturnType = await component.run(
448
+ { query: { id: MONITOR_ID } },
449
+ fixture.options,
450
+ );
451
+
452
+ const query: JSONObject = firstCallArgument(service.deleteOneBy)[
453
+ "query"
454
+ ] as JSONObject;
455
+
456
+ expect(result.executePort?.id).toBe("success");
457
+ expect(query["_id"]).toBe(MONITOR_ID);
458
+ expect(query["id"]).toBeUndefined();
459
+ });
460
+
461
+ test("scopes the query to the running project", async () => {
462
+ const service: DatabaseService<Monitor> = makeMonitorService();
463
+ jest.spyOn(service, "deleteOneBy").mockResolvedValue(1 as never);
464
+
465
+ const fixture: OptionsFixture = makeOptions();
466
+ const component: DeleteOneBaseModel<Monitor> =
467
+ new DeleteOneBaseModel<Monitor>(service);
468
+
469
+ await component.run({ query: { id: MONITOR_ID } }, fixture.options);
470
+
471
+ const query: JSONObject = firstCallArgument(service.deleteOneBy)[
472
+ "query"
473
+ ] as JSONObject;
474
+
475
+ expect(query["projectId"]).toBe(fixture.projectId);
476
+ });
477
+
478
+ test("reports how many records it deleted", async () => {
479
+ const service: DatabaseService<Monitor> = makeMonitorService();
480
+ jest.spyOn(service, "deleteOneBy").mockResolvedValue(1 as never);
481
+
482
+ const fixture: OptionsFixture = makeOptions();
483
+ const component: DeleteOneBaseModel<Monitor> =
484
+ new DeleteOneBaseModel<Monitor>(service);
485
+
486
+ const result: RunReturnType = await component.run(
487
+ { query: { id: MONITOR_ID } },
488
+ fixture.options,
489
+ );
490
+
491
+ expect(result.returnValues["items-deleted"]).toBe(1);
492
+ expect(loggedLines(fixture.log)).toContain("Deleted 1 Monitor(s).");
493
+ });
494
+ });
495
+
496
+ describe("Delete Many", () => {
497
+ test('accepts a query keyed on "id" and stays scoped to the project', async () => {
498
+ const service: DatabaseService<Monitor> = makeMonitorService();
499
+ jest.spyOn(service, "deleteBy").mockResolvedValue(3 as never);
500
+
501
+ const fixture: OptionsFixture = makeOptions();
502
+ const component: DeleteManyBaseModel<Monitor> =
503
+ new DeleteManyBaseModel<Monitor>(service);
504
+
505
+ const result: RunReturnType = await component.run(
506
+ { query: { id: MONITOR_ID } },
507
+ fixture.options,
508
+ );
509
+
510
+ const query: JSONObject = firstCallArgument(service.deleteBy)[
511
+ "query"
512
+ ] as JSONObject;
513
+
514
+ expect(result.executePort?.id).toBe("success");
515
+ expect(query["_id"]).toBe(MONITOR_ID);
516
+ expect(query["projectId"]).toBe(fixture.projectId);
517
+ expect(result.returnValues["items-deleted"]).toBe(3);
518
+ });
519
+ });
520
+
521
+ describe("Find One", () => {
522
+ test('accepts "id" in both the query and the select', async () => {
523
+ const service: DatabaseService<Monitor> = makeMonitorService();
524
+ jest.spyOn(service, "findOneBy").mockResolvedValue(null as never);
525
+
526
+ const fixture: OptionsFixture = makeOptions();
527
+ const component: FindOneBaseModel<Monitor> = new FindOneBaseModel<Monitor>(
528
+ service,
529
+ );
530
+
531
+ const result: RunReturnType = await component.run(
532
+ { query: { id: MONITOR_ID }, select: { id: true, name: true } },
533
+ fixture.options,
534
+ );
535
+
536
+ const call: JSONObject = firstCallArgument(service.findOneBy);
537
+ const query: JSONObject = call["query"] as JSONObject;
538
+ const select: JSONObject = call["select"] as JSONObject;
539
+
540
+ expect(result.executePort?.id).toBe("success");
541
+ expect(query["_id"]).toBe(MONITOR_ID);
542
+ expect(query["id"]).toBeUndefined();
543
+ expect(select).toEqual({ _id: true, name: true });
544
+ });
545
+
546
+ test("rewrites the alias inside a related record", async () => {
547
+ const service: DatabaseService<Monitor> = makeMonitorService();
548
+ jest.spyOn(service, "findOneBy").mockResolvedValue(null as never);
549
+
550
+ const fixture: OptionsFixture = makeOptions();
551
+ const component: FindOneBaseModel<Monitor> = new FindOneBaseModel<Monitor>(
552
+ service,
553
+ );
554
+
555
+ await component.run(
556
+ {
557
+ query: { _id: MONITOR_ID },
558
+ select: { project: { id: true, name: true } },
559
+ },
560
+ fixture.options,
561
+ );
562
+
563
+ const select: JSONObject = firstCallArgument(service.findOneBy)[
564
+ "select"
565
+ ] as JSONObject;
566
+
567
+ expect(select).toEqual({ project: { _id: true, name: true } });
568
+ });
569
+
570
+ test("scopes the query to the running project", async () => {
571
+ const service: DatabaseService<Monitor> = makeMonitorService();
572
+ jest.spyOn(service, "findOneBy").mockResolvedValue(null as never);
573
+
574
+ const fixture: OptionsFixture = makeOptions();
575
+ const component: FindOneBaseModel<Monitor> = new FindOneBaseModel<Monitor>(
576
+ service,
577
+ );
578
+
579
+ await component.run(
580
+ { query: { id: MONITOR_ID }, select: { _id: true } },
581
+ fixture.options,
582
+ );
583
+
584
+ const query: JSONObject = firstCallArgument(service.findOneBy)[
585
+ "query"
586
+ ] as JSONObject;
587
+
588
+ expect(query["projectId"]).toBe(fixture.projectId);
589
+ });
590
+
591
+ test("explains an unknown column on the error port", async () => {
592
+ const service: DatabaseService<Monitor> = makeMonitorService();
593
+ jest
594
+ .spyOn(service, "findOneBy")
595
+ .mockRejectedValue(
596
+ new Error(
597
+ 'Property "id" was not found in "Monitor". Make sure your query is correct.',
598
+ ) as never,
599
+ );
600
+
601
+ const fixture: OptionsFixture = makeOptions();
602
+ const component: FindOneBaseModel<Monitor> = new FindOneBaseModel<Monitor>(
603
+ service,
604
+ );
605
+
606
+ const result: RunReturnType = await component.run(
607
+ { query: { _id: MONITOR_ID }, select: { _id: true } },
608
+ fixture.options,
609
+ );
610
+
611
+ expect(result.executePort?.id).toBe("error");
612
+ expect(loggedLines(fixture.log)).toContain('Use "_id" instead');
613
+ });
614
+ });
615
+
616
+ describe("Find Many", () => {
617
+ test('accepts "id" in both the query and the select, and stays project scoped', async () => {
618
+ const service: DatabaseService<Monitor> = makeMonitorService();
619
+ jest.spyOn(service, "findBy").mockResolvedValue([] as never);
620
+
621
+ const fixture: OptionsFixture = makeOptions();
622
+ const component: FindManyBaseModel<Monitor> =
623
+ new FindManyBaseModel<Monitor>(service);
624
+
625
+ const result: RunReturnType = await component.run(
626
+ { query: { id: MONITOR_ID }, select: { id: true } },
627
+ fixture.options,
628
+ );
629
+
630
+ const call: JSONObject = firstCallArgument(service.findBy);
631
+ const query: JSONObject = call["query"] as JSONObject;
632
+
633
+ expect(result.executePort?.id).toBe("success");
634
+ expect(query["_id"]).toBe(MONITOR_ID);
635
+ expect(query["projectId"]).toBe(fixture.projectId);
636
+ expect(call["select"]).toEqual({ _id: true });
637
+ });
638
+ });
639
+
640
+ describe("Create One", () => {
641
+ test("creates the record in the project the workflow runs in", async () => {
642
+ const service: DatabaseService<Monitor> = makeMonitorService();
643
+ const created: Monitor = new Monitor();
644
+ created._id = MONITOR_ID;
645
+ jest.spyOn(service, "create").mockResolvedValue(created as never);
646
+
647
+ const fixture: OptionsFixture = makeOptions();
648
+ const component: CreateOneBaseModel<Monitor> =
649
+ new CreateOneBaseModel<Monitor>(service);
650
+
651
+ const result: RunReturnType = await component.run(
652
+ {
653
+ json: {
654
+ name: "new monitor",
655
+ project: "11111111-1111-1111-1111-111111111111",
656
+ },
657
+ },
658
+ fixture.options,
659
+ );
660
+
661
+ const data: Monitor = firstCallArgument(service.create)[
662
+ "data"
663
+ ] as unknown as Monitor;
664
+
665
+ expect(result.executePort?.id).toBe("success");
666
+ expect(data.project).toBeUndefined();
667
+ expect(data.projectId?.toString()).toBe(fixture.projectId.toString());
668
+ });
669
+ });
670
+
671
+ describe("Create Many", () => {
672
+ test("creates every record it was given", async () => {
673
+ const service: DatabaseService<Monitor> = makeMonitorService();
674
+ const created: Monitor = new Monitor();
675
+ created._id = MONITOR_ID;
676
+ jest.spyOn(service, "create").mockResolvedValue(created as never);
677
+
678
+ const fixture: OptionsFixture = makeOptions();
679
+ const component: CreateManyBaseModel<Monitor> =
680
+ new CreateManyBaseModel<Monitor>(service);
681
+
682
+ const result: RunReturnType = await component.run(
683
+ { "json-array": [{ name: "one" }, { name: "two" }] },
684
+ fixture.options,
685
+ );
686
+
687
+ expect(result.executePort?.id).toBe("success");
688
+ expect(service.create).toHaveBeenCalledTimes(2);
689
+ });
690
+
691
+ test("creates every record in the project the workflow runs in", async () => {
692
+ const service: DatabaseService<Monitor> = makeMonitorService();
693
+ const created: Monitor = new Monitor();
694
+ created._id = MONITOR_ID;
695
+ jest.spyOn(service, "create").mockResolvedValue(created as never);
696
+
697
+ const fixture: OptionsFixture = makeOptions();
698
+ const component: CreateManyBaseModel<Monitor> =
699
+ new CreateManyBaseModel<Monitor>(service);
700
+
701
+ await component.run(
702
+ {
703
+ "json-array": [
704
+ { name: "one", project: "11111111-1111-1111-1111-111111111111" },
705
+ ],
706
+ },
707
+ fixture.options,
708
+ );
709
+
710
+ const data: Monitor = firstCallArgument(service.create)[
711
+ "data"
712
+ ] as unknown as Monitor;
713
+
714
+ expect(data.project).toBeUndefined();
715
+ expect(data.projectId?.toString()).toBe(fixture.projectId.toString());
716
+ });
717
+
718
+ test("creates records for a model that has no tenant column", async () => {
719
+ /*
720
+ * Regression test. The create loop used to sit inside the
721
+ * `if (getTenantColumn())` check, so a model without a tenant column
722
+ * created nothing and still reported success.
723
+ */
724
+ const service: DatabaseService<Monitor> = makeMonitorService();
725
+ const created: Monitor = new Monitor();
726
+ created._id = MONITOR_ID;
727
+ jest.spyOn(service, "create").mockResolvedValue(created as never);
728
+ jest.spyOn(service.getModel(), "getTenantColumn").mockReturnValue(null);
729
+
730
+ const fixture: OptionsFixture = makeOptions();
731
+ const component: CreateManyBaseModel<Monitor> =
732
+ new CreateManyBaseModel<Monitor>(service);
733
+
734
+ const result: RunReturnType = await component.run(
735
+ { "json-array": [{ name: "one" }] },
736
+ fixture.options,
737
+ );
738
+
739
+ expect(result.executePort?.id).toBe("success");
740
+ expect(service.create).toHaveBeenCalledTimes(1);
741
+ });
742
+ });