@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,762 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ModelRegistry is the source of truth for model metadata: which model classes
|
|
3
|
+
* exist, the properties and references declared on each, the back-references
|
|
4
|
+
* used for cascade handling, and a stable hash of the whole schema.
|
|
5
|
+
* {@link Model} instances resolve their metadata through the active registry,
|
|
6
|
+
* and {@link InstanceCache} uses it to map between model names and constructor
|
|
7
|
+
* classes. References resolve lazily, so a model may declare a reference to
|
|
8
|
+
* another model that is registered later.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// Removed Node.js crypto import for browser compatibility
|
|
12
|
+
import {
|
|
13
|
+
type ModelMetadata,
|
|
14
|
+
type PropertyMetadata,
|
|
15
|
+
type ReferenceMetadata,
|
|
16
|
+
PropertyType,
|
|
17
|
+
LoadStrategy,
|
|
18
|
+
} from '@abloatai/transaction/types';
|
|
19
|
+
import { globalRuntime } from './context.js';
|
|
20
|
+
import type { RuntimeContext } from './RuntimeContext.js';
|
|
21
|
+
import { AbloValidationError } from '@abloatai/transaction/errors';
|
|
22
|
+
// Type-only — erased at runtime, so no Model ↔ ModelRegistry module cycle.
|
|
23
|
+
import type { Model } from './Model.js';
|
|
24
|
+
import type { ConcreteModelConstructor } from './BaseSyncedStore.js';
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* What callers may hand to {@link ModelRegistry.registerModel}: any concrete
|
|
28
|
+
* `Model` subclass constructor. `never[]` params make every subclass
|
|
29
|
+
* constructor assignable (construct-signature params are contravariant).
|
|
30
|
+
*/
|
|
31
|
+
export type ModelClassInput = new (...args: never[]) => Model;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* What the registry hands BACK: a registered model class — concretely
|
|
35
|
+
* constructible with an optional data row (`ConcreteModelConstructor`, the
|
|
36
|
+
* SDK's existing Model-vs-row construction seam) and carrying `Model`'s
|
|
37
|
+
* statics (`fromJSON`, …). `Omit<typeof Model, never>` keeps the statics
|
|
38
|
+
* while stripping the ABSTRACT construct signature (mapped types drop
|
|
39
|
+
* construct signatures), so `new registry.getModelByName(n)!(...)` is legal.
|
|
40
|
+
* The one cast from {@link ModelClassInput} lives at the validated
|
|
41
|
+
* registration boundary below.
|
|
42
|
+
*/
|
|
43
|
+
export type RegisteredModelClass = Omit<typeof Model, never> &
|
|
44
|
+
ConcreteModelConstructor<Model>;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* {@link ReferenceMetadata} extended with cascade behavior: what happens to a
|
|
48
|
+
* referencing model when the referenced model is deleted or archived.
|
|
49
|
+
*/
|
|
50
|
+
export interface ExtendedReferenceMetadata extends ReferenceMetadata {
|
|
51
|
+
onDelete?: 'cascade' | 'nullify' | 'restrict';
|
|
52
|
+
onArchive?: 'cascade' | 'nullify';
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Reference metadata in its serialized form — `referencedModel` is
|
|
57
|
+
* resolved to the model NAME (string), not the lazy constructor
|
|
58
|
+
* thunk. Produced by `exportRegistryData()` and other debug-side
|
|
59
|
+
* paths. A class function would be unserializable JSON; the name is
|
|
60
|
+
* what consumers (devtools, schema-hash inputs) actually want.
|
|
61
|
+
*/
|
|
62
|
+
export interface SerializedReferenceMetadata
|
|
63
|
+
extends Omit<ExtendedReferenceMetadata, 'referencedModel'> {
|
|
64
|
+
referencedModel: string;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Metadata that records a child model's foreign key to a parent model, used
|
|
69
|
+
* for cascade-aware transaction handling: when the parent is deleted, the
|
|
70
|
+
* child's pending transactions can be cancelled.
|
|
71
|
+
*/
|
|
72
|
+
export interface BackReferenceMetadata {
|
|
73
|
+
/** The parent model name (e.g., 'Report') */
|
|
74
|
+
parentModel: string;
|
|
75
|
+
/** The foreign key property on this model (e.g., 'reportId') */
|
|
76
|
+
foreignKey: string;
|
|
77
|
+
/** Whether to cascade-cancel transactions when parent is deleted */
|
|
78
|
+
cascadeDelete: boolean;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
interface PendingReference {
|
|
82
|
+
modelName: string;
|
|
83
|
+
propertyName: string;
|
|
84
|
+
metadata: ExtendedReferenceMetadata;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
interface RegistryConfig {
|
|
88
|
+
validateOnRegister?: boolean;
|
|
89
|
+
allowLateReferences?: boolean;
|
|
90
|
+
/** The owning client's runtime. Defaults to the module-global bridge. */
|
|
91
|
+
runtime?: RuntimeContext;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Module-level active registry. Set by createSyncEngine so that Model instances
|
|
96
|
+
* (which don't receive DI) can look up metadata without static maps.
|
|
97
|
+
*/
|
|
98
|
+
let _activeRegistry: ModelRegistry | null = null;
|
|
99
|
+
|
|
100
|
+
/** Set the active ModelRegistry instance (called by createSyncEngine) */
|
|
101
|
+
export function setActiveRegistry(registry: ModelRegistry): void {
|
|
102
|
+
_activeRegistry = registry;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Get the active ModelRegistry. Throws if none set. */
|
|
106
|
+
export function getActiveRegistry(): ModelRegistry {
|
|
107
|
+
if (!_activeRegistry) {
|
|
108
|
+
throw new AbloValidationError(
|
|
109
|
+
'No active ModelRegistry — call createSyncEngine() first',
|
|
110
|
+
{ code: 'registry_not_initialized' },
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
return _activeRegistry;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Whether an active ModelRegistry has been set. */
|
|
117
|
+
export function hasActiveRegistry(): boolean {
|
|
118
|
+
return _activeRegistry !== null;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** Clear the active ModelRegistry (tests only). */
|
|
122
|
+
export function clearActiveRegistry(): void {
|
|
123
|
+
_activeRegistry = null;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export class ModelRegistry {
|
|
127
|
+
private models = new Map<string, RegisteredModelClass>();
|
|
128
|
+
private modelMetadata = new Map<string, ModelMetadata>();
|
|
129
|
+
private properties = new Map<string, Map<string, PropertyMetadata>>();
|
|
130
|
+
private references = new Map<string, Map<string, ExtendedReferenceMetadata>>();
|
|
131
|
+
private pendingReferences = new Map<string, PendingReference[]>();
|
|
132
|
+
|
|
133
|
+
// Maps a constructor back to its model name. Keyed as `unknown` on purpose:
|
|
134
|
+
// lookups arrive both as `this.constructor` (a Function) and as typed model
|
|
135
|
+
// classes, and both are accepted without a cast.
|
|
136
|
+
private constructorToModelName = new Map<unknown, string>();
|
|
137
|
+
|
|
138
|
+
// Back-references for cascade-aware transaction handling. Maps a child model
|
|
139
|
+
// name to the parent models it references. The inverse direction (parent to
|
|
140
|
+
// children) is derived on demand by `getChildModels`; it is populated here.
|
|
141
|
+
private backReferences = new Map<string, BackReferenceMetadata[]>();
|
|
142
|
+
|
|
143
|
+
private schemaHash?: string;
|
|
144
|
+
private config: Required<Omit<RegistryConfig, 'runtime'>>;
|
|
145
|
+
private readonly runtime: RuntimeContext;
|
|
146
|
+
private registeredModels = new Set<string>();
|
|
147
|
+
|
|
148
|
+
private pendingHashUpdate = false;
|
|
149
|
+
|
|
150
|
+
constructor(config: RegistryConfig = {}) {
|
|
151
|
+
this.config = {
|
|
152
|
+
validateOnRegister: config.validateOnRegister ?? true,
|
|
153
|
+
allowLateReferences: config.allowLateReferences ?? true,
|
|
154
|
+
};
|
|
155
|
+
this.runtime = config.runtime ?? globalRuntime;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
private validateModelConstructor(name: string, constructor: unknown): void {
|
|
159
|
+
if (typeof constructor !== 'function') {
|
|
160
|
+
throw new AbloValidationError(
|
|
161
|
+
`Model ${name} constructor must be a function`,
|
|
162
|
+
{ code: 'registry_invalid_constructor' },
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const prototype: unknown = constructor.prototype;
|
|
167
|
+
if (!prototype || typeof prototype !== 'object') {
|
|
168
|
+
throw new AbloValidationError(
|
|
169
|
+
`Model ${name} constructor must have a prototype`,
|
|
170
|
+
{ code: 'registry_invalid_constructor' },
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Check for required methods
|
|
175
|
+
const required = ['updateFromData', 'toJSON', 'getModelName'];
|
|
176
|
+
for (const method of required) {
|
|
177
|
+
if (typeof (prototype as Record<string, unknown>)[method] !== 'function') {
|
|
178
|
+
this.runtime.logger.debug('Model missing required method', name, { method });
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
private arePropertiesCompatible(existing: PropertyMetadata, incoming: PropertyMetadata): boolean {
|
|
184
|
+
// For reference-generated ID properties, be more lenient
|
|
185
|
+
// Only check core compatibility, not all metadata fields
|
|
186
|
+
return (
|
|
187
|
+
existing.type === incoming.type &&
|
|
188
|
+
// For indexed, treat undefined as false for comparison
|
|
189
|
+
(existing.indexed ?? false) === (incoming.indexed ?? false) &&
|
|
190
|
+
// For optional, treat undefined as false for comparison
|
|
191
|
+
(existing.optional ?? false) === (incoming.optional ?? false)
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
private addPendingReference(
|
|
196
|
+
modelName: string,
|
|
197
|
+
propertyName: string,
|
|
198
|
+
metadata: ExtendedReferenceMetadata
|
|
199
|
+
): void {
|
|
200
|
+
// Get target model name
|
|
201
|
+
let targetName: string;
|
|
202
|
+
try {
|
|
203
|
+
targetName = metadata.referencedModel()?.name || 'Unknown';
|
|
204
|
+
} catch {
|
|
205
|
+
targetName = 'Unknown';
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
let pending = this.pendingReferences.get(targetName);
|
|
209
|
+
if (!pending) {
|
|
210
|
+
pending = [];
|
|
211
|
+
this.pendingReferences.set(targetName, pending);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
pending.push({ modelName, propertyName, metadata });
|
|
215
|
+
|
|
216
|
+
this.runtime.logger.debug('Reference deferred', `${modelName}.${propertyName}`, { targetModel: targetName });
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
private resolvePendingReferences(targetModelName: string): void {
|
|
220
|
+
const pending = this.pendingReferences.get(targetModelName);
|
|
221
|
+
if (!pending) return;
|
|
222
|
+
|
|
223
|
+
for (const ref of pending) {
|
|
224
|
+
try {
|
|
225
|
+
this.completeReferenceRegistration(ref.modelName, ref.propertyName, ref.metadata);
|
|
226
|
+
this.runtime.logger.debug('Reference resolved', `${ref.modelName}.${ref.propertyName}`, {
|
|
227
|
+
targetModel: targetModelName,
|
|
228
|
+
});
|
|
229
|
+
} catch (error) {
|
|
230
|
+
this.runtime.observability.breadcrumb(
|
|
231
|
+
`Failed to resolve reference ${ref.modelName}.${ref.propertyName}`,
|
|
232
|
+
'sync.database',
|
|
233
|
+
'error',
|
|
234
|
+
{
|
|
235
|
+
error: error instanceof Error ? error.message : String(error),
|
|
236
|
+
}
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
this.pendingReferences.delete(targetModelName);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
private completeReferenceRegistration(
|
|
245
|
+
modelName: string,
|
|
246
|
+
propertyName: string,
|
|
247
|
+
metadata: ExtendedReferenceMetadata
|
|
248
|
+
): void {
|
|
249
|
+
// Store reference
|
|
250
|
+
let refs = this.references.get(modelName);
|
|
251
|
+
if (!refs) {
|
|
252
|
+
refs = new Map();
|
|
253
|
+
this.references.set(modelName, refs);
|
|
254
|
+
}
|
|
255
|
+
refs.set(propertyName, metadata);
|
|
256
|
+
|
|
257
|
+
// Register ID property (skip organizationId as it's handled by models themselves)
|
|
258
|
+
const idPropName = propertyName.endsWith('Id') ? propertyName : `${propertyName}Id`;
|
|
259
|
+
if (idPropName !== 'organizationId') {
|
|
260
|
+
this.registerProperty(modelName, idPropName, {
|
|
261
|
+
type: PropertyType.reference,
|
|
262
|
+
indexed: metadata.indexed || false,
|
|
263
|
+
optional: metadata.nullable || false,
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Register model property
|
|
268
|
+
this.registerProperty(modelName, propertyName, {
|
|
269
|
+
type: PropertyType.referenceModel,
|
|
270
|
+
optional: metadata.nullable || false,
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
this.schemaHash = undefined;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Register a model with validation
|
|
278
|
+
*/
|
|
279
|
+
registerModel(
|
|
280
|
+
name: string,
|
|
281
|
+
constructor: ModelClassInput,
|
|
282
|
+
metadata: ModelMetadata = { loadStrategy: LoadStrategy.instant }
|
|
283
|
+
): void {
|
|
284
|
+
// Validate
|
|
285
|
+
if (this.config.validateOnRegister) {
|
|
286
|
+
this.validateModelConstructor(name, constructor);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Check for duplicate
|
|
290
|
+
if (this.models.has(name)) {
|
|
291
|
+
this.runtime.logger.debug('Model already registered, skipping', name);
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
this.runtime.logger.debug('Registering model', name);
|
|
296
|
+
|
|
297
|
+
// Register. The one cast in this file: input is any Model-subclass
|
|
298
|
+
// constructor (validated above); registered classes are concrete
|
|
299
|
+
// subclasses constructible with `data?` and carrying Model's statics —
|
|
300
|
+
// the shape `RegisteredModelClass` names for every read site.
|
|
301
|
+
const modelClass = constructor as RegisteredModelClass;
|
|
302
|
+
this.models.set(name, modelClass);
|
|
303
|
+
this.modelMetadata.set(name, metadata);
|
|
304
|
+
|
|
305
|
+
// Record the reverse mapping from constructor to model name
|
|
306
|
+
this.constructorToModelName.set(constructor, name);
|
|
307
|
+
|
|
308
|
+
// Initialize property maps
|
|
309
|
+
if (!this.properties.has(name)) {
|
|
310
|
+
this.properties.set(name, new Map());
|
|
311
|
+
}
|
|
312
|
+
if (!this.references.has(name)) {
|
|
313
|
+
this.references.set(name, new Map());
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Mark as registered
|
|
317
|
+
this.registeredModels.add(name);
|
|
318
|
+
|
|
319
|
+
// Resolve pending references to this model
|
|
320
|
+
this.resolvePendingReferences(name);
|
|
321
|
+
|
|
322
|
+
// Invalidate schema hash
|
|
323
|
+
this.schemaHash = undefined;
|
|
324
|
+
|
|
325
|
+
this.runtime.logger.debug('Model registered', name, metadata);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Register property with validation
|
|
330
|
+
*/
|
|
331
|
+
registerProperty(modelName: string, propertyName: string, metadata: PropertyMetadata): void {
|
|
332
|
+
// Validate model exists
|
|
333
|
+
if (!this.models.has(modelName) && this.config.validateOnRegister) {
|
|
334
|
+
throw new AbloValidationError(
|
|
335
|
+
`Cannot register property for unknown model: ${modelName}`,
|
|
336
|
+
{ code: 'registry_unknown_model' },
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// Get or create property map
|
|
341
|
+
let props = this.properties.get(modelName);
|
|
342
|
+
if (!props) {
|
|
343
|
+
props = new Map();
|
|
344
|
+
this.properties.set(modelName, props);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Check for conflicts
|
|
348
|
+
const existing = props.get(propertyName);
|
|
349
|
+
if (existing) {
|
|
350
|
+
if (this.arePropertiesCompatible(existing, metadata)) {
|
|
351
|
+
// Properties are compatible, skip re-registration
|
|
352
|
+
this.runtime.logger.debug('Property already registered (compatible)', `${modelName}.${propertyName}`);
|
|
353
|
+
return;
|
|
354
|
+
} else {
|
|
355
|
+
throw new AbloValidationError(
|
|
356
|
+
`Property ${modelName}.${propertyName} already registered with incompatible metadata`,
|
|
357
|
+
{ code: 'registry_property_conflict' },
|
|
358
|
+
);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
props.set(propertyName, metadata);
|
|
363
|
+
|
|
364
|
+
this.schemaHash = undefined;
|
|
365
|
+
|
|
366
|
+
this.runtime.logger.debug('Property registered', `${modelName}.${propertyName}`, metadata);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Register reference with lazy resolution
|
|
371
|
+
*/
|
|
372
|
+
registerReference(
|
|
373
|
+
modelName: string,
|
|
374
|
+
propertyName: string,
|
|
375
|
+
metadata: ExtendedReferenceMetadata
|
|
376
|
+
): void {
|
|
377
|
+
// Try to resolve target model
|
|
378
|
+
let targetModelName: string;
|
|
379
|
+
try {
|
|
380
|
+
const targetModel = metadata.referencedModel();
|
|
381
|
+
targetModelName = targetModel?.name;
|
|
382
|
+
} catch {
|
|
383
|
+
// Defer resolution
|
|
384
|
+
if (this.config.allowLateReferences) {
|
|
385
|
+
this.addPendingReference(modelName, propertyName, metadata);
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
throw new AbloValidationError(
|
|
389
|
+
`Cannot resolve reference ${modelName}.${propertyName}`,
|
|
390
|
+
{ code: 'registry_reference_unresolved' },
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// Validate target exists or defer
|
|
395
|
+
if (!this.models.has(targetModelName)) {
|
|
396
|
+
if (this.config.allowLateReferences) {
|
|
397
|
+
this.addPendingReference(modelName, propertyName, metadata);
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
throw new AbloValidationError(
|
|
401
|
+
`Reference ${modelName}.${propertyName} points to unknown model ${targetModelName}`,
|
|
402
|
+
{ code: 'registry_reference_unknown_target' },
|
|
403
|
+
);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// Complete registration
|
|
407
|
+
this.completeReferenceRegistration(modelName, propertyName, metadata);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Register a back-reference for cascade-aware transaction handling.
|
|
412
|
+
*
|
|
413
|
+
* When a parent model is deleted, the transaction queue cancels pending
|
|
414
|
+
* transactions for every child model that declares a back-reference to that
|
|
415
|
+
* parent.
|
|
416
|
+
*
|
|
417
|
+
* @param childModelName - The model that holds a foreign key to the parent (e.g., 'Section')
|
|
418
|
+
* @param metadata - The back-reference configuration
|
|
419
|
+
*/
|
|
420
|
+
registerBackReference(childModelName: string, metadata: BackReferenceMetadata): void {
|
|
421
|
+
// Add to instance map
|
|
422
|
+
let refs = this.backReferences.get(childModelName);
|
|
423
|
+
if (!refs) {
|
|
424
|
+
refs = [];
|
|
425
|
+
this.backReferences.set(childModelName, refs);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// Avoid duplicates
|
|
429
|
+
const exists = refs.some(
|
|
430
|
+
(r) => r.parentModel === metadata.parentModel && r.foreignKey === metadata.foreignKey
|
|
431
|
+
);
|
|
432
|
+
if (!exists) {
|
|
433
|
+
refs.push(metadata);
|
|
434
|
+
}
|
|
435
|
+
// Reverse lookup (parent → children) is derived on demand by
|
|
436
|
+
// `getChildModels`, which scans this map.
|
|
437
|
+
|
|
438
|
+
this.runtime.logger.debug('BackReference registered', `${childModelName} -> ${metadata.parentModel}`, {
|
|
439
|
+
foreignKey: metadata.foreignKey,
|
|
440
|
+
cascadeDelete: metadata.cascadeDelete,
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/** Get all models with specific load strategy. */
|
|
445
|
+
getModelsByLoadStrategy(strategy: LoadStrategy): string[] {
|
|
446
|
+
const models: string[] = [];
|
|
447
|
+
for (const [modelName, metadata] of this.modelMetadata) {
|
|
448
|
+
if (metadata.loadStrategy === strategy) {
|
|
449
|
+
models.push(modelName);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
return models;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/** Get model name from constructor (production-safe). */
|
|
456
|
+
getModelNameFromConstructor(constructor: unknown): string | undefined {
|
|
457
|
+
return this.constructorToModelName.get(constructor);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/** Get properties for a model. */
|
|
461
|
+
getPropertiesForModel(modelName: string): Map<string, PropertyMetadata> {
|
|
462
|
+
return this.properties.get(modelName) || new Map();
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* Get all registered model names for this instance
|
|
467
|
+
*/
|
|
468
|
+
getRegisteredModelNames(): string[] {
|
|
469
|
+
return Array.from(this.models.keys());
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/** Get model constructor by name */
|
|
473
|
+
getModelByName(name: string): RegisteredModelClass | undefined {
|
|
474
|
+
return this.models.get(name);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/** Check if model is registered */
|
|
478
|
+
hasModel(name: string): boolean {
|
|
479
|
+
return this.models.has(name);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/** Get model metadata by name */
|
|
483
|
+
getMetadata(name: string): ModelMetadata | undefined {
|
|
484
|
+
return this.modelMetadata.get(name);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/** Get properties for a model */
|
|
488
|
+
getProperties(name: string): Map<string, PropertyMetadata> {
|
|
489
|
+
return this.properties.get(name) || new Map();
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/** Get references for a model */
|
|
493
|
+
getReferences(name: string): Map<string, ExtendedReferenceMetadata> {
|
|
494
|
+
return this.references.get(name) || new Map();
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/** Get indexed properties for a model */
|
|
498
|
+
getIndexedProperties(modelName: string): string[] {
|
|
499
|
+
const properties = this.getProperties(modelName);
|
|
500
|
+
const indexed: string[] = [];
|
|
501
|
+
for (const [propName, metadata] of properties) {
|
|
502
|
+
if (metadata.indexed) indexed.push(propName);
|
|
503
|
+
}
|
|
504
|
+
return indexed;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/** Get back-references for a child model */
|
|
508
|
+
getBackReferences(childModelName: string): BackReferenceMetadata[] {
|
|
509
|
+
return this.backReferences.get(childModelName) || [];
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/** Get child models for a parent */
|
|
513
|
+
getChildModels(parentModelName: string): { childModel: string; foreignKey: string }[] {
|
|
514
|
+
// Derive from backReferences
|
|
515
|
+
const children: { childModel: string; foreignKey: string }[] = [];
|
|
516
|
+
for (const [childModel, refs] of this.backReferences) {
|
|
517
|
+
for (const ref of refs) {
|
|
518
|
+
if (ref.parentModel === parentModelName) {
|
|
519
|
+
children.push({ childModel, foreignKey: ref.foreignKey });
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
return children;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/**
|
|
527
|
+
* Compute a stable hash of the registered schema — model names, property
|
|
528
|
+
* types, and their indexed and optional flags. Memoized until the schema
|
|
529
|
+
* changes.
|
|
530
|
+
*/
|
|
531
|
+
getSchemaHash(): string {
|
|
532
|
+
if (this.schemaHash) return this.schemaHash;
|
|
533
|
+
|
|
534
|
+
const schema: Record<
|
|
535
|
+
string,
|
|
536
|
+
Record<string, { type: PropertyType; indexed: boolean; optional: boolean }>
|
|
537
|
+
> = {};
|
|
538
|
+
|
|
539
|
+
// Build schema object
|
|
540
|
+
for (const [modelName, props] of this.properties) {
|
|
541
|
+
schema[modelName] = {};
|
|
542
|
+
for (const [propName, meta] of props) {
|
|
543
|
+
schema[modelName][propName] = {
|
|
544
|
+
type: meta.type,
|
|
545
|
+
indexed: meta.indexed || false,
|
|
546
|
+
optional: meta.optional || false,
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
// Sort and stringify
|
|
552
|
+
const sorted = JSON.stringify(schema, Object.keys(schema).sort());
|
|
553
|
+
|
|
554
|
+
// Create hash - browser-compatible simple hash
|
|
555
|
+
this.schemaHash = this.simpleHash(sorted);
|
|
556
|
+
|
|
557
|
+
this.runtime.logger.debug('Schema hash updated', this.schemaHash);
|
|
558
|
+
|
|
559
|
+
return this.schemaHash;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* Browser-compatible hash function
|
|
564
|
+
*/
|
|
565
|
+
private simpleHash(str: string): string {
|
|
566
|
+
let hash = 0;
|
|
567
|
+
for (let i = 0; i < str.length; i++) {
|
|
568
|
+
const char = str.charCodeAt(i);
|
|
569
|
+
hash = (hash << 5) - hash + char;
|
|
570
|
+
hash = hash & hash; // Convert to 32bit integer
|
|
571
|
+
}
|
|
572
|
+
return Math.abs(hash).toString(16).padStart(8, '0');
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
/**
|
|
576
|
+
* Static wrapper for backward compatibility
|
|
577
|
+
*/
|
|
578
|
+
|
|
579
|
+
/**
|
|
580
|
+
* Validate all references
|
|
581
|
+
*/
|
|
582
|
+
validateReferences(): { valid: boolean; errors: string[] } {
|
|
583
|
+
const errors: string[] = [];
|
|
584
|
+
|
|
585
|
+
// Check pending references
|
|
586
|
+
for (const [target, pending] of this.pendingReferences) {
|
|
587
|
+
for (const ref of pending) {
|
|
588
|
+
errors.push(`Unresolved reference: ${ref.modelName}.${ref.propertyName} -> ${target}`);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
// Check resolved references
|
|
593
|
+
for (const [modelName, refs] of this.references) {
|
|
594
|
+
for (const [propName, meta] of refs) {
|
|
595
|
+
try {
|
|
596
|
+
const target = meta.referencedModel();
|
|
597
|
+
if (!this.models.has(target.name)) {
|
|
598
|
+
errors.push(`Invalid reference: ${modelName}.${propName} -> ${target.name}`);
|
|
599
|
+
}
|
|
600
|
+
} catch (error) {
|
|
601
|
+
errors.push(`Cannot resolve reference: ${modelName}.${propName}`);
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
const isValid = errors.length === 0;
|
|
607
|
+
if (isValid) {
|
|
608
|
+
this.runtime.logger.info('All model references are valid');
|
|
609
|
+
} else {
|
|
610
|
+
this.runtime.observability.breadcrumb('Reference validation failed', 'sync.database', 'error');
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
return {
|
|
614
|
+
valid: isValid,
|
|
615
|
+
errors,
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* Static wrapper for backward compatibility
|
|
621
|
+
*/
|
|
622
|
+
|
|
623
|
+
/**
|
|
624
|
+
* Start batch registration mode to optimize performance
|
|
625
|
+
*/
|
|
626
|
+
startBatch(): void {
|
|
627
|
+
this.pendingHashUpdate = false;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
/**
|
|
631
|
+
* Static wrapper for backward compatibility
|
|
632
|
+
*/
|
|
633
|
+
|
|
634
|
+
/**
|
|
635
|
+
* End batch registration mode and update schema hash if needed
|
|
636
|
+
*/
|
|
637
|
+
endBatch(): void {
|
|
638
|
+
if (this.pendingHashUpdate) {
|
|
639
|
+
this.getSchemaHash(); // This will recalculate if needed
|
|
640
|
+
this.pendingHashUpdate = false;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
/**
|
|
645
|
+
* Static wrapper for backward compatibility
|
|
646
|
+
*/
|
|
647
|
+
|
|
648
|
+
/**
|
|
649
|
+
* Clear registry
|
|
650
|
+
*/
|
|
651
|
+
clear(): void {
|
|
652
|
+
this.models.clear();
|
|
653
|
+
this.modelMetadata.clear();
|
|
654
|
+
this.properties.clear();
|
|
655
|
+
this.references.clear();
|
|
656
|
+
this.pendingReferences.clear();
|
|
657
|
+
this.registeredModels.clear();
|
|
658
|
+
this.backReferences.clear();
|
|
659
|
+
this.constructorToModelName.clear();
|
|
660
|
+
this.schemaHash = undefined;
|
|
661
|
+
this.pendingHashUpdate = false;
|
|
662
|
+
|
|
663
|
+
this.runtime.logger.info('ModelRegistry cleared');
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
/**
|
|
667
|
+
* Static wrapper for backward compatibility
|
|
668
|
+
*/
|
|
669
|
+
|
|
670
|
+
/**
|
|
671
|
+
* Export for debugging
|
|
672
|
+
*/
|
|
673
|
+
export() {
|
|
674
|
+
return {
|
|
675
|
+
models: Array.from(this.models.keys()),
|
|
676
|
+
metadata: Object.fromEntries(this.modelMetadata),
|
|
677
|
+
properties: Object.fromEntries(
|
|
678
|
+
Array.from(this.properties.entries()).map(([name, props]) => [
|
|
679
|
+
name,
|
|
680
|
+
Object.fromEntries(props),
|
|
681
|
+
])
|
|
682
|
+
),
|
|
683
|
+
references: Object.fromEntries(
|
|
684
|
+
Array.from(this.references.entries()).map(([name, refs]) => [
|
|
685
|
+
name,
|
|
686
|
+
Object.fromEntries(refs),
|
|
687
|
+
])
|
|
688
|
+
),
|
|
689
|
+
pending: Object.fromEntries(
|
|
690
|
+
Array.from(this.pendingReferences.entries()).map(([name, refs]) => [
|
|
691
|
+
name,
|
|
692
|
+
refs.map((r) => `${r.modelName}.${r.propertyName}`),
|
|
693
|
+
])
|
|
694
|
+
),
|
|
695
|
+
schemaHash: this.getSchemaHash(),
|
|
696
|
+
};
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
/**
|
|
700
|
+
* Export registry data for debugging (backward compatibility)
|
|
701
|
+
*/
|
|
702
|
+
exportRegistryData(): {
|
|
703
|
+
models: Record<string, string>;
|
|
704
|
+
properties: Record<string, Record<string, PropertyMetadata>>;
|
|
705
|
+
references: Record<string, Record<string, SerializedReferenceMetadata>>;
|
|
706
|
+
metadata: Record<string, ModelMetadata>;
|
|
707
|
+
schemaHash: string;
|
|
708
|
+
} {
|
|
709
|
+
const models: Record<string, string> = {};
|
|
710
|
+
const properties: Record<string, Record<string, PropertyMetadata>> = {};
|
|
711
|
+
const references: Record<string, Record<string, SerializedReferenceMetadata>> = {};
|
|
712
|
+
const metadata: Record<string, ModelMetadata> = {};
|
|
713
|
+
|
|
714
|
+
// Export models
|
|
715
|
+
for (const [name, constructor] of this.models) {
|
|
716
|
+
models[name] = constructor.name;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
// Export properties
|
|
720
|
+
for (const [modelName, propertyMap] of this.properties) {
|
|
721
|
+
properties[modelName] = {};
|
|
722
|
+
for (const [propName, propMetadata] of propertyMap) {
|
|
723
|
+
properties[modelName][propName] = propMetadata;
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
// Export references
|
|
728
|
+
for (const [modelName, referenceMap] of this.references) {
|
|
729
|
+
references[modelName] = {};
|
|
730
|
+
for (const [refName, refMetadata] of referenceMap) {
|
|
731
|
+
try {
|
|
732
|
+
references[modelName][refName] = {
|
|
733
|
+
...refMetadata,
|
|
734
|
+
referencedModel: refMetadata.referencedModel().name,
|
|
735
|
+
};
|
|
736
|
+
} catch {
|
|
737
|
+
references[modelName][refName] = {
|
|
738
|
+
...refMetadata,
|
|
739
|
+
referencedModel: 'Unresolved',
|
|
740
|
+
};
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
// Export metadata
|
|
746
|
+
for (const [modelName, modelMetadata] of this.modelMetadata) {
|
|
747
|
+
metadata[modelName] = modelMetadata;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
return {
|
|
751
|
+
models,
|
|
752
|
+
properties,
|
|
753
|
+
references,
|
|
754
|
+
metadata,
|
|
755
|
+
schemaHash: this.getSchemaHash(),
|
|
756
|
+
};
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
/**
|
|
760
|
+
* Static wrapper for backward compatibility
|
|
761
|
+
*/
|
|
762
|
+
}
|