braid-blob 0.0.39 → 0.0.41

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 (4) hide show
  1. package/AI-README.md +13 -32
  2. package/index.js +325 -320
  3. package/package.json +1 -1
  4. package/test/tests.js +199 -78
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "braid-blob",
3
- "version": "0.0.39",
3
+ "version": "0.0.41",
4
4
  "description": "Library for collaborative blobs over http using braid.",
5
5
  "author": "Braid Working Group",
6
6
  "repository": "braid-org/braid-blob",
package/test/tests.js CHANGED
@@ -378,7 +378,7 @@ runTest(
378
378
 
379
379
  return r.status
380
380
  },
381
- '204'
381
+ '200'
382
382
  )
383
383
 
384
384
  runTest(
@@ -431,45 +431,35 @@ runTest(
431
431
  )
432
432
 
433
433
  runTest(
434
- "test braid_blob.delete() cleans up subscriptions",
434
+ "test that aborting cleans up subscription",
435
435
  async () => {
436
436
  var r1 = await braid_fetch(`/eval`, {
437
437
  method: 'POST',
438
438
  body: `void (async () => {
439
- var test_id = 'test-db-' + Math.random().toString(36).slice(2)
440
- var db_folder = __dirname + '/' + test_id + '-db'
441
- var meta_folder = __dirname + '/' + test_id + '-meta'
439
+ var test_id = '/test-' + Math.random().toString(36).slice(2)
442
440
 
443
- var bb = braid_blob.create_braid_blob()
444
- bb.db_folder = db_folder
445
- bb.meta_folder = meta_folder
441
+ // Put a file
442
+ await braid_blob.put(test_id, 'hello')
446
443
 
447
- try {
448
- // Put a file
449
- await bb.put('/test-file', Buffer.from('hello'))
450
-
451
- // Subscribe to it
452
- var got_update = false
453
- await bb.get('/test-file', {
454
- subscribe: (update) => { got_update = true }
455
- })
444
+ // Subscribe to it
445
+ var got_update = false
446
+ var ac = new AbortController()
447
+ await braid_blob.get(test_id, {
448
+ signal: ac.signal,
449
+ subscribe: (update) => { got_update = true }
450
+ })
456
451
 
457
- // Verify subscription exists
458
- var has_sub_before = !!bb.key_to_subs['/test-file']
452
+ // Verify subscription exists
453
+ var has_sub_before = !!braid_blob.key_to_subs[test_id]
459
454
 
460
- // Delete it
461
- await bb.delete('/test-file')
455
+ await new Promise(done => setTimeout(done, 30))
456
+ ac.abort()
457
+ await new Promise(done => setTimeout(done, 30))
462
458
 
463
- // Verify subscription is cleaned up
464
- var has_sub_after = !!bb.key_to_subs['/test-file']
459
+ // Verify subscription is cleaned up
460
+ var has_sub_after = !!braid_blob.key_to_subs[test_id]
465
461
 
466
- res.end('' + (has_sub_before && !has_sub_after))
467
- } catch (e) {
468
- res.end('error: ' + e.message)
469
- } finally {
470
- await require('fs').promises.rm(db_folder, { recursive: true, force: true })
471
- await require('fs').promises.rm(meta_folder, { recursive: true, force: true })
472
- }
462
+ res.end('' + (has_sub_before && !has_sub_after))
473
463
  })()`
474
464
  })
475
465
  return await r1.text()
@@ -640,19 +630,6 @@ runTest(
640
630
  'false'
641
631
  )
642
632
 
643
- runTest(
644
- "test that subscribe sends 404 if there is no file.",
645
- async () => {
646
- var key = 'test-' + Math.random().toString(36).slice(2)
647
-
648
- var r = await braid_fetch(`/${key}`, {
649
- subscribe: true,
650
- })
651
- return r.status
652
- },
653
- '404'
654
- )
655
-
656
633
  runTest(
657
634
  "test that we get 404 when file doesn't exist, on GET without subscribe.",
658
635
  async () => {
@@ -1072,8 +1049,7 @@ runTest(
1072
1049
  method: 'POST',
1073
1050
  body: `void (async () => {
1074
1051
  try {
1075
- var braid_blob = require(\`\${__dirname}/../index.js\`)
1076
- var remote_url = new URL('http://localhost:' + req.socket.localPort + '${remote_key}')
1052
+ var remote_url = new URL('http://localhost:' + port + '${remote_key}')
1077
1053
 
1078
1054
  // Start sync with URL as first argument (should swap internally)
1079
1055
  braid_blob.sync(remote_url, '${local_key}')
@@ -1165,10 +1141,8 @@ runTest(
1165
1141
  method: 'POST',
1166
1142
  body: `void (async () => {
1167
1143
  try {
1168
- var braid_blob = require(\`\${__dirname}/../index.js\`)
1169
-
1170
1144
  // Put locally with SAME version - so when sync connects, no updates need to flow
1171
- await braid_blob.put('${local_key}', Buffer.from('same content'), { version: ['same-version-123'] })
1145
+ await braid_blob.put('${local_key}', 'same content', { version: ['same-version-123'] })
1172
1146
 
1173
1147
  // Wrap db.read to count calls for our specific key
1174
1148
  var read_count = 0
@@ -1178,7 +1152,7 @@ runTest(
1178
1152
  return original_read.call(this, key)
1179
1153
  }
1180
1154
 
1181
- var remote_url = new URL('http://localhost:' + req.socket.localPort + '/${remote_key}')
1155
+ var remote_url = new URL('http://localhost:' + port + '/${remote_key}')
1182
1156
 
1183
1157
  // Create an AbortController to stop the sync
1184
1158
  var ac = new AbortController()
@@ -1305,7 +1279,6 @@ runTest(
1305
1279
  // Try to subscribe with parents 200 (newer than what server has)
1306
1280
  // This triggers the "unknown version" error which gets caught and returns 309
1307
1281
  var r = await braid_fetch(`/${key}`, {
1308
- subscribe: true,
1309
1282
  parents: ['200']
1310
1283
  })
1311
1284
 
@@ -1537,38 +1510,22 @@ runTest(
1537
1510
  var r1 = await braid_fetch(`/eval`, {
1538
1511
  method: 'POST',
1539
1512
  body: `void (async () => {
1540
- var fs = require('fs').promises
1541
- var test_id = 'test-abort-get-' + Math.random().toString(36).slice(2)
1542
- var db_folder = __dirname + '/' + test_id + '-db'
1543
- var meta_folder = __dirname + '/' + test_id + '-meta'
1513
+ var test_id = '/test-abort-get-' + Math.random().toString(36).slice(2)
1544
1514
 
1545
- try {
1546
- var bb = braid_blob.create_braid_blob()
1547
- bb.db_folder = db_folder
1548
- bb.meta_folder = meta_folder
1549
-
1550
- // Put a file first
1551
- await bb.put('/test-file', Buffer.from('hello'), { version: ['1'] })
1515
+ // Put a file first
1516
+ await braid_blob.put(test_id, 'hello', { version: ['1'] })
1552
1517
 
1553
- // Create an already-aborted signal
1554
- var ac = new AbortController()
1555
- ac.abort()
1518
+ // Create an already-aborted signal
1519
+ var ac = new AbortController()
1520
+ ac.abort()
1556
1521
 
1557
- // Try to get with aborted signal (after header_cb)
1558
- var header_called = false
1559
- var result = await bb.get('/test-file', {
1560
- signal: ac.signal,
1561
- header_cb: () => { header_called = true }
1562
- })
1522
+ // Try to get with aborted signal (after header_cb)
1523
+ var result = await braid_blob.get(test_id, {
1524
+ signal: ac.signal,
1525
+ })
1563
1526
 
1564
- // Result should be undefined since operation was aborted after header_cb
1565
- res.end(header_called && result === undefined ? 'aborted' : 'not aborted: header=' + header_called + ' result=' + JSON.stringify(result))
1566
- } catch (e) {
1567
- res.end('error: ' + e.message)
1568
- } finally {
1569
- await fs.rm(db_folder, { recursive: true, force: true })
1570
- await fs.rm(meta_folder, { recursive: true, force: true })
1571
- }
1527
+ // Result should be undefined since operation was aborted already
1528
+ res.end(result === undefined ? 'aborted' : 'not aborted')
1572
1529
  })()`
1573
1530
  })
1574
1531
  return await r1.text()
@@ -1678,6 +1635,170 @@ runTest(
1678
1635
  'stopped'
1679
1636
  )
1680
1637
 
1638
+ runTest(
1639
+ "test options.db in put writes to custom db",
1640
+ async () => {
1641
+ var r1 = await braid_fetch(`/eval`, {
1642
+ method: 'POST',
1643
+ body: `void (async () => {
1644
+ var test_key = '/test-custom-db-put-' + Math.random().toString(36).slice(2)
1645
+
1646
+ // Create a simple in-memory db
1647
+ var custom_storage = {}
1648
+ var custom_db = {
1649
+ read: async (key) => custom_storage[key] || null,
1650
+ write: async (key, data) => { custom_storage[key] = data },
1651
+ delete: async (key) => { delete custom_storage[key] }
1652
+ }
1653
+
1654
+ // Put using the custom db
1655
+ await braid_blob.put(test_key, Buffer.from('custom db content'), {
1656
+ version: ['100'],
1657
+ db: custom_db
1658
+ })
1659
+
1660
+ // Verify content is in custom db
1661
+ var custom_content = await custom_db.read(test_key)
1662
+ var custom_ok = custom_content && custom_content.toString() === 'custom db content'
1663
+
1664
+ // Verify content is NOT in the default db
1665
+ var default_content = await braid_blob.db.read(test_key)
1666
+ var default_empty = default_content === null
1667
+
1668
+ res.end(custom_ok && default_empty ? 'true' :
1669
+ 'custom_ok=' + custom_ok + ', default_empty=' + default_empty)
1670
+ })()`
1671
+ })
1672
+ return await r1.text()
1673
+ },
1674
+ 'true'
1675
+ )
1676
+
1677
+ runTest(
1678
+ "test options.db in get reads from custom db",
1679
+ async () => {
1680
+ var r1 = await braid_fetch(`/eval`, {
1681
+ method: 'POST',
1682
+ body: `void (async () => {
1683
+ var test_key = '/test-custom-db-get-' + Math.random().toString(36).slice(2)
1684
+
1685
+ // Create a simple in-memory db with some content
1686
+ var custom_storage = {}
1687
+ custom_storage[test_key] = Buffer.from('from custom db')
1688
+ var custom_db = {
1689
+ read: async (key) => custom_storage[key] || null,
1690
+ write: async (key, data) => { custom_storage[key] = data },
1691
+ delete: async (key) => { delete custom_storage[key] }
1692
+ }
1693
+
1694
+ // Put with skip_write to just create meta
1695
+ await braid_blob.put(test_key, Buffer.from('ignored'), {
1696
+ version: ['200'],
1697
+ skip_write: true
1698
+ })
1699
+
1700
+ // Get using the custom db - should read from custom db
1701
+ var result = await braid_blob.get(test_key, { db: custom_db })
1702
+
1703
+ res.end(result && result.body.toString() === 'from custom db' ? 'true' :
1704
+ 'got: ' + (result ? result.body.toString() : 'null'))
1705
+ })()`
1706
+ })
1707
+ return await r1.text()
1708
+ },
1709
+ 'true'
1710
+ )
1711
+
1712
+ runTest(
1713
+ "test options.db in delete deletes from custom db",
1714
+ async () => {
1715
+ var r1 = await braid_fetch(`/eval`, {
1716
+ method: 'POST',
1717
+ body: `void (async () => {
1718
+ var test_key = '/test-custom-db-delete-' + Math.random().toString(36).slice(2)
1719
+
1720
+ // Create a simple in-memory db
1721
+ var custom_storage = {}
1722
+ custom_storage[test_key] = Buffer.from('custom content')
1723
+ var custom_db = {
1724
+ read: async (key) => custom_storage[key] || null,
1725
+ write: async (key, data) => { custom_storage[key] = data },
1726
+ delete: async (key) => { delete custom_storage[key] }
1727
+ }
1728
+
1729
+ // Also put to default db
1730
+ await braid_blob.put(test_key, Buffer.from('default content'), {
1731
+ version: ['300']
1732
+ })
1733
+
1734
+ // Delete using custom db - should only delete from custom db
1735
+ await braid_blob.delete(test_key, { db: custom_db })
1736
+
1737
+ // Verify custom db content is gone
1738
+ var custom_content = await custom_db.read(test_key)
1739
+ var custom_deleted = custom_content === null
1740
+
1741
+ // Verify default db content still exists
1742
+ var default_content = await braid_blob.db.read(test_key)
1743
+ var default_exists = default_content && default_content.toString() === 'default content'
1744
+
1745
+ res.end(custom_deleted && default_exists ? 'true' :
1746
+ 'custom_deleted=' + custom_deleted + ', default_exists=' + default_exists)
1747
+ })()`
1748
+ })
1749
+ return await r1.text()
1750
+ },
1751
+ 'true'
1752
+ )
1753
+
1754
+ runTest(
1755
+ "test options.db in get subscribe uses custom db for initial update",
1756
+ async () => {
1757
+ var r1 = await braid_fetch(`/eval`, {
1758
+ method: 'POST',
1759
+ body: `void (async () => {
1760
+ var test_key = '/test-custom-db-sub-' + Math.random().toString(36).slice(2)
1761
+
1762
+ // Create a simple in-memory db with content
1763
+ var custom_storage = {}
1764
+ custom_storage[test_key] = Buffer.from('subscribe custom content')
1765
+ var custom_db = {
1766
+ read: async (key) => custom_storage[key] || null,
1767
+ write: async (key, data) => { custom_storage[key] = data },
1768
+ delete: async (key) => { delete custom_storage[key] }
1769
+ }
1770
+
1771
+ // Create meta with version using skip_write
1772
+ await braid_blob.put(test_key, Buffer.from('ignored'), {
1773
+ version: ['400'],
1774
+ skip_write: true
1775
+ })
1776
+
1777
+ // Subscribe using custom db - initial update should come from custom db
1778
+ var ac = new AbortController()
1779
+ var received_content = null
1780
+
1781
+ await braid_blob.get(test_key, {
1782
+ db: custom_db,
1783
+ signal: ac.signal,
1784
+ subscribe: (update) => {
1785
+ received_content = update.body.toString()
1786
+ }
1787
+ })
1788
+
1789
+ // Wait for update
1790
+ await new Promise(done => setTimeout(done, 50))
1791
+ ac.abort()
1792
+
1793
+ res.end(received_content === 'subscribe custom content' ? 'true' :
1794
+ 'got: ' + received_content)
1795
+ })()`
1796
+ })
1797
+ return await r1.text()
1798
+ },
1799
+ 'true'
1800
+ )
1801
+
1681
1802
  }
1682
1803
 
1683
1804
  // Export for Node.js (CommonJS)