@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.
Files changed (55) hide show
  1. package/dist/blockstore.js +242 -0
  2. package/dist/clock.js +355 -0
  3. package/dist/crypto.js +59 -0
  4. package/dist/database.js +308 -0
  5. package/dist/db-index.js +314 -0
  6. package/dist/fireproof.js +83 -0
  7. package/dist/hooks/use-fireproof.js +100 -0
  8. package/dist/listener.js +110 -0
  9. package/dist/prolly.js +316 -0
  10. package/dist/sha1.js +74 -0
  11. package/dist/src/blockstore.js +242 -0
  12. package/dist/src/clock.js +355 -0
  13. package/dist/src/crypto.js +59 -0
  14. package/dist/src/database.js +312 -0
  15. package/dist/src/db-index.js +314 -0
  16. package/dist/src/fireproof.d.ts +319 -0
  17. package/dist/src/fireproof.js +38976 -0
  18. package/dist/src/fireproof.js.map +1 -0
  19. package/dist/src/fireproof.mjs +38972 -0
  20. package/dist/src/fireproof.mjs.map +1 -0
  21. package/dist/src/index.d.ts +1 -1
  22. package/dist/src/index.js +19 -14
  23. package/dist/src/index.js.map +1 -1
  24. package/dist/src/index.mjs +19 -14
  25. package/dist/src/index.mjs.map +1 -1
  26. package/dist/src/listener.js +108 -0
  27. package/dist/src/prolly.js +319 -0
  28. package/dist/src/sha1.js +74 -0
  29. package/dist/src/utils.js +16 -0
  30. package/dist/src/valet.js +262 -0
  31. package/dist/test/block.js +57 -0
  32. package/dist/test/clock.test.js +556 -0
  33. package/dist/test/db-index.test.js +231 -0
  34. package/dist/test/fireproof.test.js +444 -0
  35. package/dist/test/fulltext.test.js +61 -0
  36. package/dist/test/helpers.js +39 -0
  37. package/dist/test/hydrator.test.js +142 -0
  38. package/dist/test/listener.test.js +103 -0
  39. package/dist/test/prolly.test.js +162 -0
  40. package/dist/test/proofs.test.js +45 -0
  41. package/dist/test/reproduce-fixture-bug.test.js +57 -0
  42. package/dist/test/valet.test.js +56 -0
  43. package/dist/utils.js +16 -0
  44. package/dist/valet.js +262 -0
  45. package/hooks/use-fireproof.js +38 -63
  46. package/package.json +13 -14
  47. package/src/blockstore.js +8 -4
  48. package/src/database.js +338 -0
  49. package/src/db-index.js +3 -3
  50. package/src/fireproof.js +65 -322
  51. package/src/listener.js +10 -8
  52. package/src/prolly.js +10 -6
  53. package/src/utils.js +16 -0
  54. package/src/hydrator.js +0 -54
  55. 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
- // TypeScript Types
8
- // eslint-disable-next-line no-unused-vars
9
- // import { CID } from 'multiformats/dist/types/src/cid.js'
10
- // eslint-disable-next-line no-unused-vars
11
- class Proof {}
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
- * @class Fireproof
15
- * @classdesc Fireproof stores data in IndexedDB and provides a Merkle clock.
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 {Fireproof} - a new Fireproof instance
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
- async notifyReset () {
94
- await this.notifyListeners({ _reset: true, _clock: this.clockToJSON() })
95
- }
96
-
97
- // used be indexes etc to notify database listeners of new availability
98
- async notifyExternal (source = 'unknown') {
99
- await this.notifyListeners({ _external: source, _clock: this.clockToJSON() })
100
- }
101
-
102
- /**
103
- * Returns the changes made to the Fireproof instance since the specified event.
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
- id = docOrId
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
- * Updates the underlying storage with the specified event.
238
- * @private
239
- * @param {{del?: true, key : string, value?: any}} decodedEvent - the event to add
240
- * @returns {Promise<{ proof:{}, id: string, clock: CID[] }>} - The result of adding the event to storage
241
- */
242
- async putToProllyTree (decodedEvent, clock = null) {
243
- const event = encodeEvent(decodedEvent)
244
- if (clock && JSON.stringify(clock) !== JSON.stringify(this.clockToJSON())) {
245
- // we need to check and see what version of the document exists at the clock specified
246
- // if it is the same as the one we are trying to put, then we can proceed
247
- const resp = await eventsSince(this.blocks, this.clock, event.value._clock)
248
- const missedChange = resp.result.find(({ key }) => key === event.key)
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
- const result = await doTransaction(
254
- 'putToProllyTree',
255
- this.blocks,
256
- async (blocks) => await put(blocks, this.clock, event)
257
- )
258
- if (!result) {
259
- console.error('failed', event)
260
- throw new Error('failed to put at storage layer')
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
- // console.log('new clock head', this.instanceId, result.head.toString())
263
- this.clock = result.head // do we want to do this as a finally block
264
- await this.notifyListeners([decodedEvent]) // this type is odd
265
- return {
266
- id: decodedEvent.key,
267
- clock: this.clockToJSON(),
268
- proof: { data: await cidsToProof(result.cids), clock: await cidsToProof(result.clockCIDs) }
269
- }
270
- // todo should include additions (or split clock)
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('./fireproof.js').Fireproof} database - The Fireproof database instance to index.
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('./fireproof.js').Fireproof} database
17
+ * @param {import('./database.js').Database} database
18
18
  * @param {(_: any, emit: any) => void} routingFn
19
19
  */
20
- constructor (database, routingFn) {
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
- routingFn ||
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 {import('./blockstore.js').TransactionBlockstore} inBlocks Bucket block storage.
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 (transactionBlockstore) => {
252
- const { bigPut } = makeGetAndPutBlock(transactionBlockstore)
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 {import('./blockstore.js').TransactionBlockstore} blocks Bucket block storage.
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 {import('./blockstore.js').TransactionBlockstore} blocks Bucket block storage.
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 {import('./blockstore.js').TransactionBlockstore} blocks Bucket block storage.
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
- }
package/src/index.js DELETED
@@ -1,6 +0,0 @@
1
- import { Fireproof } from './fireproof.js'
2
- import { DbIndex as Index } from './db-index.js'
3
- import { Listener } from './listener.js'
4
- import { Hydrator } from './hydrator.js'
5
-
6
- export { Fireproof, Index, Listener, Hydrator }