@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,651 @@
1
+ import { BaseSchema } from "../../../Utils/Schema/BaseSchema";
2
+ import Zod from "../../../Utils/Schema/Zod";
3
+ import SortOrder from "../../../Types/BaseDatabase/SortOrder";
4
+
5
+ /*
6
+ * Direct unit tests for BaseSchema — the abstract base behind ModelSchema and
7
+ * AnalyticsModelSchema.
8
+ *
9
+ * The two concrete subclasses only ever call a handful of the base methods
10
+ * (generateSortSchema / generateSelectSchema / generateGroupBySchema /
11
+ * generateQuerySchema and applyOpenApi), so the example generators and the
12
+ * create-schema builder — getCommonExampleValue, generateSelectSchemaExample,
13
+ * generateGroupBySchemaExample, generateCreateSchema, logSchemaGeneration — are
14
+ * not exercised anywhere else in the codebase. These tests pin down that pure
15
+ * logic branch-by-branch without a database connection.
16
+ *
17
+ * BaseSchema's generators are protected static, so a thin subclass re-exports
18
+ * them as public statics for the test. Nothing else about the base changes.
19
+ */
20
+
21
+ type Column = {
22
+ key: string;
23
+ type?: any;
24
+ required?: boolean;
25
+ isDefaultValueColumn?: boolean;
26
+ };
27
+
28
+ /*
29
+ * A tiny model stand-in. The generators only ever read columns through the
30
+ * caller-supplied accessor callbacks, so the model itself can be an empty
31
+ * object.
32
+ */
33
+ const MODEL: Record<string, unknown> = {};
34
+
35
+ /*
36
+ * Re-export every protected static as a public wrapper so the test can call
37
+ * them directly. A subclass is allowed to reach the base's protected members.
38
+ */
39
+ class TestSchema extends BaseSchema {
40
+ public static commonExampleValue(
41
+ dataType: string,
42
+ second?: boolean,
43
+ ): unknown {
44
+ return this.getCommonExampleValue(dataType, second);
45
+ }
46
+
47
+ public static sortSchema(data: {
48
+ getSortableTypes: () => Array<any>;
49
+ getColumnsForSorting: () => Array<Column>;
50
+ tableName?: string;
51
+ disableOpenApiSchema?: boolean;
52
+ }): any {
53
+ return (this.generateSortSchema as (d: any) => any)({
54
+ model: MODEL,
55
+ tableName: data.tableName,
56
+ getSortableTypes: data.getSortableTypes,
57
+ getColumnsForSorting: data.getColumnsForSorting,
58
+ disableOpenApiSchema: data.disableOpenApiSchema,
59
+ });
60
+ }
61
+
62
+ public static selectSchema(data: {
63
+ getColumns: () => Array<Column>;
64
+ getSelectSchemaExample?: () => Record<string, unknown>;
65
+ allowNested?: boolean;
66
+ getNestedSchema?: (key: string) => any;
67
+ }): any {
68
+ return (this.generateSelectSchema as (d: any) => any)({
69
+ model: MODEL,
70
+ getColumns: data.getColumns,
71
+ getSelectSchemaExample:
72
+ data.getSelectSchemaExample ||
73
+ (() => {
74
+ return {};
75
+ }),
76
+ allowNested: data.allowNested,
77
+ getNestedSchema: data.getNestedSchema
78
+ ? (key: string) => {
79
+ return data.getNestedSchema!(key);
80
+ }
81
+ : undefined,
82
+ });
83
+ }
84
+
85
+ public static groupBySchema(data: {
86
+ getColumns: () => Array<Column>;
87
+ getGroupableTypes: () => Array<any>;
88
+ }): any {
89
+ return (this.generateGroupBySchema as (d: any) => any)({
90
+ model: MODEL,
91
+ getColumns: data.getColumns,
92
+ getGroupableTypes: data.getGroupableTypes,
93
+ getGroupBySchemaExample: () => {
94
+ return {};
95
+ },
96
+ });
97
+ }
98
+
99
+ public static querySchema(data: {
100
+ getColumns: () => Array<Column>;
101
+ getValidOperatorsForColumnType: (type: any) => Array<string>;
102
+ getOperatorSchema?: (op: string, type: any) => any;
103
+ getExampleValueForColumn?: (type: any) => unknown;
104
+ disableOpenApiSchema?: boolean;
105
+ }): any {
106
+ return (this.generateQuerySchema as (d: any) => any)({
107
+ model: MODEL,
108
+ getColumns: data.getColumns,
109
+ getValidOperatorsForColumnType: data.getValidOperatorsForColumnType,
110
+ getOperatorSchema: data.getOperatorSchema,
111
+ getQuerySchemaExample: () => {
112
+ return {};
113
+ },
114
+ getExampleValueForColumn:
115
+ data.getExampleValueForColumn ||
116
+ (() => {
117
+ return "example";
118
+ }),
119
+ disableOpenApiSchema: data.disableOpenApiSchema,
120
+ });
121
+ }
122
+
123
+ public static createSchema(data: {
124
+ getColumns: () => Array<Column>;
125
+ excludedFields?: Array<string>;
126
+ }): any {
127
+ return (this.generateCreateSchema as (d: any) => any)({
128
+ model: MODEL,
129
+ getColumns: data.getColumns,
130
+ getZodTypeForColumn: () => {
131
+ return Zod.string();
132
+ },
133
+ getCreateSchemaExample: () => {
134
+ return {};
135
+ },
136
+ excludedFields: data.excludedFields,
137
+ });
138
+ }
139
+
140
+ public static selectExample(data: {
141
+ getColumns: () => Array<Column>;
142
+ commonFields?: Array<string>;
143
+ maxFields?: number;
144
+ priorityFieldTypes?: Array<any>;
145
+ }): Record<string, unknown> {
146
+ return (this.generateSelectSchemaExample as (d: any) => any)({
147
+ model: MODEL,
148
+ getColumns: data.getColumns,
149
+ commonFields: data.commonFields,
150
+ maxFields: data.maxFields,
151
+ priorityFieldTypes: data.priorityFieldTypes,
152
+ });
153
+ }
154
+
155
+ public static groupByExample(data: {
156
+ getColumns: () => Array<Column>;
157
+ getGroupableTypes: () => Array<any>;
158
+ excludeFields?: Array<string>;
159
+ }): Record<string, unknown> {
160
+ return (this.generateGroupBySchemaExample as (d: any) => any)({
161
+ model: MODEL,
162
+ getColumns: data.getColumns,
163
+ getGroupableTypes: data.getGroupableTypes,
164
+ excludeFields: data.excludeFields,
165
+ });
166
+ }
167
+
168
+ public static openApi(base: any, config: any, disable?: boolean): any {
169
+ return this.applyOpenApi(base, config, disable);
170
+ }
171
+
172
+ public static logGeneration(
173
+ schemaType: string,
174
+ tableName: string,
175
+ shape: any,
176
+ ): void {
177
+ return this.logSchemaGeneration(schemaType, tableName, shape);
178
+ }
179
+ }
180
+
181
+ describe("BaseSchema.getCommonExampleValue", () => {
182
+ test("returns a placeholder UUID for id types", () => {
183
+ const uuid: string = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
184
+ expect(TestSchema.commonExampleValue("objectid")).toBe(uuid);
185
+ expect(TestSchema.commonExampleValue("id")).toBe(uuid);
186
+ });
187
+
188
+ test("distinguishes first and second string examples", () => {
189
+ expect(TestSchema.commonExampleValue("text")).toBe("example_text_1");
190
+ expect(TestSchema.commonExampleValue("string", true)).toBe(
191
+ "example_text_2",
192
+ );
193
+ });
194
+
195
+ test("returns distinct example emails", () => {
196
+ expect(TestSchema.commonExampleValue("email")).toBe("user@example.com");
197
+ expect(TestSchema.commonExampleValue("email", true)).toBe(
198
+ "user2@example.com",
199
+ );
200
+ });
201
+
202
+ test("returns numbers for number/integer", () => {
203
+ expect(TestSchema.commonExampleValue("number")).toBe(42);
204
+ expect(TestSchema.commonExampleValue("integer", true)).toBe(100);
205
+ });
206
+
207
+ test("returns ISO strings for date/datetime", () => {
208
+ expect(TestSchema.commonExampleValue("date")).toBe(
209
+ "2023-01-15T12:30:00.000Z",
210
+ );
211
+ expect(TestSchema.commonExampleValue("datetime", true)).toBe(
212
+ "2023-12-31T23:59:59.000Z",
213
+ );
214
+ });
215
+
216
+ test("inverts the boolean example on the second value", () => {
217
+ // first value is `true`, second is `false`.
218
+ expect(TestSchema.commonExampleValue("boolean")).toBe(true);
219
+ expect(TestSchema.commonExampleValue("boolean", true)).toBe(false);
220
+ });
221
+
222
+ test("returns objects for json/object", () => {
223
+ expect(TestSchema.commonExampleValue("json")).toEqual({ key: "value" });
224
+ expect(TestSchema.commonExampleValue("object", true)).toEqual({
225
+ key2: "value2",
226
+ });
227
+ });
228
+
229
+ test("returns arrays for array type", () => {
230
+ expect(TestSchema.commonExampleValue("array")).toEqual(["item1", "item2"]);
231
+ expect(TestSchema.commonExampleValue("array", true)).toEqual([
232
+ "item3",
233
+ "item4",
234
+ ]);
235
+ });
236
+
237
+ test("is case-insensitive on the data type", () => {
238
+ expect(TestSchema.commonExampleValue("ObjectID")).toBe(
239
+ "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
240
+ );
241
+ expect(TestSchema.commonExampleValue("BOOLEAN")).toBe(true);
242
+ });
243
+
244
+ test("falls back to a generic example for unknown types", () => {
245
+ expect(TestSchema.commonExampleValue("geography")).toBe("example_value_1");
246
+ expect(TestSchema.commonExampleValue("geography", true)).toBe(
247
+ "example_value_2",
248
+ );
249
+ });
250
+ });
251
+
252
+ describe("BaseSchema.generateSortSchema", () => {
253
+ const columns: Array<Column> = [
254
+ { key: "name", type: "text" },
255
+ { key: "createdAt", type: "date" },
256
+ { key: "config", type: "json" }, // not sortable
257
+ ];
258
+
259
+ test("includes only sortable columns in the shape", () => {
260
+ const schema: any = TestSchema.sortSchema({
261
+ getSortableTypes: () => {
262
+ return ["text", "date"];
263
+ },
264
+ getColumnsForSorting: () => {
265
+ return columns;
266
+ },
267
+ });
268
+
269
+ expect(Object.keys(schema.shape).sort()).toEqual(["createdAt", "name"]);
270
+ });
271
+
272
+ test("accepts valid sort orders and rejects invalid ones", () => {
273
+ const schema: any = TestSchema.sortSchema({
274
+ getSortableTypes: () => {
275
+ return ["text", "date"];
276
+ },
277
+ getColumnsForSorting: () => {
278
+ return columns;
279
+ },
280
+ });
281
+
282
+ expect(schema.safeParse({ name: SortOrder.Ascending }).success).toBe(true);
283
+ expect(schema.safeParse({ createdAt: SortOrder.Descending }).success).toBe(
284
+ true,
285
+ );
286
+ expect(schema.safeParse({ name: "sideways" }).success).toBe(false);
287
+ });
288
+
289
+ test("each sort field is optional", () => {
290
+ const schema: any = TestSchema.sortSchema({
291
+ getSortableTypes: () => {
292
+ return ["text"];
293
+ },
294
+ getColumnsForSorting: () => {
295
+ return columns;
296
+ },
297
+ });
298
+
299
+ expect(schema.safeParse({}).success).toBe(true);
300
+ });
301
+
302
+ test("produces an empty shape when nothing is sortable", () => {
303
+ const schema: any = TestSchema.sortSchema({
304
+ getSortableTypes: () => {
305
+ return [];
306
+ },
307
+ getColumnsForSorting: () => {
308
+ return columns;
309
+ },
310
+ });
311
+
312
+ expect(Object.keys(schema.shape)).toHaveLength(0);
313
+ });
314
+ });
315
+
316
+ describe("BaseSchema.generateSelectSchema", () => {
317
+ test("makes every column an optional boolean", () => {
318
+ const schema: any = TestSchema.selectSchema({
319
+ getColumns: () => {
320
+ return [{ key: "name" }, { key: "email" }];
321
+ },
322
+ });
323
+
324
+ expect(Object.keys(schema.shape).sort()).toEqual(["email", "name"]);
325
+ expect(schema.safeParse({ name: true }).success).toBe(true);
326
+ expect(schema.safeParse({}).success).toBe(true);
327
+ expect(schema.safeParse({ name: "yes" }).success).toBe(false);
328
+ });
329
+
330
+ test("uses a nested schema when nesting is allowed and available", () => {
331
+ const nested: any = Zod.object({ id: Zod.boolean().optional() });
332
+ const schema: any = TestSchema.selectSchema({
333
+ getColumns: () => {
334
+ return [{ key: "monitor" }, { key: "name" }];
335
+ },
336
+ allowNested: true,
337
+ getNestedSchema: (key: string) => {
338
+ return key === "monitor" ? nested : null;
339
+ },
340
+ });
341
+
342
+ // monitor accepts a nested object; name stays a boolean.
343
+ expect(
344
+ schema.safeParse({ monitor: { id: true }, name: true }).success,
345
+ ).toBe(true);
346
+ expect(schema.safeParse({ monitor: true }).success).toBe(false);
347
+ });
348
+
349
+ test("ignores nested schemas when allowNested is false", () => {
350
+ const nested: any = Zod.object({ id: Zod.boolean().optional() });
351
+ const schema: any = TestSchema.selectSchema({
352
+ getColumns: () => {
353
+ return [{ key: "monitor" }];
354
+ },
355
+ allowNested: false,
356
+ getNestedSchema: () => {
357
+ return nested;
358
+ },
359
+ });
360
+
361
+ // Falls back to a plain boolean, so a nested object is rejected.
362
+ expect(schema.safeParse({ monitor: true }).success).toBe(true);
363
+ expect(schema.safeParse({ monitor: { id: true } }).success).toBe(false);
364
+ });
365
+ });
366
+
367
+ describe("BaseSchema.generateGroupBySchema", () => {
368
+ const columns: Array<Column> = [
369
+ { key: "projectId", type: "objectid" },
370
+ { key: "note", type: "text" }, // not groupable
371
+ ];
372
+
373
+ test("includes only groupable columns and requires the literal true", () => {
374
+ const schema: any = TestSchema.groupBySchema({
375
+ getColumns: () => {
376
+ return columns;
377
+ },
378
+ getGroupableTypes: () => {
379
+ return ["objectid"];
380
+ },
381
+ });
382
+
383
+ expect(Object.keys(schema.shape)).toEqual(["projectId"]);
384
+ expect(schema.safeParse({ projectId: true }).success).toBe(true);
385
+ // literal(true) rejects false.
386
+ expect(schema.safeParse({ projectId: false }).success).toBe(false);
387
+ expect(schema.safeParse({}).success).toBe(true);
388
+ });
389
+ });
390
+
391
+ describe("BaseSchema.generateQuerySchema", () => {
392
+ const columns: Array<Column> = [
393
+ { key: "name", type: "text" },
394
+ { key: "secret", type: "password" }, // no operators => skipped
395
+ ];
396
+
397
+ const validOperators: (type: any) => Array<string> = (type: any) => {
398
+ return type === "password" ? [] : ["EqualTo", "NotEqual"];
399
+ };
400
+
401
+ test("skips columns that expose no operators", () => {
402
+ const schema: any = TestSchema.querySchema({
403
+ getColumns: () => {
404
+ return columns;
405
+ },
406
+ getValidOperatorsForColumnType: validOperators,
407
+ });
408
+
409
+ expect(Object.keys(schema.shape)).toEqual(["name"]);
410
+ });
411
+
412
+ test("builds a simple _type/value operator object when no operator schema is supplied", () => {
413
+ const schema: any = TestSchema.querySchema({
414
+ getColumns: () => {
415
+ return [{ key: "name", type: "text" }];
416
+ },
417
+ getValidOperatorsForColumnType: () => {
418
+ return ["EqualTo", "NotEqual"];
419
+ },
420
+ });
421
+
422
+ expect(
423
+ schema.safeParse({ name: { _type: "EqualTo", value: "x" } }).success,
424
+ ).toBe(true);
425
+ // _type must be one of the valid operators.
426
+ expect(
427
+ schema.safeParse({ name: { _type: "Bogus", value: "x" } }).success,
428
+ ).toBe(false);
429
+ expect(schema.safeParse({}).success).toBe(true);
430
+ });
431
+
432
+ test("uses a single optional operator schema when only one operator is valid", () => {
433
+ const schema: any = TestSchema.querySchema({
434
+ getColumns: () => {
435
+ return [{ key: "count", type: "number" }];
436
+ },
437
+ getValidOperatorsForColumnType: () => {
438
+ return ["EqualTo"];
439
+ },
440
+ getOperatorSchema: () => {
441
+ return Zod.object({ EqualTo: Zod.number() });
442
+ },
443
+ });
444
+
445
+ expect(schema.safeParse({ count: { EqualTo: 5 } }).success).toBe(true);
446
+ expect(schema.safeParse({ count: { EqualTo: "no" } }).success).toBe(false);
447
+ expect(schema.safeParse({}).success).toBe(true);
448
+ });
449
+
450
+ test("unions multiple operator schemas when several operators are valid", () => {
451
+ const schema: any = TestSchema.querySchema({
452
+ getColumns: () => {
453
+ return [{ key: "count", type: "number" }];
454
+ },
455
+ getValidOperatorsForColumnType: () => {
456
+ return ["EqualTo", "GreaterThan"];
457
+ },
458
+ getOperatorSchema: (op: string) => {
459
+ return op === "EqualTo"
460
+ ? Zod.object({ EqualTo: Zod.number() })
461
+ : Zod.object({ GreaterThan: Zod.number() });
462
+ },
463
+ });
464
+
465
+ expect(schema.safeParse({ count: { EqualTo: 1 } }).success).toBe(true);
466
+ expect(schema.safeParse({ count: { GreaterThan: 2 } }).success).toBe(true);
467
+ expect(schema.safeParse({ count: { LessThan: 3 } }).success).toBe(false);
468
+ });
469
+ });
470
+
471
+ describe("BaseSchema.generateCreateSchema", () => {
472
+ test("excludes the default excluded fields and default-value columns", () => {
473
+ const schema: any = TestSchema.createSchema({
474
+ getColumns: () => {
475
+ return [
476
+ { key: "_id" },
477
+ { key: "createdAt" },
478
+ { key: "updatedAt" },
479
+ { key: "createdBy", isDefaultValueColumn: true },
480
+ { key: "name", required: true },
481
+ { key: "description" },
482
+ ];
483
+ },
484
+ });
485
+
486
+ expect(Object.keys(schema.shape).sort()).toEqual(["description", "name"]);
487
+ });
488
+
489
+ test("required columns are required and optional columns are optional", () => {
490
+ const schema: any = TestSchema.createSchema({
491
+ getColumns: () => {
492
+ return [{ key: "name", required: true }, { key: "description" }];
493
+ },
494
+ });
495
+
496
+ expect(schema.safeParse({ name: "a" }).success).toBe(true);
497
+ expect(schema.safeParse({ name: "a", description: "b" }).success).toBe(
498
+ true,
499
+ );
500
+ // name is required.
501
+ expect(schema.safeParse({ description: "b" }).success).toBe(false);
502
+ });
503
+
504
+ test("honors a custom excludedFields list", () => {
505
+ const schema: any = TestSchema.createSchema({
506
+ getColumns: () => {
507
+ return [
508
+ { key: "_id" }, // no longer excluded with a custom list
509
+ { key: "internalOnly" },
510
+ { key: "name" },
511
+ ];
512
+ },
513
+ excludedFields: ["internalOnly"],
514
+ });
515
+
516
+ expect(Object.keys(schema.shape).sort()).toEqual(["_id", "name"]);
517
+ });
518
+ });
519
+
520
+ describe("BaseSchema.generateSelectSchemaExample", () => {
521
+ test("adds common fields that exist on the model", () => {
522
+ const example: Record<string, unknown> = TestSchema.selectExample({
523
+ getColumns: () => {
524
+ return [{ key: "_id" }, { key: "createdAt" }, { key: "name" }];
525
+ },
526
+ });
527
+
528
+ /*
529
+ * Default common fields present on the model become true; updatedAt is
530
+ * absent so it is omitted.
531
+ */
532
+ expect(example).toEqual({ _id: true, createdAt: true });
533
+ });
534
+
535
+ test("adds priority-typed fields up to maxFields, excluding common fields", () => {
536
+ const example: Record<string, unknown> = TestSchema.selectExample({
537
+ getColumns: () => {
538
+ return [
539
+ { key: "_id", type: "objectid" },
540
+ { key: "name", type: "text" },
541
+ { key: "email", type: "text" },
542
+ { key: "slug", type: "text" },
543
+ ];
544
+ },
545
+ commonFields: ["_id"],
546
+ priorityFieldTypes: ["text"],
547
+ maxFields: 2,
548
+ });
549
+
550
+ // _id via common fields, then two text fields (name, email) up to the cap.
551
+ expect(example).toEqual({ _id: true, name: true, email: true });
552
+ });
553
+
554
+ test("omits priority fields entirely when none are requested", () => {
555
+ const example: Record<string, unknown> = TestSchema.selectExample({
556
+ getColumns: () => {
557
+ return [{ key: "name", type: "text" }];
558
+ },
559
+ commonFields: [],
560
+ });
561
+
562
+ expect(example).toEqual({});
563
+ });
564
+ });
565
+
566
+ describe("BaseSchema.generateGroupBySchemaExample", () => {
567
+ test("returns the first groupable field that is not excluded", () => {
568
+ const example: Record<string, unknown> = TestSchema.groupByExample({
569
+ getColumns: () => {
570
+ return [
571
+ { key: "createdAt", type: "date" }, // excluded by default
572
+ { key: "projectId", type: "objectid" },
573
+ { key: "labelId", type: "objectid" },
574
+ ];
575
+ },
576
+ getGroupableTypes: () => {
577
+ return ["objectid", "date"];
578
+ },
579
+ });
580
+
581
+ expect(example).toEqual({ projectId: true });
582
+ });
583
+
584
+ test("falls back to createdAt when nothing is groupable", () => {
585
+ const example: Record<string, unknown> = TestSchema.groupByExample({
586
+ getColumns: () => {
587
+ return [{ key: "name", type: "text" }];
588
+ },
589
+ getGroupableTypes: () => {
590
+ return ["objectid"];
591
+ },
592
+ });
593
+
594
+ expect(example).toEqual({ createdAt: true });
595
+ });
596
+
597
+ test("honors a custom excludeFields list", () => {
598
+ const example: Record<string, unknown> = TestSchema.groupByExample({
599
+ getColumns: () => {
600
+ return [
601
+ { key: "projectId", type: "objectid" },
602
+ { key: "labelId", type: "objectid" },
603
+ ];
604
+ },
605
+ getGroupableTypes: () => {
606
+ return ["objectid"];
607
+ },
608
+ excludeFields: ["projectId"],
609
+ });
610
+
611
+ expect(example).toEqual({ labelId: true });
612
+ });
613
+ });
614
+
615
+ describe("BaseSchema.applyOpenApi", () => {
616
+ test("returns the base type unchanged when the schema is disabled", () => {
617
+ const base: any = Zod.string();
618
+ const result: any = TestSchema.openApi(base, { type: "string" }, true);
619
+ expect(result).toBe(base);
620
+ });
621
+
622
+ test("attaches the OpenAPI metadata when enabled", () => {
623
+ const base: any = Zod.string();
624
+ const result: any = TestSchema.openApi(
625
+ base,
626
+ { type: "string", description: "a field" },
627
+ false,
628
+ );
629
+
630
+ // openapi() returns a new schema instance carrying the metadata.
631
+ expect(result).not.toBe(base);
632
+ expect(result.safeParse("hello").success).toBe(true);
633
+ });
634
+
635
+ test("defaults to applying the metadata when the flag is omitted", () => {
636
+ const base: any = Zod.string();
637
+ const result: any = TestSchema.openApi(base, { type: "string" });
638
+ expect(result).not.toBe(base);
639
+ });
640
+ });
641
+
642
+ describe("BaseSchema.logSchemaGeneration", () => {
643
+ test("does not throw while logging shape keys", () => {
644
+ expect(() => {
645
+ TestSchema.logGeneration("Select", "Monitor", {
646
+ name: Zod.boolean(),
647
+ email: Zod.boolean(),
648
+ });
649
+ }).not.toThrow();
650
+ });
651
+ });
@@ -5,6 +5,15 @@ enum Protocol {
5
5
  WS = "ws://",
6
6
  WSS = "wss://",
7
7
  MAIL = "mailto:",
8
+ /*
9
+ * RFC 3966 / RFC 5724. These are "opaque" schemes: what follows the colon
10
+ * is a phone number, not an authority, so it must never be handed to
11
+ * Hostname. Before they were listed here, "tel:1234567890" fell through to
12
+ * the https default and was normalised on save into
13
+ * "https://tel:1234567890/" — a host of "tel" and a "port" of 1234567890.
14
+ */
15
+ TEL = "tel:",
16
+ SMS = "sms:",
8
17
  }
9
18
 
10
19
  export default Protocol;