@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
|
@@ -159,3 +159,134 @@ export function toWriteHeadHeaders(headers: any): any {
|
|
|
159
159
|
}
|
|
160
160
|
return result;
|
|
161
161
|
}
|
|
162
|
+
|
|
163
|
+
// RFC 9111 cache-scope directives; boundaries on both sides so a token like `public-foo` doesn't match.
|
|
164
|
+
export const SHARED_CACHE_OPTIN = /(^|[,\s])(public|s-maxage)($|[\s,;=])/i;
|
|
165
|
+
export const PRIVATE_SCOPE = /(^|[,\s])(private|no-store)($|[\s,;=])/i;
|
|
166
|
+
|
|
167
|
+
function headerValueString(value: unknown): string {
|
|
168
|
+
if (value == null) return '';
|
|
169
|
+
return Array.isArray(value) ? value.join(', ') : String(value);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Folds the middleware chain's response headers into the headers a fallback server produced for the
|
|
174
|
+
* same request.
|
|
175
|
+
*
|
|
176
|
+
* Bun and uWS construct a new response from legacy Fastify when the chain declines a request, so the
|
|
177
|
+
* chain's credential-dependent cache policy must be merged explicitly. Fastify wins headers it set,
|
|
178
|
+
* `Vary` is unioned, and private cache scope is re-applied unless the final response explicitly opts
|
|
179
|
+
* into RFC 9111 shared caching with `public` or `s-maxage`.
|
|
180
|
+
*/
|
|
181
|
+
export function mergeChainHeadersIntoFallback<
|
|
182
|
+
T extends {
|
|
183
|
+
get(name: string): any;
|
|
184
|
+
set(name: string, value: any): any;
|
|
185
|
+
has(name: string): boolean;
|
|
186
|
+
append?(name: string, value: any): any;
|
|
187
|
+
},
|
|
188
|
+
>(chainHeaders: any, finalHeaders: T): T {
|
|
189
|
+
if (!chainHeaders?.[Symbol.iterator]) return finalHeaders;
|
|
190
|
+
const chainVary = headerValueString(chainHeaders.get('Vary'));
|
|
191
|
+
const chainCacheControl = headerValueString(chainHeaders.get('Cache-Control'));
|
|
192
|
+
for (const [name, value] of chainHeaders) {
|
|
193
|
+
const lowerName = String(name).toLowerCase();
|
|
194
|
+
if (lowerName === 'vary' || lowerName === 'cache-control') continue;
|
|
195
|
+
if (finalHeaders.has(name)) {
|
|
196
|
+
if (lowerName === 'set-cookie') {
|
|
197
|
+
const existing = (finalHeaders as any).getSetCookie?.() ?? finalHeaders.get(name);
|
|
198
|
+
const existingValues = new Set((Array.isArray(existing) ? existing : [existing]).map(String));
|
|
199
|
+
const values = Array.isArray(value) ? value : [value];
|
|
200
|
+
for (const single of values) {
|
|
201
|
+
if (!existingValues.has(String(single))) appendHeader(finalHeaders, name, single, false);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
if (Array.isArray(value)) {
|
|
207
|
+
for (const single of value) appendHeader(finalHeaders, name, single, lowerName !== 'set-cookie');
|
|
208
|
+
} else finalHeaders.set(name, value);
|
|
209
|
+
}
|
|
210
|
+
for (const token of chainVary.split(',')) {
|
|
211
|
+
const trimmed = token.trim();
|
|
212
|
+
if (trimmed) addVaryHeader(finalHeaders as any, trimmed);
|
|
213
|
+
}
|
|
214
|
+
if (chainCacheControl) {
|
|
215
|
+
const finalCacheControl = headerValueString(finalHeaders.get('Cache-Control'));
|
|
216
|
+
if (!finalCacheControl) finalHeaders.set('Cache-Control', chainCacheControl);
|
|
217
|
+
else if (
|
|
218
|
+
PRIVATE_SCOPE.test(chainCacheControl) &&
|
|
219
|
+
!PRIVATE_SCOPE.test(finalCacheControl) &&
|
|
220
|
+
!SHARED_CACHE_OPTIN.test(finalCacheControl)
|
|
221
|
+
)
|
|
222
|
+
finalHeaders.set('Cache-Control', finalCacheControl + ', private');
|
|
223
|
+
}
|
|
224
|
+
return finalHeaders;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function nodeResponseHeaders(nodeResponse: any) {
|
|
228
|
+
return {
|
|
229
|
+
get: (name: string) => nodeResponse.getHeader(name),
|
|
230
|
+
set: (name: string, value: any) => nodeResponse.setHeader(name, value),
|
|
231
|
+
has: (name: string) => nodeResponse.hasHeader(name),
|
|
232
|
+
append: (name: string, value: any, commaDelimited?: boolean) => {
|
|
233
|
+
const existing = nodeResponse.getHeader(name);
|
|
234
|
+
if (existing == null) return nodeResponse.setHeader(name, value);
|
|
235
|
+
if (commaDelimited)
|
|
236
|
+
return nodeResponse.setHeader(name, (Array.isArray(existing) ? existing.join(', ') : existing) + ', ' + value);
|
|
237
|
+
return nodeResponse.setHeader(name, Array.isArray(existing) ? [...existing, value] : [existing, value]);
|
|
238
|
+
},
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function applyWriteHeadHeaders(nodeResponse: any, headers: any): void {
|
|
243
|
+
const suppliedHeaders = new Map<string, { name: string; value: any }>();
|
|
244
|
+
const addHeader = (name: string, value: any) => {
|
|
245
|
+
const key = String(name).toLowerCase();
|
|
246
|
+
const supplied = suppliedHeaders.get(key);
|
|
247
|
+
if (!supplied) {
|
|
248
|
+
suppliedHeaders.set(key, { name, value });
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
const values = Array.isArray(supplied.value) ? supplied.value : [supplied.value];
|
|
252
|
+
supplied.value = Array.isArray(value) ? values.concat(value) : values.concat([value]);
|
|
253
|
+
};
|
|
254
|
+
if (Array.isArray(headers)) {
|
|
255
|
+
if (Array.isArray(headers[0])) {
|
|
256
|
+
for (const [name, value] of headers) addHeader(name, value);
|
|
257
|
+
} else {
|
|
258
|
+
for (let i = 0; i + 1 < headers.length; i += 2) addHeader(headers[i], headers[i + 1]);
|
|
259
|
+
}
|
|
260
|
+
} else {
|
|
261
|
+
for (const name of Object.keys(headers)) {
|
|
262
|
+
const value = headers[name];
|
|
263
|
+
if (value != null) addHeader(name, value);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
for (const { name, value } of suppliedHeaders.values()) nodeResponse.setHeader(name, value);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Node's counterpart to the Bun and uWS fallback bridges: the chain's headers go onto the
|
|
271
|
+
* `ServerResponse` before legacy Fastify runs, so a Fastify route that sets `Cache-Control` or `Vary`
|
|
272
|
+
* replaces them outright and can make a credential-dependent response shared-cacheable (#1565).
|
|
273
|
+
* Reconciliation therefore runs at `writeHead` — the last point the header set is still mutable, and
|
|
274
|
+
* the one Node also routes implicit headers through — using the same policy as the other two bridges.
|
|
275
|
+
*/
|
|
276
|
+
export function bridgeChainHeadersToNodeResponse(chainHeaders: any, nodeResponse: any): void {
|
|
277
|
+
if (!chainHeaders?.[Symbol.iterator]) return;
|
|
278
|
+
for (const [name, value] of chainHeaders) nodeResponse.setHeader(name, value);
|
|
279
|
+
const originalWriteHead = nodeResponse.writeHead;
|
|
280
|
+
nodeResponse.writeHead = function (statusCode: number, statusMessage?: any, headers?: any) {
|
|
281
|
+
if (this.headersSent) return originalWriteHead.apply(this, arguments as any);
|
|
282
|
+
if (statusMessage != null && typeof statusMessage !== 'string') {
|
|
283
|
+
headers = statusMessage;
|
|
284
|
+
statusMessage = undefined;
|
|
285
|
+
}
|
|
286
|
+
if (headers) applyWriteHeadHeaders(this, headers);
|
|
287
|
+
mergeChainHeadersIntoFallback(chainHeaders, nodeResponseHeaders(this));
|
|
288
|
+
return statusMessage === undefined
|
|
289
|
+
? originalWriteHead.call(this, statusCode)
|
|
290
|
+
: originalWriteHead.call(this, statusCode, statusMessage);
|
|
291
|
+
};
|
|
292
|
+
}
|
|
@@ -125,6 +125,11 @@ const ndjsonHandler = {
|
|
|
125
125
|
mediaTypes.set('application/x-ndjson', ndjsonHandler);
|
|
126
126
|
mediaTypes.set('application/ndjson', ndjsonHandler);
|
|
127
127
|
|
|
128
|
+
function serializeSSEData(data: any) {
|
|
129
|
+
if (typeof data === 'object') return 'data: ' + JSONStringify(data) + '\n';
|
|
130
|
+
return 'data: ' + String(data).replace(/\r\n|\r|\n/g, '\ndata: ') + '\n';
|
|
131
|
+
}
|
|
132
|
+
|
|
128
133
|
mediaTypes.set('text/event-stream', {
|
|
129
134
|
// Server-Sent Events (SSE)
|
|
130
135
|
serializeStream: function (iterable) {
|
|
@@ -141,20 +146,20 @@ mediaTypes.set('text/event-stream', {
|
|
|
141
146
|
id: message.timestamp,
|
|
142
147
|
};
|
|
143
148
|
}
|
|
144
|
-
|
|
149
|
+
// A non-null top-level `data` or truthy `event` is an SSE envelope, even with sibling fields.
|
|
150
|
+
// `id`/`retry` alone do not open it: `id` is too common a literal-payload field name (e.g. a
|
|
151
|
+
// database record) to safely treat as an SSE-envelope signal.
|
|
152
|
+
if (message.data != null || message.event) {
|
|
145
153
|
let serialized = '';
|
|
146
154
|
if (message.event) serialized += 'event: ' + message.event + '\n';
|
|
147
|
-
if (message.data) {
|
|
148
|
-
|
|
149
|
-
if (typeof data === 'object') data = JSONStringify(data);
|
|
150
|
-
serialized += 'data: ' + data + '\n';
|
|
155
|
+
if (message.data != null) {
|
|
156
|
+
serialized += serializeSSEData(message.data);
|
|
151
157
|
}
|
|
152
|
-
if (message.id) serialized += 'id: ' + message.id + '\n';
|
|
153
|
-
if (message.retry) serialized += 'retry: ' + message.retry + '\n';
|
|
158
|
+
if (message.id != null) serialized += 'id: ' + message.id + '\n';
|
|
159
|
+
if (message.retry != null) serialized += 'retry: ' + message.retry + '\n';
|
|
154
160
|
return serialized + '\n';
|
|
155
161
|
} else {
|
|
156
|
-
|
|
157
|
-
return `data: ${message}\n\n`;
|
|
162
|
+
return serializeSSEData(message) + '\n';
|
|
158
163
|
}
|
|
159
164
|
},
|
|
160
165
|
compressible: false,
|
|
@@ -436,6 +441,20 @@ export function serialize(responseData, request, responseObject) {
|
|
|
436
441
|
}
|
|
437
442
|
|
|
438
443
|
let asyncSerializations: Promise<void>[];
|
|
444
|
+
/**
|
|
445
|
+
* Get the message serializer for a request's negotiated content type, memoized on the request.
|
|
446
|
+
* The returned function is the registered per-content-type serializer, so its identity keys the
|
|
447
|
+
* content type. Caching serialized output across requests under that key is only valid because the
|
|
448
|
+
* built-in serializers are pure functions of their argument — a component registering a serializer
|
|
449
|
+
* into `server.contentTypes` whose output depends on anything else would not be shareable.
|
|
450
|
+
* @param request
|
|
451
|
+
*/
|
|
452
|
+
export function getMessageSerializer(request?: Request): (message: any) => Buffer | string {
|
|
453
|
+
if (!request) return JSONStringify;
|
|
454
|
+
let serialize = (request as any).serialize;
|
|
455
|
+
if (!serialize) serialize = (request as any).serialize = findBestSerializer(request).serializer.serialize;
|
|
456
|
+
return serialize;
|
|
457
|
+
}
|
|
439
458
|
/**
|
|
440
459
|
* Serialize a message, may be use multiple times (like with WebSockets)
|
|
441
460
|
* @param message
|
|
@@ -450,18 +469,7 @@ export function serializeMessage(
|
|
|
450
469
|
if (message?.contentType != null && message.data != null) return message.data;
|
|
451
470
|
asyncSerializations = inAsyncContinuation ? undefined : [];
|
|
452
471
|
try {
|
|
453
|
-
|
|
454
|
-
if (request) {
|
|
455
|
-
let serialize = (request as any).serialize;
|
|
456
|
-
if (serialize) serialized = serialize(message);
|
|
457
|
-
else {
|
|
458
|
-
const serializer = findBestSerializer(request);
|
|
459
|
-
serialize = (request as any).serialize = serializer.serializer.serialize;
|
|
460
|
-
serialized = serialize(message);
|
|
461
|
-
}
|
|
462
|
-
} else {
|
|
463
|
-
serialized = JSONStringify(message);
|
|
464
|
-
}
|
|
472
|
+
const serialized: Buffer | string = getMessageSerializer(request)(message);
|
|
465
473
|
if (asyncSerializations?.length > 0)
|
|
466
474
|
// if there were any serialization attempts that must wait for async work to be done, we wait now and then retry the serialization
|
|
467
475
|
return (asyncSerializations.length === 1 ? asyncSerializations[0] : Promise.all(asyncSerializations)).then(() =>
|
|
@@ -1,25 +1,36 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
|
+
|
|
3
|
+
import type { ComponentStatus } from '../../components/status/ComponentStatus.ts';
|
|
4
|
+
|
|
1
5
|
// Deploy pre-flight validation loads throwaway candidate component code purely to surface load-time
|
|
2
6
|
// errors — its top-level `server.registerOperation` / `server.setMcpQuotaHandler` calls mutate
|
|
3
7
|
// process-wide state (the operation map, its cross-thread announcement, the quota handler) that is
|
|
4
8
|
// NOT owned by a Scope, so a failed/rolled-back deploy would otherwise leak the candidate's
|
|
5
|
-
// registrations onto the live worker. Those registration methods no-op while this guard is active
|
|
9
|
+
// registrations onto the live worker. Those registration methods no-op while this guard is active,
|
|
10
|
+
// and the candidate's component-status writes are diverted into the throwaway sink below.
|
|
6
11
|
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
|
|
12
|
+
// Context-scoped rather than a process-wide depth counter, because the live component KEEPS SERVING on
|
|
13
|
+
// this worker throughout the window and writes to both of those same places: it registers on its own
|
|
14
|
+
// reload, and `statusForComponent()` is a public API its runtime code may call at any time. A counter
|
|
15
|
+
// cannot tell the two writers apart, so it suppressed the live component's registration and reverted its
|
|
16
|
+
// status report. An async context can: only work descending from the validation load itself is diverted.
|
|
17
|
+
interface DeployValidationContext {
|
|
18
|
+
// Where the candidate's own status writes land instead of the live registry. Discarded with the context.
|
|
19
|
+
statusSink: Map<string, ComponentStatus>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const deployValidation = new AsyncLocalStorage<DeployValidationContext>();
|
|
12
23
|
|
|
13
24
|
export function isDeployValidating(): boolean {
|
|
14
|
-
return
|
|
25
|
+
return deployValidation.getStore() !== undefined;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** The throwaway map a candidate's status writes belong in, or `undefined` outside a validation load. */
|
|
29
|
+
export function deployValidationStatusSink(): Map<string, ComponentStatus> | undefined {
|
|
30
|
+
return deployValidation.getStore()?.statusSink;
|
|
15
31
|
}
|
|
16
32
|
|
|
17
33
|
/** Run `fn` (the throwaway validation load) with the guard raised, lowering it even if `fn` throws. */
|
|
18
34
|
export async function runWithDeployValidationGuard<T>(fn: () => Promise<T>): Promise<T> {
|
|
19
|
-
|
|
20
|
-
try {
|
|
21
|
-
return await fn();
|
|
22
|
-
} finally {
|
|
23
|
-
validationDepth--;
|
|
24
|
-
}
|
|
35
|
+
return deployValidation.run({ statusSink: new Map() }, fn);
|
|
25
36
|
}
|
|
@@ -1,11 +1,42 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
interface OperationAuthorizationState {
|
|
4
|
+
bypassAuth: boolean;
|
|
5
|
+
apiOperation?: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const operationAuthorizationState = new AsyncLocalStorage<OperationAuthorizationState>();
|
|
9
|
+
|
|
10
|
+
// Shared, for the common case of no carrier to preserve.
|
|
11
|
+
const BYPASSED: OperationAuthorizationState = Object.freeze({ bypassAuth: true });
|
|
12
|
+
const ENFORCED: OperationAuthorizationState = Object.freeze({ bypassAuth: false });
|
|
4
13
|
|
|
5
14
|
export function runWithOperationAuthorizationBypass<T>(bypassAuth: boolean, callback: () => T): T {
|
|
6
|
-
|
|
15
|
+
// An existing carrier survives: the enforced branch is not a bypass, and a job handler dispatching
|
|
16
|
+
// a nested authorized operation must not lose its own operation identity.
|
|
17
|
+
const apiOperation = operationAuthorizationState.getStore()?.apiOperation;
|
|
18
|
+
if (apiOperation === undefined) {
|
|
19
|
+
return operationAuthorizationState.run(bypassAuth === true ? BYPASSED : ENFORCED, callback);
|
|
20
|
+
}
|
|
21
|
+
return operationAuthorizationState.run(Object.freeze({ bypassAuth: bypassAuth === true, apiOperation }), callback);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* `apiOperation` MUST come from the same value that selected the code now running, so it cannot name
|
|
26
|
+
* an operation other than the one executing. That is the entire basis for trusting it: a request
|
|
27
|
+
* property would be forgeable, and on the direct-SQL path this check is the only gate.
|
|
28
|
+
*/
|
|
29
|
+
export function runWithDispatchedOperation<T>(apiOperation: string, callback: () => T): T {
|
|
30
|
+
return operationAuthorizationState.run(
|
|
31
|
+
Object.freeze({ bypassAuth: operationAuthorizationState.getStore()?.bypassAuth === true, apiOperation }),
|
|
32
|
+
callback
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function getOperationAuthorizationState(): OperationAuthorizationState | undefined {
|
|
37
|
+
return operationAuthorizationState.getStore();
|
|
7
38
|
}
|
|
8
39
|
|
|
9
40
|
export function isOperationAuthorizationBypassed(): boolean {
|
|
10
|
-
return operationAuthorizationState.getStore() === true;
|
|
41
|
+
return operationAuthorizationState.getStore()?.bypassAuth === true;
|
|
11
42
|
}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* so a request is sent to exactly ONE registering worker (never broadcast-first-wins).
|
|
12
12
|
*
|
|
13
13
|
* - Worker: `registerOperation()` announces the name (OPERATION_REGISTERED) to all threads;
|
|
14
|
-
* only the main thread records it, as name -> Set<threadId
|
|
14
|
+
* only the main thread records it, as name -> Set<threadId>, plus `grantable`.
|
|
15
15
|
* - Main: on an OPERATION_FUNCTION_MAP miss, `getRemoteOperationFunction()` supplies a forwarding
|
|
16
16
|
* function that sends the request body (OPERATION_EXECUTE_REQUEST) to one live registering
|
|
17
17
|
* worker and awaits the correlated OPERATION_EXECUTE_RESPONSE.
|
|
@@ -26,7 +26,11 @@ import * as env from '../../utility/environment/environmentManager.ts';
|
|
|
26
26
|
import harperLogger from '../../utility/logging/harper_logger.ts';
|
|
27
27
|
import { ServerError } from '../../utility/errors/hdbError.ts';
|
|
28
28
|
import { sendItcEvent } from '../threads/itc.js';
|
|
29
|
-
import { onMessageByType, onThreadExit } from '../threads/manageThreads.js';
|
|
29
|
+
import { hasThreadExited, onMessageByType, onThreadExit } from '../threads/manageThreads.js';
|
|
30
|
+
import {
|
|
31
|
+
registerWorkerGrantableOperation,
|
|
32
|
+
unregisterWorkerGrantableOperation,
|
|
33
|
+
} from '../../utility/operationPermissions.ts';
|
|
30
34
|
import { runWithOperationAuthorizationBypass } from './operationAuthorizationState.ts';
|
|
31
35
|
|
|
32
36
|
const operationLog = harperLogger.loggerWithTag('operation');
|
|
@@ -59,6 +63,9 @@ export function setLocalOperationDispatch(dispatch: typeof localDispatch) {
|
|
|
59
63
|
|
|
60
64
|
/** name -> threadIds of workers that registered it (main thread only) */
|
|
61
65
|
const registeredByWorker = new Map<string, Set<number>>();
|
|
66
|
+
// Per originator, not per name: a rolling deploy whose new generation drops `requiresSuperUser`
|
|
67
|
+
// must keep routing the name while retracting grantability, which a name-level flag cannot express.
|
|
68
|
+
const grantableByWorker = new Map<string, Set<number>>();
|
|
62
69
|
const pendingExecutions = new Map<
|
|
63
70
|
number,
|
|
64
71
|
{ targetThreadId: number; resolve: (result: any) => void; reject: (error: Error) => void }
|
|
@@ -71,27 +78,82 @@ let mainListenersAttached = false;
|
|
|
71
78
|
* a lost announcement just means the op stays unreachable (the pre-#1736 status quo), and the
|
|
72
79
|
* broadcast has its own ack timeout.
|
|
73
80
|
*/
|
|
74
|
-
export function announceRegisteredOperation(name: string) {
|
|
81
|
+
export function announceRegisteredOperation(name: string, grantable = false) {
|
|
75
82
|
if (isMainThread) return;
|
|
76
83
|
sendItcEvent({
|
|
77
84
|
type: terms.ITC_EVENT_TYPES.OPERATION_REGISTERED,
|
|
78
|
-
message: { name },
|
|
85
|
+
message: { name, grantable },
|
|
79
86
|
}).catch((error) => operationLog.error(`Failed to announce registered operation '${name}'`, error));
|
|
80
87
|
}
|
|
81
88
|
|
|
82
89
|
/**
|
|
83
90
|
* ITC handler (all threads receive the broadcast; only main records it).
|
|
84
91
|
*/
|
|
85
|
-
export function operationRegisteredHandler(event: {
|
|
92
|
+
export function operationRegisteredHandler(event: {
|
|
93
|
+
message?: { name?: string; grantable?: boolean; originator?: number };
|
|
94
|
+
}) {
|
|
86
95
|
if (!isMainThread) return;
|
|
87
|
-
const { name, originator } = event
|
|
96
|
+
const { name, grantable, originator } = event?.message ?? {};
|
|
88
97
|
if (typeof name !== 'string' || typeof originator !== 'number') return;
|
|
98
|
+
// An announcement can lose the race with its own thread's exit, and exit notification fires once
|
|
99
|
+
// per thread, so without this the entry would never be cleaned up. Reads manageThreads' tombstone
|
|
100
|
+
// rather than keeping a second one: job threads are one-shot workers, so a duplicate here would
|
|
101
|
+
// grow per completed job, not per worker restart.
|
|
102
|
+
if (hasThreadExited(originator)) {
|
|
103
|
+
operationLog.debug(`Ignoring operation '${name}' announced by exited worker thread ${originator}`);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
89
106
|
let workerIds = registeredByWorker.get(name);
|
|
90
107
|
if (!workerIds) registeredByWorker.set(name, (workerIds = new Set()));
|
|
91
108
|
workerIds.add(originator);
|
|
109
|
+
// Mirroring only widens what an allowlist may name; enforcement stays on the worker's
|
|
110
|
+
// chooseOperation. A re-announcement that drops the permission retracts this thread's claim.
|
|
111
|
+
setWorkerGrantable(name, originator, grantable === true);
|
|
92
112
|
operationLog.debug(`Registered operation '${name}' announced by worker thread ${originator}`);
|
|
93
113
|
}
|
|
94
114
|
|
|
115
|
+
/**
|
|
116
|
+
* A worker that dies mid-execution can never respond, so fail its in-flight forwards rather than
|
|
117
|
+
* waiting out the timeout, and forget its registrations (a replacement re-registers on load).
|
|
118
|
+
*/
|
|
119
|
+
function handleThreadExit(deadThreadId: number) {
|
|
120
|
+
for (const [name, workerIds] of registeredByWorker) {
|
|
121
|
+
if (!workerIds.delete(deadThreadId)) continue;
|
|
122
|
+
// A surviving worker that never declared a permission must not keep the name admissible.
|
|
123
|
+
if (workerIds.size === 0) dropRegistration(name);
|
|
124
|
+
else setWorkerGrantable(name, deadThreadId, false);
|
|
125
|
+
}
|
|
126
|
+
for (const [requestId, pending] of pendingExecutions) {
|
|
127
|
+
if (pending.targetThreadId === deadThreadId) {
|
|
128
|
+
pendingExecutions.delete(requestId);
|
|
129
|
+
pending.reject(new ServerError('The worker thread executing this operation exited', 503));
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function setWorkerGrantable(name: string, threadId: number, grantable: boolean) {
|
|
135
|
+
let grantableIds = grantableByWorker.get(name);
|
|
136
|
+
if (grantable) {
|
|
137
|
+
if (!grantableIds) grantableByWorker.set(name, (grantableIds = new Set()));
|
|
138
|
+
grantableIds.add(threadId);
|
|
139
|
+
registerWorkerGrantableOperation(name);
|
|
140
|
+
} else if (grantableIds?.delete(threadId) && grantableIds.size === 0) {
|
|
141
|
+
grantableByWorker.delete(name);
|
|
142
|
+
unregisterWorkerGrantableOperation(name);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Forget an operation no live worker offers any more. Both prune paths — thread exit, and a failed
|
|
148
|
+
* send discovering a dead port — route through here so a name can never keep a route without an
|
|
149
|
+
* owner. Grantability is dropped per owner instead, in `setWorkerGrantable`.
|
|
150
|
+
*/
|
|
151
|
+
function dropRegistration(name: string) {
|
|
152
|
+
registeredByWorker.delete(name);
|
|
153
|
+
grantableByWorker.delete(name);
|
|
154
|
+
unregisterWorkerGrantableOperation(name);
|
|
155
|
+
}
|
|
156
|
+
|
|
95
157
|
let rotation = 0;
|
|
96
158
|
/**
|
|
97
159
|
* Main-thread dispatch fallback: if a worker registered `name`, return a forwarding operation
|
|
@@ -122,23 +184,15 @@ function attachMainListeners() {
|
|
|
122
184
|
if (error) pending.reject(new ServerError(error.message, error.statusCode || 500));
|
|
123
185
|
else pending.resolve(result);
|
|
124
186
|
});
|
|
125
|
-
|
|
126
|
-
// than waiting out the timeout, and forget its registrations (a replacement worker
|
|
127
|
-
// re-registers on component load).
|
|
128
|
-
onThreadExit((deadThreadId: number) => {
|
|
129
|
-
for (const [name, workerIds] of registeredByWorker) {
|
|
130
|
-
workerIds.delete(deadThreadId);
|
|
131
|
-
if (workerIds.size === 0) registeredByWorker.delete(name);
|
|
132
|
-
}
|
|
133
|
-
for (const [requestId, pending] of pendingExecutions) {
|
|
134
|
-
if (pending.targetThreadId === deadThreadId) {
|
|
135
|
-
pendingExecutions.delete(requestId);
|
|
136
|
-
pending.reject(new ServerError('The worker thread executing this operation exited', 503));
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
});
|
|
187
|
+
onThreadExit(handleThreadExit);
|
|
140
188
|
}
|
|
141
189
|
|
|
190
|
+
// Armed at load rather than on first use: serverUtilities imports this module during its own load,
|
|
191
|
+
// before any worker exists. Thread-exit notification fires once per thread and is dropped outright
|
|
192
|
+
// if no listener is attached yet, so a worker dying before its first announcement is processed
|
|
193
|
+
// would otherwise leave a registration nothing could ever clean up.
|
|
194
|
+
if (isMainThread) attachMainListeners();
|
|
195
|
+
|
|
142
196
|
async function executeRemoteOperation(name: string, body: any, bypassAuth: boolean): Promise<any> {
|
|
143
197
|
attachMainListeners();
|
|
144
198
|
const workerIds = registeredByWorker.get(name);
|
|
@@ -168,7 +222,10 @@ async function executeRemoteOperation(name: string, body: any, bypassAuth: boole
|
|
|
168
222
|
);
|
|
169
223
|
}
|
|
170
224
|
if (!sent) {
|
|
225
|
+
// The port is gone, so this thread's claims go with it — grantability included, which
|
|
226
|
+
// handleThreadExit would otherwise not retract while other workers still route the name.
|
|
171
227
|
workerIds.delete(targetThreadId);
|
|
228
|
+
setWorkerGrantable(name, targetThreadId, false);
|
|
172
229
|
continue;
|
|
173
230
|
}
|
|
174
231
|
return new Promise((promiseResolve, promiseReject) => {
|
|
@@ -190,7 +247,7 @@ async function executeRemoteOperation(name: string, body: any, bypassAuth: boole
|
|
|
190
247
|
});
|
|
191
248
|
});
|
|
192
249
|
}
|
|
193
|
-
if (registeredByWorker.get(name)?.size === 0)
|
|
250
|
+
if (registeredByWorker.get(name)?.size === 0) dropRegistration(name);
|
|
194
251
|
throw new ServerError(
|
|
195
252
|
`Operation '${name}' is registered by a component but no worker thread is available to run it`,
|
|
196
253
|
503
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `evaluateSQL` honors a supplied `parsed_sql_object` verbatim and skips parsing, so one carrying
|
|
3
|
+
* `permissions_checked: true` executes an AST that no authorization check ever saw. Neither position
|
|
4
|
+
* is ever legitimately client-supplied: dispatch parses the statement itself, and the job worker
|
|
5
|
+
* re-parses from the `sql` string dispatch authorized.
|
|
6
|
+
*
|
|
7
|
+
* Both positions, because the two entry points differ: `chooseOperation` overwrites the top-level
|
|
8
|
+
* object with its own parse, but only inside its SQL branch, so a non-SQL job (`export_local` with a
|
|
9
|
+
* `search_by_value` search) can still carry a client-supplied one through to the persisted row.
|
|
10
|
+
*/
|
|
11
|
+
export function stripSuppliedParsedSqlObject(request: any): void {
|
|
12
|
+
if (!request) return;
|
|
13
|
+
delete request.parsed_sql_object;
|
|
14
|
+
delete request.search_operation?.parsed_sql_object;
|
|
15
|
+
}
|
|
@@ -41,6 +41,9 @@ const NO_AUTH_OPERATIONS = [
|
|
|
41
41
|
terms.OPERATIONS_ENUM.CREATE_AUTHENTICATION_TOKENS,
|
|
42
42
|
terms.OPERATIONS_ENUM.LOGIN,
|
|
43
43
|
terms.OPERATIONS_ENUM.LOGOUT,
|
|
44
|
+
// The OIDC exchange *is* the authentication (#2171): the caller proves identity with a token
|
|
45
|
+
// from a trusted issuer, not with Harper credentials it does not have.
|
|
46
|
+
terms.OPERATIONS_ENUM.EXCHANGE_OIDC_TOKEN,
|
|
44
47
|
];
|
|
45
48
|
|
|
46
49
|
const UNSAFE_REQUEST_BODY_PROPERTIES = ['__proto__', 'constructor', 'prototype'];
|
|
@@ -111,10 +114,10 @@ function authHandler(req, resp, done) {
|
|
|
111
114
|
const isAuthOperation = !NO_AUTH_OPERATIONS.includes(req.body.operation);
|
|
112
115
|
if (
|
|
113
116
|
isAuthOperation ||
|
|
114
|
-
//
|
|
117
|
+
// Create token needs to be authorized when called without username/password in the body, or
|
|
118
|
+
// with an inline role object (scoped-token minting is gated on the authenticated requester)
|
|
115
119
|
(req.body.operation === terms.OPERATIONS_ENUM.CREATE_AUTHENTICATION_TOKENS &&
|
|
116
|
-
!req.body.username &&
|
|
117
|
-
!req.body.password)
|
|
120
|
+
((!req.body.username && !req.body.password) || (req.body.role && typeof req.body.role === 'object')))
|
|
118
121
|
) {
|
|
119
122
|
pAuthorize(req, resp)
|
|
120
123
|
.then(async (userData) => {
|