braid-text 0.0.4 → 0.0.6

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 CHANGED
@@ -105,7 +105,11 @@ server.on("request", (req, res) => {
105
105
  },
106
106
  generate_local_diff_update: (prev_state) => {
107
107
 
108
- // Compute diff between prev_state ^ and the current textarea string...
108
+ // Compute diff between prev_state ^ and the current textarea string,
109
+ // which might look like [{
110
+ // range: [5:5],
111
+ // content: " World"
112
+ // }] to insert something after a prev_state of "Hello"
109
113
 
110
114
  // Then return the new state (as a string) and the diff (as `patches`)
111
115
  return {new_state, patches}
package/index.js CHANGED
@@ -167,7 +167,13 @@ braid_text.serve = async (req, res, options = {}) => {
167
167
  }
168
168
 
169
169
  braid_text.get = async (key, options) => {
170
- if (!options) return get_resource.cache?.[key]?.doc.get()
170
+ if (!options) {
171
+ let x = get_resource.cache?.[key]?.doc.get()
172
+ if (x !== undefined) return x
173
+ // if it doesn't exist on disk, don't create it in this case
174
+ if (!(await get_files_for_key(key)).length) return
175
+ return (await get_resource(key)).doc.get()
176
+ }
171
177
 
172
178
  let resource = (typeof key == 'string') ? await get_resource(key) : key
173
179
 
@@ -483,6 +489,15 @@ braid_text.put = async (key, options) => {
483
489
  await resource.db_delta(resource.doc.getPatchSince(v_before))
484
490
  }
485
491
 
492
+ braid_text.list = async () => {
493
+ var pages = new Set()
494
+ for (let x of await require('fs').promises.readdir(braid_text.db_folder)) {
495
+ let m = x.match(/^(.*)\.\d+$/)
496
+ if (m) pages.add(decode_filename(m[1]))
497
+ }
498
+ return [...pages.keys()]
499
+ }
500
+
486
501
  async function get_resource(key) {
487
502
  let cache = get_resource.cache || (get_resource.cache = {})
488
503
  if (cache[key]) return cache[key]
@@ -494,12 +509,9 @@ async function get_resource(key) {
494
509
  resource.doc = new Doc("server")
495
510
 
496
511
  let { change, delete_me } = braid_text.db_folder
497
- ? await file_sync(
498
- braid_text.db_folder,
499
- encodeURIComponent(key),
512
+ ? await file_sync(key,
500
513
  (bytes) => resource.doc.mergeBytes(bytes),
501
- () => resource.doc.toBytes()
502
- )
514
+ () => resource.doc.toBytes())
503
515
  : { change: () => { }, delete_me: () => { } }
504
516
 
505
517
  resource.db_delta = change
@@ -515,32 +527,30 @@ async function get_resource(key) {
515
527
  return (cache[key] = resource)
516
528
  }
517
529
 
518
- async function file_sync(db_folder, filename_base, process_delta, get_init) {
530
+ async function get_files_for_key(key) {
531
+ try {
532
+ let re = new RegExp("^" + encode_filename(key).replace(/[^a-zA-Z0-9]/g, "\\$&") + "\\.\\d+$")
533
+ return (await fs.promises.readdir(braid_text.db_folder))
534
+ .filter((a) => re.test(a))
535
+ .map((a) => `${braid_text.db_folder}/${a}`)
536
+ } catch (e) { return [] }
537
+ }
538
+
539
+ async function file_sync(key, process_delta, get_init) {
519
540
  let currentNumber = 0
520
541
  let currentSize = 0
521
542
  let threshold = 0
522
543
 
523
544
  // Ensure the existence of db_folder
524
545
  try {
525
- await fs.promises.access(db_folder);
546
+ await fs.promises.access(braid_text.db_folder);
526
547
  } catch (err) {
527
- if (err.code === 'ENOENT') {
528
- await fs.promises.mkdir(db_folder, { recursive: true });
529
- } else {
530
- throw err;
531
- }
548
+ await fs.promises.mkdir(braid_text.db_folder, { recursive: true });
532
549
  }
533
550
 
534
551
  // Read existing files and sort by numbers.
535
- async function get_sorted_files() {
536
- let re = new RegExp("^" + filename_base.replace(/[^a-zA-Z0-9]/g, "\\$&") + "\\.\\d+$")
537
- return (await fs.promises.readdir(db_folder))
538
- .filter((a) => re.test(a))
539
- .sort((a, b) => parseInt(a.match(/\d+$/)[0]) - parseInt(b.match(/\d+$/)[0]))
540
- .map((a) => `${db_folder}/${a}`)
541
- }
542
-
543
- const files = await get_sorted_files()
552
+ const files = (await get_files_for_key(key))
553
+ .sort((a, b) => parseInt(a.match(/\d+$/)[0]) - parseInt(b.match(/\d+$/)[0]))
544
554
 
545
555
  // Try to process files starting from the highest number.
546
556
  let done = false
@@ -581,7 +591,7 @@ async function file_sync(db_folder, filename_base, process_delta, get_init) {
581
591
  return {
582
592
  change: async (bytes) => {
583
593
  currentSize += bytes.length + 4 // we account for the extra 4 bytes for uint32
584
- const filename = `${db_folder}/${filename_base}.${currentNumber}`
594
+ const filename = `${braid_text.db_folder}/${encode_filename(key)}.${currentNumber}`
585
595
  if (currentSize < threshold) {
586
596
  console.log(`appending to db..`)
587
597
 
@@ -600,7 +610,7 @@ async function file_sync(db_folder, filename_base, process_delta, get_init) {
600
610
  const buffer = Buffer.allocUnsafe(4)
601
611
  buffer.writeUInt32LE(init.length, 0)
602
612
 
603
- const newFilename = `${db_folder}/${filename_base}.${currentNumber}`
613
+ const newFilename = `${braid_text.db_folder}/${encode_filename(key)}.${currentNumber}`
604
614
  await fs.promises.writeFile(newFilename, buffer)
605
615
  await fs.promises.appendFile(newFilename, init)
606
616
 
@@ -619,7 +629,7 @@ async function file_sync(db_folder, filename_base, process_delta, get_init) {
619
629
  delete_me: async () => {
620
630
  await Promise.all(
621
631
  (
622
- await get_sorted_files()
632
+ await get_files_for_key(key)
623
633
  ).map((file) => {
624
634
  return new Promise((resolve, reject) => {
625
635
  fs.unlink(file, (err) => {
@@ -1260,4 +1270,30 @@ function codePoints_to_index(str, codePoints) {
1260
1270
  return i
1261
1271
  }
1262
1272
 
1273
+ function encode_filename(filename) {
1274
+ // Replace all '!' with '%21'
1275
+ let encoded = filename.replace(/!/g, '%21');
1276
+
1277
+ // Encode the filename using encodeURIComponent()
1278
+ encoded = encodeURIComponent(encoded);
1279
+
1280
+ // Replace all '%2F' (for '/') with '!'
1281
+ encoded = encoded.replace(/%2F/g, '!');
1282
+
1283
+ return encoded;
1284
+ }
1285
+
1286
+ function decode_filename(encodedFilename) {
1287
+ // Replace all '!' with '%2F'
1288
+ let decoded = encodedFilename.replace(/!/g, '%2F');
1289
+
1290
+ // Decode the filename using decodeURIComponent()
1291
+ decoded = decodeURIComponent(decoded);
1292
+
1293
+ // Replace all '%21' with '!'
1294
+ decoded = decoded.replace(/%21/g, '!');
1295
+
1296
+ return decoded;
1297
+ }
1298
+
1263
1299
  module.exports = braid_text
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "braid-text",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "description": "Library for collaborative text over http using braid.",
5
5
  "author": "Braid Working Group",
6
6
  "repository": "braid-org/braidjs",
package/server-demo.js CHANGED
@@ -27,11 +27,7 @@ var server = require("http").createServer(async (req, res) => {
27
27
  // which displays all the currently used keys
28
28
  //
29
29
  // if (req.url === '/pages') {
30
- // var pages = new Set()
31
- // for (let x of await require('fs').promises.readdir(db_folder)) {
32
- // let m = x.match(/^(.*)\.\d+$/)
33
- // if (m) pages.add(decodeURIComponent(m[1]))
34
- // }
30
+ // var pages = await braid_text.list()
35
31
  // res.writeHead(200, {
36
32
  // "Content-Type": "application/json",
37
33
  // "Access-Control-Allow-Origin": "*",
@@ -39,7 +35,7 @@ var server = require("http").createServer(async (req, res) => {
39
35
  // "Access-Control-Allow-Headers": "*",
40
36
  // "Access-Control-Expose-Headers": "*"
41
37
  // })
42
- // res.end(JSON.stringify([...pages.keys()]))
38
+ // res.end(JSON.stringify(pages))
43
39
  // return
44
40
  // }
45
41