Skip to content

Commit 7dbf367

Browse files
committed
v1.35.7 - fix: prevent serverChange hooks from triggering on local changes (credit @trevorgeise)
1 parent 8d6b808 commit 7dbf367

File tree

5 files changed

+87
-79
lines changed

5 files changed

+87
-79
lines changed

dist/index.cjs.js

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1469,8 +1469,6 @@ function pluginActions (Firebase) {
14691469
if (!querySnapshot.metadata.fromCache) return [3 /*break*/, 1];
14701470
// if it's the very first call, we are at the initial app load. If so, we'll use
14711471
// the data in cache (if available) to populate the state.
1472-
// if it's not, this is only the result of a local modification which does not
1473-
// require to do anything else.
14741472
if (!gotFirstLocalResponse) {
14751473
// 'doc' mode:
14761474
if (!getters.collectionMode) {
@@ -1488,24 +1486,27 @@ function pluginActions (Firebase) {
14881486
}
14891487
gotFirstLocalResponse = true;
14901488
}
1491-
return [3 /*break*/, 12];
1489+
return [3 /*break*/, 13];
14921490
case 1:
1493-
if (!!getters.collectionMode) return [3 /*break*/, 10];
1494-
if (!!querySnapshot.exists) return [3 /*break*/, 8];
1495-
if (!!state._conf.sync.preventInitialDocInsertion) return [3 /*break*/, 6];
1491+
if (!querySnapshot.metadata.hasPendingWrites) return [3 /*break*/, 2];
1492+
return [3 /*break*/, 13];
1493+
case 2:
1494+
if (!!getters.collectionMode) return [3 /*break*/, 11];
1495+
if (!!querySnapshot.exists) return [3 /*break*/, 9];
1496+
if (!!state._conf.sync.preventInitialDocInsertion) return [3 /*break*/, 7];
14961497
if (state._conf.logging) {
14971498
message = gotFirstServerResponse
14981499
? 'recreating doc after remote deletion'
14991500
: 'inserting initial doc';
15001501
console.log("%c [vuex-easy-firestore] " + message + "; for Firestore PATH: " + getters.firestorePathComplete + " [" + state._conf.firestorePath + "]", 'color: MediumSeaGreen');
15011502
}
1502-
_a.label = 2;
1503-
case 2:
1504-
_a.trys.push([2, 4, , 5]);
1503+
_a.label = 3;
1504+
case 3:
1505+
_a.trys.push([3, 5, , 6]);
15051506
return [4 /*yield*/, dispatch('insertInitialDoc')
15061507
// if the initial document was successfully inserted
15071508
];
1508-
case 3:
1509+
case 4:
15091510
_a.sent();
15101511
// if the initial document was successfully inserted
15111512
if (initialPromise.isPending) {
@@ -1514,22 +1515,22 @@ function pluginActions (Firebase) {
15141515
if (refreshedPromise.isPending) {
15151516
refreshedPromise.resolve();
15161517
}
1517-
return [3 /*break*/, 5];
1518-
case 4:
1518+
return [3 /*break*/, 6];
1519+
case 5:
15191520
error_1 = _a.sent();
15201521
// we close the channel ourselves. Firestore does not, as it leaves the
15211522
// channel open as long as the user has read rights on the document, even
15221523
// if it does not exist. But since the dev enabled `insertInitialDoc`,
15231524
// it makes some sense to close as we can assume the user should have had
15241525
// write rights
15251526
streamingStop(error_1);
1526-
return [3 /*break*/, 5];
1527-
case 5: return [3 /*break*/, 7];
1528-
case 6:
1527+
return [3 /*break*/, 6];
1528+
case 6: return [3 /*break*/, 8];
1529+
case 7:
15291530
streamingStop('preventInitialDocInsertion');
1530-
_a.label = 7;
1531-
case 7: return [3 /*break*/, 9];
1532-
case 8:
1531+
_a.label = 8;
1532+
case 8: return [3 /*break*/, 10];
1533+
case 9:
15331534
processDocument(querySnapshot.data());
15341535
if (initialPromise.isPending) {
15351536
streamingStart();
@@ -1539,21 +1540,21 @@ function pluginActions (Firebase) {
15391540
if (refreshedPromise.isPending) {
15401541
refreshedPromise.resolve();
15411542
}
1542-
_a.label = 9;
1543-
case 9: return [3 /*break*/, 11];
1544-
case 10:
1543+
_a.label = 10;
1544+
case 10: return [3 /*break*/, 12];
1545+
case 11:
15451546
processCollection(querySnapshot.docChanges());
15461547
if (initialPromise.isPending) {
15471548
streamingStart();
15481549
}
15491550
if (refreshedPromise.isPending) {
15501551
refreshedPromise.resolve();
15511552
}
1552-
_a.label = 11;
1553-
case 11:
1554-
gotFirstServerResponse = true;
15551553
_a.label = 12;
1556-
case 12: return [2 /*return*/];
1554+
case 12:
1555+
gotFirstServerResponse = true;
1556+
_a.label = 13;
1557+
case 13: return [2 /*return*/];
15571558
}
15581559
});
15591560
}); }, streamingStop);

dist/index.esm.js

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1463,8 +1463,6 @@ function pluginActions (Firebase) {
14631463
if (!querySnapshot.metadata.fromCache) return [3 /*break*/, 1];
14641464
// if it's the very first call, we are at the initial app load. If so, we'll use
14651465
// the data in cache (if available) to populate the state.
1466-
// if it's not, this is only the result of a local modification which does not
1467-
// require to do anything else.
14681466
if (!gotFirstLocalResponse) {
14691467
// 'doc' mode:
14701468
if (!getters.collectionMode) {
@@ -1482,24 +1480,27 @@ function pluginActions (Firebase) {
14821480
}
14831481
gotFirstLocalResponse = true;
14841482
}
1485-
return [3 /*break*/, 12];
1483+
return [3 /*break*/, 13];
14861484
case 1:
1487-
if (!!getters.collectionMode) return [3 /*break*/, 10];
1488-
if (!!querySnapshot.exists) return [3 /*break*/, 8];
1489-
if (!!state._conf.sync.preventInitialDocInsertion) return [3 /*break*/, 6];
1485+
if (!querySnapshot.metadata.hasPendingWrites) return [3 /*break*/, 2];
1486+
return [3 /*break*/, 13];
1487+
case 2:
1488+
if (!!getters.collectionMode) return [3 /*break*/, 11];
1489+
if (!!querySnapshot.exists) return [3 /*break*/, 9];
1490+
if (!!state._conf.sync.preventInitialDocInsertion) return [3 /*break*/, 7];
14901491
if (state._conf.logging) {
14911492
message = gotFirstServerResponse
14921493
? 'recreating doc after remote deletion'
14931494
: 'inserting initial doc';
14941495
console.log("%c [vuex-easy-firestore] " + message + "; for Firestore PATH: " + getters.firestorePathComplete + " [" + state._conf.firestorePath + "]", 'color: MediumSeaGreen');
14951496
}
1496-
_a.label = 2;
1497-
case 2:
1498-
_a.trys.push([2, 4, , 5]);
1497+
_a.label = 3;
1498+
case 3:
1499+
_a.trys.push([3, 5, , 6]);
14991500
return [4 /*yield*/, dispatch('insertInitialDoc')
15001501
// if the initial document was successfully inserted
15011502
];
1502-
case 3:
1503+
case 4:
15031504
_a.sent();
15041505
// if the initial document was successfully inserted
15051506
if (initialPromise.isPending) {
@@ -1508,22 +1509,22 @@ function pluginActions (Firebase) {
15081509
if (refreshedPromise.isPending) {
15091510
refreshedPromise.resolve();
15101511
}
1511-
return [3 /*break*/, 5];
1512-
case 4:
1512+
return [3 /*break*/, 6];
1513+
case 5:
15131514
error_1 = _a.sent();
15141515
// we close the channel ourselves. Firestore does not, as it leaves the
15151516
// channel open as long as the user has read rights on the document, even
15161517
// if it does not exist. But since the dev enabled `insertInitialDoc`,
15171518
// it makes some sense to close as we can assume the user should have had
15181519
// write rights
15191520
streamingStop(error_1);
1520-
return [3 /*break*/, 5];
1521-
case 5: return [3 /*break*/, 7];
1522-
case 6:
1521+
return [3 /*break*/, 6];
1522+
case 6: return [3 /*break*/, 8];
1523+
case 7:
15231524
streamingStop('preventInitialDocInsertion');
1524-
_a.label = 7;
1525-
case 7: return [3 /*break*/, 9];
1526-
case 8:
1525+
_a.label = 8;
1526+
case 8: return [3 /*break*/, 10];
1527+
case 9:
15271528
processDocument(querySnapshot.data());
15281529
if (initialPromise.isPending) {
15291530
streamingStart();
@@ -1533,21 +1534,21 @@ function pluginActions (Firebase) {
15331534
if (refreshedPromise.isPending) {
15341535
refreshedPromise.resolve();
15351536
}
1536-
_a.label = 9;
1537-
case 9: return [3 /*break*/, 11];
1538-
case 10:
1537+
_a.label = 10;
1538+
case 10: return [3 /*break*/, 12];
1539+
case 11:
15391540
processCollection(querySnapshot.docChanges());
15401541
if (initialPromise.isPending) {
15411542
streamingStart();
15421543
}
15431544
if (refreshedPromise.isPending) {
15441545
refreshedPromise.resolve();
15451546
}
1546-
_a.label = 11;
1547-
case 11:
1548-
gotFirstServerResponse = true;
15491547
_a.label = 12;
1550-
case 12: return [2 /*return*/];
1548+
case 12:
1549+
gotFirstServerResponse = true;
1550+
_a.label = 13;
1551+
case 13: return [2 /*return*/];
15511552
}
15521553
});
15531554
}); }, streamingStop);

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "vuex-easy-firestore",
3-
"version": "1.35.6",
3+
"version": "1.35.7",
44
"description": "Easy coupling of firestore and a vuex module. 2-way sync with 0 boilerplate!",
55
"main": "dist/index.cjs.js",
66
"module": "dist/index.esm.js",

src/module/actions.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -682,8 +682,6 @@ export default function (Firebase: any): AnyObject {
682682
if (querySnapshot.metadata.fromCache) {
683683
// if it's the very first call, we are at the initial app load. If so, we'll use
684684
// the data in cache (if available) to populate the state.
685-
// if it's not, this is only the result of a local modification which does not
686-
// require to do anything else.
687685
if (!gotFirstLocalResponse) {
688686
// 'doc' mode:
689687
if (!getters.collectionMode) {
@@ -702,7 +700,14 @@ export default function (Firebase: any): AnyObject {
702700
gotFirstLocalResponse = true
703701
}
704702
}
705-
// if data comes from server
703+
// if data comes from server... BUT REALLY NOT: the data comes from local change
704+
else if (querySnapshot.metadata.hasPendingWrites) {
705+
// this is only the result of a local modification which does not
706+
// require to do anything else.
707+
// https://firebase.google.com/docs/reference/js/firebase.firestore.SnapshotMetadata
708+
// True if the snapshot contains the result of local writes (e.g. set() or update() calls) that have not yet been committed to the backend. If your listener has opted into metadata updates (via SnapshotListenOptions) you will receive another snapshot with hasPendingWrites equal to false once the writes have been committed to the backend.
709+
}
710+
// the data really comes from a change on the server
706711
else {
707712
// 'doc' mode:
708713
if (!getters.collectionMode) {

test/helpers/index.cjs.js

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1988,8 +1988,6 @@ function pluginActions (Firebase) {
19881988
if (!querySnapshot.metadata.fromCache) return [3 /*break*/, 1];
19891989
// if it's the very first call, we are at the initial app load. If so, we'll use
19901990
// the data in cache (if available) to populate the state.
1991-
// if it's not, this is only the result of a local modification which does not
1992-
// require to do anything else.
19931991
if (!gotFirstLocalResponse) {
19941992
// 'doc' mode:
19951993
if (!getters.collectionMode) {
@@ -2007,24 +2005,27 @@ function pluginActions (Firebase) {
20072005
}
20082006
gotFirstLocalResponse = true;
20092007
}
2010-
return [3 /*break*/, 12];
2008+
return [3 /*break*/, 13];
20112009
case 1:
2012-
if (!!getters.collectionMode) return [3 /*break*/, 10];
2013-
if (!!querySnapshot.exists) return [3 /*break*/, 8];
2014-
if (!!state._conf.sync.preventInitialDocInsertion) return [3 /*break*/, 6];
2010+
if (!querySnapshot.metadata.hasPendingWrites) return [3 /*break*/, 2];
2011+
return [3 /*break*/, 13];
2012+
case 2:
2013+
if (!!getters.collectionMode) return [3 /*break*/, 11];
2014+
if (!!querySnapshot.exists) return [3 /*break*/, 9];
2015+
if (!!state._conf.sync.preventInitialDocInsertion) return [3 /*break*/, 7];
20152016
if (state._conf.logging) {
20162017
message = gotFirstServerResponse
20172018
? 'recreating doc after remote deletion'
20182019
: 'inserting initial doc';
20192020
console.log("%c [vuex-easy-firestore] " + message + "; for Firestore PATH: " + getters.firestorePathComplete + " [" + state._conf.firestorePath + "]", 'color: MediumSeaGreen');
20202021
}
2021-
_a.label = 2;
2022-
case 2:
2023-
_a.trys.push([2, 4, , 5]);
2022+
_a.label = 3;
2023+
case 3:
2024+
_a.trys.push([3, 5, , 6]);
20242025
return [4 /*yield*/, dispatch('insertInitialDoc')
20252026
// if the initial document was successfully inserted
20262027
];
2027-
case 3:
2028+
case 4:
20282029
_a.sent();
20292030
// if the initial document was successfully inserted
20302031
if (initialPromise.isPending) {
@@ -2033,22 +2034,22 @@ function pluginActions (Firebase) {
20332034
if (refreshedPromise.isPending) {
20342035
refreshedPromise.resolve();
20352036
}
2036-
return [3 /*break*/, 5];
2037-
case 4:
2037+
return [3 /*break*/, 6];
2038+
case 5:
20382039
error_1 = _a.sent();
20392040
// we close the channel ourselves. Firestore does not, as it leaves the
20402041
// channel open as long as the user has read rights on the document, even
20412042
// if it does not exist. But since the dev enabled `insertInitialDoc`,
20422043
// it makes some sense to close as we can assume the user should have had
20432044
// write rights
20442045
streamingStop(error_1);
2045-
return [3 /*break*/, 5];
2046-
case 5: return [3 /*break*/, 7];
2047-
case 6:
2046+
return [3 /*break*/, 6];
2047+
case 6: return [3 /*break*/, 8];
2048+
case 7:
20482049
streamingStop('preventInitialDocInsertion');
2049-
_a.label = 7;
2050-
case 7: return [3 /*break*/, 9];
2051-
case 8:
2050+
_a.label = 8;
2051+
case 8: return [3 /*break*/, 10];
2052+
case 9:
20522053
processDocument(querySnapshot.data());
20532054
if (initialPromise.isPending) {
20542055
streamingStart();
@@ -2058,21 +2059,21 @@ function pluginActions (Firebase) {
20582059
if (refreshedPromise.isPending) {
20592060
refreshedPromise.resolve();
20602061
}
2061-
_a.label = 9;
2062-
case 9: return [3 /*break*/, 11];
2063-
case 10:
2062+
_a.label = 10;
2063+
case 10: return [3 /*break*/, 12];
2064+
case 11:
20642065
processCollection(querySnapshot.docChanges());
20652066
if (initialPromise.isPending) {
20662067
streamingStart();
20672068
}
20682069
if (refreshedPromise.isPending) {
20692070
refreshedPromise.resolve();
20702071
}
2071-
_a.label = 11;
2072-
case 11:
2073-
gotFirstServerResponse = true;
20742072
_a.label = 12;
2075-
case 12: return [2 /*return*/];
2073+
case 12:
2074+
gotFirstServerResponse = true;
2075+
_a.label = 13;
2076+
case 13: return [2 /*return*/];
20762077
}
20772078
});
20782079
}); }, streamingStop);

0 commit comments

Comments
 (0)