@fireproof/core 0.5.18 → 0.5.20

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.
@@ -153,12 +153,6 @@ const prollyRootFromAncestor = async (events, ancestor, getBlock) => {
153
153
  return root;
154
154
  }
155
155
  };
156
- // async function bigMerge (events, head, getBlock) {
157
- // const allRoots = await Promise.all(head.map(async h => prollyRootFromAncestor(events, h, getBlock)))
158
- // console.log('allRoots', allRoots)
159
- // // todo query over all roots and merge them, but how do they not have a common ancestor? they all start with the _sync root
160
- // throw new Error('not implemented')
161
- // }
162
156
  const doProllyBulk = async (inBlocks, head, event, doFull = false) => {
163
157
  const { getBlock, blocks } = makeGetAndPutBlock(inBlocks); // this is doubled with eventfetcher
164
158
  let bulkSorted = [];
@@ -316,8 +310,6 @@ export async function eventsSince(blocks, head, since) {
316
310
  *
317
311
  */
318
312
  export async function getAll(blocks, head, rootCache = null, doFull = false) {
319
- // todo use the root node left around from put, etc
320
- // move load to a central place
321
313
  if (!head.length) {
322
314
  return { root: null, clockCIDs: new CIDCounter(), cids: new CIDCounter(), result: [] };
323
315
  }
package/dist/src/sync.js CHANGED
@@ -153,7 +153,7 @@ export class Sync {
153
153
  if (!this.peer || !this.isReady)
154
154
  return;
155
155
  // console.log('send update from', this.database.instanceId)
156
- // todo should send updates since last sync
156
+ // todo should send updates since last sync (currently sends each transaction)
157
157
  const newCar = await blocksToCarBlock(blockstore.lastCid, blockstore);
158
158
  this.status = 'sending update car';
159
159
  this.peer.send(newCar.bytes);
package/dist/src/valet.js CHANGED
@@ -52,28 +52,28 @@ export class Valet {
52
52
  // )
53
53
  if (this.uploadFunction) {
54
54
  // todo we can coalesce these into a single car file
55
- return await this.withDB(async (db) => {
56
- for (const task of tasks) {
57
- await this.uploadFunction(task.carCid, task.value);
58
- // update the indexedb to mark this car as no longer pending
59
- const carMeta = await db.get('cidToCar', task.carCid);
60
- delete carMeta.pending;
61
- await db.put('cidToCar', carMeta);
62
- }
63
- });
55
+ // todo remove idb usage here
56
+ for (const task of tasks) {
57
+ await this.uploadFunction(task.carCid, task.value);
58
+ // todo update syncCidMap to say this has been synced
59
+ // const carMeta = await db.get('cidToCar', task.carCid)
60
+ // delete carMeta.pending
61
+ // await db.put('cidToCar', carMeta)
62
+ }
64
63
  }
65
64
  callback();
66
65
  });
67
66
  this.uploadQueue.drain(async () => {
68
- return await this.withDB(async (db) => {
69
- const carKeys = (await db.getAllFromIndex('cidToCar', 'pending')).map(c => c.car);
70
- for (const carKey of carKeys) {
71
- await this.uploadFunction(carKey, await db.get('cars', carKey));
72
- const carMeta = await db.get('cidToCar', carKey);
73
- delete carMeta.pending;
74
- await db.put('cidToCar', carMeta);
75
- }
76
- });
67
+ // todo read syncCidMap and sync any that are still unsynced
68
+ // return await this.withDB(async db => {
69
+ // const carKeys = (await db.getAllFromIndex('cidToCar', 'pending')).map(c => c.car)
70
+ // for (const carKey of carKeys) {
71
+ // await this.uploadFunction(carKey, await db.get('cars', carKey))
72
+ // const carMeta = await db.get('cidToCar', carKey)
73
+ // delete carMeta.pending
74
+ // await db.put('cidToCar', carMeta)
75
+ // }
76
+ // })
77
77
  });
78
78
  }
79
79
  getKeyMaterial() {
@@ -118,16 +118,10 @@ export class Valet {
118
118
  }
119
119
  withDB = async (dbWorkFun) => {
120
120
  if (!this.idb) {
121
- this.idb = await openDB(`fp.${this.keyId}.${this.name}.valet`, 2, {
121
+ this.idb = await openDB(`fp.${this.keyId}.${this.name}.valet`, 3, {
122
122
  upgrade(db, oldVersion, newVersion, transaction) {
123
123
  if (oldVersion < 1) {
124
- db.createObjectStore('cars'); // todo use database name
125
- const cidToCar = db.createObjectStore('cidToCar', { keyPath: 'car' });
126
- cidToCar.createIndex('cids', 'cids', { multiEntry: true });
127
- }
128
- if (oldVersion < 2) {
129
- const cidToCar = transaction.objectStore('cidToCar');
130
- cidToCar.createIndex('pending', 'pending');
124
+ db.createObjectStore('cars');
131
125
  }
132
126
  }
133
127
  });
@@ -142,19 +136,18 @@ export class Valet {
142
136
  */
143
137
  async *cids() {
144
138
  // console.log('valet cids')
145
- const db = await this.withDB(async (db) => db);
146
- const tx = db.transaction(['cidToCar'], 'readonly');
147
- let cursor = await tx.store.openCursor();
148
- while (cursor) {
149
- yield { cid: cursor.key, car: cursor.value.car };
150
- cursor = await cursor.continue();
151
- }
139
+ // todo use cidMap
140
+ // while (cursor) {
141
+ // yield { cid: cursor.key, car: cursor.value.car }
142
+ // cursor = await cursor.continue()
143
+ // }
152
144
  }
153
145
  setRootCarCid(cid) {
154
146
  this.valetRootCarCid = cid;
155
147
  this.valetRoot = null;
156
148
  this.valetRootCid = null;
157
149
  }
150
+ // todo memoize this
158
151
  async getCarCIDForCID(cid) {
159
152
  // make a car reader for this.valetRootCarCid
160
153
  if (!this.valetRootCarCid)
@@ -179,14 +172,6 @@ export class Valet {
179
172
  // console.log('getCarCIDForCID', cid, got)
180
173
  return { result: got };
181
174
  }
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
175
  async getCombinedReader(carCid) {
191
176
  let carMapReader;
192
177
  if (this.valetRootCarCid) {
@@ -245,17 +230,19 @@ export class Valet {
245
230
  newValetCidCar = await blocksToCarBlock(this.valetRootCid, saveValetBlocks);
246
231
  }
247
232
  // console.log('newValetCidCar', this.name, Math.floor(newValetCidCar.bytes.length / 1024))
248
- await this.withDB(async (db) => {
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());
233
+ await this.writeCars([
234
+ {
235
+ cid: carCid,
236
+ bytes: value,
237
+ replaces: null
238
+ },
239
+ {
240
+ cid: newValetCidCar.cid,
241
+ bytes: newValetCidCar.bytes,
242
+ replaces: null
243
+ // replaces: this.valetRootCarCid // todo
256
244
  }
257
- return await tx.done;
258
- });
245
+ ]);
259
246
  this.valetRootCarCid = newValetCidCar.cid; // goes to clock
260
247
  // console.log('parked car', carCid, value.length, Array.from(cids))
261
248
  // upload to web3.storage if we have credentials
@@ -273,6 +260,19 @@ export class Valet {
273
260
  // console.log('no upload function', carCid, value.length, this.uploadFunction)
274
261
  }
275
262
  }
263
+ async writeCars(cars) {
264
+ return await this.withDB(async (db) => {
265
+ const tx = db.transaction(['cars'], 'readwrite');
266
+ for (const { cid, bytes, replaces } of cars) {
267
+ await tx.objectStore('cars').put(bytes, cid.toString());
268
+ // todo remove old maps
269
+ if (replaces) {
270
+ await tx.objectStore('cars').delete(replaces.toString());
271
+ }
272
+ }
273
+ return await tx.done;
274
+ });
275
+ }
276
276
  remoteBlockFunction = null;
277
277
  async getCarReader(carCid) {
278
278
  carCid = carCid.toString();
@@ -301,7 +301,7 @@ export class Valet {
301
301
  return decoded;
302
302
  };
303
303
  const { blocks } = await blocksFromEncryptedCarBlock(roots[0], readerGetWithCodec, this.keyMaterial);
304
- // last block is the root ???
304
+ // last block is the root ??? todo
305
305
  const rootBlock = blocks[blocks.length - 1];
306
306
  return {
307
307
  root: rootBlock,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@fireproof/core",
3
- "version": "0.5.18",
4
- "description": "Cloudless database for apps, the browser, and IPFS",
3
+ "version": "0.5.20",
4
+ "description": "Live data for your React app, powered by IPFS",
5
5
  "main": "dist/src/fireproof.js",
6
6
  "module": "dist/src/fireproof.mjs",
7
7
  "typings": "dist/src/fireproof.d.ts",
package/src/blockstore.js CHANGED
@@ -91,7 +91,6 @@ export class TransactionBlockstore {
91
91
 
92
92
  async networkGet (key) {
93
93
  if (this.remoteBlockFunction) {
94
- // todo why is this on valet?
95
94
  const value = await husher(key, async () => await this.remoteBlockFunction(key))
96
95
  if (value) {
97
96
  // console.log('networkGot: ' + key, value.length)
package/src/clock.js CHANGED
@@ -88,7 +88,7 @@ export class EventBlock extends Block {
88
88
  * @param {Uint8Array} config.bytes
89
89
  */
90
90
  constructor ({ cid, value, bytes }) {
91
- // @ts-expect-error
91
+ // @ts-ignore
92
92
  super({ cid, value, bytes })
93
93
  }
94
94
 
@@ -142,7 +142,7 @@ export class EventFetcher {
142
142
  export async function encodeEventBlock (value) {
143
143
  // TODO: sort parents
144
144
  const { cid, bytes } = await encode({ value, codec: cbor, hasher: sha256 })
145
- // @ts-expect-error
145
+ // @ts-ignore
146
146
  return new Block({ cid, value, bytes })
147
147
  }
148
148
 
@@ -153,7 +153,7 @@ export async function encodeEventBlock (value) {
153
153
  */
154
154
  export async function decodeEventBlock (bytes) {
155
155
  const { cid, value } = await decode({ bytes, codec: cbor, hasher: sha256 })
156
- // @ts-expect-error
156
+ // @ts-ignore
157
157
  return new Block({ cid, value, bytes })
158
158
  }
159
159
 
package/src/database.js CHANGED
@@ -46,7 +46,6 @@ export class Database {
46
46
  * @instance
47
47
  */
48
48
  toJSON () {
49
- // todo this also needs to return the index roots...
50
49
  return {
51
50
  clock: this.clockToJSON(),
52
51
  name: this.name,
@@ -83,6 +82,18 @@ export class Database {
83
82
  }
84
83
  }
85
84
 
85
+ index (name) {
86
+ // iterate over the indexes and gather any with the same name
87
+ // if there are more than one, throw an error
88
+ // if there is one, return it
89
+ // if there are none, return null
90
+ const indexes = [...this.indexes.values()].filter(index => index.name === name)
91
+ if (indexes.length > 1) {
92
+ throw new Error(`Multiple indexes found with name ${name}`)
93
+ }
94
+ return indexes[0] || null
95
+ }
96
+
86
97
  /**
87
98
  * Triggers a notification to all listeners
88
99
  * of the Fireproof instance so they can repaint UI, etc.
@@ -171,8 +182,7 @@ export class Database {
171
182
  const cids = await cidsToProof(allResp.cids)
172
183
  const clockCids = await cidsToProof(allResp.clockCIDs)
173
184
  // console.log('allcids', cids, clockCids)
174
- // todo we need to put the clock head as the last block in the encrypted car
175
- return [...cids, ...clockCids] // need a single block version of clock head, maybe an encoded block for it
185
+ return [...cids, ...clockCids] // clock CID last -- need to handle multiple entry clocks
176
186
  }
177
187
 
178
188
  async allStoredCIDs () {
@@ -214,7 +224,7 @@ export class Database {
214
224
  const clock = opts.clock || this.clock
215
225
  const resp = await get(this.blocks, clock, charwise.encode(key), this.rootCache)
216
226
  this.rootCache = { root: resp.root, clockCIDs: resp.clockCIDs }
217
- // this tombstone is temporary until we can get the prolly tree to delete
227
+ // ? this tombstone is temporary until we can get the prolly tree to delete
218
228
  if (!resp || resp.result === null) {
219
229
  throw new Error('Not found')
220
230
  }
@@ -230,12 +240,11 @@ export class Database {
230
240
  return doc
231
241
  }
232
242
  /**
233
- * @typedef {Object} Document
243
+ * @typedef {any} Document
234
244
  * @property {string} _id - The ID of the document (required)
235
245
  * @property {string} [_proof] - The proof of the document (optional)
236
246
  * @property {string} [_clock] - The clock of the document (optional)
237
- * @property {any} [key: string] - Index signature notation to allow any other unknown fields
238
- * * @property {Object.<string, any>} [otherProperties] - Any other unknown properties (optional)
247
+ * @property {Object.<string, any>} [unknown: string] - Any other unknown properties (optional)
239
248
  */
240
249
 
241
250
  /**
package/src/db-index.js CHANGED
@@ -306,7 +306,7 @@ export class DbIndex {
306
306
  async innerUpdateIndex (inBlocks) {
307
307
  // const callTag = Math.random().toString(36).substring(4)
308
308
  // console.log(`updateIndex ${callTag} >`, this.instanceId, this.dbHead?.toString(), this.indexByKey.cid?.toString(), this.indexById.cid?.toString())
309
- // todo remove this hack
309
+ // todo remove this hack in 0.7.0
310
310
  if (ALWAYS_REBUILD) {
311
311
  this.indexById = { root: null, cid: null }
312
312
  this.indexByKey = { root: null, cid: null }
@@ -353,9 +353,7 @@ export class DbIndex {
353
353
  )
354
354
  this.indexByKey = await bulkIndex(blocks, this.indexByKey, oldIndexEntries.concat(indexEntries), dbIndexOpts)
355
355
  this.dbHead = result.clock
356
- }, false /* don't sync transaction -- maybe move this flag to database.indexBlocks? */)
357
- // todo index subscriptions
358
- // this.database.notifyExternal('dbIndex')
356
+ }, false /* don't sync transaction -- todo move this flag to database.indexBlocks, and concept of sync channels */)
359
357
  // console.timeEnd(callTag + '.doTransactionupdateIndex')
360
358
  // console.log(`updateIndex ${callTag} <`, this.instanceId, this.dbHead?.toString(), this.indexByKey.cid?.toString(), this.indexById.cid?.toString())
361
359
  return didT
package/src/fireproof.js CHANGED
@@ -6,6 +6,7 @@ import { DbIndex as Index } from './db-index.js'
6
6
  import { localGet } from './utils.js'
7
7
  import { Sync } from './sync.js'
8
8
 
9
+ // todo remove Listener in 0.7.0
9
10
  export { Index, Listener, Database, Sync }
10
11
 
11
12
  export class Fireproof {
@@ -20,7 +21,7 @@ export class Fireproof {
20
21
  static storage = (name = null, opts = {}) => {
21
22
  if (name) {
22
23
  opts.name = name
23
- // todo this can come from a registry also
24
+ // todo this can come from a registry also eg remote database / config, etc
24
25
  const existing = localGet('fp.' + name)
25
26
  if (existing) {
26
27
  const existingConfig = JSON.parse(existing)
package/src/prolly.js CHANGED
@@ -172,13 +172,6 @@ const prollyRootFromAncestor = async (events, ancestor, getBlock) => {
172
172
  }
173
173
  }
174
174
 
175
- // async function bigMerge (events, head, getBlock) {
176
- // const allRoots = await Promise.all(head.map(async h => prollyRootFromAncestor(events, h, getBlock)))
177
- // console.log('allRoots', allRoots)
178
- // // todo query over all roots and merge them, but how do they not have a common ancestor? they all start with the _sync root
179
- // throw new Error('not implemented')
180
- // }
181
-
182
175
  const doProllyBulk = async (inBlocks, head, event, doFull = false) => {
183
176
  const { getBlock, blocks } = makeGetAndPutBlock(inBlocks) // this is doubled with eventfetcher
184
177
  let bulkSorted = []
@@ -347,8 +340,6 @@ export async function eventsSince (blocks, head, since) {
347
340
  *
348
341
  */
349
342
  export async function getAll (blocks, head, rootCache = null, doFull = false) {
350
- // todo use the root node left around from put, etc
351
- // move load to a central place
352
343
  if (!head.length) {
353
344
  return { root: null, clockCIDs: new CIDCounter(), cids: new CIDCounter(), result: [] }
354
345
  }
package/src/sync.js CHANGED
@@ -162,7 +162,7 @@ export class Sync {
162
162
  async sendUpdate (blockstore) {
163
163
  if (!this.peer || !this.isReady) return
164
164
  // console.log('send update from', this.database.instanceId)
165
- // todo should send updates since last sync
165
+ // todo should send updates since last sync (currently sends each transaction)
166
166
  const newCar = await blocksToCarBlock(blockstore.lastCid, blockstore)
167
167
  this.status = 'sending update car'
168
168
  this.peer.send(newCar.bytes)
package/src/valet.js CHANGED
@@ -61,29 +61,29 @@ export class Valet {
61
61
  // )
62
62
  if (this.uploadFunction) {
63
63
  // todo we can coalesce these into a single car file
64
- return await this.withDB(async db => {
65
- for (const task of tasks) {
66
- await this.uploadFunction(task.carCid, task.value)
67
- // update the indexedb to mark this car as no longer pending
68
- const carMeta = await db.get('cidToCar', task.carCid)
69
- delete carMeta.pending
70
- await db.put('cidToCar', carMeta)
71
- }
72
- })
64
+ // todo remove idb usage here
65
+ for (const task of tasks) {
66
+ await this.uploadFunction(task.carCid, task.value)
67
+ // todo update syncCidMap to say this has been synced
68
+ // const carMeta = await db.get('cidToCar', task.carCid)
69
+ // delete carMeta.pending
70
+ // await db.put('cidToCar', carMeta)
71
+ }
73
72
  }
74
73
  callback()
75
74
  })
76
75
 
77
76
  this.uploadQueue.drain(async () => {
78
- return await this.withDB(async db => {
79
- const carKeys = (await db.getAllFromIndex('cidToCar', 'pending')).map(c => c.car)
80
- for (const carKey of carKeys) {
81
- await this.uploadFunction(carKey, await db.get('cars', carKey))
82
- const carMeta = await db.get('cidToCar', carKey)
83
- delete carMeta.pending
84
- await db.put('cidToCar', carMeta)
85
- }
86
- })
77
+ // todo read syncCidMap and sync any that are still unsynced
78
+ // return await this.withDB(async db => {
79
+ // const carKeys = (await db.getAllFromIndex('cidToCar', 'pending')).map(c => c.car)
80
+ // for (const carKey of carKeys) {
81
+ // await this.uploadFunction(carKey, await db.get('cars', carKey))
82
+ // const carMeta = await db.get('cidToCar', carKey)
83
+ // delete carMeta.pending
84
+ // await db.put('cidToCar', carMeta)
85
+ // }
86
+ // })
87
87
  })
88
88
  }
89
89
 
@@ -129,16 +129,10 @@ export class Valet {
129
129
 
130
130
  withDB = async dbWorkFun => {
131
131
  if (!this.idb) {
132
- this.idb = await openDB(`fp.${this.keyId}.${this.name}.valet`, 2, {
132
+ this.idb = await openDB(`fp.${this.keyId}.${this.name}.valet`, 3, {
133
133
  upgrade (db, oldVersion, newVersion, transaction) {
134
134
  if (oldVersion < 1) {
135
- db.createObjectStore('cars') // todo use database name
136
- const cidToCar = db.createObjectStore('cidToCar', { keyPath: 'car' })
137
- cidToCar.createIndex('cids', 'cids', { multiEntry: true })
138
- }
139
- if (oldVersion < 2) {
140
- const cidToCar = transaction.objectStore('cidToCar')
141
- cidToCar.createIndex('pending', 'pending')
135
+ db.createObjectStore('cars')
142
136
  }
143
137
  }
144
138
  })
@@ -154,13 +148,11 @@ export class Valet {
154
148
  */
155
149
  async * cids () {
156
150
  // console.log('valet cids')
157
- const db = await this.withDB(async db => db)
158
- const tx = db.transaction(['cidToCar'], 'readonly')
159
- let cursor = await tx.store.openCursor()
160
- while (cursor) {
161
- yield { cid: cursor.key, car: cursor.value.car }
162
- cursor = await cursor.continue()
163
- }
151
+ // todo use cidMap
152
+ // while (cursor) {
153
+ // yield { cid: cursor.key, car: cursor.value.car }
154
+ // cursor = await cursor.continue()
155
+ // }
164
156
  }
165
157
 
166
158
  setRootCarCid (cid) {
@@ -169,6 +161,7 @@ export class Valet {
169
161
  this.valetRootCid = null
170
162
  }
171
163
 
164
+ // todo memoize this
172
165
  async getCarCIDForCID (cid) {
173
166
  // make a car reader for this.valetRootCarCid
174
167
  if (!this.valetRootCarCid) return
@@ -194,15 +187,6 @@ export class Valet {
194
187
  return { result: got }
195
188
  }
196
189
 
197
- async OLDgetCarCIDForCID (cid) {
198
- const carCid = await this.withDB(async db => {
199
- const tx = db.transaction(['cars', 'cidToCar'], 'readonly')
200
- const indexResp = await tx.objectStore('cidToCar').index('cids').get(cid)
201
- return indexResp?.car
202
- })
203
- return { result: carCid }
204
- }
205
-
206
190
  async getCombinedReader (carCid) {
207
191
  let carMapReader
208
192
  if (this.valetRootCarCid) {
@@ -267,17 +251,20 @@ export class Valet {
267
251
  newValetCidCar = await blocksToCarBlock(this.valetRootCid, saveValetBlocks)
268
252
  }
269
253
  // console.log('newValetCidCar', this.name, Math.floor(newValetCidCar.bytes.length / 1024))
270
- await this.withDB(async db => {
271
- const tx = db.transaction(['cars'], 'readwrite')
272
- await tx.objectStore('cars').put(value, carCid.toString())
273
- if (newValetCidCar) {
274
- if (this.valetRootCarCid) {
275
- // await tx.objectStore('cars').delete(this.valetRootCarCid.toString())
276
- }
277
- await tx.objectStore('cars').put(newValetCidCar.bytes, newValetCidCar.cid.toString())
254
+ await this.writeCars([
255
+ {
256
+ cid: carCid,
257
+ bytes: value,
258
+ replaces: null
259
+ },
260
+ {
261
+ cid: newValetCidCar.cid,
262
+ bytes: newValetCidCar.bytes,
263
+ replaces: null
264
+ // replaces: this.valetRootCarCid // todo
278
265
  }
279
- return await tx.done
280
- })
266
+ ])
267
+
281
268
  this.valetRootCarCid = newValetCidCar.cid // goes to clock
282
269
 
283
270
  // console.log('parked car', carCid, value.length, Array.from(cids))
@@ -296,6 +283,20 @@ export class Valet {
296
283
  }
297
284
  }
298
285
 
286
+ async writeCars (cars) {
287
+ return await this.withDB(async db => {
288
+ const tx = db.transaction(['cars'], 'readwrite')
289
+ for (const { cid, bytes, replaces } of cars) {
290
+ await tx.objectStore('cars').put(bytes, cid.toString())
291
+ // todo remove old maps
292
+ if (replaces) {
293
+ await tx.objectStore('cars').delete(replaces.toString())
294
+ }
295
+ }
296
+ return await tx.done
297
+ })
298
+ }
299
+
299
300
  remoteBlockFunction = null
300
301
 
301
302
  async getCarReader (carCid) {
@@ -326,7 +327,7 @@ export class Valet {
326
327
  }
327
328
  const { blocks } = await blocksFromEncryptedCarBlock(roots[0], readerGetWithCodec, this.keyMaterial)
328
329
 
329
- // last block is the root ???
330
+ // last block is the root ??? todo
330
331
  const rootBlock = blocks[blocks.length - 1]
331
332
 
332
333
  return {