braid-text 0.0.19 → 0.0.21

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 (2) hide show
  1. package/index.js +77 -23
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -4,7 +4,8 @@ let braidify = require("braid-http").http_server
4
4
  let fs = require("fs")
5
5
 
6
6
  let braid_text = {
7
- db_folder: './braid-text-db'
7
+ db_folder: './braid-text-db',
8
+ cache: {}
8
9
  }
9
10
 
10
11
  let waiting_puts = 0
@@ -156,7 +157,7 @@ braid_text.serve = async (req, res, options = {}) => {
156
157
 
157
158
  await braid_text.put(resource, { peer, version: req.version, parents: req.parents, patches, body, merge_type })
158
159
 
159
- options.put_cb(options.key, resource.doc.get())
160
+ options.put_cb(options.key, resource.val)
160
161
  } catch (e) {
161
162
  console.log(`EEE= ${e}:${e.stack}`)
162
163
  // we couldn't apply the version, possibly because we're missing its parents,
@@ -195,8 +196,8 @@ braid_text.serve = async (req, res, options = {}) => {
195
196
  braid_text.get = async (key, options) => {
196
197
  if (!options) {
197
198
  // if it doesn't exist already, don't create it in this case
198
- if (!get_resource.cache?.[key]) return
199
- return (await get_resource(key)).doc.get()
199
+ if (!braid_text.cache[key]) return
200
+ return (await get_resource(key)).val
200
201
  }
201
202
 
202
203
  if (options.version) validate_version_array(options.version)
@@ -254,14 +255,7 @@ braid_text.get = async (key, options) => {
254
255
  updates = OpLog_get_patches(resource.doc.toBytes(), resource.doc.getOpsSince([]))
255
256
  } else {
256
257
  // Then start the subscription from the parents in options
257
- let parents = Object.fromEntries((options.parents ? options.parents : options.version).map((x) => [x, true]))
258
-
259
- let local_version = []
260
- let [agents, versions, parentss] = parseDT([...resource.doc.toBytes()])
261
- for (let i = 0; i < versions.length; i++) {
262
- if (parents[versions[i].join("-")]) local_version.push(i)
263
- }
264
- local_version = new Uint32Array(local_version)
258
+ let local_version = OpLog_remote_to_local(resource.doc, options.parents || options.version)
265
259
 
266
260
  updates = OpLog_get_patches(resource.doc.getPatchSince(local_version), resource.doc.getOpsSince(local_version))
267
261
  }
@@ -293,7 +287,13 @@ braid_text.put = async (key, options) => {
293
287
  let { version, patches, body, peer } = options
294
288
 
295
289
  if (version) validate_version_array(version)
296
- if (options.parents) validate_version_array(options.parents)
290
+
291
+ // translate a single parent of "root" to the empty array (same meaning)
292
+ let options_parents = options.parents
293
+ if (options_parents?.length === 1 && options_parents[0] === 'root')
294
+ options_parents = []
295
+
296
+ if (options_parents) validate_version_array(options_parents)
297
297
  if (body != null && patches) throw new Error(`cannot have a body and patches`)
298
298
  if (body != null && (typeof body !== 'string')) throw new Error(`body must be a string`)
299
299
  if (patches) validate_patches(patches)
@@ -301,7 +301,7 @@ braid_text.put = async (key, options) => {
301
301
  let resource = (typeof key == 'string') ? await get_resource(key) : key
302
302
 
303
303
  let parents = resource.doc.getRemoteVersion().map((x) => x.join("-"))
304
- let og_parents = options.parents || parents
304
+ let og_parents = options_parents || parents
305
305
 
306
306
  let max_pos = count_code_points(v_eq(parents, og_parents) ?
307
307
  resource.doc.get() :
@@ -338,7 +338,63 @@ braid_text.put = async (key, options) => {
338
338
  let v = decode_version(og_v)
339
339
 
340
340
  // validate version: make sure we haven't seen it already
341
- if (v[1] <= (resource.actor_seqs[v[0]] ?? -1)) throw new Error(`invalid version: already processed`)
341
+ if (v[1] <= (resource.actor_seqs[v[0]] ?? -1)) {
342
+
343
+ // if we have seen it already, make sure it's the same as before
344
+ let local_version = OpLog_remote_to_local(resource.doc, og_parents)
345
+ let updates = OpLog_get_patches(resource.doc.getPatchSince(local_version), resource.doc.getOpsSince(local_version))
346
+
347
+ let seen = {}
348
+ for (let u of updates) {
349
+ if (u.start != u.end) {
350
+ // delete
351
+ let v = decode_version(u.version)
352
+ for (let i = 0; i < u.end - u.start; i++) {
353
+ let ps = (i < u.end - u.start - 1) ? [`${v[0]}-${v[1] - i - 1}`] : u.parents
354
+ seen[JSON.stringify([v[0], v[1] - i, ps, u.start + i])] = true
355
+ }
356
+ } else {
357
+ // insert
358
+ let v = decode_version(u.version)
359
+ let content = [...u.content]
360
+ for (let i = 0; i < content.length; i++) {
361
+ let ps = (i > 0) ? [`${v[0]}-${v[1] - content.length + i}`] : u.parents
362
+ seen[JSON.stringify([v[0], v[1] + 1 - content.length + i, ps, u.start + i, content[i]])] = true
363
+ }
364
+ }
365
+ }
366
+
367
+ v = `${v[0]}-${v[1] + 1 - change_count}`
368
+ let ps = og_parents
369
+ let offset = 0
370
+ for (let p of patches) {
371
+ // delete
372
+ for (let i = p.range[0]; i < p.range[1]; i++) {
373
+ let vv = decode_version(v)
374
+
375
+ if (!seen[JSON.stringify([vv[0], vv[1], ps, p.range[1] - 1 + offset])]) throw new Error('invalid update: different from previous update with same version')
376
+
377
+ offset--
378
+ ps = [v]
379
+ v = vv
380
+ v = `${v[0]}-${v[1] + 1}`
381
+ }
382
+ // insert
383
+ for (let i = 0; i < p.content?.length ?? 0; i++) {
384
+ let c = p.content[i]
385
+
386
+ if (!seen[JSON.stringify([vv[0], vv[1], ps, p.range[1] + offset, c])]) throw new Error('invalid update: different from previous update with same version')
387
+
388
+ offset++
389
+ ps = [v]
390
+ v = decode_version(v)
391
+ v = `${v[0]}-${v[1] + 1}`
392
+ }
393
+ }
394
+
395
+ // we already have this version, so nothing left to do
396
+ return
397
+ }
342
398
  resource.actor_seqs[v[0]] = v[1]
343
399
 
344
400
  v = `${v[0]}-${v[1] + 1 - change_count}`
@@ -374,12 +430,6 @@ braid_text.put = async (key, options) => {
374
430
 
375
431
  resource.need_defrag = true
376
432
 
377
- let v_after = resource.doc.getLocalVersion()
378
- if (JSON.stringify(v_before) === JSON.stringify(v_after)) {
379
- console.log(`we got a version we already had: ${v_before}`)
380
- return
381
- }
382
-
383
433
  if (options.merge_type != "dt") {
384
434
  patches = get_xf_patches(resource.doc, v_before)
385
435
  console.log(JSON.stringify({ patches }))
@@ -479,6 +529,8 @@ braid_text.put = async (key, options) => {
479
529
  }
480
530
 
481
531
  await resource.db_delta(resource.doc.getPatchSince(v_before))
532
+
533
+ resource.val = resource.doc.get()
482
534
  }
483
535
 
484
536
  braid_text.list = async () => {
@@ -488,12 +540,12 @@ braid_text.list = async () => {
488
540
  var pages = new Set()
489
541
  for (let x of await require('fs').promises.readdir(braid_text.db_folder)) pages.add(decode_filename(x.replace(/\.\w+$/, '')))
490
542
  return [...pages.keys()]
491
- } else return Object.keys(get_resource.cache)
543
+ } else return Object.keys(braid_text.cache)
492
544
  } catch (e) { return [] }
493
545
  }
494
546
 
495
547
  async function get_resource(key) {
496
- let cache = get_resource.cache || (get_resource.cache = {})
548
+ let cache = braid_text.cache
497
549
  if (!cache[key]) cache[key] = new Promise(async done => {
498
550
  let resource = {}
499
551
  resource.clients = new Set()
@@ -524,6 +576,8 @@ async function get_resource(key) {
524
576
  delete cache[key]
525
577
  }
526
578
 
579
+ resource.val = resource.doc.get()
580
+
527
581
  done(resource)
528
582
  })
529
583
  return await cache[key]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "braid-text",
3
- "version": "0.0.19",
3
+ "version": "0.0.21",
4
4
  "description": "Library for collaborative text over http using braid.",
5
5
  "author": "Braid Working Group",
6
6
  "repository": "braid-org/braidjs",