@harperfast/harper 5.2.13 → 5.3.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent/mcpTools.ts +1 -1
- package/agent/session.ts +25 -14
- package/bin/cliOperations.ts +58 -9
- package/bin/copyDb.ts +282 -59
- package/bin/deploySetup.ts +16 -5
- package/bin/harper.ts +1 -1
- package/bin/help.ts +4 -1
- package/bin/lite.ts +4 -1
- package/bin/restart.ts +120 -4
- package/bin/run.ts +6 -11
- package/bin/upgrade.js +7 -3
- package/bin/workloadIdentity.ts +119 -0
- package/components/Application.ts +3436 -242
- package/components/ApplicationScope.ts +8 -0
- package/components/EntryHandler.ts +59 -39
- package/components/OptionsWatcher.ts +440 -98
- package/components/RuntimeModuleTracker.ts +38 -7
- package/components/Scope.ts +56 -15
- package/components/awaitRestart.ts +84 -0
- package/components/componentLoader.ts +381 -32
- package/components/componentPreparationLock.ts +16 -5
- package/components/deploymentOperations.ts +4 -1
- package/components/deploymentRecorder.ts +9 -2
- package/components/mcp/adapters/harperHttp.ts +4 -0
- package/components/mcp/listChanged.ts +4 -0
- package/components/mcp/toolRegistry.ts +2 -0
- package/components/mcp/tools/operations.ts +9 -0
- package/components/mcp/tools/schemas/operationDescriptions.ts +2 -2
- package/components/operations.js +537 -113
- package/components/operationsValidation.js +98 -3
- package/components/packageComponent.ts +25 -1
- package/components/requestRestart.ts +11 -0
- package/components/status/ComponentStatusRegistry.ts +59 -0
- package/config/RootConfigWatcher.ts +240 -40
- package/config/configReadRetry.ts +62 -0
- package/config/configUtils.ts +357 -48
- package/config/harperConfigEnvVars.ts +170 -27
- package/config/parseConfigFile.ts +34 -0
- package/config/readConfigFileSync.ts +44 -0
- package/config/watcherArming.ts +59 -0
- package/config-root.schema.json +33 -0
- package/dataLayer/blobBackup.ts +160 -50
- package/dataLayer/delete.ts +6 -1
- package/dataLayer/harperBridge/ResourceBridge.ts +80 -10
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.js +3 -1
- package/dataLayer/hdbInfoController.ts +34 -1
- package/dataLayer/insert.ts +44 -1
- package/dataLayer/rocksdbBackup.ts +53 -10
- package/dataLayer/schema.ts +11 -1
- package/dataLayer/schemaDescribe.ts +8 -1
- package/dist/agent/mcpTools.js +1 -1
- package/dist/agent/mcpTools.js.map +1 -1
- package/dist/agent/session.d.ts +22 -0
- package/dist/agent/session.js +26 -15
- package/dist/agent/session.js.map +1 -1
- package/dist/bin/cliOperations.js +61 -9
- package/dist/bin/cliOperations.js.map +1 -1
- package/dist/bin/copyDb.d.ts +12 -1
- package/dist/bin/copyDb.js +248 -60
- package/dist/bin/copyDb.js.map +1 -1
- package/dist/bin/deploySetup.d.ts +2 -0
- package/dist/bin/deploySetup.js +11 -3
- package/dist/bin/deploySetup.js.map +1 -1
- package/dist/bin/harper.js +1 -1
- package/dist/bin/harper.js.map +1 -1
- package/dist/bin/help.js +4 -1
- package/dist/bin/help.js.map +1 -1
- package/dist/bin/lite.js +4 -1
- package/dist/bin/lite.js.map +1 -1
- package/dist/bin/restart.js +91 -6
- package/dist/bin/restart.js.map +1 -1
- package/dist/bin/run.js +4 -10
- package/dist/bin/run.js.map +1 -1
- package/dist/bin/upgrade.js +4 -3
- package/dist/bin/upgrade.js.map +1 -1
- package/dist/bin/workloadIdentity.d.ts +18 -0
- package/dist/bin/workloadIdentity.js +100 -0
- package/dist/bin/workloadIdentity.js.map +1 -0
- package/dist/components/Application.d.ts +235 -17
- package/dist/components/Application.js +3038 -238
- package/dist/components/Application.js.map +1 -1
- package/dist/components/ApplicationScope.d.ts +8 -0
- package/dist/components/ApplicationScope.js +7 -0
- package/dist/components/ApplicationScope.js.map +1 -1
- package/dist/components/EntryHandler.js +26 -10
- package/dist/components/EntryHandler.js.map +1 -1
- package/dist/components/OptionsWatcher.d.ts +4 -0
- package/dist/components/OptionsWatcher.js +440 -99
- package/dist/components/OptionsWatcher.js.map +1 -1
- package/dist/components/RuntimeModuleTracker.js +40 -6
- package/dist/components/RuntimeModuleTracker.js.map +1 -1
- package/dist/components/Scope.js +52 -13
- package/dist/components/Scope.js.map +1 -1
- package/dist/components/awaitRestart.d.ts +33 -0
- package/dist/components/awaitRestart.js +61 -0
- package/dist/components/awaitRestart.js.map +1 -0
- package/dist/components/componentLoader.d.ts +38 -1
- package/dist/components/componentLoader.js +313 -24
- package/dist/components/componentLoader.js.map +1 -1
- package/dist/components/componentPreparationLock.d.ts +5 -0
- package/dist/components/componentPreparationLock.js +14 -6
- package/dist/components/componentPreparationLock.js.map +1 -1
- package/dist/components/deploymentOperations.js +4 -1
- package/dist/components/deploymentOperations.js.map +1 -1
- package/dist/components/deploymentRecorder.d.ts +4 -2
- package/dist/components/deploymentRecorder.js +1 -0
- package/dist/components/deploymentRecorder.js.map +1 -1
- package/dist/components/mcp/adapters/harperHttp.js +4 -0
- package/dist/components/mcp/adapters/harperHttp.js.map +1 -1
- package/dist/components/mcp/listChanged.js +5 -0
- package/dist/components/mcp/listChanged.js.map +1 -1
- package/dist/components/mcp/toolRegistry.d.ts +1 -0
- package/dist/components/mcp/toolRegistry.js.map +1 -1
- package/dist/components/mcp/tools/operations.d.ts +5 -0
- package/dist/components/mcp/tools/operations.js +9 -0
- package/dist/components/mcp/tools/operations.js.map +1 -1
- package/dist/components/mcp/tools/schemas/operationDescriptions.js +2 -2
- package/dist/components/mcp/tools/schemas/operationDescriptions.js.map +1 -1
- package/dist/components/operations.d.ts +28 -0
- package/dist/components/operations.js +476 -113
- package/dist/components/operations.js.map +1 -1
- package/dist/components/operationsValidation.js +97 -3
- package/dist/components/operationsValidation.js.map +1 -1
- package/dist/components/packageComponent.js +24 -0
- package/dist/components/packageComponent.js.map +1 -1
- package/dist/components/requestRestart.d.ts +1 -0
- package/dist/components/requestRestart.js +7 -0
- package/dist/components/requestRestart.js.map +1 -1
- package/dist/components/status/ComponentStatusRegistry.d.ts +0 -4
- package/dist/components/status/ComponentStatusRegistry.js +63 -0
- package/dist/components/status/ComponentStatusRegistry.js.map +1 -1
- package/dist/config/RootConfigWatcher.d.ts +9 -1
- package/dist/config/RootConfigWatcher.js +228 -37
- package/dist/config/RootConfigWatcher.js.map +1 -1
- package/dist/config/configReadRetry.d.ts +8 -0
- package/dist/config/configReadRetry.js +62 -0
- package/dist/config/configReadRetry.js.map +1 -0
- package/dist/config/configUtils.d.ts +11 -2
- package/dist/config/configUtils.js +304 -47
- package/dist/config/configUtils.js.map +1 -1
- package/dist/config/harperConfigEnvVars.d.ts +16 -0
- package/dist/config/harperConfigEnvVars.js +162 -25
- package/dist/config/harperConfigEnvVars.js.map +1 -1
- package/dist/config/parseConfigFile.d.ts +4 -0
- package/dist/config/parseConfigFile.js +35 -0
- package/dist/config/parseConfigFile.js.map +1 -0
- package/dist/config/readConfigFileSync.d.ts +1 -0
- package/dist/config/readConfigFileSync.js +47 -0
- package/dist/config/readConfigFileSync.js.map +1 -0
- package/dist/config/watcherArming.d.ts +15 -0
- package/dist/config/watcherArming.js +59 -0
- package/dist/config/watcherArming.js.map +1 -0
- package/dist/dataLayer/blobBackup.d.ts +49 -20
- package/dist/dataLayer/blobBackup.js +139 -50
- package/dist/dataLayer/blobBackup.js.map +1 -1
- package/dist/dataLayer/delete.js +1 -1
- package/dist/dataLayer/delete.js.map +1 -1
- package/dist/dataLayer/harperBridge/ResourceBridge.d.ts +14 -1
- package/dist/dataLayer/harperBridge/ResourceBridge.js +72 -12
- package/dist/dataLayer/harperBridge/ResourceBridge.js.map +1 -1
- package/dist/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.d.ts +3 -1
- package/dist/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.js +3 -1
- package/dist/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.js.map +1 -1
- package/dist/dataLayer/hdbInfoController.d.ts +10 -0
- package/dist/dataLayer/hdbInfoController.js +30 -1
- package/dist/dataLayer/hdbInfoController.js.map +1 -1
- package/dist/dataLayer/insert.d.ts +9 -1
- package/dist/dataLayer/insert.js +30 -0
- package/dist/dataLayer/insert.js.map +1 -1
- package/dist/dataLayer/rocksdbBackup.d.ts +2 -2
- package/dist/dataLayer/rocksdbBackup.js +45 -8
- package/dist/dataLayer/rocksdbBackup.js.map +1 -1
- package/dist/dataLayer/schema.js +8 -0
- package/dist/dataLayer/schema.js.map +1 -1
- package/dist/dataLayer/schemaDescribe.js +8 -1
- package/dist/dataLayer/schemaDescribe.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/json/systemSchema.json +55 -0
- package/dist/resources/DatabaseTransaction.d.ts +77 -0
- package/dist/resources/DatabaseTransaction.js +586 -54
- package/dist/resources/DatabaseTransaction.js.map +1 -1
- package/dist/resources/LMDBTransaction.d.ts +2 -1
- package/dist/resources/LMDBTransaction.js +43 -6
- package/dist/resources/LMDBTransaction.js.map +1 -1
- package/dist/resources/PrimaryRocksDatabase.d.ts +1 -0
- package/dist/resources/PrimaryRocksDatabase.js +49 -5
- package/dist/resources/PrimaryRocksDatabase.js.map +1 -1
- package/dist/resources/RecordEncoder.d.ts +20 -0
- package/dist/resources/RecordEncoder.js +110 -9
- package/dist/resources/RecordEncoder.js.map +1 -1
- package/dist/resources/RequestTarget.d.ts +2 -0
- package/dist/resources/RequestTarget.js.map +1 -1
- package/dist/resources/Resource.js +117 -24
- package/dist/resources/Resource.js.map +1 -1
- package/dist/resources/ResourceInterface.d.ts +28 -1
- package/dist/resources/ResourceInterface.js.map +1 -1
- package/dist/resources/RocksIndexStore.d.ts +6 -1
- package/dist/resources/RocksIndexStore.js +24 -9
- package/dist/resources/RocksIndexStore.js.map +1 -1
- package/dist/resources/RocksTransactionLogStore.d.ts +24 -1
- package/dist/resources/RocksTransactionLogStore.js +160 -49
- package/dist/resources/RocksTransactionLogStore.js.map +1 -1
- package/dist/resources/Table.d.ts +165 -10
- package/dist/resources/Table.js +1805 -303
- package/dist/resources/Table.js.map +1 -1
- package/dist/resources/analytics/write.js +10 -3
- package/dist/resources/analytics/write.js.map +1 -1
- package/dist/resources/auditStore.d.ts +181 -2
- package/dist/resources/auditStore.js +640 -29
- package/dist/resources/auditStore.js.map +1 -1
- package/dist/resources/blob.d.ts +129 -9
- package/dist/resources/blob.js +992 -114
- package/dist/resources/blob.js.map +1 -1
- package/dist/resources/branchDatabase.d.ts +48 -0
- package/dist/resources/branchDatabase.js +892 -0
- package/dist/resources/branchDatabase.js.map +1 -0
- package/dist/resources/crdt.js +50 -12
- package/dist/resources/crdt.js.map +1 -1
- package/dist/resources/dataLoader.js +3 -4
- package/dist/resources/dataLoader.js.map +1 -1
- package/dist/resources/databases.d.ts +157 -14
- package/dist/resources/databases.js +1462 -325
- package/dist/resources/databases.js.map +1 -1
- package/dist/resources/defineTable.d.ts +10 -2
- package/dist/resources/defineTable.js +9 -1
- package/dist/resources/defineTable.js.map +1 -1
- package/dist/resources/derivedIndexRegistry.d.ts +5 -0
- package/dist/resources/derivedIndexRegistry.js +68 -0
- package/dist/resources/derivedIndexRegistry.js.map +1 -0
- package/dist/resources/derivedIndexRuntime.d.ts +215 -0
- package/dist/resources/derivedIndexRuntime.js +2027 -0
- package/dist/resources/derivedIndexRuntime.js.map +1 -0
- package/dist/resources/graphql.d.ts +1 -1
- package/dist/resources/graphql.js +52 -16
- package/dist/resources/graphql.js.map +1 -1
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.d.ts +103 -9
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js +854 -41
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js.map +1 -1
- package/dist/resources/indexes/hnswDerivedIndex.d.ts +67 -0
- package/dist/resources/indexes/hnswDerivedIndex.js +464 -0
- package/dist/resources/indexes/hnswDerivedIndex.js.map +1 -0
- package/dist/resources/indexes/hnswPlaneBinding.d.ts +65 -0
- package/dist/resources/indexes/hnswPlaneBinding.js +91 -0
- package/dist/resources/indexes/hnswPlaneBinding.js.map +1 -0
- package/dist/resources/longLivedTransactions.d.ts +71 -0
- package/dist/resources/longLivedTransactions.js +358 -0
- package/dist/resources/longLivedTransactions.js.map +1 -0
- package/dist/resources/models/backendRegistry.d.ts +26 -0
- package/dist/resources/models/backendRegistry.js +60 -2
- package/dist/resources/models/backendRegistry.js.map +1 -1
- package/dist/resources/models/bootstrap.d.ts +33 -1
- package/dist/resources/models/bootstrap.js +416 -31
- package/dist/resources/models/bootstrap.js.map +1 -1
- package/dist/resources/nodeIdMapping.d.ts +5 -0
- package/dist/resources/nodeIdMapping.js +49 -0
- package/dist/resources/nodeIdMapping.js.map +1 -1
- package/dist/resources/recordLock.d.ts +123 -0
- package/dist/resources/recordLock.js +315 -0
- package/dist/resources/recordLock.js.map +1 -0
- package/dist/resources/recordLockCoordinator.d.ts +557 -0
- package/dist/resources/recordLockCoordinator.js +2565 -0
- package/dist/resources/recordLockCoordinator.js.map +1 -0
- package/dist/resources/replayLogs.d.ts +14 -1
- package/dist/resources/replayLogs.js +157 -24
- package/dist/resources/replayLogs.js.map +1 -1
- package/dist/resources/replayLogsGuards.d.ts +94 -7
- package/dist/resources/replayLogsGuards.js +111 -7
- package/dist/resources/replayLogsGuards.js.map +1 -1
- package/dist/resources/replicatedApplyFailure.d.ts +16 -0
- package/dist/resources/replicatedApplyFailure.js +63 -0
- package/dist/resources/replicatedApplyFailure.js.map +1 -0
- package/dist/resources/scheduler/scheduler.js +3 -3
- package/dist/resources/scheduler/scheduler.js.map +1 -1
- package/dist/resources/search.d.ts +10 -4
- package/dist/resources/search.js +283 -37
- package/dist/resources/search.js.map +1 -1
- package/dist/resources/tracked.d.ts +5 -1
- package/dist/resources/tracked.js +74 -23
- package/dist/resources/tracked.js.map +1 -1
- package/dist/resources/transactionBroadcast.d.ts +1 -1
- package/dist/resources/transactionBroadcast.js +2 -2
- package/dist/resources/transactionBroadcast.js.map +1 -1
- package/dist/security/auth.js +61 -30
- package/dist/security/auth.js.map +1 -1
- package/dist/security/authn/oidc/claims.d.ts +22 -0
- package/dist/security/authn/oidc/claims.js +71 -0
- package/dist/security/authn/oidc/claims.js.map +1 -0
- package/dist/security/authn/oidc/identityToken.d.ts +27 -0
- package/dist/security/authn/oidc/identityToken.js +111 -0
- package/dist/security/authn/oidc/identityToken.js.map +1 -0
- package/dist/security/authn/oidc/jwks.d.ts +25 -0
- package/dist/security/authn/oidc/jwks.js +261 -0
- package/dist/security/authn/oidc/jwks.js.map +1 -0
- package/dist/security/authn/oidc/providers/generic.d.ts +13 -0
- package/dist/security/authn/oidc/providers/generic.js +34 -0
- package/dist/security/authn/oidc/providers/generic.js.map +1 -0
- package/dist/security/authn/oidc/providers/githubActions.d.ts +11 -0
- package/dist/security/authn/oidc/providers/githubActions.js +129 -0
- package/dist/security/authn/oidc/providers/githubActions.js.map +1 -0
- package/dist/security/authn/oidc/providers/index.d.ts +37 -0
- package/dist/security/authn/oidc/providers/index.js +24 -0
- package/dist/security/authn/oidc/providers/index.js.map +1 -0
- package/dist/security/authn/oidc/tokenExchange.d.ts +12 -0
- package/dist/security/authn/oidc/tokenExchange.js +306 -0
- package/dist/security/authn/oidc/tokenExchange.js.map +1 -0
- package/dist/security/authn/oidc/trustPolicyOperations.d.ts +49 -0
- package/dist/security/authn/oidc/trustPolicyOperations.js +358 -0
- package/dist/security/authn/oidc/trustPolicyOperations.js.map +1 -0
- package/dist/security/authn/oidc/types.d.ts +38 -0
- package/dist/security/authn/oidc/types.js +6 -0
- package/dist/security/authn/oidc/types.js.map +1 -0
- package/dist/security/certificateVerification/index.js +40 -11
- package/dist/security/certificateVerification/index.js.map +1 -1
- package/dist/security/certificateVerification/trustedIssuers.d.ts +24 -0
- package/dist/security/certificateVerification/trustedIssuers.js +79 -0
- package/dist/security/certificateVerification/trustedIssuers.js.map +1 -0
- package/dist/security/certificateVerification/types.d.ts +1 -0
- package/dist/security/credentialProvenance.d.ts +35 -0
- package/dist/security/credentialProvenance.js +51 -0
- package/dist/security/credentialProvenance.js.map +1 -0
- package/dist/security/credentialRejection.d.ts +4 -0
- package/dist/security/credentialRejection.js +24 -0
- package/dist/security/credentialRejection.js.map +1 -0
- package/dist/security/deferredAuthentication.d.ts +36 -0
- package/dist/security/deferredAuthentication.js +70 -0
- package/dist/security/deferredAuthentication.js.map +1 -0
- package/dist/security/impersonation.d.ts +21 -0
- package/dist/security/impersonation.js +108 -9
- package/dist/security/impersonation.js.map +1 -1
- package/dist/security/jsLoader.d.ts +6 -0
- package/dist/security/jsLoader.js +77 -15
- package/dist/security/jsLoader.js.map +1 -1
- package/dist/security/keys.js +301 -71
- package/dist/security/keys.js.map +1 -1
- package/dist/security/operationScope.d.ts +21 -0
- package/dist/security/operationScope.js +36 -0
- package/dist/security/operationScope.js.map +1 -0
- package/dist/security/permissionsTranslator.js +21 -0
- package/dist/security/permissionsTranslator.js.map +1 -1
- package/dist/security/tokenAuthentication.d.ts +19 -1
- package/dist/security/tokenAuthentication.js +191 -10
- package/dist/security/tokenAuthentication.js.map +1 -1
- package/dist/security/user.js +4 -3
- package/dist/security/user.js.map +1 -1
- package/dist/server/DurableSubscriptionsSession.d.ts +2 -2
- package/dist/server/DurableSubscriptionsSession.js +67 -10
- package/dist/server/DurableSubscriptionsSession.js.map +1 -1
- package/dist/server/REST.js +106 -2
- package/dist/server/REST.js.map +1 -1
- package/dist/server/graphqlQuerying.js +4 -0
- package/dist/server/graphqlQuerying.js.map +1 -1
- package/dist/server/http.d.ts +16 -1
- package/dist/server/http.js +122 -17
- package/dist/server/http.js.map +1 -1
- package/dist/server/itc/serverHandlers.js +8 -1
- package/dist/server/itc/serverHandlers.js.map +1 -1
- package/dist/server/jobs/jobProcess.js +6 -2
- package/dist/server/jobs/jobProcess.js.map +1 -1
- package/dist/server/jobs/jobs.js +4 -1
- package/dist/server/jobs/jobs.js.map +1 -1
- package/dist/server/liveSubscriptionAuth.d.ts +26 -4
- package/dist/server/liveSubscriptionAuth.js +105 -39
- package/dist/server/liveSubscriptionAuth.js.map +1 -1
- package/dist/server/loadRootComponents.js +49 -10
- package/dist/server/loadRootComponents.js.map +1 -1
- package/dist/server/mqtt.d.ts +2 -0
- package/dist/server/mqtt.js +165 -30
- package/dist/server/mqtt.js.map +1 -1
- package/dist/server/nodeName.d.ts +2 -0
- package/dist/server/nodeName.js +107 -23
- package/dist/server/nodeName.js.map +1 -1
- package/dist/server/serverHelpers/Headers.d.ts +27 -0
- package/dist/server/serverHelpers/Headers.js +145 -1
- package/dist/server/serverHelpers/Headers.js.map +1 -1
- package/dist/server/serverHelpers/NodeAdapterResponse.d.ts +48 -0
- package/dist/server/serverHelpers/NodeAdapterResponse.js +220 -0
- package/dist/server/serverHelpers/NodeAdapterResponse.js.map +1 -0
- package/dist/server/serverHelpers/Request.d.ts +5 -10
- package/dist/server/serverHelpers/Request.js +38 -136
- package/dist/server/serverHelpers/Request.js.map +1 -1
- package/dist/server/serverHelpers/contentTypes.d.ts +11 -0
- package/dist/server/serverHelpers/contentTypes.js +221 -40
- package/dist/server/serverHelpers/contentTypes.js.map +1 -1
- package/dist/server/serverHelpers/deployValidationState.d.ts +3 -0
- package/dist/server/serverHelpers/deployValidationState.js +9 -19
- package/dist/server/serverHelpers/deployValidationState.js.map +1 -1
- package/dist/server/serverHelpers/operationAuthorizationState.d.ts +12 -0
- package/dist/server/serverHelpers/operationAuthorizationState.js +24 -2
- package/dist/server/serverHelpers/operationAuthorizationState.js.map +1 -1
- package/dist/server/serverHelpers/registeredOperations.d.ts +5 -4
- package/dist/server/serverHelpers/registeredOperations.js +74 -21
- package/dist/server/serverHelpers/registeredOperations.js.map +1 -1
- package/dist/server/serverHelpers/requestSanitization.d.ts +11 -0
- package/dist/server/serverHelpers/requestSanitization.js +20 -0
- package/dist/server/serverHelpers/requestSanitization.js.map +1 -0
- package/dist/server/serverHelpers/serverHandlers.js +6 -3
- package/dist/server/serverHelpers/serverHandlers.js.map +1 -1
- package/dist/server/serverHelpers/serverUtilities.d.ts +18 -0
- package/dist/server/serverHelpers/serverUtilities.js +178 -29
- package/dist/server/serverHelpers/serverUtilities.js.map +1 -1
- package/dist/server/serverHelpers/sharedMessageEncoding.d.ts +67 -0
- package/dist/server/serverHelpers/sharedMessageEncoding.js +280 -0
- package/dist/server/serverHelpers/sharedMessageEncoding.js.map +1 -0
- package/dist/server/serverHelpers/uwsServer.js +19 -1
- package/dist/server/serverHelpers/uwsServer.js.map +1 -1
- package/dist/server/static.js +24 -28
- package/dist/server/static.js.map +1 -1
- package/dist/server/storageReclamation.d.ts +5 -0
- package/dist/server/storageReclamation.js +17 -1
- package/dist/server/storageReclamation.js.map +1 -1
- package/dist/server/threads/isolatedApplications.d.ts +47 -0
- package/dist/server/threads/isolatedApplications.js +171 -0
- package/dist/server/threads/isolatedApplications.js.map +1 -0
- package/dist/server/threads/itc.d.ts +7 -2
- package/dist/server/threads/itc.js +5 -1
- package/dist/server/threads/itc.js.map +1 -1
- package/dist/server/threads/logRotationTransport.d.ts +1 -0
- package/dist/server/threads/logRotationTransport.js +33 -0
- package/dist/server/threads/logRotationTransport.js.map +1 -0
- package/dist/server/threads/manageThreads.d.ts +83 -3
- package/dist/server/threads/manageThreads.js +769 -75
- package/dist/server/threads/manageThreads.js.map +1 -1
- package/dist/server/threads/socketRouter.d.ts +1 -0
- package/dist/server/threads/socketRouter.js +277 -31
- package/dist/server/threads/socketRouter.js.map +1 -1
- package/dist/server/threads/threadHeapMemory.d.ts +2 -0
- package/dist/server/threads/threadHeapMemory.js +31 -0
- package/dist/server/threads/threadHeapMemory.js.map +1 -0
- package/dist/server/threads/threadServer.js +76 -22
- package/dist/server/threads/threadServer.js.map +1 -1
- package/dist/sqlEngine/config.d.ts +1 -3
- package/dist/sqlEngine/config.js +19 -16
- package/dist/sqlEngine/config.js.map +1 -1
- package/dist/sqlTranslator/index.d.ts +1 -1
- package/dist/sqlTranslator/index.js +30 -7
- package/dist/sqlTranslator/index.js.map +1 -1
- package/dist/upgrade/directives/5-3-0.d.ts +7 -0
- package/dist/upgrade/directives/5-3-0.js +148 -0
- package/dist/upgrade/directives/5-3-0.js.map +1 -0
- package/dist/upgrade/directives/directivesController.js +2 -1
- package/dist/upgrade/directives/directivesController.js.map +1 -1
- package/dist/utility/OperationFunctionCaller.js +2 -1
- package/dist/utility/OperationFunctionCaller.js.map +1 -1
- package/dist/utility/common_utils.d.ts +16 -0
- package/dist/utility/common_utils.js +32 -6
- package/dist/utility/common_utils.js.map +1 -1
- package/dist/utility/componentNames.d.ts +8 -0
- package/dist/utility/componentNames.js +12 -1
- package/dist/utility/componentNames.js.map +1 -1
- package/dist/utility/environment/environmentManager.js +3 -6
- package/dist/utility/environment/environmentManager.js.map +1 -1
- package/dist/utility/environment/systemInformation.d.ts +1 -0
- package/dist/utility/environment/systemInformation.js +1 -0
- package/dist/utility/environment/systemInformation.js.map +1 -1
- package/dist/utility/errors/commonErrors.d.ts +2 -0
- package/dist/utility/errors/commonErrors.js +2 -0
- package/dist/utility/errors/commonErrors.js.map +1 -1
- package/dist/utility/errors/hdbError.d.ts +33 -0
- package/dist/utility/errors/hdbError.js +58 -1
- package/dist/utility/errors/hdbError.js.map +1 -1
- package/dist/utility/globalSchema.d.ts +18 -0
- package/dist/utility/hdbTerms.d.ts +18 -0
- package/dist/utility/hdbTerms.js +20 -2
- package/dist/utility/hdbTerms.js.map +1 -1
- package/dist/utility/logging/harper_logger.d.ts +2 -0
- package/dist/utility/logging/harper_logger.js +286 -30
- package/dist/utility/logging/harper_logger.js.map +1 -1
- package/dist/utility/logging/logGenerationCoordinator.d.ts +35 -0
- package/dist/utility/logging/logGenerationCoordinator.js +184 -0
- package/dist/utility/logging/logGenerationCoordinator.js.map +1 -0
- package/dist/utility/logging/logRotation.d.ts +46 -0
- package/dist/utility/logging/logRotation.js +365 -0
- package/dist/utility/logging/logRotation.js.map +1 -0
- package/dist/utility/logging/logRotator.d.ts +1 -1
- package/dist/utility/logging/logRotator.js +192 -85
- package/dist/utility/logging/logRotator.js.map +1 -1
- package/dist/utility/nodeIdentity.d.ts +9 -0
- package/dist/utility/nodeIdentity.js +58 -0
- package/dist/utility/nodeIdentity.js.map +1 -0
- package/dist/utility/npmUtilities.js +11 -7
- package/dist/utility/npmUtilities.js.map +1 -1
- package/dist/utility/operationPermissions.d.ts +3 -1
- package/dist/utility/operationPermissions.js +16 -1
- package/dist/utility/operationPermissions.js.map +1 -1
- package/dist/utility/operation_authorization.d.ts +10 -7
- package/dist/utility/operation_authorization.js +212 -41
- package/dist/utility/operation_authorization.js.map +1 -1
- package/dist/utility/watchPath.d.ts +29 -0
- package/dist/utility/watchPath.js +68 -0
- package/dist/utility/watchPath.js.map +1 -0
- package/dist/utility/watcherFallback.d.ts +41 -0
- package/dist/utility/watcherFallback.js +153 -0
- package/dist/utility/watcherFallback.js.map +1 -1
- package/dist/validation/configValidator.d.ts +12 -0
- package/dist/validation/configValidator.js +205 -75
- package/dist/validation/configValidator.js.map +1 -1
- package/dist/validation/installValidator.js +12 -0
- package/dist/validation/installValidator.js.map +1 -1
- package/dist/validation/validationWrapper.d.ts +11 -0
- package/dist/validation/validationWrapper.js +16 -3
- package/dist/validation/validationWrapper.js.map +1 -1
- package/index.ts +8 -0
- package/json/systemSchema.json +55 -0
- package/npm-shrinkwrap.json +286 -194
- package/package.json +15 -7
- package/resources/DESIGN.md +219 -52
- package/resources/DatabaseTransaction.ts +657 -52
- package/resources/LMDBTransaction.ts +46 -6
- package/resources/PrimaryRocksDatabase.ts +46 -7
- package/resources/RecordEncoder.ts +124 -9
- package/resources/RequestTarget.ts +2 -0
- package/resources/Resource.ts +114 -22
- package/resources/ResourceInterface.ts +31 -0
- package/resources/RocksIndexStore.ts +30 -9
- package/resources/RocksTransactionLogStore.ts +188 -51
- package/resources/Table.ts +1960 -301
- package/resources/analytics/write.ts +10 -3
- package/resources/auditStore.ts +647 -32
- package/resources/blob.ts +1029 -110
- package/resources/branchDatabase.ts +941 -0
- package/resources/crdt.ts +76 -12
- package/resources/dataLoader.ts +3 -4
- package/resources/databases.ts +1584 -320
- package/resources/defineTable.ts +18 -2
- package/resources/derivedIndexRegistry.ts +56 -0
- package/resources/derivedIndexRuntime.ts +2292 -0
- package/resources/graphql.ts +72 -17
- package/resources/indexes/HierarchicalNavigableSmallWorld.ts +911 -48
- package/resources/indexes/hnswDerivedIndex.ts +531 -0
- package/resources/indexes/hnswPlaneBinding.ts +174 -0
- package/resources/longLivedTransactions.ts +360 -0
- package/resources/models/backendRegistry.ts +84 -2
- package/resources/models/bootstrap.ts +473 -28
- package/resources/nodeIdMapping.ts +50 -0
- package/resources/recordLock.ts +419 -0
- package/resources/recordLockCoordinator.ts +3043 -0
- package/resources/replayLogs.ts +152 -26
- package/resources/replayLogsGuards.ts +171 -8
- package/resources/replicatedApplyFailure.ts +77 -0
- package/resources/scheduler/scheduler.ts +4 -4
- package/resources/search.ts +288 -46
- package/resources/tracked.ts +73 -22
- package/resources/transactionBroadcast.ts +3 -3
- package/security/auth.ts +68 -29
- package/security/authn/oidc/claims.ts +72 -0
- package/security/authn/oidc/identityToken.ts +129 -0
- package/security/authn/oidc/jwks.ts +260 -0
- package/security/authn/oidc/providers/generic.ts +40 -0
- package/security/authn/oidc/providers/githubActions.ts +137 -0
- package/security/authn/oidc/providers/index.ts +52 -0
- package/security/authn/oidc/tokenExchange.ts +300 -0
- package/security/authn/oidc/trustPolicyOperations.ts +343 -0
- package/security/authn/oidc/types.ts +41 -0
- package/security/certificateVerification/index.ts +54 -13
- package/security/certificateVerification/trustedIssuers.ts +76 -0
- package/security/certificateVerification/types.ts +1 -0
- package/security/credentialProvenance.ts +47 -0
- package/security/credentialRejection.ts +22 -0
- package/security/deferredAuthentication.ts +71 -0
- package/security/impersonation.ts +117 -12
- package/security/jsLoader.ts +83 -18
- package/security/keys.ts +298 -72
- package/security/operationScope.ts +33 -0
- package/security/permissionsTranslator.js +23 -0
- package/security/tokenAuthentication.ts +233 -12
- package/security/user.ts +4 -3
- package/server/DESIGN.md +194 -16
- package/server/DurableSubscriptionsSession.ts +71 -11
- package/server/REST.ts +115 -4
- package/server/graphqlQuerying.ts +4 -0
- package/server/http.ts +133 -20
- package/server/itc/serverHandlers.js +8 -1
- package/server/jobs/jobProcess.ts +8 -2
- package/server/jobs/jobs.ts +4 -1
- package/server/liveSubscriptionAuth.ts +129 -46
- package/server/loadRootComponents.js +50 -8
- package/server/mqtt.ts +179 -38
- package/server/nodeName.ts +103 -21
- package/server/serverHelpers/Headers.ts +135 -0
- package/server/serverHelpers/NodeAdapterResponse.ts +221 -0
- package/server/serverHelpers/Request.ts +33 -131
- package/server/serverHelpers/contentTypes.ts +217 -36
- package/server/serverHelpers/deployValidationState.ts +24 -13
- package/server/serverHelpers/operationAuthorizationState.ts +34 -3
- package/server/serverHelpers/registeredOperations.ts +79 -22
- package/server/serverHelpers/requestSanitization.ts +15 -0
- package/server/serverHelpers/serverHandlers.js +6 -3
- package/server/serverHelpers/serverUtilities.ts +232 -40
- package/server/serverHelpers/sharedMessageEncoding.ts +307 -0
- package/server/serverHelpers/uwsServer.ts +17 -2
- package/server/static.ts +23 -29
- package/server/storageReclamation.ts +15 -2
- package/server/threads/isolatedApplications.ts +157 -0
- package/server/threads/itc.js +11 -1
- package/server/threads/logRotationTransport.ts +40 -0
- package/server/threads/manageThreads.js +771 -66
- package/server/threads/socketRouter.ts +291 -30
- package/server/threads/threadHeapMemory.ts +26 -0
- package/server/threads/threadServer.js +73 -22
- package/sqlTranslator/index.ts +31 -8
- package/studio/web/assets/{Chat-4RrB5134.js → Chat-D3j-1yY1.js} +1 -1
- package/studio/web/assets/{FloatingChat-omlNMDcJ.js → FloatingChat-BxJGYcfB.js} +3 -3
- package/studio/web/assets/{apiToken-Bke3wvfZ.js → apiToken-CT55oWOe.js} +1 -1
- package/studio/web/assets/{applications-DvFDYJgK.js → applications-D9Ct9_vm.js} +1 -1
- package/studio/web/assets/{cssMode-C1vRa7zh.js → cssMode-DV8H7VwA.js} +1 -1
- package/studio/web/assets/{editor-3XRWEDWX.js → editor-uatc0unt.js} +1 -1
- package/studio/web/assets/{html-CTY5tdMr.js → html-Bm6D6paN.js} +1 -1
- package/studio/web/assets/{htmlMode-CG1vSD9t.js → htmlMode-CEn7tpLG.js} +1 -1
- package/studio/web/assets/{index-Dfpeofdu.js → index-BIXW6Pu4.js} +5 -5
- package/studio/web/assets/{index.lazy-B1VOIv-t.js → index.lazy-UI7L-Vrk.js} +1 -1
- package/studio/web/assets/{javascript-CJeJzGnI.js → javascript-CJ0G3AFZ.js} +1 -1
- package/studio/web/assets/{jsonMode-CYPBwM82.js → jsonMode-DQADAYEa.js} +1 -1
- package/studio/web/assets/{languageServices-IKH4GUHl.js → languageServices-CAQJXWcI.js} +1 -1
- package/studio/web/assets/{lspLanguageFeatures-BC8_gxKG.js → lspLanguageFeatures-CCQ8P5sY.js} +1 -1
- package/studio/web/assets/{notifications-BfKBpYcq.js → notifications-BbxTU6Aw.js} +1 -1
- package/studio/web/assets/{notifications-DFbArTfC.js → notifications-Cvb3P1lB.js} +1 -1
- package/studio/web/assets/{profile-Q4-T6c-S.js → profile-Yyb7gsvL.js} +1 -1
- package/studio/web/assets/{regions-CtkV0xje.js → regions-OgjGHlU5.js} +1 -1
- package/studio/web/assets/{register-1ZZuMsiA.js → register-6qwNEOY3.js} +2 -2
- package/studio/web/assets/{setComponentFile-ZWLcWv5X.js → setComponentFile-BilDMtgB.js} +1 -1
- package/studio/web/assets/{setup-DWprJyJy.js → setup-J6qJ7OIU.js} +2 -2
- package/studio/web/assets/{status--aNm8isn.js → status-0RWGcfyD.js} +1 -1
- package/studio/web/assets/{toggleHighContrast-Cq_lt3XD.js → toggleHighContrast-BIn-vErT.js} +1 -1
- package/studio/web/assets/{tsMode-pjgytARx.js → tsMode-DgUXku4d.js} +1 -1
- package/studio/web/assets/{typescript-Cdg0mqUh.js → typescript-C9orXcsM.js} +1 -1
- package/studio/web/assets/{useEntityRestURL-RZhaY8Rn.js → useEntityRestURL-BEoXXbUB.js} +1 -1
- package/studio/web/assets/{workers-BgoXIqQe.js → workers-JVzSDmgx.js} +1 -1
- package/studio/web/assets/{xml-BwSeDMiP.js → xml-Cq-S8S4X.js} +1 -1
- package/studio/web/assets/{yaml-DotCUG5l.js → yaml-sfoRdh1M.js} +1 -1
- package/studio/web/index.html +1 -1
- package/upgrade/directives/5-3-0.ts +132 -0
- package/upgrade/directives/directivesController.ts +2 -1
- package/utility/OperationFunctionCaller.ts +2 -1
- package/utility/common_utils.ts +30 -5
- package/utility/componentNames.ts +12 -0
- package/utility/environment/environmentManager.ts +3 -7
- package/utility/environment/systemInformation.ts +7 -0
- package/utility/errors/commonErrors.ts +4 -0
- package/utility/errors/hdbError.ts +57 -0
- package/utility/hdbTerms.ts +19 -0
- package/utility/logging/harper_logger.ts +278 -26
- package/utility/logging/logGenerationCoordinator.ts +196 -0
- package/utility/logging/logRotation.ts +367 -0
- package/utility/logging/logRotator.ts +213 -81
- package/utility/nodeIdentity.ts +45 -0
- package/utility/npmUtilities.ts +12 -8
- package/utility/operationPermissions.ts +18 -1
- package/utility/operation_authorization.ts +231 -42
- package/utility/watchPath.ts +63 -0
- package/utility/watcherFallback.ts +148 -0
- package/validation/configValidator.ts +215 -75
- package/validation/installValidator.ts +15 -0
- package/validation/validationWrapper.ts +18 -4
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import { serializeMessage, getMessageSerializer } from './contentTypes.ts';
|
|
2
|
+
import { logger } from '../../utility/logging/logger.ts';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The encoding work that every subscriber of a topic would otherwise redo for the same message.
|
|
6
|
+
* `payload` is the serialized message body; `frames` holds fully encoded protocol frames that are
|
|
7
|
+
* byte-identical across subscribers (MQTT QoS 0 PUBLISH packets), keyed by whatever the frame
|
|
8
|
+
* still varies on. `next` chains the encodings for any further content types the same message was
|
|
9
|
+
* delivered in — a chain rather than a map because a topic's subscribers realistically negotiate
|
|
10
|
+
* one or two content types, and this keeps the single-content-type case to one allocation.
|
|
11
|
+
*
|
|
12
|
+
* `hits` counts the subscribers after the first, so a caller can skip caching anything derived
|
|
13
|
+
* from the payload until a fan-out is known to exist. `failed` is a distinct state from an
|
|
14
|
+
* undefined `payload`, which a serializer can legitimately return (JSON of `undefined`).
|
|
15
|
+
* `bytes` is everything this entry holds — payload plus frames — and `epoch` records which
|
|
16
|
+
* generation those bytes are charged to, so work that lands after a rotation (a serialization that
|
|
17
|
+
* resolves late) is not charged to a budget it does not belong to, and a promotion re-charges the
|
|
18
|
+
* entry exactly once. That is what makes the budget an actual accounting rather than an estimate.
|
|
19
|
+
*/
|
|
20
|
+
export interface SharedMessageEncoding {
|
|
21
|
+
serializer: Function;
|
|
22
|
+
version: number | undefined;
|
|
23
|
+
payload: Buffer | string | Promise<Buffer | string> | undefined;
|
|
24
|
+
failed: boolean;
|
|
25
|
+
hits: number;
|
|
26
|
+
bytes: number;
|
|
27
|
+
epoch: number;
|
|
28
|
+
frames: Map<number, Map<string, Buffer>> | undefined;
|
|
29
|
+
next: SharedMessageEncoding | undefined;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// A message that carries its own content type is passed through verbatim and never negotiated, so
|
|
33
|
+
// every subscriber shares one entry no matter what it negotiated. This sentinel stands in for the
|
|
34
|
+
// serializer that was deliberately not consulted.
|
|
35
|
+
const PASS_THROUGH = function passThrough() {};
|
|
36
|
+
|
|
37
|
+
// THE IDENTITY CONTRACT. A fan-out has a single shared origin: the same message object instance is
|
|
38
|
+
// dispatched to every subscription of a key (resources/transactionBroadcast.ts), so identity is
|
|
39
|
+
// what lets the first subscriber to encode do the work for all of them. This is only sound because
|
|
40
|
+
// every internal producer yields a *fresh object per version* — transactionBroadcast hands one
|
|
41
|
+
// auditRecord to every subscription, auditStore's getValue memoizes the decode in its closure, and
|
|
42
|
+
// primaryStore.getEntry is guarded by a version check — so identity implies equal content, and a
|
|
43
|
+
// miss (a primitive message, or a store cache eviction between subscribers) only costs the
|
|
44
|
+
// redundant encode we have today rather than yielding stale bytes.
|
|
45
|
+
//
|
|
46
|
+
// A custom Resource is not bound by that, so identity alone is not trusted: the event's record
|
|
47
|
+
// version is part of the key (see getSharedMessageEncoding), which makes reusing one envelope
|
|
48
|
+
// across publishes correct as long as the version advances, and refuses to share at all when there
|
|
49
|
+
// is no version to tell one publish from the next.
|
|
50
|
+
//
|
|
51
|
+
// Retention is bounded by rotating generations rather than by the message object's lifetime: for
|
|
52
|
+
// record events the message IS the store's cached record, so hanging encodings off it alone would
|
|
53
|
+
// keep serialized copies and whole PUBLISH buffers resident for as long as the record stays cached,
|
|
54
|
+
// while sharing is only ever needed for the duration of one fan-out. Two generations are kept so a
|
|
55
|
+
// fan-out spanning a rotation still hits; dropping a generation releases all of it at once.
|
|
56
|
+
const ROTATE_INTERVAL_MS = 10_000;
|
|
57
|
+
// Time alone bounds how LONG an entry is retained, not how MUCH: at high throughput on
|
|
58
|
+
// single-subscriber topics the interval's worth of payloads would all be live at once, for no
|
|
59
|
+
// benefit. The byte budget puts a ceiling on that, at the cost of a fan-out that spans an early
|
|
60
|
+
// rotation falling back to re-encoding — slower, never wrong. Note this is the ceiling for ONE
|
|
61
|
+
// generation; the previous generation can hold as much again, so steady-state retention is up to
|
|
62
|
+
// twice this per worker thread.
|
|
63
|
+
export const MAX_RETAINED_BYTES = 4_000_000;
|
|
64
|
+
let currentGeneration = new WeakMap<object, SharedMessageEncoding>();
|
|
65
|
+
let previousGeneration = new WeakMap<object, SharedMessageEncoding>();
|
|
66
|
+
// Rotation runs on a timer, not on a delivery counter: the bound has to hold when traffic stops,
|
|
67
|
+
// which is exactly when a delivery-gated check would never fire again. Insert counts only decide
|
|
68
|
+
// when the timer can stop — a WeakMap can not be asked whether it is empty.
|
|
69
|
+
let rotationTimer: ReturnType<typeof setInterval> | undefined;
|
|
70
|
+
let currentInserts = 0;
|
|
71
|
+
let currentBytes = 0;
|
|
72
|
+
// Identifies the generation an entry's bytes are charged to. Work can land after a rotation — a
|
|
73
|
+
// serialization that resolves late, a frame generated by a subscriber that arrived slowly — and
|
|
74
|
+
// charging that to the current budget would bill a generation the bytes do not belong to, then bill
|
|
75
|
+
// them again when a promotion re-charges the entry.
|
|
76
|
+
const UNRETAINED = -1;
|
|
77
|
+
// starts at 1 so UNRETAINED can never collide with `currentEpoch - 1`, which would make charge()
|
|
78
|
+
// treat a never-retained entry as one still live in the previous generation
|
|
79
|
+
let currentEpoch = 1;
|
|
80
|
+
|
|
81
|
+
/** Retire the older generation. Exported for the rotation timer and for tests. */
|
|
82
|
+
export function rotateSharedEncodings() {
|
|
83
|
+
previousGeneration = currentGeneration;
|
|
84
|
+
currentGeneration = new WeakMap();
|
|
85
|
+
currentEpoch++;
|
|
86
|
+
const rotatedInserts = currentInserts;
|
|
87
|
+
currentInserts = 0;
|
|
88
|
+
currentBytes = 0;
|
|
89
|
+
if (rotatedInserts === 0 && rotationTimer !== undefined) {
|
|
90
|
+
// nothing is retained in either generation, so stop ticking until the next insert
|
|
91
|
+
clearInterval(rotationTimer);
|
|
92
|
+
rotationTimer = undefined;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Whether the rotation timer is currently armed. Introspection for tests. */
|
|
97
|
+
export function isRotationScheduled(): boolean {
|
|
98
|
+
return rotationTimer !== undefined;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Bytes charged to the live generation. Introspection so tests can pin the accounting exactly. */
|
|
102
|
+
export function getRetainedBytes(): number {
|
|
103
|
+
return currentBytes;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function retainedSize(payload: SharedMessageEncoding['payload']): number {
|
|
107
|
+
// a pending promise is accounted for when it resolves
|
|
108
|
+
if (typeof payload === 'string') return Buffer.byteLength(payload);
|
|
109
|
+
return (payload as Buffer)?.byteLength ?? 0;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** Add to an entry's footprint, and to the budget if the entry is live. */
|
|
113
|
+
function charge(encoding: SharedMessageEncoding, bytes: number) {
|
|
114
|
+
encoding.bytes += bytes;
|
|
115
|
+
if (encoding.epoch === currentEpoch) currentBytes += bytes;
|
|
116
|
+
else if (encoding.epoch === currentEpoch - 1) {
|
|
117
|
+
// Bytes can land after a rotation — a serialization resolving late, or a frame generated by a
|
|
118
|
+
// subscriber whose await spanned one. The entry is still live in the previous generation, so
|
|
119
|
+
// fold its whole footprint into the live budget; charging only the new bytes would leave the
|
|
120
|
+
// rest counted by no generation at all, and charging nothing would under-report the ceiling.
|
|
121
|
+
encoding.epoch = currentEpoch;
|
|
122
|
+
currentBytes += encoding.bytes;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** Give back everything a chain holds, for an entry that is being discarded rather than refilled. */
|
|
127
|
+
function release(encoding: SharedMessageEncoding) {
|
|
128
|
+
for (let node = encoding; node !== undefined; node = node.next) {
|
|
129
|
+
if (node.epoch === currentEpoch) currentBytes -= node.bytes;
|
|
130
|
+
node.epoch = UNRETAINED;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function retain(message: object, encoding: SharedMessageEncoding) {
|
|
135
|
+
if (currentBytes >= MAX_RETAINED_BYTES) rotateSharedEncodings();
|
|
136
|
+
currentGeneration.set(message, encoding);
|
|
137
|
+
currentInserts++;
|
|
138
|
+
// charges the whole chain: on a promotion this re-charges everything the entry holds, since
|
|
139
|
+
// rotation zeroed the counter but the bytes are still live
|
|
140
|
+
for (let node = encoding; node !== undefined; node = node.next) {
|
|
141
|
+
if (node.epoch !== currentEpoch) {
|
|
142
|
+
node.epoch = currentEpoch;
|
|
143
|
+
currentBytes += node.bytes;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (rotationTimer === undefined) {
|
|
147
|
+
rotationTimer = setInterval(rotateSharedEncodings, ROTATE_INTERVAL_MS);
|
|
148
|
+
rotationTimer.unref?.();
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function fill(encoding: SharedMessageEncoding, message: any, request: any) {
|
|
153
|
+
// whatever this entry was holding is being replaced, so give the bytes back before re-charging
|
|
154
|
+
if (encoding.epoch === currentEpoch) currentBytes -= encoding.bytes;
|
|
155
|
+
encoding.bytes = 0;
|
|
156
|
+
encoding.frames = undefined;
|
|
157
|
+
// Pessimistic: an entry is only valid once a payload is actually in hand. Set optimistically,
|
|
158
|
+
// a synchronous throw here would leave an already-retained entry claiming success with no
|
|
159
|
+
// payload, and every later subscriber would send an empty PUBLISH instead of erroring.
|
|
160
|
+
encoding.failed = true;
|
|
161
|
+
encoding.payload = undefined;
|
|
162
|
+
const payload = serializeMessage(message, request);
|
|
163
|
+
encoding.payload = payload;
|
|
164
|
+
encoding.failed = false;
|
|
165
|
+
// A pass-through payload IS the message's own data, already reachable from the WeakMap key, so
|
|
166
|
+
// caching it retains nothing extra and must not be billed against the budget.
|
|
167
|
+
if (encoding.serializer === PASS_THROUGH) return;
|
|
168
|
+
if (typeof (payload as any)?.then === 'function')
|
|
169
|
+
// collapse an async serialization in place so later subscribers, and frame sharing, see the
|
|
170
|
+
// finished buffer rather than re-entering the async path
|
|
171
|
+
encoding.payload = (payload as Promise<Buffer | string>).then(
|
|
172
|
+
(resolved) => {
|
|
173
|
+
charge(encoding, retainedSize(resolved));
|
|
174
|
+
return (encoding.payload = resolved);
|
|
175
|
+
},
|
|
176
|
+
(error) => {
|
|
177
|
+
// mark for retry rather than memoize the failure: a shared rejected promise would turn
|
|
178
|
+
// one transient serialization error into a permanent one for every later subscriber
|
|
179
|
+
encoding.failed = true;
|
|
180
|
+
encoding.payload = undefined;
|
|
181
|
+
throw error;
|
|
182
|
+
}
|
|
183
|
+
);
|
|
184
|
+
else charge(encoding, retainedSize(payload));
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function encode(message: any, request: any, serializer: Function, version?: number): SharedMessageEncoding {
|
|
188
|
+
const encoding: SharedMessageEncoding = {
|
|
189
|
+
serializer,
|
|
190
|
+
version,
|
|
191
|
+
payload: undefined,
|
|
192
|
+
failed: false,
|
|
193
|
+
hits: 0,
|
|
194
|
+
bytes: 0,
|
|
195
|
+
epoch: UNRETAINED,
|
|
196
|
+
frames: undefined,
|
|
197
|
+
next: undefined,
|
|
198
|
+
};
|
|
199
|
+
fill(encoding, message, request);
|
|
200
|
+
return encoding;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function reuse(encoding: SharedMessageEncoding, message: any, request: any): SharedMessageEncoding {
|
|
204
|
+
encoding.hits++;
|
|
205
|
+
if (encoding.failed) fill(encoding, message, request);
|
|
206
|
+
return encoding;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Get the encoding shared by every subscriber that negotiated the same content type. Keyed on the
|
|
211
|
+
* message object's identity, the serializer function (which is what `serializeMessage` output
|
|
212
|
+
* varies on), and the event's record `version`.
|
|
213
|
+
*
|
|
214
|
+
* The version is part of the key, not a permission to share. Identity alone would be unsafe for a
|
|
215
|
+
* producer that reuses one mutable envelope across publishes — an app Resource wrapping a table
|
|
216
|
+
* subscription to enrich events can easily do that, and copies the version straight through with a
|
|
217
|
+
* spread — so a cached entry whose version does not match is treated as a miss and re-encoded.
|
|
218
|
+
* That leaves only same-object-and-same-version mutation, which is indistinguishable from "the same
|
|
219
|
+
* message". An event with no version at all is not shared: nothing then distinguishes one publish
|
|
220
|
+
* from the next.
|
|
221
|
+
*/
|
|
222
|
+
export function getSharedMessageEncoding(message: any, request?: any, version?: number): SharedMessageEncoding {
|
|
223
|
+
// Negotiation must not run for a pass-through message: an Accept header naming only unsupported
|
|
224
|
+
// types throws 406, which would kill a delivery that used to succeed by returning message.data.
|
|
225
|
+
const serializer =
|
|
226
|
+
message?.contentType != null && message.data != null ? PASS_THROUGH : getMessageSerializer(request);
|
|
227
|
+
// primitives can not key a WeakMap, and are cheap to encode anyway; these stay per-subscriber
|
|
228
|
+
if (message === null || typeof message !== 'object' || typeof version !== 'number')
|
|
229
|
+
return encode(message, request, serializer);
|
|
230
|
+
let encoding = currentGeneration.get(message);
|
|
231
|
+
if (encoding === undefined) {
|
|
232
|
+
encoding = previousGeneration.get(message);
|
|
233
|
+
// promote a surviving entry so it lives through the next rotation
|
|
234
|
+
if (encoding !== undefined && encoding.version === version) retain(message, encoding);
|
|
235
|
+
}
|
|
236
|
+
if (encoding !== undefined && encoding.version !== version) {
|
|
237
|
+
// the same object carrying a new version: every content type on the chain is stale, so give
|
|
238
|
+
// back what the whole chain held and start over rather than serving the earlier message
|
|
239
|
+
release(encoding);
|
|
240
|
+
encoding = undefined;
|
|
241
|
+
}
|
|
242
|
+
if (encoding === undefined) {
|
|
243
|
+
retain(message, (encoding = encode(message, request, serializer, version)));
|
|
244
|
+
return encoding;
|
|
245
|
+
}
|
|
246
|
+
let last: SharedMessageEncoding;
|
|
247
|
+
do {
|
|
248
|
+
if (encoding.serializer === serializer) return reuse(encoding, message, request);
|
|
249
|
+
last = encoding;
|
|
250
|
+
encoding = encoding.next;
|
|
251
|
+
} while (encoding !== undefined);
|
|
252
|
+
// a second content type on an already-retained message is retained with it, so it is charged too
|
|
253
|
+
const chained = encode(message, request, serializer, version);
|
|
254
|
+
chained.epoch = last.epoch;
|
|
255
|
+
if (chained.epoch === currentEpoch) currentBytes += chained.bytes;
|
|
256
|
+
return (last.next = chained);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Resolve a still-pending shared serialization, retrying once through a fresh lookup if it failed.
|
|
261
|
+
* Every subscriber currently in the fan-out awaits the same promise, so without this one transient
|
|
262
|
+
* failure would disconnect all of them, where before the encoding was shared each subscriber
|
|
263
|
+
* serialized — and so retried — on its own.
|
|
264
|
+
*/
|
|
265
|
+
export async function resolveSharedPayload(
|
|
266
|
+
encoding: SharedMessageEncoding,
|
|
267
|
+
message: any,
|
|
268
|
+
request: any,
|
|
269
|
+
version?: number
|
|
270
|
+
): Promise<Buffer | string> {
|
|
271
|
+
try {
|
|
272
|
+
return await (encoding.payload as Promise<Buffer | string>);
|
|
273
|
+
} catch (error) {
|
|
274
|
+
// otherwise a failure that the retry recovers from leaves no trace at all
|
|
275
|
+
logger.debug?.('Shared message serialization failed, retrying for this subscriber', error);
|
|
276
|
+
// The entry is marked for retry, or a peer in this same wave has already refilled it — either
|
|
277
|
+
// way, ask again. The first subscriber here re-encodes and the rest share that attempt; if it
|
|
278
|
+
// fails too, that rejection propagates and the caller handles it as it did before sharing.
|
|
279
|
+
return await getSharedMessageEncoding(message, request, version).payload;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Look up a fully encoded frame shared across subscribers, or undefined if it has not been
|
|
285
|
+
* generated yet. Split from `setSharedFrame` so a cache hit — the whole point on a fan-out —
|
|
286
|
+
* allocates nothing, not even a generator closure.
|
|
287
|
+
*/
|
|
288
|
+
export function getSharedFrame(encoding: SharedMessageEncoding, version: number, topic: string): Buffer | undefined {
|
|
289
|
+
return encoding.frames?.get(version)?.get(topic);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Store a generated frame for reuse by the remaining subscribers, and return it. Call only when
|
|
294
|
+
* `encoding.hits > 0`: a frame stored for a fan-out of one is never read, and would keep a whole
|
|
295
|
+
* PUBLISH buffer reachable from the message object for the rest of its retention window.
|
|
296
|
+
*/
|
|
297
|
+
export function setSharedFrame(encoding: SharedMessageEncoding, version: number, topic: string, frame: Buffer): Buffer {
|
|
298
|
+
let frames = encoding.frames;
|
|
299
|
+
if (frames === undefined) encoding.frames = frames = new Map();
|
|
300
|
+
let byTopic = frames.get(version);
|
|
301
|
+
if (byTopic === undefined) frames.set(version, (byTopic = new Map()));
|
|
302
|
+
// concurrent subscribers can each generate before any of them stores; only the retained buffer
|
|
303
|
+
// is charged, or the budget would bill every duplicate that is immediately garbage
|
|
304
|
+
if (!byTopic.has(topic)) charge(encoding, frame.byteLength);
|
|
305
|
+
byTopic.set(topic, frame);
|
|
306
|
+
return frame;
|
|
307
|
+
}
|
|
@@ -225,8 +225,23 @@ export async function createUwsServer(options: UwsServerOptions): Promise<{ app:
|
|
|
225
225
|
app.any('/*', withBody);
|
|
226
226
|
|
|
227
227
|
await new Promise<void>((resolve, reject) => {
|
|
228
|
-
|
|
229
|
-
|
|
228
|
+
let settled = false;
|
|
229
|
+
// Backstop against the native listen callback never firing at all — without it, a stuck
|
|
230
|
+
// bind is indistinguishable from a slow one, and nothing here ever rejects.
|
|
231
|
+
const bindTimeout = setTimeout(() => {
|
|
232
|
+
if (settled) return;
|
|
233
|
+
settled = true;
|
|
234
|
+
reject(
|
|
235
|
+
new Error(`uWS timed out waiting to bind ${host ?? ''}:${port ?? socketPath} (listen callback never fired)`)
|
|
236
|
+
);
|
|
237
|
+
}, 30_000);
|
|
238
|
+
const onListen = (listenSocket: unknown) => {
|
|
239
|
+
if (settled) return;
|
|
240
|
+
settled = true;
|
|
241
|
+
clearTimeout(bindTimeout);
|
|
242
|
+
if (listenSocket) resolve();
|
|
243
|
+
else reject(new Error(`uWS failed to bind ${host ?? ''}:${port ?? socketPath}`));
|
|
244
|
+
};
|
|
230
245
|
// uWS shares the port across workers (SO_REUSEPORT) by default, matching the Node reusePort path.
|
|
231
246
|
if (port != null) {
|
|
232
247
|
if (host) app.listen(host, port, onListen);
|
package/server/static.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { resolveBaseURLPath } from '../components/resolveBaseURLPath.ts';
|
|
|
5
5
|
import { convertToMS } from '../utility/common_utils.ts';
|
|
6
6
|
import { isMatch } from 'micromatch';
|
|
7
7
|
import send from 'send';
|
|
8
|
+
import { settleDeferredCredentialRejection } from '../security/deferredAuthentication.ts';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* The static plugin handles serving static files from the respective application directory.
|
|
@@ -337,40 +338,30 @@ export function handleApplication(scope: Scope) {
|
|
|
337
338
|
// Retrieve index entry
|
|
338
339
|
staticFile = indexEntries.get(req.pathname);
|
|
339
340
|
|
|
340
|
-
//
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
if (staticFile && req.pathname === '/' && externalBaseURLPath !== '/') {
|
|
350
|
-
const originalPathname: string | undefined = (req as any).originalPathname;
|
|
351
|
-
if (originalPathname && !originalPathname.endsWith('/')) {
|
|
352
|
-
const queryIndex = (req.url as string).indexOf('?');
|
|
353
|
-
const query = queryIndex === -1 ? '' : (req.url as string).slice(queryIndex);
|
|
354
|
-
return {
|
|
355
|
-
status: 301,
|
|
356
|
-
headers: {
|
|
357
|
-
Location: externalBaseURLPath + query,
|
|
358
|
-
},
|
|
359
|
-
};
|
|
360
|
-
}
|
|
361
|
-
}
|
|
341
|
+
// Prefix stripping makes `originalPathname` necessary to distinguish mounted roots (#1583).
|
|
342
|
+
const originalPathname: string | undefined = (req as any).originalPathname;
|
|
343
|
+
const redirectsMountRoot = !!(
|
|
344
|
+
staticFile &&
|
|
345
|
+
req.pathname === '/' &&
|
|
346
|
+
externalBaseURLPath !== '/' &&
|
|
347
|
+
originalPathname &&
|
|
348
|
+
!originalPathname.endsWith('/')
|
|
349
|
+
);
|
|
362
350
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
const externalPath =
|
|
367
|
-
externalBaseURLPath === '/' ? req.pathname : externalBaseURLPath.slice(0, -1) + req.pathname;
|
|
351
|
+
if (redirectsMountRoot || staticFile === null) {
|
|
352
|
+
const settledCredentialRejection = settleDeferredCredentialRejection(req);
|
|
353
|
+
if (settledCredentialRejection) return settledCredentialRejection;
|
|
368
354
|
const queryIndex = (req.url as string).indexOf('?');
|
|
369
355
|
const query = queryIndex === -1 ? '' : (req.url as string).slice(queryIndex);
|
|
356
|
+
const location = redirectsMountRoot
|
|
357
|
+
? externalBaseURLPath + query
|
|
358
|
+
: (externalBaseURLPath === '/' ? req.pathname : externalBaseURLPath.slice(0, -1) + req.pathname) +
|
|
359
|
+
'/' +
|
|
360
|
+
query;
|
|
370
361
|
return {
|
|
371
362
|
status: 301,
|
|
372
363
|
headers: {
|
|
373
|
-
Location:
|
|
364
|
+
Location: location,
|
|
374
365
|
},
|
|
375
366
|
};
|
|
376
367
|
}
|
|
@@ -393,6 +384,8 @@ export function handleApplication(scope: Scope) {
|
|
|
393
384
|
|
|
394
385
|
// If an entry matched, serve it
|
|
395
386
|
if (staticFile) {
|
|
387
|
+
const settledCredentialRejection = settleDeferredCredentialRejection(req);
|
|
388
|
+
if (settledCredentialRejection) return settledCredentialRejection;
|
|
396
389
|
// The benefit to using `send` is that it handles a lot of edge cases and headers for us.
|
|
397
390
|
return {
|
|
398
391
|
handlesHeaders: true,
|
|
@@ -405,7 +398,8 @@ export function handleApplication(scope: Scope) {
|
|
|
405
398
|
return next(req);
|
|
406
399
|
}
|
|
407
400
|
|
|
408
|
-
|
|
401
|
+
const settledCredentialRejection = settleDeferredCredentialRejection(req);
|
|
402
|
+
if (settledCredentialRejection) return settledCredentialRejection;
|
|
409
403
|
|
|
410
404
|
const notFound = scope.options.get(['notFound']);
|
|
411
405
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readFile, realpath } from 'node:fs/promises';
|
|
2
2
|
import { statfs } from 'node:fs/promises';
|
|
3
3
|
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
4
|
-
import {
|
|
4
|
+
import { ownsStoreMaintenance } from '../server/threads/manageThreads.js';
|
|
5
5
|
import { logger } from '../utility/logging/logger.ts';
|
|
6
6
|
import { CONFIG_PARAMS } from '../utility/hdbTerms.ts';
|
|
7
7
|
import * as envMgr from '../utility/environment/environmentManager.ts';
|
|
@@ -106,7 +106,7 @@ export function onStorageReclamation(
|
|
|
106
106
|
handler: (priority: number) => Promise<void> | void,
|
|
107
107
|
skipThreadCheck?: boolean
|
|
108
108
|
) {
|
|
109
|
-
if (skipThreadCheck ||
|
|
109
|
+
if (skipThreadCheck || ownsStoreMaintenance(path)) {
|
|
110
110
|
// only run on one thread (last one)
|
|
111
111
|
if (!path) {
|
|
112
112
|
throw new Error('Storage reclamation path cannot be empty');
|
|
@@ -128,6 +128,19 @@ export function onStorageReclamation(
|
|
|
128
128
|
export function removeStorageReclamation(path: string): boolean {
|
|
129
129
|
return reclamationHandlers.delete(path);
|
|
130
130
|
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Drop one handler; a RocksDB column family shares its path with every other family in the database.
|
|
134
|
+
* The list is replaced rather than spliced so a run iterating it across awaits skips nothing.
|
|
135
|
+
*/
|
|
136
|
+
export function removeStorageReclamationHandler(path: string, handler: (priority: number) => unknown): boolean {
|
|
137
|
+
const handlers = reclamationHandlers.get(path);
|
|
138
|
+
const remaining = handlers?.filter((entry) => entry.handler !== handler);
|
|
139
|
+
if (!remaining || remaining.length === handlers.length) return false;
|
|
140
|
+
if (remaining.length === 0) reclamationHandlers.delete(path);
|
|
141
|
+
else reclamationHandlers.set(path, remaining);
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
131
144
|
let reclamationTimer: NodeJS.Timeout;
|
|
132
145
|
|
|
133
146
|
export type StorageSpaceStats = {
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Isolated applications: an application whose root-config entry carries `isolated: true` runs in a
|
|
3
|
+
* worker thread of its own that loads no other application (harper#642, tier 2).
|
|
4
|
+
*
|
|
5
|
+
* The invariant every helper here serves: an isolated application is loaded by exactly one thread,
|
|
6
|
+
* and that thread loads nothing else. The dedicated worker is an ordinary `http` worker by type --
|
|
7
|
+
* so restarts, overlap rules and shutdown treat it as one -- distinguished only by
|
|
8
|
+
* `workerData.isolatedApplication`. It binds none of the public ports (the kernel would hand it
|
|
9
|
+
* connections for every other application) and is reachable only through its own UDS mirror, whose
|
|
10
|
+
* metadata names the application and its hosts for the fronting proxy to route by.
|
|
11
|
+
*/
|
|
12
|
+
import { isMainThread, workerData } from 'node:worker_threads';
|
|
13
|
+
import { getWorkerIndex } from './manageThreads.js';
|
|
14
|
+
import { getConfigObj, getConfigPath } from '../../config/configUtils.ts';
|
|
15
|
+
import * as env from '../../utility/environment/environmentManager.ts';
|
|
16
|
+
import { CONFIG_PARAMS } from '../../utility/hdbTerms.ts';
|
|
17
|
+
import { isDomainSocketPathTooLong } from '../../utility/domainSocket.ts';
|
|
18
|
+
import { existsSync } from 'node:fs';
|
|
19
|
+
import { basename, join } from 'node:path';
|
|
20
|
+
|
|
21
|
+
export const DEFAULT_MAX_ISOLATED_APPLICATIONS = 8;
|
|
22
|
+
|
|
23
|
+
/** The application this thread is dedicated to, if it is a dedicated worker. */
|
|
24
|
+
export function thisThreadsIsolatedApplication(): string | undefined {
|
|
25
|
+
return (workerData as any)?.isolatedApplication;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function thisThreadOwnsApplication(
|
|
29
|
+
appName: string | undefined,
|
|
30
|
+
owner: string | undefined = thisThreadsIsolatedApplication()
|
|
31
|
+
): boolean {
|
|
32
|
+
return owner !== undefined && appName === owner;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function isIsolatedApplication(
|
|
36
|
+
appName: string,
|
|
37
|
+
config: Record<string, any> | undefined = getConfigObj()
|
|
38
|
+
): boolean {
|
|
39
|
+
const entry = config?.[appName];
|
|
40
|
+
return typeof entry === 'object' && entry !== null && entry.isolated === true;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Every application the root config marks isolated, in config order. */
|
|
44
|
+
export function isolatedApplicationNames(config: Record<string, any> | undefined = getConfigObj()): string[] {
|
|
45
|
+
if (!config) return [];
|
|
46
|
+
return Object.keys(config).filter((name) => isIsolatedApplication(name, config));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function presentIsolatedApplicationNames(
|
|
50
|
+
config: Record<string, any> | undefined = getConfigObj(),
|
|
51
|
+
componentsRoot: string = getConfigPath(CONFIG_PARAMS.COMPONENTSROOT) as string,
|
|
52
|
+
installedRoot: string = join(env.get(CONFIG_PARAMS.ROOTPATH), 'components'),
|
|
53
|
+
runApplicationPath: string | undefined = process.env.RUN_HDB_APP
|
|
54
|
+
): string[] {
|
|
55
|
+
return isolatedApplicationNames(config).filter(
|
|
56
|
+
(application) =>
|
|
57
|
+
existsSync(join(componentsRoot, application)) ||
|
|
58
|
+
existsSync(join(installedRoot, application)) ||
|
|
59
|
+
(runApplicationPath && basename(runApplicationPath) === application)
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function maxIsolatedApplications(): number {
|
|
64
|
+
const configured = Number(env.get(CONFIG_PARAMS.THREADS_MAXISOLATED));
|
|
65
|
+
return Number.isInteger(configured) && configured >= 0 ? configured : DEFAULT_MAX_ISOLATED_APPLICATIONS;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Why `appName` cannot claim a place in the dedicated-worker budget, if the budget is full. */
|
|
69
|
+
export function isolatedApplicationCapacityRefusal(
|
|
70
|
+
appName: string,
|
|
71
|
+
runningApplications: Iterable<string>,
|
|
72
|
+
max = maxIsolatedApplications()
|
|
73
|
+
): string | undefined {
|
|
74
|
+
const running = new Set(runningApplications);
|
|
75
|
+
if (running.has(appName) || running.size < max) return undefined;
|
|
76
|
+
return `the instance already runs ${max} isolated application(s) (threads.maxIsolated)`;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Whether the calling thread is the one that loads the application `appName` (an application: a
|
|
81
|
+
* directory under componentsRoot, or a root-config entry with `package`). A dedicated worker loads
|
|
82
|
+
* only its own application; every other thread -- pool workers and the main thread alike -- loads only
|
|
83
|
+
* the applications that are not isolated. Decided before any of the application's modules are
|
|
84
|
+
* imported, so a skipped application has no side effects on the thread that skipped it.
|
|
85
|
+
*/
|
|
86
|
+
export function shouldLoadApplicationHere(
|
|
87
|
+
appName: string,
|
|
88
|
+
owner: string | undefined = thisThreadsIsolatedApplication(),
|
|
89
|
+
config: Record<string, any> | undefined = getConfigObj()
|
|
90
|
+
): boolean {
|
|
91
|
+
if (owner !== undefined) return appName === owner;
|
|
92
|
+
return !isIsolatedApplication(appName, config);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Whether this thread starts the uWS listener for one `uwsServeConfigs` entry (see listenOnPorts()).
|
|
97
|
+
* A dedicated worker starts only its own per-application UDS mirrors -- the entries that carry a
|
|
98
|
+
* `socketPath` -- and never a global port listener, which the kernel would hand connections for every
|
|
99
|
+
* other application.
|
|
100
|
+
*/
|
|
101
|
+
export function shouldStartUwsListenerHere(
|
|
102
|
+
serveConfig: { socketPath?: string },
|
|
103
|
+
owner: string | undefined = thisThreadsIsolatedApplication()
|
|
104
|
+
): boolean {
|
|
105
|
+
return owner === undefined || Boolean(serveConfig.socketPath);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Whether a dedicated worker can be reached at all: it binds only UDS mirrors of the secure port, so
|
|
110
|
+
* without `tls.unixDomainSockets` and a secure port an isolated application would load and answer
|
|
111
|
+
* nothing, silently. Refused at admission instead. Returns the reason, or undefined when reachable.
|
|
112
|
+
*/
|
|
113
|
+
export function isolatedApplicationsUnreachableReason(platform = process.platform): string | undefined {
|
|
114
|
+
if (platform === 'win32') return 'Windows does not support per-application UDS mirrors';
|
|
115
|
+
// the main thread standing in as the only worker (threads.count: 0) has no thread to give
|
|
116
|
+
if (isMainThread && getWorkerIndex() === 0) return 'threads.count is 0, so there is no worker thread to dedicate';
|
|
117
|
+
if (!env.get(CONFIG_PARAMS.HTTP_SECUREPORT)) return 'no http.securePort is configured';
|
|
118
|
+
if (!env.get(CONFIG_PARAMS.TLS_UNIXDOMAINSOCKETS)) return 'tls.unixDomainSockets is not enabled';
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Why `appName` cannot get a dedicated worker on this instance, or undefined when it can. */
|
|
123
|
+
export function isolatedApplicationRefusal(appName: string): string | undefined {
|
|
124
|
+
const unreachable = isolatedApplicationsUnreachableReason();
|
|
125
|
+
if (unreachable) return `its worker would be unreachable: ${unreachable}`;
|
|
126
|
+
const socketPath = join(
|
|
127
|
+
env.getHdbBasePath(),
|
|
128
|
+
'sockets',
|
|
129
|
+
`${applicationSocketName(appName, env.get(CONFIG_PARAMS.HTTP_SECUREPORT))}.sock`
|
|
130
|
+
);
|
|
131
|
+
if (isDomainSocketPathTooLong(socketPath)) return `its UDS mirror path ${socketPath} exceeds the platform limit`;
|
|
132
|
+
return undefined;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* The filesystem name of an isolated worker's UDS mirror for `port`: every UTF-8 byte outside
|
|
137
|
+
* `[A-Za-z0-9._]` becomes a fixed-width `%XX`, which is injective (two application names never share
|
|
138
|
+
* a socket), and the `app-` prefix keeps it apart from the pool's `<workerIndex>-<port>` names.
|
|
139
|
+
*/
|
|
140
|
+
export function applicationSocketName(appName: string, port: number | string): string {
|
|
141
|
+
let encoded = '';
|
|
142
|
+
for (const byte of Buffer.from(appName, 'utf8')) {
|
|
143
|
+
const c = String.fromCharCode(byte);
|
|
144
|
+
encoded += byte < 0x80 && /[A-Za-z0-9._]/.test(c) ? c : `%${byte.toString(16).toUpperCase().padStart(2, '0')}`;
|
|
145
|
+
}
|
|
146
|
+
return `app-${encoded}-${port}`;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** What a dedicated worker publishes in its mirror metadata for the proxy to route by. */
|
|
150
|
+
export function isolatedApplicationRoute(
|
|
151
|
+
appName: string | undefined = thisThreadsIsolatedApplication(),
|
|
152
|
+
config: Record<string, any> | undefined = getConfigObj()
|
|
153
|
+
): { application: string; hosts: string[] } | undefined {
|
|
154
|
+
if (!appName) return undefined;
|
|
155
|
+
const host = config?.[appName]?.host; // a string, as the mount parser requires
|
|
156
|
+
return { application: appName, hosts: typeof host === 'string' && host ? [host] : [] };
|
|
157
|
+
}
|
package/server/threads/itc.js
CHANGED
|
@@ -72,14 +72,24 @@ function validateEvent(event) {
|
|
|
72
72
|
* @param schema
|
|
73
73
|
* @param table
|
|
74
74
|
* @param attribute
|
|
75
|
+
* @param branchPath the branch directory when the change is to a scope-private branch of `schema`
|
|
76
|
+
* rather than to the database itself (resources/databases.ts `reloadBranchAt`)
|
|
75
77
|
* @constructor
|
|
76
78
|
*/
|
|
77
|
-
function SchemaEventMsg(
|
|
79
|
+
function SchemaEventMsg(
|
|
80
|
+
originator,
|
|
81
|
+
operation,
|
|
82
|
+
schema,
|
|
83
|
+
table = undefined,
|
|
84
|
+
attribute = undefined,
|
|
85
|
+
branchPath = undefined
|
|
86
|
+
) {
|
|
78
87
|
this.originator = originator;
|
|
79
88
|
this.operation = operation;
|
|
80
89
|
this.schema = schema;
|
|
81
90
|
this.table = table;
|
|
82
91
|
this.attribute = attribute;
|
|
92
|
+
if (branchPath) this.branchPath = branchPath;
|
|
83
93
|
}
|
|
84
94
|
|
|
85
95
|
/**
|