braid-text 0.3.16 → 0.3.18
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/client/simpleton-sync.js +30 -17
- package/package.json +1 -1
- package/server.js +17 -10
package/client/simpleton-sync.js
CHANGED
|
@@ -118,7 +118,7 @@ function simpleton_client(url, {
|
|
|
118
118
|
var outstanding_changes = 0 // PUTs sent, not yet ACKed
|
|
119
119
|
var max_outstanding_changes = 10 // throttle limit
|
|
120
120
|
var throttled = false
|
|
121
|
-
var
|
|
121
|
+
var throttled_updates = []
|
|
122
122
|
var ac = new AbortController()
|
|
123
123
|
|
|
124
124
|
// ── Subscription (GET) ──────────────────────────────────────────────
|
|
@@ -150,8 +150,11 @@ function simpleton_client(url, {
|
|
|
150
150
|
// parents match our client_version exactly. This ensures
|
|
151
151
|
// we stay on a single line of time.
|
|
152
152
|
update.parents.sort()
|
|
153
|
-
|
|
154
|
-
|
|
153
|
+
var last_queued = throttled_updates.length
|
|
154
|
+
? throttled_updates[throttled_updates.length - 1].version
|
|
155
|
+
: client_version
|
|
156
|
+
if (versions_eq(last_queued, update.parents))
|
|
157
|
+
if (throttled) throttled_updates.push(update)
|
|
155
158
|
else await apply_update(update)
|
|
156
159
|
}, on_error)
|
|
157
160
|
}).catch(on_error)
|
|
@@ -199,11 +202,31 @@ function simpleton_client(url, {
|
|
|
199
202
|
client_state = apply_patches(client_state, patches)
|
|
200
203
|
}
|
|
201
204
|
|
|
205
|
+
// ── Advance version ─────────────────────────────────────────
|
|
206
|
+
// IMPORTANT: This must happen synchronously (before any await)
|
|
207
|
+
// to prevent the changed() accumulation loop from interleaving
|
|
208
|
+
// and capturing a stale client_version during a yield point.
|
|
209
|
+
client_version = update.version
|
|
210
|
+
|
|
211
|
+
// ── Notify listener ─────────────────────────────────────────
|
|
212
|
+
// IMPORTANT: No changed() / flush is called here.
|
|
213
|
+
// The JS does NOT send edits after receiving a server
|
|
214
|
+
// update. The PUT response handler's async accumulation
|
|
215
|
+
// loop handles flushing accumulated edits.
|
|
216
|
+
if (on_state) on_state(client_state)
|
|
217
|
+
|
|
202
218
|
// ── Digest verification ─────────────────────────────────────
|
|
203
219
|
// If the server sent a repr-digest, verify our state
|
|
204
220
|
// matches. On mismatch, THROW — this halts the
|
|
205
221
|
// subscription handler. The document is corrupted and
|
|
206
222
|
// continuing would compound the problem.
|
|
223
|
+
//
|
|
224
|
+
// This is placed after advancing client_version and calling
|
|
225
|
+
// on_state so that the await does not create a yield point
|
|
226
|
+
// between applying patches and advancing client_version.
|
|
227
|
+
// That yield point previously allowed the changed() PUT loop
|
|
228
|
+
// to interleave, capturing a stale client_version and causing
|
|
229
|
+
// edit loss.
|
|
207
230
|
if (update.extra_headers &&
|
|
208
231
|
update.extra_headers["repr-digest"] &&
|
|
209
232
|
update.extra_headers["repr-digest"].startsWith('sha-256=') &&
|
|
@@ -213,16 +236,6 @@ function simpleton_client(url, {
|
|
|
213
236
|
console.log('state: ' + client_state)
|
|
214
237
|
throw new Error('repr-digest mismatch')
|
|
215
238
|
}
|
|
216
|
-
|
|
217
|
-
// ── Advance version ─────────────────────────────────────────
|
|
218
|
-
client_version = update.version
|
|
219
|
-
|
|
220
|
-
// ── Notify listener ─────────────────────────────────────────
|
|
221
|
-
// IMPORTANT: No changed() / flush is called here.
|
|
222
|
-
// The JS does NOT send edits after receiving a server
|
|
223
|
-
// update. The PUT response handler's async accumulation
|
|
224
|
-
// loop handles flushing accumulated edits.
|
|
225
|
-
if (on_state) on_state(client_state)
|
|
226
239
|
}
|
|
227
240
|
|
|
228
241
|
// ── Public interface ────────────────────────────────────────────────
|
|
@@ -255,10 +268,10 @@ function simpleton_client(url, {
|
|
|
255
268
|
if (!change) {
|
|
256
269
|
if (throttled) {
|
|
257
270
|
throttled = false
|
|
258
|
-
|
|
259
|
-
versions_eq(client_version,
|
|
260
|
-
|
|
261
|
-
|
|
271
|
+
for (var update of throttled_updates)
|
|
272
|
+
if (versions_eq(client_version, update.parents))
|
|
273
|
+
apply_update(update).catch(on_error)
|
|
274
|
+
throttled_updates = []
|
|
262
275
|
}
|
|
263
276
|
return
|
|
264
277
|
}
|
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -1023,16 +1023,10 @@ function create_braid_text() {
|
|
|
1023
1023
|
|
|
1024
1024
|
if (client.my_timeout) {
|
|
1025
1025
|
if (peer && client.peer === peer) {
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
set_timeout()
|
|
1031
|
-
} else {
|
|
1032
|
-
// hm.. it appears we got a correctly parented version,
|
|
1033
|
-
// which suggests that maybe we can stop the timeout early
|
|
1034
|
-
set_timeout(0)
|
|
1035
|
-
}
|
|
1026
|
+
// note: we don't add to client.my_unused_version_count,
|
|
1027
|
+
// because we're already in a timeout;
|
|
1028
|
+
// we'll just extend it here..
|
|
1029
|
+
set_timeout()
|
|
1036
1030
|
}
|
|
1037
1031
|
continue
|
|
1038
1032
|
}
|
|
@@ -1049,6 +1043,19 @@ function create_braid_text() {
|
|
|
1049
1043
|
|
|
1050
1044
|
x.parents = [version]
|
|
1051
1045
|
if (!v_eq(x.version, x.parents)) {
|
|
1046
|
+
// Note: this rebase will never trigger in the
|
|
1047
|
+
// presence of the timeout logic above, because
|
|
1048
|
+
// any version that would cause x.version to
|
|
1049
|
+
// differ from x.parents would have already
|
|
1050
|
+
// updated my_last_sent_version when forwarding
|
|
1051
|
+
// other peers' changes to this client, causing
|
|
1052
|
+
// a mismatch and triggering a timeout instead.
|
|
1053
|
+
//
|
|
1054
|
+
// However, this is the standard rebase path and
|
|
1055
|
+
// is left here for implementations that omit the
|
|
1056
|
+
// timeout optimization — without it, this branch
|
|
1057
|
+
// is needed to rebase the client's version when
|
|
1058
|
+
// concurrent edits have been merged.
|
|
1052
1059
|
if (braid_text.verbose) console.log("rebasing..")
|
|
1053
1060
|
x.patches = get_xf_patches(resource.doc, OpLog_remote_to_local(resource.doc, x.parents))
|
|
1054
1061
|
} else {
|