@harperfast/harper 5.2.10 → 5.3.0-alpha.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 +46 -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 +59 -3
- package/bin/run.ts +6 -11
- package/bin/upgrade.js +7 -3
- package/bin/workloadIdentity.ts +119 -0
- package/components/Application.ts +2414 -242
- package/components/ApplicationScope.ts +8 -0
- package/components/EntryHandler.ts +59 -39
- package/components/OptionsWatcher.ts +150 -74
- package/components/RuntimeModuleTracker.ts +38 -7
- package/components/Scope.ts +37 -15
- package/components/awaitRestart.ts +84 -0
- package/components/componentLoader.ts +340 -30
- package/components/componentPreparationLock.ts +16 -5
- 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 +270 -78
- package/components/operationsValidation.js +49 -1
- package/components/status/ComponentStatusRegistry.ts +59 -0
- package/config/RootConfigWatcher.ts +80 -34
- package/config/configUtils.ts +291 -34
- package/config/harperConfigEnvVars.ts +170 -27
- package/config-root.schema.json +29 -0
- package/dataLayer/blobBackup.ts +160 -50
- package/dataLayer/delete.ts +6 -1
- package/dataLayer/harperBridge/ResourceBridge.ts +52 -8
- 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 +48 -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 +54 -5
- 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 +139 -16
- package/dist/components/Application.js +2215 -267
- 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 +1 -0
- package/dist/components/OptionsWatcher.js +141 -74
- 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 +38 -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 +279 -22
- 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/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.js +231 -77
- package/dist/components/operations.js.map +1 -1
- package/dist/components/operationsValidation.js +49 -1
- package/dist/components/operationsValidation.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 +7 -1
- package/dist/config/RootConfigWatcher.js +64 -27
- package/dist/config/RootConfigWatcher.js.map +1 -1
- package/dist/config/configUtils.d.ts +9 -1
- package/dist/config/configUtils.js +254 -33
- 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/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 +51 -10
- 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 +1 -1
- package/dist/index.js.map +1 -1
- package/dist/json/systemSchema.json +52 -0
- package/dist/resources/DatabaseTransaction.d.ts +55 -3
- package/dist/resources/DatabaseTransaction.js +460 -134
- package/dist/resources/DatabaseTransaction.js.map +1 -1
- package/dist/resources/LMDBTransaction.js +22 -4
- package/dist/resources/LMDBTransaction.js.map +1 -1
- package/dist/resources/PrimaryRocksDatabase.d.ts +1 -0
- package/dist/resources/PrimaryRocksDatabase.js +30 -2
- package/dist/resources/PrimaryRocksDatabase.js.map +1 -1
- package/dist/resources/RecordEncoder.d.ts +20 -0
- package/dist/resources/RecordEncoder.js +94 -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 +20 -11
- package/dist/resources/Resource.js.map +1 -1
- package/dist/resources/ResourceInterface.d.ts +20 -1
- package/dist/resources/ResourceInterface.js.map +1 -1
- package/dist/resources/RocksIndexStore.d.ts +6 -1
- package/dist/resources/RocksIndexStore.js +24 -10
- package/dist/resources/RocksIndexStore.js.map +1 -1
- package/dist/resources/RocksTransactionLogStore.d.ts +14 -1
- package/dist/resources/RocksTransactionLogStore.js +57 -17
- package/dist/resources/RocksTransactionLogStore.js.map +1 -1
- package/dist/resources/Table.d.ts +112 -8
- package/dist/resources/Table.js +1071 -197
- package/dist/resources/Table.js.map +1 -1
- package/dist/resources/auditStore.d.ts +11 -2
- package/dist/resources/auditStore.js +183 -18
- 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/databases.d.ts +150 -9
- package/dist/resources/databases.js +1247 -525
- 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/graphql.d.ts +1 -1
- package/dist/resources/graphql.js +50 -15
- package/dist/resources/graphql.js.map +1 -1
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.d.ts +1 -0
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js +6 -2
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js.map +1 -1
- 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/recordLock.d.ts +80 -0
- package/dist/resources/recordLock.js +184 -0
- package/dist/resources/recordLock.js.map +1 -0
- package/dist/resources/replayLogs.d.ts +14 -1
- package/dist/resources/replayLogs.js +152 -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/search.js +158 -32
- package/dist/resources/search.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 +75 -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 +73 -0
- 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 +11 -0
- package/dist/server/http.js +88 -15
- 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 +25 -0
- package/dist/server/serverHelpers/Headers.js +139 -1
- package/dist/server/serverHelpers/Headers.js.map +1 -1
- package/dist/server/serverHelpers/contentTypes.d.ts +9 -0
- package/dist/server/serverHelpers/contentTypes.js +32 -25
- 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 +90 -20
- 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 +16 -0
- package/dist/server/storageReclamation.js.map +1 -1
- 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/manageThreads.d.ts +26 -4
- package/dist/server/threads/manageThreads.js +517 -72
- package/dist/server/threads/manageThreads.js.map +1 -1
- package/dist/server/threads/socketRouter.js +89 -26
- 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 +46 -15
- 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 +17 -0
- package/dist/utility/errors/hdbError.js +30 -1
- package/dist/utility/errors/hdbError.js.map +1 -1
- package/dist/utility/globalSchema.d.ts +18 -0
- package/dist/utility/hdbTerms.d.ts +16 -0
- package/dist/utility/hdbTerms.js +18 -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 +91 -14
- package/dist/utility/logging/harper_logger.js.map +1 -1
- package/dist/utility/logging/logRotator.js +76 -49
- 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 +9 -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 +86 -0
- package/dist/utility/watcherFallback.js +278 -1
- package/dist/utility/watcherFallback.js.map +1 -1
- package/dist/validation/configValidator.d.ts +12 -0
- package/dist/validation/configValidator.js +199 -72
- 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 +2 -0
- package/json/systemSchema.json +52 -0
- package/npm-shrinkwrap.json +235 -233
- package/package.json +8 -7
- package/resources/DESIGN.md +114 -52
- package/resources/DatabaseTransaction.ts +522 -130
- package/resources/LMDBTransaction.ts +26 -4
- package/resources/PrimaryRocksDatabase.ts +29 -3
- package/resources/RecordEncoder.ts +103 -8
- package/resources/RequestTarget.ts +2 -0
- package/resources/Resource.ts +17 -9
- package/resources/ResourceInterface.ts +23 -0
- package/resources/RocksIndexStore.ts +30 -10
- package/resources/RocksTransactionLogStore.ts +78 -21
- package/resources/Table.ts +1107 -164
- package/resources/auditStore.ts +187 -21
- package/resources/blob.ts +1029 -110
- package/resources/branchDatabase.ts +941 -0
- package/resources/crdt.ts +76 -12
- package/resources/databases.ts +1354 -522
- package/resources/defineTable.ts +18 -2
- package/resources/graphql.ts +70 -16
- package/resources/indexes/HierarchicalNavigableSmallWorld.ts +6 -2
- package/resources/longLivedTransactions.ts +360 -0
- package/resources/models/backendRegistry.ts +84 -2
- package/resources/models/bootstrap.ts +473 -28
- package/resources/recordLock.ts +253 -0
- package/resources/replayLogs.ts +147 -26
- package/resources/replayLogsGuards.ts +171 -8
- package/resources/search.ts +154 -32
- 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 +81 -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 +183 -16
- package/server/DurableSubscriptionsSession.ts +71 -11
- package/server/REST.ts +79 -1
- package/server/graphqlQuerying.ts +4 -0
- package/server/http.ts +99 -18
- 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 +131 -0
- package/server/serverHelpers/contentTypes.ts +29 -21
- 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 +104 -31
- package/server/serverHelpers/sharedMessageEncoding.ts +307 -0
- package/server/serverHelpers/uwsServer.ts +17 -2
- package/server/static.ts +23 -29
- package/server/storageReclamation.ts +13 -0
- package/server/threads/itc.js +11 -1
- package/server/threads/manageThreads.js +526 -63
- package/server/threads/socketRouter.ts +81 -26
- package/server/threads/threadHeapMemory.ts +26 -0
- package/server/threads/threadServer.js +43 -15
- package/sqlTranslator/index.ts +31 -8
- package/studio/web/assets/{Chat-Br06zdMA.js → Chat-BnCBegQz.js} +1 -1
- package/studio/web/assets/{FloatingChat-BWImX5fA.js → FloatingChat-CoDW1ySS.js} +3 -3
- package/studio/web/assets/{apiToken-DN0nmDsq.js → apiToken-Bwk5BLXW.js} +1 -1
- package/studio/web/assets/{applications-kSxVoyeU.js → applications-DHxGi7JH.js} +1 -1
- package/studio/web/assets/{cssMode-C1JeufH5.js → cssMode-s0cWI-_M.js} +1 -1
- package/studio/web/assets/{editor-qoo9CrGO.js → editor-DNcRHK54.js} +1 -1
- package/studio/web/assets/{html-Dt4IIy04.js → html-Bdssedlg.js} +1 -1
- package/studio/web/assets/{htmlMode-DXgKKr4C.js → htmlMode-CoDlJ3fw.js} +1 -1
- package/studio/web/assets/{index-6onkYFOG.js → index-D6sxmFLR.js} +5 -5
- package/studio/web/assets/{index.lazy-BrCFnpNJ.js → index.lazy-tmU5BS8s.js} +1 -1
- package/studio/web/assets/{javascript-DNCQGUBc.js → javascript-B8meVSTH.js} +1 -1
- package/studio/web/assets/{jsonMode-CR6HWruP.js → jsonMode-DpIPd35T.js} +1 -1
- package/studio/web/assets/{languageServices-BM4fI4rS.js → languageServices-C_5FMJzQ.js} +1 -1
- package/studio/web/assets/{lspLanguageFeatures-DSa1ttcD.js → lspLanguageFeatures-BIzNBzPK.js} +1 -1
- package/studio/web/assets/{notifications-BHXLnh6x.js → notifications-CQf18QKb.js} +1 -1
- package/studio/web/assets/{notifications-CUmtIA6z.js → notifications-CvZivSbh.js} +1 -1
- package/studio/web/assets/{profile-8BeFSF3j.js → profile-DdOwtntb.js} +1 -1
- package/studio/web/assets/{regions-C8qR0HhD.js → regions-n69fwagr.js} +1 -1
- package/studio/web/assets/{register-B4n5i0SD.js → register-PfWTCXWB.js} +2 -2
- package/studio/web/assets/{setComponentFile-g0_B0lgX.js → setComponentFile-Bg6O7X0S.js} +1 -1
- package/studio/web/assets/{setup-B0CTj_Q5.js → setup-CUx_aUDl.js} +2 -2
- package/studio/web/assets/{status-C6Yib7-K.js → status-D7BVKqX9.js} +1 -1
- package/studio/web/assets/{toggleHighContrast-Dgta7bVi.js → toggleHighContrast-DBSyXzMr.js} +1 -1
- package/studio/web/assets/{tsMode-CH_jHvU-.js → tsMode-BByKCjBS.js} +1 -1
- package/studio/web/assets/{typescript-Co9LCXd5.js → typescript-DDLnLpw9.js} +1 -1
- package/studio/web/assets/{useEntityRestURL-wKC8NsC_.js → useEntityRestURL-31CHGaHk.js} +1 -1
- package/studio/web/assets/{workers-CWeLxCXA.js → workers-pR3jRY9D.js} +1 -1
- package/studio/web/assets/{xml-BadC-0Rk.js → xml-2iRnMhQO.js} +1 -1
- package/studio/web/assets/{yaml-BiUfxPbC.js → yaml-Bf92gJpd.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 +29 -0
- package/utility/hdbTerms.ts +17 -0
- package/utility/logging/harper_logger.ts +87 -14
- package/utility/logging/logRotator.ts +72 -45
- package/utility/nodeIdentity.ts +45 -0
- package/utility/npmUtilities.ts +10 -8
- package/utility/operationPermissions.ts +18 -1
- package/utility/operation_authorization.ts +231 -42
- package/utility/watchPath.ts +63 -0
- package/utility/watcherFallback.ts +270 -0
- package/validation/configValidator.ts +209 -72
- package/validation/installValidator.ts +15 -0
- package/validation/validationWrapper.ts +18 -4
package/server/http.ts
CHANGED
|
@@ -18,7 +18,13 @@ import { createServer as createSecureServerHttp1 } from 'node:https';
|
|
|
18
18
|
import { createServer, IncomingMessage, validateHeaderName, validateHeaderValue } from 'node:http';
|
|
19
19
|
import { createServer as createNetServer } from 'node:net';
|
|
20
20
|
import { Request, BunRequest, UwsRequest, isBun } from './serverHelpers/Request.ts';
|
|
21
|
-
import {
|
|
21
|
+
import {
|
|
22
|
+
appendHeader,
|
|
23
|
+
bridgeChainHeadersToNodeResponse,
|
|
24
|
+
Headers,
|
|
25
|
+
mergeChainHeadersIntoFallback,
|
|
26
|
+
toWriteHeadHeaders,
|
|
27
|
+
} from './serverHelpers/Headers.ts';
|
|
22
28
|
import {
|
|
23
29
|
decodeProxyHeader,
|
|
24
30
|
applyProxyHeader,
|
|
@@ -34,7 +40,7 @@ import { server, type ServerOptions, type HttpOptions, type UpgradeOptions, Upgr
|
|
|
34
40
|
import { setPortServerMap, SERVERS, socketOptionDefaults } from './serverRegistry.ts';
|
|
35
41
|
import { getComponentName } from '../components/componentLoader.ts';
|
|
36
42
|
import { throttle } from './throttle.ts';
|
|
37
|
-
import { makeCallbackChain as buildCallbackChain, describeChains } from './middlewareChain.ts';
|
|
43
|
+
import { makeCallbackChain as buildCallbackChain, describeChains, type HttpEntry } from './middlewareChain.ts';
|
|
38
44
|
import { WebSocketServer } from 'ws';
|
|
39
45
|
|
|
40
46
|
const { errorToString, errorForLog } = harperLogger;
|
|
@@ -490,7 +496,7 @@ export function httpServer(listener, options) {
|
|
|
490
496
|
httpResponders[options?.runFirst ? 'unshift' : 'push'](entry);
|
|
491
497
|
} else if (isBun) {
|
|
492
498
|
// On Bun, store non-function listeners (e.g. Fastify's http.Server) for fallback delegation
|
|
493
|
-
|
|
499
|
+
registerFallbackServer(port, listener);
|
|
494
500
|
} else if ((httpServers[port] as any)?.uws) {
|
|
495
501
|
// uWS HTTP path (#914, HARPER_UWS_HTTP): the port is backed by uWebSockets.js, not a Node
|
|
496
502
|
// http server, so a raw non-function listener (e.g. Fastify's http.Server via
|
|
@@ -499,12 +505,12 @@ export function httpServer(listener, options) {
|
|
|
499
505
|
// port. Divert it to the fallback map like the Bun path; makeUwsHandler delegates unhandled
|
|
500
506
|
// requests to it via inject(). The { uws: true } marker is guaranteed present here: the
|
|
501
507
|
// getServer(port) call above (same loop iteration) sets it before this branch runs.
|
|
502
|
-
|
|
508
|
+
registerFallbackServer(port, listener);
|
|
503
509
|
} else {
|
|
504
510
|
listener.isSecure = secure;
|
|
505
511
|
registerServer(listener, port, false);
|
|
506
512
|
}
|
|
507
|
-
httpChain
|
|
513
|
+
buildChains(httpChain, httpResponders, port);
|
|
508
514
|
}
|
|
509
515
|
|
|
510
516
|
return servers;
|
|
@@ -543,10 +549,47 @@ export function pipeBodyToResponse(
|
|
|
543
549
|
} else {
|
|
544
550
|
recordAction(performance.now() - endTime, 'transfer', handlerPath, method);
|
|
545
551
|
recordAction(bytesSent, 'bytes-sent', handlerPath, method);
|
|
552
|
+
endConnectionIfClientExpectsClose(nodeResponse);
|
|
546
553
|
}
|
|
547
554
|
});
|
|
548
555
|
}
|
|
549
556
|
|
|
557
|
+
/**
|
|
558
|
+
* Bun's node:http never derives keep-alive from the request, so a stream-ended response delivers its
|
|
559
|
+
* full body and then leaves the client attached until its own timeout (#2210). Ending the *request's*
|
|
560
|
+
* socket is the only remedy that works there, and it is graceful, so nothing is truncated (measured
|
|
561
|
+
* on plain TCP and TLS). DESIGN.md carries the measurements and the alternatives that don't work.
|
|
562
|
+
*/
|
|
563
|
+
function endConnectionIfClientExpectsClose(nodeResponse: any) {
|
|
564
|
+
if (!isBun) return;
|
|
565
|
+
const nodeRequest = nodeResponse.req;
|
|
566
|
+
if (nodeRequest?.httpVersionMajor !== 1) return;
|
|
567
|
+
const socket = nodeRequest.socket;
|
|
568
|
+
// a peer that RSTs right after the terminal chunk can leave this callback holding a destroyed
|
|
569
|
+
// socket; end()ing it would throw from inside stream internals, i.e. an uncaughtException
|
|
570
|
+
if (!socket || socket.destroyed) return;
|
|
571
|
+
const connection = nodeRequest.headers?.connection;
|
|
572
|
+
const tokens = typeof connection === 'string' ? connection.split(',') : [];
|
|
573
|
+
if (hasConnectionToken(tokens, 'close')) {
|
|
574
|
+
socket.end();
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
577
|
+
// HTTP/1.0 persistence needs an explicit keep-alive AND a length to read to, so a 1.0 response
|
|
578
|
+
// that got no Content-Length is delimited by the close — the same line Node draws
|
|
579
|
+
if (
|
|
580
|
+
nodeRequest.httpVersionMinor === 0 &&
|
|
581
|
+
!(hasConnectionToken(tokens, 'keep-alive') && nodeResponse.hasHeader?.('content-length'))
|
|
582
|
+
)
|
|
583
|
+
socket.end();
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
function hasConnectionToken(tokens: string[], wanted: string) {
|
|
587
|
+
for (const token of tokens) {
|
|
588
|
+
if (token.trim().toLowerCase() === wanted) return true;
|
|
589
|
+
}
|
|
590
|
+
return false;
|
|
591
|
+
}
|
|
592
|
+
|
|
550
593
|
function getHTTPServer(port: number, secure: boolean, options: ServerOptions) {
|
|
551
594
|
const { mtls: isMtls, usageType } = options || {};
|
|
552
595
|
const isOperationsServer = usageType === 'operations-api';
|
|
@@ -642,9 +685,7 @@ function getHTTPServer(port: number, secure: boolean, options: ServerOptions) {
|
|
|
642
685
|
// This means the HDB stack didn't handle the request, and we can then cascade the request
|
|
643
686
|
// to the server-level handler, forming the bridge to the slower legacy fastify framework that expects
|
|
644
687
|
// to interact with a node HTTP server object.
|
|
645
|
-
|
|
646
|
-
nodeResponse.setHeader(headerPair[0], headerPair[1]);
|
|
647
|
-
}
|
|
688
|
+
bridgeChainHeadersToNodeResponse(response.headers, nodeResponse);
|
|
648
689
|
nodeRequest.baseRequest = request;
|
|
649
690
|
nodeResponse.baseResponse = response;
|
|
650
691
|
return httpServers[port].emit('unhandled', nodeRequest, nodeResponse);
|
|
@@ -947,7 +988,7 @@ function getHTTPServer(port: number, secure: boolean, options: ServerOptions) {
|
|
|
947
988
|
* and a Fastify fallback is registered for the port, it delegates via inject() (see injectToFastify),
|
|
948
989
|
* mirroring the Bun path — so legacy Fastify routes work behind uWS too.
|
|
949
990
|
*/
|
|
950
|
-
function makeUwsHandler(port: number | string, isOperationsServer: boolean, requestQueueLimit?: number) {
|
|
991
|
+
export function makeUwsHandler(port: number | string, isOperationsServer: boolean, requestQueueLimit?: number) {
|
|
951
992
|
// Build a fresh response descriptor rather than mutating what the chain returned: a handler may
|
|
952
993
|
// return a WHATWG `Response` (read-only `status`/`body` accessors), which the Bun path also never
|
|
953
994
|
// mutates. `headers` is normalized in place the same way the Bun path does.
|
|
@@ -983,6 +1024,7 @@ function makeUwsHandler(port: number | string, isOperationsServer: boolean, requ
|
|
|
983
1024
|
if (Array.isArray(v)) respHeaders.set(k, k.toLowerCase() === 'set-cookie' ? v : v.join(', '));
|
|
984
1025
|
else respHeaders.set(k, String(v));
|
|
985
1026
|
}
|
|
1027
|
+
mergeChainHeadersIntoFallback(headers, respHeaders);
|
|
986
1028
|
if (universalHeaders.length > 0) applyUniversalHeaders(respHeaders);
|
|
987
1029
|
logHttpRequest(request, injectResult.statusCode, requestId, performance.now() - startTime);
|
|
988
1030
|
const responseStream = injectResult.stream();
|
|
@@ -1006,6 +1048,7 @@ function makeUwsHandler(port: number | string, isOperationsServer: boolean, requ
|
|
|
1006
1048
|
}
|
|
1007
1049
|
logHttpRequest(request, 404, requestId, performance.now() - startTime);
|
|
1008
1050
|
const notFoundHeaders = new Headers({ 'content-type': 'text/plain' });
|
|
1051
|
+
mergeChainHeadersIntoFallback(headers, notFoundHeaders);
|
|
1009
1052
|
if (universalHeaders.length > 0) applyUniversalHeaders(notFoundHeaders);
|
|
1010
1053
|
return { status: 404, headers: notFoundHeaders, body: 'Not found\n' };
|
|
1011
1054
|
}
|
|
@@ -1180,10 +1223,11 @@ function getBunHTTPServer(port: number, secure: boolean, options: ServerOptions)
|
|
|
1180
1223
|
// Delegate to the fallback server (e.g. Fastify) via node:http compatibility.
|
|
1181
1224
|
// We create a Node-compatible IncomingMessage/ServerResponse and emit 'request'
|
|
1182
1225
|
// on the fallback server, then capture the response.
|
|
1183
|
-
return await bunDelegateToNodeServer(fallbackServer, webRequest, request);
|
|
1226
|
+
return await bunDelegateToNodeServer(fallbackServer, webRequest, request, response.headers);
|
|
1184
1227
|
}
|
|
1185
1228
|
logHttpRequest(request, 404, requestId, performance.now() - startTime);
|
|
1186
1229
|
const notFoundHeaders = new globalThis.Headers();
|
|
1230
|
+
mergeChainHeadersIntoFallback(response.headers, notFoundHeaders);
|
|
1187
1231
|
if (universalHeaders.length > 0) applyUniversalHeaders(notFoundHeaders);
|
|
1188
1232
|
return new Response('Not found\n', { status: 404, headers: notFoundHeaders });
|
|
1189
1233
|
}
|
|
@@ -1367,6 +1411,10 @@ let fastifyInstances: Record<string | number, any> = {};
|
|
|
1367
1411
|
export function registerFastifyInstance(port: string | number, instance: any) {
|
|
1368
1412
|
fastifyInstances[port] = instance;
|
|
1369
1413
|
}
|
|
1414
|
+
|
|
1415
|
+
export function registerFallbackServer(port: string | number, listener: any) {
|
|
1416
|
+
fallbackServers[port] = listener;
|
|
1417
|
+
}
|
|
1370
1418
|
const INTERNAL_USER_HEADER = 'x-harper-internal-pre-auth-user';
|
|
1371
1419
|
|
|
1372
1420
|
/**
|
|
@@ -1397,10 +1445,11 @@ function injectToFastify(
|
|
|
1397
1445
|
return fastify.inject({ method: req.method, url: req.url, headers, payload: req.body, payloadAsStream: true });
|
|
1398
1446
|
}
|
|
1399
1447
|
|
|
1400
|
-
async function bunDelegateToNodeServer(
|
|
1448
|
+
export async function bunDelegateToNodeServer(
|
|
1401
1449
|
nodeServer: any,
|
|
1402
1450
|
webRequest: globalThis.Request,
|
|
1403
|
-
bunRequest?: any
|
|
1451
|
+
bunRequest?: any,
|
|
1452
|
+
chainHeaders?: any
|
|
1404
1453
|
): Promise<Response> {
|
|
1405
1454
|
// Check if there's a Fastify instance registered for this port (preferred path)
|
|
1406
1455
|
for (const port in fallbackServers) {
|
|
@@ -1421,13 +1470,19 @@ async function bunDelegateToNodeServer(
|
|
|
1421
1470
|
});
|
|
1422
1471
|
const webHeaders = new globalThis.Headers();
|
|
1423
1472
|
for (const [k, v] of Object.entries(injectResult.headers)) {
|
|
1424
|
-
if (v
|
|
1473
|
+
if (v == null) continue;
|
|
1474
|
+
if (Array.isArray(v)) {
|
|
1475
|
+
if (k.toLowerCase() === 'set-cookie') {
|
|
1476
|
+
for (const single of v) webHeaders.append(k, String(single));
|
|
1477
|
+
} else webHeaders.set(k, v.join(', '));
|
|
1478
|
+
} else webHeaders.set(k, String(v));
|
|
1425
1479
|
}
|
|
1426
1480
|
// Propagate Connection: close so Bun closes the TCP connection after this response,
|
|
1427
1481
|
// preventing stale keep-alive sockets from causing silent hangs on subsequent requests.
|
|
1428
1482
|
if (webRequest.headers.get('connection')?.toLowerCase() === 'close') {
|
|
1429
1483
|
webHeaders.set('connection', 'close');
|
|
1430
1484
|
}
|
|
1485
|
+
mergeChainHeadersIntoFallback(chainHeaders, webHeaders);
|
|
1431
1486
|
if (universalHeaders.length > 0) applyUniversalHeaders(webHeaders);
|
|
1432
1487
|
const responseStream = injectResult.stream();
|
|
1433
1488
|
// Event-stream responses (MCP SSE) must reach the client incrementally — return
|
|
@@ -1462,6 +1517,7 @@ async function bunDelegateToNodeServer(
|
|
|
1462
1517
|
}
|
|
1463
1518
|
// No Fastify instance found — return 404
|
|
1464
1519
|
const notFoundHeaders = new globalThis.Headers();
|
|
1520
|
+
mergeChainHeadersIntoFallback(chainHeaders, notFoundHeaders);
|
|
1465
1521
|
if (universalHeaders.length > 0) applyUniversalHeaders(notFoundHeaders);
|
|
1466
1522
|
return new Response('Not found\n', { status: 404, headers: notFoundHeaders });
|
|
1467
1523
|
}
|
|
@@ -1470,14 +1526,39 @@ type SerializedRoute = { host?: string; urlPath?: string; order: string[] };
|
|
|
1470
1526
|
// Resolved order captured at chain-build time, keyed identically to httpChain/upgradeChains/
|
|
1471
1527
|
// websocketChains (kind → port → routes). Reporting the stored build-time order rather than
|
|
1472
1528
|
// recomputing from current responders guarantees get_status matches the callback chain actually
|
|
1473
|
-
// serving that port
|
|
1474
|
-
//
|
|
1529
|
+
// serving that port: buildChains() writes both in the same pass, so a description can never
|
|
1530
|
+
// describe an order the port isn't running (#1573).
|
|
1475
1531
|
const resolvedChainDescriptions: Record<string, Record<string, SerializedRoute[]>> = {
|
|
1476
1532
|
http: {},
|
|
1477
1533
|
upgrade: {},
|
|
1478
1534
|
websocket: {},
|
|
1479
1535
|
};
|
|
1480
1536
|
|
|
1537
|
+
// Preserve the original port type because route selection uses strict equality.
|
|
1538
|
+
const builtChainPorts: Record<string, Map<string, number | string>> = {
|
|
1539
|
+
http: new Map(),
|
|
1540
|
+
upgrade: new Map(),
|
|
1541
|
+
websocket: new Map(),
|
|
1542
|
+
};
|
|
1543
|
+
|
|
1544
|
+
// A late registration on 'all' must rebuild every already-bound concrete port (#2418).
|
|
1545
|
+
function buildChains(
|
|
1546
|
+
chains: Record<string, Function>,
|
|
1547
|
+
listeners: HttpEntry[],
|
|
1548
|
+
port: number | string,
|
|
1549
|
+
requestArgIndex: number = 0,
|
|
1550
|
+
kind: string = 'http'
|
|
1551
|
+
) {
|
|
1552
|
+
builtChainPorts[kind].set(String(port), port);
|
|
1553
|
+
if (port !== 'all') {
|
|
1554
|
+
chains[port] = makeCallbackChain(listeners, port, requestArgIndex, kind);
|
|
1555
|
+
return;
|
|
1556
|
+
}
|
|
1557
|
+
for (const builtPort of builtChainPorts[kind].values()) {
|
|
1558
|
+
chains[builtPort] = makeCallbackChain(listeners, builtPort, requestArgIndex, kind);
|
|
1559
|
+
}
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1481
1562
|
function makeCallbackChain(
|
|
1482
1563
|
responders: typeof httpResponders,
|
|
1483
1564
|
portNum: number | string,
|
|
@@ -1603,7 +1684,7 @@ function onUpgrade(listener: UpgradeListener, options: UpgradeOptions) {
|
|
|
1603
1684
|
host: options?.host || undefined,
|
|
1604
1685
|
};
|
|
1605
1686
|
upgradeListeners[options?.runFirst ? 'unshift' : 'push'](entry);
|
|
1606
|
-
upgradeChains
|
|
1687
|
+
buildChains(upgradeChains, upgradeListeners, port, 0, 'upgrade');
|
|
1607
1688
|
}
|
|
1608
1689
|
}
|
|
1609
1690
|
|
|
@@ -1742,10 +1823,10 @@ function onWebSocket(listener: (ws: WebSocket) => void, options: OnWebSocketOpti
|
|
|
1742
1823
|
host: options?.host || undefined,
|
|
1743
1824
|
};
|
|
1744
1825
|
websocketListeners[options?.runFirst ? 'unshift' : 'push'](wsEntry);
|
|
1745
|
-
websocketChains
|
|
1826
|
+
buildChains(websocketChains, websocketListeners, port, 1, 'websocket');
|
|
1746
1827
|
|
|
1747
1828
|
// mqtt doesn't invoke the http handler so this needs to be here to load up the http chains.
|
|
1748
|
-
httpChain
|
|
1829
|
+
buildChains(httpChain, httpResponders, port);
|
|
1749
1830
|
}
|
|
1750
1831
|
|
|
1751
1832
|
return servers;
|
|
@@ -12,7 +12,7 @@ const harperBridge =
|
|
|
12
12
|
require('../../dataLayer/harperBridge/harperBridge.ts');
|
|
13
13
|
const process = require('process');
|
|
14
14
|
const { isMainThread, threadId, workerData } = require('node:worker_threads');
|
|
15
|
-
const { resetDatabases, closeDatabase } = require('../../resources/databases.ts');
|
|
15
|
+
const { resetDatabases, closeDatabase, reloadBranchAt } = require('../../resources/databases.ts');
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* This object/functions are passed to the ITC client instance and dynamically added as event handlers.
|
|
@@ -76,6 +76,13 @@ schemaHandler.addListener = function (listener) {
|
|
|
76
76
|
*/
|
|
77
77
|
async function syncSchemaMetadata(msg) {
|
|
78
78
|
try {
|
|
79
|
+
// A change to a scope-private branch is not a change to any database in the global map, so the
|
|
80
|
+
// rescan below has nothing to find; a thread holding that branch open reloads it instead.
|
|
81
|
+
if (msg.branchPath) {
|
|
82
|
+
// No write barrier here: the symbol-keyed put below has never been one (harper#2522).
|
|
83
|
+
reloadBranchAt(msg.branchPath);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
79
86
|
// TODO: Eventually should indicate which database/table changed so we don't have to scan everything
|
|
80
87
|
let databases = resetDatabases();
|
|
81
88
|
if (msg.table && msg.database)
|
|
@@ -9,6 +9,8 @@ import harperLogger from '../../utility/logging/harper_logger.ts';
|
|
|
9
9
|
import * as globalSchema from '../../utility/globalSchema.ts';
|
|
10
10
|
import * as user from '../../security/user.ts';
|
|
11
11
|
import * as serverUtils from '../serverHelpers/serverUtilities.ts';
|
|
12
|
+
import { runWithDispatchedOperation } from '../serverHelpers/operationAuthorizationState.ts';
|
|
13
|
+
import { stripSuppliedParsedSqlObject } from '../serverHelpers/requestSanitization.ts';
|
|
12
14
|
import moment from 'moment';
|
|
13
15
|
import * as jobs from './jobs.ts';
|
|
14
16
|
import { cloneDeep } from 'lodash';
|
|
@@ -54,12 +56,16 @@ const JOB_ID = JOB_NAME.substring(4);
|
|
|
54
56
|
throw new Error('Did not find job request in hdb_job table, unable to proceed');
|
|
55
57
|
}
|
|
56
58
|
request = cloneDeep(request);
|
|
59
|
+
// The worker re-enters from the persisted row rather than re-dispatching, so a row queued before
|
|
60
|
+
// the dispatch-time strip existed — or written directly — is sanitized here.
|
|
61
|
+
stripSuppliedParsedSqlObject(request);
|
|
57
62
|
|
|
58
63
|
const operation = serverUtils.getOperationFunction(request);
|
|
59
64
|
harperLogger.trace('Running operation:', request.operation, 'for job', JOB_ID);
|
|
60
65
|
|
|
61
|
-
|
|
62
|
-
|
|
66
|
+
const results = await runWithDispatchedOperation(request.operation, () =>
|
|
67
|
+
operation.job_operation_function(request)
|
|
68
|
+
);
|
|
63
69
|
harperLogger.trace('Result from job:', JOB_ID, results);
|
|
64
70
|
|
|
65
71
|
jobObj.status = hdbTerms.JOB_STATUS_ENUM.COMPLETE;
|
package/server/jobs/jobs.ts
CHANGED
|
@@ -11,6 +11,7 @@ import * as search from '../../dataLayer/search.ts';
|
|
|
11
11
|
import Search_Object from '../../dataLayer/SearchObject.ts';
|
|
12
12
|
import searchByHashObj from '../../dataLayer/SearchByHashObject.ts';
|
|
13
13
|
import SQL_Search_Object from '../../dataLayer/SqlSearchObject.ts';
|
|
14
|
+
import { runWithOperationAuthorizationBypass } from '../serverHelpers/operationAuthorizationState.ts';
|
|
14
15
|
import * as hdbTerms from '../../utility/hdbTerms.ts';
|
|
15
16
|
import JobObject from './JobObject.ts';
|
|
16
17
|
import UpdateObject from '../../dataLayer/UpdateObject.ts';
|
|
@@ -249,7 +250,9 @@ export async function getJobsInDateRange(jsonBody: any) {
|
|
|
249
250
|
const hdbSql = require('../../sqlTranslator/index');
|
|
250
251
|
pSqlEvaluate = promisify(hdbSql.evaluateSQL);
|
|
251
252
|
}
|
|
252
|
-
|
|
253
|
+
// Harper's own statement, not the caller's. A carrier is not equivalent here — see DESIGN.md.
|
|
254
|
+
// Wraps only this statement: a later caller-dependent one must not inherit the bypass.
|
|
255
|
+
return await runWithOperationAuthorizationBypass(true, () => pSqlEvaluate(sqlSearchObj));
|
|
253
256
|
} catch (e) {
|
|
254
257
|
log.error(
|
|
255
258
|
`there was a problem searching for jobs from date ${jsonBody.from_date} to date ${jsonBody.to_date} ${e}`
|
|
@@ -23,8 +23,24 @@ interface LiveSubscription {
|
|
|
23
23
|
authExpiresAt?: number;
|
|
24
24
|
/** Returns true if the principal is still authorized for this subscription. */
|
|
25
25
|
recheck: () => Promise<boolean>;
|
|
26
|
-
/** Stop delivery and tear down
|
|
27
|
-
terminate: () => void
|
|
26
|
+
/** Stop delivery and tear down. May be async (e.g. a shared-feed refcount release). */
|
|
27
|
+
terminate: () => void | Promise<void>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function errorMessage(error: unknown): string {
|
|
31
|
+
try {
|
|
32
|
+
return error instanceof Error ? error.message : String(error);
|
|
33
|
+
} catch {
|
|
34
|
+
return '<error message unavailable>';
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function safeLog(log: ((message: string) => void) | undefined, message: string): void {
|
|
39
|
+
try {
|
|
40
|
+
log?.(message);
|
|
41
|
+
} catch {
|
|
42
|
+
/* a broken logger must not turn a contained failure into a new one */
|
|
43
|
+
}
|
|
28
44
|
}
|
|
29
45
|
|
|
30
46
|
const registry = new Set<LiveSubscription>();
|
|
@@ -32,9 +48,15 @@ let sweepTimer: any = null;
|
|
|
32
48
|
let itcListenerInstalled = false;
|
|
33
49
|
let sweeping = false;
|
|
34
50
|
|
|
51
|
+
const NOOP_HANDLE = { unregister: () => {} };
|
|
52
|
+
|
|
53
|
+
function triggerSweep(): void {
|
|
54
|
+
void sweep().catch((error) => safeLog(hdbLogger.error, `liveSubscriptionAuth: sweep failed: ${errorMessage(error)}`));
|
|
55
|
+
}
|
|
56
|
+
|
|
35
57
|
function ensureStarted(): void {
|
|
36
58
|
if (!sweepTimer) {
|
|
37
|
-
sweepTimer = setInterval(
|
|
59
|
+
sweepTimer = setInterval(triggerSweep, RECHECK_INTERVAL_MS);
|
|
38
60
|
// don't keep the worker alive solely for the recheck timer
|
|
39
61
|
sweepTimer.unref?.();
|
|
40
62
|
}
|
|
@@ -44,7 +66,7 @@ function ensureStarted(): void {
|
|
|
44
66
|
// user/role cache before invoking listeners, so recheck() observes the new permissions.
|
|
45
67
|
const handlers = require('./itc/serverHandlers.js');
|
|
46
68
|
if (handlers?.userHandler?.addListener) {
|
|
47
|
-
handlers.userHandler.addListener(
|
|
69
|
+
handlers.userHandler.addListener(triggerSweep);
|
|
48
70
|
itcListenerInstalled = true;
|
|
49
71
|
}
|
|
50
72
|
} catch (error) {
|
|
@@ -61,32 +83,49 @@ function stopIfIdle(): void {
|
|
|
61
83
|
}
|
|
62
84
|
|
|
63
85
|
/**
|
|
64
|
-
* Register a live subscription for continuous re-authorization.
|
|
65
|
-
*
|
|
86
|
+
* Register a live subscription for continuous re-authorization.
|
|
87
|
+
*
|
|
88
|
+
* Without `revoke`, teardown is end()/close()/emit('close') on `subscription`, and the
|
|
89
|
+
* subscription's own teardown unregisters the entry so callers need not.
|
|
90
|
+
*
|
|
91
|
+
* With `revoke`, that becomes the teardown and `subscription` is never touched — no `end` wrapping,
|
|
92
|
+
* no 'close' listener — because a feed shared by many subscribers must stay revocable per subscriber,
|
|
93
|
+
* so the registry can neither own the shared object nor let every registrant mutate it. A `revoke`
|
|
94
|
+
* caller owns the entry's lifetime: nothing detects a leaked registration, and a forgotten
|
|
95
|
+
* `unregister()` degrades sweep latency for every other tracked subscriber. It also owns teardown
|
|
96
|
+
* recovery — the entry is untracked before `revoke` runs and `revoke` is invoked exactly once, so one
|
|
97
|
+
* that throws, rejects or never settles is logged and never retried. A `recheck` shared across
|
|
98
|
+
* subscribers must not mutate state shared across them: `registerLiveSubscriptionForContext` in
|
|
99
|
+
* resources/Resource.ts mutates `context.user`, which is safe only while each context has exactly
|
|
100
|
+
* one subscriber.
|
|
66
101
|
*/
|
|
67
|
-
export function registerLiveSubscription(
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
|
|
102
|
+
export function registerLiveSubscription(
|
|
103
|
+
opts: {
|
|
104
|
+
username: string;
|
|
105
|
+
authExpiresAt?: number;
|
|
106
|
+
recheck: () => Promise<boolean>;
|
|
107
|
+
} & (
|
|
108
|
+
| { subscription: any; revoke?: undefined }
|
|
109
|
+
// requiring one of the two modes stops a caller that supplies neither from type-checking
|
|
110
|
+
// into a silent no-op registration; a revoke-only registrant may own no subscription object
|
|
111
|
+
| { subscription?: any; revoke: () => void | Promise<void> }
|
|
112
|
+
)
|
|
113
|
+
): { unregister: () => void } {
|
|
114
|
+
const { subscription, username, authExpiresAt, recheck, revoke } = opts;
|
|
115
|
+
if (!revoke && (!subscription || typeof subscription !== 'object' || subscription.closed)) return NOOP_HANDLE;
|
|
75
116
|
|
|
76
117
|
const entry: LiveSubscription = {
|
|
77
118
|
username,
|
|
78
119
|
authExpiresAt,
|
|
79
120
|
recheck,
|
|
80
|
-
terminate:
|
|
81
|
-
|
|
82
|
-
|
|
121
|
+
terminate:
|
|
122
|
+
revoke ??
|
|
123
|
+
(() => {
|
|
124
|
+
// end() removes the subscription from the broadcast loop and closes its iterable queue.
|
|
83
125
|
if (subscription.end) subscription.end();
|
|
84
126
|
else if (subscription.close) subscription.close();
|
|
85
127
|
else subscription.emit?.('close');
|
|
86
|
-
}
|
|
87
|
-
/* ignore */
|
|
88
|
-
}
|
|
89
|
-
},
|
|
128
|
+
}),
|
|
90
129
|
};
|
|
91
130
|
registry.add(entry);
|
|
92
131
|
|
|
@@ -94,51 +133,90 @@ export function registerLiveSubscription(opts: {
|
|
|
94
133
|
registry.delete(entry);
|
|
95
134
|
stopIfIdle();
|
|
96
135
|
};
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
subscription
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
136
|
+
|
|
137
|
+
if (!revoke) {
|
|
138
|
+
// Both transports ultimately call end() on normal teardown (MQTT unsubscribe/disconnect; SSE close
|
|
139
|
+
// is wired to end()); wrap it so a closed stream never leaks a registry entry. Also listen for
|
|
140
|
+
// 'close' to cover any iterable that closes without an end(). Skipped when `revoke` is supplied:
|
|
141
|
+
// the caller owns unregistration, and a subscription shared by many subscribers must not be
|
|
142
|
+
// mutated once per registrant.
|
|
143
|
+
const originalEnd = typeof subscription.end === 'function' ? subscription.end.bind(subscription) : null;
|
|
144
|
+
if (originalEnd) {
|
|
145
|
+
subscription.end = function (...args: any[]) {
|
|
146
|
+
unregister();
|
|
147
|
+
return originalEnd(...args);
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
subscription.on?.('close', unregister);
|
|
106
151
|
}
|
|
107
|
-
subscription.on?.('close', unregister);
|
|
108
152
|
|
|
109
153
|
ensureStarted();
|
|
154
|
+
return { unregister };
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** Untrack first: a `terminate` that hangs or fails must not wedge the sweep or be re-entered by a later one. */
|
|
158
|
+
function terminateEntry(
|
|
159
|
+
entry: LiveSubscription,
|
|
160
|
+
reason: string,
|
|
161
|
+
notice: ((message: string) => void) | undefined = hdbLogger.info
|
|
162
|
+
): void {
|
|
163
|
+
registry.delete(entry);
|
|
164
|
+
safeLog(notice, `liveSubscriptionAuth: revoking subscription for ${entry.username} (${reason})`);
|
|
165
|
+
const failed = (error: unknown) =>
|
|
166
|
+
safeLog(
|
|
167
|
+
hdbLogger.error,
|
|
168
|
+
`liveSubscriptionAuth: terminate failed for ${entry.username} (${reason}): ${errorMessage(error)}`
|
|
169
|
+
);
|
|
170
|
+
try {
|
|
171
|
+
// an async terminate's rejection would otherwise surface as an unhandled rejection on the timer's stack
|
|
172
|
+
Promise.resolve(entry.terminate()).catch(failed);
|
|
173
|
+
} catch (error) {
|
|
174
|
+
failed(error);
|
|
175
|
+
}
|
|
110
176
|
}
|
|
111
177
|
|
|
112
178
|
async function sweep(): Promise<void> {
|
|
113
179
|
if (sweeping) return; // a slow recheck must not overlap with the next tick/event
|
|
114
180
|
sweeping = true;
|
|
181
|
+
// the per-subscriber lines are info, which the shipped default (logging.level: warn) drops; one
|
|
182
|
+
// aggregate keeps the pass visible without making a mass role change a warn per subscriber
|
|
183
|
+
const revokedByReason = new Map<string, number>();
|
|
184
|
+
const countRevocation = (reason: string) => revokedByReason.set(reason, (revokedByReason.get(reason) ?? 0) + 1);
|
|
115
185
|
try {
|
|
116
|
-
|
|
117
|
-
for (const entry of registry) {
|
|
186
|
+
// snapshot bounds the pass to entries present at its start; the has() guards cover the rest
|
|
187
|
+
for (const entry of Array.from(registry)) {
|
|
188
|
+
if (!registry.has(entry)) continue;
|
|
118
189
|
try {
|
|
119
|
-
const expired = entry.authExpiresAt != null && now >= entry.authExpiresAt * 1000;
|
|
190
|
+
const expired = entry.authExpiresAt != null && Date.now() >= entry.authExpiresAt * 1000;
|
|
120
191
|
const stillAuthorized = expired ? false : await entry.recheck();
|
|
121
|
-
|
|
122
|
-
if (
|
|
123
|
-
|
|
124
|
-
entry
|
|
192
|
+
if (!registry.has(entry)) continue;
|
|
193
|
+
if (expired || !stillAuthorized) {
|
|
194
|
+
const reason = expired ? 'token expired' : 'no longer authorized';
|
|
195
|
+
terminateEntry(entry, reason);
|
|
196
|
+
countRevocation(reason);
|
|
125
197
|
}
|
|
126
198
|
} catch (error) {
|
|
127
199
|
// fail closed: if authorization can't be confirmed, revoke
|
|
128
|
-
registry.
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
} catch {
|
|
132
|
-
/* ignore */
|
|
200
|
+
if (registry.has(entry)) {
|
|
201
|
+
terminateEntry(entry, `recheck error: ${errorMessage(error)}`, hdbLogger.warn);
|
|
202
|
+
countRevocation('recheck error');
|
|
133
203
|
}
|
|
134
|
-
hdbLogger.warn?.(
|
|
135
|
-
`liveSubscriptionAuth: revoked subscription for ${entry.username} after recheck error: ${(error as Error).message}`
|
|
136
|
-
);
|
|
137
204
|
}
|
|
138
205
|
}
|
|
139
206
|
} finally {
|
|
140
207
|
sweeping = false;
|
|
141
208
|
stopIfIdle();
|
|
209
|
+
if (revokedByReason.size > 0) {
|
|
210
|
+
let total = 0;
|
|
211
|
+
for (const count of revokedByReason.values()) total += count;
|
|
212
|
+
const breakdown = Array.from(revokedByReason, ([reason, count]) => `${reason}: ${count}`).join(', ');
|
|
213
|
+
safeLog(
|
|
214
|
+
hdbLogger.warn,
|
|
215
|
+
// "revoking", like the per-subscriber line: teardown is dispatched, not awaited, and a
|
|
216
|
+
// failure surfaces on its own error line
|
|
217
|
+
`liveSubscriptionAuth: revoking ${total} live subscription${total === 1 ? '' : 's'} (${breakdown})`
|
|
218
|
+
);
|
|
219
|
+
}
|
|
142
220
|
}
|
|
143
221
|
}
|
|
144
222
|
|
|
@@ -146,3 +224,8 @@ async function sweep(): Promise<void> {
|
|
|
146
224
|
export function _liveSubscriptionCount(): number {
|
|
147
225
|
return registry.size;
|
|
148
226
|
}
|
|
227
|
+
|
|
228
|
+
/** Test-only: run a sweep synchronously, bypassing the interval/ITC triggers. */
|
|
229
|
+
export function _sweepNow(): Promise<void> {
|
|
230
|
+
return sweep();
|
|
231
|
+
}
|
|
@@ -1,19 +1,62 @@
|
|
|
1
1
|
const { isMainThread } = require('worker_threads');
|
|
2
2
|
const { getTables } = require('../resources/databases.ts');
|
|
3
|
-
const { loadComponentDirectories, loadComponent } = require('../components/componentLoader.ts');
|
|
3
|
+
const { loadComponentDirectories, loadComponent, readyComponentModules } = require('../components/componentLoader.ts');
|
|
4
4
|
const { resetResources } = require('../resources/Resources.ts');
|
|
5
5
|
const configUtils = require('../config/configUtils.ts');
|
|
6
6
|
const { dirname } = require('path');
|
|
7
7
|
const { loadCertificates } = require('../security/keys.ts');
|
|
8
|
-
const { installApplications } = require('../components/Application.ts');
|
|
8
|
+
const { installApplications, recoverInterruptedActivations } = require('../components/Application.ts');
|
|
9
9
|
const { errorForLog } = require('../utility/logging/harper_logger.ts');
|
|
10
|
+
const { CONFIG_PARAMS } = require('../utility/hdbTerms.ts');
|
|
10
11
|
|
|
11
12
|
let loadedComponents = new Map();
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Map every component directory to the reason activation recovery could not run. Used only when the scan
|
|
16
|
+
* fails globally, where the safe answer is "none of these are known-good" rather than "all of these are".
|
|
17
|
+
*/
|
|
18
|
+
async function failEveryComponentClosed(cause) {
|
|
19
|
+
const failures = new Map();
|
|
20
|
+
const reason = cause instanceof Error ? cause : new Error(`Activation recovery could not run: ${String(cause)}`);
|
|
21
|
+
try {
|
|
22
|
+
const { readdir } = require('node:fs/promises');
|
|
23
|
+
const componentsRoot = configUtils.getConfigPath(CONFIG_PARAMS.COMPONENTSROOT);
|
|
24
|
+
for (const entry of await readdir(componentsRoot, { withFileTypes: true })) {
|
|
25
|
+
if (!entry.name.startsWith('.') && (entry.isDirectory() || entry.isSymbolicLink())) {
|
|
26
|
+
failures.set(entry.name, reason);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
} catch (error) {
|
|
30
|
+
console.error(errorForLog(error));
|
|
31
|
+
}
|
|
32
|
+
return failures;
|
|
33
|
+
}
|
|
12
34
|
/**
|
|
13
35
|
* This is main entry point for loading the main set of global server modules that power Harper.
|
|
14
36
|
* @returns {Promise<void>}
|
|
15
37
|
*/
|
|
16
38
|
async function loadRootComponents(isWorkerThread = false) {
|
|
39
|
+
// Interrupted activations are settled FIRST, before installApplications() — not merely before the
|
|
40
|
+
// component scan. installApplications() installs whatever the root config names, so a candidate left
|
|
41
|
+
// half-swapped by a crash has to be resolved before that runs, or boot reinstalls over it. Failures are
|
|
42
|
+
// per component and returned, not thrown: the loader fails those components closed and loads the rest.
|
|
43
|
+
// Undefined, not an empty Map: a worker skips this branch entirely, and handing the loader an empty map
|
|
44
|
+
// would assert "nothing is unreconciled" on a thread that never checked. The loader treats undefined as
|
|
45
|
+
// "no verdict from boot" instead.
|
|
46
|
+
let interruptedActivationFailures;
|
|
47
|
+
try {
|
|
48
|
+
if (isMainThread && !process.env.HARPER_SAFE_MODE) {
|
|
49
|
+
interruptedActivationFailures = await recoverInterruptedActivations(
|
|
50
|
+
configUtils.getConfigPath(CONFIG_PARAMS.COMPONENTSROOT)
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
} catch (error) {
|
|
54
|
+
// The scan itself failed, so WHICH components are unsettled is unknown — loading them all would
|
|
55
|
+
// defeat the fail-closed contract this pass exists for. Every component present is failed closed
|
|
56
|
+
// instead, and a later reload cycle retries once the cause is gone.
|
|
57
|
+
console.error(errorForLog(error));
|
|
58
|
+
interruptedActivationFailures = await failEveryComponentClosed(error);
|
|
59
|
+
}
|
|
17
60
|
try {
|
|
18
61
|
if (isMainThread && !process.env.HARPER_SAFE_MODE) await installApplications();
|
|
19
62
|
} catch (error) {
|
|
@@ -33,13 +76,12 @@ async function loadRootComponents(isWorkerThread = false) {
|
|
|
33
76
|
});
|
|
34
77
|
if (!process.env.HARPER_SAFE_MODE) {
|
|
35
78
|
// once the global plugins are loaded, we now load all the CF and run applications (and their components)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if (serverModule.ready) allReady.push(serverModule.ready());
|
|
79
|
+
const readyComponentPromises = new WeakMap();
|
|
80
|
+
await loadComponentDirectories(loadedComponents, resources, readyComponentPromises, interruptedActivationFailures);
|
|
81
|
+
await readyComponentModules(loadedComponents.keys(), readyComponentPromises);
|
|
82
|
+
return;
|
|
41
83
|
}
|
|
42
|
-
|
|
84
|
+
await readyComponentModules(loadedComponents.keys());
|
|
43
85
|
}
|
|
44
86
|
|
|
45
87
|
module.exports.loadRootComponents = loadRootComponents;
|