@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
|
@@ -11,6 +11,8 @@ import {
|
|
|
11
11
|
} from 'node:fs';
|
|
12
12
|
import { join, basename, dirname, sep } from 'node:path';
|
|
13
13
|
import { isMainThread } from 'node:worker_threads';
|
|
14
|
+
|
|
15
|
+
import { isDeployValidating } from '../server/serverHelpers/deployValidationState.ts';
|
|
14
16
|
import { parseDocument } from 'yaml';
|
|
15
17
|
import * as env from '../utility/environment/environmentManager.ts';
|
|
16
18
|
import { PACKAGE_ROOT } from '../utility/packageUtils.js';
|
|
@@ -30,16 +32,23 @@ import { restartWorkers, getWorkerIndex } from '../server/threads/manageThreads.
|
|
|
30
32
|
import { resetRestartNeeded, subscribeToRestartRequests } from './requestRestart.ts';
|
|
31
33
|
import { trackScopeClose } from './scopeShutdown.ts';
|
|
32
34
|
import { deployLifecycle } from './deployLifecycle.ts';
|
|
35
|
+
import { assertBranchedDatabases, assertIsolationConfig } from './Application.ts';
|
|
36
|
+
import { prepareBranches } from '../resources/branchDatabase.ts';
|
|
37
|
+
import {
|
|
38
|
+
isIsolatedApplication,
|
|
39
|
+
shouldLoadApplicationHere,
|
|
40
|
+
thisThreadOwnsApplication,
|
|
41
|
+
} from '../server/threads/isolatedApplications.ts';
|
|
33
42
|
import { toScopeMount, nestScopeMount, type ScopeMount } from './scopeMount.ts';
|
|
34
43
|
import { scopedImport } from '../security/jsLoader.ts';
|
|
35
44
|
import { server } from '../server/Server.ts';
|
|
36
45
|
import { Resources } from '../resources/Resources.ts';
|
|
37
|
-
import {
|
|
46
|
+
import { scopedTableFactory } from '../resources/databases.ts';
|
|
38
47
|
import { getHdbBasePath } from '../utility/environment/environmentManager.ts';
|
|
39
48
|
import * as auth from '../security/auth.ts';
|
|
40
49
|
import * as mqtt from '../server/mqtt.ts';
|
|
41
50
|
import { getConfigObj, getConfigPath } from '../config/configUtils.ts';
|
|
42
|
-
import { bootstrapModels } from '../resources/models/bootstrap.ts';
|
|
51
|
+
import { bootstrapModels, startModelsConfigHotReload } from '../resources/models/bootstrap.ts';
|
|
43
52
|
import { ErrorResource } from '../resources/ErrorResource.ts';
|
|
44
53
|
import { Scope } from './Scope.ts';
|
|
45
54
|
import { ApplicationScope } from './ApplicationScope.ts';
|
|
@@ -47,17 +56,71 @@ import { ComponentV1, processResourceExtensionComponent } from './ComponentV1.ts
|
|
|
47
56
|
import * as httpComponent from '../server/http.ts';
|
|
48
57
|
import * as mcpComponent from './mcp/index.ts';
|
|
49
58
|
import { Status } from '../server/status/index.ts';
|
|
50
|
-
import { lifecycle as componentLifecycle } from './status/index.ts';
|
|
59
|
+
import { lifecycle as componentLifecycle, statusForComponent } from './status/index.ts';
|
|
51
60
|
import { DEFAULT_CONFIG } from './DEFAULT_CONFIG.ts';
|
|
52
61
|
import { materializeGlobalSecrets, processComponentEnv } from './componentSecrets.ts';
|
|
53
62
|
import { PluginModule } from './PluginModule.ts';
|
|
54
|
-
import {
|
|
63
|
+
import {
|
|
64
|
+
getEnvBuiltInComponents,
|
|
65
|
+
recoverInterruptedActivations,
|
|
66
|
+
recoverInterruptedComponentExtraction,
|
|
67
|
+
recoverInterruptedComponentExtractions,
|
|
68
|
+
unsettleableComponentsFromDisk,
|
|
69
|
+
} from './Application.ts';
|
|
70
|
+
import { ComponentPreparationLockTimeoutError } from './componentPreparationLock.ts';
|
|
55
71
|
import { pathToFileURL } from 'node:url';
|
|
56
72
|
|
|
57
73
|
const CF_ROUTES_DIR = getConfigPath(CONFIG_PARAMS.COMPONENTSROOT);
|
|
74
|
+
|
|
58
75
|
let loadedComponents = new Map<any, any>();
|
|
76
|
+
|
|
77
|
+
// Marks a registry entry as belonging to a deploy validation's throwaway load, so cleanup can tell whether
|
|
78
|
+
// an ordinary load has since ADOPTED that module. Checking "was it already loaded?" before the fact is not
|
|
79
|
+
// enough: ownership changes after that check when a real load reuses the entry while the validation is
|
|
80
|
+
// still running, and deleting it then removes a module a live consumer depends on.
|
|
81
|
+
const VALIDATION_OWNED = Symbol('validationOwnedModule');
|
|
59
82
|
let watchesSetup;
|
|
60
83
|
let resources;
|
|
84
|
+
const componentLoadTails = new Map<string, Promise<void>>();
|
|
85
|
+
type ComponentReadyPromises = WeakMap<object, Promise<void>>;
|
|
86
|
+
|
|
87
|
+
function serializeComponentLoad<T>(appName: string, load: () => Promise<T>): Promise<T> {
|
|
88
|
+
const previousLoad = componentLoadTails.get(appName);
|
|
89
|
+
const currentLoad = previousLoad ? previousLoad.then(load) : load();
|
|
90
|
+
const loadTail = currentLoad.then(
|
|
91
|
+
() => undefined,
|
|
92
|
+
() => undefined
|
|
93
|
+
);
|
|
94
|
+
componentLoadTails.set(appName, loadTail);
|
|
95
|
+
void loadTail.then(() => {
|
|
96
|
+
if (componentLoadTails.get(appName) === loadTail) componentLoadTails.delete(appName);
|
|
97
|
+
});
|
|
98
|
+
return currentLoad;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export async function readyComponentModules(
|
|
102
|
+
serverModules: Iterable<any>,
|
|
103
|
+
readyComponentPromises: ComponentReadyPromises = new WeakMap()
|
|
104
|
+
): Promise<void> {
|
|
105
|
+
const readyPromises: Promise<void>[] = [];
|
|
106
|
+
for (const serverModule of serverModules) {
|
|
107
|
+
if (
|
|
108
|
+
(typeof serverModule !== 'object' && typeof serverModule !== 'function') ||
|
|
109
|
+
serverModule === null ||
|
|
110
|
+
typeof serverModule.ready !== 'function'
|
|
111
|
+
) {
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
let readyPromise = readyComponentPromises.get(serverModule);
|
|
115
|
+
if (!readyPromise) {
|
|
116
|
+
readyPromise = Promise.resolve().then(() => serverModule.ready());
|
|
117
|
+
readyComponentPromises.set(serverModule, readyPromise);
|
|
118
|
+
void readyPromise.catch(() => readyComponentPromises.delete(serverModule));
|
|
119
|
+
}
|
|
120
|
+
readyPromises.push(readyPromise);
|
|
121
|
+
}
|
|
122
|
+
await Promise.all(readyPromises);
|
|
123
|
+
}
|
|
61
124
|
|
|
62
125
|
/**
|
|
63
126
|
* Load all the applications registered in Harper, those in the components directory as well as any directly
|
|
@@ -86,6 +149,49 @@ function rootConfigMount(appName: string): ScopeMount | undefined {
|
|
|
86
149
|
return toScopeMount(getConfigObj()?.[appName]);
|
|
87
150
|
}
|
|
88
151
|
|
|
152
|
+
/**
|
|
153
|
+
* The databases an operator declared that `appName` should get a private fork of, from the root
|
|
154
|
+
* config — the same place `host`/`urlPath` are declared, and for the same reason. Which databases an
|
|
155
|
+
* application forks is a deployment decision, not something the application checks in: the operator
|
|
156
|
+
* deploying it onto a cluster is who knows whether it should run against its own copy.
|
|
157
|
+
*
|
|
158
|
+
* ```yaml
|
|
159
|
+
* my-app:
|
|
160
|
+
* host: api.example.com
|
|
161
|
+
* branchedDatabases: [data]
|
|
162
|
+
* ```
|
|
163
|
+
*/
|
|
164
|
+
function rootConfigBranchedDatabases(appName: string): string[] | true | undefined {
|
|
165
|
+
if (Object.hasOwn(TRUSTED_RESOURCE_PLUGINS, appName)) return undefined;
|
|
166
|
+
return (getConfigObj()?.[appName] as any)?.branchedDatabases;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Whether this thread is the one that loads `appName` (harper#642, tier 2). An isolated application
|
|
171
|
+
* is loaded by its dedicated worker and by nothing else; every other thread loads only the
|
|
172
|
+
* applications that are not isolated. Decided before any of the application's modules are imported.
|
|
173
|
+
* With no worker threads at all there is nowhere for an isolated application to run, so it fails
|
|
174
|
+
* closed here rather than silently sharing the only thread.
|
|
175
|
+
*/
|
|
176
|
+
function placedOnThisThread(appName: string): boolean {
|
|
177
|
+
if (Object.hasOwn(TRUSTED_RESOURCE_PLUGINS, appName)) return true;
|
|
178
|
+
try {
|
|
179
|
+
assertIsolationConfig(appName, (getConfigObj()?.[appName] as any)?.isolated);
|
|
180
|
+
} catch (error) {
|
|
181
|
+
componentLifecycle.failed(appName, error, `Component '${appName}' failed to load`);
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
if (isIsolatedApplication(appName) && isMainThread && getWorkerIndex() === 0) {
|
|
185
|
+
componentLifecycle.failed(
|
|
186
|
+
appName,
|
|
187
|
+
new Error(`Application '${appName}' is isolated, which needs a worker thread of its own, but threads.count is 0`),
|
|
188
|
+
`Component '${appName}' failed to load`
|
|
189
|
+
);
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
return shouldLoadApplicationHere(appName);
|
|
193
|
+
}
|
|
194
|
+
|
|
89
195
|
/**
|
|
90
196
|
* Resolves the mount for `appName`, or reports the failure and returns `undefined` if the
|
|
91
197
|
* configured `host`/`urlPath` is invalid. The caller must skip loading the application in that
|
|
@@ -110,15 +216,115 @@ function tryRootConfigMount(appName: string): { ok: true; mount: ScopeMount | un
|
|
|
110
216
|
}
|
|
111
217
|
}
|
|
112
218
|
|
|
113
|
-
export async function loadComponentDirectories(
|
|
219
|
+
export async function loadComponentDirectories(
|
|
220
|
+
loadedPluginModules?: Map<any, any>,
|
|
221
|
+
loadedResources?: Resources,
|
|
222
|
+
readyComponentPromises: ComponentReadyPromises = new WeakMap(),
|
|
223
|
+
// Settled by boot BEFORE installApplications(), because that installs from the root config and would
|
|
224
|
+
// otherwise reinstall the previous release over an already-live candidate. `undefined` on a worker,
|
|
225
|
+
// which never runs that pass — distinct from an empty map, which would claim nothing is unreconciled.
|
|
226
|
+
interruptedActivationFailures?: Map<string, Error>
|
|
227
|
+
) {
|
|
114
228
|
if (loadedResources) resources = loadedResources;
|
|
115
229
|
if (loadedPluginModules) loadedComponents = loadedPluginModules;
|
|
230
|
+
const cycleResources = resources;
|
|
231
|
+
const failedRecoveries = new Map<string, Error>(interruptedActivationFailures ?? []);
|
|
232
|
+
if (!interruptedActivationFailures) {
|
|
233
|
+
// No verdict from boot means this is a worker, which never runs the recovery pass. It reads the same
|
|
234
|
+
// evidence instead: a component whose activation could not be settled must not load here either,
|
|
235
|
+
// since workers are what actually serve it.
|
|
236
|
+
//
|
|
237
|
+
// Settlement itself runs here too, not just the read-only check. A worker can be auto-restarted at any
|
|
238
|
+
// time — including mid-activation — and the legacy pass below then has an unsettled journal in front
|
|
239
|
+
// of it, which it refuses to restore against: the component stalls instead of loading. Main-thread
|
|
240
|
+
// startup sequencing does not protect a worker that restarts later. Safe to run on any thread: each deployment is settled under
|
|
241
|
+
// the component preparation lock, which is cross-thread and cross-process, and the pass is idempotent.
|
|
242
|
+
try {
|
|
243
|
+
for (const [component, error] of await recoverInterruptedActivations(CF_ROUTES_DIR)) {
|
|
244
|
+
if (!failedRecoveries.has(component)) failedRecoveries.set(component, error);
|
|
245
|
+
}
|
|
246
|
+
} catch (error) {
|
|
247
|
+
harperLogger.warn(
|
|
248
|
+
'Could not settle interrupted component activations on this thread:',
|
|
249
|
+
errorForLog(error instanceof Error ? error : new Error(String(error)))
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
// Plus anything a previous pass recorded as unsettleable, which settlement above leaves in place.
|
|
253
|
+
try {
|
|
254
|
+
for (const [component, error] of await unsettleableComponentsFromDisk(CF_ROUTES_DIR)) {
|
|
255
|
+
if (!failedRecoveries.has(component)) failedRecoveries.set(component, error);
|
|
256
|
+
}
|
|
257
|
+
} catch (error) {
|
|
258
|
+
harperLogger.warn(
|
|
259
|
+
'Could not check for unsettled component activations:',
|
|
260
|
+
errorForLog(error instanceof Error ? error : new Error(String(error)))
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
try {
|
|
265
|
+
for (const [component, error] of await recoverInterruptedComponentExtractions(CF_ROUTES_DIR)) {
|
|
266
|
+
if (!failedRecoveries.has(component)) failedRecoveries.set(component, error);
|
|
267
|
+
}
|
|
268
|
+
} catch (error) {
|
|
269
|
+
const recoveryError = error instanceof Error ? error : new Error(String(error));
|
|
270
|
+
harperLogger.warn(
|
|
271
|
+
'Loading existing filesystem components without deploy recovery because staging could not be inspected:',
|
|
272
|
+
errorForLog(recoveryError)
|
|
273
|
+
);
|
|
274
|
+
}
|
|
116
275
|
// Materialize hdb_secret global-tier rows into process.env and snapshot the scoped tier before
|
|
117
276
|
// any application loads (root components — including the Pro custody registration — have
|
|
118
277
|
// already loaded by this point). Re-runs on each reload cycle, which is how changed/late-custody
|
|
119
278
|
// secrets heal. Never throws.
|
|
120
279
|
await materializeGlobalSecrets();
|
|
121
280
|
const cfsLoaded: Promise<any>[] = [];
|
|
281
|
+
const deferredRecoveries = new Map(
|
|
282
|
+
[...failedRecoveries].filter(([, error]) => error instanceof ComponentPreparationLockTimeoutError)
|
|
283
|
+
);
|
|
284
|
+
const unreportedFailedRecoveries = new Map(
|
|
285
|
+
[...failedRecoveries].filter(([, error]) => !(error instanceof ComponentPreparationLockTimeoutError))
|
|
286
|
+
);
|
|
287
|
+
const deferComponentLoad = (appName: string) => {
|
|
288
|
+
const appFolder = join(CF_ROUTES_DIR, appName);
|
|
289
|
+
const appWasVisible = existsSync(appFolder);
|
|
290
|
+
if (appWasVisible) {
|
|
291
|
+
componentLifecycle.loading(appName, `Component '${appName}' is waiting for in-progress preparation to finish`);
|
|
292
|
+
}
|
|
293
|
+
void serializeComponentLoad(appName, () =>
|
|
294
|
+
recoverInterruptedComponentExtraction(CF_ROUTES_DIR, appName)
|
|
295
|
+
.then(async () => {
|
|
296
|
+
if (!existsSync(appFolder)) {
|
|
297
|
+
if (appWasVisible) {
|
|
298
|
+
statusForComponent(appName).unknown('Component directory no longer exists after preparation settled');
|
|
299
|
+
}
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
if (!placedOnThisThread(appName)) return;
|
|
303
|
+
const mountResult = tryRootConfigMount(appName);
|
|
304
|
+
if (!mountResult.ok) return;
|
|
305
|
+
const loadedModules = new Set<any>();
|
|
306
|
+
await loadComponent(appFolder, cycleResources, HDB_ROOT_DIR_NAME, {
|
|
307
|
+
isRoot: false,
|
|
308
|
+
autoReload: false,
|
|
309
|
+
appName,
|
|
310
|
+
mount: mountResult.mount,
|
|
311
|
+
branchedDatabases: rootConfigBranchedDatabases(appName),
|
|
312
|
+
collectLoadedModules: loadedModules,
|
|
313
|
+
});
|
|
314
|
+
await readyComponentModules(loadedModules, readyComponentPromises);
|
|
315
|
+
})
|
|
316
|
+
.catch((error) => {
|
|
317
|
+
const recoveryError = error instanceof Error ? error : new Error(String(error));
|
|
318
|
+
if (appWasVisible) {
|
|
319
|
+
componentLifecycle.failed(
|
|
320
|
+
appName,
|
|
321
|
+
recoveryError,
|
|
322
|
+
`Component '${appName}' failed to load after waiting for in-progress preparation`
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
})
|
|
326
|
+
);
|
|
327
|
+
};
|
|
122
328
|
if (existsSync(CF_ROUTES_DIR)) {
|
|
123
329
|
const cfFolders = readdirSync(CF_ROUTES_DIR, { withFileTypes: true });
|
|
124
330
|
for (const appEntry of cfFolders) {
|
|
@@ -127,35 +333,71 @@ export async function loadComponentDirectories(loadedPluginModules?: Map<any, an
|
|
|
127
333
|
// Harper's own staging dirs (e.g. deploy aside copies) from loading as components.
|
|
128
334
|
if (appEntry.name.startsWith('.')) continue;
|
|
129
335
|
const appName = appEntry.name;
|
|
336
|
+
const recoveryError = failedRecoveries.get(appName);
|
|
337
|
+
if (recoveryError) {
|
|
338
|
+
if (recoveryError instanceof ComponentPreparationLockTimeoutError) {
|
|
339
|
+
deferredRecoveries.delete(appName);
|
|
340
|
+
deferComponentLoad(appName);
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
343
|
+
unreportedFailedRecoveries.delete(appName);
|
|
344
|
+
componentLifecycle.failed(
|
|
345
|
+
appName,
|
|
346
|
+
recoveryError,
|
|
347
|
+
`Component '${appName}' failed to load because its interrupted deployment could not be recovered`
|
|
348
|
+
);
|
|
349
|
+
continue;
|
|
350
|
+
}
|
|
351
|
+
if (!placedOnThisThread(appName)) continue;
|
|
130
352
|
const appFolder = join(CF_ROUTES_DIR, appName);
|
|
131
353
|
const mountResult = tryRootConfigMount(appName);
|
|
132
354
|
if (!mountResult.ok) continue;
|
|
133
355
|
cfsLoaded.push(
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
356
|
+
serializeComponentLoad(appName, () =>
|
|
357
|
+
loadComponent(appFolder, cycleResources, HDB_ROOT_DIR_NAME, {
|
|
358
|
+
isRoot: false,
|
|
359
|
+
autoReload: false,
|
|
360
|
+
appName,
|
|
361
|
+
mount: mountResult.mount,
|
|
362
|
+
branchedDatabases: rootConfigBranchedDatabases(appName),
|
|
363
|
+
})
|
|
364
|
+
).catch((error) => {
|
|
365
|
+
const loadError = error instanceof Error ? error : new Error(String(error));
|
|
366
|
+
componentLifecycle.failed(appName, loadError, `Component '${appName}' failed to load`);
|
|
139
367
|
})
|
|
140
368
|
);
|
|
141
369
|
}
|
|
142
370
|
}
|
|
371
|
+
for (const [appName, recoveryError] of unreportedFailedRecoveries) {
|
|
372
|
+
componentLifecycle.failed(
|
|
373
|
+
appName,
|
|
374
|
+
recoveryError,
|
|
375
|
+
`Component '${appName}' failed to load because its interrupted deployment could not be recovered`
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
for (const appName of deferredRecoveries.keys()) deferComponentLoad(appName);
|
|
143
379
|
const hdbAppFolder = process.env.RUN_HDB_APP;
|
|
144
380
|
if (hdbAppFolder) {
|
|
145
381
|
if (getWorkerIndex() === 0) harperLogger.info?.('Loading application from ' + hdbAppFolder);
|
|
146
382
|
const mountResult = tryRootConfigMount(basename(hdbAppFolder));
|
|
147
|
-
if (mountResult.ok) {
|
|
383
|
+
if (mountResult.ok && placedOnThisThread(basename(hdbAppFolder))) {
|
|
148
384
|
cfsLoaded.push(
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
385
|
+
serializeComponentLoad(hdbAppFolder, () =>
|
|
386
|
+
loadComponent(hdbAppFolder, cycleResources, hdbAppFolder, {
|
|
387
|
+
isRoot: false,
|
|
388
|
+
autoReload: Boolean(process.env.DEV_MODE),
|
|
389
|
+
// The directory arg above stays the absolute path -- that's a real filesystem
|
|
390
|
+
// location -- but `appName` here is the branch identity, and a branch path segment
|
|
391
|
+
// cannot contain `/`; use the same basename the config lookup on the next line uses.
|
|
392
|
+
appName: basename(hdbAppFolder),
|
|
393
|
+
mount: mountResult.mount,
|
|
394
|
+
branchedDatabases: rootConfigBranchedDatabases(basename(hdbAppFolder)),
|
|
395
|
+
})
|
|
396
|
+
)
|
|
155
397
|
);
|
|
156
398
|
}
|
|
157
399
|
}
|
|
158
|
-
return Promise.all(cfsLoaded).then(() => {
|
|
400
|
+
return await Promise.all(cfsLoaded).then(() => {
|
|
159
401
|
watchesSetup = true;
|
|
160
402
|
});
|
|
161
403
|
}
|
|
@@ -233,6 +475,51 @@ export const loadedPaths = new Map();
|
|
|
233
475
|
export const mainThreadInitialized = new Map<string, any>();
|
|
234
476
|
|
|
235
477
|
let errorReporter;
|
|
478
|
+
/**
|
|
479
|
+
* Forget that a directory was loaded, so a throwaway load does not retain it forever. `loadedPaths` is
|
|
480
|
+
* keyed by realpath and never pruned, and every deploy validates a candidate under a fresh
|
|
481
|
+
* `.deploy-staging/<uuid>/` path — so without this the map grows by one dead entry per deploy for the life
|
|
482
|
+
* of the process.
|
|
483
|
+
*/
|
|
484
|
+
export function forgetLoadedPath(componentDirectory: string): void {
|
|
485
|
+
let resolved: string | undefined;
|
|
486
|
+
try {
|
|
487
|
+
resolved = realpathSync(componentDirectory);
|
|
488
|
+
} catch {
|
|
489
|
+
// Already renamed live or discarded; fall through and prune by prefix anyway.
|
|
490
|
+
}
|
|
491
|
+
if (resolved) loadedPaths.delete(resolved);
|
|
492
|
+
// Nested `loadComponent()` calls register plugin and dependency realpaths UNDER the candidate, so
|
|
493
|
+
// deleting only the root leaves those behind — one dead entry per nested load, per deploy, forever.
|
|
494
|
+
const prefixes = [componentDirectory, resolved].filter(Boolean) as string[];
|
|
495
|
+
for (const key of loadedPaths.keys()) {
|
|
496
|
+
if (typeof key === 'string' && prefixes.some((prefix) => key === prefix || key.startsWith(prefix + sep))) {
|
|
497
|
+
loadedPaths.delete(key);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Release exactly the modules a throwaway validation load registered, as collected by that load's
|
|
504
|
+
* `collectLoadedModules` set.
|
|
505
|
+
*
|
|
506
|
+
* Exactly those, not a before/after diff of the global registry: validations are serialized with each other
|
|
507
|
+
* but not with ordinary loads, so a deferred real load for another component can register between the two
|
|
508
|
+
* snapshots — and a diff would then delete that live module.
|
|
509
|
+
*/
|
|
510
|
+
export function forgetLoadedModules(modules: Iterable<any>): void {
|
|
511
|
+
// Only entries STILL owned by that validation. Validations serialize with each other but not with
|
|
512
|
+
// ordinary loads, so a real load can adopt a module the validation registered while it is still running —
|
|
513
|
+
// re-registering the same entry as live — and deleting it afterwards would take a live module with it.
|
|
514
|
+
for (const module of modules) {
|
|
515
|
+
if (loadedComponents.get(module) === VALIDATION_OWNED) loadedComponents.delete(module);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
/** So a caller that installs a reporter can put the previous one back when it is done with it. */
|
|
520
|
+
export function getErrorReporter() {
|
|
521
|
+
return errorReporter;
|
|
522
|
+
}
|
|
236
523
|
export function setErrorReporter(reporter) {
|
|
237
524
|
errorReporter = reporter;
|
|
238
525
|
}
|
|
@@ -252,22 +539,27 @@ export const getComponentName = () => compName;
|
|
|
252
539
|
* every non-root component load and repaired if missing or pointing elsewhere.
|
|
253
540
|
*/
|
|
254
541
|
function symlinkHarperModule(componentDirectory: string) {
|
|
255
|
-
return new Promise<void>((resolve
|
|
542
|
+
return new Promise<void>((resolve) => {
|
|
256
543
|
const store = Status.primaryStore;
|
|
257
|
-
|
|
258
|
-
const
|
|
259
|
-
store.unlock(componentDirectory);
|
|
260
|
-
reject(new Error('symlinking harperdb module timed out'));
|
|
261
|
-
}, 10_000);
|
|
262
|
-
|
|
263
|
-
const callback = () => {
|
|
544
|
+
let timeout: NodeJS.Timeout;
|
|
545
|
+
const onUnlocked = () => {
|
|
264
546
|
clearTimeout(timeout);
|
|
265
547
|
resolve();
|
|
266
548
|
};
|
|
267
|
-
const lockAcquired = store.tryLock(componentDirectory,
|
|
549
|
+
const lockAcquired = store.tryLock(componentDirectory, onUnlocked);
|
|
268
550
|
|
|
269
551
|
if (!lockAcquired) {
|
|
270
|
-
|
|
552
|
+
// The lock holder performs the fixup; wait for its unlock. The timer bounds the wait if
|
|
553
|
+
// the holder dies without unlocking, and must stay ref'd: the unlock wake arrives via an
|
|
554
|
+
// unref'd threadsafe function (see the invariant comment in threadServer.startServers).
|
|
555
|
+
// Timing out resolves rather than rejects: the fixup is idempotent maintenance, never
|
|
556
|
+
// worth failing the component load over.
|
|
557
|
+
timeout = setTimeout(() => {
|
|
558
|
+
harperLogger.warn(
|
|
559
|
+
`Timed out waiting for another thread to verify the harper module link in ${componentDirectory}; continuing with the link in its current state`
|
|
560
|
+
);
|
|
561
|
+
resolve();
|
|
562
|
+
}, 10_000);
|
|
271
563
|
} else {
|
|
272
564
|
try {
|
|
273
565
|
// validate node_modules directory exists
|
|
@@ -311,6 +603,9 @@ function symlinkHarperModule(componentDirectory: string) {
|
|
|
311
603
|
});
|
|
312
604
|
}
|
|
313
605
|
|
|
606
|
+
// Direct access keeps lock timing deterministic without exposing a broader component-load seam.
|
|
607
|
+
export const _symlinkHarperModuleForTests = symlinkHarperModule;
|
|
608
|
+
|
|
314
609
|
/**
|
|
315
610
|
* This function handles the `handleApplication` call for a plugin in a sequential manner.
|
|
316
611
|
* It ensures the execution of `handleApplication` happens on one thread at a time for a given scope.
|
|
@@ -421,11 +716,14 @@ export interface LoadComponentOptions {
|
|
|
421
716
|
autoReload?: boolean;
|
|
422
717
|
providedLoadedComponents?: Map<any, any>;
|
|
423
718
|
appName?: string;
|
|
719
|
+
/** Databases this application forks, from its root-config entry (see `rootConfigBranchedDatabases`). */
|
|
720
|
+
branchedDatabases?: string[] | true;
|
|
424
721
|
// When provided, every Scope created during this load is added to this set instead of being
|
|
425
722
|
// auto-closed on worker shutdown. The caller then owns closing them. Used by transient loads
|
|
426
723
|
// (e.g. the deploy pre-flight validation) so their deploy-lifecycle listeners don't accumulate
|
|
427
724
|
// across deploys (#1462).
|
|
428
725
|
collectScopes?: Set<Scope>;
|
|
726
|
+
collectLoadedModules?: Set<any>;
|
|
429
727
|
// Routing the operator declared for this application in the root config (`host`/`urlPath` on
|
|
430
728
|
// the application's entry). Applied to every plugin scope this load creates, and inherited by
|
|
431
729
|
// components the application itself declares, so the whole subtree moves together.
|
|
@@ -457,6 +755,7 @@ export async function loadComponent(
|
|
|
457
755
|
autoReload,
|
|
458
756
|
appName,
|
|
459
757
|
mount,
|
|
758
|
+
collectLoadedModules,
|
|
460
759
|
} = options;
|
|
461
760
|
applicationScope.runtimeRoot ??= resolvedFolder;
|
|
462
761
|
applicationScope.allowedPath ??= realpathSync(componentDirectory);
|
|
@@ -477,6 +776,36 @@ export async function loadComponent(
|
|
|
477
776
|
}
|
|
478
777
|
applicationScope.config ??= config;
|
|
479
778
|
|
|
779
|
+
// Before any of the application's modules are imported: a branch has to exist by the time its
|
|
780
|
+
// code first reaches `databases`, and a declared branch that cannot be created must fail this
|
|
781
|
+
// application's load rather than let it run against the base it asked not to share.
|
|
782
|
+
// Declaring it in the application's own config.yaml is refused rather than ignored: it is a
|
|
783
|
+
// deployment decision and lives in the root config, and an application that believed it had a
|
|
784
|
+
// private fork while silently sharing the base is the one outcome this feature exists to stop.
|
|
785
|
+
if (!isRoot && config?.branchedDatabases !== undefined) {
|
|
786
|
+
const misplaced =
|
|
787
|
+
`Application '${options.appName ?? basename(componentDirectory)}' declares branchedDatabases in its own ` +
|
|
788
|
+
`config; it belongs in the root config entry for the application, alongside host and urlPath`;
|
|
789
|
+
// Logged as well as thrown: a component load that rejects this way surfaces downstream only as
|
|
790
|
+
// the application's routes and operations being absent, which says nothing about the cause.
|
|
791
|
+
harperLogger.error?.(misplaced);
|
|
792
|
+
throw new Error(misplaced);
|
|
793
|
+
}
|
|
794
|
+
// Only on the application's own load: nested components share its scope and its branches, and
|
|
795
|
+
// re-preparing per component would key a second branch off the same application name.
|
|
796
|
+
if (!isRoot && !options.applicationScope && options.branchedDatabases !== undefined) {
|
|
797
|
+
// The loader's own application identity, not the directory's basename: a branch path is
|
|
798
|
+
// keyed by this, and two components can share a basename (a nested one and a top-level one)
|
|
799
|
+
// while being different applications that must not share a fork each believes is private.
|
|
800
|
+
const branchAppName = options.appName ?? basename(componentDirectory);
|
|
801
|
+
assertBranchedDatabases(branchAppName, options.branchedDatabases);
|
|
802
|
+
applicationScope.branches = await prepareBranches(
|
|
803
|
+
branchAppName,
|
|
804
|
+
options.branchedDatabases,
|
|
805
|
+
applicationScope.mode
|
|
806
|
+
);
|
|
807
|
+
}
|
|
808
|
+
|
|
480
809
|
// For non-root components with empty/null config (e.g., comment-only YAML),
|
|
481
810
|
// don't synthesize DEFAULT_CONFIG. Empty config means the component has nothing
|
|
482
811
|
// to load; falling back to DEFAULT_CONFIG would cause OptionsWatcher to wait
|
|
@@ -493,7 +822,10 @@ export async function loadComponent(
|
|
|
493
822
|
// methods. Per-entry errors are logged and skipped by `bootstrapModels`.
|
|
494
823
|
// Awaited so module-backed entries (#1471) finish importing before the
|
|
495
824
|
// per-component iteration below; built-in entries register synchronously.
|
|
496
|
-
if (isRoot)
|
|
825
|
+
if (isRoot) {
|
|
826
|
+
await bootstrapModels(config);
|
|
827
|
+
startModelsConfigHotReload();
|
|
828
|
+
}
|
|
497
829
|
|
|
498
830
|
// The `env:` block declares the component's environment expectations (string literal →
|
|
499
831
|
// process.env; object → declaration satisfied from the hdb_secret store / process.env).
|
|
@@ -550,6 +882,9 @@ export async function loadComponent(
|
|
|
550
882
|
if (!componentConfig) continue;
|
|
551
883
|
|
|
552
884
|
// Initialize loading status for all components (applications and extensions)
|
|
885
|
+
// A root-config application (`package:`) is placed like a directory one: an isolated application
|
|
886
|
+
// loads only in its dedicated worker, and that worker loads no other application.
|
|
887
|
+
if (isRoot && componentConfig.package && !placedOnThisThread(componentName)) continue;
|
|
553
888
|
componentLifecycle.loading(componentStatusName);
|
|
554
889
|
|
|
555
890
|
const subApplicationScope = isRoot
|
|
@@ -601,6 +936,7 @@ export async function loadComponent(
|
|
|
601
936
|
autoReload: false,
|
|
602
937
|
appName: appName || componentName,
|
|
603
938
|
collectScopes: options.collectScopes,
|
|
939
|
+
collectLoadedModules,
|
|
604
940
|
// `host`/`urlPath` on this entry route the component being loaded. For an
|
|
605
941
|
// application (no plugin module of its own) that entry is the only place an
|
|
606
942
|
// operator can say where the app is served — its own config.yaml declares the
|
|
@@ -640,7 +976,10 @@ export async function loadComponent(
|
|
|
640
976
|
// our own trusted modules can be directly retrieved from our map, otherwise use the (configurable) secure module loader
|
|
641
977
|
const ensureTable = (options: any) => {
|
|
642
978
|
options.origin = origin;
|
|
643
|
-
return
|
|
979
|
+
return scopedTableFactory(
|
|
980
|
+
applicationScope.branches,
|
|
981
|
+
thisThreadOwnsApplication(applicationScope.name)
|
|
982
|
+
)(options);
|
|
644
983
|
};
|
|
645
984
|
// call the main start hook
|
|
646
985
|
const network =
|
|
@@ -792,7 +1131,17 @@ export async function loadComponent(
|
|
|
792
1131
|
resources,
|
|
793
1132
|
...componentConfig,
|
|
794
1133
|
})) || extensionModule;
|
|
795
|
-
|
|
1134
|
+
// `collectLoadedModules` serves two different purposes, so the two decisions below are made
|
|
1135
|
+
// separately. A deferred ORDINARY load passes one too, to await readiness — for that it has to
|
|
1136
|
+
// collect what it loaded whether or not the module was already registered. Only a VALIDATION
|
|
1137
|
+
// restricts its set, because there the set doubles as the cleanup list and a shared
|
|
1138
|
+
// `rest`/`graphql` module already live from a real load must not go on it.
|
|
1139
|
+
const validating = isDeployValidating();
|
|
1140
|
+
if (!validating || !loadedComponents.has(extensionModule)) collectLoadedModules?.add(extensionModule);
|
|
1141
|
+
// Ownership follows the validation CONTEXT, not the presence of a collect set. Keying it on the
|
|
1142
|
+
// set labelled a deferred ordinary load's registrations validation-owned, which would let the
|
|
1143
|
+
// next validation that collects that module delete a live one.
|
|
1144
|
+
loadedComponents.set(extensionModule, validating ? VALIDATION_OWNED : true);
|
|
796
1145
|
|
|
797
1146
|
if (
|
|
798
1147
|
(extensionModule.handleFile ||
|
|
@@ -850,7 +1199,7 @@ export async function loadComponent(
|
|
|
850
1199
|
// — not abort the loop and discard a pending follow-up, like the save that fixes it.
|
|
851
1200
|
try {
|
|
852
1201
|
await loadComponentDirectories();
|
|
853
|
-
await restartWorkers();
|
|
1202
|
+
await restartWorkers(undefined, undefined, true, null, '*');
|
|
854
1203
|
} catch (error) {
|
|
855
1204
|
harperLogger.error('Error during component reload', error);
|
|
856
1205
|
}
|
|
@@ -23,6 +23,7 @@ export interface ComponentPreparationLockOwner {
|
|
|
23
23
|
processInstanceId: string;
|
|
24
24
|
token: string;
|
|
25
25
|
ticket?: number;
|
|
26
|
+
purpose?: string;
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
export interface ComponentPreparationLockOptions {
|
|
@@ -30,8 +31,12 @@ export interface ComponentPreparationLockOptions {
|
|
|
30
31
|
onWait?: (owner: ComponentPreparationLockOwner | null) => void;
|
|
31
32
|
onReleaseError?: (error: unknown) => void;
|
|
32
33
|
isOwnerAlive?: (owner: ComponentPreparationLockOwner) => boolean | Promise<boolean>;
|
|
34
|
+
purpose?: string;
|
|
35
|
+
renewTimeoutWhileOwnerAlive?: boolean | ((owner: ComponentPreparationLockOwner) => boolean | Promise<boolean>);
|
|
33
36
|
}
|
|
34
37
|
|
|
38
|
+
export class ComponentPreparationLockTimeoutError extends Error {}
|
|
39
|
+
|
|
35
40
|
export function componentPreparationLockIdentity(
|
|
36
41
|
componentDirPath: string,
|
|
37
42
|
platform: NodeJS.Platform = process.platform
|
|
@@ -244,10 +249,12 @@ async function acquireComponentPreparationLock(
|
|
|
244
249
|
threadId,
|
|
245
250
|
processInstanceId: COMPONENT_PREPARATION_PROCESS_INSTANCE_ID,
|
|
246
251
|
token: randomUUID(),
|
|
252
|
+
purpose: options.purpose,
|
|
247
253
|
};
|
|
248
254
|
const choosingPath = join(lockRoot, `${lockName}.choosing.${owner.token}.json`);
|
|
249
255
|
let ticketPath: string | undefined;
|
|
250
256
|
const timeoutMs = options.timeoutMs ?? DEFAULT_LOCK_WAIT_TIMEOUT_MS;
|
|
257
|
+
const renewTimeoutWhileOwnerAlive = options.renewTimeoutWhileOwnerAlive ?? timeoutMs > 0;
|
|
251
258
|
let deadline = performance.now() + timeoutMs;
|
|
252
259
|
|
|
253
260
|
await mkdir(lockRoot, { recursive: true, mode: 0o700 });
|
|
@@ -264,7 +271,7 @@ async function acquireComponentPreparationLock(
|
|
|
264
271
|
await rm(choosingPath, { force: true }).catch(() => {});
|
|
265
272
|
}
|
|
266
273
|
|
|
267
|
-
let
|
|
274
|
+
let waitingReportedForToken: string | undefined;
|
|
268
275
|
try {
|
|
269
276
|
for (;;) {
|
|
270
277
|
const claims = await scanLiveClaims(lockRoot, lockName, options, owner.token);
|
|
@@ -276,17 +283,21 @@ async function acquireComponentPreparationLock(
|
|
|
276
283
|
})[0];
|
|
277
284
|
const blocker = claims.choosing[0] ?? precedingTicket;
|
|
278
285
|
if (!blocker) break;
|
|
279
|
-
if (
|
|
280
|
-
|
|
286
|
+
if (waitingReportedForToken !== blocker.token) {
|
|
287
|
+
waitingReportedForToken = blocker.token;
|
|
281
288
|
options.onWait?.(blocker);
|
|
282
289
|
}
|
|
283
290
|
if (performance.now() >= deadline) {
|
|
284
|
-
|
|
291
|
+
const renewForOwner =
|
|
292
|
+
typeof renewTimeoutWhileOwnerAlive === 'function'
|
|
293
|
+
? await renewTimeoutWhileOwnerAlive(blocker)
|
|
294
|
+
: renewTimeoutWhileOwnerAlive;
|
|
295
|
+
if (renewForOwner && (await ownerLivenessConfirmed(blocker, options))) {
|
|
285
296
|
// A confirmed-live holder is allowed to finish; the deadline only bounds owners whose
|
|
286
297
|
// liveness cannot be positively established.
|
|
287
298
|
deadline = performance.now() + timeoutMs;
|
|
288
299
|
} else {
|
|
289
|
-
throw new
|
|
300
|
+
throw new ComponentPreparationLockTimeoutError(
|
|
290
301
|
`Timed out waiting for component preparation lock for ${canonicalPath}` +
|
|
291
302
|
` held by process ${blocker.pid}, thread ${blocker.threadId}`
|
|
292
303
|
);
|
|
@@ -13,7 +13,10 @@ import type { ProgressEmitter } from '../server/serverHelpers/progressEmitter.ts
|
|
|
13
13
|
const { HTTP_STATUS_CODES } = hdbErrors;
|
|
14
14
|
|
|
15
15
|
const DEPLOYMENT_TABLE = terms.SYSTEM_TABLE_NAMES.DEPLOYMENT_TABLE_NAME;
|
|
16
|
-
|
|
16
|
+
// `staged` belongs here: the build is complete on disk and nothing further happens to this deployment, so
|
|
17
|
+
// an SSE tail must finish and `delete_deployment_payload` must not refuse a tarball nobody is installing
|
|
18
|
+
// from any more. Activating the artifact is a separate deployment with a row of its own.
|
|
19
|
+
const TERMINAL_STATUSES = new Set(['success', 'failed', 'rolled_back', 'staged']);
|
|
17
20
|
|
|
18
21
|
interface ListRequest {
|
|
19
22
|
project?: string;
|