@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
package/resources/search.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
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, getReadTransactionGuard } from './DatabaseTransaction.ts';
|
|
9
10
|
import { recordAction } from './analytics/write';
|
|
10
11
|
import { RocksDatabase } from '@harperfast/rocksdb-js';
|
|
12
|
+
import { appendHeader } from '../server/serverHelpers/Headers.ts';
|
|
11
13
|
|
|
12
14
|
// these are ratios/percentages of overall table size
|
|
13
15
|
const OPEN_RANGE_ESTIMATE = 0.3;
|
|
@@ -140,16 +142,13 @@ export function executeConditions(
|
|
|
140
142
|
filtered
|
|
141
143
|
// recordAccess intentionally omitted: guards run once, at the top level (see above).
|
|
142
144
|
);
|
|
143
|
-
return searchByIndex(
|
|
144
|
-
|
|
145
|
-
txn,
|
|
146
|
-
condition.descending || request.reverse === true,
|
|
147
|
-
table,
|
|
148
|
-
request.allowFullScan,
|
|
145
|
+
return searchByIndex(condition, txn, condition.descending || request.reverse === true, table, {
|
|
146
|
+
allowFullScan: request.allowFullScan,
|
|
149
147
|
filtered,
|
|
150
148
|
context,
|
|
151
|
-
|
|
152
|
-
|
|
149
|
+
minResults:
|
|
150
|
+
request.limit === 0 ? 0 : request.limit !== undefined ? (request.offset || 0) + request.limit : undefined,
|
|
151
|
+
});
|
|
153
152
|
}
|
|
154
153
|
function mapConditionsToFilters(conditions, intersection, estimatedIncomingCount) {
|
|
155
154
|
return conditions
|
|
@@ -233,27 +232,70 @@ function composeRecordFilter(recordFilters, table, context): (primaryKey: Id) =>
|
|
|
233
232
|
}
|
|
234
233
|
|
|
235
234
|
/**
|
|
236
|
-
*
|
|
235
|
+
* A record's index entries are not adjacent — the composite `[indexedValue, primaryKey]` key sorts
|
|
236
|
+
* on the indexed value first — so comparing neighbours cannot collapse them and the scan has to
|
|
237
|
+
* remember what it already yielded (#2434).
|
|
238
|
+
*
|
|
239
|
+
* Heap cost is one key per distinct record in the scanned range, held for the life of the scan, and
|
|
240
|
+
* a page window does not cap it: sibling-condition and row filters run downstream, so a selective
|
|
241
|
+
* filter keeps the scan running and the set growing while the page fills. On a multi-million-row
|
|
242
|
+
* range that is hundreds of MB where main streamed at O(1). Accepted for #2434 over the bounded
|
|
243
|
+
* alternative, which costs a primary read per index entry.
|
|
244
|
+
*/
|
|
245
|
+
function distinctRecords(entries: any): AsyncIterable<Id> {
|
|
246
|
+
const distinct = new ExtendedIterable();
|
|
247
|
+
(distinct as any).iterate = (options) => {
|
|
248
|
+
// A non-scalar key decodes to a fresh instance per entry, so identity never matches it;
|
|
249
|
+
// `writeKeyId` is the store's own key equality. Its bytes get their own set because a scalar
|
|
250
|
+
// string id can legitimately carry exactly those bytes, and one set would fold the two —
|
|
251
|
+
// the collision `flattenKey` has, and the reason Table.ts prefixes its key ids.
|
|
252
|
+
const yieldedKeys = new Set();
|
|
253
|
+
const yieldedEncodedKeys = new Set();
|
|
254
|
+
// map rather than filter: filter clears `continueOnRecoverableError` for everything below it
|
|
255
|
+
return entries
|
|
256
|
+
.map((primaryKey) => {
|
|
257
|
+
const isEncoded = typeof primaryKey === 'object' && primaryKey !== null;
|
|
258
|
+
const yielded = isEncoded ? yieldedEncodedKeys : yieldedKeys;
|
|
259
|
+
const identity = isEncoded ? writeKeyId(primaryKey) : primaryKey;
|
|
260
|
+
if (yielded.has(identity)) return SKIP;
|
|
261
|
+
yielded.add(identity);
|
|
262
|
+
return primaryKey;
|
|
263
|
+
})
|
|
264
|
+
.iterate(options);
|
|
265
|
+
};
|
|
266
|
+
return distinct as any;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Search for records or keys, based on the search condition, using an index if available. The four
|
|
271
|
+
* leading parameters are required at every call site; everything optional is named, so a new
|
|
272
|
+
* capability can be added without shifting positions at callers that don't use it.
|
|
237
273
|
* @param searchCondition
|
|
238
274
|
* @param transaction
|
|
239
275
|
* @param reverse
|
|
240
276
|
* @param Table
|
|
241
|
-
* @param
|
|
242
|
-
* @param filtered
|
|
277
|
+
* @param options
|
|
243
278
|
*/
|
|
244
279
|
export function searchByIndex(
|
|
245
280
|
searchCondition: DirectCondition,
|
|
246
281
|
transaction: any,
|
|
247
282
|
reverse: boolean,
|
|
248
283
|
Table: any,
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
284
|
+
options: {
|
|
285
|
+
allowFullScan?: boolean;
|
|
286
|
+
filtered?: any;
|
|
287
|
+
context?: any;
|
|
288
|
+
// How many rows the query will ultimately consume (offset + limit), when it is bounded. An
|
|
289
|
+
// approximate index returns a fixed-size candidate list, so without this a query asking for more
|
|
290
|
+
// rows than that list holds silently gets a short result set. Only custom indexes read it.
|
|
291
|
+
minResults?: number;
|
|
292
|
+
} = {}
|
|
256
293
|
): AsyncIterable<Id | { key: Id; value: any }> {
|
|
294
|
+
// A stale positional caller passes `allowFullScan` here. Type checking only covers .ts callers, so
|
|
295
|
+
// fail loud rather than silently reading every option as undefined.
|
|
296
|
+
if (typeof options !== 'object' || options === null)
|
|
297
|
+
throw new TypeError('searchByIndex: the 5th argument is an options object (#2165), not a positional value');
|
|
298
|
+
const { allowFullScan, filtered, context, minResults } = options;
|
|
257
299
|
let attribute_name = searchCondition[0] ?? searchCondition.attribute;
|
|
258
300
|
let value = searchCondition[1] ?? searchCondition.value;
|
|
259
301
|
const comparator = searchCondition.comparator;
|
|
@@ -261,6 +303,9 @@ export function searchByIndex(
|
|
|
261
303
|
throw new ClientError(`Search condition for ${attribute_name} must have a value`);
|
|
262
304
|
}
|
|
263
305
|
let needFullScan;
|
|
306
|
+
// `[indexedValue, primaryKey]` is unique, so a scan that stays inside one indexed value cannot
|
|
307
|
+
// reach a record twice and skips the collapse below
|
|
308
|
+
let scansOneIndexedValue;
|
|
264
309
|
if (Array.isArray(attribute_name)) {
|
|
265
310
|
const firstAttributeName = attribute_name[0];
|
|
266
311
|
// get the potential relationship attribute
|
|
@@ -284,8 +329,7 @@ export function searchByIndex(
|
|
|
284
329
|
transaction,
|
|
285
330
|
reverse,
|
|
286
331
|
relatedTable,
|
|
287
|
-
allowFullScan,
|
|
288
|
-
joined
|
|
332
|
+
{ allowFullScan, filtered: joined }
|
|
289
333
|
);
|
|
290
334
|
if (attribute.relationship.to) {
|
|
291
335
|
// this is one-to-many or many-to-many, so we need to track the filtering of related entries that match
|
|
@@ -302,8 +346,7 @@ export function searchByIndex(
|
|
|
302
346
|
transaction,
|
|
303
347
|
reverse,
|
|
304
348
|
Table,
|
|
305
|
-
allowFullScan,
|
|
306
|
-
joined
|
|
349
|
+
{ allowFullScan, filtered: joined }
|
|
307
350
|
);
|
|
308
351
|
};
|
|
309
352
|
if (attribute.elements) {
|
|
@@ -388,6 +431,7 @@ export function searchByIndex(
|
|
|
388
431
|
start = value;
|
|
389
432
|
end = value;
|
|
390
433
|
inclusiveEnd = true;
|
|
434
|
+
scansOneIndexedValue = true;
|
|
391
435
|
break;
|
|
392
436
|
case 'in':
|
|
393
437
|
// Phase 1: route through filter — index-merge optimization is a Phase 2 follow-up.
|
|
@@ -510,28 +554,119 @@ export function searchByIndex(
|
|
|
510
554
|
// exploring until it has enough MATCHING results, rather than post-filtering an under-filled
|
|
511
555
|
// candidate set. Only indexes that opt in (filteredSearch) receive it; others post-filter as before.
|
|
512
556
|
const recordFilter = index.customIndex.filteredSearch ? searchCondition.recordFilter : undefined;
|
|
513
|
-
const
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
557
|
+
const waiting = index.customIndex.filePrimary && searchCondition.waitForIndexMilliseconds > 0;
|
|
558
|
+
const start = waiting ? Promise.withResolvers<void>() : undefined;
|
|
559
|
+
const controller = waiting ? new AbortController() : undefined;
|
|
560
|
+
const checkActive = waiting ? getReadTransactionGuard(transaction) : undefined;
|
|
561
|
+
const signal = waiting
|
|
562
|
+
? context.signal
|
|
563
|
+
? AbortSignal.any([context.signal, controller.signal])
|
|
564
|
+
: controller.signal
|
|
565
|
+
: undefined;
|
|
566
|
+
const searchContext = waiting
|
|
567
|
+
? Object.create(context, {
|
|
568
|
+
signal: { value: signal },
|
|
569
|
+
indexSearchStart: { value: start.promise.then(() => checkActive?.()) },
|
|
570
|
+
})
|
|
571
|
+
: context;
|
|
572
|
+
const searched = index.customIndex.search(searchCondition, searchContext, {
|
|
573
|
+
filter:
|
|
574
|
+
waiting && recordFilter
|
|
575
|
+
? (id) => {
|
|
576
|
+
if (signal.aborted) return false;
|
|
577
|
+
checkActive?.();
|
|
578
|
+
return recordFilter(id);
|
|
579
|
+
}
|
|
580
|
+
: recordFilter,
|
|
581
|
+
minResults,
|
|
527
582
|
});
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
583
|
+
const coverage = (searched as any).indexCoverage;
|
|
584
|
+
if (!waiting && coverage && context?.responseHeaders) {
|
|
585
|
+
appendHeader(
|
|
586
|
+
context.responseHeaders,
|
|
587
|
+
'Harper-Index-Coverage',
|
|
588
|
+
`${coverage.state}; lag=${coverage.lagUpperBoundMilliseconds}; tolerance=${coverage.maxLagMilliseconds}`,
|
|
589
|
+
true
|
|
590
|
+
);
|
|
591
|
+
appendHeader(context.responseHeaders, 'Access-Control-Expose-Headers', 'Harper-Index-Coverage', true);
|
|
531
592
|
}
|
|
532
|
-
|
|
593
|
+
const processEntries = (entries: any[]) => {
|
|
594
|
+
const loaded = entries
|
|
595
|
+
.map((entry) => {
|
|
596
|
+
// if the custom index returns an entry with metadata, merge it with the loaded entry
|
|
597
|
+
if (typeof entry === 'object' && entry) {
|
|
598
|
+
const { key, ...otherProps } = entry;
|
|
599
|
+
if (key == null) return SKIP; // primaryKey missing from HNSW node — skip rather than crash
|
|
600
|
+
const loadedEntry = Table.primaryStore.getEntry(key, {
|
|
601
|
+
transaction: waiting ? transaction : context && Table._readTxnForContext(context),
|
|
602
|
+
});
|
|
603
|
+
if (!loadedEntry) return SKIP; // record was deleted/expired or not yet visible
|
|
604
|
+
freezeRecord(loadedEntry?.value);
|
|
605
|
+
recordRead(loadedEntry);
|
|
606
|
+
return { ...otherProps, ...loadedEntry };
|
|
607
|
+
}
|
|
608
|
+
return entry;
|
|
609
|
+
})
|
|
610
|
+
.filter((entry) => entry !== SKIP);
|
|
611
|
+
if (index.customIndex.rescoreResults) {
|
|
612
|
+
const rescored = index.customIndex.rescoreResults(loaded, searchCondition, comparator, attribute_name);
|
|
613
|
+
if (rescored != null) return rescored as any;
|
|
614
|
+
}
|
|
615
|
+
return loaded;
|
|
616
|
+
};
|
|
617
|
+
if (typeof (searched as any)?.then === 'function') {
|
|
618
|
+
let settled = false;
|
|
619
|
+
const pending = waiting
|
|
620
|
+
? (searched as Promise<any[]>)
|
|
621
|
+
.then((entries) => {
|
|
622
|
+
if (controller.signal.aborted) return [];
|
|
623
|
+
if (signal.aborted) throw signal.reason ?? new Error('Index search aborted', { cause: signal.reason });
|
|
624
|
+
checkActive?.();
|
|
625
|
+
return processEntries(entries);
|
|
626
|
+
})
|
|
627
|
+
.finally(() => {
|
|
628
|
+
settled = true;
|
|
629
|
+
})
|
|
630
|
+
: (searched as Promise<any[]>).then(processEntries);
|
|
631
|
+
// A consumer may abandon this lazy iterable without calling next().
|
|
632
|
+
pending.catch(() => {});
|
|
633
|
+
const results: any = new ExtendedIterable();
|
|
634
|
+
results.iterate = (options?: { async?: boolean }) => {
|
|
635
|
+
if (!options?.async) {
|
|
636
|
+
throw new Error(
|
|
637
|
+
'This index resolves search results asynchronously; the results must be consumed with async iteration'
|
|
638
|
+
);
|
|
639
|
+
}
|
|
640
|
+
// Overlapping next() calls share one cursor and cannot duplicate its first entry.
|
|
641
|
+
const iteratorPromise = pending.then((entries) => entries[Symbol.iterator]());
|
|
642
|
+
iteratorPromise.catch(() => {});
|
|
643
|
+
let closed = false;
|
|
644
|
+
return {
|
|
645
|
+
next() {
|
|
646
|
+
if (closed) return Promise.resolve({ done: true, value: undefined });
|
|
647
|
+
start?.resolve();
|
|
648
|
+
return iteratorPromise.then((inner) => {
|
|
649
|
+
if (closed) return { done: true, value: undefined };
|
|
650
|
+
checkActive?.();
|
|
651
|
+
return inner.next();
|
|
652
|
+
});
|
|
653
|
+
},
|
|
654
|
+
return(value?: any) {
|
|
655
|
+
closed = true;
|
|
656
|
+
if (!settled) controller?.abort();
|
|
657
|
+
iteratorPromise.then(
|
|
658
|
+
(inner) => (inner as any).return?.(value),
|
|
659
|
+
() => {}
|
|
660
|
+
);
|
|
661
|
+
return Promise.resolve({ done: true, value });
|
|
662
|
+
},
|
|
663
|
+
};
|
|
664
|
+
};
|
|
665
|
+
return results;
|
|
666
|
+
}
|
|
667
|
+
return processEntries(searched);
|
|
533
668
|
}
|
|
534
|
-
|
|
669
|
+
const scanned = index.getRange(rangeOptions).map(
|
|
535
670
|
filter
|
|
536
671
|
? function ({ key, value }) {
|
|
537
672
|
let recordMatcher: any;
|
|
@@ -554,6 +689,14 @@ export function searchByIndex(
|
|
|
554
689
|
}
|
|
555
690
|
: ({ value }) => value
|
|
556
691
|
);
|
|
692
|
+
// Collapsing AFTER the map is required, not incidental: the condition's own filter tests one
|
|
693
|
+
// element at a time, so a record whose first entry fails it and whose second passes must
|
|
694
|
+
// still be reached. Collapsing first would settle that record on the failing entry and drop
|
|
695
|
+
// it. Scoped to attributes the schema declares multi-valued; a runtime array under an
|
|
696
|
+
// undeclared attribute repeats the same way but stays outside this boundary.
|
|
697
|
+
return scansOneIndexedValue || !findAttribute(Table.attributes, attribute_name)?.elements
|
|
698
|
+
? scanned
|
|
699
|
+
: distinctRecords(scanned);
|
|
557
700
|
} else {
|
|
558
701
|
return Table.primaryStore
|
|
559
702
|
.getRange(reverse ? { end: true, transaction, reverse: true } : { start: true, transaction })
|
|
@@ -1112,6 +1255,91 @@ export function filterByType(searchCondition, Table, context, filtered, isPrimar
|
|
|
1112
1255
|
}
|
|
1113
1256
|
}
|
|
1114
1257
|
|
|
1258
|
+
/**
|
|
1259
|
+
* Estimates a range comparator's entry count from the store's statistical estimate, blended with
|
|
1260
|
+
* the table-fraction heuristic by the estimate's confidence so low-confidence estimates degrade
|
|
1261
|
+
* to the old behavior. Returns undefined (caller falls back to the heuristic) when the store
|
|
1262
|
+
* cannot estimate, the shape is unexpected, or the executed range wouldn't match this one.
|
|
1263
|
+
*/
|
|
1264
|
+
function estimateRangeCondition(table, condition, searchType, fraction) {
|
|
1265
|
+
const attributeName = condition[0] ?? condition.attribute;
|
|
1266
|
+
const isPrimaryKey = attributeName === table.primaryKey;
|
|
1267
|
+
const store = isPrimaryKey ? table.primaryStore : usableIndex(table, attributeName);
|
|
1268
|
+
// LMDB-backed and custom index stores do not implement estimateCount
|
|
1269
|
+
if (typeof store?.estimateCount !== 'function') return undefined;
|
|
1270
|
+
let value = condition[1] ?? condition.value;
|
|
1271
|
+
if (value instanceof Date) value = value.getTime();
|
|
1272
|
+
let range;
|
|
1273
|
+
switch (searchType) {
|
|
1274
|
+
case 'lt':
|
|
1275
|
+
// `start: true` mirrors searchByIndex: `true` sorts above `null`, so an indexNulls
|
|
1276
|
+
// index's `[null, primaryKey]` entries are outside the executed range
|
|
1277
|
+
range = { start: true, end: value };
|
|
1278
|
+
break;
|
|
1279
|
+
case 'le':
|
|
1280
|
+
range = { start: true, end: value, inclusiveEnd: true };
|
|
1281
|
+
break;
|
|
1282
|
+
case 'gt':
|
|
1283
|
+
range = { start: value, exclusiveStart: true };
|
|
1284
|
+
break;
|
|
1285
|
+
case 'ge':
|
|
1286
|
+
range = { start: value };
|
|
1287
|
+
break;
|
|
1288
|
+
case 'between':
|
|
1289
|
+
case 'gele':
|
|
1290
|
+
case 'gelt':
|
|
1291
|
+
case 'gtlt':
|
|
1292
|
+
case 'gtle': {
|
|
1293
|
+
if (!Array.isArray(value)) return undefined;
|
|
1294
|
+
let [start, end] = value;
|
|
1295
|
+
if (start instanceof Date) start = start.getTime();
|
|
1296
|
+
if (end instanceof Date) end = end.getTime();
|
|
1297
|
+
range = {
|
|
1298
|
+
start,
|
|
1299
|
+
end,
|
|
1300
|
+
inclusiveEnd: searchType === 'between' || searchType === 'gele' || searchType === 'gtle',
|
|
1301
|
+
exclusiveStart: searchType === 'gtlt' || searchType === 'gtle',
|
|
1302
|
+
};
|
|
1303
|
+
break;
|
|
1304
|
+
}
|
|
1305
|
+
case 'starts_with': {
|
|
1306
|
+
const prefix = value?.toString();
|
|
1307
|
+
if (!prefix) return undefined;
|
|
1308
|
+
range = { start: prefix, end: getStringPrefixUpperBound(prefix) };
|
|
1309
|
+
break;
|
|
1310
|
+
}
|
|
1311
|
+
case 'prefix': {
|
|
1312
|
+
let start = Array.isArray(value) ? value : [value, null];
|
|
1313
|
+
if (start[start.length - 1] != null) start = start.concat(null);
|
|
1314
|
+
const end = start.slice(0);
|
|
1315
|
+
end[end.length - 1] = MAXIMUM_KEY;
|
|
1316
|
+
range = { start, end };
|
|
1317
|
+
break;
|
|
1318
|
+
}
|
|
1319
|
+
default:
|
|
1320
|
+
return undefined;
|
|
1321
|
+
}
|
|
1322
|
+
// Long string bounds get truncated + filtered at execution (searchByIndex), so the
|
|
1323
|
+
// executed range is wider than this one; don't estimate what won't be iterated.
|
|
1324
|
+
if (
|
|
1325
|
+
(typeof range.start === 'string' && range.start.length > MAX_SEARCH_KEY_LENGTH) ||
|
|
1326
|
+
(typeof range.end === 'string' && range.end.length > MAX_SEARCH_KEY_LENGTH)
|
|
1327
|
+
) {
|
|
1328
|
+
return undefined;
|
|
1329
|
+
}
|
|
1330
|
+
let count, confidence;
|
|
1331
|
+
try {
|
|
1332
|
+
({ count, confidence } = store.estimateCount(range) ?? {});
|
|
1333
|
+
} catch {
|
|
1334
|
+
// a concurrently closing/dropped store must degrade the plan, not fail the query
|
|
1335
|
+
return undefined;
|
|
1336
|
+
}
|
|
1337
|
+
if (!Number.isFinite(count) || count < 0 || !Number.isFinite(confidence) || confidence < 0 || confidence > 1)
|
|
1338
|
+
return undefined;
|
|
1339
|
+
const heuristic = fraction * estimatedEntryCount(table.primaryStore) + 1;
|
|
1340
|
+
return Math.max(1, Math.round(confidence * count + (1 - confidence) * heuristic));
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1115
1343
|
/** The index a condition can be driven by; searchByIndex refuses a rebuilding one, so it reads as absent. */
|
|
1116
1344
|
function usableIndex(table, attributeName): any {
|
|
1117
1345
|
const index = attributeName == null ? undefined : table.indices[attributeName];
|
|
@@ -1166,6 +1394,13 @@ export function estimateCondition(table) {
|
|
|
1166
1394
|
// before comparator dispatch: several branches fall back to a finite table-fraction heuristic
|
|
1167
1395
|
if (drivesRebuildingIndex(table, condition[0] ?? condition.attribute)) {
|
|
1168
1396
|
condition.estimated_count = Infinity;
|
|
1397
|
+
} else if (condition.negated) {
|
|
1398
|
+
// a negated condition always executes as a full scan (searchByIndex forces
|
|
1399
|
+
// needFullScan), so follow the filter-only convention used by contains/ends_with:
|
|
1400
|
+
// estimate Infinity so its positive-range estimate can never win the driving-condition
|
|
1401
|
+
// ordering. Short-circuit here rather than computing (and discarding) a positive-range
|
|
1402
|
+
// estimate that would cross the native FFI boundary for nothing.
|
|
1403
|
+
condition.estimated_count = Infinity;
|
|
1169
1404
|
} else if (searchType === SEARCH_TYPES.EQUALS || !searchType) {
|
|
1170
1405
|
const attribute_name = condition[0] ?? condition.attribute;
|
|
1171
1406
|
if (attribute_name == null || attribute_name === table.primaryKey) condition.estimated_count = 1;
|
|
@@ -1217,11 +1452,14 @@ export function estimateCondition(table) {
|
|
|
1217
1452
|
} else if (Array.isArray(condition.value)) {
|
|
1218
1453
|
condition.estimated_count = Infinity;
|
|
1219
1454
|
} else condition.estimated_count = Infinity;
|
|
1220
|
-
// for range queries (betweens, startsWith, greater, etc.), just arbitrarily guess
|
|
1221
1455
|
} else if (searchType === 'starts_with' || searchType === 'prefix')
|
|
1222
|
-
condition.estimated_count =
|
|
1456
|
+
condition.estimated_count =
|
|
1457
|
+
estimateRangeCondition(table, condition, searchType, STARTS_WITH_ESTIMATE) ??
|
|
1458
|
+
STARTS_WITH_ESTIMATE * estimatedEntryCount(table.primaryStore) + 1;
|
|
1223
1459
|
else if (searchType === 'between')
|
|
1224
|
-
condition.estimated_count =
|
|
1460
|
+
condition.estimated_count =
|
|
1461
|
+
estimateRangeCondition(table, condition, searchType, BETWEEN_ESTIMATE) ??
|
|
1462
|
+
BETWEEN_ESTIMATE * estimatedEntryCount(table.primaryStore) + 1;
|
|
1225
1463
|
else if (searchType === 'sort') {
|
|
1226
1464
|
const attribute_name = condition[0] ?? condition.attribute;
|
|
1227
1465
|
const index = usableIndex(table, attribute_name);
|
|
@@ -1236,7 +1474,10 @@ export function estimateCondition(table) {
|
|
|
1236
1474
|
if (index?.customIndex?.estimateCount)
|
|
1237
1475
|
// allow custom index to define its own estimation of counts
|
|
1238
1476
|
condition.estimated_count = index.customIndex.estimateCount(condition.value);
|
|
1239
|
-
else
|
|
1477
|
+
else
|
|
1478
|
+
condition.estimated_count =
|
|
1479
|
+
estimateRangeCondition(table, condition, searchType, OPEN_RANGE_ESTIMATE) ??
|
|
1480
|
+
OPEN_RANGE_ESTIMATE * estimatedEntryCount(table.primaryStore) + 1;
|
|
1240
1481
|
}
|
|
1241
1482
|
// we give a condition significantly more weight/preference if we will be ordering by it
|
|
1242
1483
|
if (typeof condition.descending === 'boolean') condition.estimated_count /= 2;
|
|
@@ -1422,6 +1663,7 @@ function parseBlock(query, expectedEnd) {
|
|
|
1422
1663
|
break;
|
|
1423
1664
|
case 'group-by':
|
|
1424
1665
|
recordError('group by is not implemented yet');
|
|
1666
|
+
break;
|
|
1425
1667
|
case 'sort':
|
|
1426
1668
|
query.sort = toSortObject(args);
|
|
1427
1669
|
break;
|
package/resources/tracked.ts
CHANGED
|
@@ -3,7 +3,15 @@ import * as crdtOperations from './crdt.ts';
|
|
|
3
3
|
import { Blob } from './blob.ts';
|
|
4
4
|
import * as harperLogger from '../utility/logging/harper_logger.ts';
|
|
5
5
|
|
|
6
|
+
export const ASSERT_TRACKED_WRITABLE = Symbol('assert-tracked-writable');
|
|
7
|
+
export const GET_TRACKED_WRITE_GENERATION = Symbol('get-tracked-write-generation');
|
|
8
|
+
|
|
9
|
+
function assertWritable(target, generation?) {
|
|
10
|
+
target[ASSERT_TRACKED_WRITABLE]?.(generation);
|
|
11
|
+
}
|
|
12
|
+
|
|
6
13
|
function getChanges(target) {
|
|
14
|
+
assertWritable(target);
|
|
7
15
|
let changes = target.getChanges();
|
|
8
16
|
if (!changes) {
|
|
9
17
|
changes = Object.create(null);
|
|
@@ -49,6 +57,7 @@ export function assignTrackedAccessors(Target, typeDef, useFullPropertyProxy = f
|
|
|
49
57
|
// still load), this is a user assignment to a resolved attribute, and a read-only resolver
|
|
50
58
|
// (a scalar @computed has no attribute.set) has nowhere to put it (harper#2359).
|
|
51
59
|
if (!attribute.set) throw new ClientError(`${name} is a computed attribute and can not be assigned`);
|
|
60
|
+
assertWritable(this);
|
|
52
61
|
return attribute.set(this, related);
|
|
53
62
|
},
|
|
54
63
|
configurable: true,
|
|
@@ -188,7 +197,7 @@ export function assignTrackedAccessors(Target, typeDef, useFullPropertyProxy = f
|
|
|
188
197
|
}
|
|
189
198
|
const sourceValue = this.getRecord()?.[name];
|
|
190
199
|
if (sourceValue && typeof sourceValue === 'object') {
|
|
191
|
-
const updatedValue = trackObject(sourceValue, attribute);
|
|
200
|
+
const updatedValue = trackObject(sourceValue, attribute, this);
|
|
192
201
|
if (updatedValue) {
|
|
193
202
|
if (!changes) {
|
|
194
203
|
this._setChanges((changes = Object.create(null)));
|
|
@@ -288,7 +297,7 @@ function getProxiedProperty(target, name, receiver) {
|
|
|
288
297
|
}
|
|
289
298
|
const sourceValue = receiver.getRecord?.()?.[name];
|
|
290
299
|
if (sourceValue && typeof sourceValue === 'object') {
|
|
291
|
-
const updatedValue = trackObject(sourceValue);
|
|
300
|
+
const updatedValue = trackObject(sourceValue, undefined, receiver);
|
|
292
301
|
if (updatedValue) {
|
|
293
302
|
if (!changes) {
|
|
294
303
|
changes = Object.create(null);
|
|
@@ -303,6 +312,7 @@ function getProxiedProperty(target, name, receiver) {
|
|
|
303
312
|
}
|
|
304
313
|
function setProxiedProperty(target: any, name: string | symbol, value, receiver) {
|
|
305
314
|
if (typeof name === 'string') {
|
|
315
|
+
assertWritable(receiver);
|
|
306
316
|
let changes = receiver.getChanges?.();
|
|
307
317
|
if (!changes) {
|
|
308
318
|
changes = {};
|
|
@@ -315,7 +325,7 @@ function setProxiedProperty(target: any, name: string | symbol, value, receiver)
|
|
|
315
325
|
return true;
|
|
316
326
|
}
|
|
317
327
|
|
|
318
|
-
function trackObject(sourceObject: any, typeDef?: any) {
|
|
328
|
+
function trackObject(sourceObject: any, typeDef?: any, writableOwner?: any) {
|
|
319
329
|
// lazily instantiate in case of recursive structures
|
|
320
330
|
let TrackedObject;
|
|
321
331
|
switch (sourceObject.constructor) {
|
|
@@ -326,18 +336,41 @@ function trackObject(sourceObject: any, typeDef?: any) {
|
|
|
326
336
|
typeDef.TrackedObject = TrackedObject = class extends GenericTrackedObject {};
|
|
327
337
|
assignTrackedAccessors(TrackedObject, typeDef);
|
|
328
338
|
}
|
|
329
|
-
return new TrackedObject(sourceObject);
|
|
339
|
+
return new TrackedObject(sourceObject, writableOwner);
|
|
330
340
|
} else {
|
|
331
|
-
return new GenericTrackedObject(sourceObject);
|
|
341
|
+
return new GenericTrackedObject(sourceObject, writableOwner);
|
|
332
342
|
}
|
|
333
343
|
case Array:
|
|
334
|
-
const trackedArray = new TrackedArray(sourceObject.length, sourceObject);
|
|
344
|
+
const trackedArray = new TrackedArray(sourceObject.length, sourceObject, writableOwner);
|
|
335
345
|
for (let i = 0, l = sourceObject.length; i < l; i++) {
|
|
336
346
|
let element = sourceObject[i];
|
|
337
|
-
if (element && typeof element === 'object') element = trackObject(element, typeDef?.elements);
|
|
347
|
+
if (element && typeof element === 'object') element = trackObject(element, typeDef?.elements, trackedArray);
|
|
338
348
|
trackedArray[i] = element;
|
|
339
349
|
}
|
|
340
|
-
return trackedArray;
|
|
350
|
+
if (!writableOwner) return trackedArray;
|
|
351
|
+
return new Proxy(trackedArray, {
|
|
352
|
+
set(target, name, value) {
|
|
353
|
+
if (typeof name === 'string') {
|
|
354
|
+
assertWritable(target);
|
|
355
|
+
target[HAS_ARRAY_CHANGES] = true;
|
|
356
|
+
}
|
|
357
|
+
return Reflect.set(target, name, value, target);
|
|
358
|
+
},
|
|
359
|
+
defineProperty(target, name, descriptor) {
|
|
360
|
+
if (typeof name === 'string') {
|
|
361
|
+
assertWritable(target);
|
|
362
|
+
target[HAS_ARRAY_CHANGES] = true;
|
|
363
|
+
}
|
|
364
|
+
return Reflect.defineProperty(target, name, descriptor);
|
|
365
|
+
},
|
|
366
|
+
deleteProperty(target, name) {
|
|
367
|
+
if (typeof name === 'string') {
|
|
368
|
+
assertWritable(target);
|
|
369
|
+
target[HAS_ARRAY_CHANGES] = true;
|
|
370
|
+
}
|
|
371
|
+
return Reflect.deleteProperty(target, name);
|
|
372
|
+
},
|
|
373
|
+
});
|
|
341
374
|
// any other objects (like Date) are left unchanged
|
|
342
375
|
default:
|
|
343
376
|
return sourceObject;
|
|
@@ -346,10 +379,20 @@ function trackObject(sourceObject: any, typeDef?: any) {
|
|
|
346
379
|
export class GenericTrackedObject<T extends object = any> {
|
|
347
380
|
#record: T;
|
|
348
381
|
#changes: Partial<T>;
|
|
349
|
-
|
|
382
|
+
#writableOwner: any;
|
|
383
|
+
#writableGeneration: any;
|
|
384
|
+
constructor(sourceObject?: GenericTrackedObject<T> | T, writableOwner?: any) {
|
|
350
385
|
if ((sourceObject as GenericTrackedObject<T>)?.getRecord)
|
|
351
386
|
throw new Error('Can not track an already tracked object, check for circular references');
|
|
352
387
|
this.#record = sourceObject as any;
|
|
388
|
+
this.#writableOwner = writableOwner;
|
|
389
|
+
this.#writableGeneration = writableOwner?.[GET_TRACKED_WRITE_GENERATION]?.();
|
|
390
|
+
}
|
|
391
|
+
[ASSERT_TRACKED_WRITABLE]() {
|
|
392
|
+
this.#writableOwner?.[ASSERT_TRACKED_WRITABLE]?.(this.#writableGeneration);
|
|
393
|
+
}
|
|
394
|
+
[GET_TRACKED_WRITE_GENERATION]() {
|
|
395
|
+
return this.#writableGeneration;
|
|
353
396
|
}
|
|
354
397
|
getRecord(): T {
|
|
355
398
|
return this.#record;
|
|
@@ -404,18 +447,13 @@ export function updateAndFreeze(target, changes = target.getChanges?.()) {
|
|
|
404
447
|
let mergedUpdatedObject: any;
|
|
405
448
|
if (!target) return changes;
|
|
406
449
|
if (target.getRecord && target.constructor === Array && !Object.isFrozen(target)) {
|
|
407
|
-
|
|
408
|
-
|
|
450
|
+
if (!hasChanges(target)) return (target as any).getRecord();
|
|
451
|
+
// Materialize a plain array so the stored value retains neither the mutation proxy nor its owner.
|
|
452
|
+
mergedUpdatedObject = new Array(target.length);
|
|
409
453
|
for (let i = 0, l = target.length; i < l; i++) {
|
|
410
454
|
let value = target[i];
|
|
411
455
|
if (value && typeof value === 'object') {
|
|
412
|
-
|
|
413
|
-
if (newValue !== value && mergedUpdatedObject === target) {
|
|
414
|
-
// if we need to make any changes to the user's array, we make a copy so we don't modify
|
|
415
|
-
// an array that the user may be using with transient properties
|
|
416
|
-
mergedUpdatedObject = target.slice(0);
|
|
417
|
-
}
|
|
418
|
-
value = newValue;
|
|
456
|
+
value = updateAndFreeze(value);
|
|
419
457
|
}
|
|
420
458
|
mergedUpdatedObject[i] = value;
|
|
421
459
|
}
|
|
@@ -493,15 +531,28 @@ export function hasChanges(target) {
|
|
|
493
531
|
}
|
|
494
532
|
|
|
495
533
|
const HAS_ARRAY_CHANGES = Symbol.for('has-array-changes');
|
|
534
|
+
const TRACKED_ARRAY_RECORD = Symbol('tracked-array-record');
|
|
535
|
+
const TRACKED_WRITABLE_OWNER = Symbol('tracked-writable-owner');
|
|
536
|
+
const TRACKED_WRITABLE_GENERATION = Symbol('tracked-writable-generation');
|
|
496
537
|
class TrackedArray extends Array {
|
|
497
|
-
|
|
538
|
+
[TRACKED_ARRAY_RECORD]: any;
|
|
539
|
+
[TRACKED_WRITABLE_OWNER]: any;
|
|
540
|
+
[TRACKED_WRITABLE_GENERATION]: any;
|
|
498
541
|
[HAS_ARRAY_CHANGES]: boolean;
|
|
499
|
-
constructor(length, record) {
|
|
542
|
+
constructor(length, record, writableOwner) {
|
|
500
543
|
super(length);
|
|
501
|
-
this
|
|
544
|
+
this[TRACKED_ARRAY_RECORD] = record;
|
|
545
|
+
this[TRACKED_WRITABLE_OWNER] = writableOwner;
|
|
546
|
+
this[TRACKED_WRITABLE_GENERATION] = writableOwner?.[GET_TRACKED_WRITE_GENERATION]?.();
|
|
547
|
+
}
|
|
548
|
+
[ASSERT_TRACKED_WRITABLE]() {
|
|
549
|
+
this[TRACKED_WRITABLE_OWNER]?.[ASSERT_TRACKED_WRITABLE]?.(this[TRACKED_WRITABLE_GENERATION]);
|
|
550
|
+
}
|
|
551
|
+
[GET_TRACKED_WRITE_GENERATION]() {
|
|
552
|
+
return this[TRACKED_WRITABLE_GENERATION];
|
|
502
553
|
}
|
|
503
554
|
getRecord() {
|
|
504
|
-
return this
|
|
555
|
+
return this[TRACKED_ARRAY_RECORD];
|
|
505
556
|
}
|
|
506
557
|
splice(...args) {
|
|
507
558
|
this[HAS_ARRAY_CHANGES] = true;
|
|
@@ -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];
|