braid-text 0.5.6 → 0.5.7
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 +59 -57
- package/package.json +2 -2
- package/server.js +14 -4
package/client/simpleton-sync.js
CHANGED
|
@@ -55,6 +55,18 @@
|
|
|
55
55
|
//
|
|
56
56
|
// content_type: used for Accept and Content-Type headers
|
|
57
57
|
//
|
|
58
|
+
// on_error?: (error) => void
|
|
59
|
+
// called when an error occurs (e.g., network failure, digest mismatch)
|
|
60
|
+
//
|
|
61
|
+
// on_online?: (is_online) => void
|
|
62
|
+
// called when the connection status changes
|
|
63
|
+
//
|
|
64
|
+
// on_ack?: () => void
|
|
65
|
+
// called when all outstanding PUTs have been acknowledged
|
|
66
|
+
//
|
|
67
|
+
// send_digests?: boolean
|
|
68
|
+
// if truthy, includes a Repr-Digest header with each PUT
|
|
69
|
+
//
|
|
58
70
|
// returns { changed, abort }
|
|
59
71
|
// call changed() whenever there is a local change,
|
|
60
72
|
// and the system will call a combination of get_state and
|
|
@@ -106,10 +118,9 @@ function simpleton_client(url, {
|
|
|
106
118
|
get_patches,
|
|
107
119
|
get_state,
|
|
108
120
|
content_type,
|
|
109
|
-
headers
|
|
110
|
-
// that are
|
|
121
|
+
headers, // The user can pass in custom headers
|
|
122
|
+
// that are forwarded into fetches
|
|
111
123
|
on_error,
|
|
112
|
-
on_res,
|
|
113
124
|
on_online,
|
|
114
125
|
on_ack,
|
|
115
126
|
send_digests
|
|
@@ -122,38 +133,34 @@ function simpleton_client(url, {
|
|
|
122
133
|
var max_outstanding_changes = 10 // throttle limit
|
|
123
134
|
var throttled = false
|
|
124
135
|
var throttled_updates = []
|
|
125
|
-
var ac = new AbortController()
|
|
126
136
|
|
|
127
|
-
//
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
//
|
|
135
|
-
//
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
headers: { ...custom_headers,
|
|
148
|
-
"Merge-Type": "simpleton",
|
|
149
|
-
...content_type && {Accept: content_type} },
|
|
150
|
-
}).then(res => {
|
|
151
|
-
if (on_res) on_res(res)
|
|
152
|
-
res.subscribe(async update => {
|
|
137
|
+
// extend the headers with merge-type and peer
|
|
138
|
+
headers = {
|
|
139
|
+
...headers,
|
|
140
|
+
"Merge-Type": "simpleton",
|
|
141
|
+
Peer: peer,
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Manages both the GET subscription and PUT requests through a single
|
|
145
|
+
// channel with automatic reconnection and PUT queuing.
|
|
146
|
+
var channel = reliable_update_channel(url, {
|
|
147
|
+
reconnect_from_parents: () => client_version.length ? client_version : null,
|
|
148
|
+
get_headers: {
|
|
149
|
+
...headers,
|
|
150
|
+
...content_type && {Accept: content_type}
|
|
151
|
+
},
|
|
152
|
+
put_headers: {
|
|
153
|
+
...headers,
|
|
154
|
+
...content_type && {"Content-Type": content_type}
|
|
155
|
+
},
|
|
156
|
+
on_update: async update => {
|
|
153
157
|
// ── Parent check ────────────────────────────────────────
|
|
154
158
|
// Core simpleton invariant: only accept updates whose
|
|
155
|
-
// parents
|
|
156
|
-
//
|
|
159
|
+
// parents form a continuous chain. We compare against the
|
|
160
|
+
// last queued update's version (if throttled) or
|
|
161
|
+
// client_version. When throttled, matching updates are
|
|
162
|
+
// queued but not applied — they'll be applied later when
|
|
163
|
+
// the throttle clears (see changed()).
|
|
157
164
|
update.parents.sort()
|
|
158
165
|
var last_queued = throttled_updates.length
|
|
159
166
|
? throttled_updates[throttled_updates.length - 1].version
|
|
@@ -161,8 +168,16 @@ function simpleton_client(url, {
|
|
|
161
168
|
if (versions_eq(last_queued, update.parents))
|
|
162
169
|
if (throttled) throttled_updates.push(update)
|
|
163
170
|
else await apply_update(update)
|
|
164
|
-
},
|
|
165
|
-
|
|
171
|
+
},
|
|
172
|
+
on_status: status => on_online && on_online(status.online),
|
|
173
|
+
on_error: err => on_error && on_error(err),
|
|
174
|
+
|
|
175
|
+
// this api is preliminary and undocumented;
|
|
176
|
+
// we use it to tell the reliable_update_channel to die,
|
|
177
|
+
// if there is a digest mismatch on the server,
|
|
178
|
+
// which will result in a 550 status code
|
|
179
|
+
no_retry_status_codes: [550]
|
|
180
|
+
})
|
|
166
181
|
|
|
167
182
|
async function apply_update(update) {
|
|
168
183
|
// ── Parse and convert patches ───────────────────────────────
|
|
@@ -246,7 +261,7 @@ function simpleton_client(url, {
|
|
|
246
261
|
// ── Public interface ────────────────────────────────────────────────
|
|
247
262
|
return {
|
|
248
263
|
// ── abort() — cancel the subscription ─────────────────────────
|
|
249
|
-
abort: () =>
|
|
264
|
+
abort: () => channel.close(),
|
|
250
265
|
|
|
251
266
|
// ── changed() — call when local edits occur ───────────────────
|
|
252
267
|
// This is the entry point for sending local edits. It:
|
|
@@ -326,28 +341,15 @@ function simpleton_client(url, {
|
|
|
326
341
|
// - HTTP 550 (Repr-Digest mismatch / out of sync):
|
|
327
342
|
// give up, throw — client must be re-created
|
|
328
343
|
outstanding_changes++
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
"Repr-Digest": await get_digest(client_state) },
|
|
339
|
-
...content_type && {
|
|
340
|
-
"Content-Type": content_type }
|
|
341
|
-
}
|
|
342
|
-
})
|
|
343
|
-
if (!r.ok) throw new Error(`bad http status: ${r.status}`)
|
|
344
|
-
} catch (e) {
|
|
345
|
-
// A 550 means Repr-Digest check failed — we're out
|
|
346
|
-
// of sync. The client must be torn down and
|
|
347
|
-
// re-created from scratch.
|
|
348
|
-
on_error(e)
|
|
349
|
-
throw e
|
|
350
|
-
}
|
|
344
|
+
|
|
345
|
+
await channel.put({
|
|
346
|
+
version, parents, patches,
|
|
347
|
+
headers: {
|
|
348
|
+
...send_digests && {
|
|
349
|
+
"Repr-Digest": await get_digest(client_state) }
|
|
350
|
+
}
|
|
351
|
+
})
|
|
352
|
+
|
|
351
353
|
throttled = false
|
|
352
354
|
outstanding_changes--
|
|
353
355
|
if (on_ack && !outstanding_changes) on_ack()
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "braid-text",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.7",
|
|
4
4
|
"description": "Library for collaborative text over http using braid.",
|
|
5
5
|
"author": "Braid Working Group",
|
|
6
6
|
"repository": "braid-org/braid-text",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@braid.org/diamond-types-node": "^2.0.1",
|
|
28
|
-
"braid-http": "
|
|
28
|
+
"braid-http": "~1.3.123"
|
|
29
29
|
},
|
|
30
30
|
"peerDependencies": {
|
|
31
31
|
"yjs": "^13.6.0"
|
package/server.js
CHANGED
|
@@ -959,7 +959,8 @@ function create_braid_text() {
|
|
|
959
959
|
}
|
|
960
960
|
for (var b of dt_bytes) resource.dt.doc.mergeBytes(b)
|
|
961
961
|
resource.version = resource.dt.doc.getRemoteVersion().map(x => x.join("-")).sort()
|
|
962
|
-
if (!resource.dt.known_versions[syn_actor])
|
|
962
|
+
if (!resource.dt.known_versions[syn_actor])
|
|
963
|
+
resource.dt.known_versions[syn_actor] = new RangeSet()
|
|
963
964
|
resource.dt.known_versions[syn_actor].add_range(0, syn_seq - 1)
|
|
964
965
|
await resource.dt.log.save(resource.dt.doc.getPatchSince(yjs_v_before))
|
|
965
966
|
|
|
@@ -977,8 +978,15 @@ function create_braid_text() {
|
|
|
977
978
|
if (!peer || client.peer !== peer)
|
|
978
979
|
await client.send_update(
|
|
979
980
|
client.accept_encoding_dt
|
|
980
|
-
? { version: resource.version,
|
|
981
|
-
|
|
981
|
+
? { version: resource.version,
|
|
982
|
+
parents: version_before_yjs_sync,
|
|
983
|
+
body: resource.dt.doc.getPatchSince(yjs_v_before),
|
|
984
|
+
encoding: 'dt'
|
|
985
|
+
}
|
|
986
|
+
: { version: resource.version,
|
|
987
|
+
parents: version_before_yjs_sync,
|
|
988
|
+
patches: xf
|
|
989
|
+
}
|
|
982
990
|
)
|
|
983
991
|
}
|
|
984
992
|
}
|
|
@@ -1349,7 +1357,9 @@ function create_braid_text() {
|
|
|
1349
1357
|
if (braid_text.db_folder) {
|
|
1350
1358
|
await db_folder_init()
|
|
1351
1359
|
var pages = new Set()
|
|
1352
|
-
for (let x of await require('fs').promises.readdir(braid_text.db_folder))
|
|
1360
|
+
for (let x of await require('fs').promises.readdir(braid_text.db_folder))
|
|
1361
|
+
if (/\.(dt|yjs)\.\d+$/.test(x))
|
|
1362
|
+
pages.add(decode_filename(x.replace(/\.(dt|yjs)\.\d+$/, '')))
|
|
1353
1363
|
return [...pages.keys()]
|
|
1354
1364
|
} else return Object.keys(braid_text.cache)
|
|
1355
1365
|
} catch (e) { return [] }
|