@harperfast/harper 5.2.10 → 5.3.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent/mcpTools.ts +1 -1
- package/agent/session.ts +25 -14
- package/bin/cliOperations.ts +46 -9
- package/bin/copyDb.ts +282 -59
- package/bin/deploySetup.ts +16 -5
- package/bin/harper.ts +1 -1
- package/bin/help.ts +4 -1
- package/bin/lite.ts +4 -1
- package/bin/restart.ts +59 -3
- package/bin/run.ts +6 -11
- package/bin/upgrade.js +7 -3
- package/bin/workloadIdentity.ts +119 -0
- package/components/Application.ts +2414 -242
- package/components/ApplicationScope.ts +8 -0
- package/components/EntryHandler.ts +59 -39
- package/components/OptionsWatcher.ts +150 -74
- package/components/RuntimeModuleTracker.ts +38 -7
- package/components/Scope.ts +37 -15
- package/components/awaitRestart.ts +84 -0
- package/components/componentLoader.ts +340 -30
- package/components/componentPreparationLock.ts +16 -5
- package/components/mcp/adapters/harperHttp.ts +4 -0
- package/components/mcp/listChanged.ts +4 -0
- package/components/mcp/toolRegistry.ts +2 -0
- package/components/mcp/tools/operations.ts +9 -0
- package/components/mcp/tools/schemas/operationDescriptions.ts +2 -2
- package/components/operations.js +270 -78
- package/components/operationsValidation.js +49 -1
- package/components/status/ComponentStatusRegistry.ts +59 -0
- package/config/RootConfigWatcher.ts +80 -34
- package/config/configUtils.ts +291 -34
- package/config/harperConfigEnvVars.ts +170 -27
- package/config-root.schema.json +29 -0
- package/dataLayer/blobBackup.ts +160 -50
- package/dataLayer/delete.ts +6 -1
- package/dataLayer/harperBridge/ResourceBridge.ts +52 -8
- package/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.js +3 -1
- package/dataLayer/hdbInfoController.ts +34 -1
- package/dataLayer/insert.ts +44 -1
- package/dataLayer/rocksdbBackup.ts +53 -10
- package/dataLayer/schema.ts +11 -1
- package/dataLayer/schemaDescribe.ts +8 -1
- package/dist/agent/mcpTools.js +1 -1
- package/dist/agent/mcpTools.js.map +1 -1
- package/dist/agent/session.d.ts +22 -0
- package/dist/agent/session.js +26 -15
- package/dist/agent/session.js.map +1 -1
- package/dist/bin/cliOperations.js +48 -9
- package/dist/bin/cliOperations.js.map +1 -1
- package/dist/bin/copyDb.d.ts +12 -1
- package/dist/bin/copyDb.js +248 -60
- package/dist/bin/copyDb.js.map +1 -1
- package/dist/bin/deploySetup.d.ts +2 -0
- package/dist/bin/deploySetup.js +11 -3
- package/dist/bin/deploySetup.js.map +1 -1
- package/dist/bin/harper.js +1 -1
- package/dist/bin/harper.js.map +1 -1
- package/dist/bin/help.js +4 -1
- package/dist/bin/help.js.map +1 -1
- package/dist/bin/lite.js +4 -1
- package/dist/bin/lite.js.map +1 -1
- package/dist/bin/restart.js +54 -5
- package/dist/bin/restart.js.map +1 -1
- package/dist/bin/run.js +4 -10
- package/dist/bin/run.js.map +1 -1
- package/dist/bin/upgrade.js +4 -3
- package/dist/bin/upgrade.js.map +1 -1
- package/dist/bin/workloadIdentity.d.ts +18 -0
- package/dist/bin/workloadIdentity.js +100 -0
- package/dist/bin/workloadIdentity.js.map +1 -0
- package/dist/components/Application.d.ts +139 -16
- package/dist/components/Application.js +2215 -267
- package/dist/components/Application.js.map +1 -1
- package/dist/components/ApplicationScope.d.ts +8 -0
- package/dist/components/ApplicationScope.js +7 -0
- package/dist/components/ApplicationScope.js.map +1 -1
- package/dist/components/EntryHandler.js +26 -10
- package/dist/components/EntryHandler.js.map +1 -1
- package/dist/components/OptionsWatcher.d.ts +1 -0
- package/dist/components/OptionsWatcher.js +141 -74
- package/dist/components/OptionsWatcher.js.map +1 -1
- package/dist/components/RuntimeModuleTracker.js +40 -6
- package/dist/components/RuntimeModuleTracker.js.map +1 -1
- package/dist/components/Scope.js +38 -13
- package/dist/components/Scope.js.map +1 -1
- package/dist/components/awaitRestart.d.ts +33 -0
- package/dist/components/awaitRestart.js +61 -0
- package/dist/components/awaitRestart.js.map +1 -0
- package/dist/components/componentLoader.d.ts +38 -1
- package/dist/components/componentLoader.js +279 -22
- package/dist/components/componentLoader.js.map +1 -1
- package/dist/components/componentPreparationLock.d.ts +5 -0
- package/dist/components/componentPreparationLock.js +14 -6
- package/dist/components/componentPreparationLock.js.map +1 -1
- package/dist/components/mcp/adapters/harperHttp.js +4 -0
- package/dist/components/mcp/adapters/harperHttp.js.map +1 -1
- package/dist/components/mcp/listChanged.js +5 -0
- package/dist/components/mcp/listChanged.js.map +1 -1
- package/dist/components/mcp/toolRegistry.d.ts +1 -0
- package/dist/components/mcp/toolRegistry.js.map +1 -1
- package/dist/components/mcp/tools/operations.d.ts +5 -0
- package/dist/components/mcp/tools/operations.js +9 -0
- package/dist/components/mcp/tools/operations.js.map +1 -1
- package/dist/components/mcp/tools/schemas/operationDescriptions.js +2 -2
- package/dist/components/mcp/tools/schemas/operationDescriptions.js.map +1 -1
- package/dist/components/operations.js +231 -77
- package/dist/components/operations.js.map +1 -1
- package/dist/components/operationsValidation.js +49 -1
- package/dist/components/operationsValidation.js.map +1 -1
- package/dist/components/status/ComponentStatusRegistry.d.ts +0 -4
- package/dist/components/status/ComponentStatusRegistry.js +63 -0
- package/dist/components/status/ComponentStatusRegistry.js.map +1 -1
- package/dist/config/RootConfigWatcher.d.ts +7 -1
- package/dist/config/RootConfigWatcher.js +64 -27
- package/dist/config/RootConfigWatcher.js.map +1 -1
- package/dist/config/configUtils.d.ts +9 -1
- package/dist/config/configUtils.js +254 -33
- package/dist/config/configUtils.js.map +1 -1
- package/dist/config/harperConfigEnvVars.d.ts +16 -0
- package/dist/config/harperConfigEnvVars.js +162 -25
- package/dist/config/harperConfigEnvVars.js.map +1 -1
- package/dist/dataLayer/blobBackup.d.ts +49 -20
- package/dist/dataLayer/blobBackup.js +139 -50
- package/dist/dataLayer/blobBackup.js.map +1 -1
- package/dist/dataLayer/delete.js +1 -1
- package/dist/dataLayer/delete.js.map +1 -1
- package/dist/dataLayer/harperBridge/ResourceBridge.d.ts +14 -1
- package/dist/dataLayer/harperBridge/ResourceBridge.js +51 -10
- package/dist/dataLayer/harperBridge/ResourceBridge.js.map +1 -1
- package/dist/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.d.ts +3 -1
- package/dist/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.js +3 -1
- package/dist/dataLayer/harperBridge/lmdbBridge/lmdbMethods/DeleteAuditLogsBeforeResults.js.map +1 -1
- package/dist/dataLayer/hdbInfoController.d.ts +10 -0
- package/dist/dataLayer/hdbInfoController.js +30 -1
- package/dist/dataLayer/hdbInfoController.js.map +1 -1
- package/dist/dataLayer/insert.d.ts +9 -1
- package/dist/dataLayer/insert.js +30 -0
- package/dist/dataLayer/insert.js.map +1 -1
- package/dist/dataLayer/rocksdbBackup.d.ts +2 -2
- package/dist/dataLayer/rocksdbBackup.js +45 -8
- package/dist/dataLayer/rocksdbBackup.js.map +1 -1
- package/dist/dataLayer/schema.js +8 -0
- package/dist/dataLayer/schema.js.map +1 -1
- package/dist/dataLayer/schemaDescribe.js +8 -1
- package/dist/dataLayer/schemaDescribe.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js.map +1 -1
- package/dist/json/systemSchema.json +52 -0
- package/dist/resources/DatabaseTransaction.d.ts +55 -3
- package/dist/resources/DatabaseTransaction.js +460 -134
- package/dist/resources/DatabaseTransaction.js.map +1 -1
- package/dist/resources/LMDBTransaction.js +22 -4
- package/dist/resources/LMDBTransaction.js.map +1 -1
- package/dist/resources/PrimaryRocksDatabase.d.ts +1 -0
- package/dist/resources/PrimaryRocksDatabase.js +30 -2
- package/dist/resources/PrimaryRocksDatabase.js.map +1 -1
- package/dist/resources/RecordEncoder.d.ts +20 -0
- package/dist/resources/RecordEncoder.js +94 -9
- package/dist/resources/RecordEncoder.js.map +1 -1
- package/dist/resources/RequestTarget.d.ts +2 -0
- package/dist/resources/RequestTarget.js.map +1 -1
- package/dist/resources/Resource.js +20 -11
- package/dist/resources/Resource.js.map +1 -1
- package/dist/resources/ResourceInterface.d.ts +20 -1
- package/dist/resources/ResourceInterface.js.map +1 -1
- package/dist/resources/RocksIndexStore.d.ts +6 -1
- package/dist/resources/RocksIndexStore.js +24 -10
- package/dist/resources/RocksIndexStore.js.map +1 -1
- package/dist/resources/RocksTransactionLogStore.d.ts +14 -1
- package/dist/resources/RocksTransactionLogStore.js +57 -17
- package/dist/resources/RocksTransactionLogStore.js.map +1 -1
- package/dist/resources/Table.d.ts +112 -8
- package/dist/resources/Table.js +1071 -197
- package/dist/resources/Table.js.map +1 -1
- package/dist/resources/auditStore.d.ts +11 -2
- package/dist/resources/auditStore.js +183 -18
- package/dist/resources/auditStore.js.map +1 -1
- package/dist/resources/blob.d.ts +129 -9
- package/dist/resources/blob.js +992 -114
- package/dist/resources/blob.js.map +1 -1
- package/dist/resources/branchDatabase.d.ts +48 -0
- package/dist/resources/branchDatabase.js +892 -0
- package/dist/resources/branchDatabase.js.map +1 -0
- package/dist/resources/crdt.js +50 -12
- package/dist/resources/crdt.js.map +1 -1
- package/dist/resources/databases.d.ts +150 -9
- package/dist/resources/databases.js +1247 -525
- package/dist/resources/databases.js.map +1 -1
- package/dist/resources/defineTable.d.ts +10 -2
- package/dist/resources/defineTable.js +9 -1
- package/dist/resources/defineTable.js.map +1 -1
- package/dist/resources/graphql.d.ts +1 -1
- package/dist/resources/graphql.js +50 -15
- package/dist/resources/graphql.js.map +1 -1
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.d.ts +1 -0
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js +6 -2
- package/dist/resources/indexes/HierarchicalNavigableSmallWorld.js.map +1 -1
- package/dist/resources/longLivedTransactions.d.ts +71 -0
- package/dist/resources/longLivedTransactions.js +358 -0
- package/dist/resources/longLivedTransactions.js.map +1 -0
- package/dist/resources/models/backendRegistry.d.ts +26 -0
- package/dist/resources/models/backendRegistry.js +60 -2
- package/dist/resources/models/backendRegistry.js.map +1 -1
- package/dist/resources/models/bootstrap.d.ts +33 -1
- package/dist/resources/models/bootstrap.js +416 -31
- package/dist/resources/models/bootstrap.js.map +1 -1
- package/dist/resources/recordLock.d.ts +80 -0
- package/dist/resources/recordLock.js +184 -0
- package/dist/resources/recordLock.js.map +1 -0
- package/dist/resources/replayLogs.d.ts +14 -1
- package/dist/resources/replayLogs.js +152 -24
- package/dist/resources/replayLogs.js.map +1 -1
- package/dist/resources/replayLogsGuards.d.ts +94 -7
- package/dist/resources/replayLogsGuards.js +111 -7
- package/dist/resources/replayLogsGuards.js.map +1 -1
- package/dist/resources/search.js +158 -32
- package/dist/resources/search.js.map +1 -1
- package/dist/resources/transactionBroadcast.d.ts +1 -1
- package/dist/resources/transactionBroadcast.js +2 -2
- package/dist/resources/transactionBroadcast.js.map +1 -1
- package/dist/security/auth.js +61 -30
- package/dist/security/auth.js.map +1 -1
- package/dist/security/authn/oidc/claims.d.ts +22 -0
- package/dist/security/authn/oidc/claims.js +71 -0
- package/dist/security/authn/oidc/claims.js.map +1 -0
- package/dist/security/authn/oidc/identityToken.d.ts +27 -0
- package/dist/security/authn/oidc/identityToken.js +111 -0
- package/dist/security/authn/oidc/identityToken.js.map +1 -0
- package/dist/security/authn/oidc/jwks.d.ts +25 -0
- package/dist/security/authn/oidc/jwks.js +261 -0
- package/dist/security/authn/oidc/jwks.js.map +1 -0
- package/dist/security/authn/oidc/providers/generic.d.ts +13 -0
- package/dist/security/authn/oidc/providers/generic.js +34 -0
- package/dist/security/authn/oidc/providers/generic.js.map +1 -0
- package/dist/security/authn/oidc/providers/githubActions.d.ts +11 -0
- package/dist/security/authn/oidc/providers/githubActions.js +129 -0
- package/dist/security/authn/oidc/providers/githubActions.js.map +1 -0
- package/dist/security/authn/oidc/providers/index.d.ts +37 -0
- package/dist/security/authn/oidc/providers/index.js +24 -0
- package/dist/security/authn/oidc/providers/index.js.map +1 -0
- package/dist/security/authn/oidc/tokenExchange.d.ts +12 -0
- package/dist/security/authn/oidc/tokenExchange.js +306 -0
- package/dist/security/authn/oidc/tokenExchange.js.map +1 -0
- package/dist/security/authn/oidc/trustPolicyOperations.d.ts +49 -0
- package/dist/security/authn/oidc/trustPolicyOperations.js +358 -0
- package/dist/security/authn/oidc/trustPolicyOperations.js.map +1 -0
- package/dist/security/authn/oidc/types.d.ts +38 -0
- package/dist/security/authn/oidc/types.js +6 -0
- package/dist/security/authn/oidc/types.js.map +1 -0
- package/dist/security/certificateVerification/index.js +40 -11
- package/dist/security/certificateVerification/index.js.map +1 -1
- package/dist/security/certificateVerification/trustedIssuers.d.ts +24 -0
- package/dist/security/certificateVerification/trustedIssuers.js +79 -0
- package/dist/security/certificateVerification/trustedIssuers.js.map +1 -0
- package/dist/security/certificateVerification/types.d.ts +1 -0
- package/dist/security/credentialProvenance.d.ts +35 -0
- package/dist/security/credentialProvenance.js +51 -0
- package/dist/security/credentialProvenance.js.map +1 -0
- package/dist/security/credentialRejection.d.ts +4 -0
- package/dist/security/credentialRejection.js +24 -0
- package/dist/security/credentialRejection.js.map +1 -0
- package/dist/security/deferredAuthentication.d.ts +36 -0
- package/dist/security/deferredAuthentication.js +70 -0
- package/dist/security/deferredAuthentication.js.map +1 -0
- package/dist/security/impersonation.d.ts +21 -0
- package/dist/security/impersonation.js +108 -9
- package/dist/security/impersonation.js.map +1 -1
- package/dist/security/jsLoader.d.ts +6 -0
- package/dist/security/jsLoader.js +75 -15
- package/dist/security/jsLoader.js.map +1 -1
- package/dist/security/keys.js +301 -71
- package/dist/security/keys.js.map +1 -1
- package/dist/security/operationScope.d.ts +21 -0
- package/dist/security/operationScope.js +36 -0
- package/dist/security/operationScope.js.map +1 -0
- package/dist/security/permissionsTranslator.js +21 -0
- package/dist/security/permissionsTranslator.js.map +1 -1
- package/dist/security/tokenAuthentication.d.ts +19 -1
- package/dist/security/tokenAuthentication.js +191 -10
- package/dist/security/tokenAuthentication.js.map +1 -1
- package/dist/security/user.js +4 -3
- package/dist/security/user.js.map +1 -1
- package/dist/server/DurableSubscriptionsSession.d.ts +2 -2
- package/dist/server/DurableSubscriptionsSession.js +67 -10
- package/dist/server/DurableSubscriptionsSession.js.map +1 -1
- package/dist/server/REST.js +73 -0
- package/dist/server/REST.js.map +1 -1
- package/dist/server/graphqlQuerying.js +4 -0
- package/dist/server/graphqlQuerying.js.map +1 -1
- package/dist/server/http.d.ts +11 -0
- package/dist/server/http.js +88 -15
- package/dist/server/http.js.map +1 -1
- package/dist/server/itc/serverHandlers.js +8 -1
- package/dist/server/itc/serverHandlers.js.map +1 -1
- package/dist/server/jobs/jobProcess.js +6 -2
- package/dist/server/jobs/jobProcess.js.map +1 -1
- package/dist/server/jobs/jobs.js +4 -1
- package/dist/server/jobs/jobs.js.map +1 -1
- package/dist/server/liveSubscriptionAuth.d.ts +26 -4
- package/dist/server/liveSubscriptionAuth.js +105 -39
- package/dist/server/liveSubscriptionAuth.js.map +1 -1
- package/dist/server/loadRootComponents.js +49 -10
- package/dist/server/loadRootComponents.js.map +1 -1
- package/dist/server/mqtt.d.ts +2 -0
- package/dist/server/mqtt.js +165 -30
- package/dist/server/mqtt.js.map +1 -1
- package/dist/server/nodeName.d.ts +2 -0
- package/dist/server/nodeName.js +107 -23
- package/dist/server/nodeName.js.map +1 -1
- package/dist/server/serverHelpers/Headers.d.ts +25 -0
- package/dist/server/serverHelpers/Headers.js +139 -1
- package/dist/server/serverHelpers/Headers.js.map +1 -1
- package/dist/server/serverHelpers/contentTypes.d.ts +9 -0
- package/dist/server/serverHelpers/contentTypes.js +32 -25
- package/dist/server/serverHelpers/contentTypes.js.map +1 -1
- package/dist/server/serverHelpers/deployValidationState.d.ts +3 -0
- package/dist/server/serverHelpers/deployValidationState.js +9 -19
- package/dist/server/serverHelpers/deployValidationState.js.map +1 -1
- package/dist/server/serverHelpers/operationAuthorizationState.d.ts +12 -0
- package/dist/server/serverHelpers/operationAuthorizationState.js +24 -2
- package/dist/server/serverHelpers/operationAuthorizationState.js.map +1 -1
- package/dist/server/serverHelpers/registeredOperations.d.ts +5 -4
- package/dist/server/serverHelpers/registeredOperations.js +74 -21
- package/dist/server/serverHelpers/registeredOperations.js.map +1 -1
- package/dist/server/serverHelpers/requestSanitization.d.ts +11 -0
- package/dist/server/serverHelpers/requestSanitization.js +20 -0
- package/dist/server/serverHelpers/requestSanitization.js.map +1 -0
- package/dist/server/serverHelpers/serverHandlers.js +6 -3
- package/dist/server/serverHelpers/serverHandlers.js.map +1 -1
- package/dist/server/serverHelpers/serverUtilities.d.ts +18 -0
- package/dist/server/serverHelpers/serverUtilities.js +90 -20
- package/dist/server/serverHelpers/serverUtilities.js.map +1 -1
- package/dist/server/serverHelpers/sharedMessageEncoding.d.ts +67 -0
- package/dist/server/serverHelpers/sharedMessageEncoding.js +280 -0
- package/dist/server/serverHelpers/sharedMessageEncoding.js.map +1 -0
- package/dist/server/serverHelpers/uwsServer.js +19 -1
- package/dist/server/serverHelpers/uwsServer.js.map +1 -1
- package/dist/server/static.js +24 -28
- package/dist/server/static.js.map +1 -1
- package/dist/server/storageReclamation.d.ts +5 -0
- package/dist/server/storageReclamation.js +16 -0
- package/dist/server/storageReclamation.js.map +1 -1
- package/dist/server/threads/itc.d.ts +7 -2
- package/dist/server/threads/itc.js +5 -1
- package/dist/server/threads/itc.js.map +1 -1
- package/dist/server/threads/manageThreads.d.ts +26 -4
- package/dist/server/threads/manageThreads.js +517 -72
- package/dist/server/threads/manageThreads.js.map +1 -1
- package/dist/server/threads/socketRouter.js +89 -26
- package/dist/server/threads/socketRouter.js.map +1 -1
- package/dist/server/threads/threadHeapMemory.d.ts +2 -0
- package/dist/server/threads/threadHeapMemory.js +31 -0
- package/dist/server/threads/threadHeapMemory.js.map +1 -0
- package/dist/server/threads/threadServer.js +46 -15
- package/dist/server/threads/threadServer.js.map +1 -1
- package/dist/sqlEngine/config.d.ts +1 -3
- package/dist/sqlEngine/config.js +19 -16
- package/dist/sqlEngine/config.js.map +1 -1
- package/dist/sqlTranslator/index.d.ts +1 -1
- package/dist/sqlTranslator/index.js +30 -7
- package/dist/sqlTranslator/index.js.map +1 -1
- package/dist/upgrade/directives/5-3-0.d.ts +7 -0
- package/dist/upgrade/directives/5-3-0.js +148 -0
- package/dist/upgrade/directives/5-3-0.js.map +1 -0
- package/dist/upgrade/directives/directivesController.js +2 -1
- package/dist/upgrade/directives/directivesController.js.map +1 -1
- package/dist/utility/OperationFunctionCaller.js +2 -1
- package/dist/utility/OperationFunctionCaller.js.map +1 -1
- package/dist/utility/common_utils.d.ts +16 -0
- package/dist/utility/common_utils.js +32 -6
- package/dist/utility/common_utils.js.map +1 -1
- package/dist/utility/componentNames.d.ts +8 -0
- package/dist/utility/componentNames.js +12 -1
- package/dist/utility/componentNames.js.map +1 -1
- package/dist/utility/environment/environmentManager.js +3 -6
- package/dist/utility/environment/environmentManager.js.map +1 -1
- package/dist/utility/environment/systemInformation.d.ts +1 -0
- package/dist/utility/environment/systemInformation.js +1 -0
- package/dist/utility/environment/systemInformation.js.map +1 -1
- package/dist/utility/errors/commonErrors.d.ts +2 -0
- package/dist/utility/errors/commonErrors.js +2 -0
- package/dist/utility/errors/commonErrors.js.map +1 -1
- package/dist/utility/errors/hdbError.d.ts +17 -0
- package/dist/utility/errors/hdbError.js +30 -1
- package/dist/utility/errors/hdbError.js.map +1 -1
- package/dist/utility/globalSchema.d.ts +18 -0
- package/dist/utility/hdbTerms.d.ts +16 -0
- package/dist/utility/hdbTerms.js +18 -2
- package/dist/utility/hdbTerms.js.map +1 -1
- package/dist/utility/logging/harper_logger.d.ts +2 -0
- package/dist/utility/logging/harper_logger.js +91 -14
- package/dist/utility/logging/harper_logger.js.map +1 -1
- package/dist/utility/logging/logRotator.js +76 -49
- package/dist/utility/logging/logRotator.js.map +1 -1
- package/dist/utility/nodeIdentity.d.ts +9 -0
- package/dist/utility/nodeIdentity.js +58 -0
- package/dist/utility/nodeIdentity.js.map +1 -0
- package/dist/utility/npmUtilities.js +9 -7
- package/dist/utility/npmUtilities.js.map +1 -1
- package/dist/utility/operationPermissions.d.ts +3 -1
- package/dist/utility/operationPermissions.js +16 -1
- package/dist/utility/operationPermissions.js.map +1 -1
- package/dist/utility/operation_authorization.d.ts +10 -7
- package/dist/utility/operation_authorization.js +212 -41
- package/dist/utility/operation_authorization.js.map +1 -1
- package/dist/utility/watchPath.d.ts +29 -0
- package/dist/utility/watchPath.js +68 -0
- package/dist/utility/watchPath.js.map +1 -0
- package/dist/utility/watcherFallback.d.ts +86 -0
- package/dist/utility/watcherFallback.js +278 -1
- package/dist/utility/watcherFallback.js.map +1 -1
- package/dist/validation/configValidator.d.ts +12 -0
- package/dist/validation/configValidator.js +199 -72
- package/dist/validation/configValidator.js.map +1 -1
- package/dist/validation/installValidator.js +12 -0
- package/dist/validation/installValidator.js.map +1 -1
- package/dist/validation/validationWrapper.d.ts +11 -0
- package/dist/validation/validationWrapper.js +16 -3
- package/dist/validation/validationWrapper.js.map +1 -1
- package/index.ts +2 -0
- package/json/systemSchema.json +52 -0
- package/npm-shrinkwrap.json +235 -233
- package/package.json +8 -7
- package/resources/DESIGN.md +114 -52
- package/resources/DatabaseTransaction.ts +522 -130
- package/resources/LMDBTransaction.ts +26 -4
- package/resources/PrimaryRocksDatabase.ts +29 -3
- package/resources/RecordEncoder.ts +103 -8
- package/resources/RequestTarget.ts +2 -0
- package/resources/Resource.ts +17 -9
- package/resources/ResourceInterface.ts +23 -0
- package/resources/RocksIndexStore.ts +30 -10
- package/resources/RocksTransactionLogStore.ts +78 -21
- package/resources/Table.ts +1107 -164
- package/resources/auditStore.ts +187 -21
- package/resources/blob.ts +1029 -110
- package/resources/branchDatabase.ts +941 -0
- package/resources/crdt.ts +76 -12
- package/resources/databases.ts +1354 -522
- package/resources/defineTable.ts +18 -2
- package/resources/graphql.ts +70 -16
- package/resources/indexes/HierarchicalNavigableSmallWorld.ts +6 -2
- package/resources/longLivedTransactions.ts +360 -0
- package/resources/models/backendRegistry.ts +84 -2
- package/resources/models/bootstrap.ts +473 -28
- package/resources/recordLock.ts +253 -0
- package/resources/replayLogs.ts +147 -26
- package/resources/replayLogsGuards.ts +171 -8
- package/resources/search.ts +154 -32
- package/resources/transactionBroadcast.ts +3 -3
- package/security/auth.ts +68 -29
- package/security/authn/oidc/claims.ts +72 -0
- package/security/authn/oidc/identityToken.ts +129 -0
- package/security/authn/oidc/jwks.ts +260 -0
- package/security/authn/oidc/providers/generic.ts +40 -0
- package/security/authn/oidc/providers/githubActions.ts +137 -0
- package/security/authn/oidc/providers/index.ts +52 -0
- package/security/authn/oidc/tokenExchange.ts +300 -0
- package/security/authn/oidc/trustPolicyOperations.ts +343 -0
- package/security/authn/oidc/types.ts +41 -0
- package/security/certificateVerification/index.ts +54 -13
- package/security/certificateVerification/trustedIssuers.ts +76 -0
- package/security/certificateVerification/types.ts +1 -0
- package/security/credentialProvenance.ts +47 -0
- package/security/credentialRejection.ts +22 -0
- package/security/deferredAuthentication.ts +71 -0
- package/security/impersonation.ts +117 -12
- package/security/jsLoader.ts +81 -18
- package/security/keys.ts +298 -72
- package/security/operationScope.ts +33 -0
- package/security/permissionsTranslator.js +23 -0
- package/security/tokenAuthentication.ts +233 -12
- package/security/user.ts +4 -3
- package/server/DESIGN.md +183 -16
- package/server/DurableSubscriptionsSession.ts +71 -11
- package/server/REST.ts +79 -1
- package/server/graphqlQuerying.ts +4 -0
- package/server/http.ts +99 -18
- package/server/itc/serverHandlers.js +8 -1
- package/server/jobs/jobProcess.ts +8 -2
- package/server/jobs/jobs.ts +4 -1
- package/server/liveSubscriptionAuth.ts +129 -46
- package/server/loadRootComponents.js +50 -8
- package/server/mqtt.ts +179 -38
- package/server/nodeName.ts +103 -21
- package/server/serverHelpers/Headers.ts +131 -0
- package/server/serverHelpers/contentTypes.ts +29 -21
- package/server/serverHelpers/deployValidationState.ts +24 -13
- package/server/serverHelpers/operationAuthorizationState.ts +34 -3
- package/server/serverHelpers/registeredOperations.ts +79 -22
- package/server/serverHelpers/requestSanitization.ts +15 -0
- package/server/serverHelpers/serverHandlers.js +6 -3
- package/server/serverHelpers/serverUtilities.ts +104 -31
- package/server/serverHelpers/sharedMessageEncoding.ts +307 -0
- package/server/serverHelpers/uwsServer.ts +17 -2
- package/server/static.ts +23 -29
- package/server/storageReclamation.ts +13 -0
- package/server/threads/itc.js +11 -1
- package/server/threads/manageThreads.js +526 -63
- package/server/threads/socketRouter.ts +81 -26
- package/server/threads/threadHeapMemory.ts +26 -0
- package/server/threads/threadServer.js +43 -15
- package/sqlTranslator/index.ts +31 -8
- package/studio/web/assets/{Chat-Br06zdMA.js → Chat-BnCBegQz.js} +1 -1
- package/studio/web/assets/{FloatingChat-BWImX5fA.js → FloatingChat-CoDW1ySS.js} +3 -3
- package/studio/web/assets/{apiToken-DN0nmDsq.js → apiToken-Bwk5BLXW.js} +1 -1
- package/studio/web/assets/{applications-kSxVoyeU.js → applications-DHxGi7JH.js} +1 -1
- package/studio/web/assets/{cssMode-C1JeufH5.js → cssMode-s0cWI-_M.js} +1 -1
- package/studio/web/assets/{editor-qoo9CrGO.js → editor-DNcRHK54.js} +1 -1
- package/studio/web/assets/{html-Dt4IIy04.js → html-Bdssedlg.js} +1 -1
- package/studio/web/assets/{htmlMode-DXgKKr4C.js → htmlMode-CoDlJ3fw.js} +1 -1
- package/studio/web/assets/{index-6onkYFOG.js → index-D6sxmFLR.js} +5 -5
- package/studio/web/assets/{index.lazy-BrCFnpNJ.js → index.lazy-tmU5BS8s.js} +1 -1
- package/studio/web/assets/{javascript-DNCQGUBc.js → javascript-B8meVSTH.js} +1 -1
- package/studio/web/assets/{jsonMode-CR6HWruP.js → jsonMode-DpIPd35T.js} +1 -1
- package/studio/web/assets/{languageServices-BM4fI4rS.js → languageServices-C_5FMJzQ.js} +1 -1
- package/studio/web/assets/{lspLanguageFeatures-DSa1ttcD.js → lspLanguageFeatures-BIzNBzPK.js} +1 -1
- package/studio/web/assets/{notifications-BHXLnh6x.js → notifications-CQf18QKb.js} +1 -1
- package/studio/web/assets/{notifications-CUmtIA6z.js → notifications-CvZivSbh.js} +1 -1
- package/studio/web/assets/{profile-8BeFSF3j.js → profile-DdOwtntb.js} +1 -1
- package/studio/web/assets/{regions-C8qR0HhD.js → regions-n69fwagr.js} +1 -1
- package/studio/web/assets/{register-B4n5i0SD.js → register-PfWTCXWB.js} +2 -2
- package/studio/web/assets/{setComponentFile-g0_B0lgX.js → setComponentFile-Bg6O7X0S.js} +1 -1
- package/studio/web/assets/{setup-B0CTj_Q5.js → setup-CUx_aUDl.js} +2 -2
- package/studio/web/assets/{status-C6Yib7-K.js → status-D7BVKqX9.js} +1 -1
- package/studio/web/assets/{toggleHighContrast-Dgta7bVi.js → toggleHighContrast-DBSyXzMr.js} +1 -1
- package/studio/web/assets/{tsMode-CH_jHvU-.js → tsMode-BByKCjBS.js} +1 -1
- package/studio/web/assets/{typescript-Co9LCXd5.js → typescript-DDLnLpw9.js} +1 -1
- package/studio/web/assets/{useEntityRestURL-wKC8NsC_.js → useEntityRestURL-31CHGaHk.js} +1 -1
- package/studio/web/assets/{workers-CWeLxCXA.js → workers-pR3jRY9D.js} +1 -1
- package/studio/web/assets/{xml-BadC-0Rk.js → xml-2iRnMhQO.js} +1 -1
- package/studio/web/assets/{yaml-BiUfxPbC.js → yaml-Bf92gJpd.js} +1 -1
- package/studio/web/index.html +1 -1
- package/upgrade/directives/5-3-0.ts +132 -0
- package/upgrade/directives/directivesController.ts +2 -1
- package/utility/OperationFunctionCaller.ts +2 -1
- package/utility/common_utils.ts +30 -5
- package/utility/componentNames.ts +12 -0
- package/utility/environment/environmentManager.ts +3 -7
- package/utility/environment/systemInformation.ts +7 -0
- package/utility/errors/commonErrors.ts +4 -0
- package/utility/errors/hdbError.ts +29 -0
- package/utility/hdbTerms.ts +17 -0
- package/utility/logging/harper_logger.ts +87 -14
- package/utility/logging/logRotator.ts +72 -45
- package/utility/nodeIdentity.ts +45 -0
- package/utility/npmUtilities.ts +10 -8
- package/utility/operationPermissions.ts +18 -1
- package/utility/operation_authorization.ts +231 -42
- package/utility/watchPath.ts +63 -0
- package/utility/watcherFallback.ts +270 -0
- package/validation/configValidator.ts +209 -72
- package/validation/installValidator.ts +15 -0
- package/validation/validationWrapper.ts +18 -4
|
@@ -132,16 +132,66 @@ export function shouldAbortSlowReplay(totalElapsedMs: number, timeLimitMs = REPL
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
/**
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
135
|
+
* A corrupt transaction-log frame from rocksdb-js. `resyncPosition` is set only when intact entries
|
|
136
|
+
* follow the break, which is what distinguishes lost entries from a merely truncated tail; its
|
|
137
|
+
* absence is also all that any rocksdb-js predating that field can report.
|
|
138
|
+
*/
|
|
139
|
+
export type CorruptFrameError = RangeError & {
|
|
140
|
+
logId?: number | null;
|
|
141
|
+
position?: number | null;
|
|
142
|
+
resyncPosition?: number | null;
|
|
143
|
+
unreadableBytes?: number | null;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Corrupt frames hit by one `getRange` call, shared by its per-log iterators.
|
|
148
|
+
*
|
|
149
|
+
* `truncatedVersions` is what a consumer has to act on: a break destroys the framing after the last
|
|
150
|
+
* entry the broken log yielded, and whether the entries it swallowed continued that entry's version
|
|
151
|
+
* is exactly what can no longer be read — UNLESS that last entry's own `endTxn` already closed its
|
|
152
|
+
* transaction, in which case nothing of it was left open to swallow. That version's transaction is
|
|
153
|
+
* therefore incomplete only when it wasn't already known-closed, and replay must discard it rather
|
|
154
|
+
* than commit the part of it that was still readable. A log that broke before yielding anything
|
|
155
|
+
* truncates no transaction.
|
|
156
|
+
*
|
|
157
|
+
* `midLogBreak` is coarser: true once any break in this range left intact entries unreadable behind
|
|
158
|
+
* it (see {@link isMidLogBreak}), regardless of which version they belonged to. A consumer that must
|
|
159
|
+
* never serve a range with lost entries — an elected branch replay publishing itself as a trustworthy
|
|
160
|
+
* point-in-time copy — rejects on this rather than on `truncatedVersions`, since a mid-log break can
|
|
161
|
+
* strand entries whose version this range never even attributes to one log (harper#2016, #2063).
|
|
162
|
+
*/
|
|
163
|
+
export interface CorruptFrameStop {
|
|
164
|
+
breaks: number;
|
|
165
|
+
truncatedVersions: Set<number>;
|
|
166
|
+
midLogBreak: boolean;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Whether a corrupt frame is a mid-log break — intact entries followed it, so entries were lost
|
|
171
|
+
* rather than the log merely being torn at its tail. Shared by the reporter below and by
|
|
172
|
+
* `RocksTransactionLogStore.getRange`'s `CorruptFrameStop.midLogBreak`, so the two can't drift on
|
|
173
|
+
* what counts as a mid-log break.
|
|
174
|
+
*/
|
|
175
|
+
export function isMidLogBreak(error: CorruptFrameError): boolean {
|
|
176
|
+
return error.resyncPosition != null;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Wraps a transaction-log query iterator so a corrupt/torn frame ends that log's iteration cleanly
|
|
181
|
+
* instead of escaping as an uncaughtException.
|
|
182
|
+
*
|
|
183
|
+
* Iteration stops at the break whether or not intact entries follow it. Resuming past a mid-log
|
|
184
|
+
* break would recover those entries, but a transaction log carries no frame-level transaction
|
|
185
|
+
* boundaries: replay groups equal-version entries into one source transaction, so skipping a frame
|
|
186
|
+
* inside such a group applies and checkpoints the surviving subset of a transaction that never
|
|
187
|
+
* committed that way at the source. Availability loss is visible and recoverable; a silently torn
|
|
188
|
+
* transaction is neither. Recovery is deferred until the engine can resume at a proven boundary
|
|
189
|
+
* (harper#2016, harper#2063); `resyncPosition` is used only to report the break as lost entries
|
|
190
|
+
* rather than as a truncated tail.
|
|
141
191
|
*/
|
|
142
192
|
export function endIteratorOnCorruptFrame<T>(
|
|
143
193
|
iterator: Iterator<T>,
|
|
144
|
-
onCorruptFrame: (error:
|
|
194
|
+
onCorruptFrame: (error: CorruptFrameError) => void
|
|
145
195
|
): IterableIterator<T> {
|
|
146
196
|
let stopped = false;
|
|
147
197
|
return {
|
|
@@ -157,7 +207,7 @@ export function endIteratorOnCorruptFrame<T>(
|
|
|
157
207
|
// version-dependent (1.4.2 added hex offsets). Anything else re-throws.
|
|
158
208
|
if (!(error instanceof RangeError)) throw error;
|
|
159
209
|
stopped = true;
|
|
160
|
-
onCorruptFrame(error);
|
|
210
|
+
onCorruptFrame(error as CorruptFrameError);
|
|
161
211
|
return { done: true, value: undefined };
|
|
162
212
|
}
|
|
163
213
|
},
|
|
@@ -175,3 +225,116 @@ export function endIteratorOnCorruptFrame<T>(
|
|
|
175
225
|
},
|
|
176
226
|
};
|
|
177
227
|
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* A corrupt frame, accumulated for the life of the process. The same frame is re-encountered by
|
|
231
|
+
* every reader until each consumer's resume cursor has passed it, so this is deduplicated by
|
|
232
|
+
* location and the repeats become a count.
|
|
233
|
+
*/
|
|
234
|
+
export interface CorruptFrameReport {
|
|
235
|
+
log: string;
|
|
236
|
+
logId?: number;
|
|
237
|
+
position?: number;
|
|
238
|
+
/** Intact entries followed the break, so entries were lost rather than merely truncated. */
|
|
239
|
+
midLog: boolean;
|
|
240
|
+
/** Extent of the unreadable region, when the engine reports it; 0 when nothing valid follows it. */
|
|
241
|
+
unreadableBytes: number;
|
|
242
|
+
firstSeen: number;
|
|
243
|
+
lastSeen: number;
|
|
244
|
+
occurrences: number;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/** Distinct break sites retained. One physical corruption yields one site, so this is generous. */
|
|
248
|
+
export const MAX_CORRUPT_FRAME_REPORTS = 256;
|
|
249
|
+
|
|
250
|
+
// Re-encounters move a site to the end, so the first key is the least recently seen. Full means
|
|
251
|
+
// evicting that one rather than refusing a new site, which could not then be deduplicated.
|
|
252
|
+
const corruptFrameReports = new Map<string, CorruptFrameReport>();
|
|
253
|
+
let evictedCorruptFrameReports = 0;
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Every corrupt frame seen by this worker. This is not yet consumed by cluster/health status;
|
|
257
|
+
* callers must aggregate it across worker threads before exposing a node-wide signal.
|
|
258
|
+
*
|
|
259
|
+
* Mid-log breaks are immediately logged at error level even without that consumer.
|
|
260
|
+
*/
|
|
261
|
+
export function getCorruptFrameReports(): CorruptFrameReport[] {
|
|
262
|
+
return [...corruptFrameReports.values()];
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/** Break sites evicted because {@link MAX_CORRUPT_FRAME_REPORTS} was reached. */
|
|
266
|
+
export function getEvictedCorruptFrameReportCount(): number {
|
|
267
|
+
return evictedCorruptFrameReports;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
export function clearCorruptFrameReports() {
|
|
271
|
+
corruptFrameReports.clear();
|
|
272
|
+
evictedCorruptFrameReports = 0;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// `logId`/`position` are absent on any rocksdb-js predating the resync support, and every break on
|
|
276
|
+
// a stream would then collapse onto one key — folding genuinely different corruptions into a single
|
|
277
|
+
// count that only ever logs once. The message carries the offset and file in text, so it separates
|
|
278
|
+
// them when the fields can't.
|
|
279
|
+
function corruptFrameKey(logName: string, error: CorruptFrameError): string {
|
|
280
|
+
const { logId, position } = error;
|
|
281
|
+
return logId != null && position != null
|
|
282
|
+
? `${logName}\u0000${logId}:${position}`
|
|
283
|
+
: `${logName}\u0000${error.message}`;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Records a corrupt frame and logs it once per distinct break.
|
|
288
|
+
*
|
|
289
|
+
* A mid-log break is an `error`, not a `warn`: entries after it were acknowledged and are now
|
|
290
|
+
* quarantined behind it. Severity follows the break's own shape, never this pass's outcome — every
|
|
291
|
+
* pass stops, so keying on that would report the #2063 signature with the benign torn-tail `warn`.
|
|
292
|
+
* A site first seen as a torn tail can escalate later, since only a rocksdb-js that reports
|
|
293
|
+
* `resyncPosition` can tell the two apart.
|
|
294
|
+
*/
|
|
295
|
+
export function createCorruptFrameReporter(logger: {
|
|
296
|
+
warn: (message: string, error?: unknown) => void;
|
|
297
|
+
error: (message: string, error?: unknown) => void;
|
|
298
|
+
}) {
|
|
299
|
+
return (logName: string) => (error: CorruptFrameError) => {
|
|
300
|
+
const midLog = isMidLogBreak(error);
|
|
301
|
+
const unreadableBytes = error.unreadableBytes ?? 0;
|
|
302
|
+
const now = Date.now();
|
|
303
|
+
const key = corruptFrameKey(logName, error);
|
|
304
|
+
const existing = corruptFrameReports.get(key);
|
|
305
|
+
if (existing) {
|
|
306
|
+
corruptFrameReports.delete(key);
|
|
307
|
+
corruptFrameReports.set(key, existing);
|
|
308
|
+
existing.occurrences++;
|
|
309
|
+
existing.lastSeen = now;
|
|
310
|
+
if (!midLog || existing.midLog) return;
|
|
311
|
+
existing.midLog = true;
|
|
312
|
+
existing.unreadableBytes = unreadableBytes;
|
|
313
|
+
} else {
|
|
314
|
+
if (corruptFrameReports.size >= MAX_CORRUPT_FRAME_REPORTS) {
|
|
315
|
+
corruptFrameReports.delete(corruptFrameReports.keys().next().value);
|
|
316
|
+
evictedCorruptFrameReports++;
|
|
317
|
+
}
|
|
318
|
+
corruptFrameReports.set(key, {
|
|
319
|
+
log: logName,
|
|
320
|
+
logId: error.logId ?? undefined,
|
|
321
|
+
position: error.position ?? undefined,
|
|
322
|
+
midLog,
|
|
323
|
+
unreadableBytes,
|
|
324
|
+
firstSeen: now,
|
|
325
|
+
lastSeen: now,
|
|
326
|
+
occurrences: 1,
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
if (midLog) {
|
|
330
|
+
logger.error(
|
|
331
|
+
`Corrupt entry in transaction log "${logName}"; ${unreadableBytes} byte(s) are unreadable and the entries within them are lost. ` +
|
|
332
|
+
'Intact entries follow the break, but reading stops there rather than skipping the frame, which could tear a source transaction: ' +
|
|
333
|
+
'they are quarantined until the log is repaired or this node is re-cloned, and they are neither replayed nor replicated meanwhile.',
|
|
334
|
+
error
|
|
335
|
+
);
|
|
336
|
+
} else {
|
|
337
|
+
logger.warn(`Stopping transaction log "${logName}" at a corrupt entry during replay`, error);
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
}
|
package/resources/search.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { ClientError, IndexRebuildingError, Violation } from '../utility/errors/hdbError.ts';
|
|
2
2
|
import { OVERFLOW_MARKER, MAX_SEARCH_KEY_LENGTH, SEARCH_TYPES } from '../utility/lmdb/terms.ts';
|
|
3
3
|
import { compareKeys, MAXIMUM_KEY, writeKey } from 'ordered-binary';
|
|
4
|
-
import { SKIP } from '@harperfast/extended-iterable';
|
|
4
|
+
import { SKIP, ExtendedIterable } from '@harperfast/extended-iterable';
|
|
5
5
|
import { INVALIDATED, EVICTED, freezeRecord } from './Table.ts';
|
|
6
6
|
import type { DirectCondition, Id } from './ResourceInterface.ts';
|
|
7
7
|
import { RequestTarget } from './RequestTarget.ts';
|
|
8
8
|
import { lastMetadata } from './RecordEncoder.ts';
|
|
9
|
+
import { writeKeyId } from './DatabaseTransaction.ts';
|
|
9
10
|
import { recordAction } from './analytics/write';
|
|
10
11
|
import { RocksDatabase } from '@harperfast/rocksdb-js';
|
|
11
12
|
|
|
@@ -232,6 +233,41 @@ function composeRecordFilter(recordFilters, table, context): (primaryKey: Id) =>
|
|
|
232
233
|
};
|
|
233
234
|
}
|
|
234
235
|
|
|
236
|
+
/**
|
|
237
|
+
* A record's index entries are not adjacent — the composite `[indexedValue, primaryKey]` key sorts
|
|
238
|
+
* on the indexed value first — so comparing neighbours cannot collapse them and the scan has to
|
|
239
|
+
* remember what it already yielded (#2434).
|
|
240
|
+
*
|
|
241
|
+
* Heap cost is one key per distinct record in the scanned range, held for the life of the scan, and
|
|
242
|
+
* a page window does not cap it: sibling-condition and row filters run downstream, so a selective
|
|
243
|
+
* filter keeps the scan running and the set growing while the page fills. On a multi-million-row
|
|
244
|
+
* range that is hundreds of MB where main streamed at O(1). Accepted for #2434 over the bounded
|
|
245
|
+
* alternative, which costs a primary read per index entry.
|
|
246
|
+
*/
|
|
247
|
+
function distinctRecords(entries: any): AsyncIterable<Id> {
|
|
248
|
+
const distinct = new ExtendedIterable();
|
|
249
|
+
(distinct as any).iterate = (options) => {
|
|
250
|
+
// A non-scalar key decodes to a fresh instance per entry, so identity never matches it;
|
|
251
|
+
// `writeKeyId` is the store's own key equality. Its bytes get their own set because a scalar
|
|
252
|
+
// string id can legitimately carry exactly those bytes, and one set would fold the two —
|
|
253
|
+
// the collision `flattenKey` has, and the reason Table.ts prefixes its key ids.
|
|
254
|
+
const yieldedKeys = new Set();
|
|
255
|
+
const yieldedEncodedKeys = new Set();
|
|
256
|
+
// map rather than filter: filter clears `continueOnRecoverableError` for everything below it
|
|
257
|
+
return entries
|
|
258
|
+
.map((primaryKey) => {
|
|
259
|
+
const isEncoded = typeof primaryKey === 'object' && primaryKey !== null;
|
|
260
|
+
const yielded = isEncoded ? yieldedEncodedKeys : yieldedKeys;
|
|
261
|
+
const identity = isEncoded ? writeKeyId(primaryKey) : primaryKey;
|
|
262
|
+
if (yielded.has(identity)) return SKIP;
|
|
263
|
+
yielded.add(identity);
|
|
264
|
+
return primaryKey;
|
|
265
|
+
})
|
|
266
|
+
.iterate(options);
|
|
267
|
+
};
|
|
268
|
+
return distinct as any;
|
|
269
|
+
}
|
|
270
|
+
|
|
235
271
|
/**
|
|
236
272
|
* Search for records or keys, based on the search condition, using an index if available
|
|
237
273
|
* @param searchCondition
|
|
@@ -261,6 +297,9 @@ export function searchByIndex(
|
|
|
261
297
|
throw new ClientError(`Search condition for ${attribute_name} must have a value`);
|
|
262
298
|
}
|
|
263
299
|
let needFullScan;
|
|
300
|
+
// `[indexedValue, primaryKey]` is unique, so a scan that stays inside one indexed value cannot
|
|
301
|
+
// reach a record twice and skips the collapse below
|
|
302
|
+
let scansOneIndexedValue;
|
|
264
303
|
if (Array.isArray(attribute_name)) {
|
|
265
304
|
const firstAttributeName = attribute_name[0];
|
|
266
305
|
// get the potential relationship attribute
|
|
@@ -388,6 +427,7 @@ export function searchByIndex(
|
|
|
388
427
|
start = value;
|
|
389
428
|
end = value;
|
|
390
429
|
inclusiveEnd = true;
|
|
430
|
+
scansOneIndexedValue = true;
|
|
391
431
|
break;
|
|
392
432
|
case 'in':
|
|
393
433
|
// Phase 1: route through filter — index-merge optimization is a Phase 2 follow-up.
|
|
@@ -531,7 +571,7 @@ export function searchByIndex(
|
|
|
531
571
|
}
|
|
532
572
|
return loaded;
|
|
533
573
|
}
|
|
534
|
-
|
|
574
|
+
const scanned = index.getRange(rangeOptions).map(
|
|
535
575
|
filter
|
|
536
576
|
? function ({ key, value }) {
|
|
537
577
|
let recordMatcher: any;
|
|
@@ -554,6 +594,14 @@ export function searchByIndex(
|
|
|
554
594
|
}
|
|
555
595
|
: ({ value }) => value
|
|
556
596
|
);
|
|
597
|
+
// Collapsing AFTER the map is required, not incidental: the condition's own filter tests one
|
|
598
|
+
// element at a time, so a record whose first entry fails it and whose second passes must
|
|
599
|
+
// still be reached. Collapsing first would settle that record on the failing entry and drop
|
|
600
|
+
// it. Scoped to attributes the schema declares multi-valued; a runtime array under an
|
|
601
|
+
// undeclared attribute repeats the same way but stays outside this boundary.
|
|
602
|
+
return scansOneIndexedValue || !findAttribute(Table.attributes, attribute_name)?.elements
|
|
603
|
+
? scanned
|
|
604
|
+
: distinctRecords(scanned);
|
|
557
605
|
} else {
|
|
558
606
|
return Table.primaryStore
|
|
559
607
|
.getRange(reverse ? { end: true, transaction, reverse: true } : { start: true, transaction })
|
|
@@ -1055,7 +1103,7 @@ export function filterByType(searchCondition, Table, context, filtered, isPrimar
|
|
|
1055
1103
|
canUseIndex =
|
|
1056
1104
|
canUseIndex && // is it a comparator that makes sense to use index
|
|
1057
1105
|
!isPrimaryKey && // no need to use index for primary keys, since we will be iterating over the primary keys
|
|
1058
|
-
|
|
1106
|
+
Table?.indices[attribute] && // is there an index for this attribute
|
|
1059
1107
|
estimatedIncomingCount > 3; // do we have a valid estimate of multiple incoming records (that is worth using an index for)
|
|
1060
1108
|
if (canUseIndex) {
|
|
1061
1109
|
if (searchCondition.estimated_count == undefined) estimateCondition(Table)(searchCondition);
|
|
@@ -1112,26 +1160,89 @@ export function filterByType(searchCondition, Table, context, filtered, isPrimar
|
|
|
1112
1160
|
}
|
|
1113
1161
|
}
|
|
1114
1162
|
|
|
1115
|
-
/** The index a condition can be driven by; searchByIndex refuses a rebuilding one, so it reads as absent. */
|
|
1116
|
-
function usableIndex(table, attributeName): any {
|
|
1117
|
-
const index = attributeName == null ? undefined : table.indices[attributeName];
|
|
1118
|
-
return index?.isIndexing ? undefined : index;
|
|
1119
|
-
}
|
|
1120
|
-
|
|
1121
1163
|
/**
|
|
1122
|
-
*
|
|
1123
|
-
*
|
|
1164
|
+
* Estimates a range comparator's entry count from the store's statistical estimate, blended with
|
|
1165
|
+
* the table-fraction heuristic by the estimate's confidence so low-confidence estimates degrade
|
|
1166
|
+
* to the old behavior. Returns undefined (caller falls back to the heuristic) when the store
|
|
1167
|
+
* cannot estimate, the shape is unexpected, or the executed range wouldn't match this one.
|
|
1124
1168
|
*/
|
|
1125
|
-
function
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
if (
|
|
1133
|
-
|
|
1134
|
-
|
|
1169
|
+
function estimateRangeCondition(table, condition, searchType, fraction) {
|
|
1170
|
+
const attributeName = condition[0] ?? condition.attribute;
|
|
1171
|
+
const isPrimaryKey = attributeName === table.primaryKey;
|
|
1172
|
+
const store = isPrimaryKey ? table.primaryStore : table.indices[attributeName];
|
|
1173
|
+
// LMDB-backed and custom index stores do not implement estimateCount
|
|
1174
|
+
if (typeof store?.estimateCount !== 'function') return undefined;
|
|
1175
|
+
let value = condition[1] ?? condition.value;
|
|
1176
|
+
if (value instanceof Date) value = value.getTime();
|
|
1177
|
+
let range;
|
|
1178
|
+
switch (searchType) {
|
|
1179
|
+
case 'lt':
|
|
1180
|
+
// `start: true` mirrors searchByIndex: `true` sorts above `null`, so an indexNulls
|
|
1181
|
+
// index's `[null, primaryKey]` entries are outside the executed range
|
|
1182
|
+
range = { start: true, end: value };
|
|
1183
|
+
break;
|
|
1184
|
+
case 'le':
|
|
1185
|
+
range = { start: true, end: value, inclusiveEnd: true };
|
|
1186
|
+
break;
|
|
1187
|
+
case 'gt':
|
|
1188
|
+
range = { start: value, exclusiveStart: true };
|
|
1189
|
+
break;
|
|
1190
|
+
case 'ge':
|
|
1191
|
+
range = { start: value };
|
|
1192
|
+
break;
|
|
1193
|
+
case 'between':
|
|
1194
|
+
case 'gele':
|
|
1195
|
+
case 'gelt':
|
|
1196
|
+
case 'gtlt':
|
|
1197
|
+
case 'gtle': {
|
|
1198
|
+
if (!Array.isArray(value)) return undefined;
|
|
1199
|
+
let [start, end] = value;
|
|
1200
|
+
if (start instanceof Date) start = start.getTime();
|
|
1201
|
+
if (end instanceof Date) end = end.getTime();
|
|
1202
|
+
range = {
|
|
1203
|
+
start,
|
|
1204
|
+
end,
|
|
1205
|
+
inclusiveEnd: searchType === 'between' || searchType === 'gele' || searchType === 'gtle',
|
|
1206
|
+
exclusiveStart: searchType === 'gtlt' || searchType === 'gtle',
|
|
1207
|
+
};
|
|
1208
|
+
break;
|
|
1209
|
+
}
|
|
1210
|
+
case 'starts_with': {
|
|
1211
|
+
const prefix = value?.toString();
|
|
1212
|
+
if (!prefix) return undefined;
|
|
1213
|
+
range = { start: prefix, end: getStringPrefixUpperBound(prefix) };
|
|
1214
|
+
break;
|
|
1215
|
+
}
|
|
1216
|
+
case 'prefix': {
|
|
1217
|
+
let start = Array.isArray(value) ? value : [value, null];
|
|
1218
|
+
if (start[start.length - 1] != null) start = start.concat(null);
|
|
1219
|
+
const end = start.slice(0);
|
|
1220
|
+
end[end.length - 1] = MAXIMUM_KEY;
|
|
1221
|
+
range = { start, end };
|
|
1222
|
+
break;
|
|
1223
|
+
}
|
|
1224
|
+
default:
|
|
1225
|
+
return undefined;
|
|
1226
|
+
}
|
|
1227
|
+
// Long string bounds get truncated + filtered at execution (searchByIndex), so the
|
|
1228
|
+
// executed range is wider than this one; don't estimate what won't be iterated.
|
|
1229
|
+
if (
|
|
1230
|
+
(typeof range.start === 'string' && range.start.length > MAX_SEARCH_KEY_LENGTH) ||
|
|
1231
|
+
(typeof range.end === 'string' && range.end.length > MAX_SEARCH_KEY_LENGTH)
|
|
1232
|
+
) {
|
|
1233
|
+
return undefined;
|
|
1234
|
+
}
|
|
1235
|
+
let count, confidence;
|
|
1236
|
+
try {
|
|
1237
|
+
({ count, confidence } = store.estimateCount(range) ?? {});
|
|
1238
|
+
} catch {
|
|
1239
|
+
// a concurrently closing/dropped store must degrade the plan, not fail the query
|
|
1240
|
+
return undefined;
|
|
1241
|
+
}
|
|
1242
|
+
if (!Number.isFinite(count) || count < 0 || !Number.isFinite(confidence) || confidence < 0 || confidence > 1)
|
|
1243
|
+
return undefined;
|
|
1244
|
+
const heuristic = fraction * estimatedEntryCount(table.primaryStore) + 1;
|
|
1245
|
+
return Math.max(1, Math.round(confidence * count + (1 - confidence) * heuristic));
|
|
1135
1246
|
}
|
|
1136
1247
|
|
|
1137
1248
|
export function estimateCondition(table) {
|
|
@@ -1163,8 +1274,12 @@ export function estimateCondition(table) {
|
|
|
1163
1274
|
// skip if it is cached
|
|
1164
1275
|
let searchType = condition.comparator || condition.search_type;
|
|
1165
1276
|
searchType = ALTERNATE_COMPARATOR_NAMES[searchType] || searchType;
|
|
1166
|
-
|
|
1167
|
-
|
|
1277
|
+
if (condition.negated) {
|
|
1278
|
+
// a negated condition always executes as a full scan (searchByIndex forces
|
|
1279
|
+
// needFullScan), so follow the filter-only convention used by contains/ends_with:
|
|
1280
|
+
// estimate Infinity so its positive-range estimate can never win the driving-condition
|
|
1281
|
+
// ordering. Short-circuit here rather than computing (and discarding) a positive-range
|
|
1282
|
+
// estimate that would cross the native FFI boundary for nothing.
|
|
1168
1283
|
condition.estimated_count = Infinity;
|
|
1169
1284
|
} else if (searchType === SEARCH_TYPES.EQUALS || !searchType) {
|
|
1170
1285
|
const attribute_name = condition[0] ?? condition.attribute;
|
|
@@ -1192,12 +1307,12 @@ export function estimateCondition(table) {
|
|
|
1192
1307
|
}
|
|
1193
1308
|
} else {
|
|
1194
1309
|
// we only attempt to estimate count on equals operator because that's really all that LMDB supports (some other key-value stores like libmdbx could be considered if we need to do estimated counts of ranges at some point)
|
|
1195
|
-
const index =
|
|
1310
|
+
const index = table.indices[attribute_name];
|
|
1196
1311
|
condition.estimated_count = index ? index.getValuesCount(condition[1] ?? condition.value) : Infinity;
|
|
1197
1312
|
}
|
|
1198
1313
|
} else if (searchType === 'contains' || searchType === 'ends_with' || searchType === 'ne') {
|
|
1199
1314
|
const attribute_name = condition[0] ?? condition.attribute;
|
|
1200
|
-
const index =
|
|
1315
|
+
const index = table.indices[attribute_name];
|
|
1201
1316
|
if (condition.value === null && searchType === 'ne') {
|
|
1202
1317
|
condition.estimated_count = Math.max(
|
|
1203
1318
|
estimatedEntryCount(table.primaryStore) - (index ? index.getValuesCount(null) : 0),
|
|
@@ -1206,7 +1321,7 @@ export function estimateCondition(table) {
|
|
|
1206
1321
|
} else condition.estimated_count = Infinity;
|
|
1207
1322
|
} else if (searchType === 'in') {
|
|
1208
1323
|
const attribute_name = condition[0] ?? condition.attribute;
|
|
1209
|
-
const index =
|
|
1324
|
+
const index = table.indices[attribute_name];
|
|
1210
1325
|
if (Array.isArray(condition.value) && index) {
|
|
1211
1326
|
// Sum of per-value matches (over-counts duplicates but is a fine ceiling)
|
|
1212
1327
|
let estimate = 0;
|
|
@@ -1217,14 +1332,17 @@ export function estimateCondition(table) {
|
|
|
1217
1332
|
} else if (Array.isArray(condition.value)) {
|
|
1218
1333
|
condition.estimated_count = Infinity;
|
|
1219
1334
|
} else condition.estimated_count = Infinity;
|
|
1220
|
-
// for range queries (betweens, startsWith, greater, etc.), just arbitrarily guess
|
|
1221
1335
|
} else if (searchType === 'starts_with' || searchType === 'prefix')
|
|
1222
|
-
condition.estimated_count =
|
|
1336
|
+
condition.estimated_count =
|
|
1337
|
+
estimateRangeCondition(table, condition, searchType, STARTS_WITH_ESTIMATE) ??
|
|
1338
|
+
STARTS_WITH_ESTIMATE * estimatedEntryCount(table.primaryStore) + 1;
|
|
1223
1339
|
else if (searchType === 'between')
|
|
1224
|
-
condition.estimated_count =
|
|
1340
|
+
condition.estimated_count =
|
|
1341
|
+
estimateRangeCondition(table, condition, searchType, BETWEEN_ESTIMATE) ??
|
|
1342
|
+
BETWEEN_ESTIMATE * estimatedEntryCount(table.primaryStore) + 1;
|
|
1225
1343
|
else if (searchType === 'sort') {
|
|
1226
1344
|
const attribute_name = condition[0] ?? condition.attribute;
|
|
1227
|
-
const index =
|
|
1345
|
+
const index = table.indices[attribute_name];
|
|
1228
1346
|
if (index?.customIndex?.estimateCountAsSort)
|
|
1229
1347
|
// allow custom index to define its own estimation of counts
|
|
1230
1348
|
condition.estimated_count = index.customIndex.estimateCountAsSort(condition);
|
|
@@ -1232,11 +1350,14 @@ export function estimateCondition(table) {
|
|
|
1232
1350
|
} else {
|
|
1233
1351
|
// for the search types that use the broadest range, try do them last
|
|
1234
1352
|
const attribute_name = condition[0] ?? condition.attribute;
|
|
1235
|
-
const index =
|
|
1353
|
+
const index = table.indices[attribute_name];
|
|
1236
1354
|
if (index?.customIndex?.estimateCount)
|
|
1237
1355
|
// allow custom index to define its own estimation of counts
|
|
1238
1356
|
condition.estimated_count = index.customIndex.estimateCount(condition.value);
|
|
1239
|
-
else
|
|
1357
|
+
else
|
|
1358
|
+
condition.estimated_count =
|
|
1359
|
+
estimateRangeCondition(table, condition, searchType, OPEN_RANGE_ESTIMATE) ??
|
|
1360
|
+
OPEN_RANGE_ESTIMATE * estimatedEntryCount(table.primaryStore) + 1;
|
|
1240
1361
|
}
|
|
1241
1362
|
// we give a condition significantly more weight/preference if we will be ordering by it
|
|
1242
1363
|
if (typeof condition.descending === 'boolean') condition.estimated_count /= 2;
|
|
@@ -1422,6 +1543,7 @@ function parseBlock(query, expectedEnd) {
|
|
|
1422
1543
|
break;
|
|
1423
1544
|
case 'group-by':
|
|
1424
1545
|
recordError('group by is not implemented yet');
|
|
1546
|
+
break;
|
|
1425
1547
|
case 'sort':
|
|
1426
1548
|
query.sort = toSortObject(args);
|
|
1427
1549
|
break;
|
|
@@ -95,7 +95,7 @@ export function addSubscription(table, key, listener?: (key) => any, startTime?:
|
|
|
95
95
|
* subscription and get the initial state.
|
|
96
96
|
*/
|
|
97
97
|
class Subscription extends IterableEventQueue {
|
|
98
|
-
listener: (recordId: Id, auditEntry: any,
|
|
98
|
+
listener: (recordId: Id, auditEntry: any, txnLogKey: number, beginTxn: boolean) => void;
|
|
99
99
|
subscriptions: any;
|
|
100
100
|
startTime?: number;
|
|
101
101
|
includeDescendants?: boolean;
|
|
@@ -178,10 +178,10 @@ function notifyFromTransactionData(subscriptions, auditLogIterable?, allowYield
|
|
|
178
178
|
}
|
|
179
179
|
if (result.done) break;
|
|
180
180
|
const auditRecord = result.value;
|
|
181
|
-
const timestamp: number = auditRecord.
|
|
181
|
+
const timestamp: number = auditRecord.txnLogKey;
|
|
182
182
|
subscriptions.lastTxnTime = timestamp;
|
|
183
183
|
// the transaction extent: RocksDB entries committed together share the log key (record
|
|
184
|
-
// versions may differ); LMDB's
|
|
184
|
+
// versions may differ); LMDB's transaction-log key is per-entry, so version delimits there
|
|
185
185
|
const txnKey = auditStore.reusableIterable ? timestamp : auditRecord.version;
|
|
186
186
|
if (ACTIONS_OF_INTEREST.includes(auditRecord.type)) {
|
|
187
187
|
const tableSubscriptions = subscriptions[auditRecord.tableId];
|