@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,215 @@
|
|
|
1
|
+
import Redis, { ClientType } from "../../../Server/Infrastructure/Redis";
|
|
2
|
+
import Semaphore, {
|
|
3
|
+
SemaphoreMutex,
|
|
4
|
+
} from "../../../Server/Infrastructure/Semaphore";
|
|
5
|
+
import { Mutex as RedisMutex } from "redis-semaphore";
|
|
6
|
+
import { afterEach, describe, expect, test } from "@jest/globals";
|
|
7
|
+
|
|
8
|
+
/*
|
|
9
|
+
* Companion to SemaphorePermit.test.ts, covering the OTHER half of Semaphore:
|
|
10
|
+
* lock()/release(), the exclusive mutex.
|
|
11
|
+
*
|
|
12
|
+
* This is the primitive every cross-process critical section in the codebase
|
|
13
|
+
* runs on -- project counters, timeline writes, the SLO sweep, and the
|
|
14
|
+
* first-Master-Admin election (GHSA-3qqq-hprx-g2jw). What is pinned here is the
|
|
15
|
+
* option plumbing between our wrapper and redis-semaphore: a lockTimeout or
|
|
16
|
+
* acquireTimeout silently dropped on the way through would not fail any test
|
|
17
|
+
* about election outcomes, it would just quietly turn a bounded wait into an
|
|
18
|
+
* unbounded one, or a self-refreshing lock into one with the library default.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
interface MockMutex {
|
|
22
|
+
acquire: jest.Mock;
|
|
23
|
+
release: jest.Mock;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
jest.mock("redis-semaphore", () => {
|
|
27
|
+
const actual: Record<string, unknown> = jest.requireActual(
|
|
28
|
+
"redis-semaphore",
|
|
29
|
+
) as Record<string, unknown>;
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
...actual,
|
|
33
|
+
Mutex: jest.fn().mockImplementation((): MockMutex => {
|
|
34
|
+
return {
|
|
35
|
+
acquire: jest.fn(async (): Promise<void> => {}),
|
|
36
|
+
release: jest.fn(async (): Promise<void> => {}),
|
|
37
|
+
};
|
|
38
|
+
}),
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const redisMutexConstructor: jest.MockedClass<typeof RedisMutex> =
|
|
43
|
+
RedisMutex as jest.MockedClass<typeof RedisMutex>;
|
|
44
|
+
|
|
45
|
+
function mockRedisClient(): ClientType {
|
|
46
|
+
const client: ClientType = {} as ClientType;
|
|
47
|
+
jest.spyOn(Redis, "getClient").mockReturnValue(client);
|
|
48
|
+
return client;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function lastMockMutex(): MockMutex {
|
|
52
|
+
/*
|
|
53
|
+
* Indexed rather than .at(-1): this project targets es2017, so
|
|
54
|
+
* Array.prototype.at is outside its lib.
|
|
55
|
+
*/
|
|
56
|
+
const results: Array<{ value: unknown }> = redisMutexConstructor.mock.results;
|
|
57
|
+
const result: unknown = results[results.length - 1]?.value;
|
|
58
|
+
return result as MockMutex;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
afterEach(() => {
|
|
62
|
+
jest.restoreAllMocks();
|
|
63
|
+
redisMutexConstructor.mockClear();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
describe("Semaphore exclusive mutex", () => {
|
|
67
|
+
test("constructs and acquires with every option forwarded", async () => {
|
|
68
|
+
const client: ClientType = mockRedisClient();
|
|
69
|
+
|
|
70
|
+
const mutex: SemaphoreMutex = await Semaphore.lock({
|
|
71
|
+
key: "instance",
|
|
72
|
+
namespace: "UserService.firstMasterAdminElection",
|
|
73
|
+
lockTimeout: 10_000,
|
|
74
|
+
acquireTimeout: 5_000,
|
|
75
|
+
acquireAttemptsLimit: 4,
|
|
76
|
+
retryInterval: 25,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
expect(redisMutexConstructor).toHaveBeenCalledWith(
|
|
80
|
+
client,
|
|
81
|
+
"UserService.firstMasterAdminElection-instance",
|
|
82
|
+
{
|
|
83
|
+
lockTimeout: 10_000,
|
|
84
|
+
acquireTimeout: 5_000,
|
|
85
|
+
acquireAttemptsLimit: 4,
|
|
86
|
+
retryInterval: 25,
|
|
87
|
+
},
|
|
88
|
+
);
|
|
89
|
+
expect(lastMockMutex().acquire).toHaveBeenCalledTimes(1);
|
|
90
|
+
expect(mutex).toBe(lastMockMutex());
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test("composes the Redis key as namespace-key", async () => {
|
|
94
|
+
mockRedisClient();
|
|
95
|
+
|
|
96
|
+
await Semaphore.lock({
|
|
97
|
+
key: "project-1",
|
|
98
|
+
namespace: "ProjectService.incidentCounter",
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
/*
|
|
102
|
+
* Callers coordinate purely by agreeing on this string. Two replicas that
|
|
103
|
+
* compose it differently exclude nobody.
|
|
104
|
+
*/
|
|
105
|
+
expect(redisMutexConstructor).toHaveBeenCalledWith(
|
|
106
|
+
expect.anything(),
|
|
107
|
+
"ProjectService.incidentCounter-project-1",
|
|
108
|
+
expect.anything(),
|
|
109
|
+
);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
test("defaults lockTimeout to five seconds when none is supplied", async () => {
|
|
113
|
+
mockRedisClient();
|
|
114
|
+
|
|
115
|
+
await Semaphore.lock({
|
|
116
|
+
key: "project-1",
|
|
117
|
+
namespace: "ProjectService.incidentCounter",
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
expect(redisMutexConstructor).toHaveBeenCalledWith(
|
|
121
|
+
expect.anything(),
|
|
122
|
+
"ProjectService.incidentCounter-project-1",
|
|
123
|
+
{ lockTimeout: 5_000 },
|
|
124
|
+
);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test("omits options the caller did not set rather than passing undefined", async () => {
|
|
128
|
+
mockRedisClient();
|
|
129
|
+
|
|
130
|
+
await Semaphore.lock({
|
|
131
|
+
key: "project-1",
|
|
132
|
+
namespace: "ProjectService.incidentCounter",
|
|
133
|
+
acquireTimeout: 1_000,
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
const options: Record<string, unknown> = redisMutexConstructor.mock
|
|
137
|
+
.calls[0]![2] as unknown as Record<string, unknown>;
|
|
138
|
+
|
|
139
|
+
/*
|
|
140
|
+
* redis-semaphore destructures its options with defaults, and an explicit
|
|
141
|
+
* `undefined` does take the default -- but only because of how it is
|
|
142
|
+
* written. Not passing the key at all is what actually guarantees the
|
|
143
|
+
* library's own default applies.
|
|
144
|
+
*/
|
|
145
|
+
expect(Object.keys(options).sort()).toEqual([
|
|
146
|
+
"acquireTimeout",
|
|
147
|
+
"lockTimeout",
|
|
148
|
+
]);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
test("rejects when Redis is not connected", async () => {
|
|
152
|
+
jest.spyOn(Redis, "getClient").mockReturnValue(null);
|
|
153
|
+
|
|
154
|
+
await expect(
|
|
155
|
+
Semaphore.lock({
|
|
156
|
+
key: "instance",
|
|
157
|
+
namespace: "UserService.firstMasterAdminElection",
|
|
158
|
+
}),
|
|
159
|
+
).rejects.toThrow(/Redis client is not connected/i);
|
|
160
|
+
|
|
161
|
+
/*
|
|
162
|
+
* Callers treat a throw as "I do not hold the lock". Constructing a mutex
|
|
163
|
+
* against a dead client and returning it would be worse than failing.
|
|
164
|
+
*/
|
|
165
|
+
expect(redisMutexConstructor).not.toHaveBeenCalled();
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
test("propagates acquisition failures without returning an unheld mutex", async () => {
|
|
169
|
+
mockRedisClient();
|
|
170
|
+
const acquireError: Error = new Error("acquire timeout");
|
|
171
|
+
redisMutexConstructor.mockImplementationOnce(() => {
|
|
172
|
+
return {
|
|
173
|
+
acquire: jest.fn(async (): Promise<void> => {
|
|
174
|
+
throw acquireError;
|
|
175
|
+
}),
|
|
176
|
+
release: jest.fn(async (): Promise<void> => {}),
|
|
177
|
+
} as unknown as RedisMutex;
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
/*
|
|
181
|
+
* The load-bearing failure mode for the Master Admin election: a caller
|
|
182
|
+
* that got a mutex handle back would run its critical section believing it
|
|
183
|
+
* was serialized.
|
|
184
|
+
*/
|
|
185
|
+
await expect(
|
|
186
|
+
Semaphore.lock({
|
|
187
|
+
key: "instance",
|
|
188
|
+
namespace: "UserService.firstMasterAdminElection",
|
|
189
|
+
}),
|
|
190
|
+
).rejects.toBe(acquireError);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
test("releases the exact acquired mutex", async () => {
|
|
194
|
+
mockRedisClient();
|
|
195
|
+
|
|
196
|
+
const mutex: SemaphoreMutex = await Semaphore.lock({
|
|
197
|
+
key: "instance",
|
|
198
|
+
namespace: "UserService.firstMasterAdminElection",
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
await Semaphore.release(mutex);
|
|
202
|
+
|
|
203
|
+
expect(lastMockMutex().release).toHaveBeenCalledTimes(1);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
test("two different keys produce two independent mutexes", async () => {
|
|
207
|
+
mockRedisClient();
|
|
208
|
+
|
|
209
|
+
await Semaphore.lock({ key: "a", namespace: "ns" });
|
|
210
|
+
await Semaphore.lock({ key: "b", namespace: "ns" });
|
|
211
|
+
|
|
212
|
+
expect(redisMutexConstructor.mock.calls[0]![1]).toBe("ns-a");
|
|
213
|
+
expect(redisMutexConstructor.mock.calls[1]![1]).toBe("ns-b");
|
|
214
|
+
});
|
|
215
|
+
});
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { AddPerUserPasswordSalt1786018109307 } from "../../../Server/Infrastructure/Postgres/SchemaMigrations/1786018109307-AddPerUserPasswordSalt";
|
|
2
|
+
import SchemaMigrations from "../../../Server/Infrastructure/Postgres/SchemaMigrations/Index";
|
|
3
|
+
import { QueryRunner } from "typeorm";
|
|
4
|
+
import { describe, expect, test } from "@jest/globals";
|
|
5
|
+
|
|
6
|
+
/*
|
|
7
|
+
* The migration that adds the per-user salt columns.
|
|
8
|
+
*
|
|
9
|
+
* Three things have to hold together or per-user salts silently do not exist
|
|
10
|
+
* in a deployed instance:
|
|
11
|
+
*
|
|
12
|
+
* 1. up() adds exactly the two columns, nullable — existing rows must keep
|
|
13
|
+
* their (unsalted) passwords working, so a NOT NULL column or a default
|
|
14
|
+
* would be wrong;
|
|
15
|
+
* 2. down() removes exactly what up() added;
|
|
16
|
+
* 3. the migration is registered in SchemaMigrations/Index.ts. An
|
|
17
|
+
* unregistered migration never runs on boot, so the column would be
|
|
18
|
+
* missing while the code writes to it — every login and every signup
|
|
19
|
+
* would 500.
|
|
20
|
+
*
|
|
21
|
+
* Pure SQL-contract assertions against a fake QueryRunner. No Postgres.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
type MakeQueryRunnerResult = {
|
|
25
|
+
runner: QueryRunner;
|
|
26
|
+
statements: Array<string>;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
type MakeQueryRunnerFunction = () => MakeQueryRunnerResult;
|
|
30
|
+
|
|
31
|
+
const makeQueryRunner: MakeQueryRunnerFunction = (): MakeQueryRunnerResult => {
|
|
32
|
+
const statements: Array<string> = [];
|
|
33
|
+
|
|
34
|
+
const query: (...args: Array<unknown>) => Promise<undefined> = (
|
|
35
|
+
...args: Array<unknown>
|
|
36
|
+
): Promise<undefined> => {
|
|
37
|
+
statements.push(String(args[0]));
|
|
38
|
+
return Promise.resolve(undefined);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
runner: { query } as unknown as QueryRunner,
|
|
43
|
+
statements,
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
describe("AddPerUserPasswordSalt1786018109307 — SQL contract", () => {
|
|
48
|
+
test("up() adds exactly the two salt columns and nothing else", async () => {
|
|
49
|
+
const { runner, statements } = makeQueryRunner();
|
|
50
|
+
|
|
51
|
+
await new AddPerUserPasswordSalt1786018109307().up(runner);
|
|
52
|
+
|
|
53
|
+
expect(statements).toEqual([
|
|
54
|
+
`ALTER TABLE "User" ADD "passwordSalt" character varying(100)`,
|
|
55
|
+
`ALTER TABLE "StatusPagePrivateUser" ADD "passwordSalt" character varying(100)`,
|
|
56
|
+
]);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test("the columns are nullable, so every existing password keeps working", async () => {
|
|
60
|
+
/*
|
|
61
|
+
* Rows written before salts existed have no salt, and are verified
|
|
62
|
+
* against the legacy unsalted scheme until the next successful login
|
|
63
|
+
* re-hashes them. A NOT NULL column would have needed a backfill value,
|
|
64
|
+
* and any backfilled salt would be wrong for the hash already stored.
|
|
65
|
+
*/
|
|
66
|
+
const { runner, statements } = makeQueryRunner();
|
|
67
|
+
|
|
68
|
+
await new AddPerUserPasswordSalt1786018109307().up(runner);
|
|
69
|
+
|
|
70
|
+
for (const statement of statements) {
|
|
71
|
+
expect(statement).not.toMatch(/NOT NULL/i);
|
|
72
|
+
expect(statement).not.toMatch(/DEFAULT/i);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test("the column is wide enough for the salts the code generates", async () => {
|
|
77
|
+
/*
|
|
78
|
+
* HashedString.generateSalt() produces 64 hex characters. A narrower
|
|
79
|
+
* column would truncate on write and the password would never verify
|
|
80
|
+
* again.
|
|
81
|
+
*/
|
|
82
|
+
const { runner, statements } = makeQueryRunner();
|
|
83
|
+
|
|
84
|
+
await new AddPerUserPasswordSalt1786018109307().up(runner);
|
|
85
|
+
|
|
86
|
+
for (const statement of statements) {
|
|
87
|
+
const width: RegExpMatchArray | null = statement.match(
|
|
88
|
+
/character varying\((\d+)\)/,
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
expect(width).not.toBeNull();
|
|
92
|
+
expect(Number(width![1])).toBeGreaterThanOrEqual(64);
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test("down() drops exactly what up() added", async () => {
|
|
97
|
+
const { runner, statements } = makeQueryRunner();
|
|
98
|
+
|
|
99
|
+
await new AddPerUserPasswordSalt1786018109307().down(runner);
|
|
100
|
+
|
|
101
|
+
expect(statements).toEqual([
|
|
102
|
+
`ALTER TABLE "StatusPagePrivateUser" DROP COLUMN "passwordSalt"`,
|
|
103
|
+
`ALTER TABLE "User" DROP COLUMN "passwordSalt"`,
|
|
104
|
+
]);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
test("up() and down() touch the same tables", async () => {
|
|
108
|
+
const up: MakeQueryRunnerResult = makeQueryRunner();
|
|
109
|
+
const down: MakeQueryRunnerResult = makeQueryRunner();
|
|
110
|
+
|
|
111
|
+
await new AddPerUserPasswordSalt1786018109307().up(up.runner);
|
|
112
|
+
await new AddPerUserPasswordSalt1786018109307().down(down.runner);
|
|
113
|
+
|
|
114
|
+
type TablesFunction = (statements: Array<string>) => Array<string>;
|
|
115
|
+
|
|
116
|
+
const tables: TablesFunction = (
|
|
117
|
+
statements: Array<string>,
|
|
118
|
+
): Array<string> => {
|
|
119
|
+
return statements
|
|
120
|
+
.map((statement: string) => {
|
|
121
|
+
return statement.match(/ALTER TABLE "([^"]+)"/)?.[1] as string;
|
|
122
|
+
})
|
|
123
|
+
.sort();
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
expect(tables(up.statements)).toEqual(tables(down.statements));
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
describe("AddPerUserPasswordSalt1786018109307 — registration", () => {
|
|
131
|
+
test("is registered in SchemaMigrations/Index.ts", () => {
|
|
132
|
+
/*
|
|
133
|
+
* The step that is easiest to forget and that fails the loudest in
|
|
134
|
+
* production: an unregistered migration is dead code, so the column never
|
|
135
|
+
* appears and the write path fails on the column that is not there.
|
|
136
|
+
*/
|
|
137
|
+
expect(SchemaMigrations).toContain(AddPerUserPasswordSalt1786018109307);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
test("its class name carries the timestamp its filename does", () => {
|
|
141
|
+
// TypeORM orders migrations by the timestamp suffix on the class name.
|
|
142
|
+
expect(AddPerUserPasswordSalt1786018109307.name).toBe(
|
|
143
|
+
"AddPerUserPasswordSalt1786018109307",
|
|
144
|
+
);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
test("runs after every migration registered before it", () => {
|
|
148
|
+
const names: Array<string> = SchemaMigrations.map(
|
|
149
|
+
(migration: { name: string }) => {
|
|
150
|
+
return migration.name;
|
|
151
|
+
},
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
const index: number = names.indexOf("AddPerUserPasswordSalt1786018109307");
|
|
155
|
+
|
|
156
|
+
expect(index).toBeGreaterThan(-1);
|
|
157
|
+
|
|
158
|
+
type TimestampFunction = (name: string) => number;
|
|
159
|
+
|
|
160
|
+
const timestampOf: TimestampFunction = (name: string): number => {
|
|
161
|
+
return Number(name.match(/(\d+)$/)?.[1] || 0);
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
for (const earlier of names.slice(0, index)) {
|
|
165
|
+
expect(timestampOf(earlier)).toBeLessThan(1786018109307);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
test("appears exactly once", () => {
|
|
170
|
+
const occurrences: number = SchemaMigrations.filter(
|
|
171
|
+
(migration: { name: string }) => {
|
|
172
|
+
return migration.name === "AddPerUserPasswordSalt1786018109307";
|
|
173
|
+
},
|
|
174
|
+
).length;
|
|
175
|
+
|
|
176
|
+
expect(occurrences).toBe(1);
|
|
177
|
+
});
|
|
178
|
+
});
|