braid-text 0.2.42 → 0.2.44

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.
Files changed (3) hide show
  1. package/index.js +40 -27
  2. package/package.json +2 -2
  3. package/test/test.html +178 -0
package/index.js CHANGED
@@ -122,6 +122,7 @@ braid_text.serve = async (req, res, options = {}) => {
122
122
  } else {
123
123
  if (!res.hasHeader("editable")) res.setHeader("Editable", "true")
124
124
  res.setHeader("Merge-Type", merge_type)
125
+ res.setHeader("Current-Version", get_current_version())
125
126
  if (req.method == "HEAD") return my_end(200)
126
127
 
127
128
  let options = {
@@ -129,6 +130,9 @@ braid_text.serve = async (req, res, options = {}) => {
129
130
  version: req.version,
130
131
  parents: req.parents,
131
132
  merge_type,
133
+ accept_encoding:
134
+ req.headers['x-accept-encoding'] ??
135
+ req.headers['accept-encoding'],
132
136
  subscribe: x => res.sendVersion(x),
133
137
  write: (x) => res.write(x)
134
138
  }
@@ -229,10 +233,9 @@ braid_text.get = async (key, options) => {
229
233
  if (options.parents) validate_version_array(options.parents)
230
234
 
231
235
  let resource = (typeof key == 'string') ? await get_resource(key) : key
236
+ var version = resource.doc.getRemoteVersion().map((x) => x.join("-")).sort()
232
237
 
233
238
  if (!options.subscribe) {
234
- var version = resource.doc.getRemoteVersion().map((x) => x.join("-")).sort()
235
-
236
239
  if (options.transfer_encoding === 'dt') {
237
240
  // optimization: if requesting current version
238
241
  // pretend as if they didn't set a version,
@@ -251,7 +254,7 @@ braid_text.get = async (key, options) => {
251
254
  }
252
255
  if (options.parents) {
253
256
  bytes = doc.getPatchSince(
254
- dt_get_local_version(bytes, options.parents))
257
+ dt_get_local_version(bytes, options.parents))
255
258
  }
256
259
  doc.free()
257
260
  } else bytes = resource.doc.toBytes()
@@ -267,7 +270,6 @@ braid_text.get = async (key, options) => {
267
270
  }
268
271
  } else {
269
272
  if (options.merge_type != "dt") {
270
- let version = resource.doc.getRemoteVersion().map((x) => x.join("-")).sort()
271
273
  let x = { version }
272
274
 
273
275
  if (!options.parents && !options.version) {
@@ -295,32 +297,43 @@ braid_text.get = async (key, options) => {
295
297
  resource.doc = defrag_dt(resource.doc)
296
298
  }
297
299
 
298
- var updates = null
299
- if (!options.parents && !options.version) {
300
- options.subscribe({
301
- version: [],
302
- parents: [],
303
- body: "",
304
- })
305
-
306
- updates = dt_get_patches(resource.doc)
300
+ if (options.accept_encoding?.match(/updates\s*\((.*)\)/)?.[1].split(',').map(x=>x.trim()).includes('dt')) {
301
+ var bytes = resource.doc.toBytes()
302
+ if (options.parents) {
303
+ var doc = Doc.fromBytes(bytes)
304
+ bytes = doc.getPatchSince(
305
+ dt_get_local_version(bytes, options.parents))
306
+ doc.free()
307
+ }
308
+ options.subscribe({ encoding: 'dt', body: bytes })
307
309
  } else {
308
- // Then start the subscription from the parents in options
309
- updates = dt_get_patches(resource.doc, options.parents || options.version)
310
- }
310
+ var updates = null
311
+ if (!options.parents && !options.version) {
312
+ options.subscribe({
313
+ version: [],
314
+ parents: [],
315
+ body: "",
316
+ })
311
317
 
312
- for (let u of updates)
313
- options.subscribe({
314
- version: [u.version],
315
- parents: u.parents,
316
- patches: [{ unit: u.unit, range: u.range, content: u.content }],
317
- })
318
+ updates = dt_get_patches(resource.doc)
319
+ } else {
320
+ // Then start the subscription from the parents in options
321
+ updates = dt_get_patches(resource.doc, options.parents || options.version)
322
+ }
323
+
324
+ for (let u of updates)
325
+ options.subscribe({
326
+ version: [u.version],
327
+ parents: u.parents,
328
+ patches: [{ unit: u.unit, range: u.range, content: u.content }],
329
+ })
318
330
 
319
- // Output at least *some* data, or else chrome gets confused and
320
- // thinks the connection failed. This isn't strictly necessary,
321
- // but it makes fewer scary errors get printed out in the JS
322
- // console.
323
- if (updates.length === 0) options.write?.("\r\n")
331
+ // Output at least *some* data, or else chrome gets confused and
332
+ // thinks the connection failed. This isn't strictly necessary,
333
+ // but it makes fewer scary errors get printed out in the JS
334
+ // console.
335
+ if (updates.length === 0) options.write?.("\r\n")
336
+ }
324
337
 
325
338
  resource.clients.add(options)
326
339
  }
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "braid-text",
3
- "version": "0.2.42",
3
+ "version": "0.2.44",
4
4
  "description": "Library for collaborative text over http using braid.",
5
5
  "author": "Braid Working Group",
6
6
  "repository": "braid-org/braid-text",
7
7
  "homepage": "https://braid.org",
8
8
  "dependencies": {
9
9
  "@braid.org/diamond-types-node": "^2.0.0",
10
- "braid-http": "~1.3.77"
10
+ "braid-http": "~1.3.79"
11
11
  }
12
12
  }
package/test/test.html CHANGED
@@ -18,8 +18,20 @@
18
18
  .failed {
19
19
  background-color: #ffebee;
20
20
  }
21
+ #summaryContainer {
22
+ display: flex;
23
+ flex-wrap: wrap;
24
+ gap: 5px;
25
+ margin-bottom: 20px;
26
+ }
27
+ .summaryBox {
28
+ width: 25px;
29
+ height: 25px;
30
+ border: 1px solid #ddd;
31
+ }
21
32
  </style>
22
33
  <script src="https://unpkg.com/braid-http@~1.3/braid-http-client.js"></script>
34
+ <div id="summaryContainer"></div>
23
35
  <div id="testContainer"></div>
24
36
  <script type=module>
25
37
 
@@ -51,20 +63,36 @@ function updateTestResult(div, passed, message, got, expected) {
51
63
  }
52
64
  }
53
65
 
66
+ function createSummaryBox() {
67
+ var summaryContainer = document.getElementById('summaryContainer')
68
+ const box = document.createElement('div');
69
+ box.className = 'summaryBox running';
70
+ summaryContainer.appendChild(box);
71
+ return box;
72
+ }
73
+
74
+ function updateSummaryBox(box, passed) {
75
+ box.className = `summaryBox ${passed ? 'passed' : passed === false ? 'failed' : 'other'}`;
76
+ }
77
+
54
78
  async function runTest(testName, testFunction, expectedResult) {
55
79
  delay += 70
56
80
 
57
81
  await new Promise(done => setTimeout(done, delay))
58
82
  const div = createTestDiv(testName)
83
+ const summaryBox = createSummaryBox()
59
84
  try {
60
85
  let x = await testFunction()
61
86
  if (x == expectedResult) {
62
87
  updateTestResult(div, true, x)
88
+ updateSummaryBox(summaryBox, true)
63
89
  } else {
64
90
  updateTestResult(div, false, "Mismatch:", x, expectedResult)
91
+ updateSummaryBox(summaryBox, false)
65
92
  }
66
93
  } catch (error) {
67
94
  updateTestResult(div, false, "Error:", error.message || error, expectedResult)
95
+ updateSummaryBox(summaryBox, false)
68
96
  }
69
97
  }
70
98
 
@@ -456,6 +484,135 @@ runTest(
456
484
  '"hi\\u2211-1" hi∑-1 buf.byteLength:0'
457
485
  )
458
486
 
487
+ runTest(
488
+ "test accept-encoding updates(dt) (with parents)",
489
+ async () => {
490
+ await dt_p
491
+ let key = 'test-' + Math.random().toString(36).slice(2)
492
+ var doc = new Doc('hi')
493
+ doc.ins(0, 'x')
494
+
495
+ let r = await braid_fetch(`/${key}`, {
496
+ method: 'PUT',
497
+ version: ['hi-1'],
498
+ parents: [],
499
+ body: 'xy'
500
+ })
501
+ if (!r.ok) throw 'got: ' + r.statusCode
502
+
503
+ var a = new AbortController()
504
+ let r2 = await braid_fetch(`/${key}`, {
505
+ signal: a.signal,
506
+ parents: ['hi-0'],
507
+ subscribe: true,
508
+ headers: {
509
+ 'merge-type': 'dt',
510
+ 'X-Accept-Encoding': 'updates(dt)'
511
+ }
512
+ })
513
+
514
+ return await new Promise(done => {
515
+ r2.subscribe(u => {
516
+ doc.mergeBytes(u.body)
517
+ done(doc.get())
518
+ doc.free()
519
+ a.abort()
520
+ })
521
+ })
522
+ },
523
+ 'xy'
524
+ )
525
+
526
+ runTest(
527
+ "test accept-encoding updates(dt)",
528
+ async () => {
529
+ await dt_p
530
+ let key = 'test-' + Math.random().toString(36).slice(2)
531
+
532
+ let r = await braid_fetch(`/${key}`, {
533
+ method: 'PUT',
534
+ version: ['hi-1'],
535
+ parents: [],
536
+ body: 'xy'
537
+ })
538
+ if (!r.ok) throw 'got: ' + r.statusCode
539
+
540
+ var a = new AbortController()
541
+ let r2 = await braid_fetch(`/${key}`, {
542
+ signal: a.signal,
543
+ subscribe: true,
544
+ headers: {
545
+ 'merge-type': 'dt',
546
+ 'X-Accept-Encoding': 'updates(dt)'
547
+ }
548
+ })
549
+
550
+ var doc = new Doc('yo')
551
+ return await new Promise(done => {
552
+ r2.subscribe(u => {
553
+ doc.mergeBytes(u.body)
554
+ done(doc.get())
555
+ doc.free()
556
+ a.abort()
557
+ })
558
+ })
559
+ },
560
+ 'xy'
561
+ )
562
+
563
+ runTest(
564
+ "test accept-encoding updates(dt), getting non-encoded update",
565
+ async () => {
566
+ await dt_p
567
+ let key = 'test-' + Math.random().toString(36).slice(2)
568
+
569
+ let r = await braid_fetch(`/${key}`, {
570
+ method: 'PUT',
571
+ version: ['hi-1'],
572
+ parents: [],
573
+ body: 'xy'
574
+ })
575
+ if (!r.ok) throw 'got: ' + r.statusCode
576
+
577
+ var a = new AbortController()
578
+ let r2 = await braid_fetch(`/${key}`, {
579
+ signal: a.signal,
580
+ subscribe: true,
581
+ headers: {
582
+ 'merge-type': 'dt',
583
+ 'X-Accept-Encoding': 'updates(dt)'
584
+ }
585
+ })
586
+
587
+ setTimeout(async () => {
588
+ await braid_fetch(`/${key}`, {
589
+ method: 'PUT',
590
+ version: ['yo-0'],
591
+ parents: ['hi-1'],
592
+ patches: [{unit: 'text', range: '[2:2]', content: 'z'}]
593
+ })
594
+ }, 200)
595
+
596
+ var results = []
597
+
598
+ var doc = new Doc('yo')
599
+ return await new Promise(done => {
600
+ r2.subscribe(u => {
601
+ if (!u.status) {
602
+ doc.mergeBytes(u.body)
603
+ results.push(doc.get())
604
+ doc.free()
605
+ } else {
606
+ results.push(u.patches[0].content_text)
607
+ done(results.join(''))
608
+ a.abort()
609
+ }
610
+ })
611
+ })
612
+ },
613
+ 'xyz'
614
+ )
615
+
459
616
  runTest(
460
617
  "test Version we get from PUTing",
461
618
  async () => {
@@ -867,4 +1024,25 @@ runTest(
867
1024
  '"yo-1", "hi-5", "hi-8"'
868
1025
  )
869
1026
 
1027
+ runTest(
1028
+ "test that subscribe returns current-version header",
1029
+ async () => {
1030
+ var key = 'test-' + Math.random().toString(36).slice(2)
1031
+
1032
+ var r = await braid_fetch(`/${key}`, {
1033
+ method: 'PUT',
1034
+ version: ['hi-11'],
1035
+ parents: [],
1036
+ body: 'xyz'
1037
+ })
1038
+ if (!r.ok) throw 'got: ' + r.statusCode
1039
+
1040
+ var r = await braid_fetch(`/${key}`, {
1041
+ subscribe: true
1042
+ })
1043
+ return r.headers.get('current-version')
1044
+ },
1045
+ '"hi-11"'
1046
+ )
1047
+
870
1048
  </script>