@fireproof/core 0.3.22 → 0.4.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.
- package/dist/blockstore.js +242 -0
- package/dist/clock.js +355 -0
- package/dist/crypto.js +59 -0
- package/dist/database.js +308 -0
- package/dist/db-index.js +314 -0
- package/dist/fireproof.js +83 -0
- package/dist/hooks/use-fireproof.js +100 -0
- package/dist/listener.js +110 -0
- package/dist/prolly.js +316 -0
- package/dist/sha1.js +74 -0
- package/dist/src/blockstore.js +242 -0
- package/dist/src/clock.js +355 -0
- package/dist/src/crypto.js +59 -0
- package/dist/src/database.js +312 -0
- package/dist/src/db-index.js +314 -0
- package/dist/src/fireproof.d.ts +319 -0
- package/dist/src/fireproof.js +38976 -0
- package/dist/src/fireproof.js.map +1 -0
- package/dist/src/fireproof.mjs +38972 -0
- package/dist/src/fireproof.mjs.map +1 -0
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +19 -14
- package/dist/src/index.js.map +1 -1
- package/dist/src/index.mjs +19 -14
- package/dist/src/index.mjs.map +1 -1
- package/dist/src/listener.js +108 -0
- package/dist/src/prolly.js +319 -0
- package/dist/src/sha1.js +74 -0
- package/dist/src/utils.js +16 -0
- package/dist/src/valet.js +262 -0
- package/dist/test/block.js +57 -0
- package/dist/test/clock.test.js +556 -0
- package/dist/test/db-index.test.js +231 -0
- package/dist/test/fireproof.test.js +444 -0
- package/dist/test/fulltext.test.js +61 -0
- package/dist/test/helpers.js +39 -0
- package/dist/test/hydrator.test.js +142 -0
- package/dist/test/listener.test.js +103 -0
- package/dist/test/prolly.test.js +162 -0
- package/dist/test/proofs.test.js +45 -0
- package/dist/test/reproduce-fixture-bug.test.js +57 -0
- package/dist/test/valet.test.js +56 -0
- package/dist/utils.js +16 -0
- package/dist/valet.js +262 -0
- package/hooks/use-fireproof.js +38 -63
- package/package.json +13 -14
- package/src/blockstore.js +8 -4
- package/src/database.js +338 -0
- package/src/db-index.js +3 -3
- package/src/fireproof.js +65 -322
- package/src/listener.js +10 -8
- package/src/prolly.js +10 -6
- package/src/utils.js +16 -0
- package/src/hydrator.js +0 -54
- package/src/index.js +0 -6
package/src/fireproof.js
CHANGED
@@ -1,343 +1,86 @@
|
|
1
|
-
// @ts-nocheck
|
2
1
|
import randomBytes from 'randombytes'
|
3
|
-
import { visMerkleClock, visMerkleTree, vis, put, get, getAll, eventsSince } from './prolly.js'
|
4
|
-
import { TransactionBlockstore, doTransaction } from './blockstore.js'
|
5
|
-
import charwise from 'charwise'
|
6
2
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
3
|
+
import { Database } from './database.js'
|
4
|
+
import { Listener } from './listener.js'
|
5
|
+
import { DbIndex as Index } from './db-index.js'
|
6
|
+
import { CID } from 'multiformats'
|
7
|
+
import { TransactionBlockstore } from './blockstore.js'
|
8
|
+
import { localGet } from './utils.js'
|
12
9
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
* This is the main class for saving and loading JSON and other documents with the database. You can find additional examples and
|
17
|
-
* usage guides in the repository README.
|
18
|
-
*
|
19
|
-
* @param {import('./blockstore.js').TransactionBlockstore} blocks - The block storage instance to use documents and indexes
|
20
|
-
* @param {CID[]} clock - The Merkle clock head to use for the Fireproof instance.
|
21
|
-
* @param {object} [config] - Optional configuration options for the Fireproof instance.
|
22
|
-
* @param {object} [authCtx] - Optional authorization context object to use for any authentication checks.
|
23
|
-
*
|
24
|
-
*/
|
25
|
-
export class Fireproof {
|
26
|
-
listeners = new Set()
|
10
|
+
export { Index, Listener }
|
11
|
+
|
12
|
+
const parseCID = cid => typeof cid === 'string' ? CID.parse(cid) : cid
|
27
13
|
|
14
|
+
export class Fireproof {
|
28
15
|
/**
|
29
16
|
* @function storage
|
30
17
|
* @memberof Fireproof
|
31
18
|
* Creates a new Fireproof instance with default storage settings
|
32
19
|
* Most apps should use this and not worry about the details.
|
33
20
|
* @static
|
34
|
-
* @returns {
|
35
|
-
*/
|
36
|
-
static storage = (name = 'global') => {
|
37
|
-
const instanceKey = randomBytes(32).toString('hex') // pass null to disable encryption
|
38
|
-
// pick a random key from const validatedKeys
|
39
|
-
// const instanceKey = validatedKeys[Math.floor(Math.random() * validatedKeys.length)]
|
40
|
-
return new Fireproof(new TransactionBlockstore(name, instanceKey), [], { name })
|
41
|
-
}
|
42
|
-
|
43
|
-
constructor (blocks, clock, config, authCtx = {}) {
|
44
|
-
this.name = config?.name || 'global'
|
45
|
-
this.instanceId = `fp.${this.name}.${Math.random().toString(36).substring(2, 7)}`
|
46
|
-
this.blocks = blocks
|
47
|
-
this.clock = clock
|
48
|
-
this.config = config
|
49
|
-
this.authCtx = authCtx
|
50
|
-
this.indexes = new Map()
|
51
|
-
}
|
52
|
-
|
53
|
-
/**
|
54
|
-
* Renders the Fireproof instance as a JSON object.
|
55
|
-
* @returns {Object} - The JSON representation of the Fireproof instance. Includes clock heads for the database and its indexes.
|
56
|
-
* @memberof Fireproof
|
57
|
-
* @instance
|
58
|
-
*/
|
59
|
-
toJSON () {
|
60
|
-
// todo this also needs to return the index roots...
|
61
|
-
return {
|
62
|
-
clock: this.clockToJSON(),
|
63
|
-
name: this.name,
|
64
|
-
key: this.blocks.valet.getKeyMaterial(),
|
65
|
-
indexes: [...this.indexes.values()].map(index => index.toJSON())
|
66
|
-
}
|
67
|
-
}
|
68
|
-
|
69
|
-
/**
|
70
|
-
* Returns the Merkle clock heads for the Fireproof instance.
|
71
|
-
* @returns {string[]} - The Merkle clock heads for the Fireproof instance.
|
72
|
-
* @memberof Fireproof
|
73
|
-
* @instance
|
74
|
-
*/
|
75
|
-
clockToJSON () {
|
76
|
-
return this.clock.map(cid => cid.toString())
|
77
|
-
}
|
78
|
-
|
79
|
-
hydrate ({ clock, name, key }) {
|
80
|
-
this.name = name
|
81
|
-
this.clock = clock
|
82
|
-
this.blocks.valet.setKeyMaterial(key)
|
83
|
-
this.indexBlocks = null
|
84
|
-
}
|
85
|
-
|
86
|
-
/**
|
87
|
-
* Triggers a notification to all listeners
|
88
|
-
* of the Fireproof instance so they can repaint UI, etc.
|
89
|
-
* @returns {Promise<void>}
|
90
|
-
* @memberof Fireproof
|
91
|
-
* @instance
|
21
|
+
* @returns {Database} - a new Fireproof instance
|
92
22
|
*/
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
* @function changesSince
|
105
|
-
* @param {CID[]} [event] - The clock head to retrieve changes since. If null or undefined, retrieves all changes.
|
106
|
-
* @returns {Promise<{rows : Object[], clock: CID[], proof: {}}>} An object containing the rows and the head of the instance's clock.
|
107
|
-
* @memberof Fireproof
|
108
|
-
* @instance
|
109
|
-
*/
|
110
|
-
async changesSince (event) {
|
111
|
-
// console.log('changesSince', this.instanceId, event, this.clock)
|
112
|
-
let rows, dataCIDs, clockCIDs
|
113
|
-
// if (!event) event = []
|
114
|
-
if (event) {
|
115
|
-
const resp = await eventsSince(this.blocks, this.clock, event)
|
116
|
-
const docsMap = new Map()
|
117
|
-
for (const { key, type, value } of resp.result.map(decodeEvent)) {
|
118
|
-
if (type === 'del') {
|
119
|
-
docsMap.set(key, { key, del: true })
|
120
|
-
} else {
|
121
|
-
docsMap.set(key, { key, value })
|
122
|
-
}
|
23
|
+
static storage = (name = null, opts = {}) => {
|
24
|
+
if (name) {
|
25
|
+
opts.name = name
|
26
|
+
const existing = localGet('fp.' + name)
|
27
|
+
if (existing) {
|
28
|
+
const existingConfig = JSON.parse(existing)
|
29
|
+
const fp = new Database(new TransactionBlockstore(name, existingConfig.key), [], opts)
|
30
|
+
return this.fromJSON(existingConfig, fp)
|
31
|
+
} else {
|
32
|
+
const instanceKey = randomBytes(32).toString('hex') // pass null to disable encryption
|
33
|
+
return new Database(new TransactionBlockstore(name, instanceKey), [], opts)
|
123
34
|
}
|
124
|
-
rows = Array.from(docsMap.values())
|
125
|
-
clockCIDs = resp.clockCIDs
|
126
|
-
// console.log('change rows', this.instanceId, rows)
|
127
|
-
} else {
|
128
|
-
const allResp = await getAll(this.blocks, this.clock)
|
129
|
-
rows = allResp.result.map(({ key, value }) => (decodeEvent({ key, value })))
|
130
|
-
dataCIDs = allResp.cids
|
131
|
-
// console.log('dbdoc rows', this.instanceId, rows)
|
132
|
-
}
|
133
|
-
return {
|
134
|
-
rows,
|
135
|
-
clock: this.clockToJSON(),
|
136
|
-
proof: { data: await cidsToProof(dataCIDs), clock: await cidsToProof(clockCIDs) }
|
137
|
-
}
|
138
|
-
}
|
139
|
-
|
140
|
-
async allDocuments () {
|
141
|
-
const allResp = await getAll(this.blocks, this.clock)
|
142
|
-
const rows = allResp.result.map(({ key, value }) => (decodeEvent({ key, value }))).map(({ key, value }) => ({ key, value: { _id: key, ...value } }))
|
143
|
-
return {
|
144
|
-
rows,
|
145
|
-
clock: this.clockToJSON(),
|
146
|
-
proof: await cidsToProof(allResp.cids)
|
147
|
-
}
|
148
|
-
}
|
149
|
-
|
150
|
-
/**
|
151
|
-
* Runs validation on the specified document using the Fireproof instance's configuration. Throws an error if the document is invalid.
|
152
|
-
*
|
153
|
-
* @param {Object} doc - The document to validate.
|
154
|
-
* @returns {Promise<void>}
|
155
|
-
* @throws {Error} - Throws an error if the document is invalid.
|
156
|
-
* @memberof Fireproof
|
157
|
-
* @instance
|
158
|
-
*/
|
159
|
-
async runValidation (doc) {
|
160
|
-
if (this.config && this.config.validateChange) {
|
161
|
-
const oldDoc = await this.get(doc._id)
|
162
|
-
.then((doc) => doc)
|
163
|
-
.catch(() => ({}))
|
164
|
-
this.config.validateChange(doc, oldDoc, this.authCtx)
|
165
|
-
}
|
166
|
-
}
|
167
|
-
|
168
|
-
/**
|
169
|
-
* Retrieves the document with the specified ID from the database
|
170
|
-
*
|
171
|
-
* @param {string} key - the ID of the document to retrieve
|
172
|
-
* @param {Object} [opts] - options
|
173
|
-
* @returns {Promise<{_id: string}>} - the document with the specified ID
|
174
|
-
* @memberof Fireproof
|
175
|
-
* @instance
|
176
|
-
*/
|
177
|
-
async get (key, opts = {}) {
|
178
|
-
const clock = opts.clock || this.clock
|
179
|
-
const resp = await get(this.blocks, clock, charwise.encode(key))
|
180
|
-
|
181
|
-
// this tombstone is temporary until we can get the prolly tree to delete
|
182
|
-
if (!resp || resp.result === null) {
|
183
|
-
throw new Error('Not found')
|
184
|
-
}
|
185
|
-
const doc = resp.result
|
186
|
-
if (opts.mvcc === true) {
|
187
|
-
doc._clock = this.clockToJSON()
|
188
|
-
}
|
189
|
-
doc._proof = {
|
190
|
-
data: await cidsToProof(resp.cids),
|
191
|
-
clock: this.clockToJSON()
|
192
|
-
}
|
193
|
-
doc._id = key
|
194
|
-
return doc
|
195
|
-
}
|
196
|
-
|
197
|
-
/**
|
198
|
-
* Adds a new document to the database, or updates an existing document. Returns the ID of the document and the new clock head.
|
199
|
-
*
|
200
|
-
* @param {Object} doc - the document to be added
|
201
|
-
* @param {string} doc._id - the document ID. If not provided, a random ID will be generated.
|
202
|
-
* @param {CID[]} doc._clock - the document ID. If not provided, a random ID will be generated.
|
203
|
-
* @param {Proof} doc._proof - CIDs referenced by the update
|
204
|
-
* @returns {Promise<{ id: string, clock: CID[] }>} - The result of adding the document to the database
|
205
|
-
* @memberof Fireproof
|
206
|
-
* @instance
|
207
|
-
*/
|
208
|
-
async put ({ _id, _proof, ...doc }) {
|
209
|
-
const id = _id || 'f' + Math.random().toString(36).slice(2)
|
210
|
-
await this.runValidation({ _id: id, ...doc })
|
211
|
-
return await this.putToProllyTree({ key: id, value: doc }, doc._clock)
|
212
|
-
}
|
213
|
-
|
214
|
-
/**
|
215
|
-
* Deletes a document from the database
|
216
|
-
* @param {string | any} docOrId - the document ID
|
217
|
-
* @returns {Promise<{ id: string, clock: CID[] }>} - The result of deleting the document from the database
|
218
|
-
* @memberof Fireproof
|
219
|
-
* @instance
|
220
|
-
*/
|
221
|
-
async del (docOrId) {
|
222
|
-
let id
|
223
|
-
let clock = null
|
224
|
-
if (docOrId._id) {
|
225
|
-
id = docOrId._id
|
226
|
-
clock = docOrId._clock
|
227
35
|
} else {
|
228
|
-
|
36
|
+
return new Database(new TransactionBlockstore(), [], opts)
|
229
37
|
}
|
230
|
-
await this.runValidation({ _id: id, _deleted: true })
|
231
|
-
return await this.putToProllyTree({ key: id, del: true }, clock) // not working at prolly tree layer?
|
232
|
-
// this tombstone is temporary until we can get the prolly tree to delete
|
233
|
-
// return await this.putToProllyTree({ key: id, value: null }, clock)
|
234
38
|
}
|
235
39
|
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
if (missedChange) {
|
250
|
-
throw new Error('MVCC conflict, document is changed, please reload the document and try again.')
|
40
|
+
static fromJSON (json, database) {
|
41
|
+
database.hydrate({ clock: json.clock.map(c => parseCID(c)), name: json.name, key: json.key })
|
42
|
+
if (json.indexes) {
|
43
|
+
for (const { name, code, clock: { byId, byKey, db } } of json.indexes) {
|
44
|
+
Index.fromJSON(database, {
|
45
|
+
clock: {
|
46
|
+
byId: byId ? parseCID(byId) : null,
|
47
|
+
byKey: byKey ? parseCID(byKey) : null,
|
48
|
+
db: db ? db.map(c => parseCID(c)) : null
|
49
|
+
},
|
50
|
+
code,
|
51
|
+
name
|
52
|
+
})
|
251
53
|
}
|
252
54
|
}
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
)
|
258
|
-
|
259
|
-
|
260
|
-
|
55
|
+
return database
|
56
|
+
}
|
57
|
+
|
58
|
+
static snapshot (database, clock) {
|
59
|
+
const definition = database.toJSON()
|
60
|
+
const withBlocks = new Database(database.blocks)
|
61
|
+
if (clock) {
|
62
|
+
definition.clock = clock.map(c => parseCID(c))
|
63
|
+
definition.indexes.forEach(index => {
|
64
|
+
index.clock.byId = null
|
65
|
+
index.clock.byKey = null
|
66
|
+
index.clock.db = null
|
67
|
+
})
|
261
68
|
}
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
69
|
+
const snappedDb = this.fromJSON(definition, withBlocks)
|
70
|
+
;([...database.indexes.values()]).forEach(index => {
|
71
|
+
snappedDb.indexes.get(index.mapFnString).mapFn = index.mapFn
|
72
|
+
})
|
73
|
+
return snappedDb
|
74
|
+
}
|
75
|
+
|
76
|
+
static async zoom (database, clock) {
|
77
|
+
;([...database.indexes.values()]).forEach(index => {
|
78
|
+
index.indexById = { root: null, cid: null }
|
79
|
+
index.indexByKey = { root: null, cid: null }
|
80
|
+
index.dbHead = null
|
81
|
+
})
|
82
|
+
database.clock = clock.map(c => parseCID(c))
|
83
|
+
await database.notifyReset() // hmm... indexes should listen to this? might be more complex than worth it. so far this is the only caller
|
84
|
+
return database
|
271
85
|
}
|
272
|
-
|
273
|
-
// /**
|
274
|
-
// * Advances the clock to the specified event and updates the root CID
|
275
|
-
// * Will be used by replication
|
276
|
-
// */
|
277
|
-
// async advance (event) {
|
278
|
-
// this.clock = await advance(this.blocks, this.clock, event)
|
279
|
-
// this.rootCid = await root(this.blocks, this.clock)
|
280
|
-
// return this.clock
|
281
|
-
// }
|
282
|
-
|
283
|
-
async * vis () {
|
284
|
-
return yield * vis(this.blocks, this.clock)
|
285
|
-
}
|
286
|
-
|
287
|
-
async visTree () {
|
288
|
-
return await visMerkleTree(this.blocks, this.clock)
|
289
|
-
}
|
290
|
-
|
291
|
-
async visClock () {
|
292
|
-
return await visMerkleClock(this.blocks, this.clock)
|
293
|
-
}
|
294
|
-
|
295
|
-
/**
|
296
|
-
* Registers a Listener to be called when the Fireproof instance's clock is updated.
|
297
|
-
* Recieves live changes from the database after they are committed.
|
298
|
-
* @param {Function} listener - The listener to be called when the clock is updated.
|
299
|
-
* @returns {Function} - A function that can be called to unregister the listener.
|
300
|
-
* @memberof Fireproof
|
301
|
-
*/
|
302
|
-
registerListener (listener) {
|
303
|
-
this.listeners.add(listener)
|
304
|
-
return () => {
|
305
|
-
this.listeners.delete(listener)
|
306
|
-
}
|
307
|
-
}
|
308
|
-
|
309
|
-
async notifyListeners (changes) {
|
310
|
-
// await sleep(10)
|
311
|
-
for (const listener of this.listeners) {
|
312
|
-
await listener(changes)
|
313
|
-
}
|
314
|
-
}
|
315
|
-
|
316
|
-
setCarUploader (carUploaderFn) {
|
317
|
-
// console.log('registering car uploader')
|
318
|
-
// https://en.wikipedia.org/wiki/Law_of_Demeter - this is a violation of the law of demeter
|
319
|
-
this.blocks.valet.uploadFunction = carUploaderFn
|
320
|
-
}
|
321
|
-
|
322
|
-
setRemoteBlockReader (remoteBlockReaderFn) {
|
323
|
-
// console.log('registering remote block reader')
|
324
|
-
this.blocks.valet.remoteBlockFunction = remoteBlockReaderFn
|
325
|
-
}
|
326
|
-
}
|
327
|
-
|
328
|
-
export async function cidsToProof (cids) {
|
329
|
-
if (!cids || !cids.all) return []
|
330
|
-
const all = await cids.all()
|
331
|
-
return [...all].map((cid) => cid.toString())
|
332
|
-
}
|
333
|
-
|
334
|
-
function decodeEvent (event) {
|
335
|
-
const decodedKey = charwise.decode(event.key)
|
336
|
-
return { ...event, key: decodedKey }
|
337
|
-
}
|
338
|
-
|
339
|
-
function encodeEvent (event) {
|
340
|
-
if (!(event && event.key)) return
|
341
|
-
const encodedKey = charwise.encode(event.key)
|
342
|
-
return { ...event, key: encodedKey }
|
343
86
|
}
|
package/src/listener.js
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
* @class Listener
|
5
5
|
* @classdesc An listener attaches to a Fireproof database and runs a routing function on each change, sending the results to subscribers.
|
6
6
|
*
|
7
|
-
* @param {import('./
|
7
|
+
* @param {import('./database.js').Database} database - The Database database instance to index.
|
8
8
|
* @param {Function} routingFn - The routing function to apply to each entry in the database.
|
9
9
|
*/
|
10
10
|
// import { ChangeEvent } from './db-index'
|
@@ -14,21 +14,23 @@ export class Listener {
|
|
14
14
|
doStopListening = null
|
15
15
|
|
16
16
|
/**
|
17
|
-
* @param {import('./
|
17
|
+
* @param {import('./database.js').Database} database
|
18
18
|
* @param {(_: any, emit: any) => void} routingFn
|
19
19
|
*/
|
20
|
-
constructor (
|
20
|
+
constructor (
|
21
|
+
database,
|
22
|
+
routingFn = function (/** @type {any} */ _, /** @type {(arg0: string) => void} */ emit) {
|
23
|
+
emit('*')
|
24
|
+
}
|
25
|
+
) {
|
21
26
|
this.database = database
|
22
27
|
this.doStopListening = database.registerListener((/** @type {any} */ changes) => this.onChanges(changes))
|
23
28
|
/**
|
24
29
|
* The map function to apply to each entry in the database.
|
25
30
|
* @type {Function}
|
26
31
|
*/
|
27
|
-
this.routingFn =
|
28
|
-
|
29
|
-
function (/** @type {any} */ _, /** @type {(arg0: string) => void} */ emit) {
|
30
|
-
emit('*')
|
31
|
-
}
|
32
|
+
this.routingFn = routingFn
|
33
|
+
|
32
34
|
this.dbHead = null
|
33
35
|
}
|
34
36
|
|
package/src/prolly.js
CHANGED
@@ -19,6 +19,10 @@ import { doTransaction } from './blockstore.js'
|
|
19
19
|
import { create as createBlock } from 'multiformats/block'
|
20
20
|
const blockOpts = { cache, chunker: bf(3), codec, hasher, compare }
|
21
21
|
|
22
|
+
/**
|
23
|
+
* @typedef {import('./blockstore.js').TransactionBlockstore} TransactionBlockstore
|
24
|
+
*/
|
25
|
+
|
22
26
|
const withLog = async (label, fn) => {
|
23
27
|
const resp = await fn()
|
24
28
|
// console.log('withLog', label, !!resp)
|
@@ -239,7 +243,7 @@ export async function put (inBlocks, head, event, options) {
|
|
239
243
|
/**
|
240
244
|
* Determine the effective prolly root given the current merkle clock head.
|
241
245
|
*
|
242
|
-
* @param {
|
246
|
+
* @param {TransactionBlockstore} inBlocks Bucket block storage.
|
243
247
|
* @param {import('./clock').EventLink<import('./clock').EventData>[]} head Merkle clock head.
|
244
248
|
*/
|
245
249
|
export async function root (inBlocks, head) {
|
@@ -248,8 +252,8 @@ export async function root (inBlocks, head) {
|
|
248
252
|
}
|
249
253
|
const { root: newProllyRootNode, blocks: newBlocks, cids } = await doProllyBulk(inBlocks, head)
|
250
254
|
// todo maybe these should go to a temp blockstore?
|
251
|
-
await doTransaction('root', inBlocks, async (
|
252
|
-
const { bigPut } = makeGetAndPutBlock(
|
255
|
+
await doTransaction('root', inBlocks, async (transactionBlocks) => {
|
256
|
+
const { bigPut } = makeGetAndPutBlock(transactionBlocks)
|
253
257
|
for (const nb of newBlocks) {
|
254
258
|
bigPut(nb)
|
255
259
|
}
|
@@ -259,7 +263,7 @@ export async function root (inBlocks, head) {
|
|
259
263
|
|
260
264
|
/**
|
261
265
|
* Get the list of events not known by the `since` event
|
262
|
-
* @param {
|
266
|
+
* @param {TransactionBlockstore} blocks Bucket block storage.
|
263
267
|
* @param {import('./clock').EventLink<import('./clock').EventData>[]} head Merkle clock head.
|
264
268
|
* @param {import('./clock').EventLink<import('./clock').EventData>} since Event to compare against.
|
265
269
|
* @returns {Promise<{clockCIDs: CIDCounter, result: import('./clock').EventData[]}>}
|
@@ -276,7 +280,7 @@ export async function eventsSince (blocks, head, since) {
|
|
276
280
|
|
277
281
|
/**
|
278
282
|
*
|
279
|
-
* @param {
|
283
|
+
* @param {TransactionBlockstore} blocks Bucket block storage.
|
280
284
|
* @param {import('./clock').EventLink<import('./clock').EventData>[]} head Merkle clock head.
|
281
285
|
*
|
282
286
|
* @returns {Promise<{cids: CIDCounter, clockCIDs: CIDCounter, result: import('./clock').EventData[]}>}
|
@@ -297,7 +301,7 @@ export async function getAll (blocks, head) {
|
|
297
301
|
}
|
298
302
|
|
299
303
|
/**
|
300
|
-
* @param {
|
304
|
+
* @param {TransactionBlockstore} blocks Bucket block storage.
|
301
305
|
* @param {import('./clock').EventLink<import('./clock').EventData>[]} head Merkle clock head.
|
302
306
|
* @param {string} key The key of the value to retrieve.
|
303
307
|
*/
|
package/src/utils.js
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
|
2
|
+
/* global localStorage */
|
3
|
+
let storageSupported = false
|
4
|
+
try {
|
5
|
+
storageSupported = window.localStorage && true
|
6
|
+
} catch (e) {}
|
7
|
+
export function localGet (key) {
|
8
|
+
if (storageSupported) {
|
9
|
+
return localStorage && localStorage.getItem(key)
|
10
|
+
}
|
11
|
+
}
|
12
|
+
export function localSet (key, value) {
|
13
|
+
if (storageSupported) {
|
14
|
+
return localStorage && localStorage.setItem(key, value)
|
15
|
+
}
|
16
|
+
}
|
package/src/hydrator.js
DELETED
@@ -1,54 +0,0 @@
|
|
1
|
-
import { DbIndex } from './db-index.js'
|
2
|
-
import { Fireproof } from './fireproof.js'
|
3
|
-
import { CID } from 'multiformats'
|
4
|
-
|
5
|
-
const parseCID = cid => typeof cid === 'string' ? CID.parse(cid) : cid
|
6
|
-
|
7
|
-
export class Hydrator {
|
8
|
-
static fromJSON (json, database) {
|
9
|
-
database.hydrate({ clock: json.clock.map(c => parseCID(c)), name: json.name, key: json.key })
|
10
|
-
if (json.indexes) {
|
11
|
-
for (const { name, code, clock: { byId, byKey, db } } of json.indexes) {
|
12
|
-
DbIndex.fromJSON(database, {
|
13
|
-
clock: {
|
14
|
-
byId: byId ? parseCID(byId) : null,
|
15
|
-
byKey: byKey ? parseCID(byKey) : null,
|
16
|
-
db: db ? db.map(c => parseCID(c)) : null
|
17
|
-
},
|
18
|
-
code,
|
19
|
-
name
|
20
|
-
})
|
21
|
-
}
|
22
|
-
}
|
23
|
-
return database
|
24
|
-
}
|
25
|
-
|
26
|
-
static snapshot (database, clock) {
|
27
|
-
const definition = database.toJSON()
|
28
|
-
const withBlocks = new Fireproof(database.blocks)
|
29
|
-
if (clock) {
|
30
|
-
definition.clock = clock.map(c => parseCID(c))
|
31
|
-
definition.indexes.forEach(index => {
|
32
|
-
index.clock.byId = null
|
33
|
-
index.clock.byKey = null
|
34
|
-
index.clock.db = null
|
35
|
-
})
|
36
|
-
}
|
37
|
-
const snappedDb = this.fromJSON(definition, withBlocks)
|
38
|
-
;([...database.indexes.values()]).forEach(index => {
|
39
|
-
snappedDb.indexes.get(index.mapFnString).mapFn = index.mapFn
|
40
|
-
})
|
41
|
-
return snappedDb
|
42
|
-
}
|
43
|
-
|
44
|
-
static async zoom (database, clock) {
|
45
|
-
;([...database.indexes.values()]).forEach(index => {
|
46
|
-
index.indexById = { root: null, cid: null }
|
47
|
-
index.indexByKey = { root: null, cid: null }
|
48
|
-
index.dbHead = null
|
49
|
-
})
|
50
|
-
database.clock = clock.map(c => parseCID(c))
|
51
|
-
await database.notifyReset() // hmm... indexes should listen to this? might be more complex than worth it. so far this is the only caller
|
52
|
-
return database
|
53
|
-
}
|
54
|
-
}
|