@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,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ViewRegistry — tracks active QueryViews per typename.
|
|
3
|
+
*
|
|
4
|
+
* When the InstanceCache mutates a model, it calls notifyAdded / notifyUpdated /
|
|
5
|
+
* notifyRemoved on the registry, which fans the event out to every active
|
|
6
|
+
* QueryView subscribed to that typename.
|
|
7
|
+
*/
|
|
8
|
+
import { modelAsRow } from '../Model.js';
|
|
9
|
+
export class ViewRegistry {
|
|
10
|
+
views = new Map();
|
|
11
|
+
register(typename, view) {
|
|
12
|
+
let set = this.views.get(typename);
|
|
13
|
+
if (!set) {
|
|
14
|
+
set = new Set();
|
|
15
|
+
this.views.set(typename, set);
|
|
16
|
+
}
|
|
17
|
+
set.add(view);
|
|
18
|
+
}
|
|
19
|
+
unregister(typename, view) {
|
|
20
|
+
const set = this.views.get(typename);
|
|
21
|
+
if (!set)
|
|
22
|
+
return;
|
|
23
|
+
set.delete(view);
|
|
24
|
+
if (set.size === 0) {
|
|
25
|
+
this.views.delete(typename);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/** Called by InstanceCache after a model is added to the pool. */
|
|
29
|
+
notifyAdded(typename, model) {
|
|
30
|
+
const set = this.views.get(typename);
|
|
31
|
+
if (!set)
|
|
32
|
+
return;
|
|
33
|
+
model.ensureObservable();
|
|
34
|
+
for (const view of set) {
|
|
35
|
+
view.handleAdded(modelAsRow(model));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/** Called by InstanceCache after a model is updated in the pool. */
|
|
39
|
+
notifyUpdated(typename, model) {
|
|
40
|
+
const set = this.views.get(typename);
|
|
41
|
+
if (!set)
|
|
42
|
+
return;
|
|
43
|
+
model.ensureObservable();
|
|
44
|
+
for (const view of set) {
|
|
45
|
+
view.handleUpdated(modelAsRow(model));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/** Called by InstanceCache after a model is removed from the pool. */
|
|
49
|
+
notifyRemoved(typename, modelId) {
|
|
50
|
+
const set = this.views.get(typename);
|
|
51
|
+
if (!set)
|
|
52
|
+
return;
|
|
53
|
+
for (const view of set) {
|
|
54
|
+
view.handleRemoved(modelId);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The {@link IncrementalView} contract — the interface a live view implements
|
|
3
|
+
* to receive add/update/remove notifications — together with the sorting,
|
|
4
|
+
* matching, and binary-insertion rules every view shares. Keeping the rules in
|
|
5
|
+
* one place ensures every view sorts and filters identically. The functions
|
|
6
|
+
* here work on plain arrays and values — they hold no reference to models,
|
|
7
|
+
* pools, or the reactivity system.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* The interface a live view implements to receive incremental updates: one call
|
|
11
|
+
* when an entity is added, one when it changes, and one when it is removed. A
|
|
12
|
+
* view registry holds its views under this non-generic base type so it can keep
|
|
13
|
+
* views over different entity shapes in a single collection and notify them
|
|
14
|
+
* uniformly. Because a generic `View<T>` is invariant in `T`, this shared base
|
|
15
|
+
* is what lets the registry store and dispatch to them without unsafe casts.
|
|
16
|
+
*/
|
|
17
|
+
export interface IncrementalView {
|
|
18
|
+
handleAdded(entity: Record<string, unknown>): void;
|
|
19
|
+
handleUpdated(entity: Record<string, unknown>): void;
|
|
20
|
+
handleRemoved(id: string): void;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Compares two values for sorting, tolerating `null` and `undefined`, which
|
|
24
|
+
* always sort last regardless of direction. `dir` is 1 for ascending or -1 for
|
|
25
|
+
* descending. Returns -1, 0, or 1.
|
|
26
|
+
*/
|
|
27
|
+
export declare function compareValues(a: unknown, b: unknown, dir: 1 | -1): number;
|
|
28
|
+
/**
|
|
29
|
+
* Finds, by binary search, the index at which `item` should be inserted to keep
|
|
30
|
+
* an array ordered. The array must already be sorted by `sortKey` in direction
|
|
31
|
+
* `dir`, using the same rule as {@link compareValues}. Returns that insertion
|
|
32
|
+
* index.
|
|
33
|
+
*/
|
|
34
|
+
export declare function binaryInsertionIndex<T>(arr: ArrayLike<T>, item: T, sortKey: string, dir: 1 | -1): number;
|
|
35
|
+
/**
|
|
36
|
+
* Returns true when an entity satisfies a declarative `where` filter: every key
|
|
37
|
+
* present in `where` must equal the entity's value for that key. A key whose
|
|
38
|
+
* filter value is `undefined` is skipped, so a partially-filled filter matches
|
|
39
|
+
* on only its defined keys.
|
|
40
|
+
*/
|
|
41
|
+
export declare function matchesWhere<T extends Record<string, unknown>>(entity: T, where: Partial<T>): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Find the index of an entity by id in an array. Returns -1 if not found.
|
|
44
|
+
*/
|
|
45
|
+
export declare function findIndexById<T extends Record<string, unknown>>(arr: ArrayLike<T>, id: string): number;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The {@link IncrementalView} contract — the interface a live view implements
|
|
3
|
+
* to receive add/update/remove notifications — together with the sorting,
|
|
4
|
+
* matching, and binary-insertion rules every view shares. Keeping the rules in
|
|
5
|
+
* one place ensures every view sorts and filters identically. The functions
|
|
6
|
+
* here work on plain arrays and values — they hold no reference to models,
|
|
7
|
+
* pools, or the reactivity system.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Compares two values for sorting, tolerating `null` and `undefined`, which
|
|
11
|
+
* always sort last regardless of direction. `dir` is 1 for ascending or -1 for
|
|
12
|
+
* descending. Returns -1, 0, or 1.
|
|
13
|
+
*/
|
|
14
|
+
export function compareValues(a, b, dir) {
|
|
15
|
+
if (a === b)
|
|
16
|
+
return 0;
|
|
17
|
+
if (a == null)
|
|
18
|
+
return 1;
|
|
19
|
+
if (b == null)
|
|
20
|
+
return -1;
|
|
21
|
+
return (a < b ? -1 : 1) * dir;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Finds, by binary search, the index at which `item` should be inserted to keep
|
|
25
|
+
* an array ordered. The array must already be sorted by `sortKey` in direction
|
|
26
|
+
* `dir`, using the same rule as {@link compareValues}. Returns that insertion
|
|
27
|
+
* index.
|
|
28
|
+
*/
|
|
29
|
+
export function binaryInsertionIndex(arr, item, sortKey, dir) {
|
|
30
|
+
let lo = 0;
|
|
31
|
+
let hi = arr.length;
|
|
32
|
+
const itemVal = item[sortKey];
|
|
33
|
+
while (lo < hi) {
|
|
34
|
+
const mid = (lo + hi) >>> 1;
|
|
35
|
+
const midVal = arr[mid][sortKey];
|
|
36
|
+
if (compareValues(midVal, itemVal, dir) <= 0) {
|
|
37
|
+
lo = mid + 1;
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
hi = mid;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return lo;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Returns true when an entity satisfies a declarative `where` filter: every key
|
|
47
|
+
* present in `where` must equal the entity's value for that key. A key whose
|
|
48
|
+
* filter value is `undefined` is skipped, so a partially-filled filter matches
|
|
49
|
+
* on only its defined keys.
|
|
50
|
+
*/
|
|
51
|
+
export function matchesWhere(entity, where) {
|
|
52
|
+
for (const [key, value] of Object.entries(where)) {
|
|
53
|
+
if (value === undefined)
|
|
54
|
+
continue;
|
|
55
|
+
if (entity[key] !== value)
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Find the index of an entity by id in an array. Returns -1 if not found.
|
|
62
|
+
*/
|
|
63
|
+
export function findIndexById(arr, id) {
|
|
64
|
+
for (let i = 0; i < arr.length; i++) {
|
|
65
|
+
if (arr[i]?.id === id)
|
|
66
|
+
return i;
|
|
67
|
+
}
|
|
68
|
+
return -1;
|
|
69
|
+
}
|
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The plugin contract (ADR 0016).
|
|
3
|
+
*
|
|
4
|
+
* The core is `commit` · `get`/`list` · `observe` · `claim` · auth. Everything
|
|
5
|
+
* else a caller might want — a local materialised copy, presence rendering,
|
|
6
|
+
* batching, framework bindings — is a plugin declared in one list, so a server
|
|
7
|
+
* or an agent installs only what it asked for.
|
|
8
|
+
*
|
|
9
|
+
* Every plugin has the same shape on purpose. Uniformity is what makes the list
|
|
10
|
+
* composable and the types inferable; bespoke plugins would reproduce today's
|
|
11
|
+
* nineteen export subpaths with extra ceremony.
|
|
12
|
+
*
|
|
13
|
+
* Where this shape came from, and the field-by-field reasoning behind it, is
|
|
14
|
+
* recorded in ADR 0016 — the contract itself only states what each field does.
|
|
15
|
+
*/
|
|
16
|
+
import type { ParticipantKind } from '@abloatai/transaction/types/participant';
|
|
17
|
+
import type { ErrorCodeSpec } from '@abloatai/transaction/errorCodes';
|
|
18
|
+
import type { Logger } from '@abloatai/transaction/logger';
|
|
19
|
+
import type { CoordinationObservability } from '@abloatai/transaction/observability';
|
|
20
|
+
import type { WsTransport } from '@abloatai/transaction/transport/wsTransport';
|
|
21
|
+
import type { AuthCredentialSource } from '@abloatai/transaction/auth/credentialSource';
|
|
22
|
+
import type { SyncDeltaWireCore } from '@abloatai/transaction/wire/delta';
|
|
23
|
+
import type { ModelData } from '@abloatai/transaction/types/modelData';
|
|
24
|
+
/**
|
|
25
|
+
* A string type that keeps literal inference alive: `id: 'humans'` stays the
|
|
26
|
+
* literal `'humans'` through object-literal inference instead of widening to
|
|
27
|
+
* `string`, which is what lets {@link InstalledSurface} key a plugin list's
|
|
28
|
+
* surface by id.
|
|
29
|
+
*/
|
|
30
|
+
export type LiteralString = '' | (string & Record<never, never>);
|
|
31
|
+
/**
|
|
32
|
+
* The ordered stages a delta passes through on its way from the feed into
|
|
33
|
+
* whatever is watching. A plugin names the one it attaches to.
|
|
34
|
+
*
|
|
35
|
+
* The order is not a convention — it is a correctness constraint. `acknowledge`
|
|
36
|
+
* must follow `persist`, because acknowledging the input range rather than the
|
|
37
|
+
* persisted high-water mark advances the server's cursor past deltas that never
|
|
38
|
+
* committed, and the next catch-up then answers "you're up to date" for a delta
|
|
39
|
+
* that was lost. Declaring the stage keeps that ordering out of array position,
|
|
40
|
+
* where it would be load-bearing and undocumented.
|
|
41
|
+
*/
|
|
42
|
+
export type PipelineStage =
|
|
43
|
+
/** Deltas arrive from `observe()` and are queued. */
|
|
44
|
+
'receive'
|
|
45
|
+
/** Per-entity collapse of the queued batch. */
|
|
46
|
+
| 'dedupe'
|
|
47
|
+
/** The batch is written to durable local storage. */
|
|
48
|
+
| 'persist'
|
|
49
|
+
/** Persisted results land in the in-memory graph. */
|
|
50
|
+
| 'apply'
|
|
51
|
+
/** The cursor advances — gated on `persist`, never on the input range. */
|
|
52
|
+
| 'acknowledge'
|
|
53
|
+
/** Anything downstream reacts: re-render, presence, subscribers. */
|
|
54
|
+
| 'notify';
|
|
55
|
+
/** Canonical order. A plugin runner must run stages in this sequence. */
|
|
56
|
+
export declare const PIPELINE_STAGES: readonly PipelineStage[];
|
|
57
|
+
/**
|
|
58
|
+
* A delta as stage handlers receive it — the identity slice of the wire
|
|
59
|
+
* shape, projected rather than restated so the wire schema stays the one
|
|
60
|
+
* definition.
|
|
61
|
+
*/
|
|
62
|
+
export type StageDelta = Pick<SyncDeltaWireCore, 'id' | 'actionType' | 'modelName' | 'modelId'>;
|
|
63
|
+
/**
|
|
64
|
+
* One persisted change: what the durable write reported and the apply stage
|
|
65
|
+
* lands in the in-memory graph. `data` is absent for actions that carry
|
|
66
|
+
* none (a remove reports identity only).
|
|
67
|
+
*/
|
|
68
|
+
export interface AppliedChange {
|
|
69
|
+
action: 'add' | 'update' | 'remove' | 'archive' | 'verify';
|
|
70
|
+
modelName: string;
|
|
71
|
+
modelId: string;
|
|
72
|
+
data?: ModelData | null;
|
|
73
|
+
/**
|
|
74
|
+
* Server-stamped transaction id, echoing the client's own commit
|
|
75
|
+
* operation id — how a client recognizes the confirmation of a change it
|
|
76
|
+
* already applied locally. Absent for system-emitted changes, which have
|
|
77
|
+
* no client transaction behind them.
|
|
78
|
+
*/
|
|
79
|
+
transactionId?: string;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* What each stage hands its handlers. Read off the delta pipeline these
|
|
83
|
+
* stages were read off, not invented: `receive` sees the delta being
|
|
84
|
+
* queued, `dedupe` and `persist` see the batch at those boundaries,
|
|
85
|
+
* `apply` and `notify` see the persisted changes, and `acknowledge` sees
|
|
86
|
+
* the persistence-gated cursor value.
|
|
87
|
+
*/
|
|
88
|
+
export interface StagePayloads {
|
|
89
|
+
receive: {
|
|
90
|
+
readonly delta: StageDelta;
|
|
91
|
+
};
|
|
92
|
+
dedupe: {
|
|
93
|
+
readonly deltas: readonly StageDelta[];
|
|
94
|
+
};
|
|
95
|
+
persist: {
|
|
96
|
+
readonly deltas: readonly StageDelta[];
|
|
97
|
+
};
|
|
98
|
+
apply: {
|
|
99
|
+
readonly changes: readonly AppliedChange[];
|
|
100
|
+
};
|
|
101
|
+
acknowledge: {
|
|
102
|
+
readonly syncId: number;
|
|
103
|
+
};
|
|
104
|
+
notify: {
|
|
105
|
+
readonly changes: readonly AppliedChange[];
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/** The handler a plugin attaches at one stage. The payload derives from the key. */
|
|
109
|
+
export type StageHandler<K extends PipelineStage> = (payload: StagePayloads[K]) => void;
|
|
110
|
+
/**
|
|
111
|
+
* What a capability needs from whatever transport was selected.
|
|
112
|
+
*
|
|
113
|
+
* Transport is a slot the caller fills, not a packaging axis, so a capability
|
|
114
|
+
* states its requirement and an incompatible pairing fails when the client is
|
|
115
|
+
* configured — with a typed error naming the plugin — rather than at runtime
|
|
116
|
+
* with a subscription that silently never delivers.
|
|
117
|
+
*/
|
|
118
|
+
export interface TransportCapabilities {
|
|
119
|
+
/**
|
|
120
|
+
* Requires a transport the server can initiate frames on. Live subscriptions,
|
|
121
|
+
* presence, and claim grants need this; commit and point-in-time reads do not.
|
|
122
|
+
*/
|
|
123
|
+
readonly duplex?: boolean;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* The core surface a plugin is handed at construction.
|
|
127
|
+
*
|
|
128
|
+
* Generic over the client's options type: the host instantiates it with its
|
|
129
|
+
* own options bag, so a plugin reads configuration without this package
|
|
130
|
+
* naming any consumer's types. Alongside the raw options, the context
|
|
131
|
+
* carries the values the host has already resolved (`participant`,
|
|
132
|
+
* `syncGroups`), so a plugin never re-derives identity.
|
|
133
|
+
*/
|
|
134
|
+
export interface PluginContext<Options = unknown> {
|
|
135
|
+
readonly logger: Logger;
|
|
136
|
+
readonly observability?: CoordinationObservability;
|
|
137
|
+
/** The client's own options bag, as the host received it. */
|
|
138
|
+
readonly options?: Options;
|
|
139
|
+
/**
|
|
140
|
+
* The live duplex connection. The host builds it during construction, so a
|
|
141
|
+
* plugin holds the thing rather than a function that fetches it: the
|
|
142
|
+
* connection object is stable for the client's lifetime — identity and
|
|
143
|
+
* read scope are seeded into it when they resolve, and reconnects replace
|
|
144
|
+
* only the socket inside it, never the object. Absent on a
|
|
145
|
+
* request-response client, which is what `requires: { duplex: true }`
|
|
146
|
+
* guards.
|
|
147
|
+
*/
|
|
148
|
+
readonly transport?: WsTransport;
|
|
149
|
+
/** The participant this client runs as, when known at construction. */
|
|
150
|
+
readonly participant?: {
|
|
151
|
+
readonly id: string;
|
|
152
|
+
readonly kind: ParticipantKind;
|
|
153
|
+
};
|
|
154
|
+
/** The connection's initial read scope (sync groups). */
|
|
155
|
+
readonly syncGroups?: readonly string[];
|
|
156
|
+
/** The resolved server base URL, settled by the host before construction. */
|
|
157
|
+
readonly url?: string;
|
|
158
|
+
/**
|
|
159
|
+
* The client's single bearer-credential source, shared with every
|
|
160
|
+
* auth-aware transport the host built. A plugin that constructs its own
|
|
161
|
+
* fetching component hands this on rather than re-deriving a credential.
|
|
162
|
+
*/
|
|
163
|
+
readonly auth?: AuthCredentialSource;
|
|
164
|
+
/**
|
|
165
|
+
* Whether a plugin with the given id is installed on this client. Supplied
|
|
166
|
+
* by {@link resolvePlugins} from the list it is resolving — the one place
|
|
167
|
+
* that truthfully knows the assembly — so a plugin interrogates what is
|
|
168
|
+
* installed instead of the host special-casing plugins by name.
|
|
169
|
+
*/
|
|
170
|
+
readonly hasPlugin?: (id: string) => boolean;
|
|
171
|
+
/**
|
|
172
|
+
* The resolved plugin list itself, supplied by {@link resolvePlugins}
|
|
173
|
+
* alongside {@link hasPlugin} (which derives from it). A component a
|
|
174
|
+
* plugin constructs — the store and its delta pipeline — holds this list
|
|
175
|
+
* to dispatch the declared stage handlers through {@link runStage}.
|
|
176
|
+
*/
|
|
177
|
+
readonly plugins?: readonly AbloPlugin[];
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* One installed capability.
|
|
181
|
+
*
|
|
182
|
+
* @typeParam Surface - what `init` contributes to the client. The plugin list's
|
|
183
|
+
* element types are what let the installed surface be inferred rather than
|
|
184
|
+
* declared.
|
|
185
|
+
*/
|
|
186
|
+
export interface AbloPlugin<Surface = unknown> {
|
|
187
|
+
/** Stable identity — deduplication, diagnostics, and error attribution.
|
|
188
|
+
* Literal-typed so a list's installed surface can be keyed by it. */
|
|
189
|
+
readonly id: LiteralString;
|
|
190
|
+
/** The plugin's own version, for diagnostics. */
|
|
191
|
+
readonly version?: string;
|
|
192
|
+
/** What this plugin needs from the transport. Checked at configuration time. */
|
|
193
|
+
readonly requires?: TransportCapabilities;
|
|
194
|
+
/**
|
|
195
|
+
* Whether this plugin keeps a local copy of rows.
|
|
196
|
+
*
|
|
197
|
+
* This is ADR 0013 §4's membership test as a declared, checkable property
|
|
198
|
+
* rather than a rule someone has to remember: a stateless caller can assert
|
|
199
|
+
* that nothing in its list materialises, and CI can assert the core's own
|
|
200
|
+
* list is uniformly `false`.
|
|
201
|
+
*/
|
|
202
|
+
readonly materialises: boolean;
|
|
203
|
+
/**
|
|
204
|
+
* Error codes this plugin may raise, folded into the registry.
|
|
205
|
+
*
|
|
206
|
+
* Registration is part of the contract because the error catalog is
|
|
207
|
+
* generated — a plugin that invents untyped errors would silently punch a
|
|
208
|
+
* hole in the published reference.
|
|
209
|
+
*/
|
|
210
|
+
readonly errorCodes?: Readonly<Record<string, ErrorCodeSpec>>;
|
|
211
|
+
/**
|
|
212
|
+
* The pipeline stages this plugin attaches to: each key names a stage and
|
|
213
|
+
* holds the handler the runner invokes there. One field on purpose — a
|
|
214
|
+
* declared stage cannot exist without its handler, nor a handler without
|
|
215
|
+
* its stage, so the declaration can never point at nothing. The payload
|
|
216
|
+
* type derives from the key ({@link StagePayloads}).
|
|
217
|
+
*/
|
|
218
|
+
readonly stages?: {
|
|
219
|
+
readonly [K in PipelineStage]?: StageHandler<K>;
|
|
220
|
+
};
|
|
221
|
+
/** Build the plugin's contribution to the client surface. */
|
|
222
|
+
init(context: PluginContext): Surface;
|
|
223
|
+
}
|
|
224
|
+
/** The surface a plugin list contributes, keyed by plugin id. */
|
|
225
|
+
export type InstalledSurface<Plugins extends readonly AbloPlugin[]> = {
|
|
226
|
+
[P in Plugins[number] as P['id']]: P extends AbloPlugin<infer S> ? S : never;
|
|
227
|
+
};
|
|
228
|
+
/**
|
|
229
|
+
* The plugin with the given id in a list, or `never` when absent. Sound
|
|
230
|
+
* because ids are literal ({@link LiteralString}); a list typed only as
|
|
231
|
+
* `AbloPlugin[]` has widened ids and resolves to `never`, so write plugin
|
|
232
|
+
* lists inline for the client type to follow them.
|
|
233
|
+
*/
|
|
234
|
+
export type PluginById<Plugins extends readonly AbloPlugin[], Id extends string> = Extract<Plugins[number], {
|
|
235
|
+
id: Id;
|
|
236
|
+
}>;
|
|
237
|
+
/** Collapses a union into an intersection, member by member. */
|
|
238
|
+
type UnionToIntersection<U> = (U extends unknown ? (member: U) => void : never) extends (member: infer I) => void ? I : never;
|
|
239
|
+
/**
|
|
240
|
+
* Every surface in a plugin list, folded into the one shape that merges onto
|
|
241
|
+
* the client: `[a(), b()]` contributes `ASurface & BSurface`. An empty list
|
|
242
|
+
* contributes nothing (`unknown`), so intersecting it changes no type.
|
|
243
|
+
*/
|
|
244
|
+
export type MergedSurface<Plugins extends readonly AbloPlugin[]> = [
|
|
245
|
+
Plugins[number]
|
|
246
|
+
] extends [never] ? unknown : UnionToIntersection<Plugins[number] extends AbloPlugin<infer Surface> ? Surface : never>;
|
|
247
|
+
/** What the selected transport can actually do, for checking `requires`. */
|
|
248
|
+
export interface TransportProfile {
|
|
249
|
+
readonly duplex: boolean;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Check a plugin list against the selected transport and build its surface.
|
|
253
|
+
*
|
|
254
|
+
* Both failures are configuration mistakes, so they surface here — while the
|
|
255
|
+
* client is being constructed and the stack still points at the caller's own
|
|
256
|
+
* setup — rather than later as a subscription that never delivers.
|
|
257
|
+
*/
|
|
258
|
+
export declare function resolvePlugins<const Plugins extends readonly AbloPlugin[], Options = unknown>(plugins: Plugins, transport: TransportProfile, context: PluginContext<Options>): InstalledSurface<Plugins>;
|
|
259
|
+
/**
|
|
260
|
+
* Lays every installed plugin surface over a built client, so a plugin's
|
|
261
|
+
* contributions are reachable as client members. The base always wins — a
|
|
262
|
+
* plugin cannot shadow `dispose`, a model accessor, or any other member the
|
|
263
|
+
* client itself defines; contributions only fill what the base leaves
|
|
264
|
+
* undefined. With nothing installed the base is returned untouched.
|
|
265
|
+
*
|
|
266
|
+
* The second half of {@link resolvePlugins}: that call turns a list into a
|
|
267
|
+
* surface, this one merges the surface onto the client the host built.
|
|
268
|
+
*/
|
|
269
|
+
export declare function layerPluginSurface<T extends object>(base: T, installed: Record<string, unknown>): T;
|
|
270
|
+
/**
|
|
271
|
+
* The plugins attached to one pipeline stage, in declaration order.
|
|
272
|
+
*
|
|
273
|
+
* Stage order across the pipeline is fixed by {@link PIPELINE_STAGES}; this
|
|
274
|
+
* returns the members of a single stage, where declaration order is the caller's
|
|
275
|
+
* to choose and carries no correctness weight.
|
|
276
|
+
*/
|
|
277
|
+
export declare function pluginsForStage(plugins: readonly AbloPlugin[], stage: PipelineStage): readonly AbloPlugin[];
|
|
278
|
+
/**
|
|
279
|
+
* Invokes every handler declared for one stage, in declaration order, with
|
|
280
|
+
* that stage's payload. No handlers declared is a plain no-op, so a pipeline
|
|
281
|
+
* dispatches unconditionally at each boundary and pays nothing when the
|
|
282
|
+
* stage is unclaimed.
|
|
283
|
+
*/
|
|
284
|
+
export declare function runStage<K extends PipelineStage>(plugins: readonly AbloPlugin[], stage: K, payload: StagePayloads[K]): void;
|
|
285
|
+
export {};
|
package/dist/plugin.js
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The plugin contract (ADR 0016).
|
|
3
|
+
*
|
|
4
|
+
* The core is `commit` · `get`/`list` · `observe` · `claim` · auth. Everything
|
|
5
|
+
* else a caller might want — a local materialised copy, presence rendering,
|
|
6
|
+
* batching, framework bindings — is a plugin declared in one list, so a server
|
|
7
|
+
* or an agent installs only what it asked for.
|
|
8
|
+
*
|
|
9
|
+
* Every plugin has the same shape on purpose. Uniformity is what makes the list
|
|
10
|
+
* composable and the types inferable; bespoke plugins would reproduce today's
|
|
11
|
+
* nineteen export subpaths with extra ceremony.
|
|
12
|
+
*
|
|
13
|
+
* Where this shape came from, and the field-by-field reasoning behind it, is
|
|
14
|
+
* recorded in ADR 0016 — the contract itself only states what each field does.
|
|
15
|
+
*/
|
|
16
|
+
import { AbloValidationError } from '@abloatai/transaction/errors';
|
|
17
|
+
/** Canonical order. A plugin runner must run stages in this sequence. */
|
|
18
|
+
export const PIPELINE_STAGES = [
|
|
19
|
+
'receive',
|
|
20
|
+
'dedupe',
|
|
21
|
+
'persist',
|
|
22
|
+
'apply',
|
|
23
|
+
'acknowledge',
|
|
24
|
+
'notify',
|
|
25
|
+
];
|
|
26
|
+
/**
|
|
27
|
+
* Check a plugin list against the selected transport and build its surface.
|
|
28
|
+
*
|
|
29
|
+
* Both failures are configuration mistakes, so they surface here — while the
|
|
30
|
+
* client is being constructed and the stack still points at the caller's own
|
|
31
|
+
* setup — rather than later as a subscription that never delivers.
|
|
32
|
+
*/
|
|
33
|
+
export function resolvePlugins(plugins, transport, context) {
|
|
34
|
+
const surface = {};
|
|
35
|
+
const seen = new Set();
|
|
36
|
+
// The assembly, injected from the list being resolved. Always this list's
|
|
37
|
+
// own answer — a host-supplied `plugins` or `hasPlugin` could disagree
|
|
38
|
+
// with the assembly it describes, so both are replaced, not deferred to.
|
|
39
|
+
const initContext = {
|
|
40
|
+
...context,
|
|
41
|
+
plugins,
|
|
42
|
+
hasPlugin: (id) => plugins.some((plugin) => plugin.id === id),
|
|
43
|
+
};
|
|
44
|
+
for (const plugin of plugins) {
|
|
45
|
+
if (seen.has(plugin.id)) {
|
|
46
|
+
throw new AbloValidationError(`The ${plugin.id} plugin is listed twice. Remove the duplicate; a plugin is installed once per client.`, { code: 'invalid_options', param: 'plugins' });
|
|
47
|
+
}
|
|
48
|
+
seen.add(plugin.id);
|
|
49
|
+
if (plugin.requires?.duplex && !transport.duplex) {
|
|
50
|
+
throw new AbloValidationError(`The ${plugin.id} plugin needs a connection the server can send on, and this client is set up for request-response only. Switch the transport to 'websocket', or drop the plugin.`, { code: 'invalid_options', param: 'plugins' });
|
|
51
|
+
}
|
|
52
|
+
surface[plugin.id] = plugin.init(initContext);
|
|
53
|
+
}
|
|
54
|
+
return surface;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Lays every installed plugin surface over a built client, so a plugin's
|
|
58
|
+
* contributions are reachable as client members. The base always wins — a
|
|
59
|
+
* plugin cannot shadow `dispose`, a model accessor, or any other member the
|
|
60
|
+
* client itself defines; contributions only fill what the base leaves
|
|
61
|
+
* undefined. With nothing installed the base is returned untouched.
|
|
62
|
+
*
|
|
63
|
+
* The second half of {@link resolvePlugins}: that call turns a list into a
|
|
64
|
+
* surface, this one merges the surface onto the client the host built.
|
|
65
|
+
*/
|
|
66
|
+
export function layerPluginSurface(base, installed) {
|
|
67
|
+
const contributions = {};
|
|
68
|
+
for (const surface of Object.values(installed)) {
|
|
69
|
+
if (surface && typeof surface === 'object') {
|
|
70
|
+
Object.assign(contributions, surface);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (Object.keys(contributions).length === 0)
|
|
74
|
+
return base;
|
|
75
|
+
return new Proxy(base, {
|
|
76
|
+
get(target, prop, receiver) {
|
|
77
|
+
const own = Reflect.get(target, prop, receiver);
|
|
78
|
+
if (own !== undefined)
|
|
79
|
+
return own;
|
|
80
|
+
return typeof prop === 'string' && prop in contributions
|
|
81
|
+
? contributions[prop]
|
|
82
|
+
: own;
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* The plugins attached to one pipeline stage, in declaration order.
|
|
88
|
+
*
|
|
89
|
+
* Stage order across the pipeline is fixed by {@link PIPELINE_STAGES}; this
|
|
90
|
+
* returns the members of a single stage, where declaration order is the caller's
|
|
91
|
+
* to choose and carries no correctness weight.
|
|
92
|
+
*/
|
|
93
|
+
export function pluginsForStage(plugins, stage) {
|
|
94
|
+
return plugins.filter((plugin) => plugin.stages?.[stage] !== undefined);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Invokes every handler declared for one stage, in declaration order, with
|
|
98
|
+
* that stage's payload. No handlers declared is a plain no-op, so a pipeline
|
|
99
|
+
* dispatches unconditionally at each boundary and pays nothing when the
|
|
100
|
+
* stage is unclaimed.
|
|
101
|
+
*/
|
|
102
|
+
export function runStage(plugins, stage, payload) {
|
|
103
|
+
for (const plugin of plugins) {
|
|
104
|
+
plugin.stages?.[stage]?.(payload);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a {@link PresenceStream} over a live sync connection. Presence is the
|
|
3
|
+
* lightweight, ephemeral "who's here and what are they doing" view: each
|
|
4
|
+
* participant broadcasts a status and an activity, and sees everyone else's.
|
|
5
|
+
* The stream is built directly on the sync WebSocket and adds no second
|
|
6
|
+
* connection. It is the sibling of {@link createClaimStream}, which reuses the
|
|
7
|
+
* same presence frames.
|
|
8
|
+
*
|
|
9
|
+
* There are two ways to construct it:
|
|
10
|
+
*
|
|
11
|
+
* 1. Direct — pass an already-open `transport`, for example an agent worker
|
|
12
|
+
* or a test.
|
|
13
|
+
* 2. Deferred — construct without a transport and call `attach(transport)`
|
|
14
|
+
* once the connection is ready. The returned stream object is stable from
|
|
15
|
+
* construction, so callers can hold the reference and let attachment
|
|
16
|
+
* happen later.
|
|
17
|
+
*
|
|
18
|
+
* Wire frames:
|
|
19
|
+
* • Outbound `presence_update` — `{ status, activity? }`. The server stamps
|
|
20
|
+
* `userId`, `kind`, `timestamp`, and `isAgent`, then broadcasts to the
|
|
21
|
+
* other participants on the same sync groups.
|
|
22
|
+
* • Inbound — the same frame, with `kind` one of `enter`, `update`, or
|
|
23
|
+
* `leave`.
|
|
24
|
+
*/
|
|
25
|
+
import type { WsTransport } from '@abloatai/transaction/transport/wsTransport';
|
|
26
|
+
import type { PresenceStream } from '@abloatai/transaction/types/streams';
|
|
27
|
+
import type { ParticipantKind } from '@abloatai/transaction/types/participant';
|
|
28
|
+
/**
|
|
29
|
+
* The wire capability the presence stream actually uses: subscribe to typed
|
|
30
|
+
* inbound frames, check liveness, and send outbound frames. The duplex
|
|
31
|
+
* `WsTransport` satisfies it — the same port shape the claim stream depends
|
|
32
|
+
* on — so the stream can attach to whatever connection the host built,
|
|
33
|
+
* without naming the engine's subclass.
|
|
34
|
+
*/
|
|
35
|
+
export type PresenceTransport = Pick<WsTransport, 'subscribe' | 'isConnected' | 'send'>;
|
|
36
|
+
export interface PresenceStreamConfig {
|
|
37
|
+
/** Identity used to filter our own echoed frames out of `others`. */
|
|
38
|
+
participantId: string;
|
|
39
|
+
/** Optional human label for the self entry. */
|
|
40
|
+
label?: string;
|
|
41
|
+
/** Sync groups the participant is broadcasting on. Used for the
|
|
42
|
+
* initial `self` entry and for `othersIn(...)` filtering. */
|
|
43
|
+
syncGroups: readonly string[];
|
|
44
|
+
/** Marks `self` as an agent. Server is the source of truth for
|
|
45
|
+
* peers' `isAgent`, but `self` is local — caller decides. */
|
|
46
|
+
isAgent?: boolean;
|
|
47
|
+
}
|
|
48
|
+
/** PresenceStream extended with engine-lifecycle hooks. */
|
|
49
|
+
export interface AttachablePresenceStream extends PresenceStream {
|
|
50
|
+
/** Wire the stream to a now-ready transport. Calls before this are
|
|
51
|
+
* buffered (self mutations only — no wire send). Idempotent. */
|
|
52
|
+
attach(transport: PresenceTransport): void;
|
|
53
|
+
/**
|
|
54
|
+
* Seeds the participant identity once the host resolves it. The stream can
|
|
55
|
+
* be built before identity is known — a hosted client learns who it is
|
|
56
|
+
* from its credential's scope during connect — and until then the
|
|
57
|
+
* construction-time values (possibly empty) would leave the `self` entry
|
|
58
|
+
* blank and let the participant's own echoed frames into `others`. Updates
|
|
59
|
+
* the `self` entry in place, so held references see the resolved identity.
|
|
60
|
+
*/
|
|
61
|
+
setParticipant(participant: {
|
|
62
|
+
id: string;
|
|
63
|
+
kind?: ParticipantKind;
|
|
64
|
+
syncGroups?: readonly string[];
|
|
65
|
+
}): void;
|
|
66
|
+
/** Tear down listeners. Stream object stays usable as a no-op. */
|
|
67
|
+
dispose(): void;
|
|
68
|
+
}
|
|
69
|
+
export declare function createPresenceStream(config: PresenceStreamConfig, transport?: PresenceTransport | null): AttachablePresenceStream;
|