braid-text 0.2.34 → 0.2.35

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 +77 -58
  2. package/package.json +1 -1
  3. package/test/test.html +196 -11
package/index.js CHANGED
@@ -72,6 +72,10 @@ braid_text.serve = async (req, res, options = {}) => {
72
72
  return my_end(200)
73
73
  }
74
74
 
75
+ var get_current_version = () => ascii_ify(
76
+ resource.doc.getRemoteVersion().map(x => x.join("-")).sort()
77
+ .map(x => JSON.stringify(x)).join(", "))
78
+
75
79
  if (req.method == "GET" || req.method == "HEAD") {
76
80
  if (!req.subscribe) {
77
81
  res.setHeader("Accept-Subscribe", "true")
@@ -88,20 +92,29 @@ braid_text.serve = async (req, res, options = {}) => {
88
92
 
89
93
  let x = null
90
94
  try {
91
- x = await braid_text.get(resource, { version: req.version, parents: req.parents })
95
+ x = await braid_text.get(resource, {
96
+ version: req.version,
97
+ parents: req.parents,
98
+ transfer_encoding: req.headers['accept-transfer-encoding']
99
+ })
92
100
  } catch (e) {
93
101
  return my_end(500, "The server failed to get something. The error generated was: " + e)
94
102
  }
95
103
 
96
- res.setHeader("Version", x.version.map((x) => JSON.stringify(x)).join(", "))
97
-
98
- const buffer = Buffer.from(x.body, "utf8")
99
- res.setHeader("Repr-Digest", `sha-256=:${require('crypto').createHash('sha256').update(buffer).digest('base64')}:`)
100
- res.setHeader("Content-Length", buffer.length)
101
-
102
- if (req.method === "HEAD") return my_end(200)
103
-
104
- return my_end(200, buffer)
104
+ if (req.headers['accept-transfer-encoding'] === 'dt') {
105
+ res.setHeader("Current-Version", get_current_version())
106
+ res.setHeader("Transfer-Encoding", 'dt')
107
+ res.setHeader("Content-Length", x.body.length)
108
+ return my_end(209, req.method === "HEAD" ? null : x.body, 'Multiresponse')
109
+ } else {
110
+ if (req.version || req.parents)
111
+ res.setHeader("Current-Version", get_current_version())
112
+ res.setHeader("Version", ascii_ify(x.version.map((x) => JSON.stringify(x)).join(", ")))
113
+ var buffer = Buffer.from(x.body, "utf8")
114
+ res.setHeader("Repr-Digest", `sha-256=:${require('crypto').createHash('sha256').update(buffer).digest('base64')}:`)
115
+ res.setHeader("Content-Length", buffer.length)
116
+ return my_end(200, req.method === "HEAD" ? null : buffer)
117
+ }
105
118
  } else {
106
119
  if (!res.hasHeader("editable")) res.setHeader("Editable", "true")
107
120
  res.setHeader("Merge-Type", merge_type)
@@ -112,7 +125,6 @@ braid_text.serve = async (req, res, options = {}) => {
112
125
  version: req.version,
113
126
  parents: req.parents,
114
127
  merge_type,
115
- transfer_encoding: req.headers['accept-transfer-encoding'],
116
128
  subscribe: x => res.sendVersion(x),
117
129
  write: (x) => res.write(x)
118
130
  }
@@ -171,7 +183,7 @@ braid_text.serve = async (req, res, options = {}) => {
171
183
 
172
184
  await braid_text.put(resource, { peer, version: req.version, parents: req.parents, patches, body, merge_type })
173
185
 
174
- res.setHeader("Version", resource.doc.getRemoteVersion().map((x) => x.join("-")).sort())
186
+ res.setHeader("Version", get_current_version())
175
187
 
176
188
  options.put_cb(options.key, resource.val)
177
189
  } catch (e) {
@@ -213,12 +225,38 @@ braid_text.get = async (key, options) => {
213
225
  let resource = (typeof key == 'string') ? await get_resource(key) : key
214
226
 
215
227
  if (!options.subscribe) {
216
- return options.version || options.parents ?
217
- {
228
+ var version = resource.doc.getRemoteVersion().map((x) => x.join("-")).sort()
229
+
230
+ if (options.transfer_encoding === 'dt') {
231
+ // optimization: if requesting current version
232
+ // pretend as if they didn't set a version,
233
+ // and let it be handled as the default
234
+ var op_v = options.version
235
+ if (op_v && v_eq(op_v, version)) op_v = null
236
+
237
+ var bytes = null
238
+ if (op_v || options.parents) {
239
+ if (op_v) {
240
+ var doc = dt_get(resource.doc, op_v)
241
+ bytes = doc.toBytes()
242
+ } else {
243
+ bytes = resource.doc.toBytes()
244
+ var doc = Doc.fromBytes(bytes)
245
+ }
246
+ if (options.parents) {
247
+ bytes = doc.getPatchSince(
248
+ dt_get_local_version(bytes, options.parents))
249
+ }
250
+ doc.free()
251
+ } else bytes = resource.doc.toBytes()
252
+ return { body: bytes }
253
+ }
254
+
255
+ return options.version || options.parents ? {
218
256
  version: options.version || options.parents,
219
257
  body: dt_get_string(resource.doc, options.version || options.parents)
220
258
  } : {
221
- version: resource.doc.getRemoteVersion().map((x) => x.join("-")).sort(),
259
+ version,
222
260
  body: resource.doc.get()
223
261
  }
224
262
  } else {
@@ -251,52 +289,33 @@ braid_text.get = async (key, options) => {
251
289
  resource.doc = defrag_dt(resource.doc)
252
290
  }
253
291
 
254
- if (options.transfer_encoding === 'dt') {
255
- var o = {
256
- 'Transfer-Encoding': 'dt',
257
- 'Current-Version': resource.doc.getRemoteVersion().
258
- map(x => x.join("-")).
259
- map(JSON.stringify).map(ascii_ify).join(", "),
260
- }
261
- var bytes = resource.doc.toBytes()
262
- if (!options.parents && !options.version) o.body = bytes
263
- else {
264
- var doc = Doc.fromBytes(bytes)
265
- o.body = doc.getPatchSince(
266
- dt_get_local_version(bytes,
267
- options.parents || options.version))
268
- doc.free()
269
- }
270
- options.subscribe(o)
271
- } else {
272
- var updates = null
273
- if (!options.parents && !options.version) {
274
- options.subscribe({
275
- version: [],
276
- parents: [],
277
- body: "",
278
- })
279
-
280
- updates = dt_get_patches(resource.doc)
281
- } else {
282
- // Then start the subscription from the parents in options
283
- updates = dt_get_patches(resource.doc, options.parents || options.version)
284
- }
292
+ var updates = null
293
+ if (!options.parents && !options.version) {
294
+ options.subscribe({
295
+ version: [],
296
+ parents: [],
297
+ body: "",
298
+ })
285
299
 
286
- for (let u of updates)
287
- options.subscribe({
288
- version: [u.version],
289
- parents: u.parents,
290
- patches: [{ unit: u.unit, range: u.range, content: u.content }],
291
- })
292
-
293
- // Output at least *some* data, or else chrome gets confused and
294
- // thinks the connection failed. This isn't strictly necessary,
295
- // but it makes fewer scary errors get printed out in the JS
296
- // console.
297
- if (updates.length === 0) options.write?.("\r\n")
300
+ updates = dt_get_patches(resource.doc)
301
+ } else {
302
+ // Then start the subscription from the parents in options
303
+ updates = dt_get_patches(resource.doc, options.parents || options.version)
298
304
  }
299
305
 
306
+ for (let u of updates)
307
+ options.subscribe({
308
+ version: [u.version],
309
+ parents: u.parents,
310
+ patches: [{ unit: u.unit, range: u.range, content: u.content }],
311
+ })
312
+
313
+ // Output at least *some* data, or else chrome gets confused and
314
+ // thinks the connection failed. This isn't strictly necessary,
315
+ // but it makes fewer scary errors get printed out in the JS
316
+ // console.
317
+ if (updates.length === 0) options.write?.("\r\n")
318
+
300
319
  resource.clients.add(options)
301
320
  }
302
321
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "braid-text",
3
- "version": "0.2.34",
3
+ "version": "0.2.35",
4
4
  "description": "Library for collaborative text over http using braid.",
5
5
  "author": "Braid Working Group",
6
6
  "repository": "braid-org/braid-text",
package/test/test.html CHANGED
@@ -69,7 +69,7 @@ async function runTest(testName, testFunction, expectedResult) {
69
69
  }
70
70
 
71
71
  runTest(
72
- "test transfer-encoding dt",
72
+ "test transfer-encoding dt (with parents)",
73
73
  async () => {
74
74
  await dt_p
75
75
  let key = 'test-' + Math.random().toString(36).slice(2)
@@ -85,25 +85,210 @@ runTest(
85
85
  if (!r.ok) throw 'got: ' + r.statusCode
86
86
 
87
87
  let r2 = await braid_fetch(`/${key}`, {
88
- version: ['hi-0'],
89
- subscribe: true,
88
+ parents: ['hi-0'],
90
89
  headers: {
91
- 'Merge-Type': 'dt',
92
90
  'Accept-Transfer-Encoding': 'dt'
93
91
  }
94
92
  })
95
- return await new Promise(async (done, fail) => {
96
- r2.subscribe(async update => {
97
- doc.mergeBytes(update.body)
98
- done(update.extra_headers['current-version'] + ' ' +
99
- update.extra_headers['transfer-encoding'] + ' ' +
100
- doc.get())
101
- }, fail)
93
+
94
+ doc.mergeBytes([...new Uint8Array(await r2.arrayBuffer())])
95
+ var text = doc.get()
96
+ doc.free()
97
+
98
+ return r2.headers.get('current-version') + ' ' + r2.headers.get('transfer-encoding') + ' ' + text + ' ' + r2.statusText
99
+ },
100
+ '"hi-1" dt xy Multiresponse'
101
+ )
102
+
103
+ runTest(
104
+ "test transfer-encoding dt",
105
+ async () => {
106
+ await dt_p
107
+ let key = 'test-' + Math.random().toString(36).slice(2)
108
+
109
+ let r = await braid_fetch(`/${key}`, {
110
+ method: 'PUT',
111
+ version: ['hi-1'],
112
+ parents: [],
113
+ body: 'xy'
114
+ })
115
+ if (!r.ok) throw 'got: ' + r.statusCode
116
+
117
+ let r2 = await braid_fetch(`/${key}`, {
118
+ headers: {
119
+ 'Accept-Transfer-Encoding': 'dt'
120
+ }
102
121
  })
122
+
123
+ var doc = new Doc('yo')
124
+ doc.mergeBytes([...new Uint8Array(await r2.arrayBuffer())])
125
+ var text = doc.get()
126
+ doc.free()
127
+
128
+ return r2.headers.get('current-version') + ' ' + r2.headers.get('transfer-encoding') + ' ' + text
103
129
  },
104
130
  '"hi-1" dt xy'
105
131
  )
106
132
 
133
+ runTest(
134
+ "test GETing old version explicitly with transfer-encoding dt",
135
+ async () => {
136
+ await dt_p
137
+ let key = 'test-' + Math.random().toString(36).slice(2)
138
+
139
+ let r = await braid_fetch(`/${key}`, {
140
+ method: 'PUT',
141
+ version: ['hi∑-1'],
142
+ parents: [],
143
+ body: 'xy'
144
+ })
145
+ if (!r.ok) throw 'got: ' + r.statusCode
146
+
147
+ let r2 = await braid_fetch(`/${key}`, {
148
+ version: ['hi∑-0'],
149
+ headers: {
150
+ 'Accept-Transfer-Encoding': 'dt'
151
+ }
152
+ })
153
+
154
+ var doc = new Doc('yo')
155
+ doc.mergeBytes([...new Uint8Array(await r2.arrayBuffer())])
156
+ var text = doc.get()
157
+ doc.free()
158
+
159
+ return r2.headers.get('current-version') + ' ' + text + ' ' + JSON.parse(r2.headers.get('current-version'))
160
+ },
161
+ '"hi\\u2211-1" x hi∑-1'
162
+ )
163
+
164
+ runTest(
165
+ "test GETing current version explicitly with transfer-encoding dt",
166
+ async () => {
167
+ await dt_p
168
+ let key = 'test-' + Math.random().toString(36).slice(2)
169
+
170
+ let r = await braid_fetch(`/${key}`, {
171
+ method: 'PUT',
172
+ version: ['hi∑-1'],
173
+ parents: [],
174
+ body: 'xy'
175
+ })
176
+ if (!r.ok) throw 'got: ' + r.statusCode
177
+
178
+ let r2 = await braid_fetch(`/${key}`, {
179
+ version: ['hi∑-1'],
180
+ headers: {
181
+ 'Accept-Transfer-Encoding': 'dt'
182
+ }
183
+ })
184
+
185
+ var doc = new Doc('yo')
186
+ doc.mergeBytes([...new Uint8Array(await r2.arrayBuffer())])
187
+ var text = doc.get()
188
+ doc.free()
189
+
190
+ return r2.headers.get('current-version') + ' ' + text + ' ' + JSON.parse(r2.headers.get('current-version'))
191
+ },
192
+ '"hi\\u2211-1" xy hi∑-1'
193
+ )
194
+
195
+ runTest(
196
+ "test for Current-Version when GETing old version",
197
+ async () => {
198
+ await dt_p
199
+ let key = 'test-' + Math.random().toString(36).slice(2)
200
+
201
+ let r = await braid_fetch(`/${key}`, {
202
+ method: 'PUT',
203
+ version: ['hi∑-1'],
204
+ parents: [],
205
+ body: 'xy'
206
+ })
207
+ if (!r.ok) throw 'got: ' + r.statusCode
208
+
209
+ let r2 = await braid_fetch(`/${key}`, {
210
+ version: ['hi∑-0']
211
+ })
212
+
213
+ var text = await r2.text()
214
+
215
+ return r2.headers.get('current-version') + ' ' + r2.headers.get('version') + ' ' + text + ' ' + JSON.parse(r2.headers.get('current-version'))
216
+ },
217
+ '"hi\\u2211-1" "hi\\u2211-0" x hi∑-1'
218
+ )
219
+
220
+ runTest(
221
+ "test HEAD for GET without subscribe",
222
+ async () => {
223
+ await dt_p
224
+ let key = 'test-' + Math.random().toString(36).slice(2)
225
+
226
+ let r = await braid_fetch(`/${key}`, {
227
+ method: 'PUT',
228
+ version: ['hi∑-1'],
229
+ parents: [],
230
+ body: 'xy'
231
+ })
232
+ if (!r.ok) throw 'got: ' + r.statusCode
233
+
234
+ let r2 = await braid_fetch(`/${key}`, {
235
+ method: 'HEAD'
236
+ })
237
+
238
+ var text = await r2.text()
239
+
240
+ return r2.headers.get('version') + ' ' + JSON.parse(r2.headers.get('version')) + ` text:[${text}]`
241
+ },
242
+ '"hi\\u2211-1" hi∑-1 text:[]'
243
+ )
244
+
245
+ runTest(
246
+ "test HEAD for GET without subscribe (with transfer-encoding)",
247
+ async () => {
248
+ await dt_p
249
+ let key = 'test-' + Math.random().toString(36).slice(2)
250
+
251
+ let r = await braid_fetch(`/${key}`, {
252
+ method: 'PUT',
253
+ version: ['hi∑-1'],
254
+ parents: [],
255
+ body: 'xy'
256
+ })
257
+ if (!r.ok) throw 'got: ' + r.statusCode
258
+
259
+ let r2 = await braid_fetch(`/${key}`, {
260
+ method: 'HEAD',
261
+ headers: {
262
+ 'accept-transfer-encoding': 'dt'
263
+ }
264
+ })
265
+
266
+ var buf = await r2.arrayBuffer()
267
+
268
+ return r2.headers.get('current-version') + ' ' + JSON.parse(r2.headers.get('current-version')) + ` buf.byteLength:${buf.byteLength}`
269
+ },
270
+ '"hi\\u2211-1" hi∑-1 buf.byteLength:0'
271
+ )
272
+
273
+ runTest(
274
+ "test Version we get from PUTing",
275
+ async () => {
276
+ await dt_p
277
+ let key = 'test-' + Math.random().toString(36).slice(2)
278
+
279
+ let r = await braid_fetch(`/${key}`, {
280
+ method: 'PUT',
281
+ version: ['hi∑-1'],
282
+ parents: [],
283
+ body: 'xy'
284
+ })
285
+ if (!r.ok) throw 'got: ' + r.statusCode
286
+
287
+ return r.headers.get('version')
288
+ },
289
+ '"hi\\u2211-1"'
290
+ )
291
+
107
292
  runTest(
108
293
  "test error code when missing parents",
109
294
  async () => {