@harperfast/harper 5.2.13 → 5.3.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent/mcpTools.ts +1 -1
- package/agent/session.ts +25 -14
- package/bin/cliOperations.ts +58 -9
- package/bin/copyDb.ts +282 -59
- package/bin/deploySetup.ts +16 -5
- package/bin/harper.ts +1 -1
- package/bin/help.ts +4 -1
- package/bin/lite.ts +4 -1
- package/bin/restart.ts +120 -4
- package/bin/run.ts +6 -11
- package/bin/upgrade.js +7 -3
- package/bin/workloadIdentity.ts +119 -0
- package/components/Application.ts +3436 -242
- package/components/ApplicationScope.ts +8 -0
- package/components/EntryHandler.ts +59 -39
- package/components/OptionsWatcher.ts +440 -98
- package/components/RuntimeModuleTracker.ts +38 -7
- package/components/Scope.ts +56 -15
- package/components/awaitRestart.ts +84 -0
- package/components/componentLoader.ts +381 -32
- package/components/componentPreparationLock.ts +16 -5
- package/components/deploymentOperations.ts +4 -1
- package/components/deploymentRecorder.ts +9 -2
- package/components/mcp/adapters/harperHttp.ts +4 -0
- package/components/mcp/listChanged.ts +4 -0
- package/components/mcp/toolRegistry.ts +2 -0
- package/components/mcp/tools/operations.ts +9 -0
- package/components/mcp/tools/schemas/operationDescriptions.ts +2 -2
- package/components/operations.js +537 -113
- package/components/operationsValidation.js +98 -3
- package/components/packageComponent.ts +25 -1
- package/components/requestRestart.ts +11 -0
- package/components/status/ComponentStatusRegistry.ts +59 -0
- package/config/RootConfigWatcher.ts +240 -40
- package/config/configReadRetry.ts +62 -0
- package/config/configUtils.ts +357 -48
- package/config/harperConfigEnvVars.ts +170 -27
- package/config/parseConfigFile.ts +34 -0
- package/config/readConfigFileSync.ts +44 -0
- package/config/watcherArming.ts +59 -0
- package/config-root.schema.json +33 -0
- package/dataLayer/blobBackup.ts +160 -50
- package/dataLayer/delete.ts +6 -1
- package/dataLayer/harperBridge/ResourceBridge.ts +80 -10
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.js +3 -1
- package/dataLayer/hdbInfoController.ts +34 -1
- package/dataLayer/insert.ts +44 -1
- package/dataLayer/rocksdbBackup.ts +53 -10
- package/dataLayer/schema.ts +11 -1
- package/dataLayer/schemaDescribe.ts +8 -1
- package/dist/agent/mcpTools.js +1 -1
- package/dist/agent/mcpTools.js.map +1 -1
- package/dist/agent/session.d.ts +22 -0
- package/dist/agent/session.js +26 -15
- package/dist/agent/session.js.map +1 -1
- package/dist/bin/cliOperations.js +61 -9
- package/dist/bin/cliOperations.js.map +1 -1
- package/dist/bin/copyDb.d.ts +12 -1
- package/dist/bin/copyDb.js +248 -60
- package/dist/bin/copyDb.js.map +1 -1
- package/dist/bin/deploySetup.d.ts +2 -0
- package/dist/bin/deploySetup.js +11 -3
- package/dist/bin/deploySetup.js.map +1 -1
- package/dist/bin/harper.js +1 -1
- package/dist/bin/harper.js.map +1 -1
- package/dist/bin/help.js +4 -1
- package/dist/bin/help.js.map +1 -1
- package/dist/bin/lite.js +4 -1
- package/dist/bin/lite.js.map +1 -1
- package/dist/bin/restart.js +91 -6
- package/dist/bin/restart.js.map +1 -1
- package/dist/bin/run.js +4 -10
- package/dist/bin/run.js.map +1 -1
- package/dist/bin/upgrade.js +4 -3
- package/dist/bin/upgrade.js.map +1 -1
- package/dist/bin/workloadIdentity.d.ts +18 -0
- package/dist/bin/workloadIdentity.js +100 -0
- package/dist/bin/workloadIdentity.js.map +1 -0
- package/dist/components/Application.d.ts +235 -17
- package/dist/components/Application.js +3038 -238
- package/dist/components/Application.js.map +1 -1
- package/dist/components/ApplicationScope.d.ts +8 -0
- package/dist/components/ApplicationScope.js +7 -0
- package/dist/components/ApplicationScope.js.map +1 -1
- package/dist/components/EntryHandler.js +26 -10
- package/dist/components/EntryHandler.js.map +1 -1
- package/dist/components/OptionsWatcher.d.ts +4 -0
- package/dist/components/OptionsWatcher.js +440 -99
- package/dist/components/OptionsWatcher.js.map +1 -1
- package/dist/components/RuntimeModuleTracker.js +40 -6
- package/dist/components/RuntimeModuleTracker.js.map +1 -1
- package/dist/components/Scope.js +52 -13
- package/dist/components/Scope.js.map +1 -1
- package/dist/components/awaitRestart.d.ts +33 -0
- package/dist/components/awaitRestart.js +61 -0
- package/dist/components/awaitRestart.js.map +1 -0
- package/dist/components/componentLoader.d.ts +38 -1
- package/dist/components/componentLoader.js +313 -24
- package/dist/components/componentLoader.js.map +1 -1
- package/dist/components/componentPreparationLock.d.ts +5 -0
- package/dist/components/componentPreparationLock.js +14 -6
- package/dist/components/componentPreparationLock.js.map +1 -1
- package/dist/components/deploymentOperations.js +4 -1
- package/dist/components/deploymentOperations.js.map +1 -1
- package/dist/components/deploymentRecorder.d.ts +4 -2
- package/dist/components/deploymentRecorder.js +1 -0
- package/dist/components/deploymentRecorder.js.map +1 -1
- package/dist/components/mcp/adapters/harperHttp.js +4 -0
- package/dist/components/mcp/adapters/harperHttp.js.map +1 -1
- package/dist/components/mcp/listChanged.js +5 -0
- package/dist/components/mcp/listChanged.js.map +1 -1
- package/dist/components/mcp/toolRegistry.d.ts +1 -0
- package/dist/components/mcp/toolRegistry.js.map +1 -1
- package/dist/components/mcp/tools/operations.d.ts +5 -0
- package/dist/components/mcp/tools/operations.js +9 -0
- package/dist/components/mcp/tools/operations.js.map +1 -1
- package/dist/components/mcp/tools/schemas/operationDescriptions.js +2 -2
- package/dist/components/mcp/tools/schemas/operationDescriptions.js.map +1 -1
- package/dist/components/operations.d.ts +28 -0
- package/dist/components/operations.js +476 -113
- package/dist/components/operations.js.map +1 -1
- package/dist/components/operationsValidation.js +97 -3
- package/dist/components/operationsValidation.js.map +1 -1
- package/dist/components/packageComponent.js +24 -0
- package/dist/components/packageComponent.js.map +1 -1
- package/dist/components/requestRestart.d.ts +1 -0
- package/dist/components/requestRestart.js +7 -0
- package/dist/components/requestRestart.js.map +1 -1
- package/dist/components/status/ComponentStatusRegistry.d.ts +0 -4
- package/dist/components/status/ComponentStatusRegistry.js +63 -0
- package/dist/components/status/ComponentStatusRegistry.js.map +1 -1
- package/dist/config/RootConfigWatcher.d.ts +9 -1
- package/dist/config/RootConfigWatcher.js +228 -37
- package/dist/config/RootConfigWatcher.js.map +1 -1
- package/dist/config/configReadRetry.d.ts +8 -0
- package/dist/config/configReadRetry.js +62 -0
- package/dist/config/configReadRetry.js.map +1 -0
- package/dist/config/configUtils.d.ts +11 -2
- package/dist/config/configUtils.js +304 -47
- package/dist/config/configUtils.js.map +1 -1
- package/dist/config/harperConfigEnvVars.d.ts +16 -0
- package/dist/config/harperConfigEnvVars.js +162 -25
- package/dist/config/harperConfigEnvVars.js.map +1 -1
- package/dist/config/parseConfigFile.d.ts +4 -0
- package/dist/config/parseConfigFile.js +35 -0
- package/dist/config/parseConfigFile.js.map +1 -0
- package/dist/config/readConfigFileSync.d.ts +1 -0
- package/dist/config/readConfigFileSync.js +47 -0
- package/dist/config/readConfigFileSync.js.map +1 -0
- package/dist/config/watcherArming.d.ts +15 -0
- package/dist/config/watcherArming.js +59 -0
- package/dist/config/watcherArming.js.map +1 -0
- package/dist/dataLayer/blobBackup.d.ts +49 -20
- package/dist/dataLayer/blobBackup.js +139 -50
- package/dist/dataLayer/blobBackup.js.map +1 -1
- package/dist/dataLayer/delete.js +1 -1
- package/dist/dataLayer/delete.js.map +1 -1
- package/dist/dataLayer/harperBridge/ResourceBridge.d.ts +14 -1
- package/dist/dataLayer/harperBridge/ResourceBridge.js +72 -12
- package/dist/dataLayer/harperBridge/ResourceBridge.js.map +1 -1
- package/dist/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.d.ts +3 -1
- package/dist/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.js +3 -1
- package/dist/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.js.map +1 -1
- package/dist/dataLayer/hdbInfoController.d.ts +10 -0
- package/dist/dataLayer/hdbInfoController.js +30 -1
- package/dist/dataLayer/hdbInfoController.js.map +1 -1
- package/dist/dataLayer/insert.d.ts +9 -1
- package/dist/dataLayer/insert.js +30 -0
- package/dist/dataLayer/insert.js.map +1 -1
- package/dist/dataLayer/rocksdbBackup.d.ts +2 -2
- package/dist/dataLayer/rocksdbBackup.js +45 -8
- package/dist/dataLayer/rocksdbBackup.js.map +1 -1
- package/dist/dataLayer/schema.js +8 -0
- package/dist/dataLayer/schema.js.map +1 -1
- package/dist/dataLayer/schemaDescribe.js +8 -1
- package/dist/dataLayer/schemaDescribe.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/json/systemSchema.json +55 -0
- package/dist/resources/DatabaseTransaction.d.ts +77 -0
- package/dist/resources/DatabaseTransaction.js +586 -54
- package/dist/resources/DatabaseTransaction.js.map +1 -1
- package/dist/resources/LMDBTransaction.d.ts +2 -1
- package/dist/resources/LMDBTransaction.js +43 -6
- package/dist/resources/LMDBTransaction.js.map +1 -1
- package/dist/resources/PrimaryRocksDatabase.d.ts +1 -0
- package/dist/resources/PrimaryRocksDatabase.js +49 -5
- package/dist/resources/PrimaryRocksDatabase.js.map +1 -1
- package/dist/resources/RecordEncoder.d.ts +20 -0
- package/dist/resources/RecordEncoder.js +110 -9
- package/dist/resources/RecordEncoder.js.map +1 -1
- package/dist/resources/RequestTarget.d.ts +2 -0
- package/dist/resources/RequestTarget.js.map +1 -1
- package/dist/resources/Resource.js +117 -24
- package/dist/resources/Resource.js.map +1 -1
- package/dist/resources/ResourceInterface.d.ts +28 -1
- package/dist/resources/ResourceInterface.js.map +1 -1
- package/dist/resources/RocksIndexStore.d.ts +6 -1
- package/dist/resources/RocksIndexStore.js +24 -9
- package/dist/resources/RocksIndexStore.js.map +1 -1
- package/dist/resources/RocksTransactionLogStore.d.ts +24 -1
- package/dist/resources/RocksTransactionLogStore.js +160 -49
- package/dist/resources/RocksTransactionLogStore.js.map +1 -1
- package/dist/resources/Table.d.ts +165 -10
- package/dist/resources/Table.js +1805 -303
- package/dist/resources/Table.js.map +1 -1
- package/dist/resources/analytics/write.js +10 -3
- package/dist/resources/analytics/write.js.map +1 -1
- package/dist/resources/auditStore.d.ts +181 -2
- package/dist/resources/auditStore.js +640 -29
- package/dist/resources/auditStore.js.map +1 -1
- package/dist/resources/blob.d.ts +129 -9
- package/dist/resources/blob.js +992 -114
- package/dist/resources/blob.js.map +1 -1
- package/dist/resources/branchDatabase.d.ts +48 -0
- package/dist/resources/branchDatabase.js +892 -0
- package/dist/resources/branchDatabase.js.map +1 -0
- package/dist/resources/crdt.js +50 -12
- package/dist/resources/crdt.js.map +1 -1
- package/dist/resources/dataLoader.js +3 -4
- package/dist/resources/dataLoader.js.map +1 -1
- package/dist/resources/databases.d.ts +157 -14
- package/dist/resources/databases.js +1462 -325
- package/dist/resources/databases.js.map +1 -1
- package/dist/resources/defineTable.d.ts +10 -2
- package/dist/resources/defineTable.js +9 -1
- package/dist/resources/defineTable.js.map +1 -1
- package/dist/resources/derivedIndexRegistry.d.ts +5 -0
- package/dist/resources/derivedIndexRegistry.js +68 -0
- package/dist/resources/derivedIndexRegistry.js.map +1 -0
- package/dist/resources/derivedIndexRuntime.d.ts +215 -0
- package/dist/resources/derivedIndexRuntime.js +2027 -0
- package/dist/resources/derivedIndexRuntime.js.map +1 -0
- package/dist/resources/graphql.d.ts +1 -1
- package/dist/resources/graphql.js +52 -16
- package/dist/resources/graphql.js.map +1 -1
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.d.ts +103 -9
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js +854 -41
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js.map +1 -1
- package/dist/resources/indexes/hnswDerivedIndex.d.ts +67 -0
- package/dist/resources/indexes/hnswDerivedIndex.js +464 -0
- package/dist/resources/indexes/hnswDerivedIndex.js.map +1 -0
- package/dist/resources/indexes/hnswPlaneBinding.d.ts +65 -0
- package/dist/resources/indexes/hnswPlaneBinding.js +91 -0
- package/dist/resources/indexes/hnswPlaneBinding.js.map +1 -0
- package/dist/resources/longLivedTransactions.d.ts +71 -0
- package/dist/resources/longLivedTransactions.js +358 -0
- package/dist/resources/longLivedTransactions.js.map +1 -0
- package/dist/resources/models/backendRegistry.d.ts +26 -0
- package/dist/resources/models/backendRegistry.js +60 -2
- package/dist/resources/models/backendRegistry.js.map +1 -1
- package/dist/resources/models/bootstrap.d.ts +33 -1
- package/dist/resources/models/bootstrap.js +416 -31
- package/dist/resources/models/bootstrap.js.map +1 -1
- package/dist/resources/nodeIdMapping.d.ts +5 -0
- package/dist/resources/nodeIdMapping.js +49 -0
- package/dist/resources/nodeIdMapping.js.map +1 -1
- package/dist/resources/recordLock.d.ts +123 -0
- package/dist/resources/recordLock.js +315 -0
- package/dist/resources/recordLock.js.map +1 -0
- package/dist/resources/recordLockCoordinator.d.ts +557 -0
- package/dist/resources/recordLockCoordinator.js +2565 -0
- package/dist/resources/recordLockCoordinator.js.map +1 -0
- package/dist/resources/replayLogs.d.ts +14 -1
- package/dist/resources/replayLogs.js +157 -24
- package/dist/resources/replayLogs.js.map +1 -1
- package/dist/resources/replayLogsGuards.d.ts +94 -7
- package/dist/resources/replayLogsGuards.js +111 -7
- package/dist/resources/replayLogsGuards.js.map +1 -1
- package/dist/resources/replicatedApplyFailure.d.ts +16 -0
- package/dist/resources/replicatedApplyFailure.js +63 -0
- package/dist/resources/replicatedApplyFailure.js.map +1 -0
- package/dist/resources/scheduler/scheduler.js +3 -3
- package/dist/resources/scheduler/scheduler.js.map +1 -1
- package/dist/resources/search.d.ts +10 -4
- package/dist/resources/search.js +283 -37
- package/dist/resources/search.js.map +1 -1
- package/dist/resources/tracked.d.ts +5 -1
- package/dist/resources/tracked.js +74 -23
- package/dist/resources/tracked.js.map +1 -1
- package/dist/resources/transactionBroadcast.d.ts +1 -1
- package/dist/resources/transactionBroadcast.js +2 -2
- package/dist/resources/transactionBroadcast.js.map +1 -1
- package/dist/security/auth.js +61 -30
- package/dist/security/auth.js.map +1 -1
- package/dist/security/authn/oidc/claims.d.ts +22 -0
- package/dist/security/authn/oidc/claims.js +71 -0
- package/dist/security/authn/oidc/claims.js.map +1 -0
- package/dist/security/authn/oidc/identityToken.d.ts +27 -0
- package/dist/security/authn/oidc/identityToken.js +111 -0
- package/dist/security/authn/oidc/identityToken.js.map +1 -0
- package/dist/security/authn/oidc/jwks.d.ts +25 -0
- package/dist/security/authn/oidc/jwks.js +261 -0
- package/dist/security/authn/oidc/jwks.js.map +1 -0
- package/dist/security/authn/oidc/providers/generic.d.ts +13 -0
- package/dist/security/authn/oidc/providers/generic.js +34 -0
- package/dist/security/authn/oidc/providers/generic.js.map +1 -0
- package/dist/security/authn/oidc/providers/githubActions.d.ts +11 -0
- package/dist/security/authn/oidc/providers/githubActions.js +129 -0
- package/dist/security/authn/oidc/providers/githubActions.js.map +1 -0
- package/dist/security/authn/oidc/providers/index.d.ts +37 -0
- package/dist/security/authn/oidc/providers/index.js +24 -0
- package/dist/security/authn/oidc/providers/index.js.map +1 -0
- package/dist/security/authn/oidc/tokenExchange.d.ts +12 -0
- package/dist/security/authn/oidc/tokenExchange.js +306 -0
- package/dist/security/authn/oidc/tokenExchange.js.map +1 -0
- package/dist/security/authn/oidc/trustPolicyOperations.d.ts +49 -0
- package/dist/security/authn/oidc/trustPolicyOperations.js +358 -0
- package/dist/security/authn/oidc/trustPolicyOperations.js.map +1 -0
- package/dist/security/authn/oidc/types.d.ts +38 -0
- package/dist/security/authn/oidc/types.js +6 -0
- package/dist/security/authn/oidc/types.js.map +1 -0
- package/dist/security/certificateVerification/index.js +40 -11
- package/dist/security/certificateVerification/index.js.map +1 -1
- package/dist/security/certificateVerification/trustedIssuers.d.ts +24 -0
- package/dist/security/certificateVerification/trustedIssuers.js +79 -0
- package/dist/security/certificateVerification/trustedIssuers.js.map +1 -0
- package/dist/security/certificateVerification/types.d.ts +1 -0
- package/dist/security/credentialProvenance.d.ts +35 -0
- package/dist/security/credentialProvenance.js +51 -0
- package/dist/security/credentialProvenance.js.map +1 -0
- package/dist/security/credentialRejection.d.ts +4 -0
- package/dist/security/credentialRejection.js +24 -0
- package/dist/security/credentialRejection.js.map +1 -0
- package/dist/security/deferredAuthentication.d.ts +36 -0
- package/dist/security/deferredAuthentication.js +70 -0
- package/dist/security/deferredAuthentication.js.map +1 -0
- package/dist/security/impersonation.d.ts +21 -0
- package/dist/security/impersonation.js +108 -9
- package/dist/security/impersonation.js.map +1 -1
- package/dist/security/jsLoader.d.ts +6 -0
- package/dist/security/jsLoader.js +77 -15
- package/dist/security/jsLoader.js.map +1 -1
- package/dist/security/keys.js +301 -71
- package/dist/security/keys.js.map +1 -1
- package/dist/security/operationScope.d.ts +21 -0
- package/dist/security/operationScope.js +36 -0
- package/dist/security/operationScope.js.map +1 -0
- package/dist/security/permissionsTranslator.js +21 -0
- package/dist/security/permissionsTranslator.js.map +1 -1
- package/dist/security/tokenAuthentication.d.ts +19 -1
- package/dist/security/tokenAuthentication.js +191 -10
- package/dist/security/tokenAuthentication.js.map +1 -1
- package/dist/security/user.js +4 -3
- package/dist/security/user.js.map +1 -1
- package/dist/server/DurableSubscriptionsSession.d.ts +2 -2
- package/dist/server/DurableSubscriptionsSession.js +67 -10
- package/dist/server/DurableSubscriptionsSession.js.map +1 -1
- package/dist/server/REST.js +106 -2
- package/dist/server/REST.js.map +1 -1
- package/dist/server/graphqlQuerying.js +4 -0
- package/dist/server/graphqlQuerying.js.map +1 -1
- package/dist/server/http.d.ts +16 -1
- package/dist/server/http.js +122 -17
- package/dist/server/http.js.map +1 -1
- package/dist/server/itc/serverHandlers.js +8 -1
- package/dist/server/itc/serverHandlers.js.map +1 -1
- package/dist/server/jobs/jobProcess.js +6 -2
- package/dist/server/jobs/jobProcess.js.map +1 -1
- package/dist/server/jobs/jobs.js +4 -1
- package/dist/server/jobs/jobs.js.map +1 -1
- package/dist/server/liveSubscriptionAuth.d.ts +26 -4
- package/dist/server/liveSubscriptionAuth.js +105 -39
- package/dist/server/liveSubscriptionAuth.js.map +1 -1
- package/dist/server/loadRootComponents.js +49 -10
- package/dist/server/loadRootComponents.js.map +1 -1
- package/dist/server/mqtt.d.ts +2 -0
- package/dist/server/mqtt.js +165 -30
- package/dist/server/mqtt.js.map +1 -1
- package/dist/server/nodeName.d.ts +2 -0
- package/dist/server/nodeName.js +107 -23
- package/dist/server/nodeName.js.map +1 -1
- package/dist/server/serverHelpers/Headers.d.ts +27 -0
- package/dist/server/serverHelpers/Headers.js +145 -1
- package/dist/server/serverHelpers/Headers.js.map +1 -1
- package/dist/server/serverHelpers/NodeAdapterResponse.d.ts +48 -0
- package/dist/server/serverHelpers/NodeAdapterResponse.js +220 -0
- package/dist/server/serverHelpers/NodeAdapterResponse.js.map +1 -0
- package/dist/server/serverHelpers/Request.d.ts +5 -10
- package/dist/server/serverHelpers/Request.js +38 -136
- package/dist/server/serverHelpers/Request.js.map +1 -1
- package/dist/server/serverHelpers/contentTypes.d.ts +11 -0
- package/dist/server/serverHelpers/contentTypes.js +221 -40
- package/dist/server/serverHelpers/contentTypes.js.map +1 -1
- package/dist/server/serverHelpers/deployValidationState.d.ts +3 -0
- package/dist/server/serverHelpers/deployValidationState.js +9 -19
- package/dist/server/serverHelpers/deployValidationState.js.map +1 -1
- package/dist/server/serverHelpers/operationAuthorizationState.d.ts +12 -0
- package/dist/server/serverHelpers/operationAuthorizationState.js +24 -2
- package/dist/server/serverHelpers/operationAuthorizationState.js.map +1 -1
- package/dist/server/serverHelpers/registeredOperations.d.ts +5 -4
- package/dist/server/serverHelpers/registeredOperations.js +74 -21
- package/dist/server/serverHelpers/registeredOperations.js.map +1 -1
- package/dist/server/serverHelpers/requestSanitization.d.ts +11 -0
- package/dist/server/serverHelpers/requestSanitization.js +20 -0
- package/dist/server/serverHelpers/requestSanitization.js.map +1 -0
- package/dist/server/serverHelpers/serverHandlers.js +6 -3
- package/dist/server/serverHelpers/serverHandlers.js.map +1 -1
- package/dist/server/serverHelpers/serverUtilities.d.ts +18 -0
- package/dist/server/serverHelpers/serverUtilities.js +178 -29
- package/dist/server/serverHelpers/serverUtilities.js.map +1 -1
- package/dist/server/serverHelpers/sharedMessageEncoding.d.ts +67 -0
- package/dist/server/serverHelpers/sharedMessageEncoding.js +280 -0
- package/dist/server/serverHelpers/sharedMessageEncoding.js.map +1 -0
- package/dist/server/serverHelpers/uwsServer.js +19 -1
- package/dist/server/serverHelpers/uwsServer.js.map +1 -1
- package/dist/server/static.js +24 -28
- package/dist/server/static.js.map +1 -1
- package/dist/server/storageReclamation.d.ts +5 -0
- package/dist/server/storageReclamation.js +17 -1
- package/dist/server/storageReclamation.js.map +1 -1
- package/dist/server/threads/isolatedApplications.d.ts +47 -0
- package/dist/server/threads/isolatedApplications.js +171 -0
- package/dist/server/threads/isolatedApplications.js.map +1 -0
- package/dist/server/threads/itc.d.ts +7 -2
- package/dist/server/threads/itc.js +5 -1
- package/dist/server/threads/itc.js.map +1 -1
- package/dist/server/threads/logRotationTransport.d.ts +1 -0
- package/dist/server/threads/logRotationTransport.js +33 -0
- package/dist/server/threads/logRotationTransport.js.map +1 -0
- package/dist/server/threads/manageThreads.d.ts +83 -3
- package/dist/server/threads/manageThreads.js +769 -75
- package/dist/server/threads/manageThreads.js.map +1 -1
- package/dist/server/threads/socketRouter.d.ts +1 -0
- package/dist/server/threads/socketRouter.js +277 -31
- package/dist/server/threads/socketRouter.js.map +1 -1
- package/dist/server/threads/threadHeapMemory.d.ts +2 -0
- package/dist/server/threads/threadHeapMemory.js +31 -0
- package/dist/server/threads/threadHeapMemory.js.map +1 -0
- package/dist/server/threads/threadServer.js +76 -22
- package/dist/server/threads/threadServer.js.map +1 -1
- package/dist/sqlEngine/config.d.ts +1 -3
- package/dist/sqlEngine/config.js +19 -16
- package/dist/sqlEngine/config.js.map +1 -1
- package/dist/sqlTranslator/index.d.ts +1 -1
- package/dist/sqlTranslator/index.js +30 -7
- package/dist/sqlTranslator/index.js.map +1 -1
- package/dist/upgrade/directives/5-3-0.d.ts +7 -0
- package/dist/upgrade/directives/5-3-0.js +148 -0
- package/dist/upgrade/directives/5-3-0.js.map +1 -0
- package/dist/upgrade/directives/directivesController.js +2 -1
- package/dist/upgrade/directives/directivesController.js.map +1 -1
- package/dist/utility/OperationFunctionCaller.js +2 -1
- package/dist/utility/OperationFunctionCaller.js.map +1 -1
- package/dist/utility/common_utils.d.ts +16 -0
- package/dist/utility/common_utils.js +32 -6
- package/dist/utility/common_utils.js.map +1 -1
- package/dist/utility/componentNames.d.ts +8 -0
- package/dist/utility/componentNames.js +12 -1
- package/dist/utility/componentNames.js.map +1 -1
- package/dist/utility/environment/environmentManager.js +3 -6
- package/dist/utility/environment/environmentManager.js.map +1 -1
- package/dist/utility/environment/systemInformation.d.ts +1 -0
- package/dist/utility/environment/systemInformation.js +1 -0
- package/dist/utility/environment/systemInformation.js.map +1 -1
- package/dist/utility/errors/commonErrors.d.ts +2 -0
- package/dist/utility/errors/commonErrors.js +2 -0
- package/dist/utility/errors/commonErrors.js.map +1 -1
- package/dist/utility/errors/hdbError.d.ts +33 -0
- package/dist/utility/errors/hdbError.js +58 -1
- package/dist/utility/errors/hdbError.js.map +1 -1
- package/dist/utility/globalSchema.d.ts +18 -0
- package/dist/utility/hdbTerms.d.ts +18 -0
- package/dist/utility/hdbTerms.js +20 -2
- package/dist/utility/hdbTerms.js.map +1 -1
- package/dist/utility/logging/harper_logger.d.ts +2 -0
- package/dist/utility/logging/harper_logger.js +286 -30
- package/dist/utility/logging/harper_logger.js.map +1 -1
- package/dist/utility/logging/logGenerationCoordinator.d.ts +35 -0
- package/dist/utility/logging/logGenerationCoordinator.js +184 -0
- package/dist/utility/logging/logGenerationCoordinator.js.map +1 -0
- package/dist/utility/logging/logRotation.d.ts +46 -0
- package/dist/utility/logging/logRotation.js +365 -0
- package/dist/utility/logging/logRotation.js.map +1 -0
- package/dist/utility/logging/logRotator.d.ts +1 -1
- package/dist/utility/logging/logRotator.js +192 -85
- package/dist/utility/logging/logRotator.js.map +1 -1
- package/dist/utility/nodeIdentity.d.ts +9 -0
- package/dist/utility/nodeIdentity.js +58 -0
- package/dist/utility/nodeIdentity.js.map +1 -0
- package/dist/utility/npmUtilities.js +11 -7
- package/dist/utility/npmUtilities.js.map +1 -1
- package/dist/utility/operationPermissions.d.ts +3 -1
- package/dist/utility/operationPermissions.js +16 -1
- package/dist/utility/operationPermissions.js.map +1 -1
- package/dist/utility/operation_authorization.d.ts +10 -7
- package/dist/utility/operation_authorization.js +212 -41
- package/dist/utility/operation_authorization.js.map +1 -1
- package/dist/utility/watchPath.d.ts +29 -0
- package/dist/utility/watchPath.js +68 -0
- package/dist/utility/watchPath.js.map +1 -0
- package/dist/utility/watcherFallback.d.ts +41 -0
- package/dist/utility/watcherFallback.js +153 -0
- package/dist/utility/watcherFallback.js.map +1 -1
- package/dist/validation/configValidator.d.ts +12 -0
- package/dist/validation/configValidator.js +205 -75
- package/dist/validation/configValidator.js.map +1 -1
- package/dist/validation/installValidator.js +12 -0
- package/dist/validation/installValidator.js.map +1 -1
- package/dist/validation/validationWrapper.d.ts +11 -0
- package/dist/validation/validationWrapper.js +16 -3
- package/dist/validation/validationWrapper.js.map +1 -1
- package/index.ts +8 -0
- package/json/systemSchema.json +55 -0
- package/npm-shrinkwrap.json +286 -194
- package/package.json +15 -7
- package/resources/DESIGN.md +219 -52
- package/resources/DatabaseTransaction.ts +657 -52
- package/resources/LMDBTransaction.ts +46 -6
- package/resources/PrimaryRocksDatabase.ts +46 -7
- package/resources/RecordEncoder.ts +124 -9
- package/resources/RequestTarget.ts +2 -0
- package/resources/Resource.ts +114 -22
- package/resources/ResourceInterface.ts +31 -0
- package/resources/RocksIndexStore.ts +30 -9
- package/resources/RocksTransactionLogStore.ts +188 -51
- package/resources/Table.ts +1960 -301
- package/resources/analytics/write.ts +10 -3
- package/resources/auditStore.ts +647 -32
- package/resources/blob.ts +1029 -110
- package/resources/branchDatabase.ts +941 -0
- package/resources/crdt.ts +76 -12
- package/resources/dataLoader.ts +3 -4
- package/resources/databases.ts +1584 -320
- package/resources/defineTable.ts +18 -2
- package/resources/derivedIndexRegistry.ts +56 -0
- package/resources/derivedIndexRuntime.ts +2292 -0
- package/resources/graphql.ts +72 -17
- package/resources/indexes/HierarchicalNavigableSmallWorld.ts +911 -48
- package/resources/indexes/hnswDerivedIndex.ts +531 -0
- package/resources/indexes/hnswPlaneBinding.ts +174 -0
- package/resources/longLivedTransactions.ts +360 -0
- package/resources/models/backendRegistry.ts +84 -2
- package/resources/models/bootstrap.ts +473 -28
- package/resources/nodeIdMapping.ts +50 -0
- package/resources/recordLock.ts +419 -0
- package/resources/recordLockCoordinator.ts +3043 -0
- package/resources/replayLogs.ts +152 -26
- package/resources/replayLogsGuards.ts +171 -8
- package/resources/replicatedApplyFailure.ts +77 -0
- package/resources/scheduler/scheduler.ts +4 -4
- package/resources/search.ts +288 -46
- package/resources/tracked.ts +73 -22
- package/resources/transactionBroadcast.ts +3 -3
- package/security/auth.ts +68 -29
- package/security/authn/oidc/claims.ts +72 -0
- package/security/authn/oidc/identityToken.ts +129 -0
- package/security/authn/oidc/jwks.ts +260 -0
- package/security/authn/oidc/providers/generic.ts +40 -0
- package/security/authn/oidc/providers/githubActions.ts +137 -0
- package/security/authn/oidc/providers/index.ts +52 -0
- package/security/authn/oidc/tokenExchange.ts +300 -0
- package/security/authn/oidc/trustPolicyOperations.ts +343 -0
- package/security/authn/oidc/types.ts +41 -0
- package/security/certificateVerification/index.ts +54 -13
- package/security/certificateVerification/trustedIssuers.ts +76 -0
- package/security/certificateVerification/types.ts +1 -0
- package/security/credentialProvenance.ts +47 -0
- package/security/credentialRejection.ts +22 -0
- package/security/deferredAuthentication.ts +71 -0
- package/security/impersonation.ts +117 -12
- package/security/jsLoader.ts +83 -18
- package/security/keys.ts +298 -72
- package/security/operationScope.ts +33 -0
- package/security/permissionsTranslator.js +23 -0
- package/security/tokenAuthentication.ts +233 -12
- package/security/user.ts +4 -3
- package/server/DESIGN.md +194 -16
- package/server/DurableSubscriptionsSession.ts +71 -11
- package/server/REST.ts +115 -4
- package/server/graphqlQuerying.ts +4 -0
- package/server/http.ts +133 -20
- package/server/itc/serverHandlers.js +8 -1
- package/server/jobs/jobProcess.ts +8 -2
- package/server/jobs/jobs.ts +4 -1
- package/server/liveSubscriptionAuth.ts +129 -46
- package/server/loadRootComponents.js +50 -8
- package/server/mqtt.ts +179 -38
- package/server/nodeName.ts +103 -21
- package/server/serverHelpers/Headers.ts +135 -0
- package/server/serverHelpers/NodeAdapterResponse.ts +221 -0
- package/server/serverHelpers/Request.ts +33 -131
- package/server/serverHelpers/contentTypes.ts +217 -36
- package/server/serverHelpers/deployValidationState.ts +24 -13
- package/server/serverHelpers/operationAuthorizationState.ts +34 -3
- package/server/serverHelpers/registeredOperations.ts +79 -22
- package/server/serverHelpers/requestSanitization.ts +15 -0
- package/server/serverHelpers/serverHandlers.js +6 -3
- package/server/serverHelpers/serverUtilities.ts +232 -40
- package/server/serverHelpers/sharedMessageEncoding.ts +307 -0
- package/server/serverHelpers/uwsServer.ts +17 -2
- package/server/static.ts +23 -29
- package/server/storageReclamation.ts +15 -2
- package/server/threads/isolatedApplications.ts +157 -0
- package/server/threads/itc.js +11 -1
- package/server/threads/logRotationTransport.ts +40 -0
- package/server/threads/manageThreads.js +771 -66
- package/server/threads/socketRouter.ts +291 -30
- package/server/threads/threadHeapMemory.ts +26 -0
- package/server/threads/threadServer.js +73 -22
- package/sqlTranslator/index.ts +31 -8
- package/studio/web/assets/{Chat-4RrB5134.js → Chat-D3j-1yY1.js} +1 -1
- package/studio/web/assets/{FloatingChat-omlNMDcJ.js → FloatingChat-BxJGYcfB.js} +3 -3
- package/studio/web/assets/{apiToken-Bke3wvfZ.js → apiToken-CT55oWOe.js} +1 -1
- package/studio/web/assets/{applications-DvFDYJgK.js → applications-D9Ct9_vm.js} +1 -1
- package/studio/web/assets/{cssMode-C1vRa7zh.js → cssMode-DV8H7VwA.js} +1 -1
- package/studio/web/assets/{editor-3XRWEDWX.js → editor-uatc0unt.js} +1 -1
- package/studio/web/assets/{html-CTY5tdMr.js → html-Bm6D6paN.js} +1 -1
- package/studio/web/assets/{htmlMode-CG1vSD9t.js → htmlMode-CEn7tpLG.js} +1 -1
- package/studio/web/assets/{index-Dfpeofdu.js → index-BIXW6Pu4.js} +5 -5
- package/studio/web/assets/{index.lazy-B1VOIv-t.js → index.lazy-UI7L-Vrk.js} +1 -1
- package/studio/web/assets/{javascript-CJeJzGnI.js → javascript-CJ0G3AFZ.js} +1 -1
- package/studio/web/assets/{jsonMode-CYPBwM82.js → jsonMode-DQADAYEa.js} +1 -1
- package/studio/web/assets/{languageServices-IKH4GUHl.js → languageServices-CAQJXWcI.js} +1 -1
- package/studio/web/assets/{lspLanguageFeatures-BC8_gxKG.js → lspLanguageFeatures-CCQ8P5sY.js} +1 -1
- package/studio/web/assets/{notifications-BfKBpYcq.js → notifications-BbxTU6Aw.js} +1 -1
- package/studio/web/assets/{notifications-DFbArTfC.js → notifications-Cvb3P1lB.js} +1 -1
- package/studio/web/assets/{profile-Q4-T6c-S.js → profile-Yyb7gsvL.js} +1 -1
- package/studio/web/assets/{regions-CtkV0xje.js → regions-OgjGHlU5.js} +1 -1
- package/studio/web/assets/{register-1ZZuMsiA.js → register-6qwNEOY3.js} +2 -2
- package/studio/web/assets/{setComponentFile-ZWLcWv5X.js → setComponentFile-BilDMtgB.js} +1 -1
- package/studio/web/assets/{setup-DWprJyJy.js → setup-J6qJ7OIU.js} +2 -2
- package/studio/web/assets/{status--aNm8isn.js → status-0RWGcfyD.js} +1 -1
- package/studio/web/assets/{toggleHighContrast-Cq_lt3XD.js → toggleHighContrast-BIn-vErT.js} +1 -1
- package/studio/web/assets/{tsMode-pjgytARx.js → tsMode-DgUXku4d.js} +1 -1
- package/studio/web/assets/{typescript-Cdg0mqUh.js → typescript-C9orXcsM.js} +1 -1
- package/studio/web/assets/{useEntityRestURL-RZhaY8Rn.js → useEntityRestURL-BEoXXbUB.js} +1 -1
- package/studio/web/assets/{workers-BgoXIqQe.js → workers-JVzSDmgx.js} +1 -1
- package/studio/web/assets/{xml-BwSeDMiP.js → xml-Cq-S8S4X.js} +1 -1
- package/studio/web/assets/{yaml-DotCUG5l.js → yaml-sfoRdh1M.js} +1 -1
- package/studio/web/index.html +1 -1
- package/upgrade/directives/5-3-0.ts +132 -0
- package/upgrade/directives/directivesController.ts +2 -1
- package/utility/OperationFunctionCaller.ts +2 -1
- package/utility/common_utils.ts +30 -5
- package/utility/componentNames.ts +12 -0
- package/utility/environment/environmentManager.ts +3 -7
- package/utility/environment/systemInformation.ts +7 -0
- package/utility/errors/commonErrors.ts +4 -0
- package/utility/errors/hdbError.ts +57 -0
- package/utility/hdbTerms.ts +19 -0
- package/utility/logging/harper_logger.ts +278 -26
- package/utility/logging/logGenerationCoordinator.ts +196 -0
- package/utility/logging/logRotation.ts +367 -0
- package/utility/logging/logRotator.ts +213 -81
- package/utility/nodeIdentity.ts +45 -0
- package/utility/npmUtilities.ts +12 -8
- package/utility/operationPermissions.ts +18 -1
- package/utility/operation_authorization.ts +231 -42
- package/utility/watchPath.ts +63 -0
- package/utility/watcherFallback.ts +148 -0
- package/validation/configValidator.ts +215 -75
- package/validation/installValidator.ts +15 -0
- package/validation/validationWrapper.ts +18 -4
|
@@ -10,6 +10,10 @@ import * as envMgr from '../../utility/environment/environmentManager.ts';
|
|
|
10
10
|
import { CONFIG_PARAMS } from '../../utility/hdbTerms.ts';
|
|
11
11
|
import * as YAML from 'yaml';
|
|
12
12
|
import { logger } from '../../utility/logging/logger.ts';
|
|
13
|
+
import {
|
|
14
|
+
errorToString as harperErrorToString,
|
|
15
|
+
errorForLog as harperErrorForLog,
|
|
16
|
+
} from '../../utility/logging/harper_logger.ts';
|
|
13
17
|
import { Blob } from '../../resources/blob.ts';
|
|
14
18
|
// TODO: Only load this if fastify is loaded
|
|
15
19
|
import fp from 'fastify-plugin';
|
|
@@ -17,6 +21,36 @@ import { parseMultipartRequest } from './multipartParser.ts';
|
|
|
17
21
|
const SERIALIZATION_BIGINT = envMgr.get(CONFIG_PARAMS.SERIALIZATION_BIGINT) !== false;
|
|
18
22
|
const JSONStringify = SERIALIZATION_BIGINT ? stringify : JSON.stringify;
|
|
19
23
|
const JSONParse = SERIALIZATION_BIGINT ? parse : JSON.parse;
|
|
24
|
+
const streamStartup = Symbol('streamStartup');
|
|
25
|
+
const serializedStreamError = Symbol('serializedStreamError');
|
|
26
|
+
|
|
27
|
+
type StreamStartup = {
|
|
28
|
+
result: Promise<{ failed?: true; error?: unknown }>;
|
|
29
|
+
abort: () => void;
|
|
30
|
+
start: () => void;
|
|
31
|
+
cancel?: () => void;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
function streamErrorRecord(error: any) {
|
|
35
|
+
let name = 'Error';
|
|
36
|
+
let message;
|
|
37
|
+
try {
|
|
38
|
+
const code = error?.code;
|
|
39
|
+
if (typeof code === 'string' || typeof code === 'number') name = String(code);
|
|
40
|
+
else if (typeof error?.constructor?.name === 'string') name = error.constructor.name;
|
|
41
|
+
else if (typeof error?.name === 'string') name = error.name;
|
|
42
|
+
} catch {}
|
|
43
|
+
try {
|
|
44
|
+
if (typeof error?.message === 'string') message = error.message;
|
|
45
|
+
} catch {}
|
|
46
|
+
message ??= harperErrorToString(error);
|
|
47
|
+
const record: { error: string; message: string; status?: number } = { error: name, message };
|
|
48
|
+
try {
|
|
49
|
+
const status = error?.statusCode ?? error?.status;
|
|
50
|
+
if (typeof status === 'number') record.status = status;
|
|
51
|
+
} catch {}
|
|
52
|
+
return record;
|
|
53
|
+
}
|
|
20
54
|
|
|
21
55
|
const PUBLIC_ENCODE_OPTIONS = {
|
|
22
56
|
useRecords: false,
|
|
@@ -103,9 +137,14 @@ mediaTypes.set('text/yaml', {
|
|
|
103
137
|
});
|
|
104
138
|
|
|
105
139
|
const ndjsonHandler = {
|
|
106
|
-
serializeStream(data: any) {
|
|
140
|
+
serializeStream(data: any, _response?: Response, request?: any) {
|
|
107
141
|
if (data?.[Symbol.iterator] || data?.[Symbol.asyncIterator]) {
|
|
108
|
-
return
|
|
142
|
+
return errorFrameStream(
|
|
143
|
+
data,
|
|
144
|
+
(msg: any) => JSONStringify(msg) + '\n',
|
|
145
|
+
(error) => JSONStringify({ $harperStreamError: streamErrorRecord(error) }) + '\n',
|
|
146
|
+
request?.method === 'GET'
|
|
147
|
+
);
|
|
109
148
|
}
|
|
110
149
|
return JSONStringify(data) + '\n';
|
|
111
150
|
},
|
|
@@ -125,11 +164,21 @@ const ndjsonHandler = {
|
|
|
125
164
|
mediaTypes.set('application/x-ndjson', ndjsonHandler);
|
|
126
165
|
mediaTypes.set('application/ndjson', ndjsonHandler);
|
|
127
166
|
|
|
167
|
+
function serializeSSEData(data: any) {
|
|
168
|
+
if (typeof data === 'object') return 'data: ' + JSONStringify(data) + '\n';
|
|
169
|
+
return 'data: ' + String(data).replace(/\r\n|\r|\n/g, '\ndata: ') + '\n';
|
|
170
|
+
}
|
|
171
|
+
|
|
128
172
|
mediaTypes.set('text/event-stream', {
|
|
129
173
|
// Server-Sent Events (SSE)
|
|
130
|
-
serializeStream: function (iterable) {
|
|
174
|
+
serializeStream: function (iterable, _response?: Response, request?: any) {
|
|
131
175
|
// create a readable stream that we use to stream out events from our subscription
|
|
132
|
-
return
|
|
176
|
+
return errorFrameStream(
|
|
177
|
+
iterable,
|
|
178
|
+
this.serialize,
|
|
179
|
+
(error) => this.serialize({ event: 'harper-error', data: streamErrorRecord(error) }),
|
|
180
|
+
request?.method === 'GET'
|
|
181
|
+
);
|
|
133
182
|
},
|
|
134
183
|
serialize: function (message) {
|
|
135
184
|
if (message.acknowledge) message.acknowledge();
|
|
@@ -141,20 +190,20 @@ mediaTypes.set('text/event-stream', {
|
|
|
141
190
|
id: message.timestamp,
|
|
142
191
|
};
|
|
143
192
|
}
|
|
144
|
-
|
|
193
|
+
// A non-null top-level `data` or truthy `event` is an SSE envelope, even with sibling fields.
|
|
194
|
+
// `id`/`retry` alone do not open it: `id` is too common a literal-payload field name (e.g. a
|
|
195
|
+
// database record) to safely treat as an SSE-envelope signal.
|
|
196
|
+
if (message.data != null || message.event) {
|
|
145
197
|
let serialized = '';
|
|
146
198
|
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';
|
|
199
|
+
if (message.data != null) {
|
|
200
|
+
serialized += serializeSSEData(message.data);
|
|
151
201
|
}
|
|
152
|
-
if (message.id) serialized += 'id: ' + message.id + '\n';
|
|
153
|
-
if (message.retry) serialized += 'retry: ' + message.retry + '\n';
|
|
202
|
+
if (message.id != null) serialized += 'id: ' + message.id + '\n';
|
|
203
|
+
if (message.retry != null) serialized += 'retry: ' + message.retry + '\n';
|
|
154
204
|
return serialized + '\n';
|
|
155
205
|
} else {
|
|
156
|
-
|
|
157
|
-
return `data: ${message}\n\n`;
|
|
206
|
+
return serializeSSEData(message) + '\n';
|
|
158
207
|
}
|
|
159
208
|
},
|
|
160
209
|
compressible: false,
|
|
@@ -391,7 +440,12 @@ export function serialize(responseData, request, responseObject) {
|
|
|
391
440
|
(responseData[Symbol.iterator] || responseData[Symbol.asyncIterator]) &&
|
|
392
441
|
serializer.serializer.serializeStream
|
|
393
442
|
) {
|
|
394
|
-
if (
|
|
443
|
+
if (
|
|
444
|
+
responseData.mapError &&
|
|
445
|
+
serializer.type !== 'application/x-ndjson' &&
|
|
446
|
+
serializer.type !== 'application/ndjson' &&
|
|
447
|
+
serializer.type !== 'text/event-stream'
|
|
448
|
+
) {
|
|
395
449
|
// indicate that we want iterator errors to be returned so we can serialize them in a meaningful way, if possible
|
|
396
450
|
const getColumns = responseData.getColumns;
|
|
397
451
|
responseData = responseData.mapError((error) => {
|
|
@@ -402,9 +456,10 @@ export function serialize(responseData, request, responseObject) {
|
|
|
402
456
|
});
|
|
403
457
|
responseData.getColumns = getColumns;
|
|
404
458
|
}
|
|
405
|
-
let stream = serializer.serializer.serializeStream(responseData, responseObject);
|
|
459
|
+
let stream = serializer.serializer.serializeStream(responseData, responseObject, request);
|
|
406
460
|
if (canCompress) {
|
|
407
461
|
responseObject.headers.set('Content-Encoding', 'br');
|
|
462
|
+
const uncompressedStream = stream;
|
|
408
463
|
stream = stream.pipe(
|
|
409
464
|
createBrotliCompress({
|
|
410
465
|
params: {
|
|
@@ -416,6 +471,7 @@ export function serialize(responseData, request, responseObject) {
|
|
|
416
471
|
},
|
|
417
472
|
})
|
|
418
473
|
);
|
|
474
|
+
if (uncompressedStream[streamStartup]) stream[streamStartup] = uncompressedStream[streamStartup];
|
|
419
475
|
}
|
|
420
476
|
return stream;
|
|
421
477
|
}
|
|
@@ -436,6 +492,20 @@ export function serialize(responseData, request, responseObject) {
|
|
|
436
492
|
}
|
|
437
493
|
|
|
438
494
|
let asyncSerializations: Promise<void>[];
|
|
495
|
+
/**
|
|
496
|
+
* Get the message serializer for a request's negotiated content type, memoized on the request.
|
|
497
|
+
* The returned function is the registered per-content-type serializer, so its identity keys the
|
|
498
|
+
* content type. Caching serialized output across requests under that key is only valid because the
|
|
499
|
+
* built-in serializers are pure functions of their argument — a component registering a serializer
|
|
500
|
+
* into `server.contentTypes` whose output depends on anything else would not be shareable.
|
|
501
|
+
* @param request
|
|
502
|
+
*/
|
|
503
|
+
export function getMessageSerializer(request?: Request): (message: any) => Buffer | string {
|
|
504
|
+
if (!request) return JSONStringify;
|
|
505
|
+
let serialize = (request as any).serialize;
|
|
506
|
+
if (!serialize) serialize = (request as any).serialize = findBestSerializer(request).serializer.serialize;
|
|
507
|
+
return serialize;
|
|
508
|
+
}
|
|
439
509
|
/**
|
|
440
510
|
* Serialize a message, may be use multiple times (like with WebSockets)
|
|
441
511
|
* @param message
|
|
@@ -450,18 +520,7 @@ export function serializeMessage(
|
|
|
450
520
|
if (message?.contentType != null && message.data != null) return message.data;
|
|
451
521
|
asyncSerializations = inAsyncContinuation ? undefined : [];
|
|
452
522
|
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
|
-
}
|
|
523
|
+
const serialized: Buffer | string = getMessageSerializer(request)(message);
|
|
465
524
|
if (asyncSerializations?.length > 0)
|
|
466
525
|
// if there were any serialization attempts that must wait for async work to be done, we wait now and then retry the serialization
|
|
467
526
|
return (asyncSerializations.length === 1 ? asyncSerializations[0] : Promise.all(asyncSerializations)).then(() =>
|
|
@@ -615,24 +674,146 @@ function deserializerUnknownType(contentType: ContentType): Deserialize {
|
|
|
615
674
|
}
|
|
616
675
|
}
|
|
617
676
|
|
|
618
|
-
function
|
|
677
|
+
function errorFrameStream(iterable, transform, serializeError, eager: boolean) {
|
|
678
|
+
const transformed = transformIterable(iterable, transform, serializeError, eager);
|
|
679
|
+
const readable = Readable.from(transformed);
|
|
680
|
+
const startup: StreamStartup = transformed[streamStartup];
|
|
681
|
+
startup.cancel = () => readable.destroy();
|
|
682
|
+
readable[streamStartup] = startup;
|
|
683
|
+
return readable;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
export function discardSerializedStream(stream) {
|
|
687
|
+
stream?.[streamStartup]?.cancel?.();
|
|
688
|
+
stream?.destroy?.();
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
export function waitForStreamStartup(stream) {
|
|
692
|
+
const startup: StreamStartup | undefined = stream?.[streamStartup];
|
|
693
|
+
if (!startup) return;
|
|
694
|
+
startup.start();
|
|
695
|
+
return startup.result.then((result) => {
|
|
696
|
+
if (result.failed) {
|
|
697
|
+
startup.abort();
|
|
698
|
+
discardSerializedStream(stream);
|
|
699
|
+
throw result.error;
|
|
700
|
+
}
|
|
701
|
+
});
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
function transformIterable(iterable, transform, serializeError, eager) {
|
|
705
|
+
let iterator;
|
|
706
|
+
let terminal = false;
|
|
707
|
+
let first = true;
|
|
708
|
+
let started = false;
|
|
709
|
+
let firstStep;
|
|
710
|
+
let startupSettled = false;
|
|
711
|
+
const startupResult = Promise.withResolvers<{ failed?: true; error?: unknown }>();
|
|
712
|
+
const errorDecision = Promise.withResolvers<boolean>();
|
|
713
|
+
let startupTimer;
|
|
714
|
+
|
|
715
|
+
const commit = () => {
|
|
716
|
+
if (startupTimer) clearImmediate(startupTimer);
|
|
717
|
+
if (!startupSettled) {
|
|
718
|
+
startupSettled = true;
|
|
719
|
+
startupResult.resolve({});
|
|
720
|
+
}
|
|
721
|
+
errorDecision.resolve(true);
|
|
722
|
+
};
|
|
723
|
+
const abort = () => {
|
|
724
|
+
if (startupTimer) clearImmediate(startupTimer);
|
|
725
|
+
errorDecision.resolve(false);
|
|
726
|
+
};
|
|
727
|
+
const handleError = async (error) => {
|
|
728
|
+
terminal = true;
|
|
729
|
+
try {
|
|
730
|
+
const returned = iterator.return?.();
|
|
731
|
+
returned?.catch?.(() => {});
|
|
732
|
+
} catch {}
|
|
733
|
+
if (!startupSettled) startupResult.resolve({ failed: true, error });
|
|
734
|
+
if (!startupSettled && !(await errorDecision.promise)) return { done: true };
|
|
735
|
+
logger.warn?.('Error serializing in stream', harperErrorForLog(error));
|
|
736
|
+
return { value: serializeError(error), done: false, [serializedStreamError]: true };
|
|
737
|
+
};
|
|
738
|
+
const transformStep = (step) => {
|
|
739
|
+
if (step?.[serializedStreamError]) return step;
|
|
740
|
+
if (terminal) return { done: true };
|
|
741
|
+
if (step.done) return step;
|
|
742
|
+
try {
|
|
743
|
+
return { value: transform(step.value), done: false };
|
|
744
|
+
} catch (error) {
|
|
745
|
+
return handleError(error);
|
|
746
|
+
}
|
|
747
|
+
};
|
|
748
|
+
const getRawNext = () => {
|
|
749
|
+
if (terminal) return { done: true };
|
|
750
|
+
let step;
|
|
751
|
+
try {
|
|
752
|
+
step = iterator.next();
|
|
753
|
+
} catch (error) {
|
|
754
|
+
return handleError(error);
|
|
755
|
+
}
|
|
756
|
+
if (step.then) return step.then(undefined, handleError);
|
|
757
|
+
return step;
|
|
758
|
+
};
|
|
759
|
+
const getNext = () => {
|
|
760
|
+
if (terminal) return { done: true };
|
|
761
|
+
let step;
|
|
762
|
+
try {
|
|
763
|
+
step = iterator.next();
|
|
764
|
+
} catch (error) {
|
|
765
|
+
return handleError(error);
|
|
766
|
+
}
|
|
767
|
+
if (step.then) return step.then(transformStep, handleError);
|
|
768
|
+
return transformStep(step);
|
|
769
|
+
};
|
|
770
|
+
const start = () => {
|
|
771
|
+
if (started) return;
|
|
772
|
+
started = true;
|
|
773
|
+
iterator = iterable[Symbol.asyncIterator] ? iterable[Symbol.asyncIterator]() : iterable[Symbol.iterator]();
|
|
774
|
+
firstStep = getRawNext();
|
|
775
|
+
Promise.resolve(firstStep).then(
|
|
776
|
+
() => {
|
|
777
|
+
if (!terminal) commit();
|
|
778
|
+
},
|
|
779
|
+
() => {}
|
|
780
|
+
);
|
|
781
|
+
// After this turn, the HTTP status can no longer wait for a first item without delaying long-lived streams.
|
|
782
|
+
startupTimer = setImmediate(commit);
|
|
783
|
+
};
|
|
784
|
+
if (eager) start();
|
|
785
|
+
|
|
619
786
|
return {
|
|
787
|
+
[streamStartup]: {
|
|
788
|
+
result: startupResult.promise,
|
|
789
|
+
abort,
|
|
790
|
+
start,
|
|
791
|
+
},
|
|
620
792
|
[Symbol.asyncIterator]() {
|
|
621
|
-
const iterator = iterable[Symbol.asyncIterator] ? iterable[Symbol.asyncIterator]() : iterable[Symbol.iterator]();
|
|
622
793
|
return {
|
|
623
794
|
next() {
|
|
624
|
-
|
|
625
|
-
if (
|
|
626
|
-
|
|
627
|
-
|
|
795
|
+
if (terminal) return { done: true };
|
|
796
|
+
if (first) {
|
|
797
|
+
first = false;
|
|
798
|
+
start();
|
|
799
|
+
const step = firstStep;
|
|
800
|
+
firstStep = undefined;
|
|
801
|
+
if (step.then) return step.then(transformStep);
|
|
802
|
+
return transformStep(step);
|
|
628
803
|
}
|
|
629
|
-
return
|
|
804
|
+
return getNext();
|
|
630
805
|
},
|
|
631
806
|
return(value) {
|
|
632
|
-
|
|
807
|
+
terminal = true;
|
|
808
|
+
started = true;
|
|
809
|
+
if (!iterator)
|
|
810
|
+
iterator = iterable[Symbol.asyncIterator]
|
|
811
|
+
? iterable[Symbol.asyncIterator]()
|
|
812
|
+
: iterable[Symbol.iterator]?.();
|
|
813
|
+
return iterator?.return?.(value) ?? { value, done: true };
|
|
633
814
|
},
|
|
634
815
|
throw(error) {
|
|
635
|
-
return iterator
|
|
816
|
+
return iterator?.throw?.(error) ?? Promise.reject(error);
|
|
636
817
|
},
|
|
637
818
|
};
|
|
638
819
|
},
|
|
@@ -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) => {
|