From cc16b4ae481edb64c788ac2826a9dc1700585875 Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Tue, 8 Sep 2020 17:06:05 +0200 Subject: [PATCH] Tree-Shake RemoteStore (#3705) --- packages/firestore/exp/dependencies.json | 668 ++++++++- packages/firestore/exp/src/api/components.ts | 10 +- .../firestore/src/core/component_provider.ts | 17 +- .../firestore/src/core/firestore_client.ts | 20 +- packages/firestore/src/core/sync_engine.ts | 38 +- packages/firestore/src/remote/remote_store.ts | 1223 +++++++++-------- .../test/unit/specs/spec_test_runner.ts | 22 +- 7 files changed, 1345 insertions(+), 653 deletions(-) diff --git a/packages/firestore/exp/dependencies.json b/packages/firestore/exp/dependencies.json index 0245a9c5ecb..2d686f1a4c8 100644 --- a/packages/firestore/exp/dependencies.json +++ b/packages/firestore/exp/dependencies.json @@ -1031,6 +1031,7 @@ "acknowledgeBatch", "addDoc", "addMutationCallback", + "addToWritePipeline", "applyArrayRemoveTransformOperation", "applyArrayUnionTransformOperation", "applyDeleteMutationToLocalView", @@ -1058,6 +1059,8 @@ "binaryStringFromUint8Array", "blobEquals", "boundEquals", + "canAddToWritePipeline", + "canUseNetwork", "canonicalId", "canonifyArray", "canonifyBound", @@ -1072,6 +1075,7 @@ "canonifyTimestamp", "canonifyValue", "cast", + "cleanUpWatchStreamState", "coercedFieldValuesArray", "compareArrays", "compareBlobs", @@ -1087,6 +1091,8 @@ "createMetadata", "debugCast", "decodeBase64", + "disableNetworkInternal", + "disableNetworkUntilRecovery", "doc", "documentEntryMap", "documentKeySet", @@ -1094,10 +1100,15 @@ "documentTargetMap", "documentVersionMap", "emitNewSnapsAndNotifyLocalStore", + "enableNetworkInternal", "encodeBase64", "enqueueWrite", "ensureWriteCallbacks", "errorMessage", + "eventManagerOnOnlineStateChange", + "eventManagerOnWatchChange", + "eventManagerOnWatchError", + "executeWithRecovery", "extractFieldMask", "extractLocalPathFromResourceName", "extractMutationBaseValue", @@ -1106,6 +1117,7 @@ "fieldMaskContains", "fieldPathFromDotSeparatedString", "fieldTransformEquals", + "fillWritePipeline", "filterEquals", "forEach", "formatJSON", @@ -1135,7 +1147,9 @@ "getPostMutationVersion", "getSyncEngine", "handleCredentialChange", + "handleTargetError", "handleUserChange", + "handleWriteError", "hardAssert", "hasLimitToFirst", "hasLimitToLast", @@ -1176,11 +1190,13 @@ "newConnection", "newConnectivityMonitor", "newDatastore", + "newEventManager", "newLocalStore", "newPersistentWatchStream", "newPersistentWriteStream", "newQueryComparator", "newQueryForPath", + "newRemoteStore", "newSerializer", "newSyncEngine", "newTarget", @@ -1195,6 +1211,13 @@ "numberEquals", "objectEquals", "objectSize", + "onMutationResult", + "onWatchStreamChange", + "onWatchStreamClose", + "onWatchStreamOpen", + "onWriteHandshakeComplete", + "onWriteStreamClose", + "onWriteStreamOpen", "orderByEquals", "ordinal", "parseArray", @@ -1216,20 +1239,33 @@ "queryMatchesPathAndCollectionGroup", "queryOrderBy", "queryToTarget", + "raiseSnapshotsInSyncEvent", + "raiseWatchSnapshot", "randomBytes", "registerFirestore", "rejectBatch", "rejectFailedWrite", "rejectOutstandingPendingWritesCallbacks", + "remoteStoreApplyPrimaryState", + "remoteStoreEnableNetwork", + "remoteStoreHandleCredentialChange", + "remoteStoreShutdown", "removeComponents", "removeComponents$1", "requireDocument", + "restartNetwork", + "sendUnwatchRequest", + "sendWatchRequest", "serverTimestamp", "serverTransformResults", "setOfflineComponentProvider", "setOnlineComponentProvider", + "shouldStartWatchStream", + "shouldStartWriteStream", "snapshotChangesMap", "sortsBeforeDocument", + "startWatchStream", + "startWriteStream", "stringifyFilter", "stringifyOrderBy", "stringifyQuery", @@ -1311,7 +1347,7 @@ "DocumentKeyReference", "DocumentReference", "DocumentWatchChange", - "EventManager", + "EventManagerImpl", "ExistenceFilter", "ExistenceFilterChange", "ExponentialBackoff", @@ -1369,11 +1405,10 @@ "Precondition", "Query", "QueryImpl", - "QueryListenersInfo", "ReferenceSet", "RemoteDocumentChangeBuffer", "RemoteEvent", - "RemoteStore", + "RemoteStoreImpl", "ResourcePath", "SerializableFieldValue", "ServerTimestampTransform", @@ -1402,7 +1437,7 @@ ], "variables": [] }, - "sizeInBytes": 191755 + "sizeInBytes": 193026 }, "arrayRemove": { "dependencies": { @@ -1727,6 +1762,7 @@ "functions": [ "acknowledgeBatch", "addMutationCallback", + "addToWritePipeline", "applyArrayRemoveTransformOperation", "applyArrayUnionTransformOperation", "applyDeleteMutationToLocalView", @@ -1753,6 +1789,8 @@ "binaryStringFromUint8Array", "blobEquals", "boundEquals", + "canAddToWritePipeline", + "canUseNetwork", "canonicalId", "canonifyArray", "canonifyBound", @@ -1767,6 +1805,7 @@ "canonifyTimestamp", "canonifyValue", "cast", + "cleanUpWatchStreamState", "coercedFieldValuesArray", "compareArrays", "compareBlobs", @@ -1782,21 +1821,29 @@ "debugCast", "decodeBase64", "deleteDoc", + "disableNetworkInternal", + "disableNetworkUntilRecovery", "documentEntryMap", "documentKeySet", "documentMap", "documentTargetMap", "documentVersionMap", "emitNewSnapsAndNotifyLocalStore", + "enableNetworkInternal", "encodeBase64", "enqueueWrite", "ensureWriteCallbacks", + "eventManagerOnOnlineStateChange", + "eventManagerOnWatchChange", + "eventManagerOnWatchError", + "executeWithRecovery", "extractFieldMask", "extractLocalPathFromResourceName", "extractMutationBaseValue", "extractTransformMutationBaseValue", "fail", "fieldTransformEquals", + "fillWritePipeline", "filterEquals", "forEach", "formatJSON", @@ -1824,7 +1871,9 @@ "getPostMutationVersion", "getSyncEngine", "handleCredentialChange", + "handleTargetError", "handleUserChange", + "handleWriteError", "hardAssert", "hasLimitToFirst", "hasLimitToLast", @@ -1860,11 +1909,13 @@ "newConnection", "newConnectivityMonitor", "newDatastore", + "newEventManager", "newLocalStore", "newPersistentWatchStream", "newPersistentWriteStream", "newQueryComparator", "newQueryForPath", + "newRemoteStore", "newSerializer", "newSyncEngine", "newTarget", @@ -1878,6 +1929,13 @@ "numberEquals", "objectEquals", "objectSize", + "onMutationResult", + "onWatchStreamChange", + "onWatchStreamClose", + "onWatchStreamOpen", + "onWriteHandshakeComplete", + "onWriteStreamClose", + "onWriteStreamOpen", "orderByEquals", "patchDocument", "patchObject", @@ -1892,20 +1950,33 @@ "queryMatchesPathAndCollectionGroup", "queryOrderBy", "queryToTarget", + "raiseSnapshotsInSyncEvent", + "raiseWatchSnapshot", "randomBytes", "registerFirestore", "rejectBatch", "rejectFailedWrite", "rejectOutstandingPendingWritesCallbacks", + "remoteStoreApplyPrimaryState", + "remoteStoreEnableNetwork", + "remoteStoreHandleCredentialChange", + "remoteStoreShutdown", "removeComponents", "removeComponents$1", "requireDocument", + "restartNetwork", + "sendUnwatchRequest", + "sendWatchRequest", "serverTimestamp", "serverTransformResults", "setOfflineComponentProvider", "setOnlineComponentProvider", + "shouldStartWatchStream", + "shouldStartWriteStream", "snapshotChangesMap", "sortsBeforeDocument", + "startWatchStream", + "startWriteStream", "stringifyFilter", "stringifyOrderBy", "stringifyQuery", @@ -1977,7 +2048,7 @@ "DocumentKeyReference", "DocumentReference", "DocumentWatchChange", - "EventManager", + "EventManagerImpl", "ExistenceFilter", "ExistenceFilterChange", "ExponentialBackoff", @@ -2031,11 +2102,10 @@ "Precondition", "Query", "QueryImpl", - "QueryListenersInfo", "ReferenceSet", "RemoteDocumentChangeBuffer", "RemoteEvent", - "RemoteStore", + "RemoteStoreImpl", "ResourcePath", "ServerTimestampTransform", "SetMutation", @@ -2062,7 +2132,7 @@ ], "variables": [] }, - "sizeInBytes": 175550 + "sizeInBytes": 176821 }, "deleteField": { "dependencies": { @@ -2109,6 +2179,7 @@ "disableNetwork": { "dependencies": { "functions": [ + "addToWritePipeline", "applyArrayRemoveTransformOperation", "applyArrayUnionTransformOperation", "applyDeleteMutationToLocalView", @@ -2133,6 +2204,8 @@ "binaryStringFromUint8Array", "blobEquals", "boundEquals", + "canAddToWritePipeline", + "canUseNetwork", "canonicalId", "canonifyArray", "canonifyBound", @@ -2147,6 +2220,7 @@ "canonifyTimestamp", "canonifyValue", "cast", + "cleanUpWatchStreamState", "coercedFieldValuesArray", "compareArrays", "compareBlobs", @@ -2162,17 +2236,25 @@ "debugCast", "decodeBase64", "disableNetwork", + "disableNetworkInternal", + "disableNetworkUntilRecovery", "documentEntryMap", "documentKeySet", "documentMap", "documentTargetMap", "documentVersionMap", "emitNewSnapsAndNotifyLocalStore", + "enableNetworkInternal", "encodeBase64", "enqueueNetworkEnabled", + "eventManagerOnOnlineStateChange", + "eventManagerOnWatchChange", + "eventManagerOnWatchError", + "executeWithRecovery", "extractLocalPathFromResourceName", "fail", "fieldTransformEquals", + "fillWritePipeline", "filterEquals", "forEach", "formatJSON", @@ -2201,7 +2283,9 @@ "getPostMutationVersion", "getRemoteStore", "handleCredentialChange", + "handleTargetError", "handleUserChange", + "handleWriteError", "hardAssert", "hasLimitToFirst", "hasLimitToLast", @@ -2235,10 +2319,12 @@ "newConnection", "newConnectivityMonitor", "newDatastore", + "newEventManager", "newLocalStore", "newPersistentWatchStream", "newPersistentWriteStream", "newQueryComparator", + "newRemoteStore", "newSerializer", "newSyncEngine", "newTarget", @@ -2252,6 +2338,13 @@ "numberEquals", "objectEquals", "objectSize", + "onMutationResult", + "onWatchStreamChange", + "onWatchStreamClose", + "onWatchStreamOpen", + "onWriteHandshakeComplete", + "onWriteStreamClose", + "onWriteStreamOpen", "orderByEquals", "patchDocument", "patchObject", @@ -2265,18 +2358,32 @@ "queryMatchesPathAndCollectionGroup", "queryOrderBy", "queryToTarget", + "raiseSnapshotsInSyncEvent", + "raiseWatchSnapshot", "randomBytes", "registerFirestore", "rejectOutstandingPendingWritesCallbacks", + "remoteStoreApplyPrimaryState", + "remoteStoreDisableNetwork", + "remoteStoreEnableNetwork", + "remoteStoreHandleCredentialChange", + "remoteStoreShutdown", "removeComponents", "removeComponents$1", "requireDocument", + "restartNetwork", + "sendUnwatchRequest", + "sendWatchRequest", "serverTimestamp", "serverTransformResults", "setOfflineComponentProvider", "setOnlineComponentProvider", + "shouldStartWatchStream", + "shouldStartWriteStream", "snapshotChangesMap", "sortsBeforeDocument", + "startWatchStream", + "startWriteStream", "stringifyFilter", "stringifyOrderBy", "stringifyQuery", @@ -2340,7 +2447,7 @@ "Document", "DocumentKey", "DocumentWatchChange", - "EventManager", + "EventManagerImpl", "ExistenceFilter", "ExistenceFilterChange", "ExponentialBackoff", @@ -2392,11 +2499,10 @@ "PersistentWriteStream", "Precondition", "QueryImpl", - "QueryListenersInfo", "ReferenceSet", "RemoteDocumentChangeBuffer", "RemoteEvent", - "RemoteStore", + "RemoteStoreImpl", "ResourcePath", "ServerTimestampTransform", "SetMutation", @@ -2423,7 +2529,7 @@ ], "variables": [] }, - "sizeInBytes": 165430 + "sizeInBytes": 166954 }, "doc": { "dependencies": { @@ -2904,6 +3010,7 @@ "dependencies": { "functions": [ "acknowledgeBatch", + "addToWritePipeline", "allocateTarget", "applyActiveTargetsChange", "applyArrayRemoveTransformOperation", @@ -2940,6 +3047,8 @@ "blobEquals", "boundEquals", "bufferEntryComparator", + "canAddToWritePipeline", + "canUseNetwork", "canonicalId", "canonifyArray", "canonifyBound", @@ -2955,6 +3064,7 @@ "canonifyValue", "cast", "checkForAndReportiOSError", + "cleanUpWatchStreamState", "clientMetadataStore", "coercedFieldValuesArray", "collectionParentsStore", @@ -2987,6 +3097,8 @@ "debugCast", "decodeBase64", "decodeResourcePath", + "disableNetworkInternal", + "disableNetworkUntilRecovery", "documentEntryMap", "documentGlobalStore", "documentKeySet", @@ -2999,17 +3111,23 @@ "dropRemoteDocumentChangesStore", "emitNewSnapsAndNotifyLocalStore", "enableMultiTabIndexedDbPersistence", + "enableNetworkInternal", "encodeBase64", "encodeResourcePath", "encodeSegment", "encodeSeparator", "ensureWatchCallbacks", "ensureWriteCallbacks", + "eventManagerOnOnlineStateChange", + "eventManagerOnWatchChange", + "eventManagerOnWatchError", "executeQuery", + "executeWithRecovery", "extractDocumentKeysFromArrayValue", "extractLocalPathFromResourceName", "fail", "fieldTransformEquals", + "fillWritePipeline", "filterEquals", "forEach", "formatJSON", @@ -3068,7 +3186,9 @@ "getWindow", "globalTargetStore", "handleCredentialChange", + "handleTargetError", "handleUserChange", + "handleWriteError", "hardAssert", "hasLimitToFirst", "hasLimitToLast", @@ -3114,12 +3234,14 @@ "newConnection", "newConnectivityMonitor", "newDatastore", + "newEventManager", "newLocalStore", "newPersistentWatchStream", "newPersistentWriteStream", "newQuery", "newQueryComparator", "newQueryForPath", + "newRemoteStore", "newSerializer", "newSyncEngine", "newTarget", @@ -3133,6 +3255,13 @@ "numberEquals", "objectEquals", "objectSize", + "onMutationResult", + "onWatchStreamChange", + "onWatchStreamClose", + "onWatchStreamOpen", + "onWriteHandshakeComplete", + "onWriteStreamClose", + "onWriteStreamOpen", "orderByEquals", "patchDocument", "patchObject", @@ -3149,6 +3278,8 @@ "queryMatchesPathAndCollectionGroup", "queryOrderBy", "queryToTarget", + "raiseSnapshotsInSyncEvent", + "raiseWatchSnapshot", "randomBytes", "registerFirestore", "rejectBatch", @@ -3157,6 +3288,12 @@ "rejectOutstandingPendingWritesCallbacks", "releaseTarget", "remoteDocumentsStore", + "remoteStoreApplyPrimaryState", + "remoteStoreEnableNetwork", + "remoteStoreHandleCredentialChange", + "remoteStoreListen", + "remoteStoreShutdown", + "remoteStoreUnlisten", "removeAndCleanupTarget", "removeCachedMutationBatchMetadata", "removeComponents", @@ -3165,6 +3302,9 @@ "removeMutationBatch", "requireDocument", "resetLimboDocuments", + "restartNetwork", + "sendUnwatchRequest", + "sendWatchRequest", "sentinelKey", "sentinelKey$1", "sentinelRow", @@ -3173,8 +3313,12 @@ "setOfflineComponentProvider", "setOnlineComponentProvider", "shouldPersistTargetData", + "shouldStartWatchStream", + "shouldStartWriteStream", "snapshotChangesMap", "sortsBeforeDocument", + "startWatchStream", + "startWriteStream", "stringifyFilter", "stringifyOrderBy", "stringifyQuery", @@ -3276,7 +3420,7 @@ "DocumentKey", "DocumentSet", "DocumentWatchChange", - "EventManager", + "EventManagerImpl", "ExistenceFilter", "ExistenceFilterChange", "ExponentialBackoff", @@ -3354,14 +3498,13 @@ "PersistentWriteStream", "Precondition", "QueryImpl", - "QueryListenersInfo", "QueryTargetMetadata", "QueryView", "ReferenceSet", "RemoteClientState", "RemoteDocumentChangeBuffer", "RemoteEvent", - "RemoteStore", + "RemoteStoreImpl", "RemovedLimboDocument", "ResourcePath", "RollingSequenceNumberBuffer", @@ -3398,11 +3541,12 @@ ], "variables": [] }, - "sizeInBytes": 302237 + "sizeInBytes": 304449 }, "enableNetwork": { "dependencies": { "functions": [ + "addToWritePipeline", "applyArrayRemoveTransformOperation", "applyArrayUnionTransformOperation", "applyDeleteMutationToLocalView", @@ -3427,6 +3571,8 @@ "binaryStringFromUint8Array", "blobEquals", "boundEquals", + "canAddToWritePipeline", + "canUseNetwork", "canonicalId", "canonifyArray", "canonifyBound", @@ -3441,6 +3587,7 @@ "canonifyTimestamp", "canonifyValue", "cast", + "cleanUpWatchStreamState", "coercedFieldValuesArray", "compareArrays", "compareBlobs", @@ -3455,6 +3602,8 @@ "createMetadata", "debugCast", "decodeBase64", + "disableNetworkInternal", + "disableNetworkUntilRecovery", "documentEntryMap", "documentKeySet", "documentMap", @@ -3462,11 +3611,17 @@ "documentVersionMap", "emitNewSnapsAndNotifyLocalStore", "enableNetwork", + "enableNetworkInternal", "encodeBase64", "enqueueNetworkEnabled", + "eventManagerOnOnlineStateChange", + "eventManagerOnWatchChange", + "eventManagerOnWatchError", + "executeWithRecovery", "extractLocalPathFromResourceName", "fail", "fieldTransformEquals", + "fillWritePipeline", "filterEquals", "forEach", "formatJSON", @@ -3495,7 +3650,9 @@ "getPostMutationVersion", "getRemoteStore", "handleCredentialChange", + "handleTargetError", "handleUserChange", + "handleWriteError", "hardAssert", "hasLimitToFirst", "hasLimitToLast", @@ -3529,10 +3686,12 @@ "newConnection", "newConnectivityMonitor", "newDatastore", + "newEventManager", "newLocalStore", "newPersistentWatchStream", "newPersistentWriteStream", "newQueryComparator", + "newRemoteStore", "newSerializer", "newSyncEngine", "newTarget", @@ -3546,6 +3705,13 @@ "numberEquals", "objectEquals", "objectSize", + "onMutationResult", + "onWatchStreamChange", + "onWatchStreamClose", + "onWatchStreamOpen", + "onWriteHandshakeComplete", + "onWriteStreamClose", + "onWriteStreamOpen", "orderByEquals", "patchDocument", "patchObject", @@ -3559,18 +3725,32 @@ "queryMatchesPathAndCollectionGroup", "queryOrderBy", "queryToTarget", + "raiseSnapshotsInSyncEvent", + "raiseWatchSnapshot", "randomBytes", "registerFirestore", "rejectOutstandingPendingWritesCallbacks", + "remoteStoreApplyPrimaryState", + "remoteStoreDisableNetwork", + "remoteStoreEnableNetwork", + "remoteStoreHandleCredentialChange", + "remoteStoreShutdown", "removeComponents", "removeComponents$1", "requireDocument", + "restartNetwork", + "sendUnwatchRequest", + "sendWatchRequest", "serverTimestamp", "serverTransformResults", "setOfflineComponentProvider", "setOnlineComponentProvider", + "shouldStartWatchStream", + "shouldStartWriteStream", "snapshotChangesMap", "sortsBeforeDocument", + "startWatchStream", + "startWriteStream", "stringifyFilter", "stringifyOrderBy", "stringifyQuery", @@ -3634,7 +3814,7 @@ "Document", "DocumentKey", "DocumentWatchChange", - "EventManager", + "EventManagerImpl", "ExistenceFilter", "ExistenceFilterChange", "ExponentialBackoff", @@ -3686,11 +3866,10 @@ "PersistentWriteStream", "Precondition", "QueryImpl", - "QueryListenersInfo", "ReferenceSet", "RemoteDocumentChangeBuffer", "RemoteEvent", - "RemoteStore", + "RemoteStoreImpl", "ResourcePath", "ServerTimestampTransform", "SetMutation", @@ -3717,7 +3896,7 @@ ], "variables": [] }, - "sizeInBytes": 165427 + "sizeInBytes": 166951 }, "endAt": { "dependencies": { @@ -3978,6 +4157,7 @@ "getDoc": { "dependencies": { "functions": [ + "addToWritePipeline", "allocateTarget", "applyArrayRemoveTransformOperation", "applyArrayUnionTransformOperation", @@ -4006,6 +4186,8 @@ "binaryStringFromUint8Array", "blobEquals", "boundEquals", + "canAddToWritePipeline", + "canUseNetwork", "canonicalId", "canonifyArray", "canonifyBound", @@ -4020,6 +4202,7 @@ "canonifyTimestamp", "canonifyValue", "cast", + "cleanUpWatchStreamState", "coercedFieldValuesArray", "compareArrays", "compareBlobs", @@ -4037,23 +4220,33 @@ "createMetadata", "debugCast", "decodeBase64", + "disableNetworkInternal", + "disableNetworkUntilRecovery", "documentEntryMap", "documentKeySet", "documentMap", "documentTargetMap", "documentVersionMap", "emitNewSnapsAndNotifyLocalStore", + "enableNetworkInternal", "encodeBase64", "enqueueListen", "enqueueReadDocumentViaSnapshotListener", "ensureWatchCallbacks", "errorMessage", + "eventManagerListen", + "eventManagerOnOnlineStateChange", + "eventManagerOnWatchChange", + "eventManagerOnWatchError", + "eventManagerUnlisten", "executeQuery", + "executeWithRecovery", "extractLocalPathFromResourceName", "fail", "fieldPathFromArgument$1", "fieldPathFromDotSeparatedString", "fieldTransformEquals", + "fillWritePipeline", "filterEquals", "forEach", "formatJSON", @@ -4087,7 +4280,9 @@ "getPreviousValue", "getRemoteKeysForTarget", "handleCredentialChange", + "handleTargetError", "handleUserChange", + "handleWriteError", "hardAssert", "hasLimitToFirst", "hasLimitToLast", @@ -4125,11 +4320,13 @@ "newConnection", "newConnectivityMonitor", "newDatastore", + "newEventManager", "newLocalStore", "newPersistentWatchStream", "newPersistentWriteStream", "newQueryComparator", "newQueryForPath", + "newRemoteStore", "newSerializer", "newSyncEngine", "newTarget", @@ -4143,6 +4340,13 @@ "numberEquals", "objectEquals", "objectSize", + "onMutationResult", + "onWatchStreamChange", + "onWatchStreamClose", + "onWatchStreamOpen", + "onWriteHandshakeComplete", + "onWriteStreamClose", + "onWriteStreamOpen", "orderByEquals", "ordinal", "patchDocument", @@ -4158,23 +4362,38 @@ "queryMatchesPathAndCollectionGroup", "queryOrderBy", "queryToTarget", + "raiseSnapshotsInSyncEvent", + "raiseWatchSnapshot", "randomBytes", "registerFirestore", "rejectListen", "rejectOutstandingPendingWritesCallbacks", "releaseTarget", + "remoteStoreApplyPrimaryState", + "remoteStoreEnableNetwork", + "remoteStoreHandleCredentialChange", + "remoteStoreListen", + "remoteStoreShutdown", + "remoteStoreUnlisten", "removeAndCleanupTarget", "removeComponents", "removeComponents$1", "removeLimboTarget", "requireDocument", + "restartNetwork", + "sendUnwatchRequest", + "sendWatchRequest", "serverTimestamp", "serverTransformResults", "setOfflineComponentProvider", "setOnlineComponentProvider", "shouldPersistTargetData", + "shouldStartWatchStream", + "shouldStartWriteStream", "snapshotChangesMap", "sortsBeforeDocument", + "startWatchStream", + "startWriteStream", "stringifyFilter", "stringifyOrderBy", "stringifyQuery", @@ -4262,7 +4481,7 @@ "DocumentSnapshot", "DocumentSnapshot$1", "DocumentWatchChange", - "EventManager", + "EventManagerImpl", "ExistenceFilter", "ExistenceFilterChange", "ExponentialBackoff", @@ -4327,7 +4546,7 @@ "ReferenceSet", "RemoteDocumentChangeBuffer", "RemoteEvent", - "RemoteStore", + "RemoteStoreImpl", "RemovedLimboDocument", "ResourcePath", "ServerTimestampTransform", @@ -4359,7 +4578,7 @@ ], "variables": [] }, - "sizeInBytes": 209370 + "sizeInBytes": 212907 }, "getDocFromCache": { "dependencies": { @@ -4618,6 +4837,7 @@ "getDocFromServer": { "dependencies": { "functions": [ + "addToWritePipeline", "allocateTarget", "applyArrayRemoveTransformOperation", "applyArrayUnionTransformOperation", @@ -4646,6 +4866,8 @@ "binaryStringFromUint8Array", "blobEquals", "boundEquals", + "canAddToWritePipeline", + "canUseNetwork", "canonicalId", "canonifyArray", "canonifyBound", @@ -4660,6 +4882,7 @@ "canonifyTimestamp", "canonifyValue", "cast", + "cleanUpWatchStreamState", "coercedFieldValuesArray", "compareArrays", "compareBlobs", @@ -4677,23 +4900,33 @@ "createMetadata", "debugCast", "decodeBase64", + "disableNetworkInternal", + "disableNetworkUntilRecovery", "documentEntryMap", "documentKeySet", "documentMap", "documentTargetMap", "documentVersionMap", "emitNewSnapsAndNotifyLocalStore", + "enableNetworkInternal", "encodeBase64", "enqueueListen", "enqueueReadDocumentViaSnapshotListener", "ensureWatchCallbacks", "errorMessage", + "eventManagerListen", + "eventManagerOnOnlineStateChange", + "eventManagerOnWatchChange", + "eventManagerOnWatchError", + "eventManagerUnlisten", "executeQuery", + "executeWithRecovery", "extractLocalPathFromResourceName", "fail", "fieldPathFromArgument$1", "fieldPathFromDotSeparatedString", "fieldTransformEquals", + "fillWritePipeline", "filterEquals", "forEach", "formatJSON", @@ -4727,7 +4960,9 @@ "getPreviousValue", "getRemoteKeysForTarget", "handleCredentialChange", + "handleTargetError", "handleUserChange", + "handleWriteError", "hardAssert", "hasLimitToFirst", "hasLimitToLast", @@ -4765,11 +5000,13 @@ "newConnection", "newConnectivityMonitor", "newDatastore", + "newEventManager", "newLocalStore", "newPersistentWatchStream", "newPersistentWriteStream", "newQueryComparator", "newQueryForPath", + "newRemoteStore", "newSerializer", "newSyncEngine", "newTarget", @@ -4783,6 +5020,13 @@ "numberEquals", "objectEquals", "objectSize", + "onMutationResult", + "onWatchStreamChange", + "onWatchStreamClose", + "onWatchStreamOpen", + "onWriteHandshakeComplete", + "onWriteStreamClose", + "onWriteStreamOpen", "orderByEquals", "ordinal", "patchDocument", @@ -4798,23 +5042,38 @@ "queryMatchesPathAndCollectionGroup", "queryOrderBy", "queryToTarget", + "raiseSnapshotsInSyncEvent", + "raiseWatchSnapshot", "randomBytes", "registerFirestore", "rejectListen", "rejectOutstandingPendingWritesCallbacks", "releaseTarget", + "remoteStoreApplyPrimaryState", + "remoteStoreEnableNetwork", + "remoteStoreHandleCredentialChange", + "remoteStoreListen", + "remoteStoreShutdown", + "remoteStoreUnlisten", "removeAndCleanupTarget", "removeComponents", "removeComponents$1", "removeLimboTarget", "requireDocument", + "restartNetwork", + "sendUnwatchRequest", + "sendWatchRequest", "serverTimestamp", "serverTransformResults", "setOfflineComponentProvider", "setOnlineComponentProvider", "shouldPersistTargetData", + "shouldStartWatchStream", + "shouldStartWriteStream", "snapshotChangesMap", "sortsBeforeDocument", + "startWatchStream", + "startWriteStream", "stringifyFilter", "stringifyOrderBy", "stringifyQuery", @@ -4902,7 +5161,7 @@ "DocumentSnapshot", "DocumentSnapshot$1", "DocumentWatchChange", - "EventManager", + "EventManagerImpl", "ExistenceFilter", "ExistenceFilterChange", "ExponentialBackoff", @@ -4967,7 +5226,7 @@ "ReferenceSet", "RemoteDocumentChangeBuffer", "RemoteEvent", - "RemoteStore", + "RemoteStoreImpl", "RemovedLimboDocument", "ResourcePath", "ServerTimestampTransform", @@ -4999,11 +5258,12 @@ ], "variables": [] }, - "sizeInBytes": 209426 + "sizeInBytes": 212963 }, "getDocs": { "dependencies": { "functions": [ + "addToWritePipeline", "allocateTarget", "applyArrayRemoveTransformOperation", "applyArrayUnionTransformOperation", @@ -5032,6 +5292,8 @@ "binaryStringFromUint8Array", "blobEquals", "boundEquals", + "canAddToWritePipeline", + "canUseNetwork", "canonicalId", "canonifyArray", "canonifyBound", @@ -5047,6 +5309,7 @@ "canonifyValue", "cast", "changesFromSnapshot", + "cleanUpWatchStreamState", "coercedFieldValuesArray", "compareArrays", "compareBlobs", @@ -5063,23 +5326,33 @@ "createMetadata", "debugCast", "decodeBase64", + "disableNetworkInternal", + "disableNetworkUntilRecovery", "documentEntryMap", "documentKeySet", "documentMap", "documentTargetMap", "documentVersionMap", "emitNewSnapsAndNotifyLocalStore", + "enableNetworkInternal", "encodeBase64", "enqueueExecuteQueryViaSnapshotListener", "enqueueListen", "ensureWatchCallbacks", "errorMessage", + "eventManagerListen", + "eventManagerOnOnlineStateChange", + "eventManagerOnWatchChange", + "eventManagerOnWatchError", + "eventManagerUnlisten", "executeQuery", + "executeWithRecovery", "extractLocalPathFromResourceName", "fail", "fieldPathFromArgument$1", "fieldPathFromDotSeparatedString", "fieldTransformEquals", + "fillWritePipeline", "filterEquals", "forEach", "formatJSON", @@ -5113,7 +5386,9 @@ "getPreviousValue", "getRemoteKeysForTarget", "handleCredentialChange", + "handleTargetError", "handleUserChange", + "handleWriteError", "hardAssert", "hasLimitToFirst", "hasLimitToLast", @@ -5151,11 +5426,13 @@ "newConnection", "newConnectivityMonitor", "newDatastore", + "newEventManager", "newLocalStore", "newPersistentWatchStream", "newPersistentWriteStream", "newQueryComparator", "newQueryForPath", + "newRemoteStore", "newSerializer", "newSyncEngine", "newTarget", @@ -5169,6 +5446,13 @@ "numberEquals", "objectEquals", "objectSize", + "onMutationResult", + "onWatchStreamChange", + "onWatchStreamClose", + "onWatchStreamOpen", + "onWriteHandshakeComplete", + "onWriteStreamClose", + "onWriteStreamOpen", "orderByEquals", "ordinal", "patchDocument", @@ -5184,24 +5468,39 @@ "queryMatchesPathAndCollectionGroup", "queryOrderBy", "queryToTarget", + "raiseSnapshotsInSyncEvent", + "raiseWatchSnapshot", "randomBytes", "registerFirestore", "rejectListen", "rejectOutstandingPendingWritesCallbacks", "releaseTarget", + "remoteStoreApplyPrimaryState", + "remoteStoreEnableNetwork", + "remoteStoreHandleCredentialChange", + "remoteStoreListen", + "remoteStoreShutdown", + "remoteStoreUnlisten", "removeAndCleanupTarget", "removeComponents", "removeComponents$1", "removeLimboTarget", "requireDocument", + "restartNetwork", "resultChangeType", + "sendUnwatchRequest", + "sendWatchRequest", "serverTimestamp", "serverTransformResults", "setOfflineComponentProvider", "setOnlineComponentProvider", "shouldPersistTargetData", + "shouldStartWatchStream", + "shouldStartWriteStream", "snapshotChangesMap", "sortsBeforeDocument", + "startWatchStream", + "startWriteStream", "stringifyFilter", "stringifyOrderBy", "stringifyQuery", @@ -5290,7 +5589,7 @@ "DocumentSnapshot", "DocumentSnapshot$1", "DocumentWatchChange", - "EventManager", + "EventManagerImpl", "ExistenceFilter", "ExistenceFilterChange", "ExponentialBackoff", @@ -5356,7 +5655,7 @@ "ReferenceSet", "RemoteDocumentChangeBuffer", "RemoteEvent", - "RemoteStore", + "RemoteStoreImpl", "RemovedLimboDocument", "ResourcePath", "ServerTimestampTransform", @@ -5388,7 +5687,7 @@ ], "variables": [] }, - "sizeInBytes": 211712 + "sizeInBytes": 215249 }, "getDocsFromCache": { "dependencies": { @@ -5659,6 +5958,7 @@ "getDocsFromServer": { "dependencies": { "functions": [ + "addToWritePipeline", "allocateTarget", "applyArrayRemoveTransformOperation", "applyArrayUnionTransformOperation", @@ -5687,6 +5987,8 @@ "binaryStringFromUint8Array", "blobEquals", "boundEquals", + "canAddToWritePipeline", + "canUseNetwork", "canonicalId", "canonifyArray", "canonifyBound", @@ -5702,6 +6004,7 @@ "canonifyValue", "cast", "changesFromSnapshot", + "cleanUpWatchStreamState", "coercedFieldValuesArray", "compareArrays", "compareBlobs", @@ -5718,23 +6021,33 @@ "createMetadata", "debugCast", "decodeBase64", + "disableNetworkInternal", + "disableNetworkUntilRecovery", "documentEntryMap", "documentKeySet", "documentMap", "documentTargetMap", "documentVersionMap", "emitNewSnapsAndNotifyLocalStore", + "enableNetworkInternal", "encodeBase64", "enqueueExecuteQueryViaSnapshotListener", "enqueueListen", "ensureWatchCallbacks", "errorMessage", + "eventManagerListen", + "eventManagerOnOnlineStateChange", + "eventManagerOnWatchChange", + "eventManagerOnWatchError", + "eventManagerUnlisten", "executeQuery", + "executeWithRecovery", "extractLocalPathFromResourceName", "fail", "fieldPathFromArgument$1", "fieldPathFromDotSeparatedString", "fieldTransformEquals", + "fillWritePipeline", "filterEquals", "forEach", "formatJSON", @@ -5768,7 +6081,9 @@ "getPreviousValue", "getRemoteKeysForTarget", "handleCredentialChange", + "handleTargetError", "handleUserChange", + "handleWriteError", "hardAssert", "hasLimitToFirst", "hasLimitToLast", @@ -5806,11 +6121,13 @@ "newConnection", "newConnectivityMonitor", "newDatastore", + "newEventManager", "newLocalStore", "newPersistentWatchStream", "newPersistentWriteStream", "newQueryComparator", "newQueryForPath", + "newRemoteStore", "newSerializer", "newSyncEngine", "newTarget", @@ -5824,6 +6141,13 @@ "numberEquals", "objectEquals", "objectSize", + "onMutationResult", + "onWatchStreamChange", + "onWatchStreamClose", + "onWatchStreamOpen", + "onWriteHandshakeComplete", + "onWriteStreamClose", + "onWriteStreamOpen", "orderByEquals", "ordinal", "patchDocument", @@ -5839,24 +6163,39 @@ "queryMatchesPathAndCollectionGroup", "queryOrderBy", "queryToTarget", + "raiseSnapshotsInSyncEvent", + "raiseWatchSnapshot", "randomBytes", "registerFirestore", "rejectListen", "rejectOutstandingPendingWritesCallbacks", "releaseTarget", + "remoteStoreApplyPrimaryState", + "remoteStoreEnableNetwork", + "remoteStoreHandleCredentialChange", + "remoteStoreListen", + "remoteStoreShutdown", + "remoteStoreUnlisten", "removeAndCleanupTarget", "removeComponents", "removeComponents$1", "removeLimboTarget", "requireDocument", + "restartNetwork", "resultChangeType", + "sendUnwatchRequest", + "sendWatchRequest", "serverTimestamp", "serverTransformResults", "setOfflineComponentProvider", "setOnlineComponentProvider", "shouldPersistTargetData", + "shouldStartWatchStream", + "shouldStartWriteStream", "snapshotChangesMap", "sortsBeforeDocument", + "startWatchStream", + "startWriteStream", "stringifyFilter", "stringifyOrderBy", "stringifyQuery", @@ -5944,7 +6283,7 @@ "DocumentSnapshot", "DocumentSnapshot$1", "DocumentWatchChange", - "EventManager", + "EventManagerImpl", "ExistenceFilter", "ExistenceFilterChange", "ExponentialBackoff", @@ -6010,7 +6349,7 @@ "ReferenceSet", "RemoteDocumentChangeBuffer", "RemoteEvent", - "RemoteStore", + "RemoteStoreImpl", "RemovedLimboDocument", "ResourcePath", "ServerTimestampTransform", @@ -6042,7 +6381,7 @@ ], "variables": [] }, - "sizeInBytes": 211451 + "sizeInBytes": 214988 }, "getFirestore": { "dependencies": { @@ -6264,6 +6603,7 @@ "onSnapshot": { "dependencies": { "functions": [ + "addToWritePipeline", "allocateTarget", "applyArrayRemoveTransformOperation", "applyArrayUnionTransformOperation", @@ -6292,6 +6632,8 @@ "binaryStringFromUint8Array", "blobEquals", "boundEquals", + "canAddToWritePipeline", + "canUseNetwork", "canonicalId", "canonifyArray", "canonifyBound", @@ -6307,6 +6649,7 @@ "canonifyValue", "cast", "changesFromSnapshot", + "cleanUpWatchStreamState", "coercedFieldValuesArray", "compareArrays", "compareBlobs", @@ -6324,22 +6667,32 @@ "createMetadata", "debugCast", "decodeBase64", + "disableNetworkInternal", + "disableNetworkUntilRecovery", "documentEntryMap", "documentKeySet", "documentMap", "documentTargetMap", "documentVersionMap", "emitNewSnapsAndNotifyLocalStore", + "enableNetworkInternal", "encodeBase64", "enqueueListen", "ensureWatchCallbacks", "errorMessage", + "eventManagerListen", + "eventManagerOnOnlineStateChange", + "eventManagerOnWatchChange", + "eventManagerOnWatchError", + "eventManagerUnlisten", "executeQuery", + "executeWithRecovery", "extractLocalPathFromResourceName", "fail", "fieldPathFromArgument$1", "fieldPathFromDotSeparatedString", "fieldTransformEquals", + "fillWritePipeline", "filterEquals", "forEach", "formatJSON", @@ -6372,7 +6725,9 @@ "getPreviousValue", "getRemoteKeysForTarget", "handleCredentialChange", + "handleTargetError", "handleUserChange", + "handleWriteError", "hardAssert", "hasLimitToFirst", "hasLimitToLast", @@ -6412,11 +6767,13 @@ "newConnection", "newConnectivityMonitor", "newDatastore", + "newEventManager", "newLocalStore", "newPersistentWatchStream", "newPersistentWriteStream", "newQueryComparator", "newQueryForPath", + "newRemoteStore", "newSerializer", "newSyncEngine", "newTarget", @@ -6430,7 +6787,14 @@ "numberEquals", "objectEquals", "objectSize", + "onMutationResult", "onSnapshot", + "onWatchStreamChange", + "onWatchStreamClose", + "onWatchStreamOpen", + "onWriteHandshakeComplete", + "onWriteStreamClose", + "onWriteStreamOpen", "orderByEquals", "ordinal", "patchDocument", @@ -6446,24 +6810,39 @@ "queryMatchesPathAndCollectionGroup", "queryOrderBy", "queryToTarget", + "raiseSnapshotsInSyncEvent", + "raiseWatchSnapshot", "randomBytes", "registerFirestore", "rejectListen", "rejectOutstandingPendingWritesCallbacks", "releaseTarget", + "remoteStoreApplyPrimaryState", + "remoteStoreEnableNetwork", + "remoteStoreHandleCredentialChange", + "remoteStoreListen", + "remoteStoreShutdown", + "remoteStoreUnlisten", "removeAndCleanupTarget", "removeComponents", "removeComponents$1", "removeLimboTarget", "requireDocument", + "restartNetwork", "resultChangeType", + "sendUnwatchRequest", + "sendWatchRequest", "serverTimestamp", "serverTransformResults", "setOfflineComponentProvider", "setOnlineComponentProvider", "shouldPersistTargetData", + "shouldStartWatchStream", + "shouldStartWriteStream", "snapshotChangesMap", "sortsBeforeDocument", + "startWatchStream", + "startWriteStream", "stringifyFilter", "stringifyOrderBy", "stringifyQuery", @@ -6552,7 +6931,7 @@ "DocumentSnapshot", "DocumentSnapshot$1", "DocumentWatchChange", - "EventManager", + "EventManagerImpl", "ExistenceFilter", "ExistenceFilterChange", "ExponentialBackoff", @@ -6618,7 +6997,7 @@ "ReferenceSet", "RemoteDocumentChangeBuffer", "RemoteEvent", - "RemoteStore", + "RemoteStoreImpl", "RemovedLimboDocument", "ResourcePath", "ServerTimestampTransform", @@ -6650,11 +7029,13 @@ ], "variables": [] }, - "sizeInBytes": 212795 + "sizeInBytes": 216332 }, "onSnapshotsInSync": { "dependencies": { "functions": [ + "addSnapshotsInSyncListener", + "addToWritePipeline", "allocateTarget", "applyArrayRemoveTransformOperation", "applyArrayUnionTransformOperation", @@ -6683,6 +7064,8 @@ "binaryStringFromUint8Array", "blobEquals", "boundEquals", + "canAddToWritePipeline", + "canUseNetwork", "canonicalId", "canonifyArray", "canonifyBound", @@ -6697,6 +7080,7 @@ "canonifyTimestamp", "canonifyValue", "cast", + "cleanUpWatchStreamState", "coercedFieldValuesArray", "compareArrays", "compareBlobs", @@ -6712,19 +7096,27 @@ "createMetadata", "debugCast", "decodeBase64", + "disableNetworkInternal", + "disableNetworkUntilRecovery", "documentEntryMap", "documentKeySet", "documentMap", "documentTargetMap", "documentVersionMap", "emitNewSnapsAndNotifyLocalStore", + "enableNetworkInternal", "encodeBase64", "enqueueSnapshotsInSyncListen", "ensureWatchCallbacks", + "eventManagerOnOnlineStateChange", + "eventManagerOnWatchChange", + "eventManagerOnWatchError", "executeQuery", + "executeWithRecovery", "extractLocalPathFromResourceName", "fail", "fieldTransformEquals", + "fillWritePipeline", "filterEquals", "forEach", "formatJSON", @@ -6754,7 +7146,9 @@ "getPostMutationVersion", "getRemoteKeysForTarget", "handleCredentialChange", + "handleTargetError", "handleUserChange", + "handleWriteError", "hardAssert", "hasLimitToFirst", "hasLimitToLast", @@ -6792,11 +7186,13 @@ "newConnection", "newConnectivityMonitor", "newDatastore", + "newEventManager", "newLocalStore", "newPersistentWatchStream", "newPersistentWriteStream", "newQueryComparator", "newQueryForPath", + "newRemoteStore", "newSerializer", "newSyncEngine", "newTarget", @@ -6810,7 +7206,14 @@ "numberEquals", "objectEquals", "objectSize", + "onMutationResult", "onSnapshotsInSync", + "onWatchStreamChange", + "onWatchStreamClose", + "onWatchStreamOpen", + "onWriteHandshakeComplete", + "onWriteStreamClose", + "onWriteStreamOpen", "orderByEquals", "patchDocument", "patchObject", @@ -6825,23 +7228,39 @@ "queryMatchesPathAndCollectionGroup", "queryOrderBy", "queryToTarget", + "raiseSnapshotsInSyncEvent", + "raiseWatchSnapshot", "randomBytes", "registerFirestore", "rejectListen", "rejectOutstandingPendingWritesCallbacks", "releaseTarget", + "remoteStoreApplyPrimaryState", + "remoteStoreEnableNetwork", + "remoteStoreHandleCredentialChange", + "remoteStoreListen", + "remoteStoreShutdown", + "remoteStoreUnlisten", "removeAndCleanupTarget", "removeComponents", "removeComponents$1", "removeLimboTarget", + "removeSnapshotsInSyncListener", "requireDocument", + "restartNetwork", + "sendUnwatchRequest", + "sendWatchRequest", "serverTimestamp", "serverTransformResults", "setOfflineComponentProvider", "setOnlineComponentProvider", "shouldPersistTargetData", + "shouldStartWatchStream", + "shouldStartWriteStream", "snapshotChangesMap", "sortsBeforeDocument", + "startWatchStream", + "startWriteStream", "stringifyFilter", "stringifyOrderBy", "stringifyQuery", @@ -6913,7 +7332,7 @@ "DocumentKey", "DocumentSet", "DocumentWatchChange", - "EventManager", + "EventManagerImpl", "ExistenceFilter", "ExistenceFilterChange", "ExponentialBackoff", @@ -6966,12 +7385,11 @@ "PersistentWriteStream", "Precondition", "QueryImpl", - "QueryListenersInfo", "QueryView", "ReferenceSet", "RemoteDocumentChangeBuffer", "RemoteEvent", - "RemoteStore", + "RemoteStoreImpl", "RemovedLimboDocument", "ResourcePath", "ServerTimestampTransform", @@ -7001,7 +7419,7 @@ ], "variables": [] }, - "sizeInBytes": 192150 + "sizeInBytes": 194654 }, "orderBy": { "dependencies": { @@ -7482,6 +7900,7 @@ "functions": [ "acknowledgeBatch", "addMutationCallback", + "addToWritePipeline", "applyArrayRemoveTransformOperation", "applyArrayUnionTransformOperation", "applyDeleteMutationToLocalView", @@ -7509,6 +7928,8 @@ "binaryStringFromUint8Array", "blobEquals", "boundEquals", + "canAddToWritePipeline", + "canUseNetwork", "canonicalId", "canonifyArray", "canonifyBound", @@ -7523,6 +7944,7 @@ "canonifyTimestamp", "canonifyValue", "cast", + "cleanUpWatchStreamState", "coercedFieldValuesArray", "compareArrays", "compareBlobs", @@ -7538,16 +7960,23 @@ "createMetadata", "debugCast", "decodeBase64", + "disableNetworkInternal", + "disableNetworkUntilRecovery", "documentEntryMap", "documentKeySet", "documentMap", "documentTargetMap", "documentVersionMap", "emitNewSnapsAndNotifyLocalStore", + "enableNetworkInternal", "encodeBase64", "enqueueWrite", "ensureWriteCallbacks", "errorMessage", + "eventManagerOnOnlineStateChange", + "eventManagerOnWatchChange", + "eventManagerOnWatchError", + "executeWithRecovery", "extractFieldMask", "extractLocalPathFromResourceName", "extractMutationBaseValue", @@ -7556,6 +7985,7 @@ "fieldMaskContains", "fieldPathFromDotSeparatedString", "fieldTransformEquals", + "fillWritePipeline", "filterEquals", "forEach", "formatJSON", @@ -7585,7 +8015,9 @@ "getPostMutationVersion", "getSyncEngine", "handleCredentialChange", + "handleTargetError", "handleUserChange", + "handleWriteError", "hardAssert", "hasLimitToFirst", "hasLimitToLast", @@ -7626,11 +8058,13 @@ "newConnection", "newConnectivityMonitor", "newDatastore", + "newEventManager", "newLocalStore", "newPersistentWatchStream", "newPersistentWriteStream", "newQueryComparator", "newQueryForPath", + "newRemoteStore", "newSerializer", "newSyncEngine", "newTarget", @@ -7645,6 +8079,13 @@ "numberEquals", "objectEquals", "objectSize", + "onMutationResult", + "onWatchStreamChange", + "onWatchStreamClose", + "onWatchStreamOpen", + "onWriteHandshakeComplete", + "onWriteStreamClose", + "onWriteStreamOpen", "orderByEquals", "ordinal", "parseArray", @@ -7666,21 +8107,34 @@ "queryMatchesPathAndCollectionGroup", "queryOrderBy", "queryToTarget", + "raiseSnapshotsInSyncEvent", + "raiseWatchSnapshot", "randomBytes", "registerFirestore", "rejectBatch", "rejectFailedWrite", "rejectOutstandingPendingWritesCallbacks", + "remoteStoreApplyPrimaryState", + "remoteStoreEnableNetwork", + "remoteStoreHandleCredentialChange", + "remoteStoreShutdown", "removeComponents", "removeComponents$1", "requireDocument", + "restartNetwork", + "sendUnwatchRequest", + "sendWatchRequest", "serverTimestamp", "serverTransformResults", "setDoc", "setOfflineComponentProvider", "setOnlineComponentProvider", + "shouldStartWatchStream", + "shouldStartWriteStream", "snapshotChangesMap", "sortsBeforeDocument", + "startWatchStream", + "startWriteStream", "stringifyFilter", "stringifyOrderBy", "stringifyQuery", @@ -7762,7 +8216,7 @@ "DocumentKeyReference", "DocumentReference", "DocumentWatchChange", - "EventManager", + "EventManagerImpl", "ExistenceFilter", "ExistenceFilterChange", "ExponentialBackoff", @@ -7820,11 +8274,10 @@ "Precondition", "Query", "QueryImpl", - "QueryListenersInfo", "ReferenceSet", "RemoteDocumentChangeBuffer", "RemoteEvent", - "RemoteStore", + "RemoteStoreImpl", "ResourcePath", "SerializableFieldValue", "ServerTimestampTransform", @@ -7853,7 +8306,7 @@ ], "variables": [] }, - "sizeInBytes": 190892 + "sizeInBytes": 192163 }, "setLogLevel": { "dependencies": { @@ -8312,6 +8765,7 @@ "functions": [ "acknowledgeBatch", "addMutationCallback", + "addToWritePipeline", "applyArrayRemoveTransformOperation", "applyArrayUnionTransformOperation", "applyDeleteMutationToLocalView", @@ -8338,6 +8792,8 @@ "binaryStringFromUint8Array", "blobEquals", "boundEquals", + "canAddToWritePipeline", + "canUseNetwork", "canonicalId", "canonifyArray", "canonifyBound", @@ -8352,6 +8808,7 @@ "canonifyTimestamp", "canonifyValue", "cast", + "cleanUpWatchStreamState", "coercedFieldValuesArray", "compareArrays", "compareBlobs", @@ -8367,16 +8824,23 @@ "createMetadata", "debugCast", "decodeBase64", + "disableNetworkInternal", + "disableNetworkUntilRecovery", "documentEntryMap", "documentKeySet", "documentMap", "documentTargetMap", "documentVersionMap", "emitNewSnapsAndNotifyLocalStore", + "enableNetworkInternal", "encodeBase64", "enqueueWrite", "ensureWriteCallbacks", "errorMessage", + "eventManagerOnOnlineStateChange", + "eventManagerOnWatchChange", + "eventManagerOnWatchError", + "executeWithRecovery", "extractFieldMask", "extractLocalPathFromResourceName", "extractMutationBaseValue", @@ -8386,6 +8850,7 @@ "fieldPathFromArgument", "fieldPathFromDotSeparatedString", "fieldTransformEquals", + "fillWritePipeline", "filterEquals", "forEach", "formatJSON", @@ -8415,7 +8880,9 @@ "getPostMutationVersion", "getSyncEngine", "handleCredentialChange", + "handleTargetError", "handleUserChange", + "handleWriteError", "hardAssert", "hasLimitToFirst", "hasLimitToLast", @@ -8456,11 +8923,13 @@ "newConnection", "newConnectivityMonitor", "newDatastore", + "newEventManager", "newLocalStore", "newPersistentWatchStream", "newPersistentWriteStream", "newQueryComparator", "newQueryForPath", + "newRemoteStore", "newSerializer", "newSyncEngine", "newTarget", @@ -8475,6 +8944,13 @@ "numberEquals", "objectEquals", "objectSize", + "onMutationResult", + "onWatchStreamChange", + "onWatchStreamClose", + "onWatchStreamOpen", + "onWriteHandshakeComplete", + "onWriteStreamClose", + "onWriteStreamOpen", "orderByEquals", "ordinal", "parseArray", @@ -8497,20 +8973,33 @@ "queryMatchesPathAndCollectionGroup", "queryOrderBy", "queryToTarget", + "raiseSnapshotsInSyncEvent", + "raiseWatchSnapshot", "randomBytes", "registerFirestore", "rejectBatch", "rejectFailedWrite", "rejectOutstandingPendingWritesCallbacks", + "remoteStoreApplyPrimaryState", + "remoteStoreEnableNetwork", + "remoteStoreHandleCredentialChange", + "remoteStoreShutdown", "removeComponents", "removeComponents$1", "requireDocument", + "restartNetwork", + "sendUnwatchRequest", + "sendWatchRequest", "serverTimestamp", "serverTransformResults", "setOfflineComponentProvider", "setOnlineComponentProvider", + "shouldStartWatchStream", + "shouldStartWriteStream", "snapshotChangesMap", "sortsBeforeDocument", + "startWatchStream", + "startWriteStream", "stringifyFilter", "stringifyOrderBy", "stringifyQuery", @@ -8594,7 +9083,7 @@ "DocumentKeyReference", "DocumentReference", "DocumentWatchChange", - "EventManager", + "EventManagerImpl", "ExistenceFilter", "ExistenceFilterChange", "ExponentialBackoff", @@ -8653,11 +9142,10 @@ "Precondition", "Query", "QueryImpl", - "QueryListenersInfo", "ReferenceSet", "RemoteDocumentChangeBuffer", "RemoteEvent", - "RemoteStore", + "RemoteStoreImpl", "ResourcePath", "SerializableFieldValue", "ServerTimestampTransform", @@ -8686,11 +9174,12 @@ ], "variables": [] }, - "sizeInBytes": 192391 + "sizeInBytes": 193662 }, "waitForPendingWrites": { "dependencies": { "functions": [ + "addToWritePipeline", "applyArrayRemoveTransformOperation", "applyArrayUnionTransformOperation", "applyDeleteMutationToLocalView", @@ -8715,6 +9204,8 @@ "binaryStringFromUint8Array", "blobEquals", "boundEquals", + "canAddToWritePipeline", + "canUseNetwork", "canonicalId", "canonifyArray", "canonifyBound", @@ -8729,6 +9220,7 @@ "canonifyTimestamp", "canonifyValue", "cast", + "cleanUpWatchStreamState", "coercedFieldValuesArray", "compareArrays", "compareBlobs", @@ -8743,17 +9235,25 @@ "createMetadata", "debugCast", "decodeBase64", + "disableNetworkInternal", + "disableNetworkUntilRecovery", "documentEntryMap", "documentKeySet", "documentMap", "documentTargetMap", "documentVersionMap", "emitNewSnapsAndNotifyLocalStore", + "enableNetworkInternal", "encodeBase64", "enqueueWaitForPendingWrites", + "eventManagerOnOnlineStateChange", + "eventManagerOnWatchChange", + "eventManagerOnWatchError", + "executeWithRecovery", "extractLocalPathFromResourceName", "fail", "fieldTransformEquals", + "fillWritePipeline", "filterEquals", "forEach", "formatJSON", @@ -8782,7 +9282,9 @@ "getPostMutationVersion", "getSyncEngine", "handleCredentialChange", + "handleTargetError", "handleUserChange", + "handleWriteError", "hardAssert", "hasLimitToFirst", "hasLimitToLast", @@ -8816,10 +9318,12 @@ "newConnection", "newConnectivityMonitor", "newDatastore", + "newEventManager", "newLocalStore", "newPersistentWatchStream", "newPersistentWriteStream", "newQueryComparator", + "newRemoteStore", "newSerializer", "newSyncEngine", "newTarget", @@ -8833,6 +9337,13 @@ "numberEquals", "objectEquals", "objectSize", + "onMutationResult", + "onWatchStreamChange", + "onWatchStreamClose", + "onWatchStreamOpen", + "onWriteHandshakeComplete", + "onWriteStreamClose", + "onWriteStreamOpen", "orderByEquals", "patchDocument", "patchObject", @@ -8846,19 +9357,32 @@ "queryMatchesPathAndCollectionGroup", "queryOrderBy", "queryToTarget", + "raiseSnapshotsInSyncEvent", + "raiseWatchSnapshot", "randomBytes", "registerFirestore", "registerPendingWritesCallback", "rejectOutstandingPendingWritesCallbacks", + "remoteStoreApplyPrimaryState", + "remoteStoreEnableNetwork", + "remoteStoreHandleCredentialChange", + "remoteStoreShutdown", "removeComponents", "removeComponents$1", "requireDocument", + "restartNetwork", + "sendUnwatchRequest", + "sendWatchRequest", "serverTimestamp", "serverTransformResults", "setOfflineComponentProvider", "setOnlineComponentProvider", + "shouldStartWatchStream", + "shouldStartWriteStream", "snapshotChangesMap", "sortsBeforeDocument", + "startWatchStream", + "startWriteStream", "stringifyFilter", "stringifyOrderBy", "stringifyQuery", @@ -8923,7 +9447,7 @@ "Document", "DocumentKey", "DocumentWatchChange", - "EventManager", + "EventManagerImpl", "ExistenceFilter", "ExistenceFilterChange", "ExponentialBackoff", @@ -8975,11 +9499,10 @@ "PersistentWriteStream", "Precondition", "QueryImpl", - "QueryListenersInfo", "ReferenceSet", "RemoteDocumentChangeBuffer", "RemoteEvent", - "RemoteStore", + "RemoteStoreImpl", "ResourcePath", "ServerTimestampTransform", "SetMutation", @@ -9006,7 +9529,7 @@ ], "variables": [] }, - "sizeInBytes": 166263 + "sizeInBytes": 167534 }, "where": { "dependencies": { @@ -9161,6 +9684,7 @@ "functions": [ "acknowledgeBatch", "addMutationCallback", + "addToWritePipeline", "applyArrayRemoveTransformOperation", "applyArrayUnionTransformOperation", "applyDeleteMutationToLocalView", @@ -9188,6 +9712,8 @@ "binaryStringFromUint8Array", "blobEquals", "boundEquals", + "canAddToWritePipeline", + "canUseNetwork", "canonicalId", "canonifyArray", "canonifyBound", @@ -9202,6 +9728,7 @@ "canonifyTimestamp", "canonifyValue", "cast", + "cleanUpWatchStreamState", "coercedFieldValuesArray", "compareArrays", "compareBlobs", @@ -9217,16 +9744,23 @@ "createMetadata", "debugCast", "decodeBase64", + "disableNetworkInternal", + "disableNetworkUntilRecovery", "documentEntryMap", "documentKeySet", "documentMap", "documentTargetMap", "documentVersionMap", "emitNewSnapsAndNotifyLocalStore", + "enableNetworkInternal", "encodeBase64", "enqueueWrite", "ensureWriteCallbacks", "errorMessage", + "eventManagerOnOnlineStateChange", + "eventManagerOnWatchChange", + "eventManagerOnWatchError", + "executeWithRecovery", "extractFieldMask", "extractLocalPathFromResourceName", "extractMutationBaseValue", @@ -9236,6 +9770,7 @@ "fieldPathFromArgument", "fieldPathFromDotSeparatedString", "fieldTransformEquals", + "fillWritePipeline", "filterEquals", "forEach", "formatJSON", @@ -9265,7 +9800,9 @@ "getPostMutationVersion", "getSyncEngine", "handleCredentialChange", + "handleTargetError", "handleUserChange", + "handleWriteError", "hardAssert", "hasLimitToFirst", "hasLimitToLast", @@ -9306,11 +9843,13 @@ "newConnection", "newConnectivityMonitor", "newDatastore", + "newEventManager", "newLocalStore", "newPersistentWatchStream", "newPersistentWriteStream", "newQueryComparator", "newQueryForPath", + "newRemoteStore", "newSerializer", "newSyncEngine", "newTarget", @@ -9325,6 +9864,13 @@ "numberEquals", "objectEquals", "objectSize", + "onMutationResult", + "onWatchStreamChange", + "onWatchStreamClose", + "onWatchStreamOpen", + "onWriteHandshakeComplete", + "onWriteStreamClose", + "onWriteStreamOpen", "orderByEquals", "ordinal", "parseArray", @@ -9348,20 +9894,33 @@ "queryMatchesPathAndCollectionGroup", "queryOrderBy", "queryToTarget", + "raiseSnapshotsInSyncEvent", + "raiseWatchSnapshot", "randomBytes", "registerFirestore", "rejectBatch", "rejectFailedWrite", "rejectOutstandingPendingWritesCallbacks", + "remoteStoreApplyPrimaryState", + "remoteStoreEnableNetwork", + "remoteStoreHandleCredentialChange", + "remoteStoreShutdown", "removeComponents", "removeComponents$1", "requireDocument", + "restartNetwork", + "sendUnwatchRequest", + "sendWatchRequest", "serverTimestamp", "serverTransformResults", "setOfflineComponentProvider", "setOnlineComponentProvider", + "shouldStartWatchStream", + "shouldStartWriteStream", "snapshotChangesMap", "sortsBeforeDocument", + "startWatchStream", + "startWriteStream", "stringifyFilter", "stringifyOrderBy", "stringifyQuery", @@ -9446,7 +10005,7 @@ "DocumentKeyReference", "DocumentReference", "DocumentWatchChange", - "EventManager", + "EventManagerImpl", "ExistenceFilter", "ExistenceFilterChange", "ExponentialBackoff", @@ -9506,11 +10065,10 @@ "Precondition", "Query", "QueryImpl", - "QueryListenersInfo", "ReferenceSet", "RemoteDocumentChangeBuffer", "RemoteEvent", - "RemoteStore", + "RemoteStoreImpl", "ResourcePath", "SerializableFieldValue", "ServerTimestampTransform", @@ -9540,6 +10098,6 @@ ], "variables": [] }, - "sizeInBytes": 196058 + "sizeInBytes": 197329 } } \ No newline at end of file diff --git a/packages/firestore/exp/src/api/components.ts b/packages/firestore/exp/src/api/components.ts index 11409f63806..3330b727f27 100644 --- a/packages/firestore/exp/src/api/components.ts +++ b/packages/firestore/exp/src/api/components.ts @@ -26,12 +26,15 @@ import { import { handleUserChange, LocalStore } from '../../../src/local/local_store'; import { Deferred } from '../../../src/util/promise'; import { logDebug } from '../../../src/util/log'; +import { + RemoteStore, + remoteStoreHandleCredentialChange +} from '../../../src/remote/remote_store'; import { SyncEngine, syncEngineListen, syncEngineUnlisten } from '../../../src/core/sync_engine'; -import { RemoteStore } from '../../../src/remote/remote_store'; import { Persistence } from '../../../src/local/persistence'; import { EventManager } from '../../../src/core/event_manager'; export const LOG_TAG = 'ComponentProvider'; @@ -100,7 +103,10 @@ export async function setOnlineComponentProvider( firestore._setCredentialChangeListener(user => // TODO(firestoreexp): This should be enqueueRetryable. firestore._queue.enqueueAndForget(() => - onlineComponentProvider.remoteStore.handleCredentialChange(user) + remoteStoreHandleCredentialChange( + onlineComponentProvider.remoteStore, + user + ) ) ); onlineDeferred.resolve(onlineComponentProvider); diff --git a/packages/firestore/src/core/component_provider.ts b/packages/firestore/src/core/component_provider.ts index 03a2aa5455f..aa05d5c4680 100644 --- a/packages/firestore/src/core/component_provider.ts +++ b/packages/firestore/src/core/component_provider.ts @@ -37,7 +37,12 @@ import { newSyncEngine, SyncEngine } from './sync_engine'; -import { RemoteStore } from '../remote/remote_store'; +import { + newRemoteStore, + RemoteStore, + remoteStoreApplyPrimaryState, + remoteStoreShutdown +} from '../remote/remote_store'; import { EventManager, newEventManager, @@ -361,8 +366,10 @@ export class OnlineComponentProvider { this.syncEngine ); - await this.remoteStore.start(); - await this.remoteStore.applyPrimaryState(this.syncEngine.isPrimaryClient); + await remoteStoreApplyPrimaryState( + this.remoteStore, + this.syncEngine.isPrimaryClient + ); } createEventManager(cfg: ComponentConfiguration): EventManager { @@ -376,7 +383,7 @@ export class OnlineComponentProvider { } createRemoteStore(cfg: ComponentConfiguration): RemoteStore { - return new RemoteStore( + return newRemoteStore( this.localStore, this.datastore, cfg.asyncQueue, @@ -403,6 +410,6 @@ export class OnlineComponentProvider { } terminate(): Promise { - return this.remoteStore.shutdown(); + return remoteStoreShutdown(this.remoteStore); } } diff --git a/packages/firestore/src/core/firestore_client.ts b/packages/firestore/src/core/firestore_client.ts index e435af13f66..9c2aeb94a3c 100644 --- a/packages/firestore/src/core/firestore_client.ts +++ b/packages/firestore/src/core/firestore_client.ts @@ -28,7 +28,13 @@ import { GarbageCollectionScheduler, Persistence } from '../local/persistence'; import { Document, NoDocument } from '../model/document'; import { DocumentKey } from '../model/document_key'; import { Mutation } from '../model/mutation'; -import { RemoteStore } from '../remote/remote_store'; +import { + remoteStoreHandleCredentialChange, + RemoteStore, + remoteStoreEnableNetwork, + remoteStoreDisableNetwork, + remoteStoreShutdown +} from '../remote/remote_store'; import { AsyncQueue, wrapInUserErrorIfRecoverable } from '../util/async_queue'; import { Code, FirestoreError } from '../util/error'; import { logDebug } from '../util/log'; @@ -209,7 +215,7 @@ export class FirestoreClient { ).then(this.initializationDone.resolve, this.initializationDone.reject); } else { this.asyncQueue.enqueueRetryable(() => - this.remoteStore.handleCredentialChange(user) + remoteStoreHandleCredentialChange(this.remoteStore, user) ); } }); @@ -228,7 +234,7 @@ export class FirestoreClient { this.verifyNotTerminated(); return this.asyncQueue.enqueue(() => { this.persistence.setNetworkEnabled(true); - return this.remoteStore.enableNetwork(); + return remoteStoreEnableNetwork(this.remoteStore); }); } @@ -375,7 +381,7 @@ export class FirestoreClient { this.verifyNotTerminated(); return this.asyncQueue.enqueue(() => { this.persistence.setNetworkEnabled(false); - return this.remoteStore.disableNetwork(); + return remoteStoreDisableNetwork(this.remoteStore); }); } @@ -389,7 +395,7 @@ export class FirestoreClient { this.gcScheduler.stop(); } - await this.remoteStore.shutdown(); + await remoteStoreShutdown(this.remoteStore); await this.sharedClientState.shutdown(); await this.persistence.shutdown(); @@ -580,7 +586,9 @@ export function enqueueNetworkEnabled( ): Promise { return asyncQueue.enqueue(() => { persistence.setNetworkEnabled(enabled); - return enabled ? remoteStore.enableNetwork() : remoteStore.disableNetwork(); + return enabled + ? remoteStoreEnableNetwork(remoteStore) + : remoteStoreDisableNetwork(remoteStore); }); } diff --git a/packages/firestore/src/core/sync_engine.ts b/packages/firestore/src/core/sync_engine.ts index 02327e4aee9..88ef6ce1fc7 100644 --- a/packages/firestore/src/core/sync_engine.ts +++ b/packages/firestore/src/core/sync_engine.ts @@ -48,7 +48,14 @@ import { DocumentKey } from '../model/document_key'; import { Mutation } from '../model/mutation'; import { BATCHID_UNKNOWN, MutationBatchResult } from '../model/mutation_batch'; import { RemoteEvent, TargetChange } from '../remote/remote_event'; -import { RemoteStore } from '../remote/remote_store'; +import { + canUseNetwork, + fillWritePipeline, + RemoteStore, + remoteStoreApplyPrimaryState, + remoteStoreListen, + remoteStoreUnlisten +} from '../remote/remote_store'; import { debugAssert, debugCast, fail, hardAssert } from '../util/assert'; import { Code, FirestoreError } from '../util/error'; import { logDebug } from '../util/log'; @@ -338,7 +345,7 @@ export async function syncEngineListen( status === 'current' ); if (syncEngineImpl.isPrimaryClient) { - syncEngineImpl.remoteStore.listen(targetData); + remoteStoreListen(syncEngineImpl.remoteStore, targetData); } } @@ -439,7 +446,7 @@ export async function syncEngineUnlisten( ) .then(() => { syncEngineImpl.sharedClientState.clearQueryState(queryView.targetId); - syncEngineImpl.remoteStore.unlisten(queryView.targetId); + remoteStoreUnlisten(syncEngineImpl.remoteStore, queryView.targetId); removeAndCleanupTarget(syncEngineImpl, queryView.targetId); }) .catch(ignoreIfPrimaryLeaseLoss); @@ -477,7 +484,7 @@ export async function syncEngineWrite( syncEngineImpl.sharedClientState.addPendingMutation(result.batchId); addMutationCallback(syncEngineImpl, result.batchId, userCallback); await emitNewSnapsAndNotifyLocalStore(syncEngineImpl, result.changes); - await syncEngineImpl.remoteStore.fillWritePipeline(); + await fillWritePipeline(syncEngineImpl.remoteStore); } catch (e) { // If we can't persist the mutation, we reject the user callback and // don't send the mutation. The user can then retry the write. @@ -725,7 +732,7 @@ export async function registerPendingWritesCallback( callback: Deferred ): Promise { const syncEngineImpl = debugCast(syncEngine, SyncEngineImpl); - if (!syncEngineImpl.remoteStore.canUseNetwork()) { + if (!canUseNetwork(syncEngineImpl.remoteStore)) { logDebug( LOG_TAG, 'The network is disabled. The task returned by ' + @@ -888,7 +895,7 @@ function removeLimboTarget( return; } - syncEngineImpl.remoteStore.unlisten(limboTargetId); + remoteStoreUnlisten(syncEngineImpl.remoteStore, limboTargetId); syncEngineImpl.activeLimboTargetsByKey = syncEngineImpl.activeLimboTargetsByKey.remove( key ); @@ -960,7 +967,8 @@ function pumpEnqueuedLimboResolutions(syncEngineImpl: SyncEngineImpl): void { key, limboTargetId ); - syncEngineImpl.remoteStore.listen( + remoteStoreListen( + syncEngineImpl.remoteStore, new TargetData( queryToTarget(newQueryForPath(key.path)), limboTargetId, @@ -1181,7 +1189,7 @@ export async function applyBatchState( // If we are the primary client, we need to send this write to the // backend. Secondary clients will ignore these writes since their remote // connection is disabled. - await syncEngineImpl.remoteStore.fillWritePipeline(); + await fillWritePipeline(syncEngineImpl.remoteStore); } else if (batchState === 'acknowledged' || batchState === 'rejected') { // NOTE: Both these methods are no-ops for batches that originated from // other clients. @@ -1217,9 +1225,9 @@ export async function applyPrimaryState( /*transitionToPrimary=*/ true ); syncEngineImpl._isPrimaryClient = true; - await syncEngineImpl.remoteStore.applyPrimaryState(true); + await remoteStoreApplyPrimaryState(syncEngineImpl.remoteStore, true); for (const targetData of activeQueries) { - syncEngineImpl.remoteStore.listen(targetData); + remoteStoreListen(syncEngineImpl.remoteStore, targetData); } } else if (isPrimary === false && syncEngineImpl._isPrimaryClient !== false) { const activeTargets: TargetId[] = []; @@ -1238,7 +1246,7 @@ export async function applyPrimaryState( ); }); } - syncEngineImpl.remoteStore.unlisten(targetId); + remoteStoreUnlisten(syncEngineImpl.remoteStore, targetId); }); await p; @@ -1249,7 +1257,7 @@ export async function applyPrimaryState( ); resetLimboDocuments(syncEngineImpl); syncEngineImpl._isPrimaryClient = false; - await syncEngineImpl.remoteStore.applyPrimaryState(false); + await remoteStoreApplyPrimaryState(syncEngineImpl.remoteStore, false); } } @@ -1257,7 +1265,7 @@ export async function applyPrimaryState( function resetLimboDocuments(syncEngine: SyncEngine): void { const syncEngineImpl = debugCast(syncEngine, SyncEngineImpl); syncEngineImpl.activeLimboResolutionsByTarget.forEach((_, targetId) => { - syncEngineImpl.remoteStore.unlisten(targetId); + remoteStoreUnlisten(syncEngineImpl.remoteStore, targetId); }); syncEngineImpl.limboDocumentRefs.removeAllReferences(); syncEngineImpl.activeLimboResolutionsByTarget = new Map< @@ -1447,7 +1455,7 @@ export async function applyActiveTargetsChange( targetData.targetId, /*current=*/ false ); - syncEngineImpl.remoteStore.listen(targetData); + remoteStoreListen(syncEngineImpl.remoteStore, targetData); } for (const targetId of removed) { @@ -1464,7 +1472,7 @@ export async function applyActiveTargetsChange( /* keepPersistedTargetData */ false ) .then(() => { - syncEngineImpl.remoteStore.unlisten(targetId); + remoteStoreUnlisten(syncEngineImpl.remoteStore, targetId); removeAndCleanupTarget(syncEngineImpl, targetId); }) .catch(ignoreIfPrimaryLeaseLoss); diff --git a/packages/firestore/src/remote/remote_store.ts b/packages/firestore/src/remote/remote_store.ts index 893fbedef8b..96e56995567 100644 --- a/packages/firestore/src/remote/remote_store.ts +++ b/packages/firestore/src/remote/remote_store.ts @@ -29,10 +29,9 @@ import { MutationBatch, MutationBatchResult } from '../model/mutation_batch'; -import { debugAssert } from '../util/assert'; +import { debugAssert, debugCast } from '../util/assert'; import { FirestoreError } from '../util/error'; import { logDebug } from '../util/log'; -import { DocumentKeySet } from '../model/collections'; import { AsyncQueue } from '../util/async_queue'; import { ConnectivityMonitor, NetworkStatus } from './connectivity_monitor'; import { @@ -50,7 +49,6 @@ import { isPermanentWriteError } from './rpc_error'; import { DocumentWatchChange, ExistenceFilterChange, - TargetMetadataProvider, WatchChange, WatchChangeAggregator, WatchTargetChange, @@ -100,7 +98,21 @@ const enum OfflineCause { * - retrying mutations that failed because of network problems. * - acking mutations to the SyncEngine once they are accepted or rejected. */ -export class RemoteStore implements TargetMetadataProvider { +export interface RemoteStore { + /** + * SyncEngine to notify of watch and write events. This must be set + * immediately after construction. + */ + remoteSyncer: RemoteSyncer; + + /** + * Starts up the remote store, creating streams, restoring state from + * LocalStore, etc. + */ + start(): Promise; +} + +class RemoteStoreImpl implements RemoteStore { /** * A list of up to MAX_PENDING_WRITES writes that we have fetched from the * LocalStore via fillWritePipeline() and have or will send to the write @@ -118,7 +130,7 @@ export class RemoteStore implements TargetMetadataProvider { * purely based on order, and so we can just shift() writes from the front of * the writePipeline as we receive responses. */ - private writePipeline: MutationBatch[] = []; + writePipeline: MutationBatch[] = []; /** * A mapping of watched targets that the client cares about tracking and the @@ -129,29 +141,29 @@ export class RemoteStore implements TargetMetadataProvider { * to the server. The targets removed with unlistens are removed eagerly * without waiting for confirmation from the listen stream. */ - private listenTargets = new Map(); + listenTargets = new Map(); - private connectivityMonitor: ConnectivityMonitor; - private watchStream: PersistentListenStream; - private writeStream: PersistentWriteStream; - private watchChangeAggregator: WatchChangeAggregator | null = null; + connectivityMonitor: ConnectivityMonitor; + watchStream: PersistentListenStream; + writeStream: PersistentWriteStream; + watchChangeAggregator: WatchChangeAggregator | null = null; /** * A set of reasons for why the RemoteStore may be offline. If empty, the * RemoteStore may start its network connections. */ - private offlineCauses = new Set(); + offlineCauses = new Set(); - private onlineStateTracker: OnlineStateTracker; + onlineStateTracker: OnlineStateTracker; constructor( /** * The local store, used to fill the write pipeline with outbound mutations. */ - private localStore: LocalStore, + readonly localStore: LocalStore, /** The client-side proxy for interacting with the backend. */ - private datastore: Datastore, - private asyncQueue: AsyncQueue, + readonly datastore: Datastore, + readonly asyncQueue: AsyncQueue, onlineStateHandler: (onlineState: OnlineState) => void, connectivityMonitor: ConnectivityMonitor ) { @@ -161,12 +173,12 @@ export class RemoteStore implements TargetMetadataProvider { // Porting Note: Unlike iOS, `restartNetwork()` is called even when the // network becomes unreachable as we don't have any other way to tear // down our streams. - if (this.canUseNetwork()) { + if (canUseNetwork(this)) { logDebug( LOG_TAG, 'Restarting streams for network reachability change.' ); - await this.restartNetwork(); + await restartNetwork(this); } }); }); @@ -178,652 +190,737 @@ export class RemoteStore implements TargetMetadataProvider { // Create streams (but note they're not started yet). this.watchStream = newPersistentWatchStream(this.datastore, asyncQueue, { - onOpen: this.onWatchStreamOpen.bind(this), - onClose: this.onWatchStreamClose.bind(this), - onWatchChange: this.onWatchStreamChange.bind(this) + onOpen: onWatchStreamOpen.bind(null, this), + onClose: onWatchStreamClose.bind(null, this), + onWatchChange: onWatchStreamChange.bind(null, this) }); this.writeStream = newPersistentWriteStream(this.datastore, asyncQueue, { - onOpen: this.onWriteStreamOpen.bind(this), - onClose: this.onWriteStreamClose.bind(this), - onHandshakeComplete: this.onWriteHandshakeComplete.bind(this), - onMutationResult: this.onMutationResult.bind(this) + onOpen: onWriteStreamOpen.bind(null, this), + onClose: onWriteStreamClose.bind(null, this), + onHandshakeComplete: onWriteHandshakeComplete.bind(null, this), + onMutationResult: onMutationResult.bind(null, this) }); } - /** - * SyncEngine callbacks to notify of watch and write events. Individual - * callbacks must be set before use. - */ remoteSyncer: RemoteSyncer = {}; - /** - * Starts up the remote store, creating streams, restoring state from - * LocalStore, etc. - */ start(): Promise { - return this.enableNetwork(); + return remoteStoreEnableNetwork(this); } +} - /** Re-enables the network. Idempotent. */ - enableNetwork(): Promise { - this.offlineCauses.delete(OfflineCause.UserDisabled); - return this.enableNetworkInternal(); - } +export function newRemoteStore( + localStore: LocalStore, + datastore: Datastore, + asyncQueue: AsyncQueue, + onlineStateHandler: (onlineState: OnlineState) => void, + connectivityMonitor: ConnectivityMonitor +): RemoteStore { + return new RemoteStoreImpl( + localStore, + datastore, + asyncQueue, + onlineStateHandler, + connectivityMonitor + ); +} - private async enableNetworkInternal(): Promise { - if (this.canUseNetwork()) { - if (this.shouldStartWatchStream()) { - this.startWatchStream(); - } else { - this.onlineStateTracker.set(OnlineState.Unknown); - } +/** Re-enables the network. Idempotent. */ +export function remoteStoreEnableNetwork( + remoteStore: RemoteStore +): Promise { + const remoteStoreImpl = debugCast(remoteStore, RemoteStoreImpl); + remoteStoreImpl.offlineCauses.delete(OfflineCause.UserDisabled); + return enableNetworkInternal(remoteStoreImpl); +} - // This will start the write stream if necessary. - await this.fillWritePipeline(); +async function enableNetworkInternal( + remoteStoreImpl: RemoteStoreImpl +): Promise { + if (canUseNetwork(remoteStoreImpl)) { + if (shouldStartWatchStream(remoteStoreImpl)) { + startWatchStream(remoteStoreImpl); + } else { + remoteStoreImpl.onlineStateTracker.set(OnlineState.Unknown); } - } - /** - * Temporarily disables the network. The network can be re-enabled using - * enableNetwork(). - */ - async disableNetwork(): Promise { - this.offlineCauses.add(OfflineCause.UserDisabled); - await this.disableNetworkInternal(); - - // Set the OnlineState to Offline so get()s return from cache, etc. - this.onlineStateTracker.set(OnlineState.Offline); + // This will start the write stream if necessary. + await fillWritePipeline(remoteStoreImpl); } +} - private async disableNetworkInternal(): Promise { - await this.writeStream.stop(); - await this.watchStream.stop(); +/** + * Temporarily disables the network. The network can be re-enabled using + * enableNetwork(). + */ +export async function remoteStoreDisableNetwork( + remoteStore: RemoteStore +): Promise { + const remoteStoreImpl = debugCast(remoteStore, RemoteStoreImpl); + remoteStoreImpl.offlineCauses.add(OfflineCause.UserDisabled); + await disableNetworkInternal(remoteStoreImpl); + + // Set the OnlineState to Offline so get()s return from cache, etc. + remoteStoreImpl.onlineStateTracker.set(OnlineState.Offline); +} - if (this.writePipeline.length > 0) { - logDebug( - LOG_TAG, - `Stopping write stream with ${this.writePipeline.length} pending writes` - ); - this.writePipeline = []; - } +async function disableNetworkInternal( + remoteStoreImpl: RemoteStoreImpl +): Promise { + await remoteStoreImpl.writeStream.stop(); + await remoteStoreImpl.watchStream.stop(); - this.cleanUpWatchStreamState(); + if (remoteStoreImpl.writePipeline.length > 0) { + logDebug( + LOG_TAG, + `Stopping write stream with ${remoteStoreImpl.writePipeline.length} pending writes` + ); + remoteStoreImpl.writePipeline = []; } - async shutdown(): Promise { - logDebug(LOG_TAG, 'RemoteStore shutting down.'); - this.offlineCauses.add(OfflineCause.Shutdown); - await this.disableNetworkInternal(); - this.connectivityMonitor.shutdown(); - - // Set the OnlineState to Unknown (rather than Offline) to avoid potentially - // triggering spurious listener events with cached data, etc. - this.onlineStateTracker.set(OnlineState.Unknown); - } + cleanUpWatchStreamState(remoteStoreImpl); +} - /** - * Starts new listen for the given target. Uses resume token if provided. It - * is a no-op if the target of given `TargetData` is already being listened to. - */ - listen(targetData: TargetData): void { - if (this.listenTargets.has(targetData.targetId)) { - return; - } +export async function remoteStoreShutdown( + remoteStore: RemoteStore +): Promise { + const remoteStoreImpl = debugCast(remoteStore, RemoteStoreImpl); + logDebug(LOG_TAG, 'RemoteStore shutting down.'); + remoteStoreImpl.offlineCauses.add(OfflineCause.Shutdown); + await disableNetworkInternal(remoteStoreImpl); + remoteStoreImpl.connectivityMonitor.shutdown(); + + // Set the OnlineState to Unknown (rather than Offline) to avoid potentially + // triggering spurious listener events with cached data, etc. + remoteStoreImpl.onlineStateTracker.set(OnlineState.Unknown); +} - // Mark this as something the client is currently listening for. - this.listenTargets.set(targetData.targetId, targetData); +/** + * Starts new listen for the given target. Uses resume token if provided. It + * is a no-op if the target of given `TargetData` is already being listened to. + */ +export function remoteStoreListen( + remoteStore: RemoteStore, + targetData: TargetData +): void { + const remoteStoreImpl = debugCast(remoteStore, RemoteStoreImpl); - if (this.shouldStartWatchStream()) { - // The listen will be sent in onWatchStreamOpen - this.startWatchStream(); - } else if (this.watchStream.isOpen()) { - this.sendWatchRequest(targetData); - } + if (remoteStoreImpl.listenTargets.has(targetData.targetId)) { + return; } - /** - * Removes the listen from server. It is a no-op if the given target id is - * not being listened to. - */ - unlisten(targetId: TargetId): void { - debugAssert( - this.listenTargets.has(targetId), - `unlisten called on target no currently watched: ${targetId}` - ); + // Mark this as something the client is currently listening for. + remoteStoreImpl.listenTargets.set(targetData.targetId, targetData); - this.listenTargets.delete(targetId); - if (this.watchStream.isOpen()) { - this.sendUnwatchRequest(targetId); - } + if (shouldStartWatchStream(remoteStoreImpl)) { + // The listen will be sent in onWatchStreamOpen + startWatchStream(remoteStoreImpl); + } else if (remoteStoreImpl.watchStream.isOpen()) { + sendWatchRequest(remoteStoreImpl, targetData); + } +} - if (this.listenTargets.size === 0) { - if (this.watchStream.isOpen()) { - this.watchStream.markIdle(); - } else if (this.canUseNetwork()) { - // Revert to OnlineState.Unknown if the watch stream is not open and we - // have no listeners, since without any listens to send we cannot - // confirm if the stream is healthy and upgrade to OnlineState.Online. - this.onlineStateTracker.set(OnlineState.Unknown); - } +/** + * Removes the listen from server. It is a no-op if the given target id is + * not being listened to. + */ +export function remoteStoreUnlisten( + remoteStore: RemoteStore, + targetId: TargetId +): void { + const remoteStoreImpl = debugCast(remoteStore, RemoteStoreImpl); + + debugAssert( + remoteStoreImpl.listenTargets.has(targetId), + `unlisten called on target no currently watched: ${targetId}` + ); + + remoteStoreImpl.listenTargets.delete(targetId); + if (remoteStoreImpl.watchStream.isOpen()) { + sendUnwatchRequest(remoteStoreImpl, targetId); + } + + if (remoteStoreImpl.listenTargets.size === 0) { + if (remoteStoreImpl.watchStream.isOpen()) { + remoteStoreImpl.watchStream.markIdle(); + } else if (canUseNetwork(remoteStoreImpl)) { + // Revert to OnlineState.Unknown if the watch stream is not open and we + // have no listeners, since without any listens to send we cannot + // confirm if the stream is healthy and upgrade to OnlineState.Online. + remoteStoreImpl.onlineStateTracker.set(OnlineState.Unknown); } } +} - /** {@link TargetMetadataProvider.getTargetDataForTarget} */ - getTargetDataForTarget(targetId: TargetId): TargetData | null { - return this.listenTargets.get(targetId) || null; - } +/** + * We need to increment the the expected number of pending responses we're due + * from watch so we wait for the ack to process any messages from this target. + */ +function sendWatchRequest( + remoteStoreImpl: RemoteStoreImpl, + targetData: TargetData +): void { + remoteStoreImpl.watchChangeAggregator!.recordPendingTargetRequest( + targetData.targetId + ); + remoteStoreImpl.watchStream.watch(targetData); +} - /** {@link TargetMetadataProvider.getRemoteKeysForTarget} */ - getRemoteKeysForTarget(targetId: TargetId): DocumentKeySet { - debugAssert( - !!this.remoteSyncer.getRemoteKeysForTarget, - 'getRemoteKeysForTarget() not set' - ); - return this.remoteSyncer.getRemoteKeysForTarget(targetId); - } +/** + * We need to increment the expected number of pending responses we're due + * from watch so we wait for the removal on the server before we process any + * messages from this target. + */ +function sendUnwatchRequest( + remoteStoreImpl: RemoteStoreImpl, + targetId: TargetId +): void { + remoteStoreImpl.watchChangeAggregator!.recordPendingTargetRequest(targetId); + remoteStoreImpl.watchStream.unwatch(targetId); +} - /** - * We need to increment the the expected number of pending responses we're due - * from watch so we wait for the ack to process any messages from this target. - */ - private sendWatchRequest(targetData: TargetData): void { - this.watchChangeAggregator!.recordPendingTargetRequest(targetData.targetId); - this.watchStream.watch(targetData); - } +function startWatchStream(remoteStoreImpl: RemoteStoreImpl): void { + debugAssert( + shouldStartWatchStream(remoteStoreImpl), + 'startWatchStream() called when shouldStartWatchStream() is false.' + ); + debugAssert( + !!remoteStoreImpl.remoteSyncer.getRemoteKeysForTarget, + 'getRemoteKeysForTarget() not set' + ); + + remoteStoreImpl.watchChangeAggregator = new WatchChangeAggregator({ + getRemoteKeysForTarget: targetId => + remoteStoreImpl.remoteSyncer.getRemoteKeysForTarget!(targetId), + getTargetDataForTarget: targetId => + remoteStoreImpl.listenTargets.get(targetId) || null + }); + remoteStoreImpl.watchStream.start(); + remoteStoreImpl.onlineStateTracker.handleWatchStreamStart(); +} - /** - * We need to increment the expected number of pending responses we're due - * from watch so we wait for the removal on the server before we process any - * messages from this target. - */ - private sendUnwatchRequest(targetId: TargetId): void { - this.watchChangeAggregator!.recordPendingTargetRequest(targetId); - this.watchStream.unwatch(targetId); - } +/** + * Returns whether the watch stream should be started because it's necessary + * and has not yet been started. + */ +function shouldStartWatchStream(remoteStoreImpl: RemoteStoreImpl): boolean { + return ( + canUseNetwork(remoteStoreImpl) && + !remoteStoreImpl.watchStream.isStarted() && + remoteStoreImpl.listenTargets.size > 0 + ); +} - private startWatchStream(): void { - debugAssert( - this.shouldStartWatchStream(), - 'startWatchStream() called when shouldStartWatchStream() is false.' - ); +export function canUseNetwork(remoteStore: RemoteStore): boolean { + const remoteStoreImpl = debugCast(remoteStore, RemoteStoreImpl); + return remoteStoreImpl.offlineCauses.size === 0; +} - this.watchChangeAggregator = new WatchChangeAggregator(this); - this.watchStream.start(); - this.onlineStateTracker.handleWatchStreamStart(); - } +function cleanUpWatchStreamState(remoteStoreImpl: RemoteStoreImpl): void { + remoteStoreImpl.watchChangeAggregator = null; +} - /** - * Returns whether the watch stream should be started because it's necessary - * and has not yet been started. - */ - private shouldStartWatchStream(): boolean { - return ( - this.canUseNetwork() && - !this.watchStream.isStarted() && - this.listenTargets.size > 0 +async function onWatchStreamOpen( + remoteStoreImpl: RemoteStoreImpl +): Promise { + remoteStoreImpl.listenTargets.forEach((targetData, targetId) => { + sendWatchRequest(remoteStoreImpl, targetData); + }); +} + +async function onWatchStreamClose( + remoteStoreImpl: RemoteStoreImpl, + error?: FirestoreError +): Promise { + if (error === undefined) { + // Graceful stop (due to stop() or idle timeout). Make sure that's + // desirable. + debugAssert( + !shouldStartWatchStream(remoteStoreImpl), + 'Watch stream was stopped gracefully while still needed.' ); } - canUseNetwork(): boolean { - return this.offlineCauses.size === 0; - } + cleanUpWatchStreamState(remoteStoreImpl); - private cleanUpWatchStreamState(): void { - this.watchChangeAggregator = null; - } + // If we still need the watch stream, retry the connection. + if (shouldStartWatchStream(remoteStoreImpl)) { + remoteStoreImpl.onlineStateTracker.handleWatchStreamFailure(error!); - private async onWatchStreamOpen(): Promise { - this.listenTargets.forEach((targetData, targetId) => { - this.sendWatchRequest(targetData); - }); + startWatchStream(remoteStoreImpl); + } else { + // No need to restart watch stream because there are no active targets. + // The online state is set to unknown because there is no active attempt + // at establishing a connection + remoteStoreImpl.onlineStateTracker.set(OnlineState.Unknown); } +} - private async onWatchStreamClose(error?: FirestoreError): Promise { - if (error === undefined) { - // Graceful stop (due to stop() or idle timeout). Make sure that's - // desirable. - debugAssert( - !this.shouldStartWatchStream(), - 'Watch stream was stopped gracefully while still needed.' +async function onWatchStreamChange( + remoteStoreImpl: RemoteStoreImpl, + watchChange: WatchChange, + snapshotVersion: SnapshotVersion +): Promise { + // Mark the client as online since we got a message from the server + remoteStoreImpl.onlineStateTracker.set(OnlineState.Online); + + if ( + watchChange instanceof WatchTargetChange && + watchChange.state === WatchTargetChangeState.Removed && + watchChange.cause + ) { + // There was an error on a target, don't wait for a consistent snapshot + // to raise events + try { + await handleTargetError(remoteStoreImpl, watchChange); + } catch (e) { + logDebug( + LOG_TAG, + 'Failed to remove targets %s: %s ', + watchChange.targetIds.join(','), + e ); + await disableNetworkUntilRecovery(remoteStoreImpl, e); } - - this.cleanUpWatchStreamState(); - - // If we still need the watch stream, retry the connection. - if (this.shouldStartWatchStream()) { - this.onlineStateTracker.handleWatchStreamFailure(error!); - - this.startWatchStream(); - } else { - // No need to restart watch stream because there are no active targets. - // The online state is set to unknown because there is no active attempt - // at establishing a connection - this.onlineStateTracker.set(OnlineState.Unknown); - } + return; } - private async onWatchStreamChange( - watchChange: WatchChange, - snapshotVersion: SnapshotVersion - ): Promise { - // Mark the client as online since we got a message from the server - this.onlineStateTracker.set(OnlineState.Online); - - if ( - watchChange instanceof WatchTargetChange && - watchChange.state === WatchTargetChangeState.Removed && - watchChange.cause - ) { - // There was an error on a target, don't wait for a consistent snapshot - // to raise events - try { - await this.handleTargetError(watchChange); - } catch (e) { - logDebug( - LOG_TAG, - 'Failed to remove targets %s: %s ', - watchChange.targetIds.join(','), - e - ); - await this.disableNetworkUntilRecovery(e); - } - return; - } + if (watchChange instanceof DocumentWatchChange) { + remoteStoreImpl.watchChangeAggregator!.handleDocumentChange(watchChange); + } else if (watchChange instanceof ExistenceFilterChange) { + remoteStoreImpl.watchChangeAggregator!.handleExistenceFilter(watchChange); + } else { + debugAssert( + watchChange instanceof WatchTargetChange, + 'Expected watchChange to be an instance of WatchTargetChange' + ); + remoteStoreImpl.watchChangeAggregator!.handleTargetChange(watchChange); + } - if (watchChange instanceof DocumentWatchChange) { - this.watchChangeAggregator!.handleDocumentChange(watchChange); - } else if (watchChange instanceof ExistenceFilterChange) { - this.watchChangeAggregator!.handleExistenceFilter(watchChange); - } else { - debugAssert( - watchChange instanceof WatchTargetChange, - 'Expected watchChange to be an instance of WatchTargetChange' + if (!snapshotVersion.isEqual(SnapshotVersion.min())) { + try { + const lastRemoteSnapshotVersion = await getLastRemoteSnapshotVersion( + remoteStoreImpl.localStore ); - this.watchChangeAggregator!.handleTargetChange(watchChange); - } - - if (!snapshotVersion.isEqual(SnapshotVersion.min())) { - try { - const lastRemoteSnapshotVersion = await getLastRemoteSnapshotVersion( - this.localStore - ); - if (snapshotVersion.compareTo(lastRemoteSnapshotVersion) >= 0) { - // We have received a target change with a global snapshot if the snapshot - // version is not equal to SnapshotVersion.min(). - await this.raiseWatchSnapshot(snapshotVersion); - } - } catch (e) { - logDebug(LOG_TAG, 'Failed to raise snapshot:', e); - await this.disableNetworkUntilRecovery(e); + if (snapshotVersion.compareTo(lastRemoteSnapshotVersion) >= 0) { + // We have received a target change with a global snapshot if the snapshot + // version is not equal to SnapshotVersion.min(). + await raiseWatchSnapshot(remoteStoreImpl, snapshotVersion); } + } catch (e) { + logDebug(LOG_TAG, 'Failed to raise snapshot:', e); + await disableNetworkUntilRecovery(remoteStoreImpl, e); } } +} - /** - * Recovery logic for IndexedDB errors that takes the network offline until - * `op` succeeds. Retries are scheduled with backoff using - * `enqueueRetryable()`. If `op()` is not provided, IndexedDB access is - * validated via a generic operation. - * - * The returned Promise is resolved once the network is disabled and before - * any retry attempt. - */ - private async disableNetworkUntilRecovery( - e: FirestoreError, - op?: () => Promise - ): Promise { - if (isIndexedDbTransactionError(e)) { - debugAssert( - !this.offlineCauses.has(OfflineCause.IndexedDbFailed), - 'Unexpected network event when IndexedDB was marked failed.' - ); - this.offlineCauses.add(OfflineCause.IndexedDbFailed); - - // Disable network and raise offline snapshots - await this.disableNetworkInternal(); - this.onlineStateTracker.set(OnlineState.Offline); +/** + * Recovery logic for IndexedDB errors that takes the network offline until + * `op` succeeds. Retries are scheduled with backoff using + * `enqueueRetryable()`. If `op()` is not provided, IndexedDB access is + * validated via a generic operation. + * + * The returned Promise is resolved once the network is disabled and before + * any retry attempt. + */ +async function disableNetworkUntilRecovery( + remoteStoreImpl: RemoteStoreImpl, + e: FirestoreError, + op?: () => Promise +): Promise { + if (isIndexedDbTransactionError(e)) { + debugAssert( + !remoteStoreImpl.offlineCauses.has(OfflineCause.IndexedDbFailed), + 'Unexpected network event when IndexedDB was marked failed.' + ); + remoteStoreImpl.offlineCauses.add(OfflineCause.IndexedDbFailed); - if (!op) { - // Use a simple read operation to determine if IndexedDB recovered. - // Ideally, we would expose a health check directly on SimpleDb, but - // RemoteStore only has access to persistence through LocalStore. - op = () => getLastRemoteSnapshotVersion(this.localStore); - } + // Disable network and raise offline snapshots + await disableNetworkInternal(remoteStoreImpl); + remoteStoreImpl.onlineStateTracker.set(OnlineState.Offline); - // Probe IndexedDB periodically and re-enable network - this.asyncQueue.enqueueRetryable(async () => { - logDebug(LOG_TAG, 'Retrying IndexedDB access'); - await op!(); - this.offlineCauses.delete(OfflineCause.IndexedDbFailed); - await this.enableNetworkInternal(); - }); - } else { - throw e; + if (!op) { + // Use a simple read operation to determine if IndexedDB recovered. + // Ideally, we would expose a health check directly on SimpleDb, but + // RemoteStore only has access to persistence through LocalStore. + op = () => getLastRemoteSnapshotVersion(remoteStoreImpl.localStore); } - } - /** - * Executes `op`. If `op` fails, takes the network offline until `op` - * succeeds. Returns after the first attempt. - */ - private executeWithRecovery(op: () => Promise): Promise { - return op().catch(e => this.disableNetworkUntilRecovery(e, op)); + // Probe IndexedDB periodically and re-enable network + remoteStoreImpl.asyncQueue.enqueueRetryable(async () => { + logDebug(LOG_TAG, 'Retrying IndexedDB access'); + await op!(); + remoteStoreImpl.offlineCauses.delete(OfflineCause.IndexedDbFailed); + await enableNetworkInternal(remoteStoreImpl); + }); + } else { + throw e; } +} - /** - * Takes a batch of changes from the Datastore, repackages them as a - * RemoteEvent, and passes that on to the listener, which is typically the - * SyncEngine. - */ - private raiseWatchSnapshot(snapshotVersion: SnapshotVersion): Promise { - debugAssert( - !!this.remoteSyncer.applyRemoteEvent, - 'applyRemoteEvent() not set' - ); - debugAssert( - !snapshotVersion.isEqual(SnapshotVersion.min()), - "Can't raise event for unknown SnapshotVersion" - ); - const remoteEvent = this.watchChangeAggregator!.createRemoteEvent( - snapshotVersion - ); - - // Update in-memory resume tokens. LocalStore will update the - // persistent view of these when applying the completed RemoteEvent. - remoteEvent.targetChanges.forEach((change, targetId) => { - if (change.resumeToken.approximateByteSize() > 0) { - const targetData = this.listenTargets.get(targetId); - // A watched target might have been removed already. - if (targetData) { - this.listenTargets.set( - targetId, - targetData.withResumeToken(change.resumeToken, snapshotVersion) - ); - } - } - }); +/** + * Executes `op`. If `op` fails, takes the network offline until `op` + * succeeds. Returns after the first attempt. + */ +function executeWithRecovery( + remoteStoreImpl: RemoteStoreImpl, + op: () => Promise +): Promise { + return op().catch(e => disableNetworkUntilRecovery(remoteStoreImpl, e, op)); +} - // Re-establish listens for the targets that have been invalidated by - // existence filter mismatches. - remoteEvent.targetMismatches.forEach(targetId => { - const targetData = this.listenTargets.get(targetId); - if (!targetData) { - // A watched target might have been removed already. - return; +/** + * Takes a batch of changes from the Datastore, repackages them as a + * RemoteEvent, and passes that on to the listener, which is typically the + * SyncEngine. + */ +function raiseWatchSnapshot( + remoteStoreImpl: RemoteStoreImpl, + snapshotVersion: SnapshotVersion +): Promise { + debugAssert( + !snapshotVersion.isEqual(SnapshotVersion.min()), + "Can't raise event for unknown SnapshotVersion" + ); + const remoteEvent = remoteStoreImpl.watchChangeAggregator!.createRemoteEvent( + snapshotVersion + ); + + // Update in-memory resume tokens. LocalStore will update the + // persistent view of these when applying the completed RemoteEvent. + remoteEvent.targetChanges.forEach((change, targetId) => { + if (change.resumeToken.approximateByteSize() > 0) { + const targetData = remoteStoreImpl.listenTargets.get(targetId); + // A watched target might have been removed already. + if (targetData) { + remoteStoreImpl.listenTargets.set( + targetId, + targetData.withResumeToken(change.resumeToken, snapshotVersion) + ); } + } + }); - // Clear the resume token for the target, since we're in a known mismatch - // state. - this.listenTargets.set( - targetId, - targetData.withResumeToken( - ByteString.EMPTY_BYTE_STRING, - targetData.snapshotVersion - ) - ); + // Re-establish listens for the targets that have been invalidated by + // existence filter mismatches. + remoteEvent.targetMismatches.forEach(targetId => { + const targetData = remoteStoreImpl.listenTargets.get(targetId); + if (!targetData) { + // A watched target might have been removed already. + return; + } - // Cause a hard reset by unwatching and rewatching immediately, but - // deliberately don't send a resume token so that we get a full update. - this.sendUnwatchRequest(targetId); - - // Mark the target we send as being on behalf of an existence filter - // mismatch, but don't actually retain that in listenTargets. This ensures - // that we flag the first re-listen this way without impacting future - // listens of this target (that might happen e.g. on reconnect). - const requestTargetData = new TargetData( - targetData.target, - targetId, - TargetPurpose.ExistenceFilterMismatch, - targetData.sequenceNumber - ); - this.sendWatchRequest(requestTargetData); - }); + // Clear the resume token for the target, since we're in a known mismatch + // state. + remoteStoreImpl.listenTargets.set( + targetId, + targetData.withResumeToken( + ByteString.EMPTY_BYTE_STRING, + targetData.snapshotVersion + ) + ); - // Finally raise remote event - return this.remoteSyncer.applyRemoteEvent(remoteEvent); - } + // Cause a hard reset by unwatching and rewatching immediately, but + // deliberately don't send a resume token so that we get a full update. + sendUnwatchRequest(remoteStoreImpl, targetId); + + // Mark the target we send as being on behalf of an existence filter + // mismatch, but don't actually retain that in listenTargets. This ensures + // that we flag the first re-listen this way without impacting future + // listens of this target (that might happen e.g. on reconnect). + const requestTargetData = new TargetData( + targetData.target, + targetId, + TargetPurpose.ExistenceFilterMismatch, + targetData.sequenceNumber + ); + sendWatchRequest(remoteStoreImpl, requestTargetData); + }); + + // Finally raise remote event + debugAssert( + !!remoteStoreImpl.remoteSyncer.applyRemoteEvent, + 'applyRemoteEvent() not set' + ); + return remoteStoreImpl.remoteSyncer.applyRemoteEvent(remoteEvent); +} - /** Handles an error on a target */ - private async handleTargetError( - watchChange: WatchTargetChange - ): Promise { - debugAssert(!!this.remoteSyncer.rejectListen, 'rejectListen() not set'); - debugAssert(!!watchChange.cause, 'Handling target error without a cause'); - const error = watchChange.cause!; - for (const targetId of watchChange.targetIds) { - // A watched target might have been removed already. - if (this.listenTargets.has(targetId)) { - await this.remoteSyncer.rejectListen(targetId, error); - this.listenTargets.delete(targetId); - this.watchChangeAggregator!.removeTarget(targetId); - } +/** Handles an error on a target */ +async function handleTargetError( + remoteStoreImpl: RemoteStoreImpl, + watchChange: WatchTargetChange +): Promise { + debugAssert( + !!remoteStoreImpl.remoteSyncer.rejectListen, + 'rejectListen() not set' + ); + debugAssert(!!watchChange.cause, 'Handling target error without a cause'); + const error = watchChange.cause!; + for (const targetId of watchChange.targetIds) { + // A watched target might have been removed already. + if (remoteStoreImpl.listenTargets.has(targetId)) { + await remoteStoreImpl.remoteSyncer.rejectListen(targetId, error); + remoteStoreImpl.listenTargets.delete(targetId); + remoteStoreImpl.watchChangeAggregator!.removeTarget(targetId); } } +} - /** - * Attempts to fill our write pipeline with writes from the LocalStore. - * - * Called internally to bootstrap or refill the write pipeline and by - * SyncEngine whenever there are new mutations to process. - * - * Starts the write stream if necessary. - */ - async fillWritePipeline(): Promise { - let lastBatchIdRetrieved = - this.writePipeline.length > 0 - ? this.writePipeline[this.writePipeline.length - 1].batchId - : BATCHID_UNKNOWN; - - while (this.canAddToWritePipeline()) { - try { - const batch = await nextMutationBatch( - this.localStore, - lastBatchIdRetrieved - ); +/** + * Attempts to fill our write pipeline with writes from the LocalStore. + * + * Called internally to bootstrap or refill the write pipeline and by + * SyncEngine whenever there are new mutations to process. + * + * Starts the write stream if necessary. + */ +export async function fillWritePipeline( + remoteStore: RemoteStore +): Promise { + const remoteStoreImpl = debugCast(remoteStore, RemoteStoreImpl); + + let lastBatchIdRetrieved = + remoteStoreImpl.writePipeline.length > 0 + ? remoteStoreImpl.writePipeline[remoteStoreImpl.writePipeline.length - 1] + .batchId + : BATCHID_UNKNOWN; + + while (canAddToWritePipeline(remoteStoreImpl)) { + try { + const batch = await nextMutationBatch( + remoteStoreImpl.localStore, + lastBatchIdRetrieved + ); - if (batch === null) { - if (this.writePipeline.length === 0) { - this.writeStream.markIdle(); - } - break; - } else { - lastBatchIdRetrieved = batch.batchId; - this.addToWritePipeline(batch); + if (batch === null) { + if (remoteStoreImpl.writePipeline.length === 0) { + remoteStoreImpl.writeStream.markIdle(); } - } catch (e) { - await this.disableNetworkUntilRecovery(e); + break; + } else { + lastBatchIdRetrieved = batch.batchId; + addToWritePipeline(remoteStoreImpl, batch); } - } - - if (this.shouldStartWriteStream()) { - this.startWriteStream(); + } catch (e) { + await disableNetworkUntilRecovery(remoteStoreImpl, e); } } - /** - * Returns true if we can add to the write pipeline (i.e. the network is - * enabled and the write pipeline is not full). - */ - private canAddToWritePipeline(): boolean { - return ( - this.canUseNetwork() && this.writePipeline.length < MAX_PENDING_WRITES - ); + if (shouldStartWriteStream(remoteStoreImpl)) { + startWriteStream(remoteStoreImpl); } +} - // For testing - outstandingWrites(): number { - return this.writePipeline.length; - } +/** + * Returns true if we can add to the write pipeline (i.e. the network is + * enabled and the write pipeline is not full). + */ +function canAddToWritePipeline(remoteStoreImpl: RemoteStoreImpl): boolean { + return ( + canUseNetwork(remoteStoreImpl) && + remoteStoreImpl.writePipeline.length < MAX_PENDING_WRITES + ); +} - /** - * Queues additional writes to be sent to the write stream, sending them - * immediately if the write stream is established. - */ - private addToWritePipeline(batch: MutationBatch): void { - debugAssert( - this.canAddToWritePipeline(), - 'addToWritePipeline called when pipeline is full' - ); - this.writePipeline.push(batch); +// For testing +export function outstandingWrites(remoteStore: RemoteStore): number { + const remoteStoreImpl = debugCast(remoteStore, RemoteStoreImpl); + return remoteStoreImpl.writePipeline.length; +} - if (this.writeStream.isOpen() && this.writeStream.handshakeComplete) { - this.writeStream.writeMutations(batch.mutations); - } +/** + * Queues additional writes to be sent to the write stream, sending them + * immediately if the write stream is established. + */ +function addToWritePipeline( + remoteStoreImpl: RemoteStoreImpl, + batch: MutationBatch +): void { + debugAssert( + canAddToWritePipeline(remoteStoreImpl), + 'addToWritePipeline called when pipeline is full' + ); + remoteStoreImpl.writePipeline.push(batch); + + if ( + remoteStoreImpl.writeStream.isOpen() && + remoteStoreImpl.writeStream.handshakeComplete + ) { + remoteStoreImpl.writeStream.writeMutations(batch.mutations); } +} - private shouldStartWriteStream(): boolean { - return ( - this.canUseNetwork() && - !this.writeStream.isStarted() && - this.writePipeline.length > 0 - ); - } +function shouldStartWriteStream(remoteStoreImpl: RemoteStoreImpl): boolean { + return ( + canUseNetwork(remoteStoreImpl) && + !remoteStoreImpl.writeStream.isStarted() && + remoteStoreImpl.writePipeline.length > 0 + ); +} - private startWriteStream(): void { - debugAssert( - this.shouldStartWriteStream(), - 'startWriteStream() called when shouldStartWriteStream() is false.' - ); - this.writeStream.start(); - } +function startWriteStream(remoteStoreImpl: RemoteStoreImpl): void { + debugAssert( + shouldStartWriteStream(remoteStoreImpl), + 'startWriteStream() called when shouldStartWriteStream() is false.' + ); + remoteStoreImpl.writeStream.start(); +} - private async onWriteStreamOpen(): Promise { - this.writeStream.writeHandshake(); - } +async function onWriteStreamOpen( + remoteStoreImpl: RemoteStoreImpl +): Promise { + remoteStoreImpl.writeStream.writeHandshake(); +} - private async onWriteHandshakeComplete(): Promise { - // Send the write pipeline now that the stream is established. - for (const batch of this.writePipeline) { - this.writeStream.writeMutations(batch.mutations); - } +async function onWriteHandshakeComplete( + remoteStoreImpl: RemoteStoreImpl +): Promise { + // Send the write pipeline now that the stream is established. + for (const batch of remoteStoreImpl.writePipeline) { + remoteStoreImpl.writeStream.writeMutations(batch.mutations); } +} - private async onMutationResult( - commitVersion: SnapshotVersion, - results: MutationResult[] - ): Promise { - // This is a response to a write containing mutations and should be - // correlated to the first write in our write pipeline. - debugAssert( - this.writePipeline.length > 0, - 'Got result for empty write pipeline' - ); - const batch = this.writePipeline.shift()!; - const success = MutationBatchResult.from(batch, commitVersion, results); +async function onMutationResult( + remoteStoreImpl: RemoteStoreImpl, + commitVersion: SnapshotVersion, + results: MutationResult[] +): Promise { + // This is a response to a write containing mutations and should be + // correlated to the first write in our write pipeline. + debugAssert( + remoteStoreImpl.writePipeline.length > 0, + 'Got result for empty write pipeline' + ); + const batch = remoteStoreImpl.writePipeline.shift()!; + const success = MutationBatchResult.from(batch, commitVersion, results); + + debugAssert( + !!remoteStoreImpl.remoteSyncer.applySuccessfulWrite, + 'applySuccessfulWrite() not set' + ); + await executeWithRecovery(remoteStoreImpl, () => + remoteStoreImpl.remoteSyncer.applySuccessfulWrite!(success) + ); + + // It's possible that with the completion of this mutation another + // slot has freed up. + await fillWritePipeline(remoteStoreImpl); +} +async function onWriteStreamClose( + remoteStoreImpl: RemoteStoreImpl, + error?: FirestoreError +): Promise { + if (error === undefined) { + // Graceful stop (due to stop() or idle timeout). Make sure that's + // desirable. debugAssert( - !!this.remoteSyncer.applySuccessfulWrite, - 'applySuccessfulWrite() not set' + !shouldStartWriteStream(remoteStoreImpl), + 'Write stream was stopped gracefully while still needed.' ); - await this.executeWithRecovery(() => - this.remoteSyncer.applySuccessfulWrite!(success) - ); - - // It's possible that with the completion of this mutation another - // slot has freed up. - await this.fillWritePipeline(); } - private async onWriteStreamClose(error?: FirestoreError): Promise { - if (error === undefined) { - // Graceful stop (due to stop() or idle timeout). Make sure that's - // desirable. - debugAssert( - !this.shouldStartWriteStream(), - 'Write stream was stopped gracefully while still needed.' - ); - } - - // If the write stream closed after the write handshake completes, a write - // operation failed and we fail the pending operation. - if (error && this.writeStream.handshakeComplete) { - // This error affects the actual write. - await this.handleWriteError(error!); - } - - // The write stream might have been started by refilling the write - // pipeline for failed writes - if (this.shouldStartWriteStream()) { - this.startWriteStream(); - } + // If the write stream closed after the write handshake completes, a write + // operation failed and we fail the pending operation. + if (error && remoteStoreImpl.writeStream.handshakeComplete) { + // This error affects the actual write. + await handleWriteError(remoteStoreImpl, error!); } - private async handleWriteError(error: FirestoreError): Promise { - // Only handle permanent errors here. If it's transient, just let the retry - // logic kick in. - if (isPermanentWriteError(error.code)) { - // This was a permanent error, the request itself was the problem - // so it's not going to succeed if we resend it. - const batch = this.writePipeline.shift()!; - - // In this case it's also unlikely that the server itself is melting - // down -- this was just a bad request so inhibit backoff on the next - // restart. - this.writeStream.inhibitBackoff(); - - debugAssert( - !!this.remoteSyncer.rejectFailedWrite, - 'rejectFailedWrite() not set' - ); - await this.executeWithRecovery(() => - this.remoteSyncer.rejectFailedWrite!(batch.batchId, error) - ); - - // It's possible that with the completion of this mutation - // another slot has freed up. - await this.fillWritePipeline(); - } else { - // Transient error, just let the retry logic kick in. - } + // The write stream might have been started by refilling the write + // pipeline for failed writes + if (shouldStartWriteStream(remoteStoreImpl)) { + startWriteStream(remoteStoreImpl); } +} - private async restartNetwork(): Promise { - this.offlineCauses.add(OfflineCause.ConnectivityChange); - await this.disableNetworkInternal(); - this.onlineStateTracker.set(OnlineState.Unknown); - this.writeStream.inhibitBackoff(); - this.watchStream.inhibitBackoff(); - this.offlineCauses.delete(OfflineCause.ConnectivityChange); - await this.enableNetworkInternal(); - } +async function handleWriteError( + remoteStoreImpl: RemoteStoreImpl, + error: FirestoreError +): Promise { + // Only handle permanent errors here. If it's transient, just let the retry + // logic kick in. + if (isPermanentWriteError(error.code)) { + // This was a permanent error, the request itself was the problem + // so it's not going to succeed if we resend it. + const batch = remoteStoreImpl.writePipeline.shift()!; + + // In this case it's also unlikely that the server itself is melting + // down -- this was just a bad request so inhibit backoff on the next + // restart. + remoteStoreImpl.writeStream.inhibitBackoff(); - async handleCredentialChange(user: User): Promise { - this.asyncQueue.verifyOperationInProgress(); debugAssert( - !!this.remoteSyncer.handleCredentialChange, - 'handleCredentialChange() not set' + !!remoteStoreImpl.remoteSyncer.rejectFailedWrite, + 'rejectFailedWrite() not set' + ); + await executeWithRecovery(remoteStoreImpl, () => + remoteStoreImpl.remoteSyncer.rejectFailedWrite!(batch.batchId, error) ); - logDebug(LOG_TAG, 'RemoteStore received new credentials'); - const canUseNetwork = this.canUseNetwork(); - - // Tear down and re-create our network streams. This will ensure we get a - // fresh auth token for the new user and re-fill the write pipeline with - // new mutations from the LocalStore (since mutations are per-user). - this.offlineCauses.add(OfflineCause.CredentialChange); - await this.disableNetworkInternal(); - if (canUseNetwork) { - // Don't set the network status to Unknown if we are offline. - this.onlineStateTracker.set(OnlineState.Unknown); - } - await this.remoteSyncer.handleCredentialChange(user); - this.offlineCauses.delete(OfflineCause.CredentialChange); - await this.enableNetworkInternal(); + // It's possible that with the completion of this mutation + // another slot has freed up. + await fillWritePipeline(remoteStoreImpl); + } else { + // Transient error, just let the retry logic kick in. } +} - /** - * Toggles the network state when the client gains or loses its primary lease. - */ - async applyPrimaryState(isPrimary: boolean): Promise { - if (isPrimary) { - this.offlineCauses.delete(OfflineCause.IsSecondary); - await this.enableNetworkInternal(); - } else if (!isPrimary) { - this.offlineCauses.add(OfflineCause.IsSecondary); - await this.disableNetworkInternal(); - this.onlineStateTracker.set(OnlineState.Unknown); - } +async function restartNetwork(remoteStore: RemoteStore): Promise { + const remoteStoreImpl = debugCast(remoteStore, RemoteStoreImpl); + remoteStoreImpl.offlineCauses.add(OfflineCause.ConnectivityChange); + await disableNetworkInternal(remoteStoreImpl); + remoteStoreImpl.writeStream.inhibitBackoff(); + remoteStoreImpl.watchStream.inhibitBackoff(); + remoteStoreImpl.onlineStateTracker.set(OnlineState.Unknown); + remoteStoreImpl.offlineCauses.delete(OfflineCause.ConnectivityChange); + await enableNetworkInternal(remoteStoreImpl); +} + +export async function remoteStoreHandleCredentialChange( + remoteStore: RemoteStore, + user: User +): Promise { + const remoteStoreImpl = debugCast(remoteStore, RemoteStoreImpl); + remoteStoreImpl.asyncQueue.verifyOperationInProgress(); + debugAssert( + !!remoteStoreImpl.remoteSyncer.handleCredentialChange, + 'handleCredentialChange() not set' + ); + + logDebug(LOG_TAG, 'RemoteStore received new credentials'); + const usesNetwork = canUseNetwork(remoteStoreImpl); + + // Tear down and re-create our network streams. This will ensure we get a + // fresh auth token for the new user and re-fill the write pipeline with + // new mutations from the LocalStore (since mutations are per-user). + remoteStoreImpl.offlineCauses.add(OfflineCause.CredentialChange); + await disableNetworkInternal(remoteStoreImpl); + if (usesNetwork) { + // Don't set the network status to Unknown if we are offline. + remoteStoreImpl.onlineStateTracker.set(OnlineState.Unknown); + } + await remoteStoreImpl.remoteSyncer.handleCredentialChange(user); + remoteStoreImpl.offlineCauses.delete(OfflineCause.CredentialChange); + await enableNetworkInternal(remoteStoreImpl); +} + +/** + * Toggles the network state when the client gains or loses its primary lease. + */ +export async function remoteStoreApplyPrimaryState( + remoteStore: RemoteStore, + isPrimary: boolean +): Promise { + const remoteStoreImpl = debugCast(remoteStore, RemoteStoreImpl); + if (isPrimary) { + remoteStoreImpl.offlineCauses.delete(OfflineCause.IsSecondary); + await enableNetworkInternal(remoteStoreImpl); + } else if (!isPrimary) { + remoteStoreImpl.offlineCauses.add(OfflineCause.IsSecondary); + await disableNetworkInternal(remoteStoreImpl); + remoteStoreImpl.onlineStateTracker.set(OnlineState.Unknown); } } diff --git a/packages/firestore/test/unit/specs/spec_test_runner.ts b/packages/firestore/test/unit/specs/spec_test_runner.ts index ab11976185f..a9dd56b66d9 100644 --- a/packages/firestore/test/unit/specs/spec_test_runner.ts +++ b/packages/firestore/test/unit/specs/spec_test_runner.ts @@ -73,7 +73,15 @@ import { JsonObject } from '../../../src/model/object_value'; import { Mutation } from '../../../src/model/mutation'; import * as api from '../../../src/protos/firestore_proto_api'; import { ExistenceFilter } from '../../../src/remote/existence_filter'; -import { RemoteStore } from '../../../src/remote/remote_store'; +import { + RemoteStore, + fillWritePipeline, + remoteStoreDisableNetwork, + remoteStoreShutdown, + remoteStoreEnableNetwork, + remoteStoreHandleCredentialChange, + outstandingWrites +} from '../../../src/remote/remote_store'; import { mapCodeFromRpcCode } from '../../../src/remote/rpc_error'; import { JsonProtoSerializer, @@ -720,9 +728,9 @@ abstract class TestRunner { this.networkEnabled = false; // Make sure to execute all writes that are currently queued. This allows us // to assert on the total number of requests sent before shutdown. - await this.remoteStore.fillWritePipeline(); + await fillWritePipeline(this.remoteStore); this.persistence.setNetworkEnabled(false); - await this.remoteStore.disableNetwork(); + await remoteStoreDisableNetwork(this.remoteStore); } private async doDrainQueue(): Promise { @@ -732,11 +740,11 @@ abstract class TestRunner { private async doEnableNetwork(): Promise { this.networkEnabled = true; this.persistence.setNetworkEnabled(true); - await this.remoteStore.enableNetwork(); + await remoteStoreEnableNetwork(this.remoteStore); } private async doShutdown(): Promise { - await this.remoteStore.shutdown(); + await remoteStoreShutdown(this.remoteStore); await this.sharedClientState.shutdown(); // We don't delete the persisted data here since multi-clients may still // be accessing it. Instead, we manually remove it at the end of the @@ -779,7 +787,7 @@ abstract class TestRunner { // during an IndexedDb failure. Non-recovery tests will pick up the user // change when the AsyncQueue is drained. this.queue.enqueueRetryable(() => - this.remoteStore.handleCredentialChange(new User(user)) + remoteStoreHandleCredentialChange(this.remoteStore, new User(user)) ); } @@ -828,7 +836,7 @@ abstract class TestRunner { ): Promise { if (expectedState) { if ('numOutstandingWrites' in expectedState) { - expect(this.remoteStore.outstandingWrites()).to.equal( + expect(outstandingWrites(this.remoteStore)).to.equal( expectedState.numOutstandingWrites ); }