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