@fireproof/core 0.3.1 → 0.3.3
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 +1 -1
- package/dist/src/blockstore.d.ts +115 -0
- package/dist/src/blockstore.d.ts.map +1 -0
- package/dist/src/clock.d.ts +98 -0
- package/dist/src/clock.d.ts.map +1 -0
- package/dist/src/crypto.d.ts +18 -0
- package/dist/src/crypto.d.ts.map +1 -0
- package/dist/src/db-index.d.ts +116 -0
- package/dist/src/db-index.d.ts.map +1 -0
- package/dist/src/fireproof.d.ts +167 -0
- package/dist/src/fireproof.d.ts.map +1 -0
- package/dist/src/hydrator.d.ts +6 -0
- package/dist/src/hydrator.d.ts.map +1 -0
- package/dist/src/index.d.ts +6 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/listener.d.ts +36 -0
- package/dist/src/listener.d.ts.map +1 -0
- package/dist/src/prolly.d.ts +83 -0
- package/dist/src/prolly.d.ts.map +1 -0
- package/dist/src/sha1.d.ts +9 -0
- package/dist/src/sha1.d.ts.map +1 -0
- package/dist/src/valet.d.ts +34 -0
- package/dist/src/valet.d.ts.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +33 -3
- package/src/blockstore.js +24 -23
- package/src/clock.js +4 -3
- package/src/crypto.js +1 -0
- package/src/db-index.js +23 -18
- package/src/fireproof.js +31 -26
- package/src/hydrator.js +3 -3
- package/src/index.js +6 -0
- package/src/listener.js +9 -8
- package/src/prolly.js +11 -24
- package/src/sha1.js +2 -1
- package/src/valet.js +22 -20
- package/hooks/use-fireproof.js +0 -135
- package/index.js +0 -6
- package/scripts/keygen.js +0 -3
- package/test/block.js +0 -65
- package/test/clock.test.js +0 -694
- package/test/db-index.test.js +0 -261
- package/test/fireproof.test.js +0 -493
- package/test/fulltext.test.js +0 -66
- package/test/helpers.js +0 -45
- package/test/hydrator.test.js +0 -81
- package/test/listener.test.js +0 -102
- package/test/prolly.test.js +0 -190
- package/test/proofs.test.js +0 -53
- package/test/reproduce-fixture-bug.test.js +0 -65
- package/test/valet.test.js +0 -59
package/src/fireproof.js
CHANGED
@@ -1,24 +1,28 @@
|
|
1
|
+
// @ts-nocheck
|
1
2
|
import { randomBytes } from 'crypto'
|
2
3
|
import { visMerkleClock, visMerkleTree, vis, put, get, getAll, eventsSince } from './prolly.js'
|
3
|
-
import TransactionBlockstore,
|
4
|
+
import { TransactionBlockstore, doTransaction } from './blockstore.js'
|
4
5
|
import charwise from 'charwise'
|
6
|
+
// import { CID } from 'multiformats/dist/types/src/cid.js'
|
5
7
|
|
6
8
|
// const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
|
7
9
|
|
10
|
+
// class Proof {}
|
11
|
+
|
8
12
|
/**
|
9
13
|
* @class Fireproof
|
10
14
|
* @classdesc Fireproof stores data in IndexedDB and provides a Merkle clock.
|
11
15
|
* This is the main class for saving and loading JSON and other documents with the database. You can find additional examples and
|
12
16
|
* usage guides in the repository README.
|
13
17
|
*
|
14
|
-
* @param {
|
18
|
+
* @param {import('./blockstore.js').TransactionBlockstore} blocks - The block storage instance to use documents and indexes
|
15
19
|
* @param {CID[]} clock - The Merkle clock head to use for the Fireproof instance.
|
16
20
|
* @param {object} [config] - Optional configuration options for the Fireproof instance.
|
17
21
|
* @param {object} [authCtx] - Optional authorization context object to use for any authentication checks.
|
18
22
|
*
|
19
23
|
*/
|
20
|
-
export
|
21
|
-
|
24
|
+
export class Fireproof {
|
25
|
+
listeners = new Set()
|
22
26
|
|
23
27
|
/**
|
24
28
|
* @function storage
|
@@ -82,12 +86,12 @@ export default class Fireproof {
|
|
82
86
|
* @instance
|
83
87
|
*/
|
84
88
|
async notifyReset () {
|
85
|
-
await this
|
89
|
+
await this.notifyListeners({ _reset: true, _clock: this.clockToJSON() })
|
86
90
|
}
|
87
91
|
|
88
92
|
// used be indexes etc to notify database listeners of new availability
|
89
93
|
async notifyExternal (source = 'unknown') {
|
90
|
-
await this
|
94
|
+
await this.notifyListeners({ _external: source, _clock: this.clockToJSON() })
|
91
95
|
}
|
92
96
|
|
93
97
|
/**
|
@@ -147,7 +151,7 @@ export default class Fireproof {
|
|
147
151
|
* @memberof Fireproof
|
148
152
|
* @instance
|
149
153
|
*/
|
150
|
-
async
|
154
|
+
async runValidation (doc) {
|
151
155
|
if (this.config && this.config.validateChange) {
|
152
156
|
const oldDoc = await this.get(doc._id)
|
153
157
|
.then((doc) => doc)
|
@@ -161,7 +165,7 @@ export default class Fireproof {
|
|
161
165
|
*
|
162
166
|
* @param {string} key - the ID of the document to retrieve
|
163
167
|
* @param {Object} [opts] - options
|
164
|
-
* @returns {
|
168
|
+
* @returns {Promise<{_id: string}>} - the document with the specified ID
|
165
169
|
* @memberof Fireproof
|
166
170
|
* @instance
|
167
171
|
*/
|
@@ -190,21 +194,22 @@ export default class Fireproof {
|
|
190
194
|
*
|
191
195
|
* @param {Object} doc - the document to be added
|
192
196
|
* @param {string} doc._id - the document ID. If not provided, a random ID will be generated.
|
193
|
-
* @param {
|
194
|
-
* @
|
197
|
+
* @param {CID[]} doc._clock - the document ID. If not provided, a random ID will be generated.
|
198
|
+
* @param {Proof} doc._proof - CIDs referenced by the update
|
199
|
+
* @returns {Promise<{ id: string, clock: CID[] }>} - The result of adding the document to the database
|
195
200
|
* @memberof Fireproof
|
196
201
|
* @instance
|
197
202
|
*/
|
198
203
|
async put ({ _id, _proof, ...doc }) {
|
199
204
|
const id = _id || 'f' + Math.random().toString(36).slice(2)
|
200
|
-
await this
|
201
|
-
return await this
|
205
|
+
await this.runValidation({ _id: id, ...doc })
|
206
|
+
return await this.putToProllyTree({ key: id, value: doc }, doc._clock)
|
202
207
|
}
|
203
208
|
|
204
209
|
/**
|
205
210
|
* Deletes a document from the database
|
206
|
-
* @param {string}
|
207
|
-
* @returns {
|
211
|
+
* @param {string | any} docOrId - the document ID
|
212
|
+
* @returns {Promise<{ id: string, clock: CID[] }>} - The result of deleting the document from the database
|
208
213
|
* @memberof Fireproof
|
209
214
|
* @instance
|
210
215
|
*/
|
@@ -217,19 +222,19 @@ export default class Fireproof {
|
|
217
222
|
} else {
|
218
223
|
id = docOrId
|
219
224
|
}
|
220
|
-
await this
|
221
|
-
return await this
|
225
|
+
await this.runValidation({ _id: id, _deleted: true })
|
226
|
+
return await this.putToProllyTree({ key: id, del: true }, clock) // not working at prolly tree layer?
|
222
227
|
// this tombstone is temporary until we can get the prolly tree to delete
|
223
|
-
// return await this
|
228
|
+
// return await this.putToProllyTree({ key: id, value: null }, clock)
|
224
229
|
}
|
225
230
|
|
226
231
|
/**
|
227
232
|
* Updates the underlying storage with the specified event.
|
228
233
|
* @private
|
229
|
-
* @param {
|
230
|
-
* @returns {
|
234
|
+
* @param {{del?: true, key : string, value?: any}} decodedEvent - the event to add
|
235
|
+
* @returns {Promise<{ proof:{}, id: string, clock: CID[] }>} - The result of adding the event to storage
|
231
236
|
*/
|
232
|
-
async
|
237
|
+
async putToProllyTree (decodedEvent, clock = null) {
|
233
238
|
const event = encodeEvent(decodedEvent)
|
234
239
|
if (clock && JSON.stringify(clock) !== JSON.stringify(this.clockToJSON())) {
|
235
240
|
// we need to check and see what version of the document exists at the clock specified
|
@@ -241,7 +246,7 @@ export default class Fireproof {
|
|
241
246
|
}
|
242
247
|
}
|
243
248
|
const result = await doTransaction(
|
244
|
-
'
|
249
|
+
'putToProllyTree',
|
245
250
|
this.blocks,
|
246
251
|
async (blocks) => await put(blocks, this.clock, event)
|
247
252
|
)
|
@@ -251,7 +256,7 @@ export default class Fireproof {
|
|
251
256
|
}
|
252
257
|
// console.log('new clock head', this.instanceId, result.head.toString())
|
253
258
|
this.clock = result.head // do we want to do this as a finally block
|
254
|
-
await this
|
259
|
+
await this.notifyListeners([decodedEvent]) // this type is odd
|
255
260
|
return {
|
256
261
|
id: decodedEvent.key,
|
257
262
|
clock: this.clockToJSON(),
|
@@ -290,15 +295,15 @@ export default class Fireproof {
|
|
290
295
|
* @memberof Fireproof
|
291
296
|
*/
|
292
297
|
registerListener (listener) {
|
293
|
-
this
|
298
|
+
this.listeners.add(listener)
|
294
299
|
return () => {
|
295
|
-
this
|
300
|
+
this.listeners.delete(listener)
|
296
301
|
}
|
297
302
|
}
|
298
303
|
|
299
|
-
async
|
304
|
+
async notifyListeners (changes) {
|
300
305
|
// await sleep(10)
|
301
|
-
for (const listener of this
|
306
|
+
for (const listener of this.listeners) {
|
302
307
|
await listener(changes)
|
303
308
|
}
|
304
309
|
}
|
package/src/hydrator.js
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
import DbIndex from './db-index.js'
|
2
|
-
import Fireproof from './fireproof.js'
|
1
|
+
import { DbIndex } from './db-index.js'
|
2
|
+
import { Fireproof } from './fireproof.js'
|
3
3
|
import { CID } from 'multiformats'
|
4
4
|
|
5
5
|
const parseCID = cid => typeof cid === 'string' ? CID.parse(cid) : cid
|
6
6
|
|
7
|
-
export
|
7
|
+
export class Hydrator {
|
8
8
|
static fromJSON (json, database) {
|
9
9
|
database.hydrate({ clock: json.clock.map(c => parseCID(c)), name: json.name, key: json.key })
|
10
10
|
if (json.indexes) {
|
package/src/index.js
ADDED
package/src/listener.js
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
// @ts-nocheck
|
1
2
|
/**
|
2
3
|
* A Fireproof database Listener allows you to react to events in the database.
|
3
4
|
*
|
@@ -9,9 +10,9 @@
|
|
9
10
|
*/
|
10
11
|
// import { ChangeEvent } from './db-index'
|
11
12
|
|
12
|
-
export
|
13
|
-
|
14
|
-
|
13
|
+
export class Listener {
|
14
|
+
subcribers = new Map()
|
15
|
+
doStopListening = null
|
15
16
|
|
16
17
|
constructor (database, routingFn) {
|
17
18
|
/** routingFn
|
@@ -19,7 +20,7 @@ export default class Listener {
|
|
19
20
|
* @type {Fireproof}
|
20
21
|
*/
|
21
22
|
this.database = database
|
22
|
-
this
|
23
|
+
this.doStopListening = database.registerListener(changes => this.onChanges(changes))
|
23
24
|
/**
|
24
25
|
* The map function to apply to each entry in the database.
|
25
26
|
* @type {Function}
|
@@ -41,7 +42,7 @@ export default class Listener {
|
|
41
42
|
* @instance
|
42
43
|
*/
|
43
44
|
on (topic, subscriber, since) {
|
44
|
-
const listOfTopicSubscribers = getTopicList(this
|
45
|
+
const listOfTopicSubscribers = getTopicList(this.subcribers, topic)
|
45
46
|
listOfTopicSubscribers.push(subscriber)
|
46
47
|
if (typeof since !== 'undefined') {
|
47
48
|
this.database.changesSince(since).then(({ rows: changes }) => {
|
@@ -55,16 +56,16 @@ export default class Listener {
|
|
55
56
|
}
|
56
57
|
}
|
57
58
|
|
58
|
-
|
59
|
+
onChanges (changes) {
|
59
60
|
if (Array.isArray(changes)) {
|
60
61
|
const seenTopics = topicsForChanges(changes, this.routingFn)
|
61
62
|
for (const [topic, keys] of seenTopics) {
|
62
|
-
const listOfTopicSubscribers = getTopicList(this
|
63
|
+
const listOfTopicSubscribers = getTopicList(this.subcribers, topic)
|
63
64
|
listOfTopicSubscribers.forEach(subscriber => keys.forEach(key => subscriber(key)))
|
64
65
|
}
|
65
66
|
} else {
|
66
67
|
// non-arrays go to all subscribers
|
67
|
-
for (const [, listOfTopicSubscribers] of this
|
68
|
+
for (const [, listOfTopicSubscribers] of this.subcribers) {
|
68
69
|
listOfTopicSubscribers.forEach(subscriber => subscriber(changes))
|
69
70
|
}
|
70
71
|
}
|
package/src/prolly.js
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
// @ts-nocheck
|
1
2
|
import {
|
2
3
|
advance,
|
3
4
|
EventFetcher,
|
@@ -37,23 +38,9 @@ export const makeGetBlock = (blocks) => {
|
|
37
38
|
}
|
38
39
|
|
39
40
|
/**
|
40
|
-
*
|
41
|
-
* @param {
|
42
|
-
* @
|
43
|
-
* @param {Function} getBlock - A function that gets a block.
|
44
|
-
* @param {Function} bigPut - A function that puts a block.
|
45
|
-
* @param {import('prolly-trees/map').Root} root - The root node.
|
46
|
-
* @param {Object<{ key: string, value: any, del: boolean }>} event - The update event.
|
47
|
-
* @param {CID[]} head - The head of the event chain.
|
48
|
-
* @param {Array<import('multiformats/block').Block>} additions - A array of additions.
|
49
|
-
* @param {Array<mport('multiformats/block').Block>>} removals - An array of removals.
|
50
|
-
* @returns {Promise<{
|
51
|
-
* root: import('prolly-trees/map').Root,
|
52
|
-
* additions: Map<string, import('multiformats/block').Block>,
|
53
|
-
* removals: Array<string>,
|
54
|
-
* head: CID[],
|
55
|
-
* event: CID[]
|
56
|
-
* }>}
|
41
|
+
*
|
42
|
+
* @param {*} param0
|
43
|
+
* @returns
|
57
44
|
*/
|
58
45
|
async function createAndSaveNewEvent ({
|
59
46
|
inBlocks,
|
@@ -198,7 +185,7 @@ const doProllyBulk = async (inBlocks, head, event) => {
|
|
198
185
|
/**
|
199
186
|
* Put a value (a CID) for the given key. If the key exists it's value is overwritten.
|
200
187
|
*
|
201
|
-
* @param {import('
|
188
|
+
* @param {import('./blockstore.js').BlockFetcher} blocks Bucket block storage.
|
202
189
|
* @param {import('./clock').EventLink<EventData>[]} head Merkle clock head.
|
203
190
|
* @param {string} key The key of the value to put.
|
204
191
|
* @param {CID} value The value to put.
|
@@ -250,7 +237,7 @@ export async function put (inBlocks, head, event, options) {
|
|
250
237
|
/**
|
251
238
|
* Determine the effective prolly root given the current merkle clock head.
|
252
239
|
*
|
253
|
-
* @param {import('
|
240
|
+
* @param {import('./blockstore.js').BlockFetcher} blocks Bucket block storage.
|
254
241
|
* @param {import('./clock').EventLink<EventData>[]} head Merkle clock head.
|
255
242
|
*/
|
256
243
|
export async function root (inBlocks, head) {
|
@@ -270,10 +257,10 @@ export async function root (inBlocks, head) {
|
|
270
257
|
|
271
258
|
/**
|
272
259
|
* Get the list of events not known by the `since` event
|
273
|
-
* @param {import('
|
260
|
+
* @param {import('./blockstore.js').BlockFetcher} blocks Bucket block storage.
|
274
261
|
* @param {import('./clock').EventLink<EventData>[]} head Merkle clock head.
|
275
262
|
* @param {import('./clock').EventLink<EventData>} since Event to compare against.
|
276
|
-
* @returns {Promise<
|
263
|
+
* @returns {Promise<{clockCIDs: CIDCounter, result: EventData[]}>}
|
277
264
|
*/
|
278
265
|
export async function eventsSince (blocks, head, since) {
|
279
266
|
if (!head.length) {
|
@@ -286,10 +273,10 @@ export async function eventsSince (blocks, head, since) {
|
|
286
273
|
|
287
274
|
/**
|
288
275
|
*
|
289
|
-
* @param {import('
|
276
|
+
* @param {import('./blockstore.js').BlockFetcher} blocks Bucket block storage.
|
290
277
|
* @param {import('./clock').EventLink<EventData>[]} head Merkle clock head.
|
291
278
|
*
|
292
|
-
* @returns {Promise<
|
279
|
+
* @returns {Promise<{clockCIDs: CIDCounter, result: EventData[]}>}
|
293
280
|
*
|
294
281
|
*/
|
295
282
|
export async function getAll (blocks, head) {
|
@@ -307,7 +294,7 @@ export async function getAll (blocks, head) {
|
|
307
294
|
}
|
308
295
|
|
309
296
|
/**
|
310
|
-
* @param {import('
|
297
|
+
* @param {import('./blockstore.js').BlockFetcher} blocks Bucket block storage.
|
311
298
|
* @param {import('./clock').EventLink<EventData>[]} head Merkle clock head.
|
312
299
|
* @param {string} key The key of the value to retrieve.
|
313
300
|
*/
|
package/src/sha1.js
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
// @ts-nocheck
|
1
2
|
// from https://github.com/duzun/sync-sha1/blob/master/rawSha1.js
|
2
3
|
// MIT License Copyright (c) 2020 Dumitru Uzun
|
3
4
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
@@ -29,7 +30,7 @@
|
|
29
30
|
*
|
30
31
|
* @return {Uint8Array} sha1 hash
|
31
32
|
*/
|
32
|
-
export
|
33
|
+
export function rawSha1 (b) {
|
33
34
|
let i = b.byteLength
|
34
35
|
let bs = 0
|
35
36
|
let A; let B; let C; let D; let G
|
package/src/valet.js
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
// @ts-nocheck
|
1
2
|
import { CarReader } from '@ipld/car'
|
2
3
|
import { CID } from 'multiformats/cid'
|
3
4
|
import { sha256 } from 'multiformats/hashes/sha2'
|
@@ -12,18 +13,18 @@ import { nocache as cache } from 'prolly-trees/cache'
|
|
12
13
|
import { encrypt, decrypt } from './crypto.js'
|
13
14
|
import { Buffer } from 'buffer'
|
14
15
|
import * as codec from 'encrypted-block'
|
15
|
-
import sha1sync from './sha1.js'
|
16
|
+
import { rawSha1 as sha1sync } from './sha1.js'
|
16
17
|
const chunker = bf(3)
|
17
18
|
|
18
19
|
const NO_ENCRYPT =
|
19
20
|
typeof process !== 'undefined' ? process.env.NO_ENCRYPT : import.meta && import.meta.env.VITE_NO_ENCRYPT
|
20
21
|
|
21
|
-
export
|
22
|
+
export class Valet {
|
22
23
|
idb = null
|
23
24
|
name = null
|
24
|
-
|
25
|
-
|
26
|
-
|
25
|
+
uploadQueue = null
|
26
|
+
alreadyEnqueued = new Set()
|
27
|
+
keyMaterial = null
|
27
28
|
keyId = 'null'
|
28
29
|
|
29
30
|
/**
|
@@ -35,7 +36,7 @@ export default class Valet {
|
|
35
36
|
constructor (name = 'default', keyMaterial) {
|
36
37
|
this.name = name
|
37
38
|
this.setKeyMaterial(keyMaterial)
|
38
|
-
this
|
39
|
+
this.uploadQueue = cargoQueue(async (tasks, callback) => {
|
39
40
|
console.log(
|
40
41
|
'queue worker',
|
41
42
|
tasks.length,
|
@@ -56,7 +57,7 @@ export default class Valet {
|
|
56
57
|
callback()
|
57
58
|
})
|
58
59
|
|
59
|
-
this
|
60
|
+
this.uploadQueue.drain(async () => {
|
60
61
|
return await this.withDB(async db => {
|
61
62
|
const carKeys = (await db.getAllFromIndex('cidToCar', 'pending')).map(c => c.car)
|
62
63
|
for (const carKey of carKeys) {
|
@@ -70,17 +71,17 @@ export default class Valet {
|
|
70
71
|
}
|
71
72
|
|
72
73
|
getKeyMaterial () {
|
73
|
-
return this
|
74
|
+
return this.keyMaterial
|
74
75
|
}
|
75
76
|
|
76
77
|
setKeyMaterial (km) {
|
77
78
|
if (km && !NO_ENCRYPT) {
|
78
79
|
const hex = Uint8Array.from(Buffer.from(km, 'hex'))
|
79
|
-
this
|
80
|
+
this.keyMaterial = km
|
80
81
|
const hash = sha1sync(hex)
|
81
82
|
this.keyId = Buffer.from(hash).toString('hex')
|
82
83
|
} else {
|
83
|
-
this
|
84
|
+
this.keyMaterial = null
|
84
85
|
this.keyId = 'null'
|
85
86
|
}
|
86
87
|
// console.trace('keyId', this.name, this.keyId)
|
@@ -95,9 +96,9 @@ export default class Valet {
|
|
95
96
|
*/
|
96
97
|
async writeTransaction (innerBlockstore, cids) {
|
97
98
|
if (innerBlockstore.lastCid) {
|
98
|
-
if (this
|
99
|
+
if (this.keyMaterial) {
|
99
100
|
// console.log('encrypting car', innerBlockstore.label)
|
100
|
-
const newCar = await blocksToEncryptedCarBlock(innerBlockstore.lastCid, innerBlockstore, this
|
101
|
+
const newCar = await blocksToEncryptedCarBlock(innerBlockstore.lastCid, innerBlockstore, this.keyMaterial)
|
101
102
|
await this.parkCar(newCar.cid.toString(), newCar.bytes, cids)
|
102
103
|
} else {
|
103
104
|
const newCar = await blocksToCarBlock(innerBlockstore.lastCid, innerBlockstore)
|
@@ -140,14 +141,14 @@ export default class Valet {
|
|
140
141
|
|
141
142
|
// upload to web3.storage if we have credentials
|
142
143
|
if (this.uploadFunction) {
|
143
|
-
if (this
|
144
|
+
if (this.alreadyEnqueued.has(carCid)) {
|
144
145
|
// console.log('already enqueued', carCid)
|
145
146
|
return
|
146
147
|
}
|
147
148
|
// don't await this, it will be done in the queue
|
148
149
|
// console.log('add to queue', carCid, value.length)
|
149
|
-
this
|
150
|
-
this
|
150
|
+
this.uploadQueue.push({ carCid, value })
|
151
|
+
this.alreadyEnqueued.add(carCid)
|
151
152
|
} else {
|
152
153
|
// console.log('no upload function', carCid, value.length, this.uploadFunction)
|
153
154
|
}
|
@@ -165,7 +166,7 @@ export default class Valet {
|
|
165
166
|
}
|
166
167
|
const carBytes = await tx.objectStore('cars').get(carCid)
|
167
168
|
const reader = await CarReader.fromBytes(carBytes)
|
168
|
-
if (this
|
169
|
+
if (this.keyMaterial) {
|
169
170
|
const roots = await reader.getRoots()
|
170
171
|
const readerGetWithCodec = async cid => {
|
171
172
|
const got = await reader.get(cid)
|
@@ -182,7 +183,7 @@ export default class Valet {
|
|
182
183
|
// console.log('decoded', decoded.value)
|
183
184
|
return decoded
|
184
185
|
}
|
185
|
-
const { blocks } = await blocksFromEncryptedCarBlock(roots[0], readerGetWithCodec, this
|
186
|
+
const { blocks } = await blocksFromEncryptedCarBlock(roots[0], readerGetWithCodec, this.keyMaterial)
|
186
187
|
const block = blocks.find(b => b.cid.toString() === dataCID)
|
187
188
|
if (block) {
|
188
189
|
return block.bytes
|
@@ -234,7 +235,8 @@ const blocksToEncryptedCarBlock = async (innerBlockStoreClockRootCid, blocks, ke
|
|
234
235
|
key: encryptionKey,
|
235
236
|
hasher: sha256,
|
236
237
|
chunker,
|
237
|
-
|
238
|
+
cache,
|
239
|
+
// codec: dagcbor, // should be crypto?
|
238
240
|
root: innerBlockStoreClockRootCid
|
239
241
|
})) {
|
240
242
|
encryptedBlocks.push(block)
|
@@ -262,8 +264,8 @@ const blocksFromEncryptedCarBlock = async (cid, get, keyMaterial) => {
|
|
262
264
|
key: decryptionKey,
|
263
265
|
chunker,
|
264
266
|
hasher: sha256,
|
265
|
-
cache
|
266
|
-
codec: dagcbor
|
267
|
+
cache
|
268
|
+
// codec: dagcbor
|
267
269
|
})) {
|
268
270
|
decryptedBlocks.push(block)
|
269
271
|
cids.add(block.cid.toString())
|
package/hooks/use-fireproof.js
DELETED
@@ -1,135 +0,0 @@
|
|
1
|
-
/* global localStorage */
|
2
|
-
// @ts-ignore
|
3
|
-
import { useEffect, useState, createContext } from 'react'
|
4
|
-
import { Fireproof, Listener, Hydrator } from '../index'
|
5
|
-
|
6
|
-
// export interface FireproofCtxValue {
|
7
|
-
// addSubscriber: (label: String, fn: Function) => void
|
8
|
-
// database: Fireproof
|
9
|
-
// ready: boolean
|
10
|
-
// persist: () => void
|
11
|
-
// }
|
12
|
-
export const FireproofCtx = createContext({
|
13
|
-
addSubscriber: () => {},
|
14
|
-
database: null,
|
15
|
-
ready: false
|
16
|
-
})
|
17
|
-
|
18
|
-
const inboundSubscriberQueue = new Map()
|
19
|
-
|
20
|
-
let startedSetup = false
|
21
|
-
let database
|
22
|
-
let listener
|
23
|
-
const initializeDatabase = name => {
|
24
|
-
if (database) return
|
25
|
-
database = Fireproof.storage(name)
|
26
|
-
listener = new Listener(database)
|
27
|
-
}
|
28
|
-
|
29
|
-
/**
|
30
|
-
* @function useFireproof
|
31
|
-
* React hook to initialize a Fireproof database, automatically saving and loading the clock.
|
32
|
-
* You might need to `import { nodePolyfills } from 'vite-plugin-node-polyfills'` in your vite.config.ts
|
33
|
-
* @param [defineDatabaseFn] Synchronous function that defines the database, run this before any async calls
|
34
|
-
* @param [setupDatabaseFn] Asynchronous function that sets up the database, run this to load fixture data etc
|
35
|
-
* @returns {FireproofCtxValue} { addSubscriber, database, ready }
|
36
|
-
*/
|
37
|
-
export function useFireproof (
|
38
|
-
defineDatabaseFn = () => {},
|
39
|
-
setupDatabaseFn = async () => {},
|
40
|
-
name
|
41
|
-
) {
|
42
|
-
const [ready, setReady] = useState(false)
|
43
|
-
initializeDatabase(name || 'useFireproof')
|
44
|
-
const localStorageKey = 'fp.' + database.name
|
45
|
-
|
46
|
-
const addSubscriber = (label, fn) => {
|
47
|
-
inboundSubscriberQueue.set(label, fn)
|
48
|
-
}
|
49
|
-
|
50
|
-
const listenerCallback = async event => {
|
51
|
-
localSet(localStorageKey, JSON.stringify(database))
|
52
|
-
if (event._external) return
|
53
|
-
for (const [, fn] of inboundSubscriberQueue) fn()
|
54
|
-
}
|
55
|
-
|
56
|
-
useEffect(() => {
|
57
|
-
const doSetup = async () => {
|
58
|
-
if (ready) return
|
59
|
-
if (startedSetup) return
|
60
|
-
startedSetup = true
|
61
|
-
defineDatabaseFn(database) // define indexes before querying them
|
62
|
-
console.log('Initializing database', database.name)
|
63
|
-
const fp = localGet(localStorageKey) // todo use db.name
|
64
|
-
if (fp) {
|
65
|
-
try {
|
66
|
-
const serialized = JSON.parse(fp)
|
67
|
-
// console.log('serialized', JSON.stringify(serialized.indexes.map(c => c.clock)))
|
68
|
-
console.log(`Loading previous database clock. (localStorage.removeItem('${localStorageKey}') to reset)`)
|
69
|
-
await Hydrator.fromJSON(serialized, database)
|
70
|
-
const changes = await database.changesSince()
|
71
|
-
if (changes.rows.length < 2) {
|
72
|
-
// console.log('Resetting database')
|
73
|
-
throw new Error('Resetting database')
|
74
|
-
}
|
75
|
-
} catch (e) {
|
76
|
-
console.error(`Error loading previous database clock. ${fp} Resetting.`, e)
|
77
|
-
await Hydrator.zoom(database, [])
|
78
|
-
await setupDatabaseFn(database)
|
79
|
-
localSet(localStorageKey, JSON.stringify(database))
|
80
|
-
}
|
81
|
-
} else {
|
82
|
-
await setupDatabaseFn(database)
|
83
|
-
localSet(localStorageKey, JSON.stringify(database))
|
84
|
-
}
|
85
|
-
setReady(true)
|
86
|
-
listener.on('*', listenerCallback)// hushed('*', listenerCallback, 250))
|
87
|
-
}
|
88
|
-
doSetup()
|
89
|
-
}, [ready])
|
90
|
-
|
91
|
-
return {
|
92
|
-
addSubscriber,
|
93
|
-
database,
|
94
|
-
ready,
|
95
|
-
persist: () => {
|
96
|
-
localSet(localStorageKey, JSON.stringify(database))
|
97
|
-
}
|
98
|
-
}
|
99
|
-
}
|
100
|
-
|
101
|
-
// const husherMap = new Map()
|
102
|
-
// const husher = (id, workFn, ms) => {
|
103
|
-
// if (!husherMap.has(id)) {
|
104
|
-
// const start = Date.now()
|
105
|
-
// husherMap.set(
|
106
|
-
// id,
|
107
|
-
// workFn().finally(() => setTimeout(() => husherMap.delete(id), ms - (Date.now() - start)))
|
108
|
-
// )
|
109
|
-
// }
|
110
|
-
// return husherMap.get(id)
|
111
|
-
// }
|
112
|
-
// const hushed =
|
113
|
-
// (id, workFn, ms) =>
|
114
|
-
// (...args) =>
|
115
|
-
// husher(id, () => workFn(...args), ms)
|
116
|
-
|
117
|
-
let storageSupported = false
|
118
|
-
try {
|
119
|
-
storageSupported = window.localStorage && true
|
120
|
-
} catch (e) {}
|
121
|
-
export function localGet (key) {
|
122
|
-
if (storageSupported) {
|
123
|
-
return localStorage && localStorage.getItem(key)
|
124
|
-
}
|
125
|
-
}
|
126
|
-
function localSet (key, value) {
|
127
|
-
if (storageSupported) {
|
128
|
-
return localStorage && localStorage.setItem(key, value)
|
129
|
-
}
|
130
|
-
}
|
131
|
-
// function localRemove(key) {
|
132
|
-
// if (storageSupported) {
|
133
|
-
// return localStorage && localStorage.removeItem(key)
|
134
|
-
// }
|
135
|
-
// }
|
package/index.js
DELETED
package/scripts/keygen.js
DELETED
package/test/block.js
DELETED
@@ -1,65 +0,0 @@
|
|
1
|
-
import { parse } from 'multiformats/link'
|
2
|
-
|
3
|
-
/**
|
4
|
-
* @typedef {{ cid: import('../src/link').AnyLink, bytes: Uint8Array }} AnyBlock
|
5
|
-
* @typedef {{ get: (link: import('../src/link').AnyLink) => Promise<AnyBlock | undefined> }} BlockFetcher
|
6
|
-
*/
|
7
|
-
|
8
|
-
/** @implements {BlockFetcher} */
|
9
|
-
export class MemoryBlockstore {
|
10
|
-
/** @type {Map<string, Uint8Array>} */
|
11
|
-
#blocks = new Map()
|
12
|
-
|
13
|
-
/**
|
14
|
-
* @param {import('../src/link').AnyLink} cid
|
15
|
-
* @returns {Promise<AnyBlock | undefined>}
|
16
|
-
*/
|
17
|
-
async get (cid) {
|
18
|
-
const bytes = this.#blocks.get(cid.toString())
|
19
|
-
if (!bytes) return
|
20
|
-
return { cid, bytes }
|
21
|
-
}
|
22
|
-
|
23
|
-
/**
|
24
|
-
* @param {import('../src/link').AnyLink} cid
|
25
|
-
* @param {Uint8Array} bytes
|
26
|
-
*/
|
27
|
-
async put (cid, bytes) {
|
28
|
-
// console.log('put', cid)
|
29
|
-
this.#blocks.set(cid.toString(), bytes)
|
30
|
-
}
|
31
|
-
|
32
|
-
/**
|
33
|
-
* @param {import('../src/link').AnyLink} cid
|
34
|
-
* @param {Uint8Array} bytes
|
35
|
-
*/
|
36
|
-
putSync (cid, bytes) {
|
37
|
-
this.#blocks.set(cid.toString(), bytes)
|
38
|
-
}
|
39
|
-
|
40
|
-
* entries () {
|
41
|
-
for (const [str, bytes] of this.#blocks) {
|
42
|
-
yield { cid: parse(str), bytes }
|
43
|
-
}
|
44
|
-
}
|
45
|
-
}
|
46
|
-
|
47
|
-
export class MultiBlockFetcher {
|
48
|
-
/** @type {BlockFetcher[]} */
|
49
|
-
#fetchers
|
50
|
-
|
51
|
-
/** @param {BlockFetcher[]} fetchers */
|
52
|
-
constructor (...fetchers) {
|
53
|
-
this.#fetchers = fetchers
|
54
|
-
}
|
55
|
-
|
56
|
-
/** @param {import('../src/link').AnyLink} link */
|
57
|
-
async get (link) {
|
58
|
-
for (const f of this.#fetchers) {
|
59
|
-
const v = await f.get(link)
|
60
|
-
if (v) {
|
61
|
-
return v
|
62
|
-
}
|
63
|
-
}
|
64
|
-
}
|
65
|
-
}
|