@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
@@ -5,6 +5,27 @@ import Port from "../Port";
5
5
  import Typeof from "../Typeof";
6
6
  import { FindOperator } from "typeorm";
7
7
 
8
+ /*
9
+ * A chain of DNS labels (which also covers IPv4 literals). Labels are
10
+ * alphanumeric plus "-" and "_", may not start or end with "-", and are
11
+ * capped at 63 characters; a single trailing dot (the fully-qualified form)
12
+ * is allowed. "_" is permitted because internal and service-discovery names
13
+ * use it and it is not a URL delimiter.
14
+ */
15
+ const HOST_REGEX: RegExp =
16
+ /^[a-zA-Z0-9_](?:[a-zA-Z0-9_-]{0,61}[a-zA-Z0-9_])?(?:\.[a-zA-Z0-9_](?:[a-zA-Z0-9_-]{0,61}[a-zA-Z0-9_])?)*\.?$/;
17
+
18
+ /*
19
+ * Anything that is not a URL delimiter. The point is not to validate
20
+ * credentials, it is to make sure userinfo cannot smuggle a path, a query, a
21
+ * fragment or a second authority past the host check.
22
+ */
23
+ const USER_INFO_REGEX: RegExp = /^[^@/?#\s[\]]*$/;
24
+
25
+ const IPV6_CHARS_REGEX: RegExp = /^[0-9a-fA-F:.]+$/;
26
+
27
+ const PORT_REGEX: RegExp = /^\d{1,5}$/;
28
+
8
29
  export default class Hostname extends DatabaseProperty {
9
30
  private _route: string = "";
10
31
  public get hostname(): string {
@@ -31,13 +52,80 @@ export default class Hostname extends DatabaseProperty {
31
52
  }
32
53
  }
33
54
 
55
+ /*
56
+ * True when the value is a usable authority: an optional "userinfo@"
57
+ * prefix, a host (DNS name, IPv4, or IPv6 literal) and an optional ":port".
58
+ *
59
+ * The old check was a character allowlist that permitted "/", "?", "#" and
60
+ * "@" anywhere, which made "169.254.169.254/latest/meta-data/#" a valid
61
+ * Hostname. Anything that stores a Hostname and later interpolates it into
62
+ * a URL therefore inherited full control of the host, port and path of the
63
+ * resulting request. Structure, not a charset, is what rules that out.
64
+ *
65
+ * Userinfo is still accepted because "https://user:token@host/path" is a
66
+ * real thing customers put in webhook URLs, and those values are already in
67
+ * the database — rejecting them here would fail on read, not just on write.
68
+ * Callers that need the bare host must not split this string themselves;
69
+ * SSRFProtection.getBareHostname exists for that.
70
+ */
34
71
  public static isValid(value: string): boolean {
35
- const re: RegExp = /^[a-zA-Z-\d!#$&'*+,/:;=?@[\].]*$/;
36
- const isValid: boolean = re.test(value);
37
- if (!isValid) {
72
+ const authorityWithUserInfo: string = value.trim();
73
+
74
+ /*
75
+ * 253 for a DNS name, plus room for ":65535" and a userinfo prefix.
76
+ * A bound here also keeps the label regex from being handed something
77
+ * pathological.
78
+ */
79
+ if (!authorityWithUserInfo || authorityWithUserInfo.length > 512) {
80
+ return false;
81
+ }
82
+
83
+ /*
84
+ * Split on the LAST "@": userinfo may itself contain "@" percent-encoded
85
+ * or not, and everything after the final one is the authority.
86
+ */
87
+ const atIndex: number = authorityWithUserInfo.lastIndexOf("@");
88
+
89
+ if (atIndex !== -1) {
90
+ const userInfo: string = authorityWithUserInfo.substring(0, atIndex);
91
+ if (!USER_INFO_REGEX.test(userInfo)) {
92
+ return false;
93
+ }
94
+ }
95
+
96
+ const authority: string = authorityWithUserInfo.substring(atIndex + 1);
97
+
98
+ if (!authority) {
38
99
  return false;
39
100
  }
40
- return true;
101
+
102
+ // Bracketed IPv6, with or without a port: "[::1]", "[::1]:8080".
103
+ const bracketedIpv6Match: RegExpMatchArray | null = authority.match(
104
+ /^\[([0-9a-fA-F:.]+)\](?::(\d{1,5}))?$/,
105
+ );
106
+ if (bracketedIpv6Match) {
107
+ return true;
108
+ }
109
+
110
+ /*
111
+ * Unbracketed IPv6 literal. Two or more colons cannot be a "host:port",
112
+ * so the colons must be part of the address itself.
113
+ */
114
+ if ((authority.match(/:/g) || []).length > 1) {
115
+ return IPV6_CHARS_REGEX.test(authority);
116
+ }
117
+
118
+ const colonIndex: number = authority.indexOf(":");
119
+ const host: string =
120
+ colonIndex === -1 ? authority : authority.substring(0, colonIndex);
121
+ const port: string =
122
+ colonIndex === -1 ? "" : authority.substring(colonIndex + 1);
123
+
124
+ if (colonIndex !== -1 && !PORT_REGEX.test(port)) {
125
+ return false;
126
+ }
127
+
128
+ return HOST_REGEX.test(host);
41
129
  }
42
130
 
43
131
  public constructor(hostname: string, port?: Port | string | number) {
package/Types/API/URL.ts CHANGED
@@ -131,37 +131,55 @@ export default class URL extends DatabaseProperty {
131
131
  public static fromString(url: string): URL {
132
132
  let protocol: Protocol = Protocol.HTTPS;
133
133
 
134
- if (url.startsWith("https://")) {
135
- protocol = Protocol.HTTPS;
136
- url = url.replace("https://", "");
137
- }
138
-
139
- if (url.startsWith("http://")) {
140
- protocol = Protocol.HTTP;
141
- url = url.replace("http://", "");
142
- }
143
-
144
- if (url.startsWith("wss://")) {
145
- protocol = Protocol.WSS;
146
- url = url.replace("wss://", "");
134
+ /*
135
+ * Schemes are case-insensitive (RFC 3986), so match on a lower-cased
136
+ * copy and strip by length. Matching the literal prefix left "HTTPS://"
137
+ * in place, which then read as an authority of "HTTPS:".
138
+ *
139
+ * Longest-first: "https://" has to be tested before "http://", and only
140
+ * the first match is stripped.
141
+ */
142
+ const schemePrefixes: Array<[string, Protocol]> = [
143
+ ["https://", Protocol.HTTPS],
144
+ ["http://", Protocol.HTTP],
145
+ ["wss://", Protocol.WSS],
146
+ ["ws://", Protocol.WS],
147
+ ["mongodb://", Protocol.MONGO_DB],
148
+ ["mailto:", Protocol.MAIL],
149
+ ];
150
+
151
+ const lowerCasedUrl: string = url.toLowerCase();
152
+
153
+ for (const [prefix, prefixProtocol] of schemePrefixes) {
154
+ if (lowerCasedUrl.startsWith(prefix)) {
155
+ protocol = prefixProtocol;
156
+ url = url.substring(prefix.length);
157
+ break;
158
+ }
147
159
  }
148
160
 
149
- if (url.startsWith("ws://")) {
150
- protocol = Protocol.WS;
151
- url = url.replace("ws://", "");
152
- }
161
+ if (protocol === Protocol.MAIL) {
162
+ /*
163
+ * Hand the bare address to the constructor so it is recognised as an
164
+ * Email. Routing it through Hostname instead would ask a host validator
165
+ * to accept an email address — and "?subject=..." along with it.
166
+ */
167
+ const address: string = url.split("?")[0] || "";
168
+ const mailQueryString: string = url.split("?")[1] || "";
153
169
 
154
- if (url.startsWith("mongodb://")) {
155
- protocol = Protocol.MONGO_DB;
156
- url = url.replace("mongodb://", "");
170
+ return new URL(protocol, address, undefined, mailQueryString);
157
171
  }
158
172
 
159
- if (url.startsWith("mailto:")) {
160
- protocol = Protocol.MAIL;
161
- url = url.replace("mailto:", "");
162
- }
173
+ /*
174
+ * The authority ends at the first "/", "?" or "#". Splitting on "/" alone
175
+ * left the query and fragment glued to the host for URLs with no path
176
+ * ("https://host?token=x" parsed to a host of "host?token=x"), which both
177
+ * round-tripped wrong and handed anything that later interpolated the
178
+ * host a way to smuggle a path.
179
+ */
180
+ const authority: string = (url.split("/")[0] || "").split(/[?#]/)[0] || "";
163
181
 
164
- const hostname: Hostname = new Hostname(url.split("/")[0] || "");
182
+ const hostname: Hostname = new Hostname(authority);
165
183
 
166
184
  let route: Route | undefined;
167
185
 
@@ -0,0 +1,14 @@
1
+ /*
2
+ * How a manual balance adjustment is applied. Add and Deduct are relative and
3
+ * land as a single atomic SQL delta, so they cannot lose a usage charge that
4
+ * is being written at the same moment. Set is absolute - last writer wins -
5
+ * and is only there for the case where staff need the balance to read a
6
+ * specific number regardless of what it holds now.
7
+ */
8
+ enum BalanceAdjustmentType {
9
+ Add = "Add",
10
+ Deduct = "Deduct",
11
+ Set = "Set",
12
+ }
13
+
14
+ export default BalanceAdjustmentType;
@@ -0,0 +1,13 @@
1
+ /*
2
+ * The prepaid balances a project carries. Each one maps to its own column on
3
+ * the project and is drawn down by a different kind of usage, so they are
4
+ * topped up and corrected independently.
5
+ */
6
+ enum ProjectBalanceType {
7
+ // Drawn down by SMS, voice calls, WhatsApp messages and incoming numbers.
8
+ SmsOrCall = "SmsOrCall",
9
+ // Drawn down by LLM spend - AI agents, investigations and code fixes.
10
+ AI = "AI",
11
+ }
12
+
13
+ export default ProjectBalanceType;
package/Types/Domain.ts CHANGED
@@ -67,6 +67,32 @@ export default class Domain extends DatabaseProperty {
67
67
  return domainRegex.test(domain);
68
68
  }
69
69
 
70
+ /**
71
+ * Validates a subdomain: one or more DNS labels, no scheme, no port, no
72
+ * path, no userinfo.
73
+ *
74
+ * This is a security control, not a nicety. A subdomain is concatenated
75
+ * with a verified base domain to build fullDomain, and fullDomain is
76
+ * interpolated into a URL that the certificate-provisioning cron fetches
77
+ * unattended. URL parsing takes everything before the first "/" as the
78
+ * host, so a subdomain of "169.254.169.254/latest/meta-data/#" yields a URL
79
+ * whose host, port and path are all attacker-chosen. Restricting the value
80
+ * to DNS labels removes the ability to smuggle any of those.
81
+ *
82
+ * The empty string is NOT valid here: callers use "" (or "@") to mean the
83
+ * apex and must check for that before calling.
84
+ */
85
+ public static isValidSubdomain(subdomain: string): boolean {
86
+ if (!subdomain || subdomain.length > 253) {
87
+ return false;
88
+ }
89
+
90
+ const subdomainRegex: RegExp =
91
+ /^[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
92
+
93
+ return subdomainRegex.test(subdomain);
94
+ }
95
+
70
96
  public constructor(domain: string) {
71
97
  super();
72
98
  this.domain = domain;
@@ -8,6 +8,17 @@ enum MimeType {
8
8
  svg = "image/svg+xml",
9
9
  gif = "image/gif",
10
10
  webp = "image/webp",
11
+ /*
12
+ * Raster formats a browser or an API client can legitimately report but the
13
+ * file picker never names. Listed so those uploads are not rejected outright
14
+ * now that FileService validates fileType against this enum, and so rows
15
+ * written before the picker normalised types are still servable.
16
+ */
17
+ ico = "image/x-icon",
18
+ bmp = "image/bmp",
19
+ tiff = "image/tiff",
20
+ avif = "image/avif",
21
+ heic = "image/heic",
11
22
  pdf = "application/pdf",
12
23
  doc = "application/msword",
13
24
  docx = "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
@@ -297,6 +297,21 @@ export default class JSONFunctions {
297
297
  Object.keys(ObjectType).includes((val as JSONObject)["_type"] as string)
298
298
  ) {
299
299
  return val;
300
+ } else if (Array.isArray(val)) {
301
+ /*
302
+ * This has to be checked before the plain-object branch below: arrays are
303
+ * typeof "object", so falling through to serialize() would walk them by
304
+ * key and hand back { "0": ..., "1": ... } instead of an array. That
305
+ * silently corrupts every nested array persisted into a JSON column —
306
+ * e.g. the [facetKey, value] filter tuples of a telemetry saved view.
307
+ */
308
+ const arr: Array<JSONValue> = [];
309
+
310
+ for (const v of val) {
311
+ arr.push(this.serializeValue(v));
312
+ }
313
+
314
+ return arr;
300
315
  } else if (typeof val === Typeof.Object) {
301
316
  return this.serialize(val as JSONObject);
302
317
  }
@@ -19,7 +19,15 @@ export interface TelemetrySavedViewTimeRange {
19
19
  export default interface TelemetrySavedViewState {
20
20
  // Submitted search string from the explorer search bar.
21
21
  search?: string | undefined;
22
- // Active facet filters as [facetKey, value] tuples.
22
+ /*
23
+ * Active facet filters as [facetKey, value] tuples.
24
+ *
25
+ * Read these with readSavedViewFilters (Common/Utils/Telemetry/
26
+ * SavedViewFilters) rather than destructuring them. Rows written before
27
+ * JSONFunctions.serializeValue learned to preserve nested arrays hold
28
+ * { "0": facetKey, "1": value } instead, and destructuring one of those
29
+ * throws — which is what this type asserting otherwise once cost us.
30
+ */
23
31
  filters?: Array<[string, string]> | undefined;
24
32
  // Selected time range.
25
33
  timeRange?: TelemetrySavedViewTimeRange | undefined;
@@ -1,4 +1,5 @@
1
1
  import BaseModel from "../../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
2
+ import Route from "../../API/Route";
2
3
  import IconProp from "../../Icon/IconProp";
3
4
  import Text from "../../Text";
4
5
  import ComponentMetadata, {
@@ -14,6 +15,29 @@ export default class BaseModelComponent {
14
15
  return [];
15
16
  }
16
17
 
18
+ /*
19
+ * Every one of these arguments is keyed on column names, and the single
20
+ * most common way to get one wrong is to write "id" - which is what an ID
21
+ * is called everywhere else in the product - when the column is "_id".
22
+ * Both spellings work now, but the hint has to say so where the builder is
23
+ * actually typing, because the Query argument is a bare JSON editor with
24
+ * no field picker behind it.
25
+ */
26
+ const columnHint: string = `Keys are column names on ${model.singularName}. The ID column is "_id" (the "id" spelling is accepted too).`;
27
+
28
+ const queryDescription: string = `Query that selects which ${model.pluralName} this component acts on. ${columnHint}`;
29
+
30
+ const queryPlaceholder: string =
31
+ 'Example: {"_id": "00000000-0000-0000-0000-000000000000"}';
32
+
33
+ const selectPlaceholder: string = 'Example: {"_id": true, "name": true}';
34
+
35
+ const dataDescription: string = `${model.singularName} fields to write, as a JSON object. ${columnHint}`;
36
+
37
+ const documentationLink: Route = Route.fromString(
38
+ "/workflow/docs/DatabaseComponents.md",
39
+ );
40
+
17
41
  if (model.enableWorkflowOn.read) {
18
42
  components.push({
19
43
  id: `${Text.pascalCaseToDashes(model.tableName!)}-find-one`,
@@ -23,22 +47,23 @@ export default class BaseModelComponent {
23
47
  iconProp: IconProp.ArrowCircleDown,
24
48
  tableName: model.tableName!,
25
49
  componentType: ComponentType.Component,
50
+ documentationLink: documentationLink,
26
51
  arguments: [
27
52
  {
28
53
  type: ComponentInputType.Query,
29
54
  name: "Query",
30
- description: `Query on ${model.singularName}`,
55
+ description: queryDescription,
31
56
  required: true,
32
57
  id: "query",
33
- placeholder: 'Example: {"columnName": "value", ...}',
58
+ placeholder: queryPlaceholder,
34
59
  },
35
60
  {
36
61
  type: ComponentInputType.Select,
37
62
  name: "Select Fields",
38
- description: `Select on ${model.singularName}`,
63
+ description: `Fields to read from ${model.singularName}. ${columnHint}`,
39
64
  required: true,
40
65
  id: "select",
41
- placeholder: 'Example: {"columnName": true, ...}',
66
+ placeholder: selectPlaceholder,
42
67
  },
43
68
  ],
44
69
  returnValues: [
@@ -82,22 +107,23 @@ export default class BaseModelComponent {
82
107
  iconProp: IconProp.ArrowCircleDown,
83
108
  tableName: model.tableName!,
84
109
  componentType: ComponentType.Component,
110
+ documentationLink: documentationLink,
85
111
  arguments: [
86
112
  {
87
113
  type: ComponentInputType.Query,
88
114
  name: "Query",
89
- description: "Please fill out this query",
115
+ description: queryDescription,
90
116
  required: true,
91
117
  id: "query",
92
- placeholder: 'Example: {"columnName": "value", ...}',
118
+ placeholder: queryPlaceholder,
93
119
  },
94
120
  {
95
121
  type: ComponentInputType.Select,
96
122
  name: "Select Fields",
97
- description: `Select on ${model.singularName}`,
123
+ description: `Fields to read from ${model.singularName}. ${columnHint}`,
98
124
  required: true,
99
125
  id: "select",
100
- placeholder: 'Example: {"columnName": true, ...}',
126
+ placeholder: selectPlaceholder,
101
127
  },
102
128
  {
103
129
  type: ComponentInputType.Number,
@@ -196,17 +222,26 @@ export default class BaseModelComponent {
196
222
  iconProp: IconProp.Trash,
197
223
  tableName: model.tableName!,
198
224
  componentType: ComponentType.Component,
225
+ documentationLink: documentationLink,
199
226
  arguments: [
200
227
  {
201
228
  type: ComponentInputType.Query,
202
229
  name: "Delete by",
203
- description: "Please fill out this query",
230
+ description: queryDescription,
204
231
  required: true,
205
232
  id: "query",
206
- placeholder: 'Example: {"columnName": "value", ...}',
233
+ placeholder: queryPlaceholder,
234
+ },
235
+ ],
236
+ returnValues: [
237
+ {
238
+ id: "items-deleted",
239
+ name: "Items Deleted",
240
+ description: `How many ${model.pluralName} the query matched and deleted. Zero is not an error - it means nothing matched.`,
241
+ type: ComponentInputType.Number,
242
+ required: false,
207
243
  },
208
244
  ],
209
- returnValues: [],
210
245
  inPorts: [
211
246
  {
212
247
  title: "In",
@@ -239,14 +274,15 @@ export default class BaseModelComponent {
239
274
  iconProp: IconProp.Trash,
240
275
  tableName: model.tableName!,
241
276
  componentType: ComponentType.Component,
277
+ documentationLink: documentationLink,
242
278
  arguments: [
243
279
  {
244
280
  type: ComponentInputType.Query,
245
281
  name: "Delete by",
246
- description: "Please fill out this query",
282
+ description: queryDescription,
247
283
  required: true,
248
284
  id: "query",
249
- placeholder: 'Example: {"columnName": "value", ...}',
285
+ placeholder: queryPlaceholder,
250
286
  },
251
287
  {
252
288
  type: ComponentInputType.Number,
@@ -263,7 +299,15 @@ export default class BaseModelComponent {
263
299
  id: "limit",
264
300
  },
265
301
  ],
266
- returnValues: [],
302
+ returnValues: [
303
+ {
304
+ id: "items-deleted",
305
+ name: "Items Deleted",
306
+ description: `How many ${model.pluralName} the query matched and deleted. Zero is not an error - it means nothing matched.`,
307
+ type: ComponentInputType.Number,
308
+ required: false,
309
+ },
310
+ ],
267
311
  inPorts: [
268
312
  {
269
313
  title: "In",
@@ -312,10 +356,10 @@ export default class BaseModelComponent {
312
356
  {
313
357
  type: ComponentInputType.Select,
314
358
  name: "Select Fields",
315
- description: `Select on ${model.singularName}`,
359
+ description: `Fields to read from ${model.singularName}. ${columnHint}`,
316
360
  required: true,
317
361
  id: "select",
318
- placeholder: 'Example: {"columnName": true, ...}',
362
+ placeholder: selectPlaceholder,
319
363
  },
320
364
  ],
321
365
  returnValues: [
@@ -346,12 +390,13 @@ export default class BaseModelComponent {
346
390
  iconProp: IconProp.Database,
347
391
  tableName: model.tableName!,
348
392
  componentType: ComponentType.Component,
393
+ documentationLink: documentationLink,
349
394
  arguments: [
350
395
  {
351
396
  id: "json",
352
397
  placeholder: 'Example: {"columnName": "value", ...}',
353
398
  name: "JSON Object",
354
- description: `${model.singularName} represented as JSON`,
399
+ description: `${model.singularName} represented as JSON. ${columnHint}`,
355
400
  type: ComponentInputType.JSON,
356
401
  required: true,
357
402
  },
@@ -397,12 +442,13 @@ export default class BaseModelComponent {
397
442
  iconProp: IconProp.Database,
398
443
  tableName: model.tableName!,
399
444
  componentType: ComponentType.Component,
445
+ documentationLink: documentationLink,
400
446
  arguments: [
401
447
  {
402
448
  id: "json-array",
403
449
  name: "JSON Array",
404
450
  placeholder: 'Example: [{"columnName": "value", ...}, {...}]',
405
- description: "List of models represented as JSON array",
451
+ description: `List of ${model.pluralName} represented as a JSON array. ${columnHint}`,
406
452
  type: ComponentInputType.JSONArray,
407
453
  required: true,
408
454
  },
@@ -472,10 +518,10 @@ export default class BaseModelComponent {
472
518
  {
473
519
  type: ComponentInputType.Select,
474
520
  name: "Select Fields",
475
- description: `Select on ${model.singularName}`,
521
+ description: `Fields to read from ${model.singularName}. ${columnHint}`,
476
522
  required: true,
477
523
  id: "select",
478
- placeholder: 'Example: {"columnName": true, ...}',
524
+ placeholder: selectPlaceholder,
479
525
  },
480
526
  ],
481
527
  returnValues: [
@@ -505,25 +551,34 @@ export default class BaseModelComponent {
505
551
  iconProp: IconProp.ArrowCircleUp,
506
552
  tableName: model.tableName!,
507
553
  componentType: ComponentType.Component,
554
+ documentationLink: documentationLink,
508
555
  arguments: [
509
556
  {
510
557
  type: ComponentInputType.Query,
511
558
  name: "Query",
512
- description: "Please fill out this query",
559
+ description: queryDescription,
513
560
  required: true,
514
561
  id: "query",
515
- placeholder: 'Example: {"columnName": "value", ...}',
562
+ placeholder: queryPlaceholder,
516
563
  },
517
564
  {
518
565
  id: "data",
519
566
  placeholder: 'Example: {"columnName": "value", ...}',
520
567
  name: "Data (JSON Object)",
521
- description: `${model.singularName} represented as JSON`,
568
+ description: dataDescription,
522
569
  type: ComponentInputType.JSON,
523
570
  required: true,
524
571
  },
525
572
  ],
526
- returnValues: [],
573
+ returnValues: [
574
+ {
575
+ id: "items-updated",
576
+ name: "Items Updated",
577
+ description: `How many ${model.pluralName} the query matched and updated. Zero is not an error - it means nothing matched.`,
578
+ type: ComponentInputType.Number,
579
+ required: false,
580
+ },
581
+ ],
527
582
  inPorts: [
528
583
  {
529
584
  title: "In",
@@ -556,20 +611,21 @@ export default class BaseModelComponent {
556
611
  iconProp: IconProp.ArrowCircleUp,
557
612
  tableName: model.tableName!,
558
613
  componentType: ComponentType.Component,
614
+ documentationLink: documentationLink,
559
615
  arguments: [
560
616
  {
561
617
  type: ComponentInputType.Query,
562
618
  name: "Query",
563
- description: "Please fill out this query",
619
+ description: queryDescription,
564
620
  required: true,
565
621
  id: "query",
566
- placeholder: 'Example: {"columnName": "value", ...}',
622
+ placeholder: queryPlaceholder,
567
623
  },
568
624
  {
569
625
  id: "data",
570
626
  name: "Data (JSON Object)",
571
627
  placeholder: 'Example: {"columnName": "value", ...}',
572
- description: `${model.singularName} represented as JSON`,
628
+ description: dataDescription,
573
629
  type: ComponentInputType.JSON,
574
630
  required: true,
575
631
  },
@@ -588,7 +644,15 @@ export default class BaseModelComponent {
588
644
  id: "limit",
589
645
  },
590
646
  ],
591
- returnValues: [],
647
+ returnValues: [
648
+ {
649
+ id: "items-updated",
650
+ name: "Items Updated",
651
+ description: `How many ${model.pluralName} the query matched and updated. Zero is not an error - it means nothing matched.`,
652
+ type: ComponentInputType.Number,
653
+ required: false,
654
+ },
655
+ ],
592
656
  inPorts: [
593
657
  {
594
658
  title: "In",
@@ -1,3 +1,15 @@
1
1
  declare module "*.png";
2
2
  declare module "*.jpg";
3
3
  declare module "*.gif";
4
+
5
+ /*
6
+ * i18next-browser-languagedetector is an App-only browser dependency that a
7
+ * few Common tests reach through imported App/FeatureSet sources (e.g. the
8
+ * StatusPage detail pages via their Utils/i18n). It is not installed in
9
+ * Common/node_modules — Common's jest moduleNameMapper mocks it at runtime —
10
+ * so the type checker has nothing to resolve when it compiles those App files
11
+ * from within the Common Test job (which installs Common alone). This ambient
12
+ * shim gives the type checker an `any` module so the suite compiles; the mock
13
+ * supplies the behaviour at runtime.
14
+ */
15
+ declare module "i18next-browser-languagedetector";
@@ -36,9 +36,10 @@ const ChartContainer: FunctionComponent<ComponentProps> = (
36
36
  /*
37
37
  * `isolate` creates a new stacking context so the chart's internal
38
38
  * z-indexes (e.g. a highlighted/matched bar uses z-30, see Bar/Index.tsx)
39
- * stay trapped inside the chart. Without it those bars paint above
40
- * page-level overlays like the span-details SideOver (z-10), making a
41
- * matched span "show above" the sidebar.
39
+ * stay trapped inside the chart. Without it those bars compete directly
40
+ * with page-level overlays such as the span-details SideOver (z-30, and
41
+ * portalled to the end of <body>), and a matched span would "show above"
42
+ * the sidebar.
42
43
  */
43
44
  <div ref={divRef} className={"w-full"} style={{ isolation: "isolate" }}>
44
45
  {props.children}
@@ -15,6 +15,8 @@ export interface ComponentProps {
15
15
  isLoading?: boolean;
16
16
  error?: string | undefined;
17
17
  disableSubmitButton?: boolean | undefined;
18
+ // Rendered under the description - for confirmations that also ask something.
19
+ children?: ReactElement | undefined;
18
20
  }
19
21
 
20
22
  const ConfirmModal: FunctionComponent<ComponentProps> = (
@@ -51,11 +53,14 @@ const ConfirmModal: FunctionComponent<ComponentProps> = (
51
53
  * a long confirmation two nested scrollbars, and the inner one clipped
52
54
  * the text well short of the space the modal had spare.
53
55
  */}
54
- <div
55
- data-testid="confirm-modal-description"
56
- className="whitespace-pre-wrap break-words text-sm leading-6 text-gray-600"
57
- >
58
- {translatedDescription}
56
+ <div>
57
+ <div
58
+ data-testid="confirm-modal-description"
59
+ className="whitespace-pre-wrap break-words text-sm leading-6 text-gray-600"
60
+ >
61
+ {translatedDescription}
62
+ </div>
63
+ {props.children ? <div className="mt-4">{props.children}</div> : <></>}
59
64
  </div>
60
65
  </Modal>
61
66
  );