@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/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
|
-
}
|