@oneuptime/common 12.0.2 → 12.0.4
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.
- package/Models/DatabaseModels/CephCluster.ts +14 -0
- package/Models/DatabaseModels/CodeRepository.ts +14 -6
- package/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.ts +14 -0
- package/Models/DatabaseModels/DockerHost.ts +14 -0
- package/Models/DatabaseModels/GlobalOidcProject.ts +18 -0
- package/Models/DatabaseModels/GlobalSsoProject.ts +18 -0
- package/Models/DatabaseModels/Index.ts +2 -0
- package/Models/DatabaseModels/IoTFleet.ts +14 -0
- package/Models/DatabaseModels/KubernetesCluster.ts +14 -0
- package/Models/DatabaseModels/LogDropFilter.ts +9 -20
- package/Models/DatabaseModels/NetworkDevice.ts +14 -0
- package/Models/DatabaseModels/NetworkInterface.ts +18 -0
- package/Models/DatabaseModels/Project.ts +16 -2
- package/Models/DatabaseModels/ProxmoxCluster.ts +14 -0
- package/Models/DatabaseModels/Service.ts +30 -0
- package/Models/DatabaseModels/StatusPageMonitorRule.ts +911 -0
- package/Models/DatabaseModels/StatusPagePrivateUser.ts +30 -0
- package/Models/DatabaseModels/StatusPageResource.ts +73 -0
- package/Models/DatabaseModels/TraceDropFilter.ts +9 -20
- package/Models/DatabaseModels/User.ts +30 -0
- package/Server/API/AIAgentDataAPI.ts +31 -0
- package/Server/API/BaseAPI.ts +13 -2
- package/Server/API/DashboardAPI.ts +458 -12
- package/Server/API/GitHubAPI.ts +119 -283
- package/Server/API/UserAPI.ts +263 -1
- package/Server/EnvironmentConfig.ts +38 -4
- package/Server/Infrastructure/GlobalCache.ts +152 -0
- package/Server/Infrastructure/Postgres/DataSourceOptions.ts +16 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.ts +123 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786018109307-AddPerUserPasswordSalt.ts +21 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786023262402-WidenHashedStringColumnsForScrypt.ts +68 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786100000000-RestoreServiceLowerNameIndex.ts +100 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786200000000-RestoreDroppedUniqueIndexes.ts +214 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1786300000000-QuarantineUnboundGitHubInstallations.ts +69 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +12 -0
- package/Server/Services/AlertStateTimelineService.ts +20 -0
- package/Server/Services/AnalyticsDatabaseService.ts +72 -1
- package/Server/Services/CephClusterService.ts +26 -86
- package/Server/Services/CloudResourceService.ts +23 -83
- package/Server/Services/CodeRepositoryService.ts +105 -2
- package/Server/Services/DatabaseService.ts +296 -2
- package/Server/Services/DockerHostService.ts +19 -79
- package/Server/Services/DockerSwarmClusterService.ts +27 -88
- package/Server/Services/HostService.ts +46 -99
- package/Server/Services/IncidentStateTimelineService.ts +20 -0
- package/Server/Services/Index.ts +2 -0
- package/Server/Services/IoTFleetService.ts +19 -79
- package/Server/Services/KubernetesClusterService.ts +17 -78
- package/Server/Services/LabelService.ts +57 -10
- package/Server/Services/MetricTypeService.ts +84 -0
- package/Server/Services/MonitorService.ts +89 -14
- package/Server/Services/MonitorStatusTimelineService.ts +29 -0
- package/Server/Services/MonitorTemplateService.ts +65 -0
- package/Server/Services/OpenTelemetryIngestService.ts +230 -26
- package/Server/Services/PodmanHostService.ts +19 -79
- package/Server/Services/ProxmoxClusterService.ts +23 -83
- package/Server/Services/RumApplicationService.ts +19 -80
- package/Server/Services/ScheduledMaintenanceStateTimelineService.ts +21 -0
- package/Server/Services/ServerlessFunctionService.ts +24 -85
- package/Server/Services/ServiceService.ts +299 -73
- package/Server/Services/StatusPageMonitorRuleEngineService.ts +752 -0
- package/Server/Services/StatusPageMonitorRuleService.ts +471 -0
- package/Server/Services/TelemetryEntityRelationshipService.ts +1 -0
- package/Server/Services/TelemetryEntityService.ts +1 -0
- package/Server/Services/UserService.ts +184 -0
- package/Server/Utils/AI/Toolbox/CodeTools.ts +45 -4
- package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +13 -0
- package/Server/Utils/CodeRepository/GitHub/GitHub.ts +157 -4
- package/Server/Utils/CodeRepository/GitHub/GitHubInstallationBinding.ts +130 -0
- package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +170 -39
- package/Server/Utils/Monitor/MonitorResource.ts +63 -36
- package/Server/Utils/Monitor/MonitorStatusTimeline.ts +36 -0
- package/Server/Utils/Monitor/MonitorStepsProjectValidator.ts +148 -127
- package/Server/Utils/Monitor/MonitorStepsReferenceExtractor.ts +434 -0
- package/Server/Utils/PasswordHash.ts +306 -0
- package/Server/Utils/SingleFlight.ts +83 -0
- package/Server/Utils/StatusPage/MonitorRulePatternValidator.ts +46 -0
- package/Server/Utils/Telemetry/EntityRegistry.ts +107 -26
- package/Server/Utils/Telemetry/ResourceHeartbeat.ts +314 -0
- package/Server/Utils/Telemetry/Telemetry.ts +351 -122
- package/Tests/App/Dashboard/OverviewCustomFields.test.tsx +333 -0
- package/Tests/App/Dashboard/UserCustomFields.test.tsx +392 -0
- package/Tests/App/Dashboard/WidgetCatalog.test.ts +2 -0
- package/Tests/Models/DatabaseModels/ColumnTransformerInvariants.test.ts +306 -0
- package/Tests/Models/DatabaseModels/NumberColumnDeserialization.test.ts +333 -0
- package/Tests/Models/DatabaseModels/StatusPageMonitorRuleModel.test.ts +190 -0
- package/Tests/Server/API/AIAgentDataRepositoryToken.test.ts +381 -0
- package/Tests/Server/API/DashboardPublicAttributeValuesAPI.test.ts +943 -0
- package/Tests/Server/API/DashboardPublicMetricsAggregateAPI.test.ts +1296 -0
- package/Tests/Server/API/DashboardPublicResourceListAPI.test.ts +26 -0
- package/Tests/Server/API/DashboardPublicTemplatePayloads.test.ts +598 -0
- package/Tests/Server/API/GitHubAppInstallationBindingAPI.test.ts +539 -0
- package/Tests/Server/API/Helpers.ts +6 -1
- package/Tests/Server/API/UserProjectsAPI.test.ts +852 -0
- package/Tests/Server/Infrastructure/GlobalCache.test.ts +354 -0
- package/Tests/Server/Infrastructure/PostgresLockTimeoutOptions.test.ts +181 -0
- package/Tests/Server/Infrastructure/SemaphoreMutex.test.ts +215 -0
- package/Tests/Server/Services/AddPerUserPasswordSaltMigration.test.ts +178 -0
- package/Tests/Server/Services/AnalyticsDatabasePaginationStability.test.ts +582 -0
- package/Tests/Server/Services/AnalyticsDatabaseService.test.ts +5 -0
- package/Tests/Server/Services/CodeRepositoryInstallationBinding.test.ts +305 -0
- package/Tests/Server/Services/CodeRepositoryResolutionBinding.test.ts +147 -0
- package/Tests/Server/Services/DatabaseServicePerUserPasswordSalt.test.ts +870 -0
- package/Tests/Server/Services/DatabaseServiceUpdateColumnsIfUnlocked.test.ts +342 -0
- package/Tests/Server/Services/DropFilterSaveValidation.test.ts +245 -0
- package/Tests/Server/Services/HostServiceUpdateLastSeen.test.ts +163 -15
- package/Tests/Server/Services/MetricTypeAttachServices.test.ts +222 -0
- package/Tests/Server/Services/MissingReferenceWriteGuard.test.ts +614 -0
- package/Tests/Server/Services/MonitorStatusTimelineFastPath.test.ts +23 -0
- package/Tests/Server/Services/OpenTelemetryServiceResolutionCache.test.ts +568 -0
- package/Tests/Server/Services/ResourceUpdateLastSeenLivenessFallback.test.ts +305 -56
- package/Tests/Server/Services/RestoreDroppedUniqueIndexesMigration.test.ts +386 -0
- package/Tests/Server/Services/RestoreServiceLowerNameIndexMigration.test.ts +240 -0
- package/Tests/Server/Services/ServiceUpdateLastSeenSplitGates.test.ts +705 -0
- package/Tests/Server/Services/StatusPageMonitorRuleEngineService.test.ts +1719 -0
- package/Tests/Server/Services/StatusPageMonitorRuleHooks.test.ts +1212 -0
- package/Tests/Server/Services/StatusPageMonitorRuleMonitorCreateHook.test.ts +228 -0
- package/Tests/Server/Services/UserServiceFirstMasterAdminElection.test.ts +885 -0
- package/Tests/Server/Services/WidenHashedStringColumnsForScryptMigration.test.ts +220 -0
- package/Tests/Server/Utils/AI/CodeTools.test.ts +47 -1
- package/Tests/Server/Utils/AI/CodeWriteTools.test.ts +10 -0
- package/Tests/Server/Utils/APIKey/AccessPermission.test.ts +267 -0
- package/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.ts +120 -0
- package/Tests/Server/Utils/CodeRepository/GitHubInstallationBinding.test.ts +292 -0
- package/Tests/Server/Utils/Database/ProjectScopedReferenceValidator.test.ts +260 -13
- package/Tests/Server/Utils/EntityRegistryRowFence.test.ts +302 -0
- package/Tests/Server/Utils/GitHubInstallationOwnershipVerification.test.ts +340 -0
- package/Tests/Server/Utils/GitHubWebhookAndTreeCacheIsolation.test.ts +250 -0
- package/Tests/Server/Utils/MetricTypeIndexConvergence.test.ts +598 -0
- package/Tests/Server/Utils/Monitor/MonitorStatusTimelineUnusableStatus.test.ts +154 -0
- package/Tests/Server/Utils/Monitor/MonitorStepsProjectValidator.test.ts +638 -92
- package/Tests/Server/Utils/Monitor/MonitorStepsReferenceExtractor.test.ts +724 -0
- package/Tests/Server/Utils/PasswordHash.test.ts +555 -0
- package/Tests/Server/Utils/SingleFlight.test.ts +221 -0
- package/Tests/Types/Dashboard/NetworkDashboardTemplate.test.ts +793 -0
- package/Tests/Types/Database/BigIntColumnTransformer.test.ts +147 -0
- package/Tests/Types/Database/ColumnLength.test.ts +7 -1
- package/Tests/Types/Database/DatabasePropertyTransformer.test.ts +140 -0
- package/Tests/Types/Database/NumericColumnValue.test.ts +127 -0
- package/Tests/Types/Decimal.test.ts +37 -0
- package/Tests/Types/HashedStringPerUserSalt.test.ts +476 -0
- package/Tests/Types/Monitor/DockerAlertTemplates.test.ts +293 -0
- package/Tests/Types/Monitor/HostAlertTemplates.test.ts +249 -0
- package/Tests/Types/Monitor/IotAlertTemplates.test.ts +320 -0
- package/Tests/Types/Monitor/PodmanAlertTemplates.test.ts +271 -0
- package/Tests/Types/Monitor/SnmpVersionParsing.test.ts +152 -0
- package/Tests/Types/Port.test.ts +38 -0
- package/Tests/UI/Components/CustomFields/CustomFieldsDetail.test.tsx +696 -0
- package/Tests/UI/Components/LogsHistogram.test.tsx +276 -0
- package/Tests/UI/Components/UseLiveLogsRefresh.test.tsx +489 -0
- package/Tests/UI/Components/UseLogsHistogram.test.tsx +500 -0
- package/Tests/UI/Utils/UserProjectsModelAPI.test.ts +714 -0
- package/Tests/Utils/Dashboard/Components/DashboardComponentsUtil.test.ts +120 -0
- package/Tests/Utils/Dashboard/DashboardNetworkMapComponent.test.ts +327 -0
- package/Tests/Utils/TeamMembersByProject.test.ts +655 -0
- package/Types/Dashboard/DashboardComponentType.ts +1 -0
- package/Types/Dashboard/DashboardComponents/ComponentArgument.ts +1 -0
- package/Types/Dashboard/DashboardComponents/DashboardNetworkMapComponent.ts +40 -0
- package/Types/Dashboard/DashboardTemplates.ts +397 -0
- package/Types/Database/BigIntColumnTransformer.ts +74 -0
- package/Types/Database/ColumnLength.ts +9 -1
- package/Types/Database/DatabaseProperty.ts +26 -0
- package/Types/Database/NumericColumnValue.ts +128 -0
- package/Types/Database/TableColumn.ts +11 -0
- package/Types/Database/UnsynchronizedIndex.ts +48 -0
- package/Types/Decimal.ts +16 -4
- package/Types/HashedString.ts +139 -4
- package/Types/Permission.ts +48 -0
- package/Types/Port.ts +16 -4
- package/UI/Components/CustomFields/CustomFieldsDetail.tsx +85 -11
- package/UI/Components/LogsViewer/useLiveLogsRefresh.ts +86 -0
- package/UI/Components/LogsViewer/useLogsHistogram.ts +113 -0
- package/UI/Components/Navbar/NavBar.tsx +12 -2
- package/UI/Components/Navbar/NavBarMenuModal.tsx +19 -7
- package/UI/Utils/ModelAPI/UserProjectsModelAPI.ts +257 -0
- package/Utils/Dashboard/Components/DashboardNetworkMapComponent.ts +136 -0
- package/Utils/Dashboard/Components/Index.ts +7 -0
- package/Utils/TeamMembersByProject.ts +237 -0
- package/build/dist/Models/DatabaseModels/CephCluster.js +16 -1
- package/build/dist/Models/DatabaseModels/CephCluster.js.map +1 -1
- package/build/dist/Models/DatabaseModels/CodeRepository.js +14 -6
- package/build/dist/Models/DatabaseModels/CodeRepository.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js +12 -0
- package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js.map +1 -1
- package/build/dist/Models/DatabaseModels/DockerHost.js +16 -1
- package/build/dist/Models/DatabaseModels/DockerHost.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GlobalOidcProject.js +16 -1
- package/build/dist/Models/DatabaseModels/GlobalOidcProject.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GlobalSsoProject.js +16 -1
- package/build/dist/Models/DatabaseModels/GlobalSsoProject.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +2 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/IoTFleet.js +16 -1
- package/build/dist/Models/DatabaseModels/IoTFleet.js.map +1 -1
- package/build/dist/Models/DatabaseModels/KubernetesCluster.js +16 -1
- package/build/dist/Models/DatabaseModels/KubernetesCluster.js.map +1 -1
- package/build/dist/Models/DatabaseModels/LogDropFilter.js +9 -20
- package/build/dist/Models/DatabaseModels/LogDropFilter.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDevice.js +16 -1
- package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkInterface.js +16 -1
- package/build/dist/Models/DatabaseModels/NetworkInterface.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Project.js +16 -2
- package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ProxmoxCluster.js +16 -1
- package/build/dist/Models/DatabaseModels/ProxmoxCluster.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Service.js +28 -1
- package/build/dist/Models/DatabaseModels/Service.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageMonitorRule.js +925 -0
- package/build/dist/Models/DatabaseModels/StatusPageMonitorRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/StatusPagePrivateUser.js +32 -0
- package/build/dist/Models/DatabaseModels/StatusPagePrivateUser.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageResource.js +72 -0
- package/build/dist/Models/DatabaseModels/StatusPageResource.js.map +1 -1
- package/build/dist/Models/DatabaseModels/TraceDropFilter.js +9 -20
- package/build/dist/Models/DatabaseModels/TraceDropFilter.js.map +1 -1
- package/build/dist/Models/DatabaseModels/User.js +32 -0
- package/build/dist/Models/DatabaseModels/User.js.map +1 -1
- package/build/dist/Server/API/AIAgentDataAPI.js +21 -2
- package/build/dist/Server/API/AIAgentDataAPI.js.map +1 -1
- package/build/dist/Server/API/BaseAPI.js +11 -1
- package/build/dist/Server/API/BaseAPI.js.map +1 -1
- package/build/dist/Server/API/DashboardAPI.js +343 -10
- package/build/dist/Server/API/DashboardAPI.js.map +1 -1
- package/build/dist/Server/API/GitHubAPI.js +94 -167
- package/build/dist/Server/API/GitHubAPI.js.map +1 -1
- package/build/dist/Server/API/UserAPI.js +187 -2
- package/build/dist/Server/API/UserAPI.js.map +1 -1
- package/build/dist/Server/EnvironmentConfig.js +34 -4
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/GlobalCache.js +120 -0
- package/build/dist/Server/Infrastructure/GlobalCache.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/DataSourceOptions.js +5 -3
- package/build/dist/Server/Infrastructure/Postgres/DataSourceOptions.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.js +48 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786005052769-AddStatusPageMonitorRule.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786018109307-AddPerUserPasswordSalt.js +14 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786018109307-AddPerUserPasswordSalt.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786023262402-WidenHashedStringColumnsForScrypt.js +59 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786023262402-WidenHashedStringColumnsForScrypt.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786100000000-RestoreServiceLowerNameIndex.js +93 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786100000000-RestoreServiceLowerNameIndex.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786200000000-RestoreDroppedUniqueIndexes.js +101 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786200000000-RestoreDroppedUniqueIndexes.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786300000000-QuarantineUnboundGitHubInstallations.js +66 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786300000000-QuarantineUnboundGitHubInstallations.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Services/AlertStateTimelineService.js +19 -0
- package/build/dist/Server/Services/AlertStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js +57 -1
- package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
- package/build/dist/Server/Services/CephClusterService.js +26 -76
- package/build/dist/Server/Services/CephClusterService.js.map +1 -1
- package/build/dist/Server/Services/CloudResourceService.js +23 -73
- package/build/dist/Server/Services/CloudResourceService.js.map +1 -1
- package/build/dist/Server/Services/CodeRepositoryService.js +90 -2
- package/build/dist/Server/Services/CodeRepositoryService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +246 -2
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/DockerHostService.js +19 -69
- package/build/dist/Server/Services/DockerHostService.js.map +1 -1
- package/build/dist/Server/Services/DockerSwarmClusterService.js +27 -78
- package/build/dist/Server/Services/DockerSwarmClusterService.js.map +1 -1
- package/build/dist/Server/Services/HostService.js +58 -102
- package/build/dist/Server/Services/HostService.js.map +1 -1
- package/build/dist/Server/Services/IncidentStateTimelineService.js +19 -0
- package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +2 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/IoTFleetService.js +19 -69
- package/build/dist/Server/Services/IoTFleetService.js.map +1 -1
- package/build/dist/Server/Services/KubernetesClusterService.js +17 -68
- package/build/dist/Server/Services/KubernetesClusterService.js.map +1 -1
- package/build/dist/Server/Services/LabelService.js +42 -7
- package/build/dist/Server/Services/LabelService.js.map +1 -1
- package/build/dist/Server/Services/MetricTypeService.js +74 -0
- package/build/dist/Server/Services/MetricTypeService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +81 -9
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/MonitorStatusTimelineService.js +28 -0
- package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
- package/build/dist/Server/Services/MonitorTemplateService.js +60 -0
- package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
- package/build/dist/Server/Services/OpenTelemetryIngestService.js +155 -25
- package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
- package/build/dist/Server/Services/PodmanHostService.js +19 -69
- package/build/dist/Server/Services/PodmanHostService.js.map +1 -1
- package/build/dist/Server/Services/ProxmoxClusterService.js +23 -73
- package/build/dist/Server/Services/ProxmoxClusterService.js.map +1 -1
- package/build/dist/Server/Services/RumApplicationService.js +19 -70
- package/build/dist/Server/Services/RumApplicationService.js.map +1 -1
- package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js +20 -0
- package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js.map +1 -1
- package/build/dist/Server/Services/ServerlessFunctionService.js +24 -75
- package/build/dist/Server/Services/ServerlessFunctionService.js.map +1 -1
- package/build/dist/Server/Services/ServiceService.js +236 -61
- package/build/dist/Server/Services/ServiceService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js +603 -0
- package/build/dist/Server/Services/StatusPageMonitorRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/StatusPageMonitorRuleService.js +401 -0
- package/build/dist/Server/Services/StatusPageMonitorRuleService.js.map +1 -0
- package/build/dist/Server/Services/TelemetryEntityRelationshipService.js +1 -0
- package/build/dist/Server/Services/TelemetryEntityRelationshipService.js.map +1 -1
- package/build/dist/Server/Services/TelemetryEntityService.js +1 -0
- package/build/dist/Server/Services/TelemetryEntityService.js.map +1 -1
- package/build/dist/Server/Services/UserService.js +165 -0
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/CodeTools.js +31 -1
- package/build/dist/Server/Utils/AI/Toolbox/CodeTools.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +13 -0
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js +126 -4
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js.map +1 -1
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubInstallationBinding.js +136 -0
- package/build/dist/Server/Utils/CodeRepository/GitHub/GitHubInstallationBinding.js.map +1 -0
- package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +105 -29
- package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResource.js +56 -32
- package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorStatusTimeline.js +30 -3
- package/build/dist/Server/Utils/Monitor/MonitorStatusTimeline.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js +110 -98
- package/build/dist/Server/Utils/Monitor/MonitorStepsProjectValidator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorStepsReferenceExtractor.js +312 -0
- package/build/dist/Server/Utils/Monitor/MonitorStepsReferenceExtractor.js.map +1 -0
- package/build/dist/Server/Utils/PasswordHash.js +237 -0
- package/build/dist/Server/Utils/PasswordHash.js.map +1 -0
- package/build/dist/Server/Utils/SingleFlight.js +76 -0
- package/build/dist/Server/Utils/SingleFlight.js.map +1 -0
- package/build/dist/Server/Utils/StatusPage/MonitorRulePatternValidator.js +29 -0
- package/build/dist/Server/Utils/StatusPage/MonitorRulePatternValidator.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +78 -19
- package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
- package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js +160 -0
- package/build/dist/Server/Utils/Telemetry/ResourceHeartbeat.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/Telemetry.js +279 -104
- package/build/dist/Server/Utils/Telemetry/Telemetry.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardComponentType.js +1 -0
- package/build/dist/Types/Dashboard/DashboardComponentType.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js +1 -0
- package/build/dist/Types/Dashboard/DashboardComponents/ComponentArgument.js.map +1 -1
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardNetworkMapComponent.js +2 -0
- package/build/dist/Types/Dashboard/DashboardComponents/DashboardNetworkMapComponent.js.map +1 -0
- package/build/dist/Types/Dashboard/DashboardTemplates.js +368 -0
- package/build/dist/Types/Dashboard/DashboardTemplates.js.map +1 -1
- package/build/dist/Types/Database/BigIntColumnTransformer.js +66 -0
- package/build/dist/Types/Database/BigIntColumnTransformer.js.map +1 -0
- package/build/dist/Types/Database/ColumnLength.js +9 -1
- package/build/dist/Types/Database/ColumnLength.js.map +1 -1
- package/build/dist/Types/Database/DatabaseProperty.js +25 -0
- package/build/dist/Types/Database/DatabaseProperty.js.map +1 -1
- package/build/dist/Types/Database/NumericColumnValue.js +97 -0
- package/build/dist/Types/Database/NumericColumnValue.js.map +1 -0
- package/build/dist/Types/Database/TableColumn.js.map +1 -1
- package/build/dist/Types/Database/UnsynchronizedIndex.js +46 -0
- package/build/dist/Types/Database/UnsynchronizedIndex.js.map +1 -0
- package/build/dist/Types/Decimal.js +14 -3
- package/build/dist/Types/Decimal.js.map +1 -1
- package/build/dist/Types/HashedString.js +95 -5
- package/build/dist/Types/HashedString.js.map +1 -1
- package/build/dist/Types/Permission.js +42 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Port.js +15 -5
- package/build/dist/Types/Port.js.map +1 -1
- package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +51 -10
- package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/useLiveLogsRefresh.js +44 -0
- package/build/dist/UI/Components/LogsViewer/useLiveLogsRefresh.js.map +1 -0
- package/build/dist/UI/Components/LogsViewer/useLogsHistogram.js +75 -0
- package/build/dist/UI/Components/LogsViewer/useLogsHistogram.js.map +1 -0
- package/build/dist/UI/Components/Navbar/NavBar.js +3 -1
- package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
- package/build/dist/UI/Components/Navbar/NavBarMenuModal.js +19 -7
- package/build/dist/UI/Components/Navbar/NavBarMenuModal.js.map +1 -1
- package/build/dist/UI/Utils/ModelAPI/UserProjectsModelAPI.js +156 -0
- package/build/dist/UI/Utils/ModelAPI/UserProjectsModelAPI.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/DashboardNetworkMapComponent.js +114 -0
- package/build/dist/Utils/Dashboard/Components/DashboardNetworkMapComponent.js.map +1 -0
- package/build/dist/Utils/Dashboard/Components/Index.js +4 -0
- package/build/dist/Utils/Dashboard/Components/Index.js.map +1 -1
- package/build/dist/Utils/TeamMembersByProject.js +145 -0
- package/build/dist/Utils/TeamMembersByProject.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { getBigIntDatabaseTransformer } from "../../../Types/Database/BigIntColumnTransformer";
|
|
2
|
+
import { ValueTransformer } from "typeorm/decorator/options/ValueTransformer";
|
|
3
|
+
import { describe, expect, it } from "@jest/globals";
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
* Contract under test — the Postgres bigint round-trip used by counter
|
|
7
|
+
* columns.
|
|
8
|
+
*
|
|
9
|
+
* The interesting half is `to(undefined)`. TypeORM applies a column
|
|
10
|
+
* transformer BEFORE it decides whether the column was supplied at all:
|
|
11
|
+
*
|
|
12
|
+
* InsertQueryBuilder.createColumnValueExpression
|
|
13
|
+
* -> driver.preparePersistentValue (runs transformer.to)
|
|
14
|
+
* -> if (value === undefined) expression += "DEFAULT"
|
|
15
|
+
*
|
|
16
|
+
* so a transformer that answers `null` for `undefined` has already turned
|
|
17
|
+
* "the caller did not set this column" into "the caller set it to NULL" by
|
|
18
|
+
* the time that check runs, and the column DEFAULT is unreachable. On the
|
|
19
|
+
* drop-filter `droppedCount` columns — NOT NULL DEFAULT 0, written only by
|
|
20
|
+
* the ingest path — that made every single insert fail:
|
|
21
|
+
*
|
|
22
|
+
* null value in column "droppedCount" of relation "LogDropFilter"
|
|
23
|
+
* violates not-null constraint
|
|
24
|
+
*
|
|
25
|
+
* i.e. creating any log drop filter in the dashboard returned HTTP 500.
|
|
26
|
+
* github.com/OneUptime/oneuptime/issues/3026
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
const transformer: ValueTransformer = getBigIntDatabaseTransformer();
|
|
30
|
+
|
|
31
|
+
describe("getBigIntDatabaseTransformer().to", () => {
|
|
32
|
+
/*
|
|
33
|
+
* The regression. `undefined` and `null` are NOT interchangeable here:
|
|
34
|
+
* one means "use the column default", the other means "write NULL".
|
|
35
|
+
*/
|
|
36
|
+
it("passes undefined through so the column DEFAULT applies", () => {
|
|
37
|
+
expect(transformer.to(undefined)).toBeUndefined();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("does not confuse undefined with null", () => {
|
|
41
|
+
expect(transformer.to(undefined)).not.toBeNull();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("keeps an explicit null as null", () => {
|
|
45
|
+
expect(transformer.to(null)).toBeNull();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("stringifies a number, because the pg driver binds bigint as text", () => {
|
|
49
|
+
expect(transformer.to(0)).toBe("0");
|
|
50
|
+
expect(transformer.to(1)).toBe("1");
|
|
51
|
+
expect(transformer.to(42)).toBe("42");
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it("truncates rather than emitting a decimal Postgres would reject", () => {
|
|
55
|
+
expect(transformer.to(10.9)).toBe("10");
|
|
56
|
+
expect(transformer.to(-10.9)).toBe("-10");
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
/*
|
|
60
|
+
* The reason these columns are bigint at all: a sample filter on a
|
|
61
|
+
* high-volume project passes 2^31 well within a year, and a silently
|
|
62
|
+
* wrapped diagnostic counter is worse than no counter.
|
|
63
|
+
*/
|
|
64
|
+
it("carries a value past the 32-bit range without losing precision", () => {
|
|
65
|
+
expect(transformer.to(4_294_967_296)).toBe("4294967296");
|
|
66
|
+
expect(transformer.to(Number.MAX_SAFE_INTEGER)).toBe("9007199254740991");
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
/*
|
|
70
|
+
* `Math.trunc(NaN).toString()` is the string "NaN", which Postgres
|
|
71
|
+
* rejects with a syntax error naming neither the column nor the caller.
|
|
72
|
+
*/
|
|
73
|
+
it("refuses to emit a non-finite value as text", () => {
|
|
74
|
+
expect(transformer.to(NaN)).toBeNull();
|
|
75
|
+
expect(transformer.to(Infinity)).toBeNull();
|
|
76
|
+
expect(transformer.to(-Infinity)).toBeNull();
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
describe("getBigIntDatabaseTransformer().from", () => {
|
|
81
|
+
/*
|
|
82
|
+
* node-postgres hands bigint back as a string — it does not fit a JS
|
|
83
|
+
* number in the general case. Every value stored in these counters is
|
|
84
|
+
* inside MAX_SAFE_INTEGER, and the dashboard renders them as numbers.
|
|
85
|
+
*/
|
|
86
|
+
it("parses the string the driver returns into a number", () => {
|
|
87
|
+
expect(transformer.from("0")).toBe(0);
|
|
88
|
+
expect(transformer.from("42")).toBe(42);
|
|
89
|
+
expect(transformer.from("9007199254740991")).toBe(9007199254740991);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("accepts a number unchanged, in case a driver already parsed it", () => {
|
|
93
|
+
expect(transformer.from(7)).toBe(7);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("maps a null column to null rather than 0", () => {
|
|
97
|
+
expect(transformer.from(null)).toBeNull();
|
|
98
|
+
expect(transformer.from(undefined)).toBeNull();
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("maps unparsable text to null rather than NaN", () => {
|
|
102
|
+
expect(transformer.from("not a number")).toBeNull();
|
|
103
|
+
expect(transformer.from("")).toBeNull();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("round-trips a counter value", () => {
|
|
107
|
+
for (const value of [0, 1, 999, 4_294_967_296]) {
|
|
108
|
+
expect(transformer.from(transformer.to(value))).toBe(value);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
/*
|
|
114
|
+
* A miniature of TypeORM's own decision, so the consequence of the
|
|
115
|
+
* transformer's answer is asserted rather than left to a comment. Mirrors
|
|
116
|
+
* PostgresDriver.preparePersistentValue followed by
|
|
117
|
+
* InsertQueryBuilder.createColumnValueExpression.
|
|
118
|
+
*/
|
|
119
|
+
describe("the INSERT expression TypeORM derives from this transformer", () => {
|
|
120
|
+
type InsertExpression = "DEFAULT" | "NULL" | string;
|
|
121
|
+
|
|
122
|
+
function insertExpressionFor(value: number | null | undefined): string {
|
|
123
|
+
const prepared: unknown = transformer.to(value);
|
|
124
|
+
|
|
125
|
+
if (prepared === undefined) {
|
|
126
|
+
return "DEFAULT";
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (prepared === null) {
|
|
130
|
+
return "NULL";
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return String(prepared);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
it("emits DEFAULT for a counter the caller never set", () => {
|
|
137
|
+
const expression: InsertExpression = insertExpressionFor(undefined);
|
|
138
|
+
|
|
139
|
+
expect(expression).toBe("DEFAULT");
|
|
140
|
+
// The old inline transformer produced this, and NOT NULL rejected it.
|
|
141
|
+
expect(expression).not.toBe("NULL");
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it("emits the value for a counter the caller did set", () => {
|
|
145
|
+
expect(insertExpressionFor(5)).toBe("5");
|
|
146
|
+
});
|
|
147
|
+
});
|
|
@@ -42,7 +42,13 @@ describe("enum ColumnLength", () => {
|
|
|
42
42
|
});
|
|
43
43
|
|
|
44
44
|
test("ColumnLength.HashedString", () => {
|
|
45
|
-
|
|
45
|
+
/*
|
|
46
|
+
* Not 64 (a bare SHA-256 digest) since user passwords became scrypt
|
|
47
|
+
* hashes that carry their own cost parameters: `scrypt$N=...,r=...,p=...$
|
|
48
|
+
* <64 hex>`, around 90 characters. Narrowing this back would truncate
|
|
49
|
+
* every password on write and lock the whole instance out.
|
|
50
|
+
*/
|
|
51
|
+
expect(ColumnLength.HashedString).toEqual(255);
|
|
46
52
|
});
|
|
47
53
|
|
|
48
54
|
test("ColumnLength.Phone", () => {
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import Recurring from "../../../Types/Events/Recurring";
|
|
2
|
+
import RestrictionTimes from "../../../Types/OnCallDutyPolicy/RestrictionTimes";
|
|
3
|
+
import ObjectID from "../../../Types/ObjectID";
|
|
4
|
+
import Email from "../../../Types/Email";
|
|
5
|
+
import Color from "../../../Types/Color";
|
|
6
|
+
import EventInterval from "../../../Types/Events/EventInterval";
|
|
7
|
+
import PositiveNumber from "../../../Types/PositiveNumber";
|
|
8
|
+
import { ValueTransformer } from "typeorm/decorator/options/ValueTransformer";
|
|
9
|
+
import { describe, expect, it } from "@jest/globals";
|
|
10
|
+
|
|
11
|
+
/*
|
|
12
|
+
* Contract under test — `DatabaseProperty.getDatabaseTransformer()`, the one
|
|
13
|
+
* transformer behind nearly every non-primitive column in the schema.
|
|
14
|
+
*
|
|
15
|
+
* Its `to` has to keep `undefined` and `null` apart. TypeORM applies the
|
|
16
|
+
* transformer BEFORE deciding whether the caller supplied the column:
|
|
17
|
+
*
|
|
18
|
+
* InsertQueryBuilder.createColumnValueExpression
|
|
19
|
+
* -> driver.preparePersistentValue (runs transformer.to)
|
|
20
|
+
* -> if (value === undefined) expression += "DEFAULT"
|
|
21
|
+
*
|
|
22
|
+
* Every `toDatabase` implementation returns null for a falsy input, so
|
|
23
|
+
* before this guard an omitted column arrived as an explicit NULL and the
|
|
24
|
+
* column's DEFAULT was unreachable. On a NOT NULL column with a default that
|
|
25
|
+
* is a not-null constraint violation — an HTTP 500 — on every create that
|
|
26
|
+
* does not mention the column. That is the mechanism behind
|
|
27
|
+
* github.com/OneUptime/oneuptime/issues/3026 (the drop-filter counters), and
|
|
28
|
+
* `OnCallDutyPolicyScheduleLayer.rotation` / `.restrictionTimes` are the same
|
|
29
|
+
* shape: NOT NULL, with a JSON default, written through this transformer.
|
|
30
|
+
*
|
|
31
|
+
* UPDATE is unaffected in both directions — UpdateQueryBuilder drops
|
|
32
|
+
* undefined properties before the transformer runs — so this only ever
|
|
33
|
+
* changes an INSERT from "write NULL" to "use the DEFAULT".
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
interface TransformerCase {
|
|
37
|
+
name: string;
|
|
38
|
+
transformer: ValueTransformer;
|
|
39
|
+
sample: unknown;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const CASES: Array<TransformerCase> = [
|
|
43
|
+
{
|
|
44
|
+
name: "Recurring",
|
|
45
|
+
transformer: Recurring.getDatabaseTransformer(),
|
|
46
|
+
sample: Recurring.getDefault(),
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: "RestrictionTimes",
|
|
50
|
+
transformer: RestrictionTimes.getDatabaseTransformer(),
|
|
51
|
+
sample: RestrictionTimes.getDefault(),
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: "ObjectID",
|
|
55
|
+
transformer: ObjectID.getDatabaseTransformer(),
|
|
56
|
+
sample: new ObjectID("11111111-1111-4111-8111-111111111111"),
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: "Email",
|
|
60
|
+
transformer: Email.getDatabaseTransformer(),
|
|
61
|
+
sample: new Email("someone@oneuptime.com"),
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
name: "Color",
|
|
65
|
+
transformer: Color.getDatabaseTransformer(),
|
|
66
|
+
sample: new Color("#ff0000"),
|
|
67
|
+
},
|
|
68
|
+
];
|
|
69
|
+
|
|
70
|
+
describe.each(CASES)(
|
|
71
|
+
"$name.getDatabaseTransformer()",
|
|
72
|
+
({ transformer, sample }: TransformerCase) => {
|
|
73
|
+
it("passes undefined through so the column DEFAULT applies", () => {
|
|
74
|
+
expect(transformer.to(undefined)).toBeUndefined();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("does not collapse undefined into null", () => {
|
|
78
|
+
expect(transformer.to(undefined)).not.toBeNull();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
/*
|
|
82
|
+
* An explicit null is a different instruction — "store nothing here" —
|
|
83
|
+
* and still has to reach the column as NULL.
|
|
84
|
+
*/
|
|
85
|
+
it("keeps an explicit null as null", () => {
|
|
86
|
+
expect(transformer.to(null)).toBeNull();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("still serializes a real value", () => {
|
|
90
|
+
expect(transformer.to(sample)).not.toBeUndefined();
|
|
91
|
+
expect(transformer.to(sample)).not.toBeNull();
|
|
92
|
+
});
|
|
93
|
+
},
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
describe("the INSERT expression TypeORM derives for a NOT NULL column", () => {
|
|
97
|
+
/*
|
|
98
|
+
* A miniature of PostgresDriver.preparePersistentValue followed by
|
|
99
|
+
* InsertQueryBuilder.createColumnValueExpression, so the consequence is
|
|
100
|
+
* asserted rather than described.
|
|
101
|
+
*/
|
|
102
|
+
function insertExpressionFor(
|
|
103
|
+
transformer: ValueTransformer,
|
|
104
|
+
value: unknown,
|
|
105
|
+
): string {
|
|
106
|
+
const prepared: unknown = transformer.to(value);
|
|
107
|
+
|
|
108
|
+
if (prepared === undefined) {
|
|
109
|
+
return "DEFAULT";
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (prepared === null) {
|
|
113
|
+
return "NULL";
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return "?";
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
it("uses the schedule layer's rotation default instead of NULL", () => {
|
|
120
|
+
expect(
|
|
121
|
+
insertExpressionFor(Recurring.getDatabaseTransformer(), undefined),
|
|
122
|
+
).toBe("DEFAULT");
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it("uses the schedule layer's restriction default instead of NULL", () => {
|
|
126
|
+
expect(
|
|
127
|
+
insertExpressionFor(RestrictionTimes.getDatabaseTransformer(), undefined),
|
|
128
|
+
).toBe("DEFAULT");
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it("still binds a supplied value", () => {
|
|
132
|
+
const rotation: Recurring = new Recurring();
|
|
133
|
+
rotation.intervalType = EventInterval.Week;
|
|
134
|
+
rotation.intervalCount = new PositiveNumber(2);
|
|
135
|
+
|
|
136
|
+
expect(
|
|
137
|
+
insertExpressionFor(Recurring.getDatabaseTransformer(), rotation),
|
|
138
|
+
).toBe("?");
|
|
139
|
+
});
|
|
140
|
+
});
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import {
|
|
2
|
+
coerceNumericColumnValue,
|
|
3
|
+
isNumericTableColumnType,
|
|
4
|
+
} from "../../../Types/Database/NumericColumnValue";
|
|
5
|
+
import TableColumnType from "../../../Types/Database/TableColumnType";
|
|
6
|
+
import { describe, expect, it } from "@jest/globals";
|
|
7
|
+
|
|
8
|
+
/*
|
|
9
|
+
* Contract under test — normalizing a JSON value bound for a number column.
|
|
10
|
+
*
|
|
11
|
+
* HTML has no numeric input event: `<input type="number">` hands back
|
|
12
|
+
* `e.target.value`, a string. So the dashboard posted the JSON string "10"
|
|
13
|
+
* for every number field, and Postgres quietly coerced '10' to 10 on the way
|
|
14
|
+
* in — which is why nobody noticed until a server-side check read the value
|
|
15
|
+
* BEFORE it was stored:
|
|
16
|
+
*
|
|
17
|
+
* BadDataException: Sample percentage is required when the action is
|
|
18
|
+
* "Sample". Enter the percentage of matching logs to keep, between 1 and 99.
|
|
19
|
+
*
|
|
20
|
+
* on a form where the user had typed a percentage. HTTP 400 on a valid
|
|
21
|
+
* submission. github.com/OneUptime/oneuptime/issues/3027
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
describe("isNumericTableColumnType", () => {
|
|
25
|
+
it("covers every column type stored as a plain JS number", () => {
|
|
26
|
+
for (const type of [
|
|
27
|
+
TableColumnType.Number,
|
|
28
|
+
TableColumnType.SmallNumber,
|
|
29
|
+
TableColumnType.BigNumber,
|
|
30
|
+
TableColumnType.PositiveNumber,
|
|
31
|
+
TableColumnType.SmallPositiveNumber,
|
|
32
|
+
TableColumnType.BigPositiveNumber,
|
|
33
|
+
]) {
|
|
34
|
+
expect(isNumericTableColumnType(type)).toBe(true);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
/*
|
|
39
|
+
* The types that would be destroyed by coercion. `Port` and `Version` are
|
|
40
|
+
* wrapped objects and `Date` is a Date, however numeric they look.
|
|
41
|
+
*/
|
|
42
|
+
it("excludes types that only look numeric", () => {
|
|
43
|
+
for (const type of [
|
|
44
|
+
TableColumnType.Port,
|
|
45
|
+
TableColumnType.Version,
|
|
46
|
+
TableColumnType.Date,
|
|
47
|
+
TableColumnType.ShortText,
|
|
48
|
+
TableColumnType.LongText,
|
|
49
|
+
TableColumnType.Boolean,
|
|
50
|
+
TableColumnType.ObjectID,
|
|
51
|
+
TableColumnType.Entity,
|
|
52
|
+
TableColumnType.EntityArray,
|
|
53
|
+
TableColumnType.JSON,
|
|
54
|
+
]) {
|
|
55
|
+
expect(isNumericTableColumnType(type)).toBe(false);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("treats a missing type as not numeric", () => {
|
|
60
|
+
expect(isNumericTableColumnType(undefined)).toBe(false);
|
|
61
|
+
expect(isNumericTableColumnType(null)).toBe(false);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
describe("coerceNumericColumnValue", () => {
|
|
66
|
+
it("converts the string an <input type=number> produces", () => {
|
|
67
|
+
expect(coerceNumericColumnValue("10")).toBe(10);
|
|
68
|
+
expect(coerceNumericColumnValue("1")).toBe(1);
|
|
69
|
+
expect(coerceNumericColumnValue("99")).toBe(99);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("handles the shapes a browser can put in that string", () => {
|
|
73
|
+
expect(coerceNumericColumnValue("0")).toBe(0);
|
|
74
|
+
expect(coerceNumericColumnValue("-5")).toBe(-5);
|
|
75
|
+
expect(coerceNumericColumnValue("2.5")).toBe(2.5);
|
|
76
|
+
expect(coerceNumericColumnValue(" 42 ")).toBe(42);
|
|
77
|
+
expect(coerceNumericColumnValue("1e3")).toBe(1000);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("leaves a value that is already a number alone", () => {
|
|
81
|
+
expect(coerceNumericColumnValue(10)).toBe(10);
|
|
82
|
+
expect(coerceNumericColumnValue(0)).toBe(0);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("leaves null and undefined alone", () => {
|
|
86
|
+
expect(coerceNumericColumnValue(null)).toBeNull();
|
|
87
|
+
expect(coerceNumericColumnValue(undefined)).toBeUndefined();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
/*
|
|
91
|
+
* `Number("")` is 0. Writing a real 0 for a field the user cleared would
|
|
92
|
+
* be a silent data change, and for a sample percentage specifically, 0 is
|
|
93
|
+
* the value that used to mean "throw away half". Leave it untouched and
|
|
94
|
+
* let the field's own validation speak.
|
|
95
|
+
*/
|
|
96
|
+
it("does not turn a cleared field into zero", () => {
|
|
97
|
+
expect(coerceNumericColumnValue("")).toBe("");
|
|
98
|
+
expect(coerceNumericColumnValue(" ")).toBe(" ");
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("leaves unparsable text alone so validation can reject it by name", () => {
|
|
102
|
+
for (const garbage of ["abc", "10abc", "NaN", "Infinity", "--1", "1,000"]) {
|
|
103
|
+
expect(coerceNumericColumnValue(garbage)).toBe(garbage);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("never invents a non-finite number", () => {
|
|
108
|
+
const results: Array<unknown> = ["Infinity", "-Infinity", "NaN"].map(
|
|
109
|
+
(value: string) => {
|
|
110
|
+
return coerceNumericColumnValue(value);
|
|
111
|
+
},
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
for (const result of results) {
|
|
115
|
+
expect(typeof result).toBe("string");
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it("passes non-string, non-number values through untouched", () => {
|
|
120
|
+
const object: Record<string, string> = { a: "1" };
|
|
121
|
+
const array: Array<number> = [1];
|
|
122
|
+
|
|
123
|
+
expect(coerceNumericColumnValue(object)).toBe(object);
|
|
124
|
+
expect(coerceNumericColumnValue(array)).toBe(array);
|
|
125
|
+
expect(coerceNumericColumnValue(true)).toBe(true);
|
|
126
|
+
});
|
|
127
|
+
});
|
|
@@ -89,4 +89,41 @@ describe("Decimal", () => {
|
|
|
89
89
|
expect(restored.equals(original)).toBe(true);
|
|
90
90
|
});
|
|
91
91
|
});
|
|
92
|
+
|
|
93
|
+
/*
|
|
94
|
+
* A decimal column is declared `TableColumnType.Number`, so whatever
|
|
95
|
+
* reaches the transformer may be a Decimal, a string, or a plain number
|
|
96
|
+
* depending on how far the request body got through deserialization.
|
|
97
|
+
*/
|
|
98
|
+
describe("getDatabaseTransformer().to", () => {
|
|
99
|
+
const transformer: ReturnType<typeof Decimal.getDatabaseTransformer> =
|
|
100
|
+
Decimal.getDatabaseTransformer();
|
|
101
|
+
|
|
102
|
+
test("stores a Decimal instance as its string form", () => {
|
|
103
|
+
expect(transformer.to(new Decimal(125.5))).toBe("125.5");
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test("stores a raw string", () => {
|
|
107
|
+
expect(transformer.to("125.5")).toBe("125.5");
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test("stores a raw number", () => {
|
|
111
|
+
expect(transformer.to(125.5)).toBe("125.5");
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
/*
|
|
115
|
+
* `0` is a perfectly good decimal, and both of its columns are NOT NULL.
|
|
116
|
+
* A truthiness check used to send it to null, which the column rejects.
|
|
117
|
+
*/
|
|
118
|
+
test("stores zero rather than turning it into null", () => {
|
|
119
|
+
expect(transformer.to(0)).toBe("0");
|
|
120
|
+
expect(transformer.to("0")).toBe("0");
|
|
121
|
+
expect(transformer.to(new Decimal(0))).toBe("0");
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
test("keeps undefined distinct from null so a column DEFAULT applies", () => {
|
|
125
|
+
expect(transformer.to(undefined)).toBeUndefined();
|
|
126
|
+
expect(transformer.to(null)).toBeNull();
|
|
127
|
+
});
|
|
128
|
+
});
|
|
92
129
|
});
|