@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/dataLayer/blobBackup.ts
CHANGED
|
@@ -5,6 +5,12 @@ import { copyFile, link, mkdir, readdir, rename, rm, unlink, writeFile } from 'n
|
|
|
5
5
|
import { dirname, join, relative } from 'node:path';
|
|
6
6
|
import { ClientError } from '../utility/errors/hdbError.ts';
|
|
7
7
|
import logger from '../utility/logging/harper_logger.ts';
|
|
8
|
+
import {
|
|
9
|
+
type BlobCaptureDisposition,
|
|
10
|
+
classifyBlobFileForCapture,
|
|
11
|
+
createCaptureMarker,
|
|
12
|
+
isSystemicIoError,
|
|
13
|
+
} from '../resources/blob.ts';
|
|
8
14
|
|
|
9
15
|
/**
|
|
10
16
|
* Managed-backup snapshotting of a database's file-backed blobs.
|
|
@@ -21,17 +27,17 @@ import logger from '../utility/logging/harper_logger.ts';
|
|
|
21
27
|
* possible (cheap, no extra space on the same filesystem) and copied otherwise (never symlinked, so
|
|
22
28
|
* a snapshot is a standalone set of files that survives independent of the live blob).
|
|
23
29
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
30
|
+
* Harper does not freeze blob writes for a backup, and a blob is written in place at its final path,
|
|
31
|
+
* so the walk can meet one that is still growing. Hard-linking that inode would put bytes in the
|
|
32
|
+
* snapshot that keep changing after it was taken. Every entry returned by the walk is therefore
|
|
33
|
+
* classified (`captureBlobFile`): a complete blob is linked, and one that becomes unavailable or is
|
|
34
|
+
* not yet complete is replaced by a marker rather than dropped. This closes the classify-to-capture
|
|
35
|
+
* race and keeps that file id reserved; a file reclaimed before its parent directory is read remains
|
|
36
|
+
* outside the snapshot.
|
|
29
37
|
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
* bytes alive even after the live blob is deleted, and no in-place overwrite can retroactively alter
|
|
34
|
-
* a snapshot.
|
|
38
|
+
* Past that gate, hard-linking is safe against later mutation: each write takes a fresh monotonic
|
|
39
|
+
* file id, and an update, delete, or in-place repair replaces or unlinks the path rather than
|
|
40
|
+
* rewriting the inode.
|
|
35
41
|
*/
|
|
36
42
|
|
|
37
43
|
/** Directory holding all blob snapshots for a backup repository. */
|
|
@@ -46,17 +52,17 @@ export function blobSnapshotDir(backupDir: string, backupId: number): string {
|
|
|
46
52
|
|
|
47
53
|
/**
|
|
48
54
|
* Hard-link `src` to `dest`, falling back to a copy when the two are on different filesystems (or
|
|
49
|
-
* the filesystem does not support additional hard links). Never creates a symlink.
|
|
50
|
-
*
|
|
55
|
+
* the filesystem does not support additional hard links). Never creates a symlink. Returns false
|
|
56
|
+
* when the source vanishes so the caller can substitute a marker for it. `counts.copied` is what a
|
|
57
|
+
* caller on a latency budget needs: the fallback turns a constant-time clone into an O(bytes) one.
|
|
51
58
|
*/
|
|
52
|
-
async function linkOrCopy(src: string, dest: string): Promise<
|
|
59
|
+
async function linkOrCopy(src: string, dest: string, counts?: { copied: number }): Promise<boolean> {
|
|
53
60
|
await mkdir(dirname(dest), { recursive: true });
|
|
54
61
|
try {
|
|
55
62
|
await link(src, dest);
|
|
56
63
|
} catch (error: any) {
|
|
57
64
|
if (error.code === 'ENOENT') {
|
|
58
|
-
|
|
59
|
-
if (!existsSync(src)) return;
|
|
65
|
+
if (!existsSync(src)) return false; // vanished since it was classified
|
|
60
66
|
throw error;
|
|
61
67
|
}
|
|
62
68
|
if (
|
|
@@ -66,24 +72,86 @@ async function linkOrCopy(src: string, dest: string): Promise<void> {
|
|
|
66
72
|
error.code === 'ENOTSUP' ||
|
|
67
73
|
error.code === 'EOPNOTSUPP'
|
|
68
74
|
) {
|
|
69
|
-
|
|
70
|
-
|
|
75
|
+
try {
|
|
76
|
+
await copyFile(src, dest);
|
|
77
|
+
} catch (copyError: any) {
|
|
78
|
+
if (copyError.code === 'ENOENT') return false;
|
|
79
|
+
throw copyError;
|
|
80
|
+
}
|
|
81
|
+
if (counts) counts.copied++;
|
|
82
|
+
return true;
|
|
71
83
|
}
|
|
72
84
|
if (error.code === 'EEXIST') {
|
|
73
85
|
await unlink(dest);
|
|
74
|
-
|
|
75
|
-
return;
|
|
86
|
+
return linkOrCopy(src, dest, counts);
|
|
76
87
|
}
|
|
77
88
|
throw error;
|
|
78
89
|
}
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** What a substituted marker says happened, so a branch clone doesn't report itself as a backup. */
|
|
94
|
+
export interface CaptureMarkerReasons {
|
|
95
|
+
gone: string;
|
|
96
|
+
pending: string;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const BACKUP_MARKER_REASONS: CaptureMarkerReasons = {
|
|
100
|
+
gone: 'blob was deleted while this backup was being taken',
|
|
101
|
+
pending: 'blob was not yet complete when this backup was taken',
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
/** Put one blob file into the destination, returning how the entry was captured. */
|
|
105
|
+
async function captureBlobFile(
|
|
106
|
+
srcPath: string,
|
|
107
|
+
destPath: string,
|
|
108
|
+
reasons: CaptureMarkerReasons = BACKUP_MARKER_REASONS,
|
|
109
|
+
counts?: { copied: number }
|
|
110
|
+
): Promise<BlobCaptureDisposition> {
|
|
111
|
+
let disposition: BlobCaptureDisposition;
|
|
112
|
+
try {
|
|
113
|
+
disposition = await classifyBlobFileForCapture(srcPath);
|
|
114
|
+
} catch (error) {
|
|
115
|
+
// This rethrow is unverified: only the membership of SYSTEMIC_IO_ERRORS is tested, because
|
|
116
|
+
// reaching it needs a real host-level fault no test here can produce.
|
|
117
|
+
if (isSystemicIoError(error)) throw error;
|
|
118
|
+
// Fall back to what this walk did before it classified anything. `link()` needs no read permission
|
|
119
|
+
// on the source, so a blob this failed to *read* may still be perfectly capturable; substituting
|
|
120
|
+
// here would turn an unreadable-but-valid root into a backup of nothing but stubs.
|
|
121
|
+
logger.warn(`Could not verify blob ${srcPath} for snapshot; capturing it unverified`, error);
|
|
122
|
+
disposition = 'capture';
|
|
123
|
+
}
|
|
124
|
+
if (disposition === 'skip') return disposition;
|
|
125
|
+
if (disposition === 'capture') {
|
|
126
|
+
if (await linkOrCopy(srcPath, destPath, counts)) return disposition;
|
|
127
|
+
disposition = 'gone';
|
|
128
|
+
}
|
|
129
|
+
await mkdir(dirname(destPath), { recursive: true });
|
|
130
|
+
await writeFile(destPath, createCaptureMarker(disposition, disposition === 'gone' ? reasons.gone : reasons.pending));
|
|
131
|
+
return disposition;
|
|
79
132
|
}
|
|
80
133
|
|
|
81
134
|
/**
|
|
82
135
|
* Recursively copy every file under `srcRoot` into `destRoot` (hard-link-else-copy), preserving the
|
|
83
136
|
* relative directory structure. Missing `srcRoot` is a no-op (a database with no blobs yet).
|
|
137
|
+
*
|
|
138
|
+
* `classify` substitutes a marker for a file that is mid-write or already gone, so the destination
|
|
139
|
+
* fails loudly on that blob rather than carrying a truncated one. It belongs to the capture direction
|
|
140
|
+
* only; restore must replace exactly what the snapshot holds.
|
|
141
|
+
*
|
|
142
|
+
* Also used by branch materialization (harper#644), which clones a base's blob roots into the
|
|
143
|
+
* branch's own so the OS inode refcount does the reference counting. Its walk runs inside a window
|
|
144
|
+
* other threads wait on, which is what `onProgress` is for.
|
|
84
145
|
*/
|
|
85
|
-
async function copyTree(
|
|
86
|
-
|
|
146
|
+
export async function copyTree(
|
|
147
|
+
srcRoot: string,
|
|
148
|
+
destRoot: string,
|
|
149
|
+
classify = false,
|
|
150
|
+
reasons?: CaptureMarkerReasons,
|
|
151
|
+
onProgress?: () => void
|
|
152
|
+
): Promise<{ substituted: number; captured: number; copied: number }> {
|
|
153
|
+
const counts = { substituted: 0, captured: 0, copied: 0 };
|
|
154
|
+
if (!existsSync(srcRoot)) return counts;
|
|
87
155
|
const stack: string[] = [srcRoot];
|
|
88
156
|
while (stack.length > 0) {
|
|
89
157
|
const dir = stack.pop() as string;
|
|
@@ -99,63 +167,103 @@ async function copyTree(srcRoot: string, destRoot: string): Promise<void> {
|
|
|
99
167
|
if (entry.isDirectory()) {
|
|
100
168
|
stack.push(srcPath);
|
|
101
169
|
} else if (entry.isFile()) {
|
|
102
|
-
|
|
170
|
+
const destPath = join(destRoot, relative(srcRoot, srcPath));
|
|
171
|
+
if (classify) {
|
|
172
|
+
const disposition = await captureBlobFile(srcPath, destPath, reasons, counts);
|
|
173
|
+
if (disposition === 'pending' || disposition === 'gone') counts.substituted++;
|
|
174
|
+
else if (disposition === 'capture') counts.captured++;
|
|
175
|
+
} else {
|
|
176
|
+
await linkOrCopy(srcPath, destPath, counts);
|
|
177
|
+
}
|
|
178
|
+
onProgress?.();
|
|
103
179
|
}
|
|
104
180
|
// symlinks/other node types in a blob root are not expected and are intentionally skipped
|
|
105
181
|
}
|
|
106
182
|
}
|
|
183
|
+
return counts;
|
|
107
184
|
}
|
|
108
185
|
|
|
109
186
|
/**
|
|
110
|
-
*
|
|
111
|
-
* and atomically renames into place so a
|
|
112
|
-
*
|
|
113
|
-
*
|
|
187
|
+
* Copy every blob root into `destDir` as `<rootIndex>/<relpath>`, hard-linking where possible.
|
|
188
|
+
* Writes to a temporary sibling and atomically renames into place so a run that fails mid-copy never
|
|
189
|
+
* leaves a partial directory a later restore would trust, and replaces any pre-existing `destDir`.
|
|
190
|
+
* Shared by managed-backup snapshots and `copy-db`'s standalone blob copy (harper#2048).
|
|
114
191
|
*/
|
|
115
|
-
export async function
|
|
116
|
-
const
|
|
117
|
-
const tempDir = join(blobsRootDir(backupDir), `.tmp-${backupId}`);
|
|
192
|
+
export async function copyBlobRootsByIndex(destDir: string, blobRoots: string[]): Promise<void> {
|
|
193
|
+
const tempDir = destDir + '.tmp';
|
|
118
194
|
await rm(tempDir, { recursive: true, force: true });
|
|
119
195
|
await mkdir(tempDir, { recursive: true });
|
|
120
196
|
try {
|
|
197
|
+
let substituted = 0;
|
|
198
|
+
let captured = 0;
|
|
121
199
|
for (let index = 0; index < blobRoots.length; index++) {
|
|
122
|
-
await copyTree(blobRoots[index], join(tempDir, String(index)));
|
|
200
|
+
const counts = await copyTree(blobRoots[index], join(tempDir, String(index)), true);
|
|
201
|
+
substituted += counts.substituted;
|
|
202
|
+
captured += counts.captured;
|
|
123
203
|
}
|
|
124
|
-
|
|
125
|
-
|
|
204
|
+
if (substituted > 0) {
|
|
205
|
+
logger.warn(
|
|
206
|
+
`Blob copy into ${destDir} substituted ${substituted} of ${substituted + captured} blob ` +
|
|
207
|
+
`file(s) with PENDING or ERROR markers because they were not capturable whole.`
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
await rm(destDir, { recursive: true, force: true });
|
|
211
|
+
await rename(tempDir, destDir);
|
|
126
212
|
} catch (error) {
|
|
127
213
|
await rm(tempDir, { recursive: true, force: true }).catch(() => {});
|
|
128
214
|
throw error;
|
|
129
215
|
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Snapshot a database's blob roots into a backup's blob directory. Overwrites any pre-existing
|
|
220
|
+
* snapshot for the same id (create_backup always produces a fresh id, so this only matters on a
|
|
221
|
+
* retried offline run).
|
|
222
|
+
*/
|
|
223
|
+
export async function snapshotBlobs(backupDir: string, backupId: number, blobRoots: string[]): Promise<void> {
|
|
224
|
+
await copyBlobRootsByIndex(blobSnapshotDir(backupDir, backupId), blobRoots);
|
|
130
225
|
await writeBlobsReadme(backupDir, blobRoots);
|
|
131
226
|
}
|
|
132
227
|
|
|
133
228
|
/**
|
|
134
229
|
* Build the `blobs/README.md` documenting the blob snapshot layout, so an operator inspecting or
|
|
135
|
-
* hand-recovering a backup can decode the numeric directories.
|
|
136
|
-
* - managed (default): a create_backup repository, where snapshots are keyed by backup id
|
|
230
|
+
* hand-recovering a backup can decode the numeric directories. Three variants:
|
|
231
|
+
* - `managed` (default): a create_backup repository, where snapshots are keyed by backup id
|
|
137
232
|
* (`<backupId>/<rootIndex>/…`) and restore is automatic via `restore_backup`.
|
|
138
|
-
* -
|
|
139
|
-
*
|
|
233
|
+
* - `archive`: a downloaded `get_backup` tar, which holds a single snapshot with no backup-id level
|
|
234
|
+
* (`<rootIndex>/…`) and is restored by extracting the files back into the roots.
|
|
235
|
+
* - `copy`: the companion directory `copy-db` writes beside a database copy, restored by hand.
|
|
140
236
|
*/
|
|
141
|
-
export function blobsReadmeContent(
|
|
237
|
+
export function blobsReadmeContent(
|
|
238
|
+
blobRoots: string[],
|
|
239
|
+
{ variant = 'managed' }: { variant?: 'managed' | 'archive' | 'copy' } = {}
|
|
240
|
+
): string {
|
|
142
241
|
const rootMapping =
|
|
143
242
|
blobRoots.length > 0 ? blobRoots.map((root, index) => ` ${index} -> ${root}`).join('\n') : ' (none)';
|
|
144
|
-
const layout =
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
243
|
+
const layout =
|
|
244
|
+
variant === 'managed'
|
|
245
|
+
? '<backupId>/<rootIndex>/<shard1>/<shard2>/<fileId>'
|
|
246
|
+
: '<rootIndex>/<shard1>/<shard2>/<fileId>';
|
|
247
|
+
const intro =
|
|
248
|
+
variant === 'copy'
|
|
249
|
+
? `This directory holds the file-backed blobs of a \`copy-db\` database copy; the database file itself
|
|
250
|
+
is the sibling \`.mdb\` this directory is named after. Blobs are addressed by database NAME and the
|
|
251
|
+
configured blob roots — never by the database file's path — so a copy is only restorable with these
|
|
252
|
+
files: put each \`<rootIndex>/\` tree into the matching blob root of whatever database name you
|
|
253
|
+
restore the copy as (mapping below).`
|
|
254
|
+
: variant === 'archive'
|
|
255
|
+
? `This directory holds this database's file-backed blobs within a downloaded \`get_backup\` archive.
|
|
149
256
|
To restore them, extract each \`<rootIndex>/\` tree back into the matching blob root (see the mapping
|
|
150
257
|
below and ../README.md).`
|
|
151
|
-
|
|
258
|
+
: `This directory holds point-in-time snapshots of this database's file-backed blobs, captured
|
|
152
259
|
alongside each RocksDB managed backup. You do not restore these by hand — \`restore_backup\` puts
|
|
153
260
|
them back automatically (see ../README.md); this file just documents the layout.`;
|
|
154
|
-
const backupIdBullet =
|
|
155
|
-
|
|
156
|
-
|
|
261
|
+
const backupIdBullet =
|
|
262
|
+
variant === 'managed'
|
|
263
|
+
? `- **<backupId>** matches the RocksDB backup id (\`harper list_backups\`). Each id is a full,
|
|
157
264
|
independent snapshot (not incremental).
|
|
158
|
-
|
|
265
|
+
`
|
|
266
|
+
: '';
|
|
159
267
|
return `# Harper blob snapshots
|
|
160
268
|
|
|
161
269
|
${intro}
|
|
@@ -166,7 +274,7 @@ ${intro}
|
|
|
166
274
|
|
|
167
275
|
${backupIdBullet}- **<rootIndex>** is which of the database's blob roots the file came from — the index into
|
|
168
276
|
\`storage.blobPaths[n]\`. When \`storage.blobPaths\` is not configured there is a single default root
|
|
169
|
-
(\`<rootPath>/blobs/<db>\`) at index 0. Current mapping
|
|
277
|
+
(\`<rootPath>/blobs/<db>\`) at index 0. Current mapping:
|
|
170
278
|
|
|
171
279
|
${rootMapping}
|
|
172
280
|
|
|
@@ -175,8 +283,10 @@ ${rootMapping}
|
|
|
175
283
|
4096 entries per directory). E.g. a blob with id \`0x12345678\` lives at \`12/345/678\`; a short id
|
|
176
284
|
like \`0xc1a\` lives at \`0/0/c1a\`.
|
|
177
285
|
|
|
178
|
-
|
|
179
|
-
otherwise.
|
|
286
|
+
Complete blobs are hard links to the live blobs when the destination is on the same filesystem, and
|
|
287
|
+
copies otherwise. A blob that was not capturable whole is stored as a marker instead: header type
|
|
288
|
+
\`0xfe\` is retryable (PENDING), while \`0xff\` is terminal (ERROR). The marker preserves the file id
|
|
289
|
+
but does not contain the original blob bytes.
|
|
180
290
|
`;
|
|
181
291
|
}
|
|
182
292
|
|
package/dataLayer/delete.ts
CHANGED
|
@@ -110,7 +110,12 @@ export async function deleteAuditLogsBefore(deleteObj: any) {
|
|
|
110
110
|
harperLogger.info(`Finished deleting audit logs before ${deleteObj.timestamp}`);
|
|
111
111
|
|
|
112
112
|
// `deleteTransactionLogsBefore` returns `entries_deleted`; the legacy result exposes it as `transactions_deleted`.
|
|
113
|
-
return new DeleteAuditLogsBeforeResults(
|
|
113
|
+
return new DeleteAuditLogsBeforeResults(
|
|
114
|
+
results.start_timestamp,
|
|
115
|
+
results.end_timestamp,
|
|
116
|
+
results.entries_deleted,
|
|
117
|
+
results.log_files_deleted
|
|
118
|
+
);
|
|
114
119
|
}
|
|
115
120
|
|
|
116
121
|
/**
|
|
@@ -25,6 +25,7 @@ import type {
|
|
|
25
25
|
import { collapseData } from '../../resources/tracked.ts';
|
|
26
26
|
import { errorToString } from '../../utility/logging/harper_logger.ts';
|
|
27
27
|
import { RocksDatabase } from '@harperfast/rocksdb-js';
|
|
28
|
+
import { boundedAuditPruneEnd, raiseAuditFloor } from '../../resources/auditStore.ts';
|
|
28
29
|
import { BridgeMethods } from './BridgeMethods.ts';
|
|
29
30
|
import lmdbGetBackup from './lmdbBridge/lmdbMethods/lmdbGetBackup.js';
|
|
30
31
|
import { createBackupStream, resolveSingleRootStore } from '../rocksdbBackup.ts';
|
|
@@ -199,10 +200,35 @@ export class ResourceBridge extends BridgeMethods {
|
|
|
199
200
|
return this.upsertRecords(updateObj);
|
|
200
201
|
}
|
|
201
202
|
|
|
202
|
-
|
|
203
|
+
/**
|
|
204
|
+
* Create-or-replace: the stored record becomes exactly the submitted one, so an attribute the
|
|
205
|
+
* request omits is REMOVED rather than kept. `update`/`upsert` merge (`Table.patch`), which is the
|
|
206
|
+
* v4-compatible behaviour every existing client depends on and is why this is a separate operation
|
|
207
|
+
* rather than a flag on those. Equivalent to REST `PUT /Table/id` — same `Table.put`, so the same
|
|
208
|
+
* audit type, replication shape, and retained `__createdtime__`.
|
|
209
|
+
*/
|
|
210
|
+
async putRecords(putObj) {
|
|
211
|
+
return this.upsertRecords(putObj, true);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
async upsertRecords(upsertObj, fullRecord = false) {
|
|
203
215
|
const { attributes } = insertUpdateValidate(upsertObj);
|
|
204
216
|
|
|
205
217
|
let new_attributes;
|
|
218
|
+
// `fullRecord` arrives as an ARGUMENT, never as a field on the request. Reading it off
|
|
219
|
+
// `upsertObj` would let a client send `full_record: true` with an `update` and get a replace —
|
|
220
|
+
// which makes the operation name stop describing the write, and bypasses the attribute-scoped
|
|
221
|
+
// `put` denial in `verifyPerms`, since that is keyed on the operation.
|
|
222
|
+
//
|
|
223
|
+
// Without it a write over an existing record merges (`Table.patch`), so an attribute the caller
|
|
224
|
+
// omitted keeps its stored value and `null` stores a null. That merge is the v4-compatible
|
|
225
|
+
// behaviour `update`/`upsert` must keep; HarperFast/studio#1643 is the removal case it cannot
|
|
226
|
+
// serve, and `put` is the operation that can.
|
|
227
|
+
//
|
|
228
|
+
// A put is also one operation where a client emulating removal needs two: the record is never
|
|
229
|
+
// absent between them, subscribers see a single write rather than a delete followed by an
|
|
230
|
+
// insert, and `__createdtime__` survives (`Table._writeUpdate` retains the stored created time
|
|
231
|
+
// on a full update and only stamps a new one for a new entry).
|
|
206
232
|
const Table = getDatabases()[upsertObj.schema][upsertObj.table];
|
|
207
233
|
const context: Context = {
|
|
208
234
|
user: upsertObj.hdb_user,
|
|
@@ -259,9 +285,14 @@ export class ResourceBridge extends BridgeMethods {
|
|
|
259
285
|
}
|
|
260
286
|
}
|
|
261
287
|
}
|
|
288
|
+
// Keyed on whether there IS a record to remove from, not on which operation asked. Guarding
|
|
289
|
+
// the insert flag alone left `upsert` with no primary key reaching the same silent partial
|
|
290
|
+
// write one branch over: `insertUpdateValidate` requires a hash attribute only for
|
|
291
|
+
// `update`, so such a record takes the `id == undefined → Table.create` path and stored an
|
|
292
|
+
// auto-keyed record with the named attributes stripped, returning 200.
|
|
262
293
|
await (id == undefined
|
|
263
294
|
? Table.create(record, context)
|
|
264
|
-
: existingRecord
|
|
295
|
+
: existingRecord && !fullRecord
|
|
265
296
|
? Table.patch(record, context)
|
|
266
297
|
: Table.put(record, context));
|
|
267
298
|
keys.push(record[Table.primaryKey]);
|
|
@@ -490,8 +521,26 @@ export class ResourceBridge extends BridgeMethods {
|
|
|
490
521
|
deleteObj.timestamp instanceof Date
|
|
491
522
|
? deleteObj.timestamp.getTime()
|
|
492
523
|
: typeof deleteObj.timestamp === 'string'
|
|
493
|
-
? Number.parseInt(
|
|
524
|
+
? // Number, not Number.parseInt: parseInt takes a numeric PREFIX ('9999999999999oops' is a
|
|
525
|
+
// year-2286 bound to it, '1e3' is 1) where Number rejects both as NaN. Empty/whitespace is
|
|
526
|
+
// explicit because Number('') and Number(' ') are 0.
|
|
527
|
+
deleteObj.timestamp.trim() === ''
|
|
528
|
+
? Number.NaN
|
|
529
|
+
: Number(deleteObj.timestamp)
|
|
494
530
|
: deleteObj.timestamp;
|
|
531
|
+
// Audit keys are raw float64: NaN and negatives sort above every real timestamp (a range ending
|
|
532
|
+
// there spans the whole log), and Infinity records the unknown sentinel raiseAuditFloor never lifts.
|
|
533
|
+
// Reject anything but a finite non-negative number here, as the 400 it is rather than a server
|
|
534
|
+
// fault. `Number.isFinite` never coerces, so it is the type check too.
|
|
535
|
+
if (!Number.isFinite(before) || before < 0 || Object.is(before, -0))
|
|
536
|
+
throw handleHDBError(
|
|
537
|
+
new Error(),
|
|
538
|
+
`'timestamp' must be a non-negative epoch time or Date, received: ${String(deleteObj.timestamp)}`,
|
|
539
|
+
400,
|
|
540
|
+
undefined,
|
|
541
|
+
undefined,
|
|
542
|
+
true
|
|
543
|
+
);
|
|
495
544
|
const databaseName = deleteObj.database || deleteObj.schema || DEFAULT_DATABASE;
|
|
496
545
|
const table = getTable(deleteObj);
|
|
497
546
|
// A nonexistent table must not fall through to the no-table branch below — on RocksDB that
|
|
@@ -514,7 +563,14 @@ export class ResourceBridge extends BridgeMethods {
|
|
|
514
563
|
if (tables) {
|
|
515
564
|
for (const table of Object.values(tables)) {
|
|
516
565
|
if (table.primaryStore instanceof RocksDatabase) {
|
|
517
|
-
|
|
566
|
+
// Clamp before recording: an operator-supplied bound has no ceiling of its own, and a
|
|
567
|
+
// floor above everything reachable never comes down (`raiseAuditFloor` only raises and
|
|
568
|
+
// `establishAuditFloor` skips a store that has a record), so a far-future bound would
|
|
569
|
+
// retire the floor for every table in this database. The purge takes the same clamped
|
|
570
|
+
// bound, so it cannot remove an entry the floor does not cover.
|
|
571
|
+
const pruneEnd = boundedAuditPruneEnd(table.auditStore, before);
|
|
572
|
+
raiseAuditFloor(table.auditStore, pruneEnd);
|
|
573
|
+
const deleted = table.primaryStore.purgeLogs({ before: pruneEnd, includeEntryCounts: true });
|
|
518
574
|
totalResults.log_files_deleted += deleted.length;
|
|
519
575
|
totalResults.entries_deleted += deleted.reduce((acc, file) => acc + file.entries, 0);
|
|
520
576
|
break;
|
|
@@ -546,11 +602,12 @@ export class ResourceBridge extends BridgeMethods {
|
|
|
546
602
|
// get the history of each record
|
|
547
603
|
for (const id of readAuditLogObj.search_values) {
|
|
548
604
|
histories[id] = (await table.getHistoryOfRecord(id)).map((auditRecord) => {
|
|
549
|
-
let operation = auditRecord.operation
|
|
550
|
-
if (operation === 'put') operation = 'upsert';
|
|
605
|
+
let operation = normalizeHistoryOperation(auditRecord.operation, auditRecord.type);
|
|
551
606
|
return {
|
|
552
607
|
operation,
|
|
553
|
-
|
|
608
|
+
// the transaction's position in the log, which is what this field has always
|
|
609
|
+
// reported on RocksDB and what groups an atomic transaction (harper#2412)
|
|
610
|
+
timestamp: auditRecord.localTime,
|
|
554
611
|
user_name: auditRecord.user,
|
|
555
612
|
ids: [id],
|
|
556
613
|
records: [auditRecord.value],
|
|
@@ -745,9 +802,8 @@ async function* groupRecordsInHistory(table, start?, end?, limit?) {
|
|
|
745
802
|
let enqueued;
|
|
746
803
|
let count = 0;
|
|
747
804
|
for await (const entry of table.getHistory(start, end)) {
|
|
748
|
-
let operation = entry.operation
|
|
749
|
-
|
|
750
|
-
const { id, version: timestamp, value } = entry;
|
|
805
|
+
let operation = normalizeHistoryOperation(entry.operation, entry.type);
|
|
806
|
+
const { id, localTime: timestamp, value } = entry;
|
|
751
807
|
if (enqueued?.timestamp === timestamp) {
|
|
752
808
|
enqueued.ids.push(id);
|
|
753
809
|
enqueued.records.push(value);
|
|
@@ -771,3 +827,17 @@ async function* groupRecordsInHistory(table, start?, end?, limit?) {
|
|
|
771
827
|
}
|
|
772
828
|
if (enqueued) yield enqueued;
|
|
773
829
|
}
|
|
830
|
+
|
|
831
|
+
/**
|
|
832
|
+
* Which operation a history entry should report: the originating operation when one was recorded,
|
|
833
|
+
* otherwise the physical write type.
|
|
834
|
+
*
|
|
835
|
+
* A recorded `put` is reported as `put`, so replication catch-up replays it as a replace. Only a
|
|
836
|
+
* LEGACY physical put — one with no originating operation, written before `put` existed — is still
|
|
837
|
+
* normalized to `upsert`, which is what produced a physical put back then. Normalizing both would
|
|
838
|
+
* make catch-up patch the replica and retain attributes the source removed.
|
|
839
|
+
*/
|
|
840
|
+
function normalizeHistoryOperation(originatingOperation, physicalType) {
|
|
841
|
+
if (originatingOperation !== undefined) return originatingOperation;
|
|
842
|
+
return physicalType === 'put' ? 'upsert' : physicalType;
|
|
843
|
+
}
|
|
@@ -8,11 +8,13 @@ class DeleteAuditLogsBeforeResults {
|
|
|
8
8
|
* @param {number} startTimestamp
|
|
9
9
|
* @param {number} endTimestamp
|
|
10
10
|
* @param {number} transactionsDeleted
|
|
11
|
+
* @param {number} logFilesDeleted
|
|
11
12
|
*/
|
|
12
|
-
constructor(startTimestamp = undefined, endTimestamp = undefined, transactionsDeleted = 0) {
|
|
13
|
+
constructor(startTimestamp = undefined, endTimestamp = undefined, transactionsDeleted = 0, logFilesDeleted = 0) {
|
|
13
14
|
this.start_timestamp = startTimestamp;
|
|
14
15
|
this.end_timestamp = endTimestamp;
|
|
15
16
|
this.transactions_deleted = transactionsDeleted;
|
|
17
|
+
this.log_files_deleted = logFilesDeleted;
|
|
16
18
|
this.deprecated = 'Please use delete_transaction_logs_before instead';
|
|
17
19
|
}
|
|
18
20
|
}
|
|
@@ -37,6 +37,37 @@ const DEFAULT_DATA_VERSION_NUM = '2.9.9';
|
|
|
37
37
|
// This value should change as supported versions change.
|
|
38
38
|
const MINIMUM_SUPPORTED_VERSION_NUM = '3.0.0';
|
|
39
39
|
|
|
40
|
+
export class VersionStampNotRecordedError extends Error {
|
|
41
|
+
statusCode: number;
|
|
42
|
+
constructor(message: string) {
|
|
43
|
+
super(message);
|
|
44
|
+
this.name = 'VersionStampNotRecordedError';
|
|
45
|
+
this.statusCode = 500;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* `insert.insert` reports a key that already exists as skipped, not as a failure, so a resolved
|
|
51
|
+
* insert is not evidence that the version was recorded. Ids compare as strings: the guard is
|
|
52
|
+
* against a write that did not happen, not against a hash returned in a different type.
|
|
53
|
+
*/
|
|
54
|
+
export function assertVersionRecorded(insertResult: any, expectedId: number, newVersionString: string) {
|
|
55
|
+
const insertedHashes = insertResult?.inserted_hashes;
|
|
56
|
+
if (
|
|
57
|
+
Array.isArray(insertedHashes) &&
|
|
58
|
+
insertedHashes.length === 1 &&
|
|
59
|
+
String(insertedHashes[0]) === String(expectedId)
|
|
60
|
+
) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
throw new VersionStampNotRecordedError(
|
|
65
|
+
`Could not record data version ${newVersionString} in '${hdbTerms.SYSTEM_SCHEMA_NAME}.${hdbTerms.SYSTEM_TABLE_NAMES.INFO_TABLE_NAME}': ` +
|
|
66
|
+
`the insert of ${HDB_INFO_SEARCH_ATTRIBUTE} ${expectedId} reported inserted ${JSON.stringify(insertedHashes ?? null)} ` +
|
|
67
|
+
`and skipped ${JSON.stringify(insertResult?.skipped_hashes ?? null)}`
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
40
71
|
/**
|
|
41
72
|
* * Insert a row into hdbInfo with the initial version data at install.
|
|
42
73
|
*
|
|
@@ -91,7 +122,9 @@ export async function insertHdbUpgradeInfo(newVersionString: string) {
|
|
|
91
122
|
);
|
|
92
123
|
|
|
93
124
|
await pSetSchemaDataToGlobal();
|
|
94
|
-
|
|
125
|
+
const insertResult = await insert.insert(insertObject);
|
|
126
|
+
assertVersionRecorded(insertResult, newId, newVersionString);
|
|
127
|
+
return insertResult;
|
|
95
128
|
}
|
|
96
129
|
|
|
97
130
|
/**
|
package/dataLayer/insert.ts
CHANGED
|
@@ -21,6 +21,7 @@ const pGlobalSchema = util.promisify(globalSchema.getTableSchema);
|
|
|
21
21
|
const UPDATE_ACTION = 'updated';
|
|
22
22
|
const INSERT_ACTION = 'inserted';
|
|
23
23
|
const UPSERT_ACTION = 'upserted';
|
|
24
|
+
const PUT_ACTION = 'put';
|
|
24
25
|
|
|
25
26
|
//IMPORTANT - This validation function is the async version of the code in harperBridge/bridgeUtility/insertUpdateValidate.js
|
|
26
27
|
// make sure any changes below are also made there. This is to resolve a circular dependency.
|
|
@@ -218,6 +219,42 @@ async function upsertData(upsertObject: any) {
|
|
|
218
219
|
);
|
|
219
220
|
}
|
|
220
221
|
|
|
222
|
+
/**
|
|
223
|
+
* Create-or-replace the records in the putObject parameter: the stored record becomes exactly the
|
|
224
|
+
* submitted one, so an attribute the request omits is removed. `update`/`upsert` merge instead, and
|
|
225
|
+
* must keep doing so for v4 compatibility — hence a distinct operation rather than a flag on those.
|
|
226
|
+
* Equivalent to REST `PUT /Table/id`.
|
|
227
|
+
* @param putObject - Represents the data that will be written
|
|
228
|
+
*/
|
|
229
|
+
async function putData(putObject: any) {
|
|
230
|
+
if (putObject.operation !== 'put') {
|
|
231
|
+
throw handleHDBError(new Error(), 'invalid operation, must be put', HTTP_STATUS_CODES.INTERNAL_SERVER_ERROR);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
let validator = insertValidator(putObject);
|
|
235
|
+
if (validator) {
|
|
236
|
+
throw handleHDBError(new Error(), validator.message, HTTP_STATUS_CODES.BAD_REQUEST);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
hdbUtils.transformReq(putObject);
|
|
240
|
+
|
|
241
|
+
let invalidSchemaTableMsg = hdbUtils.checkSchemaTableExist(putObject.schema, putObject.table);
|
|
242
|
+
if (invalidSchemaTableMsg) {
|
|
243
|
+
throw handleHDBError(new Error(), invalidSchemaTableMsg, HTTP_STATUS_CODES.BAD_REQUEST);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
let bridgePutResult = await harperBridge.putRecords(putObject);
|
|
247
|
+
|
|
248
|
+
return returnObject(
|
|
249
|
+
PUT_ACTION,
|
|
250
|
+
bridgePutResult.written_hashes,
|
|
251
|
+
putObject,
|
|
252
|
+
[],
|
|
253
|
+
bridgePutResult.new_attributes,
|
|
254
|
+
bridgePutResult.txn_time
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
|
|
221
258
|
/**
|
|
222
259
|
* Constructs return object for insert, update, and upsert.
|
|
223
260
|
* @param action
|
|
@@ -254,6 +291,12 @@ function returnObject(
|
|
|
254
291
|
return return_object;
|
|
255
292
|
}
|
|
256
293
|
|
|
294
|
+
if (action === PUT_ACTION) {
|
|
295
|
+
// `put` never skips: every submitted record is written, created or replaced.
|
|
296
|
+
return_object.put_hashes = written_hashes;
|
|
297
|
+
return return_object;
|
|
298
|
+
}
|
|
299
|
+
|
|
257
300
|
return_object.update_hashes = written_hashes;
|
|
258
301
|
return_object.skipped_hashes = skipped;
|
|
259
302
|
return return_object;
|
|
@@ -263,4 +306,4 @@ export function flush(object: any) {
|
|
|
263
306
|
hdbUtils.transformReq(object);
|
|
264
307
|
return harperBridge.flush(object.schema, object.table);
|
|
265
308
|
}
|
|
266
|
-
export { insertData as insert, updateData as update, upsertData as upsert };
|
|
309
|
+
export { insertData as insert, updateData as update, upsertData as upsert, putData as put };
|