@harperfast/harper 5.2.13 → 5.3.0-beta.1
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/agent/mcpTools.ts +1 -1
- package/agent/session.ts +25 -14
- package/bin/cliOperations.ts +58 -9
- package/bin/copyDb.ts +282 -59
- package/bin/deploySetup.ts +16 -5
- package/bin/harper.ts +1 -1
- package/bin/help.ts +4 -1
- package/bin/lite.ts +4 -1
- package/bin/restart.ts +120 -4
- package/bin/run.ts +6 -11
- package/bin/upgrade.js +7 -3
- package/bin/workloadIdentity.ts +119 -0
- package/components/Application.ts +3436 -242
- package/components/ApplicationScope.ts +8 -0
- package/components/EntryHandler.ts +59 -39
- package/components/OptionsWatcher.ts +440 -98
- package/components/RuntimeModuleTracker.ts +38 -7
- package/components/Scope.ts +56 -15
- package/components/awaitRestart.ts +84 -0
- package/components/componentLoader.ts +381 -32
- package/components/componentPreparationLock.ts +16 -5
- package/components/deploymentOperations.ts +4 -1
- package/components/deploymentRecorder.ts +9 -2
- package/components/mcp/adapters/harperHttp.ts +4 -0
- package/components/mcp/listChanged.ts +4 -0
- package/components/mcp/toolRegistry.ts +2 -0
- package/components/mcp/tools/operations.ts +9 -0
- package/components/mcp/tools/schemas/operationDescriptions.ts +2 -2
- package/components/operations.js +537 -113
- package/components/operationsValidation.js +98 -3
- package/components/packageComponent.ts +25 -1
- package/components/requestRestart.ts +11 -0
- package/components/status/ComponentStatusRegistry.ts +59 -0
- package/config/RootConfigWatcher.ts +240 -40
- package/config/configReadRetry.ts +62 -0
- package/config/configUtils.ts +357 -48
- package/config/harperConfigEnvVars.ts +170 -27
- package/config/parseConfigFile.ts +34 -0
- package/config/readConfigFileSync.ts +44 -0
- package/config/watcherArming.ts +59 -0
- package/config-root.schema.json +33 -0
- package/dataLayer/blobBackup.ts +160 -50
- package/dataLayer/delete.ts +6 -1
- package/dataLayer/harperBridge/ResourceBridge.ts +80 -10
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.js +3 -1
- package/dataLayer/hdbInfoController.ts +34 -1
- package/dataLayer/insert.ts +44 -1
- package/dataLayer/rocksdbBackup.ts +53 -10
- package/dataLayer/schema.ts +11 -1
- package/dataLayer/schemaDescribe.ts +8 -1
- package/dist/agent/mcpTools.js +1 -1
- package/dist/agent/mcpTools.js.map +1 -1
- package/dist/agent/session.d.ts +22 -0
- package/dist/agent/session.js +26 -15
- package/dist/agent/session.js.map +1 -1
- package/dist/bin/cliOperations.js +61 -9
- package/dist/bin/cliOperations.js.map +1 -1
- package/dist/bin/copyDb.d.ts +12 -1
- package/dist/bin/copyDb.js +248 -60
- package/dist/bin/copyDb.js.map +1 -1
- package/dist/bin/deploySetup.d.ts +2 -0
- package/dist/bin/deploySetup.js +11 -3
- package/dist/bin/deploySetup.js.map +1 -1
- package/dist/bin/harper.js +1 -1
- package/dist/bin/harper.js.map +1 -1
- package/dist/bin/help.js +4 -1
- package/dist/bin/help.js.map +1 -1
- package/dist/bin/lite.js +4 -1
- package/dist/bin/lite.js.map +1 -1
- package/dist/bin/restart.js +91 -6
- package/dist/bin/restart.js.map +1 -1
- package/dist/bin/run.js +4 -10
- package/dist/bin/run.js.map +1 -1
- package/dist/bin/upgrade.js +4 -3
- package/dist/bin/upgrade.js.map +1 -1
- package/dist/bin/workloadIdentity.d.ts +18 -0
- package/dist/bin/workloadIdentity.js +100 -0
- package/dist/bin/workloadIdentity.js.map +1 -0
- package/dist/components/Application.d.ts +235 -17
- package/dist/components/Application.js +3038 -238
- package/dist/components/Application.js.map +1 -1
- package/dist/components/ApplicationScope.d.ts +8 -0
- package/dist/components/ApplicationScope.js +7 -0
- package/dist/components/ApplicationScope.js.map +1 -1
- package/dist/components/EntryHandler.js +26 -10
- package/dist/components/EntryHandler.js.map +1 -1
- package/dist/components/OptionsWatcher.d.ts +4 -0
- package/dist/components/OptionsWatcher.js +440 -99
- package/dist/components/OptionsWatcher.js.map +1 -1
- package/dist/components/RuntimeModuleTracker.js +40 -6
- package/dist/components/RuntimeModuleTracker.js.map +1 -1
- package/dist/components/Scope.js +52 -13
- package/dist/components/Scope.js.map +1 -1
- package/dist/components/awaitRestart.d.ts +33 -0
- package/dist/components/awaitRestart.js +61 -0
- package/dist/components/awaitRestart.js.map +1 -0
- package/dist/components/componentLoader.d.ts +38 -1
- package/dist/components/componentLoader.js +313 -24
- package/dist/components/componentLoader.js.map +1 -1
- package/dist/components/componentPreparationLock.d.ts +5 -0
- package/dist/components/componentPreparationLock.js +14 -6
- package/dist/components/componentPreparationLock.js.map +1 -1
- package/dist/components/deploymentOperations.js +4 -1
- package/dist/components/deploymentOperations.js.map +1 -1
- package/dist/components/deploymentRecorder.d.ts +4 -2
- package/dist/components/deploymentRecorder.js +1 -0
- package/dist/components/deploymentRecorder.js.map +1 -1
- package/dist/components/mcp/adapters/harperHttp.js +4 -0
- package/dist/components/mcp/adapters/harperHttp.js.map +1 -1
- package/dist/components/mcp/listChanged.js +5 -0
- package/dist/components/mcp/listChanged.js.map +1 -1
- package/dist/components/mcp/toolRegistry.d.ts +1 -0
- package/dist/components/mcp/toolRegistry.js.map +1 -1
- package/dist/components/mcp/tools/operations.d.ts +5 -0
- package/dist/components/mcp/tools/operations.js +9 -0
- package/dist/components/mcp/tools/operations.js.map +1 -1
- package/dist/components/mcp/tools/schemas/operationDescriptions.js +2 -2
- package/dist/components/mcp/tools/schemas/operationDescriptions.js.map +1 -1
- package/dist/components/operations.d.ts +28 -0
- package/dist/components/operations.js +476 -113
- package/dist/components/operations.js.map +1 -1
- package/dist/components/operationsValidation.js +97 -3
- package/dist/components/operationsValidation.js.map +1 -1
- package/dist/components/packageComponent.js +24 -0
- package/dist/components/packageComponent.js.map +1 -1
- package/dist/components/requestRestart.d.ts +1 -0
- package/dist/components/requestRestart.js +7 -0
- package/dist/components/requestRestart.js.map +1 -1
- package/dist/components/status/ComponentStatusRegistry.d.ts +0 -4
- package/dist/components/status/ComponentStatusRegistry.js +63 -0
- package/dist/components/status/ComponentStatusRegistry.js.map +1 -1
- package/dist/config/RootConfigWatcher.d.ts +9 -1
- package/dist/config/RootConfigWatcher.js +228 -37
- package/dist/config/RootConfigWatcher.js.map +1 -1
- package/dist/config/configReadRetry.d.ts +8 -0
- package/dist/config/configReadRetry.js +62 -0
- package/dist/config/configReadRetry.js.map +1 -0
- package/dist/config/configUtils.d.ts +11 -2
- package/dist/config/configUtils.js +304 -47
- package/dist/config/configUtils.js.map +1 -1
- package/dist/config/harperConfigEnvVars.d.ts +16 -0
- package/dist/config/harperConfigEnvVars.js +162 -25
- package/dist/config/harperConfigEnvVars.js.map +1 -1
- package/dist/config/parseConfigFile.d.ts +4 -0
- package/dist/config/parseConfigFile.js +35 -0
- package/dist/config/parseConfigFile.js.map +1 -0
- package/dist/config/readConfigFileSync.d.ts +1 -0
- package/dist/config/readConfigFileSync.js +47 -0
- package/dist/config/readConfigFileSync.js.map +1 -0
- package/dist/config/watcherArming.d.ts +15 -0
- package/dist/config/watcherArming.js +59 -0
- package/dist/config/watcherArming.js.map +1 -0
- package/dist/dataLayer/blobBackup.d.ts +49 -20
- package/dist/dataLayer/blobBackup.js +139 -50
- package/dist/dataLayer/blobBackup.js.map +1 -1
- package/dist/dataLayer/delete.js +1 -1
- package/dist/dataLayer/delete.js.map +1 -1
- package/dist/dataLayer/harperBridge/ResourceBridge.d.ts +14 -1
- package/dist/dataLayer/harperBridge/ResourceBridge.js +72 -12
- package/dist/dataLayer/harperBridge/ResourceBridge.js.map +1 -1
- package/dist/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.d.ts +3 -1
- package/dist/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.js +3 -1
- package/dist/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.js.map +1 -1
- package/dist/dataLayer/hdbInfoController.d.ts +10 -0
- package/dist/dataLayer/hdbInfoController.js +30 -1
- package/dist/dataLayer/hdbInfoController.js.map +1 -1
- package/dist/dataLayer/insert.d.ts +9 -1
- package/dist/dataLayer/insert.js +30 -0
- package/dist/dataLayer/insert.js.map +1 -1
- package/dist/dataLayer/rocksdbBackup.d.ts +2 -2
- package/dist/dataLayer/rocksdbBackup.js +45 -8
- package/dist/dataLayer/rocksdbBackup.js.map +1 -1
- package/dist/dataLayer/schema.js +8 -0
- package/dist/dataLayer/schema.js.map +1 -1
- package/dist/dataLayer/schemaDescribe.js +8 -1
- package/dist/dataLayer/schemaDescribe.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/json/systemSchema.json +55 -0
- package/dist/resources/DatabaseTransaction.d.ts +77 -0
- package/dist/resources/DatabaseTransaction.js +586 -54
- package/dist/resources/DatabaseTransaction.js.map +1 -1
- package/dist/resources/LMDBTransaction.d.ts +2 -1
- package/dist/resources/LMDBTransaction.js +43 -6
- package/dist/resources/LMDBTransaction.js.map +1 -1
- package/dist/resources/PrimaryRocksDatabase.d.ts +1 -0
- package/dist/resources/PrimaryRocksDatabase.js +49 -5
- package/dist/resources/PrimaryRocksDatabase.js.map +1 -1
- package/dist/resources/RecordEncoder.d.ts +20 -0
- package/dist/resources/RecordEncoder.js +110 -9
- package/dist/resources/RecordEncoder.js.map +1 -1
- package/dist/resources/RequestTarget.d.ts +2 -0
- package/dist/resources/RequestTarget.js.map +1 -1
- package/dist/resources/Resource.js +117 -24
- package/dist/resources/Resource.js.map +1 -1
- package/dist/resources/ResourceInterface.d.ts +28 -1
- package/dist/resources/ResourceInterface.js.map +1 -1
- package/dist/resources/RocksIndexStore.d.ts +6 -1
- package/dist/resources/RocksIndexStore.js +24 -9
- package/dist/resources/RocksIndexStore.js.map +1 -1
- package/dist/resources/RocksTransactionLogStore.d.ts +24 -1
- package/dist/resources/RocksTransactionLogStore.js +160 -49
- package/dist/resources/RocksTransactionLogStore.js.map +1 -1
- package/dist/resources/Table.d.ts +165 -10
- package/dist/resources/Table.js +1805 -303
- package/dist/resources/Table.js.map +1 -1
- package/dist/resources/analytics/write.js +10 -3
- package/dist/resources/analytics/write.js.map +1 -1
- package/dist/resources/auditStore.d.ts +181 -2
- package/dist/resources/auditStore.js +640 -29
- package/dist/resources/auditStore.js.map +1 -1
- package/dist/resources/blob.d.ts +129 -9
- package/dist/resources/blob.js +992 -114
- package/dist/resources/blob.js.map +1 -1
- package/dist/resources/branchDatabase.d.ts +48 -0
- package/dist/resources/branchDatabase.js +892 -0
- package/dist/resources/branchDatabase.js.map +1 -0
- package/dist/resources/crdt.js +50 -12
- package/dist/resources/crdt.js.map +1 -1
- package/dist/resources/dataLoader.js +3 -4
- package/dist/resources/dataLoader.js.map +1 -1
- package/dist/resources/databases.d.ts +157 -14
- package/dist/resources/databases.js +1462 -325
- package/dist/resources/databases.js.map +1 -1
- package/dist/resources/defineTable.d.ts +10 -2
- package/dist/resources/defineTable.js +9 -1
- package/dist/resources/defineTable.js.map +1 -1
- package/dist/resources/derivedIndexRegistry.d.ts +5 -0
- package/dist/resources/derivedIndexRegistry.js +68 -0
- package/dist/resources/derivedIndexRegistry.js.map +1 -0
- package/dist/resources/derivedIndexRuntime.d.ts +215 -0
- package/dist/resources/derivedIndexRuntime.js +2027 -0
- package/dist/resources/derivedIndexRuntime.js.map +1 -0
- package/dist/resources/graphql.d.ts +1 -1
- package/dist/resources/graphql.js +52 -16
- package/dist/resources/graphql.js.map +1 -1
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.d.ts +103 -9
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js +854 -41
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js.map +1 -1
- package/dist/resources/indexes/hnswDerivedIndex.d.ts +67 -0
- package/dist/resources/indexes/hnswDerivedIndex.js +464 -0
- package/dist/resources/indexes/hnswDerivedIndex.js.map +1 -0
- package/dist/resources/indexes/hnswPlaneBinding.d.ts +65 -0
- package/dist/resources/indexes/hnswPlaneBinding.js +91 -0
- package/dist/resources/indexes/hnswPlaneBinding.js.map +1 -0
- package/dist/resources/longLivedTransactions.d.ts +71 -0
- package/dist/resources/longLivedTransactions.js +358 -0
- package/dist/resources/longLivedTransactions.js.map +1 -0
- package/dist/resources/models/backendRegistry.d.ts +26 -0
- package/dist/resources/models/backendRegistry.js +60 -2
- package/dist/resources/models/backendRegistry.js.map +1 -1
- package/dist/resources/models/bootstrap.d.ts +33 -1
- package/dist/resources/models/bootstrap.js +416 -31
- package/dist/resources/models/bootstrap.js.map +1 -1
- package/dist/resources/nodeIdMapping.d.ts +5 -0
- package/dist/resources/nodeIdMapping.js +49 -0
- package/dist/resources/nodeIdMapping.js.map +1 -1
- package/dist/resources/recordLock.d.ts +123 -0
- package/dist/resources/recordLock.js +315 -0
- package/dist/resources/recordLock.js.map +1 -0
- package/dist/resources/recordLockCoordinator.d.ts +557 -0
- package/dist/resources/recordLockCoordinator.js +2565 -0
- package/dist/resources/recordLockCoordinator.js.map +1 -0
- package/dist/resources/replayLogs.d.ts +14 -1
- package/dist/resources/replayLogs.js +157 -24
- package/dist/resources/replayLogs.js.map +1 -1
- package/dist/resources/replayLogsGuards.d.ts +94 -7
- package/dist/resources/replayLogsGuards.js +111 -7
- package/dist/resources/replayLogsGuards.js.map +1 -1
- package/dist/resources/replicatedApplyFailure.d.ts +16 -0
- package/dist/resources/replicatedApplyFailure.js +63 -0
- package/dist/resources/replicatedApplyFailure.js.map +1 -0
- package/dist/resources/scheduler/scheduler.js +3 -3
- package/dist/resources/scheduler/scheduler.js.map +1 -1
- package/dist/resources/search.d.ts +10 -4
- package/dist/resources/search.js +283 -37
- package/dist/resources/search.js.map +1 -1
- package/dist/resources/tracked.d.ts +5 -1
- package/dist/resources/tracked.js +74 -23
- package/dist/resources/tracked.js.map +1 -1
- package/dist/resources/transactionBroadcast.d.ts +1 -1
- package/dist/resources/transactionBroadcast.js +2 -2
- package/dist/resources/transactionBroadcast.js.map +1 -1
- package/dist/security/auth.js +61 -30
- package/dist/security/auth.js.map +1 -1
- package/dist/security/authn/oidc/claims.d.ts +22 -0
- package/dist/security/authn/oidc/claims.js +71 -0
- package/dist/security/authn/oidc/claims.js.map +1 -0
- package/dist/security/authn/oidc/identityToken.d.ts +27 -0
- package/dist/security/authn/oidc/identityToken.js +111 -0
- package/dist/security/authn/oidc/identityToken.js.map +1 -0
- package/dist/security/authn/oidc/jwks.d.ts +25 -0
- package/dist/security/authn/oidc/jwks.js +261 -0
- package/dist/security/authn/oidc/jwks.js.map +1 -0
- package/dist/security/authn/oidc/providers/generic.d.ts +13 -0
- package/dist/security/authn/oidc/providers/generic.js +34 -0
- package/dist/security/authn/oidc/providers/generic.js.map +1 -0
- package/dist/security/authn/oidc/providers/githubActions.d.ts +11 -0
- package/dist/security/authn/oidc/providers/githubActions.js +129 -0
- package/dist/security/authn/oidc/providers/githubActions.js.map +1 -0
- package/dist/security/authn/oidc/providers/index.d.ts +37 -0
- package/dist/security/authn/oidc/providers/index.js +24 -0
- package/dist/security/authn/oidc/providers/index.js.map +1 -0
- package/dist/security/authn/oidc/tokenExchange.d.ts +12 -0
- package/dist/security/authn/oidc/tokenExchange.js +306 -0
- package/dist/security/authn/oidc/tokenExchange.js.map +1 -0
- package/dist/security/authn/oidc/trustPolicyOperations.d.ts +49 -0
- package/dist/security/authn/oidc/trustPolicyOperations.js +358 -0
- package/dist/security/authn/oidc/trustPolicyOperations.js.map +1 -0
- package/dist/security/authn/oidc/types.d.ts +38 -0
- package/dist/security/authn/oidc/types.js +6 -0
- package/dist/security/authn/oidc/types.js.map +1 -0
- package/dist/security/certificateVerification/index.js +40 -11
- package/dist/security/certificateVerification/index.js.map +1 -1
- package/dist/security/certificateVerification/trustedIssuers.d.ts +24 -0
- package/dist/security/certificateVerification/trustedIssuers.js +79 -0
- package/dist/security/certificateVerification/trustedIssuers.js.map +1 -0
- package/dist/security/certificateVerification/types.d.ts +1 -0
- package/dist/security/credentialProvenance.d.ts +35 -0
- package/dist/security/credentialProvenance.js +51 -0
- package/dist/security/credentialProvenance.js.map +1 -0
- package/dist/security/credentialRejection.d.ts +4 -0
- package/dist/security/credentialRejection.js +24 -0
- package/dist/security/credentialRejection.js.map +1 -0
- package/dist/security/deferredAuthentication.d.ts +36 -0
- package/dist/security/deferredAuthentication.js +70 -0
- package/dist/security/deferredAuthentication.js.map +1 -0
- package/dist/security/impersonation.d.ts +21 -0
- package/dist/security/impersonation.js +108 -9
- package/dist/security/impersonation.js.map +1 -1
- package/dist/security/jsLoader.d.ts +6 -0
- package/dist/security/jsLoader.js +77 -15
- package/dist/security/jsLoader.js.map +1 -1
- package/dist/security/keys.js +301 -71
- package/dist/security/keys.js.map +1 -1
- package/dist/security/operationScope.d.ts +21 -0
- package/dist/security/operationScope.js +36 -0
- package/dist/security/operationScope.js.map +1 -0
- package/dist/security/permissionsTranslator.js +21 -0
- package/dist/security/permissionsTranslator.js.map +1 -1
- package/dist/security/tokenAuthentication.d.ts +19 -1
- package/dist/security/tokenAuthentication.js +191 -10
- package/dist/security/tokenAuthentication.js.map +1 -1
- package/dist/security/user.js +4 -3
- package/dist/security/user.js.map +1 -1
- package/dist/server/DurableSubscriptionsSession.d.ts +2 -2
- package/dist/server/DurableSubscriptionsSession.js +67 -10
- package/dist/server/DurableSubscriptionsSession.js.map +1 -1
- package/dist/server/REST.js +106 -2
- package/dist/server/REST.js.map +1 -1
- package/dist/server/graphqlQuerying.js +4 -0
- package/dist/server/graphqlQuerying.js.map +1 -1
- package/dist/server/http.d.ts +16 -1
- package/dist/server/http.js +122 -17
- package/dist/server/http.js.map +1 -1
- package/dist/server/itc/serverHandlers.js +8 -1
- package/dist/server/itc/serverHandlers.js.map +1 -1
- package/dist/server/jobs/jobProcess.js +6 -2
- package/dist/server/jobs/jobProcess.js.map +1 -1
- package/dist/server/jobs/jobs.js +4 -1
- package/dist/server/jobs/jobs.js.map +1 -1
- package/dist/server/liveSubscriptionAuth.d.ts +26 -4
- package/dist/server/liveSubscriptionAuth.js +105 -39
- package/dist/server/liveSubscriptionAuth.js.map +1 -1
- package/dist/server/loadRootComponents.js +49 -10
- package/dist/server/loadRootComponents.js.map +1 -1
- package/dist/server/mqtt.d.ts +2 -0
- package/dist/server/mqtt.js +165 -30
- package/dist/server/mqtt.js.map +1 -1
- package/dist/server/nodeName.d.ts +2 -0
- package/dist/server/nodeName.js +107 -23
- package/dist/server/nodeName.js.map +1 -1
- package/dist/server/serverHelpers/Headers.d.ts +27 -0
- package/dist/server/serverHelpers/Headers.js +145 -1
- package/dist/server/serverHelpers/Headers.js.map +1 -1
- package/dist/server/serverHelpers/NodeAdapterResponse.d.ts +48 -0
- package/dist/server/serverHelpers/NodeAdapterResponse.js +220 -0
- package/dist/server/serverHelpers/NodeAdapterResponse.js.map +1 -0
- package/dist/server/serverHelpers/Request.d.ts +5 -10
- package/dist/server/serverHelpers/Request.js +38 -136
- package/dist/server/serverHelpers/Request.js.map +1 -1
- package/dist/server/serverHelpers/contentTypes.d.ts +11 -0
- package/dist/server/serverHelpers/contentTypes.js +221 -40
- package/dist/server/serverHelpers/contentTypes.js.map +1 -1
- package/dist/server/serverHelpers/deployValidationState.d.ts +3 -0
- package/dist/server/serverHelpers/deployValidationState.js +9 -19
- package/dist/server/serverHelpers/deployValidationState.js.map +1 -1
- package/dist/server/serverHelpers/operationAuthorizationState.d.ts +12 -0
- package/dist/server/serverHelpers/operationAuthorizationState.js +24 -2
- package/dist/server/serverHelpers/operationAuthorizationState.js.map +1 -1
- package/dist/server/serverHelpers/registeredOperations.d.ts +5 -4
- package/dist/server/serverHelpers/registeredOperations.js +74 -21
- package/dist/server/serverHelpers/registeredOperations.js.map +1 -1
- package/dist/server/serverHelpers/requestSanitization.d.ts +11 -0
- package/dist/server/serverHelpers/requestSanitization.js +20 -0
- package/dist/server/serverHelpers/requestSanitization.js.map +1 -0
- package/dist/server/serverHelpers/serverHandlers.js +6 -3
- package/dist/server/serverHelpers/serverHandlers.js.map +1 -1
- package/dist/server/serverHelpers/serverUtilities.d.ts +18 -0
- package/dist/server/serverHelpers/serverUtilities.js +178 -29
- package/dist/server/serverHelpers/serverUtilities.js.map +1 -1
- package/dist/server/serverHelpers/sharedMessageEncoding.d.ts +67 -0
- package/dist/server/serverHelpers/sharedMessageEncoding.js +280 -0
- package/dist/server/serverHelpers/sharedMessageEncoding.js.map +1 -0
- package/dist/server/serverHelpers/uwsServer.js +19 -1
- package/dist/server/serverHelpers/uwsServer.js.map +1 -1
- package/dist/server/static.js +24 -28
- package/dist/server/static.js.map +1 -1
- package/dist/server/storageReclamation.d.ts +5 -0
- package/dist/server/storageReclamation.js +17 -1
- package/dist/server/storageReclamation.js.map +1 -1
- package/dist/server/threads/isolatedApplications.d.ts +47 -0
- package/dist/server/threads/isolatedApplications.js +171 -0
- package/dist/server/threads/isolatedApplications.js.map +1 -0
- package/dist/server/threads/itc.d.ts +7 -2
- package/dist/server/threads/itc.js +5 -1
- package/dist/server/threads/itc.js.map +1 -1
- package/dist/server/threads/logRotationTransport.d.ts +1 -0
- package/dist/server/threads/logRotationTransport.js +33 -0
- package/dist/server/threads/logRotationTransport.js.map +1 -0
- package/dist/server/threads/manageThreads.d.ts +83 -3
- package/dist/server/threads/manageThreads.js +769 -75
- package/dist/server/threads/manageThreads.js.map +1 -1
- package/dist/server/threads/socketRouter.d.ts +1 -0
- package/dist/server/threads/socketRouter.js +277 -31
- package/dist/server/threads/socketRouter.js.map +1 -1
- package/dist/server/threads/threadHeapMemory.d.ts +2 -0
- package/dist/server/threads/threadHeapMemory.js +31 -0
- package/dist/server/threads/threadHeapMemory.js.map +1 -0
- package/dist/server/threads/threadServer.js +76 -22
- package/dist/server/threads/threadServer.js.map +1 -1
- package/dist/sqlEngine/config.d.ts +1 -3
- package/dist/sqlEngine/config.js +19 -16
- package/dist/sqlEngine/config.js.map +1 -1
- package/dist/sqlTranslator/index.d.ts +1 -1
- package/dist/sqlTranslator/index.js +30 -7
- package/dist/sqlTranslator/index.js.map +1 -1
- package/dist/upgrade/directives/5-3-0.d.ts +7 -0
- package/dist/upgrade/directives/5-3-0.js +148 -0
- package/dist/upgrade/directives/5-3-0.js.map +1 -0
- package/dist/upgrade/directives/directivesController.js +2 -1
- package/dist/upgrade/directives/directivesController.js.map +1 -1
- package/dist/utility/OperationFunctionCaller.js +2 -1
- package/dist/utility/OperationFunctionCaller.js.map +1 -1
- package/dist/utility/common_utils.d.ts +16 -0
- package/dist/utility/common_utils.js +32 -6
- package/dist/utility/common_utils.js.map +1 -1
- package/dist/utility/componentNames.d.ts +8 -0
- package/dist/utility/componentNames.js +12 -1
- package/dist/utility/componentNames.js.map +1 -1
- package/dist/utility/environment/environmentManager.js +3 -6
- package/dist/utility/environment/environmentManager.js.map +1 -1
- package/dist/utility/environment/systemInformation.d.ts +1 -0
- package/dist/utility/environment/systemInformation.js +1 -0
- package/dist/utility/environment/systemInformation.js.map +1 -1
- package/dist/utility/errors/commonErrors.d.ts +2 -0
- package/dist/utility/errors/commonErrors.js +2 -0
- package/dist/utility/errors/commonErrors.js.map +1 -1
- package/dist/utility/errors/hdbError.d.ts +33 -0
- package/dist/utility/errors/hdbError.js +58 -1
- package/dist/utility/errors/hdbError.js.map +1 -1
- package/dist/utility/globalSchema.d.ts +18 -0
- package/dist/utility/hdbTerms.d.ts +18 -0
- package/dist/utility/hdbTerms.js +20 -2
- package/dist/utility/hdbTerms.js.map +1 -1
- package/dist/utility/logging/harper_logger.d.ts +2 -0
- package/dist/utility/logging/harper_logger.js +286 -30
- package/dist/utility/logging/harper_logger.js.map +1 -1
- package/dist/utility/logging/logGenerationCoordinator.d.ts +35 -0
- package/dist/utility/logging/logGenerationCoordinator.js +184 -0
- package/dist/utility/logging/logGenerationCoordinator.js.map +1 -0
- package/dist/utility/logging/logRotation.d.ts +46 -0
- package/dist/utility/logging/logRotation.js +365 -0
- package/dist/utility/logging/logRotation.js.map +1 -0
- package/dist/utility/logging/logRotator.d.ts +1 -1
- package/dist/utility/logging/logRotator.js +192 -85
- package/dist/utility/logging/logRotator.js.map +1 -1
- package/dist/utility/nodeIdentity.d.ts +9 -0
- package/dist/utility/nodeIdentity.js +58 -0
- package/dist/utility/nodeIdentity.js.map +1 -0
- package/dist/utility/npmUtilities.js +11 -7
- package/dist/utility/npmUtilities.js.map +1 -1
- package/dist/utility/operationPermissions.d.ts +3 -1
- package/dist/utility/operationPermissions.js +16 -1
- package/dist/utility/operationPermissions.js.map +1 -1
- package/dist/utility/operation_authorization.d.ts +10 -7
- package/dist/utility/operation_authorization.js +212 -41
- package/dist/utility/operation_authorization.js.map +1 -1
- package/dist/utility/watchPath.d.ts +29 -0
- package/dist/utility/watchPath.js +68 -0
- package/dist/utility/watchPath.js.map +1 -0
- package/dist/utility/watcherFallback.d.ts +41 -0
- package/dist/utility/watcherFallback.js +153 -0
- package/dist/utility/watcherFallback.js.map +1 -1
- package/dist/validation/configValidator.d.ts +12 -0
- package/dist/validation/configValidator.js +205 -75
- package/dist/validation/configValidator.js.map +1 -1
- package/dist/validation/installValidator.js +12 -0
- package/dist/validation/installValidator.js.map +1 -1
- package/dist/validation/validationWrapper.d.ts +11 -0
- package/dist/validation/validationWrapper.js +16 -3
- package/dist/validation/validationWrapper.js.map +1 -1
- package/index.ts +8 -0
- package/json/systemSchema.json +55 -0
- package/npm-shrinkwrap.json +286 -194
- package/package.json +15 -7
- package/resources/DESIGN.md +219 -52
- package/resources/DatabaseTransaction.ts +657 -52
- package/resources/LMDBTransaction.ts +46 -6
- package/resources/PrimaryRocksDatabase.ts +46 -7
- package/resources/RecordEncoder.ts +124 -9
- package/resources/RequestTarget.ts +2 -0
- package/resources/Resource.ts +114 -22
- package/resources/ResourceInterface.ts +31 -0
- package/resources/RocksIndexStore.ts +30 -9
- package/resources/RocksTransactionLogStore.ts +188 -51
- package/resources/Table.ts +1960 -301
- package/resources/analytics/write.ts +10 -3
- package/resources/auditStore.ts +647 -32
- package/resources/blob.ts +1029 -110
- package/resources/branchDatabase.ts +941 -0
- package/resources/crdt.ts +76 -12
- package/resources/dataLoader.ts +3 -4
- package/resources/databases.ts +1584 -320
- package/resources/defineTable.ts +18 -2
- package/resources/derivedIndexRegistry.ts +56 -0
- package/resources/derivedIndexRuntime.ts +2292 -0
- package/resources/graphql.ts +72 -17
- package/resources/indexes/HierarchicalNavigableSmallWorld.ts +911 -48
- package/resources/indexes/hnswDerivedIndex.ts +531 -0
- package/resources/indexes/hnswPlaneBinding.ts +174 -0
- package/resources/longLivedTransactions.ts +360 -0
- package/resources/models/backendRegistry.ts +84 -2
- package/resources/models/bootstrap.ts +473 -28
- package/resources/nodeIdMapping.ts +50 -0
- package/resources/recordLock.ts +419 -0
- package/resources/recordLockCoordinator.ts +3043 -0
- package/resources/replayLogs.ts +152 -26
- package/resources/replayLogsGuards.ts +171 -8
- package/resources/replicatedApplyFailure.ts +77 -0
- package/resources/scheduler/scheduler.ts +4 -4
- package/resources/search.ts +288 -46
- package/resources/tracked.ts +73 -22
- package/resources/transactionBroadcast.ts +3 -3
- package/security/auth.ts +68 -29
- package/security/authn/oidc/claims.ts +72 -0
- package/security/authn/oidc/identityToken.ts +129 -0
- package/security/authn/oidc/jwks.ts +260 -0
- package/security/authn/oidc/providers/generic.ts +40 -0
- package/security/authn/oidc/providers/githubActions.ts +137 -0
- package/security/authn/oidc/providers/index.ts +52 -0
- package/security/authn/oidc/tokenExchange.ts +300 -0
- package/security/authn/oidc/trustPolicyOperations.ts +343 -0
- package/security/authn/oidc/types.ts +41 -0
- package/security/certificateVerification/index.ts +54 -13
- package/security/certificateVerification/trustedIssuers.ts +76 -0
- package/security/certificateVerification/types.ts +1 -0
- package/security/credentialProvenance.ts +47 -0
- package/security/credentialRejection.ts +22 -0
- package/security/deferredAuthentication.ts +71 -0
- package/security/impersonation.ts +117 -12
- package/security/jsLoader.ts +83 -18
- package/security/keys.ts +298 -72
- package/security/operationScope.ts +33 -0
- package/security/permissionsTranslator.js +23 -0
- package/security/tokenAuthentication.ts +233 -12
- package/security/user.ts +4 -3
- package/server/DESIGN.md +194 -16
- package/server/DurableSubscriptionsSession.ts +71 -11
- package/server/REST.ts +115 -4
- package/server/graphqlQuerying.ts +4 -0
- package/server/http.ts +133 -20
- package/server/itc/serverHandlers.js +8 -1
- package/server/jobs/jobProcess.ts +8 -2
- package/server/jobs/jobs.ts +4 -1
- package/server/liveSubscriptionAuth.ts +129 -46
- package/server/loadRootComponents.js +50 -8
- package/server/mqtt.ts +179 -38
- package/server/nodeName.ts +103 -21
- package/server/serverHelpers/Headers.ts +135 -0
- package/server/serverHelpers/NodeAdapterResponse.ts +221 -0
- package/server/serverHelpers/Request.ts +33 -131
- package/server/serverHelpers/contentTypes.ts +217 -36
- package/server/serverHelpers/deployValidationState.ts +24 -13
- package/server/serverHelpers/operationAuthorizationState.ts +34 -3
- package/server/serverHelpers/registeredOperations.ts +79 -22
- package/server/serverHelpers/requestSanitization.ts +15 -0
- package/server/serverHelpers/serverHandlers.js +6 -3
- package/server/serverHelpers/serverUtilities.ts +232 -40
- package/server/serverHelpers/sharedMessageEncoding.ts +307 -0
- package/server/serverHelpers/uwsServer.ts +17 -2
- package/server/static.ts +23 -29
- package/server/storageReclamation.ts +15 -2
- package/server/threads/isolatedApplications.ts +157 -0
- package/server/threads/itc.js +11 -1
- package/server/threads/logRotationTransport.ts +40 -0
- package/server/threads/manageThreads.js +771 -66
- package/server/threads/socketRouter.ts +291 -30
- package/server/threads/threadHeapMemory.ts +26 -0
- package/server/threads/threadServer.js +73 -22
- package/sqlTranslator/index.ts +31 -8
- package/studio/web/assets/{Chat-4RrB5134.js → Chat-D3j-1yY1.js} +1 -1
- package/studio/web/assets/{FloatingChat-omlNMDcJ.js → FloatingChat-BxJGYcfB.js} +3 -3
- package/studio/web/assets/{apiToken-Bke3wvfZ.js → apiToken-CT55oWOe.js} +1 -1
- package/studio/web/assets/{applications-DvFDYJgK.js → applications-D9Ct9_vm.js} +1 -1
- package/studio/web/assets/{cssMode-C1vRa7zh.js → cssMode-DV8H7VwA.js} +1 -1
- package/studio/web/assets/{editor-3XRWEDWX.js → editor-uatc0unt.js} +1 -1
- package/studio/web/assets/{html-CTY5tdMr.js → html-Bm6D6paN.js} +1 -1
- package/studio/web/assets/{htmlMode-CG1vSD9t.js → htmlMode-CEn7tpLG.js} +1 -1
- package/studio/web/assets/{index-Dfpeofdu.js → index-BIXW6Pu4.js} +5 -5
- package/studio/web/assets/{index.lazy-B1VOIv-t.js → index.lazy-UI7L-Vrk.js} +1 -1
- package/studio/web/assets/{javascript-CJeJzGnI.js → javascript-CJ0G3AFZ.js} +1 -1
- package/studio/web/assets/{jsonMode-CYPBwM82.js → jsonMode-DQADAYEa.js} +1 -1
- package/studio/web/assets/{languageServices-IKH4GUHl.js → languageServices-CAQJXWcI.js} +1 -1
- package/studio/web/assets/{lspLanguageFeatures-BC8_gxKG.js → lspLanguageFeatures-CCQ8P5sY.js} +1 -1
- package/studio/web/assets/{notifications-BfKBpYcq.js → notifications-BbxTU6Aw.js} +1 -1
- package/studio/web/assets/{notifications-DFbArTfC.js → notifications-Cvb3P1lB.js} +1 -1
- package/studio/web/assets/{profile-Q4-T6c-S.js → profile-Yyb7gsvL.js} +1 -1
- package/studio/web/assets/{regions-CtkV0xje.js → regions-OgjGHlU5.js} +1 -1
- package/studio/web/assets/{register-1ZZuMsiA.js → register-6qwNEOY3.js} +2 -2
- package/studio/web/assets/{setComponentFile-ZWLcWv5X.js → setComponentFile-BilDMtgB.js} +1 -1
- package/studio/web/assets/{setup-DWprJyJy.js → setup-J6qJ7OIU.js} +2 -2
- package/studio/web/assets/{status--aNm8isn.js → status-0RWGcfyD.js} +1 -1
- package/studio/web/assets/{toggleHighContrast-Cq_lt3XD.js → toggleHighContrast-BIn-vErT.js} +1 -1
- package/studio/web/assets/{tsMode-pjgytARx.js → tsMode-DgUXku4d.js} +1 -1
- package/studio/web/assets/{typescript-Cdg0mqUh.js → typescript-C9orXcsM.js} +1 -1
- package/studio/web/assets/{useEntityRestURL-RZhaY8Rn.js → useEntityRestURL-BEoXXbUB.js} +1 -1
- package/studio/web/assets/{workers-BgoXIqQe.js → workers-JVzSDmgx.js} +1 -1
- package/studio/web/assets/{xml-BwSeDMiP.js → xml-Cq-S8S4X.js} +1 -1
- package/studio/web/assets/{yaml-DotCUG5l.js → yaml-sfoRdh1M.js} +1 -1
- package/studio/web/index.html +1 -1
- package/upgrade/directives/5-3-0.ts +132 -0
- package/upgrade/directives/directivesController.ts +2 -1
- package/utility/OperationFunctionCaller.ts +2 -1
- package/utility/common_utils.ts +30 -5
- package/utility/componentNames.ts +12 -0
- package/utility/environment/environmentManager.ts +3 -7
- package/utility/environment/systemInformation.ts +7 -0
- package/utility/errors/commonErrors.ts +4 -0
- package/utility/errors/hdbError.ts +57 -0
- package/utility/hdbTerms.ts +19 -0
- package/utility/logging/harper_logger.ts +278 -26
- package/utility/logging/logGenerationCoordinator.ts +196 -0
- package/utility/logging/logRotation.ts +367 -0
- package/utility/logging/logRotator.ts +213 -81
- package/utility/nodeIdentity.ts +45 -0
- package/utility/npmUtilities.ts +12 -8
- package/utility/operationPermissions.ts +18 -1
- package/utility/operation_authorization.ts +231 -42
- package/utility/watchPath.ts +63 -0
- package/utility/watcherFallback.ts +148 -0
- package/validation/configValidator.ts +215 -75
- package/validation/installValidator.ts +15 -0
- package/validation/validationWrapper.ts +18 -4
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// Why a lock that outlives the reader's budget is retried from a timer, and why both the bound and
|
|
2
|
+
// the backoff are wall clock rather than an attempt count: see "Root config watchers must read
|
|
3
|
+
// synchronously" in DESIGN.md (harper#2191).
|
|
4
|
+
const RETRY_BUDGET_MS = 3_100;
|
|
5
|
+
const INITIAL_DELAY_MS = 100;
|
|
6
|
+
const MAX_DELAY_MS = 1_600;
|
|
7
|
+
|
|
8
|
+
let retryBudgetMs = RETRY_BUDGET_MS;
|
|
9
|
+
|
|
10
|
+
// Test-only, the read-side twin of `atomicWriteFile`'s `retryBudgetMs` option. A case that only
|
|
11
|
+
// needs the ladder *spent* has no way to get there but wall clock, so without this each one sits
|
|
12
|
+
// out the shipped 3.1 s; a dozen of them cost the unit job 40 s. Called with no argument it
|
|
13
|
+
// restores the shipped value, and `configReadRetry.test.js` still spends that value in full, so
|
|
14
|
+
// shortening it elsewhere cannot hide a change to what ships.
|
|
15
|
+
export function _setRetryBudgetForTests(ms: number = RETRY_BUDGET_MS): void {
|
|
16
|
+
retryBudgetMs = ms;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export class ConfigReadRetry {
|
|
20
|
+
#timer?: NodeJS.Timeout;
|
|
21
|
+
#deadline?: number;
|
|
22
|
+
// Captured with the deadline: the backoff is a fraction of the budget the deadline came from,
|
|
23
|
+
// so reading the module value again mid-ladder would mis-scale it if a test had changed it.
|
|
24
|
+
#budgetMs: number = retryBudgetMs;
|
|
25
|
+
|
|
26
|
+
// `holdEventLoop` is for a caller whose boot barrier this ladder is the only thing left to
|
|
27
|
+
// settle: an unref'd timer would let the thread drain and exit mid-boot instead.
|
|
28
|
+
schedule(retry: () => void, holdEventLoop: boolean = false): boolean {
|
|
29
|
+
this.cancel();
|
|
30
|
+
const now = performance.now();
|
|
31
|
+
if (this.#deadline === undefined) {
|
|
32
|
+
this.#budgetMs = retryBudgetMs;
|
|
33
|
+
this.#deadline = now + this.#budgetMs;
|
|
34
|
+
}
|
|
35
|
+
const remainingMs = this.#deadline - now;
|
|
36
|
+
if (remainingMs <= 0) {
|
|
37
|
+
this.reset();
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
const elapsedMs = this.#budgetMs - remainingMs;
|
|
41
|
+
const delayMs = Math.min(Math.max(elapsedMs, INITIAL_DELAY_MS), MAX_DELAY_MS, remainingMs);
|
|
42
|
+
this.#timer = setTimeout(retry, delayMs);
|
|
43
|
+
if (!holdEventLoop) this.#timer.unref();
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
get pending(): boolean {
|
|
48
|
+
return this.#timer !== undefined;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
reset(): void {
|
|
52
|
+
this.cancel();
|
|
53
|
+
this.#deadline = undefined;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
cancel(): void {
|
|
57
|
+
if (this.#timer) {
|
|
58
|
+
clearTimeout(this.#timer);
|
|
59
|
+
this.#timer = undefined;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
package/config/configUtils.ts
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import * as hdbTerms from '../utility/hdbTerms.ts';
|
|
2
2
|
import * as hdbUtils from '../utility/common_utils.ts';
|
|
3
3
|
import logger from '../utility/logging/harper_logger.ts';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
configValidator,
|
|
6
|
+
getDomainSocketPathLengthWarning,
|
|
7
|
+
isLegacySqlApplicationEntry,
|
|
8
|
+
} from '../validation/configValidator.ts';
|
|
9
|
+
import { isReservedComponentName } from '../utility/componentNames.ts';
|
|
5
10
|
import fs from 'fs-extra';
|
|
6
11
|
import YAML from 'yaml';
|
|
7
12
|
import path from 'path';
|
|
8
|
-
import {
|
|
13
|
+
import { constants as osConstants } from 'node:os';
|
|
14
|
+
import { isMainThread, threadId } from 'node:worker_threads';
|
|
9
15
|
import { randomBytes } from 'node:crypto';
|
|
10
16
|
import isNumber from 'is-number';
|
|
11
17
|
import propertiesReaderModule from 'properties-reader';
|
|
@@ -23,8 +29,9 @@ import { server } from '../server/Server.ts';
|
|
|
23
29
|
import { getBackupDirPath } from './configHelpers.ts';
|
|
24
30
|
import { PACKAGE_ROOT } from '../utility/packageUtils.js';
|
|
25
31
|
import * as env from '../utility/environment/environmentManager.ts';
|
|
26
|
-
import {
|
|
32
|
+
import { prepareRuntimeEnvConfig, hasPersistedEnvConfigState, discardConfigState } from './harperConfigEnvVars.ts';
|
|
27
33
|
import { warnComponentEnvConfigVars, resolveConfiguredPath } from './componentEnvPrepass.ts';
|
|
34
|
+
import { isStartableThreadHeapMemory } from '../server/threads/threadHeapMemory.ts';
|
|
28
35
|
|
|
29
36
|
const { DATABASES_PARAM_CONFIG, CONFIG_PARAMS, CONFIG_PARAM_MAP } = hdbTerms;
|
|
30
37
|
const UNINIT_GET_CONFIG_ERR = 'Unable to get config value because config is uninitialized';
|
|
@@ -85,63 +92,191 @@ export function getConfigPath(param: string) {
|
|
|
85
92
|
return path.resolve(rootPath, value);
|
|
86
93
|
}
|
|
87
94
|
|
|
88
|
-
// Write atomically via temp file + rename so readers
|
|
89
|
-
//
|
|
90
|
-
// in the same millisecond can't collide on the temp name and then race the rename.
|
|
91
|
-
//
|
|
95
|
+
// Write atomically via a randomized temp file + rename so readers do not observe partial content
|
|
96
|
+
// and concurrent workers, which share process.pid, do not collide on a temp path.
|
|
92
97
|
// Windows has no POSIX-style "replace an open file" semantics: rename() fails with
|
|
93
|
-
// EPERM/EACCES
|
|
94
|
-
//
|
|
95
|
-
//
|
|
96
|
-
//
|
|
97
|
-
//
|
|
98
|
-
//
|
|
99
|
-
|
|
100
|
-
//
|
|
101
|
-
const RENAME_RETRY_MAX_ATTEMPTS =
|
|
98
|
+
// EPERM/EACCES/EBUSY while another worker or AV holds the destination open. Root config watchers use
|
|
99
|
+
// readConfigFileSync so this blocking retry cannot wait on a read owned by its own worker.
|
|
100
|
+
// The budget is the wall-clock window of the 12-attempt schedule it replaced
|
|
101
|
+
// (10+20+40+80+160+320+500*6), so it stays a deadline rather than an attempt count without
|
|
102
|
+
// widening the stall: this loop blocks the calling worker's event loop, and `set_configuration`
|
|
103
|
+
// reaches it from a live request thread.
|
|
104
|
+
const RENAME_RETRY_BUDGET_MS = 3_630;
|
|
105
|
+
// Secondary guard only: stops a degenerate zero-delay option set from spinning the whole budget.
|
|
106
|
+
const RENAME_RETRY_MAX_ATTEMPTS = 25;
|
|
102
107
|
const RENAME_RETRY_INITIAL_DELAY_MS = 10;
|
|
103
108
|
const RENAME_RETRY_MAX_DELAY_MS = 500;
|
|
104
|
-
// Never notified;
|
|
109
|
+
// Never notified; Atomics.wait uses this only as a CPU-idle synchronous sleep.
|
|
105
110
|
const renameRetrySleepBuffer = new Int32Array(new SharedArrayBuffer(4));
|
|
106
111
|
|
|
112
|
+
// Classified by code alone rather than gated to win32 like the read side: `process.platform` does
|
|
113
|
+
// not answer whether this filesystem can replace an open file — WSL drvfs, CIFS/SMB and Docker
|
|
114
|
+
// Desktop bind mounts all report `linux` and return these codes transiently.
|
|
115
|
+
function isRetryableRenameError(code: string): boolean {
|
|
116
|
+
return code === 'EPERM' || code === 'EACCES' || code === 'EBUSY';
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
type RenameRetryOptions = {
|
|
120
|
+
retryBudgetMs?: number;
|
|
121
|
+
maxRetries?: number;
|
|
122
|
+
initialDelayMs?: number;
|
|
123
|
+
maxDelayMs?: number;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
type AtomicWriteOptions = RenameRetryOptions & {
|
|
127
|
+
skipIfUnchanged?: boolean;
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
function validateRenameRetryOptions({ retryBudgetMs, maxRetries, initialDelayMs, maxDelayMs }: RenameRetryOptions) {
|
|
131
|
+
const invalidOption =
|
|
132
|
+
!Number.isFinite(retryBudgetMs) ||
|
|
133
|
+
retryBudgetMs < 0 ||
|
|
134
|
+
(!Number.isFinite(maxRetries) && maxRetries !== Infinity) ||
|
|
135
|
+
maxRetries < 0 ||
|
|
136
|
+
!Number.isFinite(initialDelayMs) ||
|
|
137
|
+
initialDelayMs < 0 ||
|
|
138
|
+
!Number.isFinite(maxDelayMs) ||
|
|
139
|
+
maxDelayMs < 0;
|
|
140
|
+
if (invalidOption) {
|
|
141
|
+
throw new RangeError('rename retry options must be non-negative numbers');
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Linux has no libuv mapping for EDQUOT, so a quota-exhausted write surfaces as
|
|
146
|
+
// `Unknown system error -122` with an unusable `code`; the numeric errno is the portable signal
|
|
147
|
+
// (EDQUOT is 122 on Linux, 69 on macOS).
|
|
148
|
+
const STORAGE_EXHAUSTED_CODES = new Set(['ENOSPC', 'EDQUOT']);
|
|
149
|
+
// EDQUOT is absent from os.constants.errno on platforms without quotas, so filter before negating:
|
|
150
|
+
// -undefined is NaN, which would sit in the set matching nothing and reading as a bug.
|
|
151
|
+
const STORAGE_EXHAUSTED_ERRNOS = new Set(
|
|
152
|
+
[osConstants.errno.ENOSPC, osConstants.errno.EDQUOT].filter((errno) => errno !== undefined).map((errno) => -errno)
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
export function isStorageExhausted(error): boolean {
|
|
156
|
+
return STORAGE_EXHAUSTED_CODES.has(error?.code) || STORAGE_EXHAUSTED_ERRNOS.has(error?.errno);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Boot-path persistence of derived config is best-effort: on an exhausted volume a fatal write here
|
|
160
|
+
// is an un-breakable restart loop, because freeing space needs a started process (#847).
|
|
161
|
+
export function persistConfigDuringBoot(artifactPath: string, write: () => void): boolean {
|
|
162
|
+
try {
|
|
163
|
+
write();
|
|
164
|
+
return true;
|
|
165
|
+
} catch (error) {
|
|
166
|
+
if (!isStorageExhausted(error)) throw error;
|
|
167
|
+
logger.error(
|
|
168
|
+
`Storage exhausted (${error.code ?? error.errno}) writing ${artifactPath}; continuing startup with the in-memory configuration. The file on disk is unchanged - free space on the Harper volume to restore config persistence.`
|
|
169
|
+
);
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Returns true when the file was written, false when an unchanged write was skipped.
|
|
107
175
|
export function atomicWriteFile(
|
|
108
176
|
filePath,
|
|
109
177
|
content,
|
|
110
178
|
{
|
|
179
|
+
retryBudgetMs = RENAME_RETRY_BUDGET_MS,
|
|
111
180
|
maxRetries = RENAME_RETRY_MAX_ATTEMPTS,
|
|
112
181
|
initialDelayMs = RENAME_RETRY_INITIAL_DELAY_MS,
|
|
113
182
|
maxDelayMs = RENAME_RETRY_MAX_DELAY_MS,
|
|
114
|
-
|
|
183
|
+
skipIfUnchanged = false,
|
|
184
|
+
}: AtomicWriteOptions = {}
|
|
115
185
|
) {
|
|
186
|
+
// Before the temp write, so an option set that can never rename leaves no file behind.
|
|
187
|
+
validateRenameRetryOptions({ retryBudgetMs, maxRetries, initialDelayMs, maxDelayMs });
|
|
188
|
+
// Opt-in: skipping means no mtime bump, so no watcher event. Only callers that re-derive the
|
|
189
|
+
// same file every boot want that.
|
|
190
|
+
if (skipIfUnchanged && matchesFileContent(filePath, content)) return false;
|
|
116
191
|
const tempPath = `${filePath}.${process.pid}.${threadId}.${randomBytes(4).toString('hex')}.tmp`;
|
|
117
|
-
|
|
192
|
+
try {
|
|
193
|
+
fs.writeFileSync(tempPath, content);
|
|
194
|
+
} catch (err) {
|
|
195
|
+
// The open succeeds before the write runs out of room, leaving the temp file behind.
|
|
196
|
+
removeTempFile(tempPath);
|
|
197
|
+
throw err;
|
|
198
|
+
}
|
|
199
|
+
try {
|
|
200
|
+
renameWithRetry(tempPath, filePath, { retryBudgetMs, maxRetries, initialDelayMs, maxDelayMs });
|
|
201
|
+
} catch (err) {
|
|
202
|
+
// The temp name carries fresh randomness on every call, so a spent budget would otherwise
|
|
203
|
+
// leave a file nothing else will ever collect.
|
|
204
|
+
removeTempFile(tempPath);
|
|
205
|
+
throw err;
|
|
206
|
+
}
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export function renameWithRetry(
|
|
211
|
+
fromPath,
|
|
212
|
+
toPath,
|
|
213
|
+
{
|
|
214
|
+
retryBudgetMs = RENAME_RETRY_BUDGET_MS,
|
|
215
|
+
maxRetries = RENAME_RETRY_MAX_ATTEMPTS,
|
|
216
|
+
initialDelayMs = RENAME_RETRY_INITIAL_DELAY_MS,
|
|
217
|
+
maxDelayMs = RENAME_RETRY_MAX_DELAY_MS,
|
|
218
|
+
}: RenameRetryOptions = {}
|
|
219
|
+
) {
|
|
220
|
+
validateRenameRetryOptions({ retryBudgetMs, maxRetries, initialDelayMs, maxDelayMs });
|
|
118
221
|
let retries = maxRetries;
|
|
119
222
|
let delayMs = initialDelayMs;
|
|
223
|
+
let retryDeadline;
|
|
224
|
+
let finalAttempt = false;
|
|
225
|
+
let attempts = 0;
|
|
226
|
+
const startedAt = performance.now();
|
|
120
227
|
while (true) {
|
|
121
228
|
try {
|
|
122
|
-
|
|
123
|
-
|
|
229
|
+
attempts++;
|
|
230
|
+
fs.renameSync(fromPath, toPath);
|
|
231
|
+
return;
|
|
124
232
|
} catch (err) {
|
|
125
|
-
if (retries > 0 && (err.code
|
|
233
|
+
if (!finalAttempt && retries > 0 && isRetryableRenameError(err.code)) {
|
|
126
234
|
retries--;
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
235
|
+
if (retryDeadline === undefined) {
|
|
236
|
+
retryDeadline = performance.now() + retryBudgetMs;
|
|
237
|
+
}
|
|
238
|
+
const remainingBudgetMs = retryDeadline - performance.now();
|
|
239
|
+
if (remainingBudgetMs > 0) {
|
|
240
|
+
// Sleep synchronously (all call sites are sync) to allow the holder to close the
|
|
241
|
+
// file. Atomics.wait yields the thread to the OS instead of spinning the CPU,
|
|
242
|
+
// which is what makes a multi-second worst-case budget affordable.
|
|
243
|
+
const sleepMs = Math.min(delayMs, remainingBudgetMs);
|
|
244
|
+
finalAttempt = sleepMs === remainingBudgetMs;
|
|
245
|
+
if (sleepMs > 0) Atomics.wait(renameRetrySleepBuffer, 0, 0, sleepMs);
|
|
246
|
+
delayMs = Math.min(Math.max(delayMs * 2, RENAME_RETRY_INITIAL_DELAY_MS), maxDelayMs);
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
133
249
|
}
|
|
134
|
-
//
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
250
|
+
// Whether the budget was spent or the code was never retryable is the difference
|
|
251
|
+
// between a holder that never released and a one-off failure, and neither survives on
|
|
252
|
+
// the rethrown error.
|
|
253
|
+
if (isRetryableRenameError(err.code)) {
|
|
254
|
+
logger.warn(
|
|
255
|
+
`Could not replace ${toPath}: ${err.code} after ${attempts} attempts over ${Math.round(performance.now() - startedAt)}ms`
|
|
256
|
+
);
|
|
139
257
|
}
|
|
140
258
|
throw err;
|
|
141
259
|
}
|
|
142
260
|
}
|
|
143
261
|
}
|
|
144
262
|
|
|
263
|
+
function removeTempFile(tempPath) {
|
|
264
|
+
try {
|
|
265
|
+
fs.unlinkSync(tempPath);
|
|
266
|
+
} catch {
|
|
267
|
+
// ignore cleanup errors
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function matchesFileContent(filePath, content): boolean {
|
|
272
|
+
if (typeof content !== 'string') return false;
|
|
273
|
+
try {
|
|
274
|
+
return fs.readFileSync(filePath, 'utf8') === content;
|
|
275
|
+
} catch {
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
145
280
|
/**
|
|
146
281
|
* Builds the Harper config file using user inputs and default values from defaultConfig.yaml
|
|
147
282
|
* @param args - any args that the user provided.
|
|
@@ -154,7 +289,7 @@ export function createConfigFile(args, skipFsValidation = false) {
|
|
|
154
289
|
// Loop through the user inputted args. Match them to a parameter in the default config file and update value.
|
|
155
290
|
let schemasArgs;
|
|
156
291
|
for (const arg in args) {
|
|
157
|
-
let configParam =
|
|
292
|
+
let configParam = lookupConfigParam(arg);
|
|
158
293
|
|
|
159
294
|
// Schemas config args are handled differently, so if they exist set them to var that will be used by setSchemasConfig
|
|
160
295
|
if (configParam === CONFIG_PARAMS.DATABASES) {
|
|
@@ -169,7 +304,7 @@ export function createConfigFile(args, skipFsValidation = false) {
|
|
|
169
304
|
continue;
|
|
170
305
|
}
|
|
171
306
|
|
|
172
|
-
if (!configParam && (arg
|
|
307
|
+
if (!configParam && isSuffixEscapedParam(arg)) {
|
|
173
308
|
configParam = arg;
|
|
174
309
|
}
|
|
175
310
|
|
|
@@ -273,7 +408,7 @@ export function getDefaultConfig(param: string) {
|
|
|
273
408
|
flatDefaultConfigObj = flattenConfig(configDoc.toJSON());
|
|
274
409
|
}
|
|
275
410
|
|
|
276
|
-
const paramMap =
|
|
411
|
+
const paramMap = lookupConfigParam(param);
|
|
277
412
|
if (paramMap === undefined) return undefined;
|
|
278
413
|
|
|
279
414
|
return flatDefaultConfigObj[paramMap.toLowerCase()];
|
|
@@ -297,7 +432,7 @@ export function getConfigValue(param: string | null | undefined) {
|
|
|
297
432
|
return undefined;
|
|
298
433
|
}
|
|
299
434
|
|
|
300
|
-
const paramMap =
|
|
435
|
+
const paramMap = lookupConfigParam(param);
|
|
301
436
|
if (paramMap === undefined) return undefined;
|
|
302
437
|
|
|
303
438
|
return flatConfigObj[paramMap.toLowerCase()];
|
|
@@ -352,7 +487,10 @@ export function ensureConfigKeysPresent(keys: string[]): string[] {
|
|
|
352
487
|
}
|
|
353
488
|
if (added.length === 0) return [];
|
|
354
489
|
|
|
355
|
-
|
|
490
|
+
// Worker threads re-read the config from disk and never run this backfill, so a key that only
|
|
491
|
+
// exists in this thread's memory activates nowhere that serves requests: report nothing when the
|
|
492
|
+
// write was refused rather than logging an activation the request path did not get.
|
|
493
|
+
if (!persistConfigDuringBoot(configFilePath, () => atomicWriteFile(configFilePath, String(configDoc)))) return [];
|
|
356
494
|
|
|
357
495
|
// Mirror the additions into the already-memoized config so a built-in gated on the new key
|
|
358
496
|
// activates on the CURRENT boot: componentLoader reads the root config from getConfigObj(),
|
|
@@ -572,7 +710,7 @@ function checkForUpdatedConfig(configDoc, configFilePath) {
|
|
|
572
710
|
HTTP_STATUS_CODES.INTERNAL_SERVER_ERROR
|
|
573
711
|
);
|
|
574
712
|
}
|
|
575
|
-
atomicWriteFile(configFilePath, String(configDoc));
|
|
713
|
+
persistConfigDuringBoot(configFilePath, () => atomicWriteFile(configFilePath, String(configDoc)));
|
|
576
714
|
}
|
|
577
715
|
}
|
|
578
716
|
|
|
@@ -676,6 +814,10 @@ function validateConfig(configDoc, skipFsValidation = false) {
|
|
|
676
814
|
configDoc.setIn(['operationsApi', 'network', 'domainSocket'], domainSocket);
|
|
677
815
|
const domainSocketWarning = getDomainSocketPathLengthWarning(validation.value.rootPath, domainSocket);
|
|
678
816
|
if (domainSocketWarning) logger.warn(domainSocketWarning);
|
|
817
|
+
if (isLegacySqlApplicationEntry(configJson.sql))
|
|
818
|
+
logger.warn(
|
|
819
|
+
"The root config entry 'sql' is an application, but 'sql' now configures Harper's SQL engine. Redeploy that application under a different name and remove the 'sql' entry; until then the SQL engine settings cannot be configured."
|
|
820
|
+
);
|
|
679
821
|
}
|
|
680
822
|
|
|
681
823
|
/**
|
|
@@ -690,7 +832,7 @@ export function updateConfigObject(param: string, value: any) {
|
|
|
690
832
|
flatConfigObj = {};
|
|
691
833
|
}
|
|
692
834
|
|
|
693
|
-
const configObjKey =
|
|
835
|
+
const configObjKey = lookupConfigParam(param);
|
|
694
836
|
if (configObjKey === undefined) {
|
|
695
837
|
logger.trace(`Unable to update config object because config param '${param}' does not exist`);
|
|
696
838
|
return;
|
|
@@ -734,6 +876,71 @@ export function updateConfigObject(param: string, value: any) {
|
|
|
734
876
|
}
|
|
735
877
|
}
|
|
736
878
|
|
|
879
|
+
/**
|
|
880
|
+
* Canonical config param for an arg name, or `undefined` when the name is not a config param.
|
|
881
|
+
* `Object.hasOwn` because a bare lookup resolves inherited names: `constructor` yields an
|
|
882
|
+
* `Object.prototype` member that then fails `.split('_')` or `.toLowerCase()`.
|
|
883
|
+
*/
|
|
884
|
+
function lookupConfigParam(arg: string): string | undefined {
|
|
885
|
+
if (typeof arg !== 'string') return undefined;
|
|
886
|
+
const name = arg.toLowerCase();
|
|
887
|
+
return Object.hasOwn(CONFIG_PARAM_MAP, name) ? CONFIG_PARAM_MAP[name] : undefined;
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
const COMPONENT_PARAM_SUFFIXES = ['_package', '_port'];
|
|
891
|
+
|
|
892
|
+
function suffixEscapedComponentName(arg: string): string | undefined {
|
|
893
|
+
if (typeof arg !== 'string') return undefined;
|
|
894
|
+
const suffix = COMPONENT_PARAM_SUFFIXES.find((candidate) => arg.endsWith(candidate));
|
|
895
|
+
if (suffix === undefined) return undefined;
|
|
896
|
+
const component = arg.slice(0, -suffix.length);
|
|
897
|
+
return component === '' ? undefined : component;
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
/**
|
|
901
|
+
* Component entries (`my-component_package`, `my-component_port`) are operator-named, so they
|
|
902
|
+
* cannot be enumerated in CONFIG_PARAM_MAP and bypass it. This escape is the one way to write a
|
|
903
|
+
* root component entry without going through deploy_component, so a reserved name is excluded.
|
|
904
|
+
*/
|
|
905
|
+
function isSuffixEscapedParam(arg: string): boolean {
|
|
906
|
+
const component = suffixEscapedComponentName(arg);
|
|
907
|
+
return component !== undefined && !isReservedComponentName(component);
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
function findReservedComponentParams(args: object): string[] {
|
|
911
|
+
const reserved = [];
|
|
912
|
+
for (const arg in args) {
|
|
913
|
+
if (!Object.hasOwn(args, arg)) continue;
|
|
914
|
+
const component = suffixEscapedComponentName(arg);
|
|
915
|
+
if (component !== undefined && isReservedComponentName(component)) reserved.push(arg);
|
|
916
|
+
}
|
|
917
|
+
return reserved;
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
const MAX_REPORTED_UNRECOGNIZED = 10;
|
|
921
|
+
|
|
922
|
+
/**
|
|
923
|
+
* Render unrecognized names for an error that also reaches the operations log: control characters
|
|
924
|
+
* are stripped so a name containing a newline cannot forge a log line, and the list is capped so a
|
|
925
|
+
* body carrying thousands of unknown keys cannot produce an unbounded message.
|
|
926
|
+
*/
|
|
927
|
+
function describeUnrecognized(names: string[]): string {
|
|
928
|
+
const shown = names
|
|
929
|
+
.slice(0, MAX_REPORTED_UNRECOGNIZED)
|
|
930
|
+
// eslint-disable-next-line no-control-regex
|
|
931
|
+
.map((name) => name.replace(/[\u0000-\u001f\u007f]/g, '?'));
|
|
932
|
+
const remaining = names.length - shown.length;
|
|
933
|
+
return remaining > 0 ? `${shown.join(', ')} (and ${remaining} more)` : shown.join(', ');
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
function findUnrecognizedParams(args: object): string[] {
|
|
937
|
+
let unrecognized;
|
|
938
|
+
for (const arg in args) {
|
|
939
|
+
if (lookupConfigParam(arg) === undefined && !isSuffixEscapedParam(arg)) (unrecognized ??= []).push(arg);
|
|
940
|
+
}
|
|
941
|
+
return unrecognized ?? [];
|
|
942
|
+
}
|
|
943
|
+
|
|
737
944
|
/**
|
|
738
945
|
* Updates and validates a config value in config file. Can also create a backup of config before updating.
|
|
739
946
|
* @param param - the config value to update
|
|
@@ -794,7 +1001,7 @@ export function updateConfigValue(
|
|
|
794
1001
|
if (skipParamMap) {
|
|
795
1002
|
configParam = param;
|
|
796
1003
|
} else {
|
|
797
|
-
configParam =
|
|
1004
|
+
configParam = lookupConfigParam(param);
|
|
798
1005
|
if (configParam === undefined) {
|
|
799
1006
|
throw handleHDBError(
|
|
800
1007
|
new Error(),
|
|
@@ -813,7 +1020,7 @@ export function updateConfigValue(
|
|
|
813
1020
|
} else {
|
|
814
1021
|
// Loop through the user inputted args. Match them to a parameter in the default config file and update value.
|
|
815
1022
|
for (const arg in parsedArgs) {
|
|
816
|
-
let configParam =
|
|
1023
|
+
let configParam = lookupConfigParam(arg);
|
|
817
1024
|
|
|
818
1025
|
// If setting http.securePort to the same value as http.port, set http.port to null to avoid clashing ports
|
|
819
1026
|
if (
|
|
@@ -845,7 +1052,7 @@ export function updateConfigValue(
|
|
|
845
1052
|
}
|
|
846
1053
|
}
|
|
847
1054
|
|
|
848
|
-
if (!configParam && (arg
|
|
1055
|
+
if (!configParam && isSuffixEscapedParam(arg)) {
|
|
849
1056
|
configParam = arg;
|
|
850
1057
|
}
|
|
851
1058
|
|
|
@@ -1039,14 +1246,54 @@ export function getConfiguration() {
|
|
|
1039
1246
|
return configDoc.toJSON();
|
|
1040
1247
|
}
|
|
1041
1248
|
|
|
1249
|
+
// `set_configuration` is the one config writer that also fans out (`replicated: true`), so a value
|
|
1250
|
+
// accepted here lands on every peer at once and the next rolling restart takes the whole cluster
|
|
1251
|
+
// down together (harper-pro#558). Boot-time writers are deliberately not gated the same way: config
|
|
1252
|
+
// that already exists has to stay bootable, so it is recovered at the point of use instead
|
|
1253
|
+
// (server/threads/threadHeapMemory.ts).
|
|
1254
|
+
function assertThreadHeapMemoryStartable(configFields) {
|
|
1255
|
+
for (const field in configFields) {
|
|
1256
|
+
const configParam = CONFIG_PARAM_MAP[field.toLowerCase()];
|
|
1257
|
+
let configured;
|
|
1258
|
+
if (configParam === CONFIG_PARAMS.THREADS_MAXHEAPMEMORY) configured = configFields[field];
|
|
1259
|
+
else if (configParam === CONFIG_PARAMS.THREADS) configured = readSectionHeapMemory(configFields[field]);
|
|
1260
|
+
else continue;
|
|
1261
|
+
const value = castConfigValue(CONFIG_PARAMS.THREADS_MAXHEAPMEMORY, configured);
|
|
1262
|
+
if (typeof value !== 'number' || isStartableThreadHeapMemory(value)) continue;
|
|
1263
|
+
throw handleHDBError(
|
|
1264
|
+
new Error(),
|
|
1265
|
+
HDB_ERROR_MSGS.CONFIG_VALIDATION(
|
|
1266
|
+
`'threads.maxHeapMemory' must be greater than or equal to ${hdbTerms.MIN_THREAD_HEAP_MEMORY_MB}`
|
|
1267
|
+
),
|
|
1268
|
+
HTTP_STATUS_CODES.BAD_REQUEST,
|
|
1269
|
+
undefined,
|
|
1270
|
+
undefined,
|
|
1271
|
+
true
|
|
1272
|
+
);
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
// A whole `threads` section reaches the same config key, and `threads` canonicalizes to itself
|
|
1277
|
+
// rather than to `threads_count`. It arrives either as an object or as the JSON string
|
|
1278
|
+
// castConfigValue parses, and flattenConfig lowercases every key on the way back out, so the nested
|
|
1279
|
+
// name has to be matched the same way the top-level one is.
|
|
1280
|
+
function readSectionHeapMemory(section) {
|
|
1281
|
+
const parsed = castConfigValue(CONFIG_PARAMS.THREADS, section);
|
|
1282
|
+
if (!hdbUtils.isObject(parsed)) return undefined;
|
|
1283
|
+
for (const key in parsed) if (key.toLowerCase() === 'maxheapmemory') return parsed[key];
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1042
1286
|
/**
|
|
1043
1287
|
* Set Configuration - this function sets new configuration
|
|
1044
1288
|
* @param setConfigJson
|
|
1045
1289
|
|
|
1046
1290
|
*/
|
|
1047
1291
|
export async function setConfiguration(setConfigJson) {
|
|
1292
|
+
// `hdb_auth_header` is the 4.x spelling of `hdbAuthHeader`, and `impersonate` is a generic
|
|
1293
|
+
// operation-body field (server/operationsServer.ts): control fields, never config params.
|
|
1048
1294
|
// eslint-disable-next-line no-unused-vars
|
|
1049
|
-
const { operation, hdb_user, hdbAuthHeader, replicated, ...configFields } =
|
|
1295
|
+
const { operation, hdb_user, hdbAuthHeader, hdb_auth_header, impersonate, replicated, ...configFields } =
|
|
1296
|
+
setConfigJson;
|
|
1050
1297
|
// Operation-control field, not a config param: enforce boolean (matching other
|
|
1051
1298
|
// `replicated` surfaces, e.g. analyticsValidator) before any local write so a
|
|
1052
1299
|
// malformed value like the string "false" — which is truthy — can't apply config
|
|
@@ -1061,6 +1308,32 @@ export async function setConfiguration(setConfigJson) {
|
|
|
1061
1308
|
true
|
|
1062
1309
|
);
|
|
1063
1310
|
}
|
|
1311
|
+
const reservedComponentParams = findReservedComponentParams(configFields);
|
|
1312
|
+
if (reservedComponentParams.length > 0) {
|
|
1313
|
+
throw handleHDBError(
|
|
1314
|
+
new Error(),
|
|
1315
|
+
`Unable to update config, cannot configure a component whose name is reserved for Harper's own configuration section: ${describeUnrecognized(reservedComponentParams)}`,
|
|
1316
|
+
HTTP_STATUS_CODES.BAD_REQUEST,
|
|
1317
|
+
undefined,
|
|
1318
|
+
undefined,
|
|
1319
|
+
true
|
|
1320
|
+
);
|
|
1321
|
+
}
|
|
1322
|
+
// Before any local write: the writer skips names it cannot resolve, so a request mixing
|
|
1323
|
+
// recognized and unrecognized names would otherwise apply the recognized half and still report
|
|
1324
|
+
// success.
|
|
1325
|
+
const unrecognized = findUnrecognizedParams(configFields);
|
|
1326
|
+
if (unrecognized.length > 0) {
|
|
1327
|
+
throw handleHDBError(
|
|
1328
|
+
new Error(),
|
|
1329
|
+
`Unable to update config, unrecognized config parameter${unrecognized.length > 1 ? 's' : ''}: ${describeUnrecognized(unrecognized)}`,
|
|
1330
|
+
HTTP_STATUS_CODES.BAD_REQUEST,
|
|
1331
|
+
undefined,
|
|
1332
|
+
undefined,
|
|
1333
|
+
true
|
|
1334
|
+
);
|
|
1335
|
+
}
|
|
1336
|
+
assertThreadHeapMemoryStartable(configFields);
|
|
1064
1337
|
try {
|
|
1065
1338
|
updateConfigValue(undefined, undefined, configFields, true);
|
|
1066
1339
|
if (replicated) {
|
|
@@ -1151,9 +1424,16 @@ function applyRuntimeEnvVarConfig(configDoc, configFilePath, options = {}) {
|
|
|
1151
1424
|
// Convert to JSON for processing
|
|
1152
1425
|
const configObj = configDoc.toJSON();
|
|
1153
1426
|
|
|
1427
|
+
let saveEnvConfigState;
|
|
1428
|
+
let confirmEnvConfigState;
|
|
1429
|
+
let commitEnvConfigState;
|
|
1154
1430
|
try {
|
|
1155
1431
|
// Apply env vars with source tracking and drift detection
|
|
1156
|
-
|
|
1432
|
+
({
|
|
1433
|
+
saveState: saveEnvConfigState,
|
|
1434
|
+
confirmConfigWritten: confirmEnvConfigState,
|
|
1435
|
+
commitState: commitEnvConfigState,
|
|
1436
|
+
} = prepareRuntimeEnvConfig(configObj, rootPath, options));
|
|
1157
1437
|
|
|
1158
1438
|
// If securePort was set to the same value as port, auto-null port to avoid clashing
|
|
1159
1439
|
if (configObj.http?.port && configObj.http?.port === configObj.http?.securePort) {
|
|
@@ -1185,11 +1465,18 @@ function applyRuntimeEnvVarConfig(configDoc, configFilePath, options = {}) {
|
|
|
1185
1465
|
throw error;
|
|
1186
1466
|
}
|
|
1187
1467
|
|
|
1188
|
-
//
|
|
1468
|
+
// Install has no config file yet and no process to keep alive, so its snapshot write stays
|
|
1469
|
+
// mandatory - an install that never recorded originals should fail, not proceed.
|
|
1189
1470
|
if (!configFilePath) {
|
|
1471
|
+
commitEnvConfigState();
|
|
1190
1472
|
return;
|
|
1191
1473
|
}
|
|
1192
1474
|
|
|
1475
|
+
// Every worker thread runs initConfig and derives the same merged config, so letting them all
|
|
1476
|
+
// persist it means N threads racing over one pair of files for a result they already agree on.
|
|
1477
|
+
// The main thread owns the on-disk copy; a worker runs on the in-memory one.
|
|
1478
|
+
if (!isMainThread) return;
|
|
1479
|
+
|
|
1193
1480
|
// Persist changes to file
|
|
1194
1481
|
try {
|
|
1195
1482
|
if (configDoc.errors?.length > 0) {
|
|
@@ -1199,8 +1486,30 @@ function applyRuntimeEnvVarConfig(configDoc, configFilePath, options = {}) {
|
|
|
1199
1486
|
HTTP_STATUS_CODES.INTERNAL_SERVER_ERROR
|
|
1200
1487
|
);
|
|
1201
1488
|
}
|
|
1202
|
-
|
|
1203
|
-
|
|
1489
|
+
// Stage, write the file, promote by rename: the confirmed state is the only record of the
|
|
1490
|
+
// file's pre-env values, so no write an exhausted volume can refuse may stand between it and
|
|
1491
|
+
// disk. See DESIGN.md, boot-path config persistence.
|
|
1492
|
+
let stateStaged = false;
|
|
1493
|
+
if (persistConfigDuringBoot(`${rootPath} env config state`, () => (stateStaged = saveEnvConfigState()))) {
|
|
1494
|
+
let configPersisted = false;
|
|
1495
|
+
let configRewritten = false;
|
|
1496
|
+
try {
|
|
1497
|
+
configPersisted = persistConfigDuringBoot(configFilePath, () => {
|
|
1498
|
+
configRewritten = atomicWriteFile(configFilePath, String(configDoc), { skipIfUnchanged: true });
|
|
1499
|
+
});
|
|
1500
|
+
} finally {
|
|
1501
|
+
if (!configPersisted && stateStaged) discardConfigState(rootPath as string);
|
|
1502
|
+
}
|
|
1503
|
+
if (configPersisted) {
|
|
1504
|
+
if (stateStaged) confirmEnvConfigState();
|
|
1505
|
+
// Distinguished, because this is the line that answers "did something rewrite my config?"
|
|
1506
|
+
logger.debug(
|
|
1507
|
+
configRewritten
|
|
1508
|
+
? 'Config file updated with runtime env var values'
|
|
1509
|
+
: 'Config file already matched the runtime env var values'
|
|
1510
|
+
);
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1204
1513
|
} catch (error) {
|
|
1205
1514
|
logger.error(`Failed to write config file after applying runtime env vars: ${error.message}`);
|
|
1206
1515
|
throw error;
|