@fireproof/core 0.6.4 → 0.7.0-alpha.0

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 (48) hide show
  1. package/README.md +2 -2
  2. package/dist/{src/blockstore.js → blockstore.js} +7 -3
  3. package/dist/{src/database.js → database.js} +74 -48
  4. package/dist/{src/db-index.js → db-index.js} +13 -2
  5. package/dist/fireproof.js +92 -0
  6. package/dist/import.js +29 -0
  7. package/dist/loader.js +23 -0
  8. package/dist/{src/prolly.js → prolly.js} +1 -0
  9. package/dist/src/fireproof.d.ts +138 -137
  10. package/dist/src/fireproof.js +18183 -11479
  11. package/dist/src/fireproof.js.map +1 -1
  12. package/dist/src/fireproof.mjs +18184 -11479
  13. package/dist/src/fireproof.mjs.map +1 -1
  14. package/dist/storage/base.js +348 -0
  15. package/dist/storage/browser.js +61 -0
  16. package/dist/storage/filesystem.js +65 -0
  17. package/dist/storage/rest.js +58 -0
  18. package/dist/storage/ucan.js +0 -0
  19. package/dist/{src/sync.js → sync.js} +1 -1
  20. package/dist/valet.js +200 -0
  21. package/package.json +4 -5
  22. package/src/blockstore.js +6 -3
  23. package/src/database.js +80 -52
  24. package/src/db-index.js +12 -2
  25. package/src/fireproof.js +41 -30
  26. package/src/import.js +34 -0
  27. package/src/loader.js +26 -0
  28. package/src/prolly.js +2 -0
  29. package/src/storage/base.js +371 -0
  30. package/src/storage/browser.js +67 -0
  31. package/src/storage/filesystem.js +70 -0
  32. package/src/storage/rest.js +60 -0
  33. package/src/storage/ucan.js +0 -0
  34. package/src/sync.js +1 -1
  35. package/src/valet.js +57 -359
  36. package/dist/hooks/use-fireproof.js +0 -150
  37. package/dist/src/crypto-poly.js +0 -4
  38. package/dist/src/link.js +0 -1
  39. package/dist/src/loader.js +0 -131
  40. package/dist/src/valet.js +0 -476
  41. package/hooks/use-fireproof.js +0 -173
  42. package/src/listener.js +0 -119
  43. package/src/utils.js +0 -16
  44. /package/dist/{src/clock.js → clock.js} +0 -0
  45. /package/dist/{src/crypto.js → crypto.js} +0 -0
  46. /package/dist/{src/listener.js → listener.js} +0 -0
  47. /package/dist/{src/sha1.js → sha1.js} +0 -0
  48. /package/dist/{src/utils.js → utils.js} +0 -0
@@ -1,131 +0,0 @@
1
- import { readFileSync
2
- // createReadStream
3
- } from 'node:fs';
4
- import { mkdir, writeFile } from 'node:fs/promises';
5
- import { openDB } from 'idb';
6
- import { join, dirname } from 'path';
7
- // import { parse } from '@jsonlines/core'
8
- // import cargoQueue from 'async/cargoQueue.js'
9
- import { homedir } from 'os';
10
- const defaultConfig = {
11
- dataDir: join(homedir(), '.fireproof'),
12
- headerKeyPrefix: 'fp.'
13
- };
14
- const FORCE_IDB = typeof process !== 'undefined' && !!process.env?.FORCE_IDB;
15
- /* global localStorage */
16
- export class Loader {
17
- constructor(name, keyId, config = defaultConfig) {
18
- this.name = name;
19
- this.keyId = keyId;
20
- this.config = config;
21
- this.isBrowser = false;
22
- try {
23
- this.isBrowser = window.localStorage && true;
24
- }
25
- catch (e) { }
26
- }
27
- withDB = async (dbWorkFun) => {
28
- if (!this.idb) {
29
- this.idb = await openDB(`fp.${this.keyId}.${this.name}.valet`, 3, {
30
- upgrade(db, oldVersion, newVersion, transaction) {
31
- if (oldVersion < 1) {
32
- db.createObjectStore('cars');
33
- }
34
- }
35
- });
36
- }
37
- return await dbWorkFun(this.idb);
38
- };
39
- async writeCars(cars) {
40
- // console.log('writeCars', this.config.dataDir, this.name, cars.map(c => c.cid.toString()))
41
- // console.log('writeCars', cars.length)
42
- if (FORCE_IDB || this.isBrowser) {
43
- await this.writeCarsIDB(cars);
44
- }
45
- else {
46
- const writes = [];
47
- for (const { cid, bytes } of cars) {
48
- const carFilename = join(this.config.dataDir, this.name, `${cid.toString()}.car`);
49
- // console.log('writeCars', carFilename)
50
- writes.push(writeSync(carFilename, bytes));
51
- }
52
- await Promise.all(writes);
53
- }
54
- }
55
- async writeCarsIDB(cars) {
56
- return await this.withDB(async (db) => {
57
- const tx = db.transaction(['cars'], 'readwrite');
58
- for (const { cid, bytes, replaces } of cars) {
59
- await tx.objectStore('cars').put(bytes, cid.toString());
60
- // todo remove old maps
61
- if (replaces) {
62
- await tx.objectStore('cars').delete(replaces.toString());
63
- }
64
- }
65
- return await tx.done;
66
- });
67
- }
68
- async readCar(carCid) {
69
- if (FORCE_IDB || this.isBrowser) {
70
- return await this.readCarIDB(carCid);
71
- }
72
- else {
73
- const carFilename = join(this.config.dataDir, this.name, `${carCid.toString()}.car`);
74
- const got = readFileSync(carFilename);
75
- // console.log('readCar', carFilename, got.constructor.name)
76
- return got;
77
- }
78
- }
79
- async readCarIDB(carCid) {
80
- return await this.withDB(async (db) => {
81
- const tx = db.transaction(['cars'], 'readonly');
82
- // console.log('getCarReader', carCid)
83
- return await tx.objectStore('cars').get(carCid);
84
- });
85
- }
86
- getHeader() {
87
- if (this.isBrowser) {
88
- return localStorage.getItem(this.config.headerKeyPrefix + this.name);
89
- }
90
- else {
91
- return loadSync(this.headerFilename());
92
- // return null
93
- }
94
- }
95
- async saveHeader(stringValue) {
96
- // console.log('saveHeader', this.isBrowser)
97
- if (this.isBrowser) {
98
- // console.log('localStorage!', this.config.headerKeyPrefix)
99
- return localStorage.setItem(this.config.headerKeyPrefix + this.name, stringValue);
100
- }
101
- else {
102
- // console.log('no localStorage', this.config.dataDir, this.name)
103
- // console.log('saving clock to', this.headerFilename(), stringValue)
104
- try {
105
- await writeSync(this.headerFilename(), stringValue);
106
- }
107
- catch (error) {
108
- console.log('error', error);
109
- }
110
- // console.log('saved clock to', this.headerFilename())
111
- }
112
- }
113
- headerFilename() {
114
- // console.log('headerFilename', this.config.dataDir, this.name)
115
- return join(this.config.dataDir, this.name, 'header.json');
116
- }
117
- }
118
- function loadSync(filename) {
119
- try {
120
- return readFileSync(filename, 'utf8').toString();
121
- }
122
- catch (error) {
123
- // console.log('error', error)
124
- return null;
125
- }
126
- }
127
- async function writeSync(fullpath, stringValue) {
128
- await mkdir(dirname(fullpath), { recursive: true });
129
- // writeFileSync(fullpath, stringValue)
130
- await writeFile(fullpath, stringValue);
131
- }
package/dist/src/valet.js DELETED
@@ -1,476 +0,0 @@
1
- import { CarReader } from '@ipld/car';
2
- import { CID } from 'multiformats/cid';
3
- import { sha256 } from 'multiformats/hashes/sha2';
4
- import { parse } from 'multiformats/link';
5
- import * as CBW from '@ipld/car/buffer-writer';
6
- import * as raw from 'multiformats/codecs/raw';
7
- import * as Block from 'multiformats/block';
8
- import * as dagcbor from '@ipld/dag-cbor';
9
- import { openDB } from 'idb';
10
- import cargoQueue from 'async/cargoQueue.js';
11
- // @ts-ignore
12
- // @ts-ignore
13
- import { bf, simpleCompare as compare } from 'prolly-trees/utils';
14
- // @ts-ignore
15
- import { nocache as cache } from 'prolly-trees/cache';
16
- // import { makeGetBlock } from './prolly.js'
17
- import { encrypt, decrypt } from './crypto.js';
18
- import { Buffer } from 'buffer';
19
- // @ts-ignore
20
- import * as codec from 'encrypted-block';
21
- import { create, load } from 'ipld-hashmap';
22
- import { rawSha1 as sha1sync } from './sha1.js';
23
- const chunker = bf(30);
24
- const blockOpts = { cache, chunker, codec: dagcbor, hasher: sha256, compare };
25
- const NO_ENCRYPT = typeof process !== 'undefined' && !!process.env?.NO_ENCRYPT;
26
- // ? process.env.NO_ENCRYPT : import.meta && import.meta.env.VITE_NO_ENCRYPT
27
- export class Valet {
28
- idb = null;
29
- name = null;
30
- uploadQueue = null;
31
- alreadyEnqueued = new Set();
32
- keyMaterial = null;
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);
39
- /**
40
- * Function installed by the database to upload car files
41
- * @type {null|function(string, Uint8Array):Promise<void>}
42
- */
43
- uploadFunction = null;
44
- constructor(name = 'default', keyMaterial) {
45
- this.name = name;
46
- this.setKeyMaterial(keyMaterial);
47
- this.uploadQueue = cargoQueue(async (tasks, callback) => {
48
- // console.log(
49
- // 'queue worker',
50
- // tasks.length,
51
- // tasks.reduce((acc, t) => acc + t.value.length, 0)
52
- // )
53
- if (this.uploadFunction) {
54
- // todo we can coalesce these into a single car file
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
- }
63
- }
64
- callback();
65
- });
66
- this.uploadQueue.drain(async () => {
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
- });
78
- }
79
- getKeyMaterial() {
80
- return this.keyMaterial;
81
- }
82
- setKeyMaterial(km) {
83
- if (km && !NO_ENCRYPT) {
84
- const hex = Uint8Array.from(Buffer.from(km, 'hex'));
85
- this.keyMaterial = km;
86
- const hash = sha1sync(hex);
87
- this.keyId = Buffer.from(hash).toString('hex');
88
- }
89
- else {
90
- this.keyMaterial = null;
91
- this.keyId = 'null';
92
- }
93
- // console.trace('keyId', this.name, this.keyId)
94
- }
95
- /**
96
- * Group the blocks into a car and write it to the valet.
97
- * @param {import('./blockstore.js').InnerBlockstore} innerBlockstore
98
- * @param {Set<string>} cids
99
- * @returns {Promise<void>}
100
- * @memberof Valet
101
- */
102
- async writeTransaction(innerBlockstore, cids) {
103
- if (innerBlockstore.lastCid) {
104
- if (this.keyMaterial) {
105
- // console.log('encrypting car', innerBlockstore.label)
106
- // should we pass cids in instead of iterating frin innerBlockstore?
107
- const newCar = await blocksToEncryptedCarBlock(innerBlockstore.lastCid, innerBlockstore, this.keyMaterial);
108
- await this.parkCar(newCar.cid.toString(), newCar.bytes, cids);
109
- }
110
- else {
111
- const newCar = await blocksToCarBlock(innerBlockstore.lastCid, innerBlockstore);
112
- await this.parkCar(newCar.cid.toString(), newCar.bytes, cids);
113
- }
114
- }
115
- else {
116
- throw new Error('missing lastCid for car header');
117
- }
118
- }
119
- withDB = async (dbWorkFun) => {
120
- if (!this.idb) {
121
- this.idb = await openDB(`fp.${this.keyId}.${this.name}.valet`, 3, {
122
- upgrade(db, oldVersion, newVersion, transaction) {
123
- if (oldVersion < 1) {
124
- db.createObjectStore('cars');
125
- }
126
- }
127
- });
128
- }
129
- return await dbWorkFun(this.idb);
130
- };
131
- /**
132
- * Iterate over all blocks in the store.
133
- *
134
- * @yields {{cid: string, value: Uint8Array}}
135
- * @returns {AsyncGenerator<any, any, any>}
136
- */
137
- async *cids() {
138
- // console.log('valet cids')
139
- // todo use cidMap
140
- // while (cursor) {
141
- // yield { cid: cursor.key, car: cursor.value.car }
142
- // cursor = await cursor.continue()
143
- // }
144
- }
145
- setRootCarCid(cid) {
146
- this.valetRootCarCid = cid;
147
- this.valetRoot = null;
148
- this.valetRootCid = null;
149
- }
150
- // todo memoize this
151
- async getCarCIDForCID(cid) {
152
- // make a car reader for this.valetRootCarCid
153
- if (!this.valetRootCarCid)
154
- return { result: null };
155
- let indexNode;
156
- if (this.valetRoot) {
157
- indexNode = this.valetRoot;
158
- }
159
- else {
160
- const combinedReader = await this.getCombinedReader(this.valetRootCarCid);
161
- if (!this.valetRootCid) {
162
- const root = combinedReader.root.cid;
163
- // console.log('roots', this.instanceId, this.name, root, this.valetRootCarCid, this.valetRootCid)
164
- this.valetRootCid = root;
165
- }
166
- indexNode = await load(combinedReader, this.valetRootCid, {
167
- blockHasher: blockOpts.hasher,
168
- blockCodec: blockOpts.codec
169
- });
170
- }
171
- const got = await indexNode.get(cid);
172
- // console.log('getCarCIDForCID', cid, got)
173
- return { result: got };
174
- }
175
- async getCombinedReader(carCid) {
176
- let carMapReader;
177
- if (this.valetRootCarCid) {
178
- // todo only need this if we are cold starting
179
- carMapReader = await this.getCarReader(this.valetRootCarCid);
180
- }
181
- const theseValetCidBlocks = this.valetCidBlocks;
182
- // console.log('theseValetCidBlocks', theseValetCidBlocks)
183
- const combinedReader = {
184
- root: carMapReader?.root,
185
- put: async (cid, bytes) => {
186
- // console.log('mapPut', cid, bytes.length)
187
- return await theseValetCidBlocks.put(cid, bytes);
188
- },
189
- get: async (cid) => {
190
- // console.log('mapGet', cid)
191
- try {
192
- const got = await theseValetCidBlocks.get(cid);
193
- return got.bytes;
194
- }
195
- catch (e) {
196
- // console.log('get from car', cid, carMapReader)
197
- if (!carMapReader)
198
- throw e;
199
- const bytes = await carMapReader.get(cid);
200
- await theseValetCidBlocks.put(cid, bytes);
201
- // console.log('mapGet', cid, bytes.length, bytes.constructor.name)
202
- return bytes;
203
- }
204
- }
205
- };
206
- return combinedReader;
207
- }
208
- /**
209
- *
210
- * @param {string} carCid
211
- * @param {*} value
212
- */
213
- async parkCar(carCid, value, cids) {
214
- // console.log('parkCar', this.instanceId, this.name, carCid, cids)
215
- const combinedReader = await this.getCombinedReader(carCid);
216
- const mapNode = await addCidsToCarIndex(combinedReader, this.valetRoot, this.valetRootCid, Array.from(cids).map(cid => ({ key: cid.toString(), value: carCid.toString() })));
217
- this.valetRoot = mapNode;
218
- this.valetRootCid = mapNode.cid;
219
- // make a block set with all the cids of the map
220
- const saveValetBlocks = new VMemoryBlockstore(); // todo this blockstore should read from the last valetCid car also
221
- for await (const cidx of mapNode.cids()) {
222
- const bytes = await combinedReader.get(cidx);
223
- saveValetBlocks.put(cidx, bytes);
224
- }
225
- let newValetCidCar;
226
- if (this.keyMaterial) {
227
- newValetCidCar = await blocksToEncryptedCarBlock(this.valetRootCid, saveValetBlocks, this.keyMaterial);
228
- }
229
- else {
230
- newValetCidCar = await blocksToCarBlock(this.valetRootCid, saveValetBlocks);
231
- }
232
- // console.log('newValetCidCar', this.name, Math.floor(newValetCidCar.bytes.length / 1024))
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
244
- }
245
- ]);
246
- this.valetRootCarCid = newValetCidCar.cid; // goes to clock
247
- // console.log('parked car', carCid, value.length, Array.from(cids))
248
- // upload to web3.storage if we have credentials
249
- if (this.uploadFunction) {
250
- if (this.alreadyEnqueued.has(carCid)) {
251
- // console.log('already enqueued', carCid)
252
- return;
253
- }
254
- // don't await this, it will be done in the queue
255
- // console.log('add to queue', carCid, value.length)
256
- this.uploadQueue.push({ carCid, value });
257
- this.alreadyEnqueued.add(carCid);
258
- }
259
- else {
260
- // console.log('no upload function', carCid, value.length, this.uploadFunction)
261
- }
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
- remoteBlockFunction = null;
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 ??? todo
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;
315
- }
316
- }
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
- }
327
- }
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);
340
- }
341
- }
342
- export const blocksToCarBlock = async (rootCids, blocks) => {
343
- // console.log('blocksToCarBlock', rootCids, blocks.constructor.name)
344
- let size = 0;
345
- if (!Array.isArray(rootCids)) {
346
- rootCids = [rootCids];
347
- }
348
- const headerSize = CBW.headerLength({ roots: rootCids });
349
- size += headerSize;
350
- if (!Array.isArray(blocks)) {
351
- blocks = Array.from(blocks.entries());
352
- }
353
- for (const { cid, bytes } of blocks) {
354
- // console.log(cid, bytes)
355
- size += CBW.blockLength({ cid, bytes });
356
- }
357
- const buffer = new Uint8Array(size);
358
- const writer = await CBW.createWriter(buffer, { headerSize });
359
- for (const cid of rootCids) {
360
- writer.addRoot(cid);
361
- }
362
- for (const { cid, bytes } of blocks) {
363
- writer.write({ cid, bytes });
364
- }
365
- await writer.close();
366
- return await Block.encode({ value: writer.bytes, hasher: sha256, codec: raw });
367
- };
368
- export const blocksToEncryptedCarBlock = async (innerBlockStoreClockRootCid, blocks, keyMaterial) => {
369
- const encryptionKey = Buffer.from(keyMaterial, 'hex');
370
- const encryptedBlocks = [];
371
- const theCids = [];
372
- for (const { cid } of blocks.entries()) {
373
- theCids.push(cid.toString());
374
- }
375
- // console.log('encrypting', theCids.length, 'blocks', theCids.includes(innerBlockStoreClockRootCid.toString()))
376
- // console.log('cids', theCids, innerBlockStoreClockRootCid.toString())
377
- let last;
378
- for await (const block of encrypt({
379
- cids: theCids,
380
- get: async (cid) => blocks.get(cid),
381
- key: encryptionKey,
382
- hasher: sha256,
383
- chunker,
384
- cache,
385
- // codec: dagcbor, // should be crypto?
386
- root: innerBlockStoreClockRootCid
387
- })) {
388
- encryptedBlocks.push(block);
389
- last = block;
390
- }
391
- // console.log('last', last.cid.toString(), 'for clock', innerBlockStoreClockRootCid.toString())
392
- const encryptedCar = await blocksToCarBlock(last.cid, encryptedBlocks);
393
- return encryptedCar;
394
- };
395
- // { root, get, key, cache, chunker, hasher }
396
- const memoizeDecryptedCarBlocks = new Map();
397
- const blocksFromEncryptedCarBlock = async (cid, get, keyMaterial) => {
398
- if (memoizeDecryptedCarBlocks.has(cid.toString())) {
399
- return memoizeDecryptedCarBlocks.get(cid.toString());
400
- }
401
- else {
402
- const blocksPromise = (async () => {
403
- const decryptionKey = Buffer.from(keyMaterial, 'hex');
404
- // console.log('decrypting', keyMaterial, cid.toString())
405
- const cids = new Set();
406
- const decryptedBlocks = [];
407
- for await (const block of decrypt({
408
- root: cid,
409
- get,
410
- key: decryptionKey,
411
- chunker,
412
- hasher: sha256,
413
- cache
414
- // codec: dagcbor
415
- })) {
416
- decryptedBlocks.push(block);
417
- cids.add(block.cid.toString());
418
- }
419
- return { blocks: decryptedBlocks, cids };
420
- })();
421
- memoizeDecryptedCarBlocks.set(cid.toString(), blocksPromise);
422
- return blocksPromise;
423
- }
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
- }