@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/blockstore.js
DELETED
@@ -1,283 +0,0 @@
|
|
1
|
-
import { parse } from 'multiformats/link'
|
2
|
-
import { CID } from 'multiformats'
|
3
|
-
import { Valet } from './valet.js'
|
4
|
-
|
5
|
-
// const sleep = ms => new Promise(r => setTimeout(r, ms))
|
6
|
-
|
7
|
-
const husherMap = new Map()
|
8
|
-
const husher = (id, workFn) => {
|
9
|
-
if (!husherMap.has(id)) {
|
10
|
-
husherMap.set(
|
11
|
-
id,
|
12
|
-
workFn().finally(() => setTimeout(() => husherMap.delete(id), 100))
|
13
|
-
)
|
14
|
-
}
|
15
|
-
return husherMap.get(id)
|
16
|
-
}
|
17
|
-
|
18
|
-
/**
|
19
|
-
* @typedef {{ get: (link: import('../src/link').AnyLink) => Promise<AnyBlock | undefined> }} BlockFetcher
|
20
|
-
*/
|
21
|
-
|
22
|
-
/**
|
23
|
-
* @typedef {Object} AnyBlock
|
24
|
-
* @property {import('./link').AnyLink} cid - The CID of the block
|
25
|
-
* @property {Uint8Array} bytes - The block's data
|
26
|
-
*
|
27
|
-
* @typedef {Object} Blockstore
|
28
|
-
* @property {function(import('./link').AnyLink): Promise<AnyBlock|undefined>} get - A function to retrieve a block by CID
|
29
|
-
* @property {function(import('./link').AnyLink, Uint8Array): Promise<void>} put - A function to store a block's data and CID
|
30
|
-
*
|
31
|
-
* A blockstore that caches writes to a transaction and only persists them when committed.
|
32
|
-
*/
|
33
|
-
export class TransactionBlockstore {
|
34
|
-
/** @type {Map<string, Uint8Array>} */
|
35
|
-
committedBlocks = new Map()
|
36
|
-
|
37
|
-
/** @type {Valet} */
|
38
|
-
valet = null
|
39
|
-
|
40
|
-
instanceId = 'blkz.' + Math.random().toString(36).substring(2, 4)
|
41
|
-
inflightTransactions = new Set()
|
42
|
-
syncs = new Set()
|
43
|
-
|
44
|
-
constructor (name, config) {
|
45
|
-
if (name) {
|
46
|
-
this.valet = new Valet(name, config)
|
47
|
-
this.ready = this.valet.ready
|
48
|
-
} else {
|
49
|
-
this.ready = Promise.resolve()
|
50
|
-
}
|
51
|
-
this.remoteBlockFunction = null
|
52
|
-
}
|
53
|
-
|
54
|
-
/**
|
55
|
-
* Get a block from the store.
|
56
|
-
*
|
57
|
-
* @param {import('./link').AnyLink} cid
|
58
|
-
* @returns {Promise<AnyBlock | undefined>}
|
59
|
-
*/
|
60
|
-
async get (cid) {
|
61
|
-
const key = cid.toString()
|
62
|
-
// it is safe to read from the in-flight transactions becauase they are immutable
|
63
|
-
const bytes = await Promise.any([this.transactionsGet(key), this.committedGet(key)]).catch(e => {
|
64
|
-
console.log('get error', cid.toString(), e)
|
65
|
-
return this.networkGet(key)
|
66
|
-
})
|
67
|
-
if (!bytes) throw new Error('Missing block: ' + key)
|
68
|
-
return { cid, bytes }
|
69
|
-
}
|
70
|
-
|
71
|
-
// this iterates over the in-flight transactions
|
72
|
-
// and returns the first matching block it finds
|
73
|
-
async transactionsGet (key) {
|
74
|
-
for (const transaction of this.inflightTransactions) {
|
75
|
-
const got = await transaction.get(key)
|
76
|
-
if (got && got.bytes) return got.bytes
|
77
|
-
}
|
78
|
-
throw new Error('Missing block: ' + key)
|
79
|
-
}
|
80
|
-
|
81
|
-
async committedGet (key) {
|
82
|
-
const old = this.committedBlocks.get(key)
|
83
|
-
// console.log('committedGet: ' + key + ' ' + this.instanceId, old.length)
|
84
|
-
if (old) return old
|
85
|
-
if (!this.valet) throw new Error('Missing block: ' + key)
|
86
|
-
const got = await this.valet.getValetBlock(key)
|
87
|
-
this.committedBlocks.set(key, got)
|
88
|
-
return got
|
89
|
-
}
|
90
|
-
|
91
|
-
async clearCommittedCache () {
|
92
|
-
this.committedBlocks.clear()
|
93
|
-
}
|
94
|
-
|
95
|
-
async networkGet (key) {
|
96
|
-
if (this.remoteBlockFunction) {
|
97
|
-
const value = await husher(key, async () => await this.remoteBlockFunction(key))
|
98
|
-
if (value) {
|
99
|
-
// console.log('networkGot: ' + key, value.length)
|
100
|
-
doTransaction('networkGot: ' + key, this, async innerBlockstore => {
|
101
|
-
await innerBlockstore.put(CID.parse(key), value)
|
102
|
-
})
|
103
|
-
return value
|
104
|
-
}
|
105
|
-
} else {
|
106
|
-
return false
|
107
|
-
}
|
108
|
-
}
|
109
|
-
|
110
|
-
/**
|
111
|
-
* Add a block to the store. Usually bound to a transaction by a closure.
|
112
|
-
* It sets the lastCid property to the CID of the block that was put.
|
113
|
-
* This is used by the transaction as the head of the car when written to the valet.
|
114
|
-
* We don't have to worry about which transaction we are when we are here because
|
115
|
-
* we are the transactionBlockstore.
|
116
|
-
*
|
117
|
-
* @param {import('./link').AnyLink} cid
|
118
|
-
* @param {Uint8Array} bytes
|
119
|
-
*/
|
120
|
-
put (cid, bytes) {
|
121
|
-
throw new Error('use a transaction to put')
|
122
|
-
}
|
123
|
-
|
124
|
-
/**
|
125
|
-
* Iterate over all blocks in the store.
|
126
|
-
*
|
127
|
-
* @yields {{cid: string, bytes: Uint8Array}}
|
128
|
-
* @returns {AsyncGenerator<any, any, any>}
|
129
|
-
*/
|
130
|
-
async * entries () {
|
131
|
-
for (const transaction of this.inflightTransactions) {
|
132
|
-
for (const [cid, bytes] of transaction.entries()) { // test for this?
|
133
|
-
yield { cid: cid.toString(), bytes }
|
134
|
-
}
|
135
|
-
}
|
136
|
-
for (const [str, bytes] of this.committedBlocks) {
|
137
|
-
yield { cid: str, bytes }
|
138
|
-
}
|
139
|
-
if (this.valet) {
|
140
|
-
for await (const { cid } of this.valet.cids()) {
|
141
|
-
yield { cid }
|
142
|
-
}
|
143
|
-
}
|
144
|
-
}
|
145
|
-
|
146
|
-
/**
|
147
|
-
* Begin a transaction. Ensures the uncommited blocks are empty at the begining.
|
148
|
-
* Returns the blocks to read and write during the transaction.
|
149
|
-
* @returns {InnerBlockstore}
|
150
|
-
* @memberof TransactionBlockstore
|
151
|
-
*/
|
152
|
-
begin (label = '') {
|
153
|
-
const innerTransactionBlockstore = new InnerBlockstore(label, this)
|
154
|
-
this.inflightTransactions.add(innerTransactionBlockstore)
|
155
|
-
return innerTransactionBlockstore
|
156
|
-
}
|
157
|
-
|
158
|
-
/**
|
159
|
-
* Commit the transaction. Writes the blocks to the store.
|
160
|
-
* @returns {Promise<void>}
|
161
|
-
* @memberof TransactionBlockstore
|
162
|
-
*/
|
163
|
-
async commit (innerBlockstore, doSync = true) {
|
164
|
-
// console.log('commit', doSync, innerBlockstore.label)
|
165
|
-
await this.doCommit(innerBlockstore)
|
166
|
-
if (doSync) {
|
167
|
-
// const all =
|
168
|
-
// console.log('syncing', innerBlockstore.label)
|
169
|
-
await Promise.all([...this.syncs].map(async sync => sync.sendUpdate(innerBlockstore).catch(e => {
|
170
|
-
console.error('sync error, cancelling', e)
|
171
|
-
sync.destroy()
|
172
|
-
})))
|
173
|
-
}
|
174
|
-
}
|
175
|
-
|
176
|
-
// first get the transaction blockstore from the map of transaction blockstores
|
177
|
-
// then copy it to committedBlocks
|
178
|
-
// then write the transaction blockstore to a car
|
179
|
-
// then write the car to the valet
|
180
|
-
// then remove the transaction blockstore from the map of transaction blockstores
|
181
|
-
doCommit = async innerBlockstore => {
|
182
|
-
const cids = new Set()
|
183
|
-
for (const { cid, bytes } of innerBlockstore.entries()) {
|
184
|
-
const stringCid = cid.toString()
|
185
|
-
if (this.committedBlocks.has(stringCid)) {
|
186
|
-
// console.log('Duplicate block: ' + stringCid) // todo some of this can be avoided, cost is extra size on car files
|
187
|
-
} else {
|
188
|
-
this.committedBlocks.set(stringCid, bytes)
|
189
|
-
cids.add(stringCid)
|
190
|
-
}
|
191
|
-
}
|
192
|
-
// console.log(innerBlockstore.label, 'committing', cids.size, 'blocks', [...cids].map(cid => cid.toString()), this.valet)
|
193
|
-
if (cids.size > 0 && this.valet) {
|
194
|
-
await this.valet.writeTransaction(innerBlockstore, cids)
|
195
|
-
}
|
196
|
-
}
|
197
|
-
|
198
|
-
/**
|
199
|
-
* Retire the transaction. Clears the uncommited blocks.
|
200
|
-
* @returns {void}
|
201
|
-
* @memberof TransactionBlockstore
|
202
|
-
*/
|
203
|
-
retire (innerBlockstore) {
|
204
|
-
this.inflightTransactions.delete(innerBlockstore)
|
205
|
-
}
|
206
|
-
}
|
207
|
-
|
208
|
-
/**
|
209
|
-
* Runs a function on an inner blockstore, then persists the change to a car writer
|
210
|
-
* or other outer blockstore.
|
211
|
-
* @param {string} label
|
212
|
-
* @param {TransactionBlockstore} blockstore
|
213
|
-
* @param {(innerBlockstore: Blockstore) => Promise<any>} doFun
|
214
|
-
* @returns {Promise<any>}
|
215
|
-
* @memberof TransactionBlockstore
|
216
|
-
*/
|
217
|
-
export const doTransaction = async (label, blockstore, doFun, doSync = true) => {
|
218
|
-
// @ts-ignore
|
219
|
-
if (!blockstore.commit) return await doFun(blockstore)
|
220
|
-
// @ts-ignore
|
221
|
-
const innerBlockstore = blockstore.begin(label)
|
222
|
-
try {
|
223
|
-
const result = await doFun(innerBlockstore)
|
224
|
-
// console.log('doTransaction', label, 'result', result.head)
|
225
|
-
if (result && result.head) { innerBlockstore.head = result.head }
|
226
|
-
// pass the latest clock head for writing to the valet
|
227
|
-
// @ts-ignore
|
228
|
-
await blockstore.commit(innerBlockstore, doSync)
|
229
|
-
return result
|
230
|
-
} catch (e) {
|
231
|
-
console.error(`Transaction ${label} failed`, e, e.stack)
|
232
|
-
throw e
|
233
|
-
} finally {
|
234
|
-
// @ts-ignore
|
235
|
-
blockstore.retire(innerBlockstore)
|
236
|
-
}
|
237
|
-
}
|
238
|
-
|
239
|
-
export class InnerBlockstore {
|
240
|
-
/** @type {Map<string, Uint8Array>} */
|
241
|
-
blocks = new Map()
|
242
|
-
head = []
|
243
|
-
lastCid = null
|
244
|
-
label = ''
|
245
|
-
parentBlockstore = null
|
246
|
-
|
247
|
-
constructor (label, parentBlockstore) {
|
248
|
-
this.label = label
|
249
|
-
this.parentBlockstore = parentBlockstore
|
250
|
-
}
|
251
|
-
|
252
|
-
/**
|
253
|
-
* @param {import('./link').AnyLink} cid
|
254
|
-
* @returns {Promise<AnyBlock | undefined>}
|
255
|
-
*/
|
256
|
-
async get (cid) {
|
257
|
-
const key = cid.toString()
|
258
|
-
let bytes = this.blocks.get(key)
|
259
|
-
if (bytes) {
|
260
|
-
return { cid, bytes }
|
261
|
-
}
|
262
|
-
bytes = await this.parentBlockstore.committedGet(key)
|
263
|
-
if (bytes) {
|
264
|
-
return { cid, bytes }
|
265
|
-
}
|
266
|
-
}
|
267
|
-
|
268
|
-
/**
|
269
|
-
* @param {import('./link').AnyLink} cid
|
270
|
-
* @param {Uint8Array} bytes
|
271
|
-
*/
|
272
|
-
async put (cid, bytes) {
|
273
|
-
// console.log('put', cid)
|
274
|
-
this.blocks.set(cid.toString(), bytes)
|
275
|
-
this.lastCid = cid
|
276
|
-
}
|
277
|
-
|
278
|
-
* entries () {
|
279
|
-
for (const [str, bytes] of this.blocks) {
|
280
|
-
yield { cid: parse(str), bytes }
|
281
|
-
}
|
282
|
-
}
|
283
|
-
}
|