@fireproof/core 0.8.0 → 0.10.1-dev
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +5 -184
- package/dist/fireproof.browser.js +18879 -0
- package/dist/fireproof.browser.js.map +7 -0
- package/dist/fireproof.cjs.js +9305 -0
- package/dist/fireproof.cjs.js.map +7 -0
- package/dist/fireproof.esm.js +9295 -0
- package/dist/fireproof.esm.js.map +7 -0
- package/package.json +57 -105
- package/dist/blockstore.js +0 -268
- package/dist/clock.js +0 -459
- package/dist/crypto.js +0 -63
- package/dist/database.js +0 -434
- package/dist/db-index.js +0 -403
- package/dist/encrypted-block.js +0 -48
- package/dist/fireproof.js +0 -84
- package/dist/import.js +0 -29
- package/dist/listener.js +0 -111
- package/dist/loader.js +0 -13
- package/dist/prolly.js +0 -405
- package/dist/remote.js +0 -102
- package/dist/sha1.js +0 -74
- package/dist/src/fireproof.d.ts +0 -472
- package/dist/src/fireproof.js +0 -81191
- package/dist/src/fireproof.js.map +0 -1
- package/dist/src/fireproof.mjs +0 -81186
- package/dist/src/fireproof.mjs.map +0 -1
- package/dist/storage/base.js +0 -426
- package/dist/storage/blocksToEncryptedCarBlock.js +0 -144
- package/dist/storage/browser.js +0 -62
- package/dist/storage/filesystem.js +0 -67
- package/dist/storage/rest.js +0 -57
- package/dist/storage/ucan.js +0 -0
- package/dist/storage/utils.js +0 -144
- package/dist/sync.js +0 -218
- package/dist/utils.js +0 -16
- package/dist/valet.js +0 -102
- package/src/blockstore.js +0 -283
- package/src/clock.js +0 -486
- package/src/crypto.js +0 -70
- package/src/database.js +0 -469
- package/src/db-index.js +0 -426
- package/src/encrypted-block.js +0 -57
- package/src/fireproof.js +0 -98
- package/src/import.js +0 -34
- package/src/link.d.ts +0 -3
- package/src/loader.js +0 -16
- package/src/prolly.js +0 -445
- package/src/remote.js +0 -113
- package/src/sha1.js +0 -83
- package/src/storage/base.js +0 -463
- package/src/storage/browser.js +0 -67
- package/src/storage/filesystem.js +0 -73
- package/src/storage/rest.js +0 -59
- package/src/storage/ucan.js +0 -0
- package/src/storage/utils.js +0 -152
- package/src/sync.js +0 -237
- package/src/valet.js +0 -105
package/dist/storage/base.js
DELETED
@@ -1,426 +0,0 @@
|
|
1
|
-
import randomBytes from 'randombytes';
|
2
|
-
// import { randomBytes } from 'crypto'
|
3
|
-
import { CarReader } from '@ipld/car';
|
4
|
-
import { CID } from 'multiformats/cid';
|
5
|
-
import { sha256 } from 'multiformats/hashes/sha2';
|
6
|
-
import * as Block from 'multiformats/block';
|
7
|
-
import * as dagcbor from '@ipld/dag-cbor';
|
8
|
-
// @ts-ignore
|
9
|
-
import { bf, simpleCompare as compare } from 'prolly-trees/utils';
|
10
|
-
// @ts-ignore
|
11
|
-
import { nocache as cache } from 'prolly-trees/cache';
|
12
|
-
import { Buffer } from 'buffer';
|
13
|
-
import { rawSha1 as sha1sync } from '../sha1.js';
|
14
|
-
// @ts-ignore
|
15
|
-
import * as codec from '../encrypted-block.js';
|
16
|
-
import { blocksToEncryptedCarBlock, blocksToCarBlock, blocksFromEncryptedCarBlock, VMemoryBlockstore } from './utils.js';
|
17
|
-
const chunker = bf(30);
|
18
|
-
const blockOpts = { cache, chunker, codec: dagcbor, hasher: sha256, compare };
|
19
|
-
const NO_ENCRYPT = typeof process !== 'undefined' && !!process.env?.NO_ENCRYPT;
|
20
|
-
const NOT_IMPL = true;
|
21
|
-
class Base {
|
22
|
-
static format = '0.8';
|
23
|
-
lastCar = null;
|
24
|
-
carLog = [];
|
25
|
-
keyMaterial = null;
|
26
|
-
keyId = 'null';
|
27
|
-
readonly = false;
|
28
|
-
instanceId = Math.random().toString(36).slice(2);
|
29
|
-
constructor(name, config = {}) {
|
30
|
-
this.name = name;
|
31
|
-
this.config = config;
|
32
|
-
if (!this.config.branches) {
|
33
|
-
this.config.branches = {
|
34
|
-
main: { readonly: false }
|
35
|
-
};
|
36
|
-
}
|
37
|
-
this.ready = this.getHeaders().then(blocksReady => {
|
38
|
-
// console.log('blocksReady base', this.name, blocksReady)
|
39
|
-
return blocksReady;
|
40
|
-
});
|
41
|
-
}
|
42
|
-
setLastCar(car) {
|
43
|
-
this.lastCar = car;
|
44
|
-
this.carLog.unshift(car);
|
45
|
-
}
|
46
|
-
setKeyMaterial(km) {
|
47
|
-
if (km && !NO_ENCRYPT) {
|
48
|
-
const hex = Uint8Array.from(Buffer.from(km, 'hex'));
|
49
|
-
this.keyMaterial = km;
|
50
|
-
const hash = sha1sync(hex);
|
51
|
-
this.keyId = Buffer.from(hash).toString('hex');
|
52
|
-
}
|
53
|
-
else {
|
54
|
-
this.keyMaterial = null;
|
55
|
-
this.keyId = 'null';
|
56
|
-
}
|
57
|
-
}
|
58
|
-
async compact(clock) {
|
59
|
-
if (this.readonly)
|
60
|
-
return;
|
61
|
-
if (clock.length !== 1) {
|
62
|
-
throw new Error(`Compacting with clock length ${clock.length} instead of 1. To merge the clock, apply an update to the database first.`);
|
63
|
-
}
|
64
|
-
const cidMap = await this.getCidCarMap();
|
65
|
-
const dataCids = new Set([...cidMap.keys()].filter(cid => cid[0] !== '_').map(cid => CID.parse(cid)));
|
66
|
-
const allBlocks = new Map();
|
67
|
-
for (const cid of dataCids) {
|
68
|
-
const block = await this.getLoaderBlock(cid);
|
69
|
-
allBlocks.set(cid, block.block);
|
70
|
-
}
|
71
|
-
cidMap.clear();
|
72
|
-
let lastCid = clock[0];
|
73
|
-
const blocks = {
|
74
|
-
head: clock,
|
75
|
-
lastCid,
|
76
|
-
get: cid => allBlocks.get(cid.toString()),
|
77
|
-
put: async (cid, block) => {
|
78
|
-
allBlocks.set(cid.toString(), block);
|
79
|
-
lastCid = cid.toString();
|
80
|
-
}
|
81
|
-
};
|
82
|
-
// const lastCompactCar =
|
83
|
-
await this.parkCar(blocks, dataCids); // todo this should remove old cars from the cid car map
|
84
|
-
// console.log('compact', this.name, lastCompactCar.cid, blocks.lastCid.toString(), dataCids.length)
|
85
|
-
// await this.setLastCompact(lastCompactCar.cid)
|
86
|
-
}
|
87
|
-
async parkCar(innerBlockstore, cids) {
|
88
|
-
// console.log('parkCar', this.instanceId, this.name, this.readonly)
|
89
|
-
if (this.readonly)
|
90
|
-
return;
|
91
|
-
// console.log('parkCar', this.name, this.carLog, innerBlockstore.head)
|
92
|
-
const value = { fp: { last: innerBlockstore.lastCid, clock: innerBlockstore.head, cars: this.carLog } };
|
93
|
-
const header = await Block.encode({ value, hasher: blockOpts.hasher, codec: blockOpts.codec });
|
94
|
-
await innerBlockstore.put(header.cid, header.bytes);
|
95
|
-
cids.add(header.cid.toString());
|
96
|
-
let newCar;
|
97
|
-
if (this.keyMaterial) {
|
98
|
-
// console.log('encrypting car', innerBlockstore.label)
|
99
|
-
newCar = await blocksToEncryptedCarBlock(innerBlockstore.lastCid, innerBlockstore, this.keyMaterial, [...cids]);
|
100
|
-
}
|
101
|
-
else {
|
102
|
-
// todo should we pass cids in instead of iterating innerBlockstore?
|
103
|
-
newCar = await blocksToCarBlock(innerBlockstore.lastCid, innerBlockstore);
|
104
|
-
}
|
105
|
-
return await this.saveCar(newCar.cid.toString(), newCar.bytes);
|
106
|
-
}
|
107
|
-
async saveCar(carCid, value) {
|
108
|
-
// add the car cid to our in memory car list
|
109
|
-
this.carLog.unshift(carCid);
|
110
|
-
this.lastCar = carCid;
|
111
|
-
// console.log('saveCar', this.name, carCid, this.carLog.length)
|
112
|
-
await this.writeCars([
|
113
|
-
{
|
114
|
-
cid: carCid,
|
115
|
-
bytes: value
|
116
|
-
}
|
117
|
-
]);
|
118
|
-
}
|
119
|
-
async applyHeaders(headers) {
|
120
|
-
// console.log('applyHeaders', headers.index)
|
121
|
-
this.headers = headers;
|
122
|
-
// console.log('before applied', this.instanceId, this.name, this.keyMaterial, this.valetRootCarCid)
|
123
|
-
for (const [, header] of Object.entries(headers)) {
|
124
|
-
if (header) {
|
125
|
-
// console.log('applyHeaders', this.instanceId, this.name, header.key, header.car)
|
126
|
-
header.key && this.setKeyMaterial(header.key);
|
127
|
-
// this.setCarCidMapCarCid(header.car) // instead we should just extract the list of cars from the car
|
128
|
-
const carHeader = await this.readHeaderCar(header.car);
|
129
|
-
// console.log('carHeader', this.name, carHeader)
|
130
|
-
this.carLog = carHeader.cars || [];
|
131
|
-
// console.log('stored carHeader', this.name, this.config.type, this.carLog)
|
132
|
-
// this.lastCar = header.car // ?
|
133
|
-
if (header.car) {
|
134
|
-
// console.log('header.car', header.car, this.blocks.valet.primary.carLog)
|
135
|
-
this.setLastCar(header.car);
|
136
|
-
}
|
137
|
-
header.clock = carHeader.clock.map(c => c.toString());
|
138
|
-
}
|
139
|
-
}
|
140
|
-
if (!this.keyMaterial) {
|
141
|
-
const nullKey = this.config.key === null;
|
142
|
-
if (nullKey || this.config.key) {
|
143
|
-
this.setKeyMaterial(this.config.key);
|
144
|
-
}
|
145
|
-
else {
|
146
|
-
this.setKeyMaterial(randomBytes(32).toString('hex'));
|
147
|
-
}
|
148
|
-
}
|
149
|
-
// console.log('applied', this.instanceId, this.name, this.keyMaterial, this.valetRootCarCid)
|
150
|
-
}
|
151
|
-
async getHeaders() {
|
152
|
-
const headers = {};
|
153
|
-
for (const [branch] of Object.entries(this.config.branches)) {
|
154
|
-
const got = await this.loadHeader(branch);
|
155
|
-
headers[branch] = got;
|
156
|
-
}
|
157
|
-
await this.applyHeaders(headers);
|
158
|
-
return headers;
|
159
|
-
}
|
160
|
-
loadHeader(branch = 'main') {
|
161
|
-
if (NOT_IMPL)
|
162
|
-
throw new Error('not implemented');
|
163
|
-
return {};
|
164
|
-
}
|
165
|
-
async saveHeader(header) {
|
166
|
-
// this.clock = header.clock
|
167
|
-
// for each branch, save the header
|
168
|
-
// console.log('saveHeader', this.config.branches)
|
169
|
-
// for (const branch of this.branches) {
|
170
|
-
// await this.saveBranchHeader(branch)
|
171
|
-
// }
|
172
|
-
for (const [branch, { readonly }] of Object.entries(this.config.branches)) {
|
173
|
-
if (readonly)
|
174
|
-
continue;
|
175
|
-
// console.log('saveHeader', this.instanceId, this.name, branch, header)
|
176
|
-
await this.writeHeader(branch, this.prepareHeader(header));
|
177
|
-
}
|
178
|
-
}
|
179
|
-
prepareHeader(header, json = true) {
|
180
|
-
header.key = this.keyMaterial;
|
181
|
-
header.car = this.lastCar?.toString();
|
182
|
-
// console.log('prepareHeader', this.instanceId, this.name, header)
|
183
|
-
return json ? JSON.stringify(header) : header;
|
184
|
-
}
|
185
|
-
writeHeader(branch, header) {
|
186
|
-
throw new Error('not implemented');
|
187
|
-
}
|
188
|
-
async getCarCIDForCID(cid) {
|
189
|
-
// console.log('getCarCIDForCID', cid, this.carLog, this.config.type)
|
190
|
-
// for each car in the car log
|
191
|
-
for (const carCid of this.carLog) {
|
192
|
-
const reader = await this.getCarReader(carCid);
|
193
|
-
// console.log('getCarCIDForCID', carCid, cid)
|
194
|
-
// if (reader.has(cid)) {
|
195
|
-
// console.log('getCarCIDForCID found', cid)
|
196
|
-
// return { result: carCid }
|
197
|
-
// }
|
198
|
-
for await (const block of reader.entries()) {
|
199
|
-
// console.log('getCarCIDForCID', cid, block.cid.toString())
|
200
|
-
// console.log('getCarCIDForCID', cid, block.cid.toString())
|
201
|
-
if (block.cid.toString() === cid.toString()) {
|
202
|
-
// console.log('getCarCIDForCID found', cid)
|
203
|
-
return { result: carCid };
|
204
|
-
}
|
205
|
-
}
|
206
|
-
}
|
207
|
-
// console.log('getCarCIDForCID not found', cid, this.config.type)
|
208
|
-
return { result: null };
|
209
|
-
// return this.carLog[0]
|
210
|
-
// const cidMap = await this.getCidCarMap()
|
211
|
-
// const carCid = cidMap.get(cid.toString())
|
212
|
-
// if (carCid) {
|
213
|
-
// return { result: carCid }
|
214
|
-
// }
|
215
|
-
// return { result: null }
|
216
|
-
}
|
217
|
-
async readCar(carCid) {
|
218
|
-
if (NOT_IMPL)
|
219
|
-
throw new Error('not implemented');
|
220
|
-
return new Uint8Array(carCid);
|
221
|
-
}
|
222
|
-
async getLoaderBlock(dataCID) {
|
223
|
-
// console.log('getLoaderBlock', dataCID, this.config, this.carLog)
|
224
|
-
const { result: carCid } = await this.getCarCIDForCID(dataCID);
|
225
|
-
// console.log('gotLoaderBlock', dataCID, carCid)
|
226
|
-
if (!carCid) {
|
227
|
-
throw new Error('Missing car for: ' + dataCID);
|
228
|
-
}
|
229
|
-
const reader = await this.getCarReader(carCid);
|
230
|
-
const block = await reader.get(dataCID);
|
231
|
-
// console.log('gotLoaderBlock', dataCID, block.length)
|
232
|
-
return { block, reader, carCid };
|
233
|
-
}
|
234
|
-
// async getLastSynced () {
|
235
|
-
// const metadata = await this.getCidCarMap()
|
236
|
-
// if (metadata.has('_last_sync_head')) {
|
237
|
-
// return JSON.parse(metadata.get('_last_sync_head'))
|
238
|
-
// } else {
|
239
|
-
// return []
|
240
|
-
// }
|
241
|
-
// }
|
242
|
-
// async setLastSynced (lastSynced) {
|
243
|
-
// const metadata = await this.getCidCarMap()
|
244
|
-
// metadata.set('_last_sync_head', JSON.stringify(lastSynced))
|
245
|
-
// // await this.writeMetadata(metadata)
|
246
|
-
// }
|
247
|
-
// async getCompactSince (sinceHead) {
|
248
|
-
// // get the car for the head
|
249
|
-
// // find the location of the car in the metadata car sequence
|
250
|
-
// }
|
251
|
-
/** Private - internal **/
|
252
|
-
async getCidCarMap() {
|
253
|
-
if (this.valetCarCidMap)
|
254
|
-
return this.valetCarCidMap;
|
255
|
-
this.valetCarCidMap = new Map();
|
256
|
-
return this.valetCarCidMap;
|
257
|
-
}
|
258
|
-
async readHeaderCar(carCid) {
|
259
|
-
const carMapReader = await this.getCarReader(carCid);
|
260
|
-
// await this.getWriteableCarReader(carCid)
|
261
|
-
// console.log('readHeaderCar', carCid, carMapReader)
|
262
|
-
// now when we load the root cid from the car, we get our new custom root node
|
263
|
-
const bytes = await carMapReader.get(carMapReader.root.cid);
|
264
|
-
const decoded = await Block.decode({ bytes, hasher: blockOpts.hasher, codec: blockOpts.codec });
|
265
|
-
// @ts-ignore
|
266
|
-
const { fp: { cars, clock } } = decoded.value;
|
267
|
-
return { cars, clock, reader: carMapReader };
|
268
|
-
}
|
269
|
-
// todo this is only because parkCar wants a writable reader to put the metadata block
|
270
|
-
// parkCar should handle it's own writeable wrapper, and it should love to be called with
|
271
|
-
// a read only car reader
|
272
|
-
async getWriteableCarReader(carReader) {
|
273
|
-
// console.log('getWriteableCarReader')
|
274
|
-
// const carReader = await this.getCarReader(carCid)
|
275
|
-
// console.log('getWriteableCarReader', carCid, carReader)
|
276
|
-
const theseWriteableBlocks = new VMemoryBlockstore();
|
277
|
-
const combinedReader = {
|
278
|
-
blocks: theseWriteableBlocks,
|
279
|
-
root: carReader?.root,
|
280
|
-
put: async (cid, bytes) => {
|
281
|
-
return await theseWriteableBlocks.put(cid, bytes);
|
282
|
-
},
|
283
|
-
get: async (cid) => {
|
284
|
-
// console.log('getWriteableCarReader get', cid)
|
285
|
-
try {
|
286
|
-
const got = await theseWriteableBlocks.get(cid);
|
287
|
-
return got.bytes;
|
288
|
-
}
|
289
|
-
catch (e) {
|
290
|
-
if (!carReader)
|
291
|
-
throw e;
|
292
|
-
const bytes = await carReader.get(cid);
|
293
|
-
// console.log('getWriteableCarReader', cid, bytes)
|
294
|
-
await theseWriteableBlocks.put(cid, bytes);
|
295
|
-
return bytes;
|
296
|
-
}
|
297
|
-
}
|
298
|
-
};
|
299
|
-
return combinedReader;
|
300
|
-
}
|
301
|
-
carReaderCache = new Map();
|
302
|
-
async getCarReader(carCid) {
|
303
|
-
if (!this.carReaderCache.has(carCid)) {
|
304
|
-
this.carReaderCache.set(carCid, this.getCarReaderImpl(carCid));
|
305
|
-
}
|
306
|
-
return this.carReaderCache.get(carCid);
|
307
|
-
}
|
308
|
-
async getCarReaderImpl(carCid) {
|
309
|
-
carCid = carCid.toString();
|
310
|
-
const carBytes = await this.readCar(carCid);
|
311
|
-
// console.log('getCarReader', this.constructor.name, carCid, carBytes.length)
|
312
|
-
const reader = await CarReader.fromBytes(carBytes);
|
313
|
-
// console.log('getCarReader', carCid, reader._header)
|
314
|
-
if (this.keyMaterial) {
|
315
|
-
const roots = await reader.getRoots();
|
316
|
-
const readerGetWithCodec = async (cid) => {
|
317
|
-
const got = await reader.get(cid);
|
318
|
-
let useCodec = codec;
|
319
|
-
if (cid.toString().indexOf('bafy') === 0) {
|
320
|
-
// @ts-ignore
|
321
|
-
useCodec = dagcbor; // todo this is a dirty check
|
322
|
-
}
|
323
|
-
const decoded = await Block.decode({
|
324
|
-
...got,
|
325
|
-
codec: useCodec,
|
326
|
-
hasher: sha256
|
327
|
-
});
|
328
|
-
return decoded;
|
329
|
-
};
|
330
|
-
const { blocks } = await blocksFromEncryptedCarBlock(roots[0], readerGetWithCodec, this.keyMaterial);
|
331
|
-
const rootBlock = blocks[blocks.length - 1];
|
332
|
-
const blocksIterable = function* () {
|
333
|
-
for (const block of blocks)
|
334
|
-
yield block;
|
335
|
-
};
|
336
|
-
const gat = async (dataCID) => {
|
337
|
-
dataCID = dataCID.toString();
|
338
|
-
return blocks.find(b => b.cid.toString() === dataCID);
|
339
|
-
};
|
340
|
-
return {
|
341
|
-
entries: blocksIterable,
|
342
|
-
root: rootBlock,
|
343
|
-
gat,
|
344
|
-
get: async (dataCID) => {
|
345
|
-
const block = await gat(dataCID);
|
346
|
-
if (block) {
|
347
|
-
return block.bytes;
|
348
|
-
}
|
349
|
-
}
|
350
|
-
};
|
351
|
-
}
|
352
|
-
else {
|
353
|
-
const gat = async (dataCID) => {
|
354
|
-
return await reader.get(CID.parse(dataCID));
|
355
|
-
};
|
356
|
-
return {
|
357
|
-
// blocks,
|
358
|
-
entries: reader.blocks.bind(reader),
|
359
|
-
root: reader.getRoots()[0],
|
360
|
-
gat,
|
361
|
-
get: async (dataCID) => {
|
362
|
-
const gotBlock = await gat(dataCID);
|
363
|
-
if (gotBlock) {
|
364
|
-
return gotBlock.bytes;
|
365
|
-
}
|
366
|
-
}
|
367
|
-
};
|
368
|
-
}
|
369
|
-
}
|
370
|
-
writeCars(cars) { }
|
371
|
-
// sequenceCarMapAppend (theCarMap, carCid) {
|
372
|
-
// // _last_compact
|
373
|
-
// // _last_sync (map per clock? you can find this by looking at a clocks car and it's position in the map)
|
374
|
-
// const oldMark = theCarMap.get('_last_compact') // todo we can track _next_seq directly
|
375
|
-
// // console.log('sequenceCarMapAppend oldMark', oldMark)
|
376
|
-
// const lastCompact = oldMark ? charwise.decode(oldMark) : 0
|
377
|
-
// // start iterating from the last compact point and find the first missing entry.
|
378
|
-
// // then write the carCid to that entry
|
379
|
-
// let next = lastCompact
|
380
|
-
// while (true) {
|
381
|
-
// const key = `_${charwise.encode(next)}`
|
382
|
-
// if (!theCarMap.has(key)) {
|
383
|
-
// console.log('sequenceCarMapAppend', next, key, carCid)
|
384
|
-
// theCarMap.set(key, carCid.toString())
|
385
|
-
// break
|
386
|
-
// } else {
|
387
|
-
// // const got = theCarMap.get(key)
|
388
|
-
// next++
|
389
|
-
// }
|
390
|
-
// }
|
391
|
-
// }
|
392
|
-
// async setLastCompact (lastCompactCarCid) {
|
393
|
-
// console.log('setLastCompact', lastCompactCarCid)
|
394
|
-
// const theCarMap = await this.getCidCarMap()
|
395
|
-
// const oldMark = theCarMap.get('_last_compact')
|
396
|
-
// const lastCompact = oldMark ? charwise.decode(oldMark) : 0
|
397
|
-
// let next = lastCompact
|
398
|
-
// while (true) {
|
399
|
-
// const key = `_${charwise.encode(next)}`
|
400
|
-
// if (!theCarMap.has(key)) {
|
401
|
-
// if (next === 0) {
|
402
|
-
// theCarMap.set('_last_compact', charwise.encode(next))
|
403
|
-
// break
|
404
|
-
// } else {
|
405
|
-
// throw new Error(`last compact point not found ${next} ${key}`)
|
406
|
-
// }
|
407
|
-
// } else {
|
408
|
-
// const got = theCarMap.get(key)
|
409
|
-
// // console.log('setLastCompact', key, got)
|
410
|
-
// if (got === lastCompactCarCid) {
|
411
|
-
// theCarMap.set('_last_compact', charwise.encode(next))
|
412
|
-
// break
|
413
|
-
// }
|
414
|
-
// next++
|
415
|
-
// }
|
416
|
-
// }
|
417
|
-
// }
|
418
|
-
async updateCarCidMap(dataCarCid, cids, head) {
|
419
|
-
// this hydrates the map if it has not been hydrated
|
420
|
-
const theCarMap = await this.getCidCarMap();
|
421
|
-
for (const cid of cids) {
|
422
|
-
theCarMap.set(cid, dataCarCid);
|
423
|
-
}
|
424
|
-
}
|
425
|
-
}
|
426
|
-
export { Base };
|
@@ -1,144 +0,0 @@
|
|
1
|
-
import * as CBW from '@ipld/car/buffer-writer';
|
2
|
-
import * as raw from 'multiformats/codecs/raw';
|
3
|
-
import { encrypt, decrypt } from '../crypto.js';
|
4
|
-
import { parse } from 'multiformats/link';
|
5
|
-
import { sha256 } from 'multiformats/hashes/sha2';
|
6
|
-
import * as Block from 'multiformats/block';
|
7
|
-
import { Buffer } from 'buffer';
|
8
|
-
// @ts-ignore
|
9
|
-
import { bf } from 'prolly-trees/utils';
|
10
|
-
// @ts-ignore
|
11
|
-
import { nocache as cache } from 'prolly-trees/cache';
|
12
|
-
const chunker = bf(30);
|
13
|
-
export async function getEmptyLoader() {
|
14
|
-
const theseWriteableBlocks = new VMemoryBlockstore();
|
15
|
-
return {
|
16
|
-
blocks: theseWriteableBlocks,
|
17
|
-
put: async (cid, bytes) => {
|
18
|
-
return await theseWriteableBlocks.put(cid, bytes);
|
19
|
-
},
|
20
|
-
get: async (cid) => {
|
21
|
-
const got = await theseWriteableBlocks.get(cid);
|
22
|
-
return got.bytes;
|
23
|
-
}
|
24
|
-
};
|
25
|
-
}
|
26
|
-
export class VMemoryBlockstore {
|
27
|
-
/** @type {Map<string, Uint8Array>} */
|
28
|
-
blocks = new Map();
|
29
|
-
instanceId = Math.random().toString(36).slice(2);
|
30
|
-
async get(cid) {
|
31
|
-
const bytes = this.blocks.get(cid.toString());
|
32
|
-
if (!bytes)
|
33
|
-
throw new Error('block not found ' + cid.toString());
|
34
|
-
return { cid, bytes };
|
35
|
-
}
|
36
|
-
/**
|
37
|
-
* @param {any} cid
|
38
|
-
* @param {Uint8Array} bytes
|
39
|
-
*/
|
40
|
-
async put(cid, bytes) {
|
41
|
-
this.blocks.set(cid.toString(), bytes);
|
42
|
-
}
|
43
|
-
*entries() {
|
44
|
-
for (const [str, bytes] of this.blocks) {
|
45
|
-
yield { cid: parse(str), bytes };
|
46
|
-
}
|
47
|
-
}
|
48
|
-
}
|
49
|
-
export const blocksToCarBlock = async (rootCids, blocks) => {
|
50
|
-
// console.log('blocksToCarBlock', rootCids, blocks.constructor.name)
|
51
|
-
let size = 0;
|
52
|
-
if (!Array.isArray(rootCids)) {
|
53
|
-
rootCids = [rootCids];
|
54
|
-
}
|
55
|
-
const headerSize = CBW.headerLength({ roots: rootCids });
|
56
|
-
size += headerSize;
|
57
|
-
if (!Array.isArray(blocks)) {
|
58
|
-
blocks = Array.from(blocks.entries());
|
59
|
-
}
|
60
|
-
for (const { cid, bytes } of blocks) {
|
61
|
-
// console.log(cid, bytes)
|
62
|
-
size += CBW.blockLength({ cid, bytes });
|
63
|
-
}
|
64
|
-
const buffer = new Uint8Array(size);
|
65
|
-
const writer = await CBW.createWriter(buffer, { headerSize });
|
66
|
-
for (const cid of rootCids) {
|
67
|
-
writer.addRoot(cid);
|
68
|
-
}
|
69
|
-
for (const { cid, bytes } of blocks) {
|
70
|
-
writer.write({ cid, bytes });
|
71
|
-
}
|
72
|
-
await writer.close();
|
73
|
-
return await Block.encode({ value: writer.bytes, hasher: sha256, codec: raw });
|
74
|
-
};
|
75
|
-
export const blocksToEncryptedCarBlock = async (innerBlockStoreClockRootCid, blocks, keyMaterial, cids) => {
|
76
|
-
const encryptionKey = Buffer.from(keyMaterial, 'hex');
|
77
|
-
const encryptedBlocks = [];
|
78
|
-
const theCids = cids;
|
79
|
-
// console.trace('blocksToEncryptedCarBlock', blocks)
|
80
|
-
// for (const { cid } of blocks.entries()) {
|
81
|
-
// theCids.push(cid.toString())
|
82
|
-
// }
|
83
|
-
// console.log(
|
84
|
-
// 'encrypting',
|
85
|
-
// theCids.length,
|
86
|
-
// 'blocks',
|
87
|
-
// theCids.includes(innerBlockStoreClockRootCid.toString()),
|
88
|
-
// keyMaterial
|
89
|
-
// )
|
90
|
-
// console.log('cids', theCids, innerBlockStoreClockRootCid.toString())
|
91
|
-
let last;
|
92
|
-
for await (const block of encrypt({
|
93
|
-
cids: theCids,
|
94
|
-
get: async (cid) => {
|
95
|
-
// console.log('getencrypt', cid)
|
96
|
-
const got = blocks.get(cid);
|
97
|
-
// console.log('got', got)
|
98
|
-
return got.block ? ({ cid, bytes: got.block }) : got;
|
99
|
-
},
|
100
|
-
key: encryptionKey,
|
101
|
-
hasher: sha256,
|
102
|
-
chunker,
|
103
|
-
cache,
|
104
|
-
// codec: dagcbor, // should be crypto?
|
105
|
-
root: innerBlockStoreClockRootCid
|
106
|
-
})) {
|
107
|
-
encryptedBlocks.push(block);
|
108
|
-
last = block;
|
109
|
-
}
|
110
|
-
// console.log('last', last.cid.toString(), 'for clock', innerBlockStoreClockRootCid.toString())
|
111
|
-
const encryptedCar = await blocksToCarBlock(last.cid, encryptedBlocks);
|
112
|
-
return encryptedCar;
|
113
|
-
};
|
114
|
-
// { root, get, key, cache, chunker, hasher }
|
115
|
-
const memoizeDecryptedCarBlocks = new Map();
|
116
|
-
export const blocksFromEncryptedCarBlock = async (cid, get, keyMaterial) => {
|
117
|
-
if (memoizeDecryptedCarBlocks.has(cid.toString())) {
|
118
|
-
return memoizeDecryptedCarBlocks.get(cid.toString());
|
119
|
-
}
|
120
|
-
else {
|
121
|
-
const blocksPromise = (async () => {
|
122
|
-
const decryptionKey = Buffer.from(keyMaterial, 'hex');
|
123
|
-
// console.log('decrypting', keyMaterial, cid.toString())
|
124
|
-
const cids = new Set();
|
125
|
-
const decryptedBlocks = [];
|
126
|
-
for await (const block of decrypt({
|
127
|
-
root: cid,
|
128
|
-
get,
|
129
|
-
key: decryptionKey,
|
130
|
-
chunker,
|
131
|
-
hasher: sha256,
|
132
|
-
cache
|
133
|
-
// codec: dagcbor
|
134
|
-
})) {
|
135
|
-
// console.log('decrypted', block.cid.toString())
|
136
|
-
decryptedBlocks.push(block);
|
137
|
-
cids.add(block.cid.toString());
|
138
|
-
}
|
139
|
-
return { blocks: decryptedBlocks, cids };
|
140
|
-
})();
|
141
|
-
memoizeDecryptedCarBlocks.set(cid.toString(), blocksPromise);
|
142
|
-
return blocksPromise;
|
143
|
-
}
|
144
|
-
};
|
package/dist/storage/browser.js
DELETED
@@ -1,62 +0,0 @@
|
|
1
|
-
import { openDB } from 'idb';
|
2
|
-
import { Base } from './base.js';
|
3
|
-
const defaultConfig = {
|
4
|
-
headerKeyPrefix: 'fp.' + Base.format
|
5
|
-
};
|
6
|
-
/* global localStorage */
|
7
|
-
export class Browser extends Base {
|
8
|
-
constructor(name, config = {}) {
|
9
|
-
super(name, Object.assign({}, defaultConfig, config));
|
10
|
-
}
|
11
|
-
withDB = async (dbWorkFun) => {
|
12
|
-
if (!this.idb) {
|
13
|
-
this.idb = await openDB(`fp.${Base.format}.${this.keyId}.${this.name}.valet`, 3, {
|
14
|
-
upgrade(db, oldVersion, newVersion, transaction) {
|
15
|
-
if (oldVersion < 1) {
|
16
|
-
db.createObjectStore('cars');
|
17
|
-
}
|
18
|
-
}
|
19
|
-
});
|
20
|
-
}
|
21
|
-
return await dbWorkFun(this.idb);
|
22
|
-
};
|
23
|
-
async writeCars(cars) {
|
24
|
-
if (this.config.readonly)
|
25
|
-
return;
|
26
|
-
return await this.withDB(async (db) => {
|
27
|
-
const tx = db.transaction(['cars'], 'readwrite');
|
28
|
-
for (const { cid, bytes, replaces } of cars) {
|
29
|
-
await tx.objectStore('cars').put(bytes, cid.toString());
|
30
|
-
// todo remove old maps
|
31
|
-
if (replaces) {
|
32
|
-
await tx.objectStore('cars').delete(replaces.toString());
|
33
|
-
}
|
34
|
-
}
|
35
|
-
return await tx.done;
|
36
|
-
});
|
37
|
-
}
|
38
|
-
async readCar(carCid) {
|
39
|
-
return await this.withDB(async (db) => {
|
40
|
-
const tx = db.transaction(['cars'], 'readonly');
|
41
|
-
// console.log('getCarReader', carCid)
|
42
|
-
return await tx.objectStore('cars').get(carCid);
|
43
|
-
});
|
44
|
-
}
|
45
|
-
loadHeader(branch = 'main') {
|
46
|
-
try {
|
47
|
-
return JSON.parse(localStorage.getItem(this.headerKey(branch)));
|
48
|
-
}
|
49
|
-
catch (e) { }
|
50
|
-
}
|
51
|
-
async writeHeader(branch, header) {
|
52
|
-
if (this.config.readonly)
|
53
|
-
return;
|
54
|
-
try {
|
55
|
-
return localStorage.setItem(this.headerKey(branch), header);
|
56
|
-
}
|
57
|
-
catch (e) { }
|
58
|
-
}
|
59
|
-
headerKey(branch = 'main') {
|
60
|
-
return this.config.headerKeyPrefix + this.name + '.' + branch;
|
61
|
-
}
|
62
|
-
}
|