braid-text 0.5.15 → 0.5.17
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/README.md +3 -1
- package/package.json +2 -2
- package/server.js +37 -8
package/README.md
CHANGED
|
@@ -77,6 +77,7 @@ http_server.on("request", (req, res) => {
|
|
|
77
77
|
- `version` - The version after the PUT
|
|
78
78
|
- `parents` - The version prior to the PUT
|
|
79
79
|
- This is the main method of this library, and does all the work to handle Braid-HTTP `GET` and `PUT` requests concerned with a specific text resource.
|
|
80
|
+
- A `GET` with `Subscribe: true` and `Method-Override: HEAD` headers subscribes to header-only updates: each update carries just `Version` and `Parents` headers, with no body or patches — useful for cheaply knowing *that* something changed. (A `Method-Override: HEAD` on a `GET` without `Subscribe` acts like a normal `HEAD` request.)
|
|
80
81
|
|
|
81
82
|
`await braid_text.get(key)`
|
|
82
83
|
- `key`: ID of text resource.
|
|
@@ -86,10 +87,11 @@ http_server.on("request", (req, res) => {
|
|
|
86
87
|
- `key`: ID of text resource.
|
|
87
88
|
- `options`: An object containing additional options, like http headers:
|
|
88
89
|
- `version`: <small style="color:lightgrey">[optional]</small> The [version](https://datatracker.ietf.org/doc/html/draft-toomim-httpbis-braid-http#section-2) to get, as an array of strings. (The array is typically length 1.)
|
|
89
|
-
- `parents`: <small style="color:lightgrey">[optional]</small> The version to start the subscription at, as an array of strings.
|
|
90
|
+
- `parents`: <small style="color:lightgrey">[optional]</small> The version to start the subscription at, as an array of strings. If this is already the current version, no initial update is sent.
|
|
90
91
|
- `subscribe: cb`: <small style="color:lightgrey">[optional]</small> Instead of returning the state; [subscribes](https://datatracker.ietf.org/doc/html/draft-toomim-httpbis-braid-http#section-4) to the state, and calls `cb` with the initial state and each update. The function `cb` will be called with a Braid [update](https://datatracker.ietf.org/doc/html/draft-toomim-httpbis-braid-http#section-3) of the form `cb({version, parents, body, patches})`.
|
|
91
92
|
- `merge_type`: <small style="color:lightgrey">[optional]</small> The CRDT/OT [merge-type](https://raw.githubusercontent.com/braid-org/braid-spec/master/draft-toomim-httpbis-merge-types-00.txt) algorithm to emulate. Currently supports `"simpleton"` (default) and `"dt"`.
|
|
92
93
|
- `peer`: <small style="color:lightgrey">[optional]</small> Unique string ID that identifies the peer making the subscription. Mutations will not be echoed back to the same peer that `PUT`s them, for any `PUT` setting the same `peer` header.
|
|
94
|
+
- `head`: <small style="color:lightgrey">[optional]</small> If true, the subscription receives header-only updates of the form `{version, parents}` — no `body` or `patches`. Useful for cheaply knowing *that* something changed, without the cost of materializing history or patch content. On subscribe, `cb` is called once with the current version (or not at all, if `parents` is already current — as with any subscription); after that, once per update. Only meaningful with `subscribe`.
|
|
93
95
|
- If NOT subscribing, returns `{version: <current_version>, body: <current-text>}`. If subscribing, returns nothing.
|
|
94
96
|
|
|
95
97
|
`await braid_text.put(key, options)`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "braid-text",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.17",
|
|
4
4
|
"description": "Library for collaborative text over http using braid.",
|
|
5
5
|
"author": "Braid Working Group",
|
|
6
6
|
"repository": "braid-org/braid-text",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
],
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@braid.org/diamond-types-node": "^2.0.1",
|
|
30
|
-
"braid-http": "~1.3.
|
|
30
|
+
"braid-http": "~1.3.131"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"yjs": "^13.6.0"
|
package/server.js
CHANGED
|
@@ -372,9 +372,15 @@ function create_braid_text() {
|
|
|
372
372
|
if (merge_type !== 'simpleton' && merge_type !== 'dt' && merge_type !== 'yjs')
|
|
373
373
|
return my_end(400, `Unknown merge type: ${merge_type}`)
|
|
374
374
|
|
|
375
|
+
// Method-Override: HEAD makes a GET act like a HEAD request.
|
|
376
|
+
// Combined with Subscribe, it subscribes to header-only updates
|
|
377
|
+
// (Version/Parents, no body or patches) — which a real HEAD request
|
|
378
|
+
// can't do, since HEAD responses can't stream a body.
|
|
379
|
+
var head_override = /^head$/i.test(req.headers['method-override'] ?? '')
|
|
380
|
+
|
|
375
381
|
var is_read = req.method === 'GET' || req.method === 'HEAD',
|
|
376
382
|
is_write = req.method === 'PUT' || req.method === 'POST' || req.method === 'PATCH',
|
|
377
|
-
is_head = req.method === 'HEAD'
|
|
383
|
+
is_head = req.method === 'HEAD' || (head_override && !req.subscribe)
|
|
378
384
|
|
|
379
385
|
// ── Handle simple methods that don't need further processing ──
|
|
380
386
|
|
|
@@ -506,12 +512,16 @@ function create_braid_text() {
|
|
|
506
512
|
version: req.version,
|
|
507
513
|
parents: req.parents,
|
|
508
514
|
merge_type,
|
|
515
|
+
head: head_override,
|
|
509
516
|
signal: aborter.signal,
|
|
510
517
|
accept_encoding:
|
|
511
518
|
req.headers['x-accept-encoding'] ?? req.headers['accept-encoding'],
|
|
512
519
|
subscribe: update => {
|
|
513
520
|
// Add digest for integrity checking on the client
|
|
514
|
-
|
|
521
|
+
// (skipped for header-only updates, which carry
|
|
522
|
+
// no content to check)
|
|
523
|
+
if (!head_override
|
|
524
|
+
&& update.version && v_eq(update.version, resource.version))
|
|
515
525
|
update['Repr-Digest'] = get_digest(resource.val)
|
|
516
526
|
|
|
517
527
|
// Collapse single-element patches array for HTTP
|
|
@@ -519,7 +529,7 @@ function create_braid_text() {
|
|
|
519
529
|
update.patch = update.patches[0]
|
|
520
530
|
delete update.patches
|
|
521
531
|
}
|
|
522
|
-
if (!update.encoding)
|
|
532
|
+
if (!update.encoding && !head_override)
|
|
523
533
|
update.content_type = content_type
|
|
524
534
|
res.sendUpdate(update)
|
|
525
535
|
},
|
|
@@ -690,7 +700,11 @@ function create_braid_text() {
|
|
|
690
700
|
|
|
691
701
|
var resource = (typeof key == 'string') ? await get_resource(key) : key
|
|
692
702
|
var version = resource.version
|
|
693
|
-
|
|
703
|
+
// head: true = subscribe to header-only updates (version/parents,
|
|
704
|
+
// no body or patches). Cheap: never materializes history or patch
|
|
705
|
+
// content. Head clients live in the dt client list.
|
|
706
|
+
var merge_type = options.head ? 'dt'
|
|
707
|
+
: options.range_unit === 'yjs-text' ? 'yjs'
|
|
694
708
|
: (options.merge_type || 'simpleton')
|
|
695
709
|
var has_parents = Array.isArray(options.parents)
|
|
696
710
|
var has_version = Array.isArray(options.version)
|
|
@@ -829,12 +843,20 @@ function create_braid_text() {
|
|
|
829
843
|
var client = {
|
|
830
844
|
merge_type: 'dt',
|
|
831
845
|
peer: options.peer,
|
|
846
|
+
head: !!options.head,
|
|
832
847
|
send_update: one_at_a_time(options.subscribe),
|
|
833
848
|
accept_encoding_dt: !!options.accept_encoding?.match(/updates\s*\((.*)\)/)?.[1]?.split(',').map(x=>x.trim()).includes('dt'),
|
|
834
849
|
}
|
|
835
850
|
|
|
836
851
|
// Send initial history
|
|
837
|
-
if (client.
|
|
852
|
+
if (client.head) {
|
|
853
|
+
// Header-only: announce the current frontier in a single
|
|
854
|
+
// update — or send nothing if the subscriber's parents
|
|
855
|
+
// are already current (getting.history === false)
|
|
856
|
+
if (getting.history)
|
|
857
|
+
client.send_update({ version: resource.version,
|
|
858
|
+
parents: options.parents || [] })
|
|
859
|
+
} else if (client.accept_encoding_dt) {
|
|
838
860
|
if (!getting.history)
|
|
839
861
|
client.send_update({ encoding: 'dt', body: new Doc().toBytes() })
|
|
840
862
|
else {
|
|
@@ -993,7 +1015,11 @@ function create_braid_text() {
|
|
|
993
1015
|
for (let client of resource.dt.clients) {
|
|
994
1016
|
if (!peer || client.peer !== peer)
|
|
995
1017
|
await client.send_update(
|
|
996
|
-
client.
|
|
1018
|
+
client.head
|
|
1019
|
+
? { version: resource.version,
|
|
1020
|
+
parents: version_before_yjs_sync
|
|
1021
|
+
}
|
|
1022
|
+
: client.accept_encoding_dt
|
|
997
1023
|
? { version: resource.version,
|
|
998
1024
|
parents: version_before_yjs_sync,
|
|
999
1025
|
body: resource.dt.doc.getPatchSince(yjs_v_before),
|
|
@@ -1042,6 +1068,7 @@ function create_braid_text() {
|
|
|
1042
1068
|
|
|
1043
1069
|
if (options.transfer_encoding === 'dt') {
|
|
1044
1070
|
await ensure_dt_exists(resource)
|
|
1071
|
+
var version_before_dt_put = resource.version
|
|
1045
1072
|
var start_i = 1 + resource.dt.doc.getLocalVersion().reduce((a, b) => Math.max(a, b), -1)
|
|
1046
1073
|
|
|
1047
1074
|
resource.dt.doc.mergeBytes(body)
|
|
@@ -1059,9 +1086,10 @@ function create_braid_text() {
|
|
|
1059
1086
|
|
|
1060
1087
|
// Notify non-simpleton clients with the dt-encoded update
|
|
1061
1088
|
var dt_update = { body, encoding: 'dt' }
|
|
1089
|
+
var head_update = { version: resource.version, parents: version_before_dt_put }
|
|
1062
1090
|
for (let client of resource.dt.clients)
|
|
1063
1091
|
if (!peer || client.peer !== peer)
|
|
1064
|
-
await client.send_update(dt_update)
|
|
1092
|
+
await client.send_update(client.head ? head_update : dt_update)
|
|
1065
1093
|
|
|
1066
1094
|
return { dt: { change_count: end_i - start_i + 1 } }
|
|
1067
1095
|
}
|
|
@@ -1355,9 +1383,10 @@ function create_braid_text() {
|
|
|
1355
1383
|
content: p.content
|
|
1356
1384
|
})),
|
|
1357
1385
|
}
|
|
1386
|
+
var x_head = { version: x.version, parents: x.parents }
|
|
1358
1387
|
for (let client of resource.dt.clients) {
|
|
1359
1388
|
if (!peer || client.peer !== peer)
|
|
1360
|
-
post_commit_updates.push([client, x])
|
|
1389
|
+
post_commit_updates.push([client, client.head ? x_head : x])
|
|
1361
1390
|
}
|
|
1362
1391
|
|
|
1363
1392
|
await resource.dt.log.save(resource.dt.doc.getPatchSince(v_before))
|