@abloatai/humans 0.37.0
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/README.md +52 -0
- package/dist/Ablo.d.ts +208 -0
- package/dist/Ablo.js +120 -0
- package/dist/client.d.ts +317 -0
- package/dist/client.js +13 -0
- package/dist/core.d.ts +35 -0
- package/dist/core.js +48 -0
- package/dist/humans.d.ts +28 -0
- package/dist/humans.js +34 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +6 -0
- package/dist/local/BaseSyncedStore.d.ts +807 -0
- package/dist/local/BaseSyncedStore.js +1516 -0
- package/dist/local/Database.d.ts +322 -0
- package/dist/local/Database.js +1589 -0
- package/dist/local/InstanceCache.d.ts +255 -0
- package/dist/local/InstanceCache.js +1263 -0
- package/dist/local/LazyReferenceCollection.d.ts +177 -0
- package/dist/local/LazyReferenceCollection.js +461 -0
- package/dist/local/Model.d.ts +475 -0
- package/dist/local/Model.js +950 -0
- package/dist/local/ModelRegistry.d.ts +225 -0
- package/dist/local/ModelRegistry.js +539 -0
- package/dist/local/NetworkMonitor.d.ts +28 -0
- package/dist/local/NetworkMonitor.js +79 -0
- package/dist/local/RuntimeContext.d.ts +52 -0
- package/dist/local/RuntimeContext.js +80 -0
- package/dist/local/SyncClient.d.ts +516 -0
- package/dist/local/SyncClient.js +1754 -0
- package/dist/local/adapters/alwaysOnline.d.ts +14 -0
- package/dist/local/adapters/alwaysOnline.js +17 -0
- package/dist/local/adapters/inMemoryStorage.d.ts +37 -0
- package/dist/local/adapters/inMemoryStorage.js +122 -0
- package/dist/local/client/clientPrelude.d.ts +52 -0
- package/dist/local/client/clientPrelude.js +60 -0
- package/dist/local/client/consoleLogger.d.ts +35 -0
- package/dist/local/client/consoleLogger.js +44 -0
- package/dist/local/client/createInternalComponents.d.ts +50 -0
- package/dist/local/client/createInternalComponents.js +98 -0
- package/dist/local/client/createModelProxy.d.ts +248 -0
- package/dist/local/client/createModelProxy.js +880 -0
- package/dist/local/client/modelRegistration.d.ts +10 -0
- package/dist/local/client/modelRegistration.js +316 -0
- package/dist/local/client/options.d.ts +440 -0
- package/dist/local/client/options.js +7 -0
- package/dist/local/client/reactiveEngine.d.ts +53 -0
- package/dist/local/client/reactiveEngine.js +705 -0
- package/dist/local/client/resourceTypes.d.ts +12 -0
- package/dist/local/client/resourceTypes.js +10 -0
- package/dist/local/client/schemaConfig.d.ts +44 -0
- package/dist/local/client/schemaConfig.js +185 -0
- package/dist/local/client/storeCluster.d.ts +46 -0
- package/dist/local/client/storeCluster.js +133 -0
- package/dist/local/client/storeLifecycle.d.ts +61 -0
- package/dist/local/client/storeLifecycle.js +236 -0
- package/dist/local/client/validateAbloOptions.d.ts +42 -0
- package/dist/local/client/validateAbloOptions.js +43 -0
- package/dist/local/client/wsMutationExecutor.d.ts +27 -0
- package/dist/local/client/wsMutationExecutor.js +72 -0
- package/dist/local/context.d.ts +42 -0
- package/dist/local/context.js +81 -0
- package/dist/local/coordination/ClaimLog.d.ts +26 -0
- package/dist/local/coordination/ClaimLog.js +32 -0
- package/dist/local/interfaces/index.d.ts +311 -0
- package/dist/local/interfaces/index.js +9 -0
- package/dist/local/localModelContract.d.ts +14 -0
- package/dist/local/localModelContract.js +1 -0
- package/dist/local/logPosition.d.ts +31 -0
- package/dist/local/logPosition.js +53 -0
- package/dist/local/mutationPersistence.d.ts +6 -0
- package/dist/local/mutationPersistence.js +1 -0
- package/dist/local/mutators/RecordingMutation.d.ts +36 -0
- package/dist/local/mutators/RecordingMutation.js +182 -0
- package/dist/local/mutators/Transaction.d.ts +40 -0
- package/dist/local/mutators/Transaction.js +58 -0
- package/dist/local/mutators/UndoManager.d.ts +258 -0
- package/dist/local/mutators/UndoManager.js +665 -0
- package/dist/local/mutators/defineMutators.d.ts +60 -0
- package/dist/local/mutators/defineMutators.js +18 -0
- package/dist/local/mutators/inverseOp.d.ts +126 -0
- package/dist/local/mutators/inverseOp.js +71 -0
- package/dist/local/mutators/mutateActions.d.ts +45 -0
- package/dist/local/mutators/mutateActions.js +105 -0
- package/dist/local/mutators/readerActions.d.ts +33 -0
- package/dist/local/mutators/readerActions.js +57 -0
- package/dist/local/mutators/undoApply.d.ts +51 -0
- package/dist/local/mutators/undoApply.js +117 -0
- package/dist/local/persistence.d.ts +7 -0
- package/dist/local/persistence.js +9 -0
- package/dist/local/query/QueryProcessor.d.ts +75 -0
- package/dist/local/query/QueryProcessor.js +255 -0
- package/dist/local/query/client.d.ts +64 -0
- package/dist/local/query/client.js +138 -0
- package/dist/local/query/types.d.ts +85 -0
- package/dist/local/query/types.js +16 -0
- package/dist/local/schema/serialize.d.ts +1 -0
- package/dist/local/schema/serialize.js +1 -0
- package/dist/local/store/queryApi.d.ts +13 -0
- package/dist/local/store/queryApi.js +35 -0
- package/dist/local/storeContract.d.ts +145 -0
- package/dist/local/storeContract.js +12 -0
- package/dist/local/stores/DatabaseManager.d.ts +112 -0
- package/dist/local/stores/DatabaseManager.js +400 -0
- package/dist/local/stores/ObjectStore.d.ts +115 -0
- package/dist/local/stores/ObjectStore.js +393 -0
- package/dist/local/stores/ObjectStoreContract.d.ts +38 -0
- package/dist/local/stores/ObjectStoreContract.js +1 -0
- package/dist/local/stores/StoreManager.d.ts +114 -0
- package/dist/local/stores/StoreManager.js +304 -0
- package/dist/local/stores/SyncActionStore.d.ts +99 -0
- package/dist/local/stores/SyncActionStore.js +506 -0
- package/dist/local/stores/openIDBWithTimeout.d.ts +65 -0
- package/dist/local/stores/openIDBWithTimeout.js +153 -0
- package/dist/local/stores/persistenceCleanup.d.ts +7 -0
- package/dist/local/stores/persistenceCleanup.js +26 -0
- package/dist/local/stores/persistenceIdentity.d.ts +27 -0
- package/dist/local/stores/persistenceIdentity.js +38 -0
- package/dist/local/stores/syncAction.d.ts +26 -0
- package/dist/local/stores/syncAction.js +16 -0
- package/dist/local/stores/v1PersistenceDeletion.d.ts +8 -0
- package/dist/local/stores/v1PersistenceDeletion.js +16 -0
- package/dist/local/sync/BootstrapFetcher.d.ts +284 -0
- package/dist/local/sync/BootstrapFetcher.js +964 -0
- package/dist/local/sync/ConnectionManager.d.ts +8 -0
- package/dist/local/sync/ConnectionManager.js +8 -0
- package/dist/local/sync/OnDemandLoader.d.ts +231 -0
- package/dist/local/sync/OnDemandLoader.js +743 -0
- package/dist/local/sync/SubscriptionManager.d.ts +159 -0
- package/dist/local/sync/SubscriptionManager.js +243 -0
- package/dist/local/sync/SyncWebSocket.d.ts +173 -0
- package/dist/local/sync/SyncWebSocket.js +438 -0
- package/dist/local/sync/bootstrapApply.d.ts +73 -0
- package/dist/local/sync/bootstrapApply.js +73 -0
- package/dist/local/sync/commitFrames.d.ts +8 -0
- package/dist/local/sync/commitFrames.js +8 -0
- package/dist/local/sync/connectionManagerLifecycle.d.ts +23 -0
- package/dist/local/sync/connectionManagerLifecycle.js +126 -0
- package/dist/local/sync/contextPorts.d.ts +18 -0
- package/dist/local/sync/contextPorts.js +31 -0
- package/dist/local/sync/createClaimStream.d.ts +64 -0
- package/dist/local/sync/createClaimStream.js +475 -0
- package/dist/local/sync/createSnapshot.d.ts +29 -0
- package/dist/local/sync/createSnapshot.js +116 -0
- package/dist/local/sync/credentialLifecycle.d.ts +7 -0
- package/dist/local/sync/credentialLifecycle.js +7 -0
- package/dist/local/sync/deltaPipeline.d.ts +116 -0
- package/dist/local/sync/deltaPipeline.js +357 -0
- package/dist/local/sync/groupChange.d.ts +116 -0
- package/dist/local/sync/groupChange.js +244 -0
- package/dist/local/sync/initialize.d.ts +27 -0
- package/dist/local/sync/initialize.js +137 -0
- package/dist/local/sync/participants.d.ts +132 -0
- package/dist/local/sync/participants.js +342 -0
- package/dist/local/sync/persistedPrefix.d.ts +12 -0
- package/dist/local/sync/persistedPrefix.js +22 -0
- package/dist/local/sync/reconnect.d.ts +23 -0
- package/dist/local/sync/reconnect.js +55 -0
- package/dist/local/sync/schemaDrift.d.ts +55 -0
- package/dist/local/sync/schemaDrift.js +53 -0
- package/dist/local/sync/schemas.d.ts +71 -0
- package/dist/local/sync/schemas.js +94 -0
- package/dist/local/sync/socketEventWiring.d.ts +31 -0
- package/dist/local/sync/socketEventWiring.js +130 -0
- package/dist/local/sync/syncCursor.d.ts +40 -0
- package/dist/local/sync/syncCursor.js +55 -0
- package/dist/local/sync/syncPlan.d.ts +54 -0
- package/dist/local/sync/syncPlan.js +50 -0
- package/dist/local/sync/terminalSessionLifecycle.d.ts +20 -0
- package/dist/local/sync/terminalSessionLifecycle.js +50 -0
- package/dist/local/sync/wsFrameHandlers.d.ts +8 -0
- package/dist/local/sync/wsFrameHandlers.js +8 -0
- package/dist/local/transactions/databaseCommitOutbox.d.ts +15 -0
- package/dist/local/transactions/databaseCommitOutbox.js +16 -0
- package/dist/local/transactions/localMutation.d.ts +10 -0
- package/dist/local/transactions/localMutation.js +37 -0
- package/dist/local/transactions/mutations/MutationQueue.d.ts +511 -0
- package/dist/local/transactions/mutations/MutationQueue.js +1498 -0
- package/dist/local/transactions/mutations/MutationStore.d.ts +20 -0
- package/dist/local/transactions/mutations/MutationStore.js +53 -0
- package/dist/local/transactions/mutations/UnconfirmedWrites.d.ts +82 -0
- package/dist/local/transactions/mutations/UnconfirmedWrites.js +104 -0
- package/dist/local/transactions/mutations/batchProcessing.d.ts +64 -0
- package/dist/local/transactions/mutations/batchProcessing.js +349 -0
- package/dist/local/transactions/mutations/coalesceRules.d.ts +58 -0
- package/dist/local/transactions/mutations/coalesceRules.js +140 -0
- package/dist/local/transactions/mutations/commitApi.d.ts +19 -0
- package/dist/local/transactions/mutations/commitApi.js +74 -0
- package/dist/local/transactions/mutations/commitLane.d.ts +70 -0
- package/dist/local/transactions/mutations/commitLane.js +140 -0
- package/dist/local/transactions/mutations/commitLatency.d.ts +52 -0
- package/dist/local/transactions/mutations/commitLatency.js +130 -0
- package/dist/local/transactions/mutations/commitPayload.d.ts +165 -0
- package/dist/local/transactions/mutations/commitPayload.js +152 -0
- package/dist/local/transactions/mutations/commitTransport.d.ts +36 -0
- package/dist/local/transactions/mutations/commitTransport.js +104 -0
- package/dist/local/transactions/mutations/deltaConfirmation.d.ts +63 -0
- package/dist/local/transactions/mutations/deltaConfirmation.js +235 -0
- package/dist/local/transactions/mutations/durableCommitRestore.d.ts +17 -0
- package/dist/local/transactions/mutations/durableCommitRestore.js +95 -0
- package/dist/local/transactions/mutations/durableWriteStore.d.ts +14 -0
- package/dist/local/transactions/mutations/durableWriteStore.js +12 -0
- package/dist/local/transactions/mutations/executionSelection.d.ts +6 -0
- package/dist/local/transactions/mutations/executionSelection.js +42 -0
- package/dist/local/transactions/mutations/failureHandling.d.ts +16 -0
- package/dist/local/transactions/mutations/failureHandling.js +130 -0
- package/dist/local/transactions/mutations/failurePolicy.d.ts +13 -0
- package/dist/local/transactions/mutations/failurePolicy.js +48 -0
- package/dist/local/transactions/mutations/localMutation.d.ts +58 -0
- package/dist/local/transactions/mutations/localMutation.js +75 -0
- package/dist/local/transactions/mutations/modelOperations.d.ts +44 -0
- package/dist/local/transactions/mutations/modelOperations.js +144 -0
- package/dist/local/transactions/mutations/mutationPersistence.d.ts +25 -0
- package/dist/local/transactions/mutations/mutationPersistence.js +188 -0
- package/dist/local/transactions/mutations/pendingDrain.d.ts +33 -0
- package/dist/local/transactions/mutations/pendingDrain.js +112 -0
- package/dist/local/transactions/mutations/processingScheduler.d.ts +14 -0
- package/dist/local/transactions/mutations/processingScheduler.js +24 -0
- package/dist/local/transactions/mutations/queueCoalescing.d.ts +13 -0
- package/dist/local/transactions/mutations/queueCoalescing.js +35 -0
- package/dist/local/transactions/mutations/replayValidation.d.ts +187 -0
- package/dist/local/transactions/mutations/replayValidation.js +164 -0
- package/dist/local/transactions/reconnectDrain.d.ts +11 -0
- package/dist/local/transactions/reconnectDrain.js +13 -0
- package/dist/local/utils/mobxSetup.d.ts +53 -0
- package/dist/local/utils/mobxSetup.js +330 -0
- package/dist/local/views/QueryView.d.ts +79 -0
- package/dist/local/views/QueryView.js +218 -0
- package/dist/local/views/ViewRegistry.d.ts +20 -0
- package/dist/local/views/ViewRegistry.js +57 -0
- package/dist/local/views/incrementalView.d.ts +45 -0
- package/dist/local/views/incrementalView.js +69 -0
- package/dist/plugin.d.ts +285 -0
- package/dist/plugin.js +106 -0
- package/dist/presenceStream.d.ts +69 -0
- package/dist/presenceStream.js +200 -0
- package/dist/react/AbloProvider.d.ts +242 -0
- package/dist/react/AbloProvider.js +456 -0
- package/dist/react/ClientSideSuspense.d.ts +36 -0
- package/dist/react/ClientSideSuspense.js +17 -0
- package/dist/react/DefaultFallback.d.ts +24 -0
- package/dist/react/DefaultFallback.js +43 -0
- package/dist/react/context.d.ts +55 -0
- package/dist/react/context.js +29 -0
- package/dist/react/createAbloReact.d.ts +50 -0
- package/dist/react/createAbloReact.js +48 -0
- package/dist/react/internalContext.d.ts +33 -0
- package/dist/react/internalContext.js +3 -0
- package/dist/react/useAblo.d.ts +96 -0
- package/dist/react/useAblo.js +120 -0
- package/dist/react/useCurrentUserId.d.ts +2 -0
- package/dist/react/useCurrentUserId.js +12 -0
- package/dist/react/useErrorListener.d.ts +2 -0
- package/dist/react/useErrorListener.js +14 -0
- package/dist/react/useMutationFailureListener.d.ts +8 -0
- package/dist/react/useMutationFailureListener.js +19 -0
- package/dist/react/useMutators.d.ts +56 -0
- package/dist/react/useMutators.js +84 -0
- package/dist/react/useSyncStatus.d.ts +19 -0
- package/dist/react/useSyncStatus.js +37 -0
- package/dist/react/useUndoScope.d.ts +34 -0
- package/dist/react/useUndoScope.js +73 -0
- package/dist/react.d.ts +18 -0
- package/dist/react.js +14 -0
- package/dist/reactRuntime.d.ts +4 -0
- package/dist/reactRuntime.js +2 -0
- package/dist/surface.d.ts +36 -0
- package/dist/surface.js +77 -0
- package/dist/useReactive.d.ts +6 -0
- package/dist/useReactive.js +43 -0
- package/package.json +119 -0
- package/src/Ablo.ts +456 -0
- package/src/client.ts +374 -0
- package/src/core.ts +104 -0
- package/src/humans.ts +61 -0
- package/src/index.ts +40 -0
- package/src/local/BaseSyncedStore.ts +1991 -0
- package/src/local/Database.ts +2052 -0
- package/src/local/InstanceCache.ts +1503 -0
- package/src/local/LazyReferenceCollection.ts +563 -0
- package/src/local/Model.ts +1124 -0
- package/src/local/ModelRegistry.ts +762 -0
- package/src/local/NetworkMonitor.ts +88 -0
- package/src/local/RuntimeContext.ts +141 -0
- package/src/local/SyncClient.ts +2131 -0
- package/src/local/adapters/alwaysOnline.ts +20 -0
- package/src/local/adapters/inMemoryStorage.ts +141 -0
- package/src/local/client/clientPrelude.ts +112 -0
- package/src/local/client/consoleLogger.ts +60 -0
- package/src/local/client/createInternalComponents.ts +163 -0
- package/src/local/client/createModelProxy.ts +1390 -0
- package/src/local/client/modelRegistration.ts +350 -0
- package/src/local/client/options.ts +526 -0
- package/src/local/client/reactiveEngine.ts +935 -0
- package/src/local/client/resourceTypes.ts +37 -0
- package/src/local/client/schemaConfig.ts +194 -0
- package/src/local/client/storeCluster.ts +172 -0
- package/src/local/client/storeLifecycle.ts +343 -0
- package/src/local/client/validateAbloOptions.ts +95 -0
- package/src/local/client/wsMutationExecutor.ts +110 -0
- package/src/local/context.ts +96 -0
- package/src/local/coordination/ClaimLog.ts +39 -0
- package/src/local/interfaces/index.ts +468 -0
- package/src/local/localModelContract.ts +15 -0
- package/src/local/logPosition.ts +84 -0
- package/src/local/mutationPersistence.ts +7 -0
- package/src/local/mutators/RecordingMutation.ts +222 -0
- package/src/local/mutators/Transaction.ts +97 -0
- package/src/local/mutators/UndoManager.ts +741 -0
- package/src/local/mutators/defineMutators.ts +76 -0
- package/src/local/mutators/inverseOp.ts +83 -0
- package/src/local/mutators/mutateActions.ts +167 -0
- package/src/local/mutators/readerActions.ts +99 -0
- package/src/local/mutators/undoApply.ts +141 -0
- package/src/local/persistence.ts +16 -0
- package/src/local/query/QueryProcessor.ts +347 -0
- package/src/local/query/client.ts +197 -0
- package/src/local/query/types.ts +102 -0
- package/src/local/schema/serialize.ts +1 -0
- package/src/local/store/queryApi.ts +56 -0
- package/src/local/storeContract.ts +146 -0
- package/src/local/stores/DatabaseManager.ts +507 -0
- package/src/local/stores/ObjectStore.ts +449 -0
- package/src/local/stores/ObjectStoreContract.ts +48 -0
- package/src/local/stores/StoreManager.ts +388 -0
- package/src/local/stores/SyncActionStore.ts +579 -0
- package/src/local/stores/openIDBWithTimeout.ts +195 -0
- package/src/local/stores/persistenceCleanup.ts +43 -0
- package/src/local/stores/persistenceIdentity.ts +83 -0
- package/src/local/stores/syncAction.ts +21 -0
- package/src/local/stores/v1PersistenceDeletion.ts +21 -0
- package/src/local/sync/BootstrapFetcher.ts +1224 -0
- package/src/local/sync/ConnectionManager.ts +15 -0
- package/src/local/sync/OnDemandLoader.ts +927 -0
- package/src/local/sync/SubscriptionManager.ts +300 -0
- package/src/local/sync/SyncWebSocket.ts +584 -0
- package/src/local/sync/bootstrapApply.ts +130 -0
- package/src/local/sync/commitFrames.ts +16 -0
- package/src/local/sync/connectionManagerLifecycle.ts +158 -0
- package/src/local/sync/contextPorts.ts +37 -0
- package/src/local/sync/createClaimStream.ts +668 -0
- package/src/local/sync/createSnapshot.ts +160 -0
- package/src/local/sync/credentialLifecycle.ts +18 -0
- package/src/local/sync/deltaPipeline.ts +473 -0
- package/src/local/sync/groupChange.ts +343 -0
- package/src/local/sync/initialize.ts +205 -0
- package/src/local/sync/participants.ts +564 -0
- package/src/local/sync/persistedPrefix.ts +27 -0
- package/src/local/sync/reconnect.ts +88 -0
- package/src/local/sync/schemaDrift.ts +86 -0
- package/src/local/sync/schemas.ts +118 -0
- package/src/local/sync/socketEventWiring.ts +196 -0
- package/src/local/sync/syncCursor.ts +62 -0
- package/src/local/sync/syncPlan.ts +89 -0
- package/src/local/sync/terminalSessionLifecycle.ts +66 -0
- package/src/local/sync/wsFrameHandlers.ts +20 -0
- package/src/local/transactions/databaseCommitOutbox.ts +33 -0
- package/src/local/transactions/localMutation.ts +58 -0
- package/src/local/transactions/mutations/MutationQueue.ts +1998 -0
- package/src/local/transactions/mutations/MutationStore.ts +65 -0
- package/src/local/transactions/mutations/UnconfirmedWrites.ts +133 -0
- package/src/local/transactions/mutations/batchProcessing.ts +469 -0
- package/src/local/transactions/mutations/coalesceRules.ts +192 -0
- package/src/local/transactions/mutations/commitApi.ts +97 -0
- package/src/local/transactions/mutations/commitLane.ts +191 -0
- package/src/local/transactions/mutations/commitLatency.ts +164 -0
- package/src/local/transactions/mutations/commitPayload.ts +281 -0
- package/src/local/transactions/mutations/commitTransport.ts +174 -0
- package/src/local/transactions/mutations/deltaConfirmation.ts +298 -0
- package/src/local/transactions/mutations/durableCommitRestore.ts +128 -0
- package/src/local/transactions/mutations/durableWriteStore.ts +21 -0
- package/src/local/transactions/mutations/executionSelection.ts +42 -0
- package/src/local/transactions/mutations/failureHandling.ts +154 -0
- package/src/local/transactions/mutations/failurePolicy.ts +61 -0
- package/src/local/transactions/mutations/localMutation.ts +135 -0
- package/src/local/transactions/mutations/modelOperations.ts +210 -0
- package/src/local/transactions/mutations/mutationPersistence.ts +231 -0
- package/src/local/transactions/mutations/pendingDrain.ts +160 -0
- package/src/local/transactions/mutations/processingScheduler.ts +35 -0
- package/src/local/transactions/mutations/queueCoalescing.ts +45 -0
- package/src/local/transactions/mutations/replayValidation.ts +192 -0
- package/src/local/transactions/reconnectDrain.ts +24 -0
- package/src/local/utils/mobxSetup.ts +388 -0
- package/src/local/views/QueryView.ts +311 -0
- package/src/local/views/ViewRegistry.ts +61 -0
- package/src/local/views/incrementalView.ts +92 -0
- package/src/plugin.ts +396 -0
- package/src/presenceStream.ts +279 -0
- package/src/react/AbloProvider.tsx +744 -0
- package/src/react/ClientSideSuspense.tsx +57 -0
- package/src/react/DefaultFallback.tsx +60 -0
- package/src/react/context.ts +89 -0
- package/src/react/createAbloReact.ts +116 -0
- package/src/react/internalContext.ts +38 -0
- package/src/react/useAblo.ts +280 -0
- package/src/react/useCurrentUserId.ts +17 -0
- package/src/react/useErrorListener.ts +22 -0
- package/src/react/useMutationFailureListener.ts +34 -0
- package/src/react/useMutators.ts +184 -0
- package/src/react/useSyncStatus.ts +42 -0
- package/src/react/useUndoScope.ts +143 -0
- package/src/react.ts +69 -0
- package/src/reactRuntime.ts +10 -0
- package/src/surface.ts +106 -0
- package/src/useReactive.ts +51 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { RuntimeContext } from '../../RuntimeContext.js';
|
|
2
|
+
import type { ReadDependency, TrackDependency, OnStaleMode, StaleNotification } from '@abloatai/transaction/coordination/schema';
|
|
3
|
+
import type { MutationCommitResult } from '@abloatai/transaction/wire/commit';
|
|
4
|
+
import type { DurableCommitEnvelope, DurableCommitOperation } from '@abloatai/transaction/transactions/settlement/commitEnvelope';
|
|
5
|
+
import type { SealDurableCommitInput } from './commitTransport.js';
|
|
6
|
+
export interface CommitTransaction {
|
|
7
|
+
id: string;
|
|
8
|
+
kind: 'commit';
|
|
9
|
+
operations: {
|
|
10
|
+
type: DurableCommitOperation['type'];
|
|
11
|
+
model: string;
|
|
12
|
+
id: string;
|
|
13
|
+
input?: Record<string, unknown>;
|
|
14
|
+
transactionId?: string;
|
|
15
|
+
readAt?: number | null;
|
|
16
|
+
onStale?: OnStaleMode | null;
|
|
17
|
+
}[];
|
|
18
|
+
reads?: ReadDependency[] | null;
|
|
19
|
+
track?: TrackDependency[] | null;
|
|
20
|
+
status: 'pending' | 'executing' | 'awaiting_delta' | 'completed' | 'failed';
|
|
21
|
+
createdAt: number;
|
|
22
|
+
attempts: number;
|
|
23
|
+
transientAttempts?: number;
|
|
24
|
+
lastSyncId?: number;
|
|
25
|
+
correlationId?: string;
|
|
26
|
+
error?: Error;
|
|
27
|
+
sealedAt: number;
|
|
28
|
+
sequence: number;
|
|
29
|
+
sealPromise?: Promise<void>;
|
|
30
|
+
durableEnvelope?: DurableCommitEnvelope;
|
|
31
|
+
sourceMutationIds?: string[];
|
|
32
|
+
}
|
|
33
|
+
export interface CommitLaneContext {
|
|
34
|
+
readonly runtime: RuntimeContext;
|
|
35
|
+
readonly config: {
|
|
36
|
+
maxRetries: number;
|
|
37
|
+
};
|
|
38
|
+
readonly commitLane: CommitTransaction[];
|
|
39
|
+
readonly commitNotifications: Map<string, StaleNotification[]>;
|
|
40
|
+
readonly commitMissingIds: Map<string, string[]>;
|
|
41
|
+
readonly commitProcessing: boolean;
|
|
42
|
+
readonly setCommitProcessing: (value: boolean) => void;
|
|
43
|
+
readonly durableReplayBlock: object | null;
|
|
44
|
+
readonly sealDurableCommit: (input: SealDurableCommitInput) => Promise<DurableCommitEnvelope>;
|
|
45
|
+
readonly assertEnvelopeInsideReplayWindow: (envelope: DurableCommitEnvelope) => void;
|
|
46
|
+
readonly dispatchCommit: (envelope: DurableCommitEnvelope) => Promise<MutationCommitResult>;
|
|
47
|
+
readonly persistDurableCommitAcceptance: (envelope: DurableCommitEnvelope, result: MutationCommitResult) => Promise<DurableCommitEnvelope>;
|
|
48
|
+
readonly removeDurableCommit: (idempotencyKey: string) => Promise<void>;
|
|
49
|
+
readonly queuedCommitEchoSyncId: (transaction: CommitTransaction) => number | undefined;
|
|
50
|
+
readonly completeQueuedCommit: (transaction: CommitTransaction, syncId: number) => void;
|
|
51
|
+
readonly scheduleReplicationLagTimeout: (transactionId: string, clientTxId: string, correlationId?: string) => void;
|
|
52
|
+
readonly noteAck: (syncId: number | undefined) => void;
|
|
53
|
+
readonly isDefinitiveRejection: (error: Error) => boolean;
|
|
54
|
+
readonly isPermanentError: (error: Error) => boolean;
|
|
55
|
+
readonly emitCommitLifecycle: (event: string, payload: object) => void;
|
|
56
|
+
}
|
|
57
|
+
export interface CommitReceiptContext {
|
|
58
|
+
readonly commitStore: Map<string, CommitTransaction>;
|
|
59
|
+
readonly commitNotifications: Map<string, StaleNotification[]>;
|
|
60
|
+
readonly commitMissingIds: Map<string, string[]>;
|
|
61
|
+
readonly replicationLagErrors: Map<string, Error>;
|
|
62
|
+
readonly on: (event: string, listener: (payload: object) => void) => void;
|
|
63
|
+
readonly off: (event: string, listener: (payload: object) => void) => void;
|
|
64
|
+
}
|
|
65
|
+
export declare function waitForCommitReceipt(ctx: CommitReceiptContext, clientTxId: string): Promise<{
|
|
66
|
+
lastSyncId: number;
|
|
67
|
+
notifications?: StaleNotification[];
|
|
68
|
+
missingIds?: string[];
|
|
69
|
+
}>;
|
|
70
|
+
export declare function processCommitLane(ctx: CommitLaneContext): Promise<void>;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { AbloConnectionError } from '@abloatai/transaction/errors';
|
|
2
|
+
export function waitForCommitReceipt(ctx, clientTxId) {
|
|
3
|
+
const drainNotifications = () => {
|
|
4
|
+
const notifications = ctx.commitNotifications.get(clientTxId);
|
|
5
|
+
if (!notifications)
|
|
6
|
+
return undefined;
|
|
7
|
+
ctx.commitNotifications.delete(clientTxId);
|
|
8
|
+
return notifications.length > 0 ? notifications : undefined;
|
|
9
|
+
};
|
|
10
|
+
const drainMissingIds = () => {
|
|
11
|
+
const ids = ctx.commitMissingIds.get(clientTxId);
|
|
12
|
+
if (!ids)
|
|
13
|
+
return undefined;
|
|
14
|
+
ctx.commitMissingIds.delete(clientTxId);
|
|
15
|
+
return ids.length > 0 ? ids : undefined;
|
|
16
|
+
};
|
|
17
|
+
const receipt = (lastSyncId) => {
|
|
18
|
+
const missingIds = drainMissingIds();
|
|
19
|
+
return {
|
|
20
|
+
lastSyncId,
|
|
21
|
+
notifications: drainNotifications(),
|
|
22
|
+
...(missingIds ? { missingIds } : {}),
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
return new Promise((resolve, reject) => {
|
|
26
|
+
const existing = ctx.commitStore.get(clientTxId);
|
|
27
|
+
if (existing?.status === 'completed') {
|
|
28
|
+
resolve(receipt(existing.lastSyncId ?? 0));
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (existing?.status === 'failed' && existing.error) {
|
|
32
|
+
reject(existing.error);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const lagError = ctx.replicationLagErrors.get(clientTxId);
|
|
36
|
+
if (lagError) {
|
|
37
|
+
reject(lagError);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const onCompleted = (tx) => { cleanup(); resolve(receipt(tx.lastSyncId ?? 0)); };
|
|
41
|
+
const onFailed = (payload) => { cleanup(); reject(payload.error); };
|
|
42
|
+
const onLagged = (payload) => { cleanup(); reject(payload.error); };
|
|
43
|
+
const cleanup = () => {
|
|
44
|
+
ctx.off(`transaction:completed:${clientTxId}`, onCompleted);
|
|
45
|
+
ctx.off(`transaction:failed:${clientTxId}`, onFailed);
|
|
46
|
+
ctx.off(`transaction:confirmation_lagged:${clientTxId}`, onLagged);
|
|
47
|
+
};
|
|
48
|
+
ctx.on(`transaction:completed:${clientTxId}`, onCompleted);
|
|
49
|
+
ctx.on(`transaction:failed:${clientTxId}`, onFailed);
|
|
50
|
+
ctx.on(`transaction:confirmation_lagged:${clientTxId}`, onLagged);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
export async function processCommitLane(ctx) {
|
|
54
|
+
if (ctx.commitProcessing || ctx.durableReplayBlock)
|
|
55
|
+
return;
|
|
56
|
+
ctx.setCommitProcessing(true);
|
|
57
|
+
try {
|
|
58
|
+
while (ctx.commitLane.length > 0) {
|
|
59
|
+
const tx = ctx.commitLane[0];
|
|
60
|
+
if (!tx)
|
|
61
|
+
break;
|
|
62
|
+
if (tx.status !== 'pending') {
|
|
63
|
+
ctx.commitLane.shift();
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
tx.status = 'executing';
|
|
67
|
+
tx.attempts += 1;
|
|
68
|
+
let dispatchStarted = false;
|
|
69
|
+
try {
|
|
70
|
+
const durableEnvelope = tx.durableEnvelope ?? await ctx.sealDurableCommit({
|
|
71
|
+
idempotencyKey: tx.id,
|
|
72
|
+
origin: 'atomic_commit',
|
|
73
|
+
operations: tx.operations,
|
|
74
|
+
sourceMutationIds: tx.sourceMutationIds,
|
|
75
|
+
commitOptions: {
|
|
76
|
+
...(tx.reads ? { reads: tx.reads } : {}),
|
|
77
|
+
...(tx.track ? { track: tx.track } : {}),
|
|
78
|
+
},
|
|
79
|
+
createdAt: tx.createdAt,
|
|
80
|
+
sealedAt: tx.sealedAt,
|
|
81
|
+
sequence: tx.sequence,
|
|
82
|
+
});
|
|
83
|
+
tx.durableEnvelope = durableEnvelope;
|
|
84
|
+
ctx.assertEnvelopeInsideReplayWindow(durableEnvelope);
|
|
85
|
+
dispatchStarted = true;
|
|
86
|
+
const result = await ctx.dispatchCommit(durableEnvelope);
|
|
87
|
+
tx.durableEnvelope = await ctx.persistDurableCommitAcceptance(durableEnvelope, result);
|
|
88
|
+
tx.lastSyncId = result.lastSyncId;
|
|
89
|
+
if (result.notifications?.length)
|
|
90
|
+
ctx.commitNotifications.set(tx.id, result.notifications);
|
|
91
|
+
if (result.missingIds?.length)
|
|
92
|
+
ctx.commitMissingIds.set(tx.id, result.missingIds);
|
|
93
|
+
ctx.commitLane.shift();
|
|
94
|
+
if (result.status === 'queued') {
|
|
95
|
+
tx.correlationId = result.correlationId;
|
|
96
|
+
tx.status = 'awaiting_delta';
|
|
97
|
+
const echoSyncId = ctx.queuedCommitEchoSyncId(tx);
|
|
98
|
+
if (echoSyncId !== undefined)
|
|
99
|
+
ctx.completeQueuedCommit(tx, echoSyncId);
|
|
100
|
+
else
|
|
101
|
+
ctx.scheduleReplicationLagTimeout(tx.id, tx.id, result.correlationId);
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
await ctx.removeDurableCommit(tx.id);
|
|
105
|
+
ctx.noteAck(tx.lastSyncId);
|
|
106
|
+
tx.status = 'completed';
|
|
107
|
+
ctx.emitCommitLifecycle('transaction:completed', tx);
|
|
108
|
+
ctx.emitCommitLifecycle(`transaction:completed:${tx.id}`, tx);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch (cause) {
|
|
112
|
+
const error = cause instanceof Error ? cause : new Error(String(cause));
|
|
113
|
+
if (dispatchStarted && ctx.isDefinitiveRejection(error))
|
|
114
|
+
await ctx.removeDurableCommit(tx.id);
|
|
115
|
+
if (!(error instanceof AbloConnectionError))
|
|
116
|
+
tx.transientAttempts = (tx.transientAttempts ?? 0) + 1;
|
|
117
|
+
const exhausted = (tx.transientAttempts ?? 0) > ctx.config.maxRetries;
|
|
118
|
+
if (!ctx.isPermanentError(error) && !exhausted) {
|
|
119
|
+
tx.status = 'pending';
|
|
120
|
+
ctx.runtime.logger.debug('[MutationQueue] commit lane transient', {
|
|
121
|
+
txId: tx.id.slice(0, 12), attempts: tx.attempts,
|
|
122
|
+
transientAttempts: tx.transientAttempts ?? 0, message: error.message,
|
|
123
|
+
});
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
tx.status = 'failed';
|
|
127
|
+
tx.error = error;
|
|
128
|
+
ctx.commitLane.shift();
|
|
129
|
+
ctx.runtime.logger.debug('[MutationQueue] commit lane permanent error', {
|
|
130
|
+
txId: tx.id.slice(0, 12), attempts: tx.attempts, message: error.message,
|
|
131
|
+
});
|
|
132
|
+
ctx.emitCommitLifecycle('transaction:failed', { transaction: tx, error, permanent: true });
|
|
133
|
+
ctx.emitCommitLifecycle(`transaction:failed:${tx.id}`, { error });
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
finally {
|
|
138
|
+
ctx.setCommitProcessing(false);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Commit latency — how long a user's edit actually takes to land.
|
|
3
|
+
*
|
|
4
|
+
* The engine has never measured this. HUDs and dashboards reach for
|
|
5
|
+
* `window.fetch` timings, which the sync engine's WebSocket never touches, so
|
|
6
|
+
* the latency a user sees reported while editing has had nothing to do with
|
|
7
|
+
* the writes they are making. This module closes that gap without adding a
|
|
8
|
+
* single timestamp to the hot path: `MutationQueue` already emits the commit
|
|
9
|
+
* lifecycle, and the events already carry the correlation key.
|
|
10
|
+
*
|
|
11
|
+
* Three events, two intervals:
|
|
12
|
+
*
|
|
13
|
+
* commit:staging ──sealMs──▶ commit:created ──ackMs──▶ transaction:completed
|
|
14
|
+
*
|
|
15
|
+
* - `sealMs` is **local** — writing the durable envelope before the commit is
|
|
16
|
+
* allowed onto the wire. Slow here means durable storage, not network.
|
|
17
|
+
* - `ackMs` is **remote** — dispatch, round-trip, and server work. For a
|
|
18
|
+
* commit routed at a connected source this also spans the wait for the
|
|
19
|
+
* correlated echo that promotes `queued` to `confirmed`, so it answers
|
|
20
|
+
* "when did my edit become real" rather than raw socket round-trip. Read a
|
|
21
|
+
* large `ackMs` against a small `sealMs` as a network or replication cost.
|
|
22
|
+
*
|
|
23
|
+
* Correlation is by `clientTxId`: `MutationQueue` uses it as the transaction
|
|
24
|
+
* id verbatim, so the staging event and the completion event share one key.
|
|
25
|
+
*/
|
|
26
|
+
/**
|
|
27
|
+
* The slice of an event emitter this module needs. Declared structurally so a
|
|
28
|
+
* plain object can stand in under test — `MutationQueue` satisfies it by
|
|
29
|
+
* extending `EventEmitter`.
|
|
30
|
+
*/
|
|
31
|
+
export interface CommitEventSource {
|
|
32
|
+
on(event: string, listener: (payload: unknown) => void): unknown;
|
|
33
|
+
off(event: string, listener: (payload: unknown) => void): unknown;
|
|
34
|
+
}
|
|
35
|
+
/** One completed commit, broken into its local and remote halves. */
|
|
36
|
+
export interface CommitLatencySample {
|
|
37
|
+
/** The commit's `clientTxId`, identical to its transaction id. */
|
|
38
|
+
clientTxId: string;
|
|
39
|
+
/** Milliseconds sealing the durable envelope locally. */
|
|
40
|
+
sealMs: number;
|
|
41
|
+
/** Milliseconds from sealed envelope to acknowledgement. */
|
|
42
|
+
ackMs: number;
|
|
43
|
+
/** Milliseconds from staging to acknowledgement — `sealMs + ackMs`. */
|
|
44
|
+
totalMs: number;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Pair commit lifecycle events into latency samples. Returns an unsubscribe
|
|
48
|
+
* function that also drops any still-pending timings.
|
|
49
|
+
*
|
|
50
|
+
* `onSample` fires once per commit that completes, in completion order.
|
|
51
|
+
*/
|
|
52
|
+
export declare function observeCommitLatency(source: CommitEventSource, onSample: (sample: CommitLatencySample) => void): () => void;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Commit latency — how long a user's edit actually takes to land.
|
|
3
|
+
*
|
|
4
|
+
* The engine has never measured this. HUDs and dashboards reach for
|
|
5
|
+
* `window.fetch` timings, which the sync engine's WebSocket never touches, so
|
|
6
|
+
* the latency a user sees reported while editing has had nothing to do with
|
|
7
|
+
* the writes they are making. This module closes that gap without adding a
|
|
8
|
+
* single timestamp to the hot path: `MutationQueue` already emits the commit
|
|
9
|
+
* lifecycle, and the events already carry the correlation key.
|
|
10
|
+
*
|
|
11
|
+
* Three events, two intervals:
|
|
12
|
+
*
|
|
13
|
+
* commit:staging ──sealMs──▶ commit:created ──ackMs──▶ transaction:completed
|
|
14
|
+
*
|
|
15
|
+
* - `sealMs` is **local** — writing the durable envelope before the commit is
|
|
16
|
+
* allowed onto the wire. Slow here means durable storage, not network.
|
|
17
|
+
* - `ackMs` is **remote** — dispatch, round-trip, and server work. For a
|
|
18
|
+
* commit routed at a connected source this also spans the wait for the
|
|
19
|
+
* correlated echo that promotes `queued` to `confirmed`, so it answers
|
|
20
|
+
* "when did my edit become real" rather than raw socket round-trip. Read a
|
|
21
|
+
* large `ackMs` against a small `sealMs` as a network or replication cost.
|
|
22
|
+
*
|
|
23
|
+
* Correlation is by `clientTxId`: `MutationQueue` uses it as the transaction
|
|
24
|
+
* id verbatim, so the staging event and the completion event share one key.
|
|
25
|
+
*/
|
|
26
|
+
/**
|
|
27
|
+
* Cap on commits awaiting completion. A commit whose completion never arrives
|
|
28
|
+
* (connection dropped mid-flight, retry abandoned) would otherwise pin its
|
|
29
|
+
* entry forever, so the map is bounded rather than trusted to drain.
|
|
30
|
+
*/
|
|
31
|
+
const MAX_PENDING_COMMITS = 256;
|
|
32
|
+
function nowMs() {
|
|
33
|
+
return typeof performance !== 'undefined' ? performance.now() : Date.now();
|
|
34
|
+
}
|
|
35
|
+
/** Read `clientTxId` off a `commit:*` payload, or null if it isn't shaped so. */
|
|
36
|
+
function readClientTxId(payload) {
|
|
37
|
+
if (typeof payload !== 'object' || payload === null)
|
|
38
|
+
return null;
|
|
39
|
+
const { clientTxId } = payload;
|
|
40
|
+
return typeof clientTxId === 'string' ? clientTxId : null;
|
|
41
|
+
}
|
|
42
|
+
/** Read `id` off a transaction payload (`transaction:completed` sends the tx). */
|
|
43
|
+
function readTransactionId(payload) {
|
|
44
|
+
if (typeof payload !== 'object' || payload === null)
|
|
45
|
+
return null;
|
|
46
|
+
const { id } = payload;
|
|
47
|
+
return typeof id === 'string' ? id : null;
|
|
48
|
+
}
|
|
49
|
+
/** `transaction:failed` wraps the transaction rather than sending it bare. */
|
|
50
|
+
function readFailedTransactionId(payload) {
|
|
51
|
+
if (typeof payload !== 'object' || payload === null)
|
|
52
|
+
return null;
|
|
53
|
+
return readTransactionId(payload.transaction);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Pair commit lifecycle events into latency samples. Returns an unsubscribe
|
|
57
|
+
* function that also drops any still-pending timings.
|
|
58
|
+
*
|
|
59
|
+
* `onSample` fires once per commit that completes, in completion order.
|
|
60
|
+
*/
|
|
61
|
+
export function observeCommitLatency(source, onSample) {
|
|
62
|
+
const pending = new Map();
|
|
63
|
+
const handleStaging = (payload) => {
|
|
64
|
+
const id = readClientTxId(payload);
|
|
65
|
+
if (id === null)
|
|
66
|
+
return;
|
|
67
|
+
// Map preserves insertion order, so the first key is the stalest entry.
|
|
68
|
+
if (pending.size >= MAX_PENDING_COMMITS) {
|
|
69
|
+
const oldest = pending.keys().next();
|
|
70
|
+
if (!oldest.done)
|
|
71
|
+
pending.delete(oldest.value);
|
|
72
|
+
}
|
|
73
|
+
pending.set(id, { stagedAt: nowMs(), sealedAt: null });
|
|
74
|
+
};
|
|
75
|
+
const handleCreated = (payload) => {
|
|
76
|
+
const id = readClientTxId(payload);
|
|
77
|
+
if (id === null)
|
|
78
|
+
return;
|
|
79
|
+
const timing = pending.get(id);
|
|
80
|
+
if (timing === undefined)
|
|
81
|
+
return;
|
|
82
|
+
timing.sealedAt = nowMs();
|
|
83
|
+
};
|
|
84
|
+
const handleCompleted = (payload) => {
|
|
85
|
+
const id = readTransactionId(payload);
|
|
86
|
+
if (id === null)
|
|
87
|
+
return;
|
|
88
|
+
const timing = pending.get(id);
|
|
89
|
+
// `transaction:completed` also fires for local (non-commit) transactions
|
|
90
|
+
// and for mutation-log replay. Only ids we staged are commits, so an
|
|
91
|
+
// absent entry is the normal way those are filtered out.
|
|
92
|
+
if (timing === undefined)
|
|
93
|
+
return;
|
|
94
|
+
pending.delete(id);
|
|
95
|
+
const completedAt = nowMs();
|
|
96
|
+
// A commit can complete without an observed seal only if the listener was
|
|
97
|
+
// attached mid-flight; attributing the whole span to `ackMs` keeps
|
|
98
|
+
// `sealMs + ackMs === totalMs` true rather than reporting a bogus seal.
|
|
99
|
+
const sealedAt = timing.sealedAt ?? timing.stagedAt;
|
|
100
|
+
onSample({
|
|
101
|
+
clientTxId: id,
|
|
102
|
+
sealMs: sealedAt - timing.stagedAt,
|
|
103
|
+
ackMs: completedAt - sealedAt,
|
|
104
|
+
totalMs: completedAt - timing.stagedAt,
|
|
105
|
+
});
|
|
106
|
+
};
|
|
107
|
+
const handleSealFailed = (payload) => {
|
|
108
|
+
const id = readClientTxId(payload);
|
|
109
|
+
if (id !== null)
|
|
110
|
+
pending.delete(id);
|
|
111
|
+
};
|
|
112
|
+
const handleFailed = (payload) => {
|
|
113
|
+
const id = readFailedTransactionId(payload);
|
|
114
|
+
if (id !== null)
|
|
115
|
+
pending.delete(id);
|
|
116
|
+
};
|
|
117
|
+
source.on('commit:staging', handleStaging);
|
|
118
|
+
source.on('commit:created', handleCreated);
|
|
119
|
+
source.on('commit:seal_failed', handleSealFailed);
|
|
120
|
+
source.on('transaction:completed', handleCompleted);
|
|
121
|
+
source.on('transaction:failed', handleFailed);
|
|
122
|
+
return () => {
|
|
123
|
+
source.off('commit:staging', handleStaging);
|
|
124
|
+
source.off('commit:created', handleCreated);
|
|
125
|
+
source.off('commit:seal_failed', handleSealFailed);
|
|
126
|
+
source.off('transaction:completed', handleCompleted);
|
|
127
|
+
source.off('transaction:failed', handleFailed);
|
|
128
|
+
pending.clear();
|
|
129
|
+
};
|
|
130
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The vocabulary a local transaction uses on the wire. This module defines the
|
|
3
|
+
* {@link QueuedMutation} record and the helpers that turn a transaction into a
|
|
4
|
+
* wire-safe commit operation: schema-field projection
|
|
5
|
+
* ({@link projectCommitPayload}), write-option projection
|
|
6
|
+
* ({@link applyWriteOptions}), foreign-key-aware priority scoring
|
|
7
|
+
* ({@link computePriorityScore}), and the structural checks used to classify
|
|
8
|
+
* transport errors. Nothing here holds queue state or timers, so the batched
|
|
9
|
+
* queue path and the HTTP commit path share the same projection.
|
|
10
|
+
*/
|
|
11
|
+
import type { RuntimeContext } from '../../RuntimeContext.js';
|
|
12
|
+
import { MutationOperationType } from '@abloatai/transaction/types';
|
|
13
|
+
import type { OnStaleMode } from '@abloatai/transaction/coordination/schema';
|
|
14
|
+
import type { MutationOptions, WriteOptions } from '../../interfaces/index.js';
|
|
15
|
+
import type { CommitEnvelopeMember } from '@abloatai/transaction/transactions/settlement/commitEnvelope';
|
|
16
|
+
export interface UserContext {
|
|
17
|
+
userId: string;
|
|
18
|
+
organizationId: string;
|
|
19
|
+
role?: string;
|
|
20
|
+
teamIds?: string[];
|
|
21
|
+
}
|
|
22
|
+
/** Wire-format mutation payload (post-projection). */
|
|
23
|
+
export type MutationInput = Record<string, unknown>;
|
|
24
|
+
/**
|
|
25
|
+
* Projects a model's serialized data onto the fields declared in its schema and
|
|
26
|
+
* returns a wire-safe commit payload. It does two things:
|
|
27
|
+
*
|
|
28
|
+
* 1. Drops framework-internal keys (`__class`, `__typename`, `clientId`,
|
|
29
|
+
* `syncStatus`) and anything not declared on the model's schema.
|
|
30
|
+
* 2. Takes a fresh plain JSON snapshot of the projected values. JSON-typed
|
|
31
|
+
* fields stay objects rather than pre-serialized strings, while reactive
|
|
32
|
+
* proxies cannot leak into persistence or the wire payload.
|
|
33
|
+
*
|
|
34
|
+
* For updates (`dropUndefined: true`), `undefined` values are also removed so
|
|
35
|
+
* they are not written as `SET column = NULL` on the server.
|
|
36
|
+
*
|
|
37
|
+
* Field metadata comes from the model registry, populated when the schema is
|
|
38
|
+
* registered at initialization. If a model has no registered field metadata —
|
|
39
|
+
* for example a manually registered model — projection snapshots all serialized
|
|
40
|
+
* data apart from the framework keys.
|
|
41
|
+
*/
|
|
42
|
+
export declare function projectCommitPayload(modelName: string, source: Record<string, unknown>, opts: {
|
|
43
|
+
dropUndefined: boolean;
|
|
44
|
+
}, runtime?: RuntimeContext): MutationInput;
|
|
45
|
+
export interface QueuedMutation {
|
|
46
|
+
id: string;
|
|
47
|
+
type: 'create' | 'update' | 'delete' | 'archive' | 'unarchive';
|
|
48
|
+
modelName: string;
|
|
49
|
+
modelId: string;
|
|
50
|
+
modelKey: string;
|
|
51
|
+
data?: MutationInput;
|
|
52
|
+
previousData?: MutationInput | null;
|
|
53
|
+
context: UserContext;
|
|
54
|
+
status: 'pending' | 'executing' | 'awaiting_delta' | 'completed' | 'failed' | 'rolled_back';
|
|
55
|
+
createdAt: number;
|
|
56
|
+
attempts: number;
|
|
57
|
+
priority: 'normal' | 'high';
|
|
58
|
+
priorityScore: number;
|
|
59
|
+
writeOptions?: WriteOptions;
|
|
60
|
+
batchId?: string;
|
|
61
|
+
/**
|
|
62
|
+
* Stable identity of the wire commit that currently owns this operation.
|
|
63
|
+
*
|
|
64
|
+
* A transport failure is ambiguous: the server may have committed the
|
|
65
|
+
* batch even though the acknowledgement never reached this client. Keeping
|
|
66
|
+
* this envelope on every member lets the queue replay the exact same ordered
|
|
67
|
+
* batch with the exact same idempotency key instead of accidentally
|
|
68
|
+
* re-batching its operations under a fresh key.
|
|
69
|
+
*/
|
|
70
|
+
commitEnvelope?: CommitEnvelopeMember;
|
|
71
|
+
/** Pending-mutation journal entries atomically consumed by this envelope. */
|
|
72
|
+
sourceMutationIds?: string[];
|
|
73
|
+
/** Completed locally without a server operation; no sync echo will arrive. */
|
|
74
|
+
localOnly?: boolean;
|
|
75
|
+
/** Sync-id threshold: the transaction confirms once a delta with an id at least this value arrives. */
|
|
76
|
+
syncIdNeededForCompletion?: number;
|
|
77
|
+
/**
|
|
78
|
+
* Opaque customer-side batch identity returned with a queued source receipt.
|
|
79
|
+
* It is retained durably and is the only identity a live WAL delta may use
|
|
80
|
+
* to settle this pending commit. Server-side replay additionally proves the
|
|
81
|
+
* complete stored operation-id set before returning `confirmed`.
|
|
82
|
+
*/
|
|
83
|
+
correlationId?: string;
|
|
84
|
+
/**
|
|
85
|
+
* A queued forward has no authoritative sync-id watermark yet. It may only
|
|
86
|
+
* confirm when a WAL delta carries its opaque server-derived correlation;
|
|
87
|
+
* unrelated deltas must never satisfy it by advancing the global watermark.
|
|
88
|
+
*/
|
|
89
|
+
requiresCorrelatedDelta?: boolean;
|
|
90
|
+
/**
|
|
91
|
+
* Resolves once the server has confirmed this transaction, whether by a delta
|
|
92
|
+
* or an HTTP acknowledgement. It rejects with the originating error if the
|
|
93
|
+
* transaction is permanently rolled back; for a source-forwarded write it
|
|
94
|
+
* also rejects with `replication_lag_timeout` when the accepted write's WAL
|
|
95
|
+
* echo misses the confirmation deadline. That timeout does not roll back or
|
|
96
|
+
* fail the transaction: it remains pending and may confirm when replication
|
|
97
|
+
* recovers. This gives a caller one place to await the answer to "did my write
|
|
98
|
+
* land?", matching the
|
|
99
|
+
* `commits.create({ wait: 'confirmed' })` and
|
|
100
|
+
* {@link MutationQueue.waitForConfirmation} vocabulary, so a failure
|
|
101
|
+
* surfaces at the call site instead of only as a silent local rollback. The
|
|
102
|
+
* permanent-rejection value is the same {@link AbloError} carried on the
|
|
103
|
+
* queue's `transaction:failed` event.
|
|
104
|
+
*/
|
|
105
|
+
confirmation?: Promise<void>;
|
|
106
|
+
}
|
|
107
|
+
export declare const normalizeModelKey: (modelName: string) => string;
|
|
108
|
+
export declare const stripModelSuffix: (modelName: string) => string;
|
|
109
|
+
/**
|
|
110
|
+
* Returns the priority score used to order create operations by foreign-key
|
|
111
|
+
* depth, so a parent row commits before its children.
|
|
112
|
+
*
|
|
113
|
+
* The score comes from a priority map on the runtime configuration, built once
|
|
114
|
+
* at initialization by walking the schema's `belongsTo` graph. No model names
|
|
115
|
+
* are hard-coded here, and an application can override specific priorities
|
|
116
|
+
* through `configOverrides.modelCreatePriority`.
|
|
117
|
+
*
|
|
118
|
+
* Non-create operations (update, delete, archive, unarchive) need no
|
|
119
|
+
* foreign-key ordering because the row already exists, so they all share the
|
|
120
|
+
* configured default non-create priority.
|
|
121
|
+
*/
|
|
122
|
+
export declare const computePriorityScore: (type: QueuedMutation["type"], modelName: string, runtime?: RuntimeContext) => number;
|
|
123
|
+
export declare const TX_TYPE_TO_MUTATION_OP: Record<QueuedMutation['type'], MutationOperationType>;
|
|
124
|
+
export declare function hasStaleWriteOptions(options?: WriteOptions): boolean;
|
|
125
|
+
/** Options whose identity/audit semantics forbid merging two caller writes. */
|
|
126
|
+
export declare function hasCommitCoalescingBarrier(options?: WriteOptions): boolean;
|
|
127
|
+
export interface WriteOperationFields {
|
|
128
|
+
readAt?: number | null;
|
|
129
|
+
onStale?: OnStaleMode | null;
|
|
130
|
+
fenceToken?: number | null;
|
|
131
|
+
options?: Pick<MutationOptions, 'idempotencyKey' | 'label'>;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Copies a transaction's `writeOptions` onto the wire operation. The
|
|
135
|
+
* stale-context guards (`readAt` and `onStale`) sit at the operation's root,
|
|
136
|
+
* while `idempotencyKey` and `label` go in its `options` slot — the
|
|
137
|
+
* `mutation_log` cache key and audit tag. This is the one place caller-supplied
|
|
138
|
+
* write options cross onto the wire.
|
|
139
|
+
*/
|
|
140
|
+
export declare function applyWriteOptions<T extends object>(op: T, transaction: QueuedMutation): T & WriteOperationFields;
|
|
141
|
+
/**
|
|
142
|
+
* The structural shape used to inspect transport-layer errors. It covers the
|
|
143
|
+
* GraphQL-style and HTTP-style error shapes the mutation executor can surface,
|
|
144
|
+
* and is kept intentionally narrow so it does not claim fields the runtime may
|
|
145
|
+
* not supply.
|
|
146
|
+
*/
|
|
147
|
+
export interface TransportError {
|
|
148
|
+
message?: string;
|
|
149
|
+
code?: string | number;
|
|
150
|
+
extensions?: Record<string, unknown>;
|
|
151
|
+
locations?: readonly unknown[];
|
|
152
|
+
path?: readonly (string | number)[];
|
|
153
|
+
response?: {
|
|
154
|
+
status?: number;
|
|
155
|
+
errors?: readonly {
|
|
156
|
+
extensions?: {
|
|
157
|
+
code?: string;
|
|
158
|
+
};
|
|
159
|
+
message?: string;
|
|
160
|
+
}[];
|
|
161
|
+
};
|
|
162
|
+
error?: string;
|
|
163
|
+
}
|
|
164
|
+
export declare function asTransportError(value: unknown): TransportError;
|
|
165
|
+
export declare function extractStatusCode(error: unknown): number | undefined;
|