@fireproof/core 0.5.16 → 0.5.18

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/dist/src/sync.js CHANGED
@@ -147,7 +147,7 @@ export class Sync {
147
147
  destroy() {
148
148
  this.database.blocks.syncs.delete(this);
149
149
  this.status = 'destroyed';
150
- this.peer.destroy();
150
+ // this.peer.destroy() todo
151
151
  }
152
152
  async sendUpdate(blockstore) {
153
153
  if (!this.peer || !this.isReady)
package/dist/src/valet.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { CarReader } from '@ipld/car';
2
2
  import { CID } from 'multiformats/cid';
3
3
  import { sha256 } from 'multiformats/hashes/sha2';
4
+ import { parse } from 'multiformats/link';
4
5
  import * as CBW from '@ipld/car/buffer-writer';
5
6
  import * as raw from 'multiformats/codecs/raw';
6
7
  import * as Block from 'multiformats/block';
@@ -8,15 +9,19 @@ import * as dagcbor from '@ipld/dag-cbor';
8
9
  import { openDB } from 'idb';
9
10
  import cargoQueue from 'async/cargoQueue.js';
10
11
  // @ts-ignore
11
- import { bf } from 'prolly-trees/utils';
12
+ // @ts-ignore
13
+ import { bf, simpleCompare as compare } from 'prolly-trees/utils';
12
14
  // @ts-ignore
13
15
  import { nocache as cache } from 'prolly-trees/cache';
16
+ // import { makeGetBlock } from './prolly.js'
14
17
  import { encrypt, decrypt } from './crypto.js';
15
18
  import { Buffer } from 'buffer';
16
19
  // @ts-ignore
17
20
  import * as codec from 'encrypted-block';
21
+ import { create, load } from 'ipld-hashmap';
18
22
  import { rawSha1 as sha1sync } from './sha1.js';
19
23
  const chunker = bf(30);
24
+ const blockOpts = { cache, chunker, codec: dagcbor, hasher: sha256, compare };
20
25
  const NO_ENCRYPT = typeof process !== 'undefined' && !!process.env?.NO_ENCRYPT;
21
26
  // ? process.env.NO_ENCRYPT : import.meta && import.meta.env.VITE_NO_ENCRYPT
22
27
  export class Valet {
@@ -26,6 +31,11 @@ export class Valet {
26
31
  alreadyEnqueued = new Set();
27
32
  keyMaterial = null;
28
33
  keyId = 'null';
34
+ valetRoot = null;
35
+ valetRootCid = null; // set by hydrate
36
+ valetRootCarCid = null; // most recent diff
37
+ valetCidBlocks = new VMemoryBlockstore();
38
+ instanceId = Math.random().toString(36).slice(2);
29
39
  /**
30
40
  * Function installed by the database to upload car files
31
41
  * @type {null|function(string, Uint8Array):Promise<void>}
@@ -140,18 +150,113 @@ export class Valet {
140
150
  cursor = await cursor.continue();
141
151
  }
142
152
  }
153
+ setRootCarCid(cid) {
154
+ this.valetRootCarCid = cid;
155
+ this.valetRoot = null;
156
+ this.valetRootCid = null;
157
+ }
158
+ async getCarCIDForCID(cid) {
159
+ // make a car reader for this.valetRootCarCid
160
+ if (!this.valetRootCarCid)
161
+ return;
162
+ let indexNode;
163
+ if (this.valetRoot) {
164
+ indexNode = this.valetRoot;
165
+ }
166
+ else {
167
+ const combinedReader = await this.getCombinedReader(this.valetRootCarCid);
168
+ if (!this.valetRootCid) {
169
+ const root = combinedReader.root.cid;
170
+ // console.log('roots', this.instanceId, this.name, root, this.valetRootCarCid, this.valetRootCid)
171
+ this.valetRootCid = root;
172
+ }
173
+ indexNode = await load(combinedReader, this.valetRootCid, {
174
+ blockHasher: blockOpts.hasher,
175
+ blockCodec: blockOpts.codec
176
+ });
177
+ }
178
+ const got = await indexNode.get(cid);
179
+ // console.log('getCarCIDForCID', cid, got)
180
+ return { result: got };
181
+ }
182
+ async OLDgetCarCIDForCID(cid) {
183
+ const carCid = await this.withDB(async (db) => {
184
+ const tx = db.transaction(['cars', 'cidToCar'], 'readonly');
185
+ const indexResp = await tx.objectStore('cidToCar').index('cids').get(cid);
186
+ return indexResp?.car;
187
+ });
188
+ return { result: carCid };
189
+ }
190
+ async getCombinedReader(carCid) {
191
+ let carMapReader;
192
+ if (this.valetRootCarCid) {
193
+ // todo only need this if we are cold starting
194
+ carMapReader = await this.getCarReader(this.valetRootCarCid);
195
+ }
196
+ const theseValetCidBlocks = this.valetCidBlocks;
197
+ // console.log('theseValetCidBlocks', theseValetCidBlocks)
198
+ const combinedReader = {
199
+ root: carMapReader?.root,
200
+ put: async (cid, bytes) => {
201
+ // console.log('mapPut', cid, bytes.length)
202
+ return await theseValetCidBlocks.put(cid, bytes);
203
+ },
204
+ get: async (cid) => {
205
+ // console.log('mapGet', cid)
206
+ try {
207
+ const got = await theseValetCidBlocks.get(cid);
208
+ return got.bytes;
209
+ }
210
+ catch (e) {
211
+ // console.log('get from car', cid, carMapReader)
212
+ if (!carMapReader)
213
+ throw e;
214
+ const bytes = await carMapReader.get(cid);
215
+ await theseValetCidBlocks.put(cid, bytes);
216
+ // console.log('mapGet', cid, bytes.length, bytes.constructor.name)
217
+ return bytes;
218
+ }
219
+ }
220
+ };
221
+ return combinedReader;
222
+ }
143
223
  /**
144
224
  *
145
225
  * @param {string} carCid
146
226
  * @param {*} value
147
227
  */
148
228
  async parkCar(carCid, value, cids) {
229
+ // console.log('parkCar', this.instanceId, this.name, carCid, cids)
230
+ const combinedReader = await this.getCombinedReader(carCid);
231
+ const mapNode = await addCidsToCarIndex(combinedReader, this.valetRoot, this.valetRootCid, Array.from(cids).map(cid => ({ key: cid.toString(), value: carCid.toString() })));
232
+ this.valetRoot = mapNode;
233
+ this.valetRootCid = mapNode.cid;
234
+ // make a block set with all the cids of the map
235
+ const saveValetBlocks = new VMemoryBlockstore(); // todo this blockstore should read from the last valetCid car also
236
+ for await (const cidx of mapNode.cids()) {
237
+ const bytes = await combinedReader.get(cidx);
238
+ saveValetBlocks.put(cidx, bytes);
239
+ }
240
+ let newValetCidCar;
241
+ if (this.keyMaterial) {
242
+ newValetCidCar = await blocksToEncryptedCarBlock(this.valetRootCid, saveValetBlocks, this.keyMaterial);
243
+ }
244
+ else {
245
+ newValetCidCar = await blocksToCarBlock(this.valetRootCid, saveValetBlocks);
246
+ }
247
+ // console.log('newValetCidCar', this.name, Math.floor(newValetCidCar.bytes.length / 1024))
149
248
  await this.withDB(async (db) => {
150
- const tx = db.transaction(['cars', 'cidToCar'], 'readwrite');
151
- await tx.objectStore('cars').put(value, carCid);
152
- await tx.objectStore('cidToCar').put({ pending: 'y', car: carCid, cids: Array.from(cids) });
249
+ const tx = db.transaction(['cars'], 'readwrite');
250
+ await tx.objectStore('cars').put(value, carCid.toString());
251
+ if (newValetCidCar) {
252
+ if (this.valetRootCarCid) {
253
+ // await tx.objectStore('cars').delete(this.valetRootCarCid.toString())
254
+ }
255
+ await tx.objectStore('cars').put(newValetCidCar.bytes, newValetCidCar.cid.toString());
256
+ }
153
257
  return await tx.done;
154
258
  });
259
+ this.valetRootCarCid = newValetCidCar.cid; // goes to clock
155
260
  // console.log('parked car', carCid, value.length, Array.from(cids))
156
261
  // upload to web3.storage if we have credentials
157
262
  if (this.uploadFunction) {
@@ -169,49 +274,73 @@ export class Valet {
169
274
  }
170
275
  }
171
276
  remoteBlockFunction = null;
172
- async getBlock(dataCID) {
173
- return await this.withDB(async (db) => {
174
- const tx = db.transaction(['cars', 'cidToCar'], 'readonly');
175
- const indexResp = await tx.objectStore('cidToCar').index('cids').get(dataCID);
176
- const carCid = indexResp?.car;
177
- if (!carCid) {
178
- throw new Error('Missing block: ' + dataCID);
179
- }
180
- const carBytes = await tx.objectStore('cars').get(carCid);
181
- const reader = await CarReader.fromBytes(carBytes);
182
- if (this.keyMaterial) {
183
- const roots = await reader.getRoots();
184
- const readerGetWithCodec = async (cid) => {
185
- const got = await reader.get(cid);
186
- // console.log('got.', cid.toString())
187
- let useCodec = codec;
188
- if (cid.toString().indexOf('bafy') === 0) {
189
- useCodec = dagcbor;
277
+ async getCarReader(carCid) {
278
+ carCid = carCid.toString();
279
+ const carBytes = await this.withDB(async (db) => {
280
+ const tx = db.transaction(['cars'], 'readonly');
281
+ // console.log('getCarReader', carCid)
282
+ return await tx.objectStore('cars').get(carCid);
283
+ });
284
+ const reader = await CarReader.fromBytes(carBytes);
285
+ if (this.keyMaterial) {
286
+ const roots = await reader.getRoots();
287
+ const readerGetWithCodec = async (cid) => {
288
+ const got = await reader.get(cid);
289
+ // console.log('got.', cid.toString())
290
+ let useCodec = codec;
291
+ if (cid.toString().indexOf('bafy') === 0) {
292
+ // todo cleanup types
293
+ useCodec = dagcbor;
294
+ }
295
+ const decoded = await Block.decode({
296
+ ...got,
297
+ codec: useCodec,
298
+ hasher: sha256
299
+ });
300
+ // console.log('decoded', decoded.value)
301
+ return decoded;
302
+ };
303
+ const { blocks } = await blocksFromEncryptedCarBlock(roots[0], readerGetWithCodec, this.keyMaterial);
304
+ // last block is the root ???
305
+ const rootBlock = blocks[blocks.length - 1];
306
+ return {
307
+ root: rootBlock,
308
+ get: async (dataCID) => {
309
+ // console.log('getCarReader dataCID', dataCID)
310
+ dataCID = dataCID.toString();
311
+ const block = blocks.find(b => b.cid.toString() === dataCID);
312
+ // console.log('getCarReader block', block)
313
+ if (block) {
314
+ return block.bytes;
190
315
  }
191
- const decoded = await Block.decode({
192
- ...got,
193
- codec: useCodec,
194
- hasher: sha256
195
- });
196
- // console.log('decoded', decoded.value)
197
- return decoded;
198
- };
199
- const { blocks } = await blocksFromEncryptedCarBlock(roots[0], readerGetWithCodec, this.keyMaterial);
200
- const block = blocks.find(b => b.cid.toString() === dataCID);
201
- if (block) {
202
- return block.bytes;
203
316
  }
204
- }
205
- else {
206
- const gotBlock = await reader.get(CID.parse(dataCID));
207
- if (gotBlock) {
208
- return gotBlock.bytes;
317
+ };
318
+ }
319
+ else {
320
+ return {
321
+ root: reader.getRoots()[0],
322
+ get: async (dataCID) => {
323
+ const gotBlock = await reader.get(CID.parse(dataCID));
324
+ if (gotBlock) {
325
+ return gotBlock.bytes;
326
+ }
209
327
  }
210
- }
211
- });
328
+ };
329
+ }
330
+ }
331
+ // todo memoize this
332
+ async getValetBlock(dataCID) {
333
+ // console.log('get valet block', dataCID)
334
+ const { result: carCid } = await this.getCarCIDForCID(dataCID);
335
+ if (!carCid) {
336
+ throw new Error('Missing block: ' + dataCID);
337
+ }
338
+ const reader = await this.getCarReader(carCid);
339
+ return await reader.get(dataCID);
212
340
  }
213
341
  }
214
342
  export const blocksToCarBlock = async (rootCids, blocks) => {
343
+ // console.log('blocksToCarBlock', rootCids, blocks.constructor.name)
215
344
  let size = 0;
216
345
  if (!Array.isArray(rootCids)) {
217
346
  rootCids = [rootCids];
@@ -293,3 +422,55 @@ const blocksFromEncryptedCarBlock = async (cid, get, keyMaterial) => {
293
422
  return blocksPromise;
294
423
  }
295
424
  };
425
+ const addCidsToCarIndex = async (blockstore, valetRoot, valetRootCid, bulkOperations) => {
426
+ let indexNode;
427
+ if (valetRootCid) {
428
+ if (valetRoot) {
429
+ indexNode = valetRoot;
430
+ }
431
+ else {
432
+ indexNode = await load(blockstore, valetRootCid, { blockHasher: blockOpts.hasher, blockCodec: blockOpts.codec });
433
+ }
434
+ }
435
+ else {
436
+ indexNode = await create(blockstore, {
437
+ bitWidth: 4,
438
+ bucketSize: 2,
439
+ blockHasher: blockOpts.hasher,
440
+ blockCodec: blockOpts.codec
441
+ });
442
+ }
443
+ // console.log('adding', bulkOperations.length, 'cids to index')
444
+ for (const { key, value } of bulkOperations) {
445
+ // console.log('adding', key, value)
446
+ await indexNode.set(key, value);
447
+ }
448
+ return indexNode;
449
+ };
450
+ export class VMemoryBlockstore {
451
+ /** @type {Map<string, Uint8Array>} */
452
+ blocks = new Map();
453
+ instanceId = Math.random().toString(36).slice(2);
454
+ async get(cid) {
455
+ const bytes = this.blocks.get(cid.toString());
456
+ // console.log('getvm', bytes.constructor.name, this.instanceId, cid, bytes && bytes.length)
457
+ if (bytes.length === 253) {
458
+ // console.log('getvm', bytes.())
459
+ }
460
+ if (!bytes)
461
+ throw new Error('block not found ' + cid.toString());
462
+ return { cid, bytes };
463
+ }
464
+ /**
465
+ * @param {import('../src/link').AnyLink} cid
466
+ * @param {Uint8Array} bytes
467
+ */
468
+ async put(cid, bytes) {
469
+ this.blocks.set(cid.toString(), bytes);
470
+ }
471
+ *entries() {
472
+ for (const [str, bytes] of this.blocks) {
473
+ yield { cid: parse(str), bytes };
474
+ }
475
+ }
476
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fireproof/core",
3
- "version": "0.5.16",
3
+ "version": "0.5.18",
4
4
  "description": "Cloudless database for apps, the browser, and IPFS",
5
5
  "main": "dist/src/fireproof.js",
6
6
  "module": "dist/src/fireproof.mjs",
@@ -49,6 +49,7 @@
49
49
  "crypto-browserify": "^3.12.0",
50
50
  "encrypted-block": "^0.0.3",
51
51
  "idb": "^7.1.1",
52
+ "ipld-hashmap": "^2.1.18",
52
53
  "multiformats": "^11.0.1",
53
54
  "node-polyfill-webpack-plugin": "^2.0.1",
54
55
  "prolly-trees": "1.0.4",
package/src/blockstore.js CHANGED
@@ -80,7 +80,7 @@ export class TransactionBlockstore {
80
80
  // console.log('committedGet: ' + key + ' ' + this.instanceId, old.length)
81
81
  if (old) return old
82
82
  if (!this.valet) throw new Error('Missing block: ' + key)
83
- const got = await this.valet.getBlock(key)
83
+ const got = await this.valet.getValetBlock(key)
84
84
  this.committedBlocks.set(key, got)
85
85
  return got
86
86
  }
package/src/clock.js CHANGED
@@ -237,12 +237,13 @@ export async function findEventsToSync (blocks, head) {
237
237
  // console.time(callTag + '.findCommonAncestorWithSortedEvents')
238
238
  const { ancestor, sorted } = await findCommonAncestorWithSortedEvents(events, head)
239
239
  // console.timeEnd(callTag + '.findCommonAncestorWithSortedEvents')
240
- // console.log('sorted', !!ancestor, sorted.length)
240
+ // console.log('sorted', !!ancestor, sorted)
241
241
  // console.time(callTag + '.contains')
242
242
 
243
243
  const toSync = ancestor ? await asyncFilter(sorted, async uks => !(await contains(events, ancestor, uks.cid))) : sorted
244
244
  // console.timeEnd(callTag + '.contains')
245
- // console.log('optimize sorted', !!ancestor, sorted.length - toSync.length)
245
+ const sortDifference = sorted.length - toSync.length
246
+ if (sortDifference / sorted.length > 0.6) console.log('optimize sorted', !!ancestor, sortDifference)
246
247
 
247
248
  return { cids: events, events: toSync }
248
249
  }
package/src/database.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
2
  import { visMerkleClock, visMerkleTree, vis, put, get, getAll, eventsSince } from './prolly.js'
3
- import { doTransaction } from './blockstore.js'
3
+ import { doTransaction, TransactionBlockstore } from './blockstore.js'
4
4
  import charwise from 'charwise'
5
5
  import { localSet } from './utils.js'
6
6
  import { CID } from 'multiformats'
@@ -19,7 +19,6 @@ export const parseCID = cid => (typeof cid === 'string' ? CID.parse(cid) : cid)
19
19
  * This is the main class for saving and loading JSON and other documents with the database. You can find additional examples and
20
20
  * usage guides in the repository README.
21
21
  *
22
- * @param {import('./blockstore.js').TransactionBlockstore} blocks - The block storage instance to use documents and indexes
23
22
  * @param {CID[]} clock - The Merkle clock head to use for the Fireproof instance.
24
23
  * @param {object} [config] - Optional configuration options for the Fireproof instance.
25
24
  * @param {object} [authCtx] - Optional authorization context object to use for any authentication checks.
@@ -31,10 +30,11 @@ export class Database {
31
30
  rootCache = null
32
31
  eventsCache = new Map()
33
32
 
34
- constructor (blocks, clock, config = {}) {
35
- this.name = config.name
33
+ constructor (name, clock, config = {}) {
34
+ this.name = name
36
35
  this.instanceId = `fp.${this.name}.${Math.random().toString(36).substring(2, 7)}`
37
- this.blocks = blocks
36
+ this.blocks = new TransactionBlockstore(name, config.key)
37
+ this.indexBlocks = new TransactionBlockstore(name + '.indexes', config.key)
38
38
  this.clock = clock
39
39
  this.config = config
40
40
  }
@@ -51,6 +51,8 @@ export class Database {
51
51
  clock: this.clockToJSON(),
52
52
  name: this.name,
53
53
  key: this.blocks.valet?.getKeyMaterial(),
54
+ car: this.blocks.valet?.valetRootCarCid.toString(),
55
+ indexCar: this.indexBlocks.valet?.valetRootCarCid?.toString(),
54
56
  indexes: [...this.indexes.values()].map(index => index.toJSON())
55
57
  }
56
58
  }
@@ -65,11 +67,14 @@ export class Database {
65
67
  return (clock || this.clock).map(cid => cid.toString())
66
68
  }
67
69
 
68
- hydrate ({ clock, name, key }) {
70
+ hydrate ({ clock, name, key, car, indexCar }) {
69
71
  this.name = name
70
72
  this.clock = clock
71
73
  this.blocks.valet?.setKeyMaterial(key)
72
- this.indexBlocks = null
74
+ this.blocks.valet?.setRootCarCid(car) // maybe
75
+ this.indexBlocks.valet?.setKeyMaterial(key)
76
+ this.indexBlocks.valet?.setRootCarCid(indexCar) // maybe
77
+ // this.indexBlocks = null
73
78
  }
74
79
 
75
80
  maybeSaveClock () {
@@ -108,7 +113,7 @@ export class Database {
108
113
  let rows, dataCIDs, clockCIDs
109
114
  // if (!aClock) aClock = []
110
115
  if (aClock && aClock.length > 0) {
111
- aClock = aClock.map((cid) => cid.toString())
116
+ aClock = aClock.map(cid => cid.toString())
112
117
  const eventKey = JSON.stringify([...this.clockToJSON(aClock), ...this.clockToJSON()])
113
118
 
114
119
  let resp
@@ -276,6 +281,7 @@ export class Database {
276
281
  * @returns {Promise<{ proof:{}, id: string, clock: CID[] }>} - The result of adding the event to storage
277
282
  */
278
283
  async putToProllyTree (decodedEvent, clock = null) {
284
+ // console.log('putToProllyTree', decodedEvent)
279
285
  const event = encodeEvent(decodedEvent)
280
286
  if (clock && JSON.stringify(this.clockToJSON(clock)) !== JSON.stringify(this.clockToJSON())) {
281
287
  // console.log('this.clock', this.clockToJSON())
@@ -393,7 +399,9 @@ export class Database {
393
399
 
394
400
  export async function cidsToProof (cids) {
395
401
  if (!cids) return []
396
- if (!cids.all) { return [...cids] }
402
+ if (!cids.all) {
403
+ return [...cids]
404
+ }
397
405
 
398
406
  const all = await cids.all()
399
407
  return [...all].map(cid => cid.toString())
package/src/db-index.js CHANGED
@@ -13,7 +13,7 @@ import { Database, cidsToProof } from './database.js'
13
13
 
14
14
  import * as codec from '@ipld/dag-cbor'
15
15
  // import { create as createBlock } from 'multiformats/block'
16
- import { TransactionBlockstore, doTransaction } from './blockstore.js'
16
+ import { doTransaction } from './blockstore.js'
17
17
  // @ts-ignore
18
18
  import charwise from 'charwise'
19
19
 
@@ -69,21 +69,21 @@ const makeDoc = ({ key, value }) => ({ _id: key, ...value })
69
69
  */
70
70
  const indexEntriesForChanges = (changes, mapFn) => {
71
71
  const indexEntries = []
72
- changes.forEach(({ key, value, del }) => {
72
+ changes.forEach(({ key: _id, value, del }) => {
73
73
  // key is _id, value is the document
74
74
  if (del || !value) return
75
75
  let mapCalled = false
76
- const mapReturn = mapFn(makeDoc({ key, value }), (k, v) => {
76
+ const mapReturn = mapFn(makeDoc({ key: _id, value }), (k, v) => {
77
77
  mapCalled = true
78
78
  if (typeof k === 'undefined') return
79
79
  indexEntries.push({
80
- key: [charwise.encode(k), key],
80
+ key: [charwise.encode(k), _id],
81
81
  value: v || null
82
82
  })
83
83
  })
84
84
  if (!mapCalled && mapReturn) {
85
85
  indexEntries.push({
86
- key: [charwise.encode(mapReturn), key],
86
+ key: [charwise.encode(mapReturn), _id],
87
87
  value: null
88
88
  })
89
89
  }
@@ -107,12 +107,6 @@ export class DbIndex {
107
107
  */
108
108
  constructor (database, name, mapFn, clock = null, opts = {}) {
109
109
  this.database = database
110
- if (!database.indexBlocks) {
111
- database.indexBlocks = new TransactionBlockstore(
112
- database?.name + '.indexes',
113
- database.blocks.valet?.getKeyMaterial()
114
- )
115
- }
116
110
  if (typeof name === 'function') {
117
111
  // app is using deprecated API, remove in 0.7
118
112
  opts = clock || {}
@@ -265,7 +259,14 @@ export class DbIndex {
265
259
  await loadIndex(this.database.indexBlocks, this.indexByKey, dbIndexOpts)
266
260
  if (!this.indexByKey.root) return { result: [] }
267
261
  if (query.includeDocs === undefined) query.includeDocs = this.includeDocsDefault
268
- if (query.range) {
262
+ if (query.prefix) {
263
+ // ensure prefix is an array
264
+ if (!Array.isArray(query.prefix)) query.prefix = [query.prefix]
265
+ const start = [...query.prefix, NaN]
266
+ const end = [...query.prefix, Infinity]
267
+ const prefixRange = [start, end].map(key => charwise.encode(key))
268
+ return await this.applyQuery(await this.indexByKey.root.range(...prefixRange), query)
269
+ } else if (query.range) {
269
270
  const encodedRange = query.range.map(key => charwise.encode(key))
270
271
  return await this.applyQuery(await this.indexByKey.root.range(...encodedRange), query)
271
272
  } else if (query.key) {
package/src/fireproof.js CHANGED
@@ -2,7 +2,7 @@ import randomBytes from 'randombytes'
2
2
  import { Database, parseCID } from './database.js'
3
3
  import { Listener } from './listener.js'
4
4
  import { DbIndex as Index } from './db-index.js'
5
- import { TransactionBlockstore } from './blockstore.js'
5
+ // import { TransactionBlockstore } from './blockstore.js'
6
6
  import { localGet } from './utils.js'
7
7
  import { Sync } from './sync.js'
8
8
 
@@ -20,22 +20,29 @@ export class Fireproof {
20
20
  static storage = (name = null, opts = {}) => {
21
21
  if (name) {
22
22
  opts.name = name
23
+ // todo this can come from a registry also
23
24
  const existing = localGet('fp.' + name)
24
25
  if (existing) {
25
26
  const existingConfig = JSON.parse(existing)
26
- const fp = new Database(new TransactionBlockstore(name, existingConfig.key), [], opts)
27
- return Fireproof.fromJSON(existingConfig, fp)
27
+ return Fireproof.fromConfig(name, existingConfig, opts)
28
28
  } else {
29
29
  const instanceKey = randomBytes(32).toString('hex') // pass null to disable encryption
30
- return new Database(new TransactionBlockstore(name, instanceKey), [], opts)
30
+ opts.key = instanceKey
31
+ return new Database(name, [], opts)
31
32
  }
32
33
  } else {
33
- return new Database(new TransactionBlockstore(), [], opts)
34
+ return new Database(null, [], opts)
34
35
  }
35
36
  }
36
37
 
38
+ static fromConfig (name, existingConfig, opts = {}) {
39
+ opts.key = existingConfig.key
40
+ const fp = new Database(name, [], opts)
41
+ return Fireproof.fromJSON(existingConfig, fp)
42
+ }
43
+
37
44
  static fromJSON (json, database) {
38
- database.hydrate({ clock: json.clock.map(c => parseCID(c)), name: json.name, key: json.key })
45
+ database.hydrate({ car: json.car, indexCar: json.indexCar, clock: json.clock.map(c => parseCID(c)), name: json.name, key: json.key })
39
46
  if (json.indexes) {
40
47
  for (const {
41
48
  name,
@@ -58,7 +65,8 @@ export class Fireproof {
58
65
 
59
66
  static snapshot (database, clock) {
60
67
  const definition = database.toJSON()
61
- const withBlocks = new Database(database.blocks)
68
+ const withBlocks = new Database(database.name)
69
+ withBlocks.blocks = database.blocks
62
70
  if (clock) {
63
71
  definition.clock = clock.map(c => parseCID(c))
64
72
  definition.indexes.forEach(index => {
package/src/sync.js CHANGED
@@ -156,7 +156,7 @@ export class Sync {
156
156
  destroy () {
157
157
  this.database.blocks.syncs.delete(this)
158
158
  this.status = 'destroyed'
159
- this.peer.destroy()
159
+ // this.peer.destroy() todo
160
160
  }
161
161
 
162
162
  async sendUpdate (blockstore) {