@oneuptime/common 12.0.9 → 12.0.11

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 (262) hide show
  1. package/Models/DatabaseModels/NetworkDevice.ts +44 -0
  2. package/Models/DatabaseModels/NetworkDeviceLink.ts +116 -0
  3. package/Models/DatabaseModels/RunnerJob.ts +17 -2
  4. package/Server/API/LlmProviderAPI.ts +8 -0
  5. package/Server/Infrastructure/Postgres/SchemaMigrations/1787400000000-AddDeviceRoleAndDeclaredLinkParent.ts +52 -0
  6. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
  7. package/Server/Services/NetworkDeviceLabelRuleEngineService.ts +240 -0
  8. package/Server/Services/NetworkDeviceLinkService.ts +338 -2
  9. package/Server/Services/NetworkDeviceService.ts +265 -12
  10. package/Server/Services/RunnerJobService.ts +24 -1
  11. package/Server/Types/Billing/MeteredPlan/AllMeteredPlans.ts +19 -5
  12. package/Server/Types/Database/JSONColumnQuery.ts +42 -4
  13. package/Server/Utils/LLM/LLMService.ts +108 -19
  14. package/Server/Utils/Monitor/MonitorAlert.ts +22 -115
  15. package/Server/Utils/Monitor/MonitorIncident.ts +7 -337
  16. package/Server/Utils/Monitor/MonitorMaintenanceSuppression.ts +27 -2
  17. package/Server/Utils/Monitor/SeriesResourceLabels.ts +32 -0
  18. package/Server/Utils/Monitor/SeriesResourceLinker.ts +469 -0
  19. package/Server/Utils/SSRFProtection.ts +5 -4
  20. package/Server/Utils/Telemetry/InventoryEntityRegistry.ts +186 -38
  21. package/Tests/App/AdminDashboard/AdminUsersBulkAddToProject.test.tsx +955 -0
  22. package/Tests/App/AdminDashboard/BulkAddUsersToProject.test.ts +778 -0
  23. package/Tests/App/AdminDashboard/BulkAddUsersToProjectModal.test.tsx +1051 -0
  24. package/Tests/App/Dashboard/AdminNotificationRulesPage.test.tsx +420 -112
  25. package/Tests/App/Dashboard/OnCallReadinessSurfaces.test.tsx +81 -6
  26. package/Tests/App/Dashboard/PayAsYouGoConsentGate.test.tsx +543 -0
  27. package/Tests/App/Dashboard/PayAsYouGoFreePlan.test.ts +125 -0
  28. package/Tests/App/Dashboard/PayAsYouGoNotices.test.tsx +612 -0
  29. package/Tests/App/Dashboard/SloWidgetChartRendering.test.tsx +536 -0
  30. package/Tests/App/Dashboard/UserElementEmail.test.tsx +447 -0
  31. package/Tests/App/Dashboard/UserEmailCallSites.test.tsx +284 -0
  32. package/Tests/Models/AnalyticsModels/CommonModel.test.ts +312 -0
  33. package/Tests/Server/Infrastructure/Postgres/DeviceRoleAndDeclaredLinkParentMigration.test.ts +250 -0
  34. package/Tests/Server/Infrastructure/Postgres/EpisodeMemberNotifyIndexesMigration.test.ts +46 -18
  35. package/Tests/Server/Services/NetworkDeviceLabelRuleRun.test.ts +618 -0
  36. package/Tests/Server/Services/NetworkDeviceLinkParentValidation.test.ts +1043 -0
  37. package/Tests/Server/Services/NetworkSiteAssignmentRuleRun.test.ts +706 -0
  38. package/Tests/Server/Services/RunnerJobEnqueue.test.ts +412 -0
  39. package/Tests/Server/Types/Billing/PayAsYouGoMeteredPricing.test.ts +125 -0
  40. package/Tests/Server/Types/Database/JSONColumnQuery.test.ts +508 -0
  41. package/Tests/Server/Utils/AI/LLMServiceRequestPolicy.test.ts +2 -2
  42. package/Tests/Server/Utils/AI/LLMServiceRetryPolicy.test.ts +450 -0
  43. package/Tests/Server/Utils/Monitor/MonitorAlertResourceLinking.test.ts +556 -0
  44. package/Tests/Server/Utils/Monitor/MonitorIncidentResourceLinking.test.ts +547 -0
  45. package/Tests/Server/Utils/Monitor/MonitorMaintenanceSuppression.test.ts +30 -0
  46. package/Tests/Server/Utils/Monitor/SeriesResourceLinker.test.ts +699 -0
  47. package/Tests/Server/Utils/SeriesResourceLabels.test.ts +55 -0
  48. package/Tests/Server/Utils/Telemetry/InventoryEntityRegistry.test.ts +668 -0
  49. package/Tests/Types/API/URLMalformedTolerance.test.ts +301 -0
  50. package/Tests/Types/API/URLTelScheme.test.ts +261 -0
  51. package/Tests/Types/API/URLUnsupportedScheme.test.ts +148 -0
  52. package/Tests/Types/Billing/PayAsYouGoPricing.test.ts +64 -0
  53. package/Tests/Types/CustomField/CustomFieldTypeCorrespondence.test.ts +107 -0
  54. package/Tests/Types/Monitor/MonitorType.test.ts +62 -0
  55. package/Tests/Types/NetworkAutomation/RuleRunResult.test.ts +184 -0
  56. package/Tests/Types/Runbook/RunbookStepType.test.ts +124 -0
  57. package/Tests/Types/Workflow/BaseModelComponents.test.ts +17 -0
  58. package/Tests/UI/Components/Button.test.tsx +279 -0
  59. package/Tests/UI/Components/Charts/ChartXAxisDataKey.test.tsx +256 -0
  60. package/Tests/UI/Components/Charts/DataPointUtil.test.ts +323 -0
  61. package/Tests/UI/Components/DictionaryValuePlaceholderAndSuggestions.test.tsx +595 -0
  62. package/Tests/UI/Components/Icon.test.tsx +57 -0
  63. package/Tests/UI/Components/List.test.tsx +20 -3
  64. package/Tests/UI/Components/LogsSavedViewsDropdown.test.tsx +304 -0
  65. package/Tests/UI/Components/LogsViewerClearSavedView.test.tsx +179 -0
  66. package/Tests/UI/Components/ModelTable/CustomFieldColumns.test.tsx +349 -1
  67. package/Tests/UI/Components/Pagination.test.tsx +721 -146
  68. package/Tests/UI/Components/PaginationIntegration.test.tsx +386 -0
  69. package/Tests/UI/Components/PaginationUtil.test.ts +417 -0
  70. package/Tests/UI/Components/TelemetrySavedViewsDropdown.test.tsx +343 -0
  71. package/Tests/UI/Components/Workflow/ColumnEditor/ColumnControl.test.ts +289 -0
  72. package/Tests/UI/Components/Workflow/ColumnEditor/ColumnOperators.test.ts +271 -0
  73. package/Tests/UI/Components/Workflow/ColumnEditor/ColumnRow.test.ts +119 -0
  74. package/Tests/UI/Components/Workflow/ColumnEditor/ColumnRowSerialization.test.ts +968 -0
  75. package/Tests/UI/Components/Workflow/ModelColumnEditor.render.test.tsx +766 -0
  76. package/Tests/UI/Utils/RunNetworkRule.test.ts +320 -0
  77. package/Tests/Utils/APIRetryPolicy.test.ts +823 -0
  78. package/Tests/Utils/Monitor/NetworkDeviceRoleUtil.test.ts +502 -0
  79. package/Tests/Utils/Monitor/NetworkTopologyDeclaredHierarchy.test.ts +759 -0
  80. package/Tests/Utils/NetworkAutomation/RuleRunSummary.test.ts +286 -0
  81. package/Tests/Utils/Schema/BaseSchema.test.ts +651 -0
  82. package/Types/API/Protocol.ts +9 -0
  83. package/Types/API/URL.ts +286 -20
  84. package/Types/Billing/PayAsYouGoPricing.ts +47 -0
  85. package/Types/CustomField/CustomFieldType.ts +28 -0
  86. package/Types/Monitor/MonitorType.ts +11 -0
  87. package/Types/Monitor/SnmpMonitor/NetworkTopology.ts +13 -0
  88. package/Types/NetworkAutomation/RuleRunResult.ts +121 -0
  89. package/Types/Runbook/RunbookStepType.ts +23 -0
  90. package/UI/Components/AutocompleteTextInput/AutocompleteTextInput.tsx +7 -0
  91. package/UI/Components/Button/Button.tsx +14 -22
  92. package/UI/Components/Charts/Area/AreaChart.tsx +4 -2
  93. package/UI/Components/Charts/Bar/BarChart.tsx +4 -2
  94. package/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.ts +13 -0
  95. package/UI/Components/Charts/Line/LineChart.tsx +4 -2
  96. package/UI/Components/Charts/Types/XAxis/XAxis.ts +6 -0
  97. package/UI/Components/Charts/Utils/DataPoint.ts +15 -12
  98. package/UI/Components/Dictionary/Dictionary.tsx +4 -39
  99. package/UI/Components/Icon/Icon.tsx +1 -1
  100. package/UI/Components/LogsViewer/LogsViewer.tsx +5 -1
  101. package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +8 -0
  102. package/UI/Components/LogsViewer/components/LogsPagination.tsx +29 -91
  103. package/UI/Components/LogsViewer/components/LogsViewerToolbar.tsx +2 -0
  104. package/UI/Components/LogsViewer/components/SavedViewsDropdown.tsx +66 -1
  105. package/UI/Components/ModelTable/CustomFieldColumns.tsx +55 -0
  106. package/UI/Components/Pagination/Pagination.tsx +373 -328
  107. package/UI/Components/Pagination/PaginationUtil.ts +263 -0
  108. package/UI/Components/Pagination/Screenshots/README.md +15 -0
  109. package/UI/Components/Pagination/Screenshots/pagination-before-after.png +0 -0
  110. package/UI/Components/Pagination/Screenshots/pagination-go-to-page-modal.png +0 -0
  111. package/UI/Components/Pagination/Screenshots/pagination-long-list.png +0 -0
  112. package/UI/Components/Pagination/Screenshots/pagination-mobile.png +0 -0
  113. package/UI/Components/Pagination/Screenshots/pagination-telemetry.png +0 -0
  114. package/UI/Components/TelemetryViewer/components/SavedViewsDropdown.tsx +66 -1
  115. package/UI/Components/TelemetryViewer/components/TelemetryPagination.tsx +38 -92
  116. package/UI/Components/TextArea/TextArea.tsx +3 -0
  117. package/UI/Components/Workflow/ArgumentsForm.tsx +18 -1
  118. package/UI/Components/Workflow/ColumnEditor/AddColumnDropdown.tsx +177 -0
  119. package/UI/Components/Workflow/ColumnEditor/ColumnConditionRow.tsx +243 -0
  120. package/UI/Components/Workflow/ColumnEditor/ColumnControl.ts +255 -0
  121. package/UI/Components/Workflow/ColumnEditor/ColumnFieldRow.tsx +178 -0
  122. package/UI/Components/Workflow/ColumnEditor/ColumnOperators.ts +206 -0
  123. package/UI/Components/Workflow/ColumnEditor/ColumnRow.ts +157 -0
  124. package/UI/Components/Workflow/ColumnEditor/ColumnRowSerialization.ts +517 -0
  125. package/UI/Components/Workflow/ColumnEditor/ColumnValueInput.tsx +482 -0
  126. package/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.tsx +131 -0
  127. package/UI/Components/Workflow/ColumnEditor/ModelRecordForm.tsx +163 -0
  128. package/UI/Components/Workflow/ModelColumnEditor.tsx +284 -100
  129. package/UI/Utils/NetworkAutomation/RunNetworkRule.ts +122 -0
  130. package/Utils/API.ts +243 -36
  131. package/Utils/Monitor/NetworkDeviceRoleUtil.ts +45 -0
  132. package/Utils/Monitor/NetworkTopologyUtil.ts +42 -2
  133. package/Utils/NetworkAutomation/RuleRunSummary.ts +147 -0
  134. package/build/dist/Models/DatabaseModels/NetworkDevice.js +45 -0
  135. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
  136. package/build/dist/Models/DatabaseModels/NetworkDeviceLink.js +115 -0
  137. package/build/dist/Models/DatabaseModels/NetworkDeviceLink.js.map +1 -1
  138. package/build/dist/Models/DatabaseModels/RunnerJob.js +17 -2
  139. package/build/dist/Models/DatabaseModels/RunnerJob.js.map +1 -1
  140. package/build/dist/Server/API/LlmProviderAPI.js +9 -1
  141. package/build/dist/Server/API/LlmProviderAPI.js.map +1 -1
  142. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787400000000-AddDeviceRoleAndDeclaredLinkParent.js +33 -0
  143. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787400000000-AddDeviceRoleAndDeclaredLinkParent.js.map +1 -0
  144. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
  145. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  146. package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js +202 -0
  147. package/build/dist/Server/Services/NetworkDeviceLabelRuleEngineService.js.map +1 -1
  148. package/build/dist/Server/Services/NetworkDeviceLinkService.js +253 -1
  149. package/build/dist/Server/Services/NetworkDeviceLinkService.js.map +1 -1
  150. package/build/dist/Server/Services/NetworkDeviceService.js +223 -12
  151. package/build/dist/Server/Services/NetworkDeviceService.js.map +1 -1
  152. package/build/dist/Server/Services/RunnerJobService.js +20 -2
  153. package/build/dist/Server/Services/RunnerJobService.js.map +1 -1
  154. package/build/dist/Server/Types/Billing/MeteredPlan/AllMeteredPlans.js +12 -5
  155. package/build/dist/Server/Types/Billing/MeteredPlan/AllMeteredPlans.js.map +1 -1
  156. package/build/dist/Server/Types/Database/JSONColumnQuery.js +40 -4
  157. package/build/dist/Server/Types/Database/JSONColumnQuery.js.map +1 -1
  158. package/build/dist/Server/Utils/LLM/LLMService.js +78 -22
  159. package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
  160. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +22 -98
  161. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  162. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +7 -254
  163. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  164. package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js +14 -2
  165. package/build/dist/Server/Utils/Monitor/MonitorMaintenanceSuppression.js.map +1 -1
  166. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +27 -0
  167. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js.map +1 -1
  168. package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js +285 -0
  169. package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js.map +1 -0
  170. package/build/dist/Server/Utils/SSRFProtection.js +5 -4
  171. package/build/dist/Server/Utils/SSRFProtection.js.map +1 -1
  172. package/build/dist/Server/Utils/Telemetry/InventoryEntityRegistry.js +128 -35
  173. package/build/dist/Server/Utils/Telemetry/InventoryEntityRegistry.js.map +1 -1
  174. package/build/dist/Types/API/Protocol.js +9 -0
  175. package/build/dist/Types/API/Protocol.js.map +1 -1
  176. package/build/dist/Types/API/URL.js +241 -18
  177. package/build/dist/Types/API/URL.js.map +1 -1
  178. package/build/dist/Types/Billing/PayAsYouGoPricing.js +41 -0
  179. package/build/dist/Types/Billing/PayAsYouGoPricing.js.map +1 -0
  180. package/build/dist/Types/CustomField/CustomFieldType.js +26 -0
  181. package/build/dist/Types/CustomField/CustomFieldType.js.map +1 -1
  182. package/build/dist/Types/Monitor/MonitorType.js +10 -0
  183. package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
  184. package/build/dist/Types/NetworkAutomation/RuleRunResult.js +39 -0
  185. package/build/dist/Types/NetworkAutomation/RuleRunResult.js.map +1 -0
  186. package/build/dist/Types/Runbook/RunbookStepType.js +21 -0
  187. package/build/dist/Types/Runbook/RunbookStepType.js.map +1 -1
  188. package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js +1 -1
  189. package/build/dist/UI/Components/AutocompleteTextInput/AutocompleteTextInput.js.map +1 -1
  190. package/build/dist/UI/Components/Button/Button.js +10 -16
  191. package/build/dist/UI/Components/Button/Button.js.map +1 -1
  192. package/build/dist/UI/Components/Charts/Area/AreaChart.js +2 -1
  193. package/build/dist/UI/Components/Charts/Area/AreaChart.js.map +1 -1
  194. package/build/dist/UI/Components/Charts/Bar/BarChart.js +2 -1
  195. package/build/dist/UI/Components/Charts/Bar/BarChart.js.map +1 -1
  196. package/build/dist/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.js +12 -0
  197. package/build/dist/UI/Components/Charts/ChartLibrary/Types/ChartDataPoint.js.map +1 -1
  198. package/build/dist/UI/Components/Charts/Line/LineChart.js +2 -1
  199. package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
  200. package/build/dist/UI/Components/Charts/Utils/DataPoint.js +17 -10
  201. package/build/dist/UI/Components/Charts/Utils/DataPoint.js.map +1 -1
  202. package/build/dist/UI/Components/Dictionary/Dictionary.js +4 -18
  203. package/build/dist/UI/Components/Dictionary/Dictionary.js.map +1 -1
  204. package/build/dist/UI/Components/Icon/Icon.js +1 -1
  205. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  206. package/build/dist/UI/Components/LogsViewer/LogsViewer.js +3 -3
  207. package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
  208. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +5 -1
  209. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
  210. package/build/dist/UI/Components/LogsViewer/components/LogsPagination.js +14 -44
  211. package/build/dist/UI/Components/LogsViewer/components/LogsPagination.js.map +1 -1
  212. package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js +1 -1
  213. package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js.map +1 -1
  214. package/build/dist/UI/Components/LogsViewer/components/SavedViewsDropdown.js +20 -2
  215. package/build/dist/UI/Components/LogsViewer/components/SavedViewsDropdown.js.map +1 -1
  216. package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js +42 -0
  217. package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js.map +1 -1
  218. package/build/dist/UI/Components/Pagination/Pagination.js +174 -199
  219. package/build/dist/UI/Components/Pagination/Pagination.js.map +1 -1
  220. package/build/dist/UI/Components/Pagination/PaginationUtil.js +160 -0
  221. package/build/dist/UI/Components/Pagination/PaginationUtil.js.map +1 -0
  222. package/build/dist/UI/Components/TelemetryViewer/components/SavedViewsDropdown.js +20 -2
  223. package/build/dist/UI/Components/TelemetryViewer/components/SavedViewsDropdown.js.map +1 -1
  224. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryPagination.js +23 -47
  225. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryPagination.js.map +1 -1
  226. package/build/dist/UI/Components/TextArea/TextArea.js +1 -1
  227. package/build/dist/UI/Components/TextArea/TextArea.js.map +1 -1
  228. package/build/dist/UI/Components/Workflow/ArgumentsForm.js +14 -2
  229. package/build/dist/UI/Components/Workflow/ArgumentsForm.js.map +1 -1
  230. package/build/dist/UI/Components/Workflow/ColumnEditor/AddColumnDropdown.js +86 -0
  231. package/build/dist/UI/Components/Workflow/ColumnEditor/AddColumnDropdown.js.map +1 -0
  232. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnConditionRow.js +119 -0
  233. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnConditionRow.js.map +1 -0
  234. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnControl.js +206 -0
  235. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnControl.js.map +1 -0
  236. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnFieldRow.js +57 -0
  237. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnFieldRow.js.map +1 -0
  238. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnOperators.js +150 -0
  239. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnOperators.js.map +1 -0
  240. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnRow.js +67 -0
  241. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnRow.js.map +1 -0
  242. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnRowSerialization.js +309 -0
  243. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnRowSerialization.js.map +1 -0
  244. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnValueInput.js +204 -0
  245. package/build/dist/UI/Components/Workflow/ColumnEditor/ColumnValueInput.js.map +1 -0
  246. package/build/dist/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.js +66 -0
  247. package/build/dist/UI/Components/Workflow/ColumnEditor/ModelQueryBuilder.js.map +1 -0
  248. package/build/dist/UI/Components/Workflow/ColumnEditor/ModelRecordForm.js +83 -0
  249. package/build/dist/UI/Components/Workflow/ColumnEditor/ModelRecordForm.js.map +1 -0
  250. package/build/dist/UI/Components/Workflow/ModelColumnEditor.js +187 -68
  251. package/build/dist/UI/Components/Workflow/ModelColumnEditor.js.map +1 -1
  252. package/build/dist/UI/Utils/NetworkAutomation/RunNetworkRule.js +75 -0
  253. package/build/dist/UI/Utils/NetworkAutomation/RunNetworkRule.js.map +1 -0
  254. package/build/dist/Utils/API.js +175 -34
  255. package/build/dist/Utils/API.js.map +1 -1
  256. package/build/dist/Utils/Monitor/NetworkDeviceRoleUtil.js +37 -0
  257. package/build/dist/Utils/Monitor/NetworkDeviceRoleUtil.js.map +1 -1
  258. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +25 -3
  259. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
  260. package/build/dist/Utils/NetworkAutomation/RuleRunSummary.js +78 -0
  261. package/build/dist/Utils/NetworkAutomation/RuleRunSummary.js.map +1 -0
  262. package/package.json +1 -1
@@ -0,0 +1,148 @@
1
+ import Protocol from "../../../Types/API/Protocol";
2
+ import URL from "../../../Types/API/URL";
3
+ import BadDataException from "../../../Types/Exception/BadDataException";
4
+ import { describe, expect, test } from "@jest/globals";
5
+
6
+ /*
7
+ * An unrecognised scheme used to be swallowed: the prefix loop did not match,
8
+ * the protocol stayed at its https default, and the remainder was read as an
9
+ * authority. That is how "tel:3136361710" became the stored value
10
+ * "https://tel:3136361710/" — a URL nobody typed, with a host of "tel".
11
+ *
12
+ * The write side now refuses a scheme it cannot represent and says which one,
13
+ * instead of quietly rewriting the value into something else.
14
+ */
15
+
16
+ describe("URL — an unsupported scheme is refused, not rewritten", () => {
17
+ const unsupportedSchemes: Array<string> = [
18
+ "ftp://files.example.com/x",
19
+ "file:///etc/passwd",
20
+ "gopher://example.com/1",
21
+ "ldap://example.com/x",
22
+ "smb://example.com/share",
23
+ "chrome://settings",
24
+ "mongodb+srv://cluster.example.com/db",
25
+ ];
26
+
27
+ test.each(unsupportedSchemes)("rejects %s", (input: string) => {
28
+ expect(() => {
29
+ return URL.fromString(input);
30
+ }).toThrow(BadDataException);
31
+ });
32
+
33
+ test("the error names the offending scheme", () => {
34
+ expect(() => {
35
+ return URL.fromString("ftp://files.example.com/x");
36
+ }).toThrow("URL scheme ftp: is not supported.");
37
+ });
38
+
39
+ /*
40
+ * These are dangerous in an href, so they are refused even without the "//"
41
+ * authority marker.
42
+ */
43
+ const dangerousSchemes: Array<string> = [
44
+ "javascript:alert(1)",
45
+ "javascript:alert('xss')",
46
+ "JavaScript:alert(1)",
47
+ "data:text/html,<script>alert(1)</script>",
48
+ "data:text/plain,hello",
49
+ "vbscript:msgbox(1)",
50
+ "file:/etc/passwd",
51
+ "blob:https://example.com/uuid",
52
+ ];
53
+
54
+ test.each(dangerousSchemes)("rejects %s", (input: string) => {
55
+ expect(() => {
56
+ return URL.fromString(input);
57
+ }).toThrow(BadDataException);
58
+ });
59
+
60
+ /*
61
+ * The specific hole this closes: a scheme whose remainder happens to look
62
+ * like a valid host:port used to sail through and be silently rewritten.
63
+ */
64
+ test("an unsupported scheme with a port-shaped remainder is refused", () => {
65
+ expect(() => {
66
+ return URL.fromString("javascript:12345");
67
+ }).toThrow(BadDataException);
68
+ });
69
+
70
+ test("no unsupported scheme is silently rewritten to https", () => {
71
+ for (const input of [...unsupportedSchemes, ...dangerousSchemes]) {
72
+ let rewritten: string | null = null;
73
+
74
+ try {
75
+ rewritten = URL.fromString(input).toString();
76
+ } catch {
77
+ // Refused, which is the point.
78
+ }
79
+
80
+ expect(rewritten).toBeNull();
81
+ }
82
+ });
83
+ });
84
+
85
+ describe("URL — scheme rejection does not catch things that are not schemes", () => {
86
+ /*
87
+ * "example.com:8080/hook" has no scheme — that colon separates a host from a
88
+ * port. A regex alone cannot tell the two apart, so the rule keys on the
89
+ * "//" authority marker, which a host:port never has.
90
+ */
91
+ const schemeLessValues: Array<[string, string]> = [
92
+ ["example.com:8080/hook", "example.com:8080"],
93
+ ["localhost:5000", "localhost:5000"],
94
+ ["example.com", "example.com"],
95
+ ["status.example.com/path", "status.example.com"],
96
+ ];
97
+
98
+ test.each(schemeLessValues)(
99
+ "%s is still parsed as a host, not a scheme",
100
+ (input: string, expectedHost: string) => {
101
+ const url: URL = URL.fromString(input);
102
+
103
+ expect(url.protocol).toBe(Protocol.HTTPS);
104
+ expect(url.hostname.toString()).toBe(expectedHost);
105
+ },
106
+ );
107
+
108
+ test("every supported scheme still parses", () => {
109
+ const supported: Array<[string, Protocol]> = [
110
+ ["https://example.com/x", Protocol.HTTPS],
111
+ ["http://example.com/x", Protocol.HTTP],
112
+ ["ws://example.com/x", Protocol.WS],
113
+ ["wss://example.com/x", Protocol.WSS],
114
+ ["mongodb://example.com/db", Protocol.MONGO_DB],
115
+ ["mailto:support@example.com", Protocol.MAIL],
116
+ ["tel:+13136361710", Protocol.TEL],
117
+ ["sms:+15555550123", Protocol.SMS],
118
+ ];
119
+
120
+ for (const [input, expected] of supported) {
121
+ expect(URL.fromString(input).protocol).toBe(expected);
122
+ }
123
+ });
124
+ });
125
+
126
+ /*
127
+ * The read side is unaffected: a value already sitting in the database with an
128
+ * unsupported scheme still comes back, flagged, rather than failing the query
129
+ * that touched it.
130
+ */
131
+ describe("URL — reads still tolerate an unsupported scheme already stored", () => {
132
+ test("fromStringLenient keeps a stored ftp:// link readable", () => {
133
+ const url: URL = URL.fromStringLenient("ftp://files.example.com/x");
134
+
135
+ expect(url.isMalformed()).toBe(true);
136
+ expect(url.toString()).toBe("ftp://files.example.com/x");
137
+ });
138
+
139
+ test("but it can never be written back", () => {
140
+ const transformer: {
141
+ to: (value: unknown) => unknown;
142
+ } = URL.getDatabaseTransformer() as { to: (value: unknown) => unknown };
143
+
144
+ expect(() => {
145
+ return transformer.to(URL.fromStringLenient("ftp://files.example.com/x"));
146
+ }).toThrow(BadDataException);
147
+ });
148
+ });
@@ -0,0 +1,64 @@
1
+ import { describe, expect, it } from "@jest/globals";
2
+ import {
3
+ ACTIVE_MONITOR_PRICE_IN_USD_PER_MONTH,
4
+ PRICING_PAGE_URL,
5
+ SESSION_REPLAY_PRICE_IN_USD_PER_GB,
6
+ TELEMETRY_PRICE_IN_USD_PER_GB,
7
+ TELEMETRY_PRICE_RETENTION_IN_DAYS,
8
+ formatPriceInUSD,
9
+ } from "../../../Types/Billing/PayAsYouGoPricing";
10
+
11
+ /*
12
+ * These constants are quoted to users, verbatim, on the telemetry ingestion
13
+ * key and create monitor pages. They are pinned here because changing one
14
+ * silently changes what the product promises a customer - a change to any of
15
+ * them has to be deliberate, and has to be made on the pricing page too.
16
+ */
17
+
18
+ describe("PayAsYouGoPricing", () => {
19
+ describe("rates", () => {
20
+ it("charges $0.10 per GB of telemetry, quoted for 15 day retention", () => {
21
+ expect(TELEMETRY_PRICE_IN_USD_PER_GB).toBe(0.1);
22
+ expect(TELEMETRY_PRICE_RETENTION_IN_DAYS).toBe(15);
23
+ });
24
+
25
+ it("charges $2 per GB for session replay, on the same 15 day window", () => {
26
+ expect(SESSION_REPLAY_PRICE_IN_USD_PER_GB).toBe(2);
27
+ });
28
+
29
+ it("charges $1 per active monitor per month", () => {
30
+ expect(ACTIVE_MONITOR_PRICE_IN_USD_PER_MONTH).toBe(1);
31
+ });
32
+
33
+ it("points at the public pricing page", () => {
34
+ expect(PRICING_PAGE_URL).toBe("https://oneuptime.com/pricing");
35
+ });
36
+ });
37
+
38
+ describe("formatPriceInUSD", () => {
39
+ it("writes a whole number of dollars without cents, like the pricing page", () => {
40
+ expect(formatPriceInUSD(1)).toBe("$1");
41
+ expect(formatPriceInUSD(22)).toBe("$22");
42
+ expect(formatPriceInUSD(0)).toBe("$0");
43
+ });
44
+
45
+ it("writes a fractional amount with two decimal places", () => {
46
+ expect(formatPriceInUSD(0.1)).toBe("$0.10");
47
+ expect(formatPriceInUSD(1.5)).toBe("$1.50");
48
+ expect(formatPriceInUSD(2.05)).toBe("$2.05");
49
+ });
50
+
51
+ it("rounds to cents rather than spilling extra digits into the copy", () => {
52
+ expect(formatPriceInUSD(0.125)).toBe("$0.13");
53
+ expect(formatPriceInUSD(0.006)).toBe("$0.01");
54
+ });
55
+
56
+ it("renders the advertised rates exactly as the pricing page writes them", () => {
57
+ expect(formatPriceInUSD(TELEMETRY_PRICE_IN_USD_PER_GB)).toBe("$0.10");
58
+ expect(formatPriceInUSD(SESSION_REPLAY_PRICE_IN_USD_PER_GB)).toBe("$2");
59
+ expect(formatPriceInUSD(ACTIVE_MONITOR_PRICE_IN_USD_PER_MONTH)).toBe(
60
+ "$1",
61
+ );
62
+ });
63
+ });
64
+ });
@@ -0,0 +1,107 @@
1
+ import CustomFieldType from "../../../Types/CustomField/CustomFieldType";
2
+ import FormFieldSchemaType from "../../../UI/Components/Forms/Types/FormFieldSchemaType";
3
+ import FieldType from "../../../UI/Components/Types/FieldType";
4
+ import { describe, expect, test } from "@jest/globals";
5
+
6
+ /*
7
+ * CustomFieldsDetail does not translate a definition's `customFieldType` into a
8
+ * render type - it hands the raw string to a Detail field and to a form field
9
+ * as their `fieldType`, through an `as any` that erases the enum on the way.
10
+ * Nothing in the compiler is watching that seam, so a member added here without
11
+ * a same-VALUE member in FieldType and FormFieldSchemaType type-checks, builds,
12
+ * ships, and only then shows itself: the Detail column falls off the end of the
13
+ * render switch and paints an empty cell, and the form falls off the end of the
14
+ * input switch and paints a control the user cannot type into. The field looks
15
+ * present and is silently unusable, which is the worst shape a regression can
16
+ * take because nothing throws and nothing logs.
17
+ *
18
+ * These are value-set comparisons rather than key comparisons on purpose. The
19
+ * three enums are free to spell a member however reads best on their own side -
20
+ * `Boolean` reaches the form as `FormFieldSchemaType.Toggle`, which is written
21
+ * `Toggle = "Boolean"` for exactly this reason - and only the value crosses the
22
+ * seam. A key-based check would both miss real breakage and reject that legal
23
+ * spelling.
24
+ */
25
+
26
+ const customFieldTypeEntries: Array<[string, string]> = Object.entries(
27
+ CustomFieldType,
28
+ ) as Array<[string, string]>;
29
+
30
+ const fieldTypeValues: Set<string> = new Set<string>(
31
+ Object.values(FieldType) as Array<string>,
32
+ );
33
+
34
+ const formFieldSchemaTypeValues: Set<string> = new Set<string>(
35
+ Object.values(FormFieldSchemaType) as Array<string>,
36
+ );
37
+
38
+ describe("CustomFieldType corresponds to FieldType", () => {
39
+ test.each(customFieldTypeEntries)(
40
+ "CustomFieldType.%s is a FieldType value",
41
+ (_key: string, value: string) => {
42
+ expect(fieldTypeValues.has(value)).toBe(true);
43
+ },
44
+ );
45
+ });
46
+
47
+ describe("CustomFieldType corresponds to FormFieldSchemaType", () => {
48
+ test.each(customFieldTypeEntries)(
49
+ "CustomFieldType.%s is a FormFieldSchemaType value",
50
+ (_key: string, value: string) => {
51
+ expect(formFieldSchemaTypeValues.has(value)).toBe(true);
52
+ },
53
+ );
54
+ });
55
+
56
+ describe("CustomFieldType member set", () => {
57
+ test("has at least one member so the correspondence loops cannot pass vacuously", () => {
58
+ /*
59
+ * The two blocks above are generated from this enum. If it were ever
60
+ * emptied - a bad merge, a barrel file re-export that resolves to {} - the
61
+ * per-member assertions would simply stop existing and the suite would go
62
+ * green while guarding nothing.
63
+ */
64
+ expect(customFieldTypeEntries.length).toBeGreaterThan(0);
65
+ });
66
+
67
+ test("has no duplicate values", () => {
68
+ /*
69
+ * Two keys sharing a value collapse at runtime: the second one wins every
70
+ * lookup, and a definition saved under the first key renders as the second
71
+ * one's type. It also makes the loops above lie, because a duplicate is
72
+ * checked twice and the shadowed member is never exercised on its own.
73
+ */
74
+ const values: Array<string> = customFieldTypeEntries.map(
75
+ ([, value]: [string, string]) => {
76
+ return value;
77
+ },
78
+ );
79
+
80
+ expect(new Set<string>(values).size).toBe(values.length);
81
+ });
82
+
83
+ test("includes Date and DateTime", () => {
84
+ /*
85
+ * The date members are what the jsonb range filters and the ISO-8601
86
+ * storage format exist for. Losing them is a silent feature removal - old
87
+ * definitions keep their stored `customFieldType` string in the database
88
+ * and would then fall through every switch that reads this enum.
89
+ */
90
+ expect(CustomFieldType.Date).toEqual("Date");
91
+ expect(CustomFieldType.DateTime).toEqual("DateTime");
92
+ });
93
+ });
94
+
95
+ describe("CustomFieldType correspondence is by value, not by key", () => {
96
+ test("Boolean reaches the form as Toggle, which is only visible by value", () => {
97
+ /*
98
+ * This is the case that proves the checks above have to compare values.
99
+ * FormFieldSchemaType has no member named `Boolean`; it names the same
100
+ * value `Toggle`. A correspondence test written against key names would
101
+ * fail here on code that works perfectly, and would then be "fixed" by
102
+ * relaxing it into something that no longer catches a missing member.
103
+ */
104
+ expect(Object.keys(FormFieldSchemaType)).not.toContain("Boolean");
105
+ expect(FormFieldSchemaType.Toggle).toEqual(CustomFieldType.Boolean);
106
+ });
107
+ });
@@ -253,6 +253,68 @@ describe("MonitorTypeHelper", () => {
253
253
  });
254
254
  });
255
255
 
256
+ /*
257
+ * The dashboard tells Free plan users which monitors cost money before they
258
+ * create one, and gates the create button on acknowledging it. That warning
259
+ * is only honest while this predicate agrees with what the server actually
260
+ * meters - ActiveMonitoringMeteredPlan counts every monitor whose type is
261
+ * not Manual.
262
+ */
263
+ describe("isBilledAsActiveMonitor", () => {
264
+ test("Manual monitors are free", () => {
265
+ expect(
266
+ MonitorTypeHelper.isBilledAsActiveMonitor(MonitorType.Manual),
267
+ ).toBe(false);
268
+ });
269
+
270
+ test("every other monitor type is billed", () => {
271
+ const billed: Array<MonitorType> = Object.values(MonitorType).filter(
272
+ (monitorType: MonitorType) => {
273
+ return monitorType !== MonitorType.Manual;
274
+ },
275
+ );
276
+
277
+ expect(billed.length).toBeGreaterThan(0);
278
+
279
+ for (const monitorType of billed) {
280
+ expect(MonitorTypeHelper.isBilledAsActiveMonitor(monitorType)).toBe(
281
+ true,
282
+ );
283
+ }
284
+ });
285
+
286
+ test("telemetry monitors are billed as active monitors too, on top of their ingest", () => {
287
+ expect(MonitorTypeHelper.isBilledAsActiveMonitor(MonitorType.Logs)).toBe(
288
+ true,
289
+ );
290
+ expect(
291
+ MonitorTypeHelper.isBilledAsActiveMonitor(MonitorType.Metrics),
292
+ ).toBe(true);
293
+ expect(
294
+ MonitorTypeHelper.isBilledAsActiveMonitor(MonitorType.Traces),
295
+ ).toBe(true);
296
+ });
297
+
298
+ test("agrees exactly with getActiveMonitorTypes", () => {
299
+ const active: Array<MonitorType> =
300
+ MonitorTypeHelper.getActiveMonitorTypes();
301
+
302
+ for (const monitorType of Object.values(MonitorType)) {
303
+ expect(MonitorTypeHelper.isBilledAsActiveMonitor(monitorType)).toBe(
304
+ active.includes(monitorType),
305
+ );
306
+ }
307
+ });
308
+
309
+ test("is the exact inverse of isManualMonitor", () => {
310
+ for (const monitorType of Object.values(MonitorType)) {
311
+ expect(MonitorTypeHelper.isBilledAsActiveMonitor(monitorType)).toBe(
312
+ !MonitorTypeHelper.isManualMonitor(monitorType),
313
+ );
314
+ }
315
+ });
316
+ });
317
+
256
318
  describe("doesMonitorTypeHaveGraphs", () => {
257
319
  test("returns true for graphable types and false otherwise", () => {
258
320
  expect(
@@ -0,0 +1,184 @@
1
+ import {
2
+ LabelRuleRunResult,
3
+ RuleRunResultUtil,
4
+ SiteAssignmentRuleRunResult,
5
+ } from "../../../Types/NetworkAutomation/RuleRunResult";
6
+ import { JSONObject } from "../../../Types/JSON";
7
+ import { describe, expect, it } from "@jest/globals";
8
+
9
+ /*
10
+ * Contract under test - narrowing a rule run's response.
11
+ *
12
+ * The dashboard renders these counters straight into a sentence, so anything
13
+ * the parser lets through untyped ends up on screen. A field the server did
14
+ * not send has to read as zero, not as "NaN devices"; isTruncated has to be a
15
+ * real boolean, not whatever truthy value happened to arrive.
16
+ */
17
+
18
+ describe("RuleRunResultUtil.parseSiteAssignmentRuleRunResult", () => {
19
+ it("reads a full response", () => {
20
+ const parsed: SiteAssignmentRuleRunResult =
21
+ RuleRunResultUtil.parseSiteAssignmentRuleRunResult({
22
+ devicesEvaluated: 40,
23
+ devicesMatched: 12,
24
+ devicesAssigned: 8,
25
+ devicesAlreadyInRuleSite: 2,
26
+ devicesSkippedAlreadyInAnotherSite: 1,
27
+ devicesClaimedByHigherPriorityRule: 1,
28
+ devicesFailed: 0,
29
+ isTruncated: false,
30
+ } as JSONObject);
31
+
32
+ expect(parsed).toEqual({
33
+ devicesEvaluated: 40,
34
+ devicesMatched: 12,
35
+ devicesAssigned: 8,
36
+ devicesAlreadyInRuleSite: 2,
37
+ devicesSkippedAlreadyInAnotherSite: 1,
38
+ devicesClaimedByHigherPriorityRule: 1,
39
+ devicesFailed: 0,
40
+ isTruncated: false,
41
+ });
42
+ });
43
+
44
+ it("reads every missing counter as zero", () => {
45
+ const parsed: SiteAssignmentRuleRunResult =
46
+ RuleRunResultUtil.parseSiteAssignmentRuleRunResult({});
47
+
48
+ expect(parsed).toEqual({
49
+ devicesEvaluated: 0,
50
+ devicesMatched: 0,
51
+ devicesAssigned: 0,
52
+ devicesAlreadyInRuleSite: 0,
53
+ devicesSkippedAlreadyInAnotherSite: 0,
54
+ devicesClaimedByHigherPriorityRule: 0,
55
+ devicesFailed: 0,
56
+ isTruncated: false,
57
+ });
58
+ });
59
+
60
+ it("survives a null or undefined body", () => {
61
+ expect(
62
+ RuleRunResultUtil.parseSiteAssignmentRuleRunResult(null).devicesEvaluated,
63
+ ).toBe(0);
64
+ expect(
65
+ RuleRunResultUtil.parseSiteAssignmentRuleRunResult(undefined)
66
+ .devicesMatched,
67
+ ).toBe(0);
68
+ });
69
+
70
+ /*
71
+ * A numeric string is exactly what a hand-rolled proxy or a JSON layer that
72
+ * stringifies large numbers would send. It must not become "12" concatenated
73
+ * into a sentence, nor NaN.
74
+ */
75
+ it("refuses a non-numeric counter rather than passing it through", () => {
76
+ const parsed: SiteAssignmentRuleRunResult =
77
+ RuleRunResultUtil.parseSiteAssignmentRuleRunResult({
78
+ devicesEvaluated: "40",
79
+ devicesMatched: null,
80
+ devicesAssigned: {},
81
+ } as unknown as JSONObject);
82
+
83
+ expect(parsed.devicesEvaluated).toBe(0);
84
+ expect(parsed.devicesMatched).toBe(0);
85
+ expect(parsed.devicesAssigned).toBe(0);
86
+ });
87
+
88
+ it("refuses NaN and Infinity", () => {
89
+ const parsed: SiteAssignmentRuleRunResult =
90
+ RuleRunResultUtil.parseSiteAssignmentRuleRunResult({
91
+ devicesEvaluated: Number.NaN,
92
+ devicesMatched: Number.POSITIVE_INFINITY,
93
+ } as unknown as JSONObject);
94
+
95
+ expect(parsed.devicesEvaluated).toBe(0);
96
+ expect(parsed.devicesMatched).toBe(0);
97
+ });
98
+
99
+ it("treats only a literal true as truncation", () => {
100
+ expect(
101
+ RuleRunResultUtil.parseSiteAssignmentRuleRunResult({
102
+ isTruncated: true,
103
+ }).isTruncated,
104
+ ).toBe(true);
105
+
106
+ expect(
107
+ RuleRunResultUtil.parseSiteAssignmentRuleRunResult({
108
+ isTruncated: "true",
109
+ } as unknown as JSONObject).isTruncated,
110
+ ).toBe(false);
111
+
112
+ expect(
113
+ RuleRunResultUtil.parseSiteAssignmentRuleRunResult({
114
+ isTruncated: 1,
115
+ } as unknown as JSONObject).isTruncated,
116
+ ).toBe(false);
117
+ });
118
+
119
+ // Unknown fields are dropped: the shape the UI reads is the declared one.
120
+ it("ignores fields it does not know", () => {
121
+ const parsed: SiteAssignmentRuleRunResult =
122
+ RuleRunResultUtil.parseSiteAssignmentRuleRunResult({
123
+ devicesEvaluated: 3,
124
+ somethingElse: "ignored",
125
+ } as unknown as JSONObject);
126
+
127
+ expect(parsed.devicesEvaluated).toBe(3);
128
+ expect(Object.keys(parsed)).not.toContain("somethingElse");
129
+ });
130
+ });
131
+
132
+ describe("RuleRunResultUtil.parseLabelRuleRunResult", () => {
133
+ it("reads a full response", () => {
134
+ const parsed: LabelRuleRunResult =
135
+ RuleRunResultUtil.parseLabelRuleRunResult({
136
+ devicesEvaluated: 40,
137
+ devicesMatched: 12,
138
+ devicesLabeled: 10,
139
+ labelsAttached: 20,
140
+ labelsFailed: 0,
141
+ isTruncated: true,
142
+ } as JSONObject);
143
+
144
+ expect(parsed).toEqual({
145
+ devicesEvaluated: 40,
146
+ devicesMatched: 12,
147
+ devicesLabeled: 10,
148
+ labelsAttached: 20,
149
+ labelsFailed: 0,
150
+ isTruncated: true,
151
+ });
152
+ });
153
+
154
+ it("reads every missing counter as zero", () => {
155
+ const parsed: LabelRuleRunResult =
156
+ RuleRunResultUtil.parseLabelRuleRunResult({});
157
+
158
+ expect(parsed).toEqual({
159
+ devicesEvaluated: 0,
160
+ devicesMatched: 0,
161
+ devicesLabeled: 0,
162
+ labelsAttached: 0,
163
+ labelsFailed: 0,
164
+ isTruncated: false,
165
+ });
166
+ });
167
+
168
+ it("survives a null body", () => {
169
+ expect(RuleRunResultUtil.parseLabelRuleRunResult(null).labelsAttached).toBe(
170
+ 0,
171
+ );
172
+ });
173
+
174
+ it("refuses a non-numeric counter", () => {
175
+ const parsed: LabelRuleRunResult =
176
+ RuleRunResultUtil.parseLabelRuleRunResult({
177
+ labelsAttached: "20",
178
+ devicesLabeled: false,
179
+ } as unknown as JSONObject);
180
+
181
+ expect(parsed.labelsAttached).toBe(0);
182
+ expect(parsed.devicesLabeled).toBe(0);
183
+ });
184
+ });