sharedb 5.1.1 → 5.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client/doc.js
CHANGED
|
@@ -61,6 +61,7 @@ function Doc(connection, collection, id) {
|
|
|
61
61
|
this.id = id;
|
|
62
62
|
|
|
63
63
|
this.version = null;
|
|
64
|
+
// The OT type of this document. An uncreated document has type `null`
|
|
64
65
|
this.type = null;
|
|
65
66
|
this.data = undefined;
|
|
66
67
|
|
|
@@ -70,6 +71,8 @@ function Doc(connection, collection, id) {
|
|
|
70
71
|
this.pendingFetch = [];
|
|
71
72
|
this.pendingSubscribe = [];
|
|
72
73
|
|
|
74
|
+
this._isInHardRollback = false;
|
|
75
|
+
|
|
73
76
|
// Whether we think we are subscribed on the server. Synchronously set to
|
|
74
77
|
// false on calls to unsubscribe and disconnect. Should never be true when
|
|
75
78
|
// this.wantSubscribe is false
|
|
@@ -93,9 +96,6 @@ function Doc(connection, collection, id) {
|
|
|
93
96
|
// This is a list of {[create:{...}], [del:true], [op:...], callbacks:[...]}
|
|
94
97
|
this.pendingOps = [];
|
|
95
98
|
|
|
96
|
-
// The OT type of this document. An uncreated document has type `null`
|
|
97
|
-
this.type = null;
|
|
98
|
-
|
|
99
99
|
// The applyStack enables us to track any ops submitted while we are
|
|
100
100
|
// applying an op incrementally. This value is an array when we are
|
|
101
101
|
// performing an incremental apply and null otherwise. When it is an array,
|
|
@@ -748,10 +748,18 @@ Doc.prototype._submit = function(op, source, callback) {
|
|
|
748
748
|
// The op contains either op, create, delete, or none of the above (a no-op).
|
|
749
749
|
if ('op' in op) {
|
|
750
750
|
if (!this.type) {
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
751
|
+
if (this._isInHardRollback) {
|
|
752
|
+
var err = new ShareDBError(
|
|
753
|
+
ERROR_CODE.ERR_DOC_IN_HARD_ROLLBACK,
|
|
754
|
+
'Cannot submit op. Document is performing hard rollback. ' + this.collection + '.' + this.id
|
|
755
|
+
);
|
|
756
|
+
} else {
|
|
757
|
+
var err = new ShareDBError(
|
|
758
|
+
ERROR_CODE.ERR_DOC_DOES_NOT_EXIST,
|
|
759
|
+
'Cannot submit op. Document has not been created. ' + this.collection + '.' + this.id
|
|
760
|
+
);
|
|
761
|
+
}
|
|
762
|
+
|
|
755
763
|
if (callback) return callback(err);
|
|
756
764
|
return this.emit('error', err);
|
|
757
765
|
}
|
|
@@ -1030,6 +1038,7 @@ Doc.prototype._rollback = function(err) {
|
|
|
1030
1038
|
};
|
|
1031
1039
|
|
|
1032
1040
|
Doc.prototype._hardRollback = function(err) {
|
|
1041
|
+
this._isInHardRollback = true;
|
|
1033
1042
|
// Store pending ops so that we can notify their callbacks of the error.
|
|
1034
1043
|
// We combine the inflight op and the pending ops, because it's possible
|
|
1035
1044
|
// to hit a condition where we have no inflight op, but we do have pending
|
|
@@ -1047,6 +1056,8 @@ Doc.prototype._hardRollback = function(err) {
|
|
|
1047
1056
|
// Fetch the latest version from the server to get us back into a working state
|
|
1048
1057
|
var doc = this;
|
|
1049
1058
|
this._fetch({force: true}, function(fetchError) {
|
|
1059
|
+
doc._isInHardRollback = false;
|
|
1060
|
+
|
|
1050
1061
|
// We want to check that no errors are swallowed, so we check that:
|
|
1051
1062
|
// - there are callbacks to call, and
|
|
1052
1063
|
// - that every single pending op called a callback
|
|
@@ -30,10 +30,20 @@ LocalDocPresence.prototype.submit = function(value, callback) {
|
|
|
30
30
|
// be null. Let's early return, instead of error since this is a harmless
|
|
31
31
|
// no-op
|
|
32
32
|
if (value === null) return this._callbackOrEmit(null, callback);
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
|
|
34
|
+
var error = null;
|
|
35
|
+
if (this._doc._isInHardRollback) {
|
|
36
|
+
error = {
|
|
37
|
+
code: ERROR_CODE.ERR_DOC_IN_HARD_ROLLBACK,
|
|
38
|
+
message: 'Cannot submit presence. Document is processing hard rollback'
|
|
39
|
+
};
|
|
40
|
+
} else {
|
|
41
|
+
error = {
|
|
42
|
+
code: ERROR_CODE.ERR_DOC_DOES_NOT_EXIST,
|
|
43
|
+
message: 'Cannot submit presence. Document has not been created'
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
37
47
|
return this._callbackOrEmit(error, callback);
|
|
38
48
|
};
|
|
39
49
|
|
package/lib/error.js
CHANGED
|
@@ -30,6 +30,7 @@ ShareDBError.CODES = {
|
|
|
30
30
|
ERR_DOC_DOES_NOT_EXIST: 'ERR_DOC_DOES_NOT_EXIST',
|
|
31
31
|
ERR_DOC_TYPE_NOT_RECOGNIZED: 'ERR_DOC_TYPE_NOT_RECOGNIZED',
|
|
32
32
|
ERR_DOC_WAS_DELETED: 'ERR_DOC_WAS_DELETED',
|
|
33
|
+
ERR_DOC_IN_HARD_ROLLBACK: 'ERR_DOC_IN_HARD_ROLLBACK',
|
|
33
34
|
ERR_INFLIGHT_OP_MISSING: 'ERR_INFLIGHT_OP_MISSING',
|
|
34
35
|
ERR_INGESTED_SNAPSHOT_HAS_NO_VERSION: 'ERR_INGESTED_SNAPSHOT_HAS_NO_VERSION',
|
|
35
36
|
ERR_MAX_SUBMIT_RETRIES_EXCEEDED: 'ERR_MAX_SUBMIT_RETRIES_EXCEEDED',
|
package/package.json
CHANGED
package/test/client/doc.js
CHANGED
|
@@ -636,6 +636,25 @@ describe('Doc', function() {
|
|
|
636
636
|
}
|
|
637
637
|
], done);
|
|
638
638
|
});
|
|
639
|
+
|
|
640
|
+
it('rejects ops with ERR_DOC_IN_HARD_ROLLBACK error when in hard rollback', function(done) {
|
|
641
|
+
var backend = this.backend;
|
|
642
|
+
var doc = backend.connect().get('dogs', 'snoopy');
|
|
643
|
+
|
|
644
|
+
async.series([
|
|
645
|
+
doc.create.bind(doc, {color: 'red'}),
|
|
646
|
+
function(next) {
|
|
647
|
+
doc.on('error', function(error) {
|
|
648
|
+
expect(error.code).to.be.equal('TEST_ERROR');
|
|
649
|
+
});
|
|
650
|
+
doc._hardRollback(new ShareDBError('TEST_ERROR'));
|
|
651
|
+
doc.submitOp({p: ['color'], oi: 'blue', od: 'red'}, function(error) {
|
|
652
|
+
expect(error.code).to.be.equal('ERR_DOC_IN_HARD_ROLLBACK');
|
|
653
|
+
next();
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
], done);
|
|
657
|
+
});
|
|
639
658
|
});
|
|
640
659
|
|
|
641
660
|
describe('errors on ops that could cause prototype corruption', function() {
|
|
@@ -829,6 +829,20 @@ describe('DocPresence', function() {
|
|
|
829
829
|
], done);
|
|
830
830
|
});
|
|
831
831
|
|
|
832
|
+
|
|
833
|
+
it('errors local presence when doc is in hard rollback', function(done) {
|
|
834
|
+
var localPresence1 = presence1.create('presence-1');
|
|
835
|
+
|
|
836
|
+
doc1.on('error', function(error) {
|
|
837
|
+
expect(error).to.be.equal('some error');
|
|
838
|
+
});
|
|
839
|
+
doc1._hardRollback('some error');
|
|
840
|
+
localPresence1.submit({index: 1}, function(error) {
|
|
841
|
+
expect(error.code).to.be.equal('ERR_DOC_IN_HARD_ROLLBACK');
|
|
842
|
+
done();
|
|
843
|
+
});
|
|
844
|
+
});
|
|
845
|
+
|
|
832
846
|
it('returns errors sent from the middleware', function(done) {
|
|
833
847
|
backend.use(backend.MIDDLEWARE_ACTIONS.sendPresence, function(request, callback) {
|
|
834
848
|
callback('some error');
|