@fireproof/core 0.3.22 → 0.4.1

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.
@@ -1,14 +1,16 @@
1
- /* global localStorage */
2
1
  // @ts-ignore
3
2
  import { useEffect, useState, createContext } from 'react'
4
- import { Fireproof, Listener, Hydrator } from '../src/index'
3
+ import { Fireproof, Listener } from '../src/fireproof.js'
5
4
 
6
- // export interface FireproofCtxValue {
7
- // addSubscriber: (label: String, fn: Function) => void
8
- // database: Fireproof
9
- // ready: boolean
10
- // persist: () => void
11
- // }
5
+ /**
6
+ @typedef {Object} FireproofCtxValue
7
+ @property {Function} addSubscriber - A function to add a subscriber with a label and function.
8
+ @property {Fireproof} database - An instance of the Fireproof class.
9
+ @property {boolean} ready - A boolean indicating whether the database is ready.
10
+ @param {string} label - A label for the subscriber.
11
+ @param {Function} fn - A function to be added as a subscriber.
12
+ @returns {void}
13
+ */
12
14
  export const FireproofCtx = createContext({
13
15
  addSubscriber: () => {},
14
16
  database: null,
@@ -27,28 +29,24 @@ const initializeDatabase = name => {
27
29
  }
28
30
 
29
31
  /**
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
- ) {
32
+
33
+ @function useFireproof
34
+ React hook to initialize a Fireproof database, automatically saving and loading the clock.
35
+ You might need to import { nodePolyfills } from 'vite-plugin-node-polyfills' in your vite.config.ts
36
+ @param {string} name - The path to the database file
37
+ @param {function(database): void} [defineDatabaseFn] - Synchronous function that defines the database, run this before any async calls
38
+ @param {function(database): Promise<void>} [setupDatabaseFn] - Asynchronous function that sets up the database, run this to load fixture data etc
39
+ @returns {FireproofCtxValue} { addSubscriber, database, ready }
40
+ */
41
+ export function useFireproof (name = 'useFireproof', defineDatabaseFn = () => {}, setupDatabaseFn = async () => {}) {
42
42
  const [ready, setReady] = useState(false)
43
- initializeDatabase(name || 'useFireproof')
44
- const localStorageKey = 'fp.' + database.name
43
+ initializeDatabase(name)
45
44
 
46
45
  const addSubscriber = (label, fn) => {
47
46
  inboundSubscriberQueue.set(label, fn)
48
47
  }
49
48
 
50
49
  const listenerCallback = async event => {
51
- localSet(localStorageKey, JSON.stringify(database))
52
50
  if (event._external) return
53
51
  for (const [, fn] of inboundSubscriberQueue) fn()
54
52
  }
@@ -59,31 +57,11 @@ export function useFireproof (
59
57
  if (startedSetup) return
60
58
  startedSetup = true
61
59
  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 {
60
+ if (database.clock.length === 0) {
82
61
  await setupDatabaseFn(database)
83
- localSet(localStorageKey, JSON.stringify(database))
84
62
  }
85
63
  setReady(true)
86
- listener.on('*', listenerCallback)// hushed('*', listenerCallback, 250))
64
+ listener.on('*', listenerCallback) // hushed('*', listenerCallback, 250))
87
65
  }
88
66
  doSetup()
89
67
  }, [ready])
@@ -91,10 +69,7 @@ export function useFireproof (
91
69
  return {
92
70
  addSubscriber,
93
71
  database,
94
- ready,
95
- persist: () => {
96
- localSet(localStorageKey, JSON.stringify(database))
97
- }
72
+ ready
98
73
  }
99
74
  }
100
75
 
@@ -114,20 +89,20 @@ export function useFireproof (
114
89
  // (...args) =>
115
90
  // husher(id, () => workFn(...args), ms)
116
91
 
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
- }
92
+ // let storageSupported = false
93
+ // try {
94
+ // storageSupported = window.localStorage && true
95
+ // } catch (e) {}
96
+ // export function localGet (key) {
97
+ // if (storageSupported) {
98
+ // return localStorage && localStorage.getItem(key)
99
+ // }
100
+ // }
101
+ // function localSet (key, value) {
102
+ // if (storageSupported) {
103
+ // return localStorage && localStorage.setItem(key, value)
104
+ // }
105
+ // }
131
106
  // function localRemove(key) {
132
107
  // if (storageSupported) {
133
108
  // return localStorage && localStorage.removeItem(key)
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@fireproof/core",
3
- "version": "0.3.22",
3
+ "version": "0.4.1",
4
4
  "description": "Realtime database for IPFS",
5
- "main": "dist/src/index.js",
6
- "module": "dist/src/index.mjs",
7
- "typings": "dist/src/index.d.ts",
8
- "types": "dist/src/index.d.ts",
5
+ "main": "dist/src/fireproof.js",
6
+ "module": "dist/src/fireproof.mjs",
7
+ "typings": "dist/src/fireproof.d.ts",
8
+ "types": "dist/src/fireproof.d.ts",
9
9
  "type": "module",
10
10
  "scripts": {
11
11
  "keygen": "node scripts/keygen.js",
@@ -14,11 +14,11 @@
14
14
  "test:mocha": "mocha --reporter list test/*.test.js",
15
15
  "test:watch": "npm run test:mocha -- -w --parallel",
16
16
  "coverage": "c8 -r html -r text npm test",
17
- "prepublishOnly": "cp ../../README.md .",
17
+ "prepublishOnly": "cp ../../README.md . && npm run build",
18
18
  "postpublish": "rm README.md",
19
19
  "lint": "standard",
20
20
  "lint:fix": "standard --fix",
21
- "tbuild": "tsc --build",
21
+ "tsc": "tsc --watch",
22
22
  "build": "rollup -c"
23
23
  },
24
24
  "keywords": [
@@ -99,14 +99,13 @@
99
99
  "homepage": "https://fireproof.storage",
100
100
  "exports": {
101
101
  ".": {
102
- "types": "./dist/src/index.d.ts",
103
- "import": "./dist/src/index.mjs",
104
- "module": "./dist/src/index.mjs",
105
- "default": "./dist/src/index.js",
106
- "require": "./dist/src/index.js"
102
+ "types": "./dist/src/fireproof.d.ts",
103
+ "import": "./dist/src/fireproof.mjs",
104
+ "module": "./dist/src/fireproof.mjs",
105
+ "default": "./dist/src/fireproof.js",
106
+ "require": "./dist/src/fireproof.js"
107
107
  },
108
- "./use-fireproof": {
109
- "types": "./dist/hooks/use-fireproof.d.ts",
108
+ "./hooks/use-fireproof": {
110
109
  "import": "./hooks/use-fireproof.js"
111
110
  },
112
111
  "./package.json": "./package.json"
package/src/blockstore.js CHANGED
@@ -40,7 +40,10 @@ export class TransactionBlockstore {
40
40
  inflightTransactions = new Set()
41
41
 
42
42
  constructor (name, encryptionKey) {
43
- this.valet = new Valet(name, encryptionKey)
43
+ if (name) {
44
+ this.valet = new Valet(name, encryptionKey)
45
+ }
46
+ this.remoteBlockFunction = null
44
47
  }
45
48
 
46
49
  /**
@@ -73,6 +76,7 @@ export class TransactionBlockstore {
73
76
  async committedGet (key) {
74
77
  const old = this.committedBlocks.get(key)
75
78
  if (old) return old
79
+ if (!this.valet) throw new Error('Missing block: ' + key)
76
80
  const got = await this.valet.getBlock(key)
77
81
  // console.log('committedGet: ' + key)
78
82
  this.committedBlocks.set(key, got)
@@ -84,9 +88,9 @@ export class TransactionBlockstore {
84
88
  }
85
89
 
86
90
  async networkGet (key) {
87
- if (this.valet.remoteBlockFunction) {
91
+ if (this.remoteBlockFunction) {
88
92
  // todo why is this on valet?
89
- const value = await husher(key, async () => await this.valet.remoteBlockFunction(key))
93
+ const value = await husher(key, async () => await this.remoteBlockFunction(key))
90
94
  if (value) {
91
95
  // console.log('networkGot: ' + key, value.length)
92
96
  doTransaction('networkGot: ' + key, this, async innerBlockstore => {
@@ -166,7 +170,7 @@ export class TransactionBlockstore {
166
170
  cids.add(stringCid)
167
171
  }
168
172
  }
169
- if (cids.size > 0) {
173
+ if (cids.size > 0 && this.valet) {
170
174
  // console.log(innerBlockstore.label, 'committing', cids.size, 'blocks')
171
175
  await this.valet.writeTransaction(innerBlockstore, cids)
172
176
  }
@@ -0,0 +1,339 @@
1
+ // @ts-nocheck
2
+ import { visMerkleClock, visMerkleTree, vis, put, get, getAll, eventsSince } from './prolly.js'
3
+ import { doTransaction } from './blockstore.js'
4
+ import charwise from 'charwise'
5
+ import { localSet } from './utils.js'
6
+
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 {}
12
+
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 Database {
26
+ listeners = new Set()
27
+
28
+ // todo refactor this for the next version
29
+ constructor (blocks, clock, config = {}) {
30
+ this.name = config.name
31
+ this.instanceId = `fp.${this.name}.${Math.random().toString(36).substring(2, 7)}`
32
+ this.blocks = blocks
33
+ this.clock = clock
34
+ this.config = config
35
+ this.indexes = new Map()
36
+ }
37
+
38
+ /**
39
+ * Renders the Fireproof instance as a JSON object.
40
+ * @returns {Object} - The JSON representation of the Fireproof instance. Includes clock heads for the database and its indexes.
41
+ * @memberof Fireproof
42
+ * @instance
43
+ */
44
+ toJSON () {
45
+ // todo this also needs to return the index roots...
46
+ return {
47
+ clock: this.clockToJSON(),
48
+ name: this.name,
49
+ key: this.blocks.valet?.getKeyMaterial(),
50
+ indexes: [...this.indexes.values()].map(index => index.toJSON())
51
+ }
52
+ }
53
+
54
+ /**
55
+ * Returns the Merkle clock heads for the Fireproof instance.
56
+ * @returns {string[]} - The Merkle clock heads for the Fireproof instance.
57
+ * @memberof Fireproof
58
+ * @instance
59
+ */
60
+ clockToJSON () {
61
+ return this.clock.map(cid => cid.toString())
62
+ }
63
+
64
+ hydrate ({ clock, name, key }) {
65
+ this.name = name
66
+ this.clock = clock
67
+ this.blocks.valet?.setKeyMaterial(key)
68
+ this.indexBlocks = null
69
+ }
70
+
71
+ maybeSaveClock () {
72
+ if (this.name && this.blocks.valet) {
73
+ localSet('fp.' + this.name, JSON.stringify(this))
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Triggers a notification to all listeners
79
+ * of the Fireproof instance so they can repaint UI, etc.
80
+ * @returns {Promise<void>}
81
+ * @memberof Fireproof
82
+ * @instance
83
+ */
84
+ async notifyReset () {
85
+ await this.notifyListeners({ _reset: true, _clock: this.clockToJSON() })
86
+ }
87
+
88
+ // used be indexes etc to notify database listeners of new availability
89
+ async notifyExternal (source = 'unknown') {
90
+ await this.notifyListeners({ _external: source, _clock: this.clockToJSON() })
91
+ }
92
+
93
+ /**
94
+ * Returns the changes made to the Fireproof instance since the specified event.
95
+ * @function changesSince
96
+ * @param {CID[]} [event] - The clock head to retrieve changes since. If null or undefined, retrieves all changes.
97
+ * @returns {Promise<{rows : Object[], clock: CID[], proof: {}}>} An object containing the rows and the head of the instance's clock.
98
+ * @memberof Fireproof
99
+ * @instance
100
+ */
101
+ async changesSince (event) {
102
+ // console.log('changesSince', this.instanceId, event, this.clock)
103
+ let rows, dataCIDs, clockCIDs
104
+ // if (!event) event = []
105
+ if (event) {
106
+ const resp = await eventsSince(this.blocks, this.clock, event)
107
+ const docsMap = new Map()
108
+ for (const { key, type, value } of resp.result.map(decodeEvent)) {
109
+ if (type === 'del') {
110
+ docsMap.set(key, { key, del: true })
111
+ } else {
112
+ docsMap.set(key, { key, value })
113
+ }
114
+ }
115
+ rows = Array.from(docsMap.values())
116
+ clockCIDs = resp.clockCIDs
117
+ // console.log('change rows', this.instanceId, rows)
118
+ } else {
119
+ const allResp = await getAll(this.blocks, this.clock)
120
+ rows = allResp.result.map(({ key, value }) => (decodeEvent({ key, value })))
121
+ dataCIDs = allResp.cids
122
+ // console.log('dbdoc rows', this.instanceId, rows)
123
+ }
124
+ return {
125
+ rows,
126
+ clock: this.clockToJSON(),
127
+ proof: { data: await cidsToProof(dataCIDs), clock: await cidsToProof(clockCIDs) }
128
+ }
129
+ }
130
+
131
+ async allDocuments () {
132
+ const allResp = await getAll(this.blocks, this.clock)
133
+ const rows = allResp.result.map(({ key, value }) => (decodeEvent({ key, value }))).map(({ key, value }) => ({ key, value: { _id: key, ...value } }))
134
+ return {
135
+ rows,
136
+ clock: this.clockToJSON(),
137
+ proof: await cidsToProof(allResp.cids)
138
+ }
139
+ }
140
+
141
+ /**
142
+ * Runs validation on the specified document using the Fireproof instance's configuration. Throws an error if the document is invalid.
143
+ *
144
+ * @param {Object} doc - The document to validate.
145
+ * @returns {Promise<void>}
146
+ * @throws {Error} - Throws an error if the document is invalid.
147
+ * @memberof Fireproof
148
+ * @instance
149
+ */
150
+ async runValidation (doc) {
151
+ if (this.config && this.config.validateChange) {
152
+ const oldDoc = await this.get(doc._id)
153
+ .then((doc) => doc)
154
+ .catch(() => ({}))
155
+ this.config.validateChange(doc, oldDoc, this.authCtx)
156
+ }
157
+ }
158
+
159
+ /**
160
+ * Retrieves the document with the specified ID from the database
161
+ *
162
+ * @param {string} key - the ID of the document to retrieve
163
+ * @param {Object} [opts] - options
164
+ * @returns {Promise<{_id: string}>} - the document with the specified ID
165
+ * @memberof Fireproof
166
+ * @instance
167
+ */
168
+ async get (key, opts = {}) {
169
+ const clock = opts.clock || this.clock
170
+ const resp = await get(this.blocks, clock, charwise.encode(key))
171
+
172
+ // this tombstone is temporary until we can get the prolly tree to delete
173
+ if (!resp || resp.result === null) {
174
+ throw new Error('Not found')
175
+ }
176
+ const doc = resp.result
177
+ if (opts.mvcc === true) {
178
+ doc._clock = this.clockToJSON()
179
+ }
180
+ doc._proof = {
181
+ data: await cidsToProof(resp.cids),
182
+ clock: this.clockToJSON()
183
+ }
184
+ doc._id = key
185
+ return doc
186
+ }
187
+ /**
188
+ * @typedef {Object} Document
189
+ * @property {string} _id - The ID of the document (required)
190
+ * @property {string} [_proof] - The proof of the document (optional)
191
+ * @property {string} [_clock] - The clock of the document (optional)
192
+ * @property {any} [key: string] - Index signature notation to allow any other unknown fields
193
+ * * @property {Object.<string, any>} [otherProperties] - Any other unknown properties (optional)
194
+ */
195
+
196
+ /**
197
+ * Adds a new document to the database, or updates an existing document. Returns the ID of the document and the new clock head.
198
+ *
199
+ * @param {Document} doc - the document to be added
200
+ * @returns {Promise<{ id: string, clock: CID[] }>} - The result of adding the document to the database
201
+ * @memberof Fireproof
202
+ * @instance
203
+ */
204
+ async put ({ _id, _proof, ...doc }) {
205
+ const id = _id || 'f' + Math.random().toString(36).slice(2)
206
+ await this.runValidation({ _id: id, ...doc })
207
+ return await this.putToProllyTree({ key: id, value: doc }, doc._clock)
208
+ }
209
+
210
+ /**
211
+ * Deletes a document from the database
212
+ * @param {string | any} docOrId - the document ID
213
+ * @returns {Promise<{ id: string, clock: CID[] }>} - The result of deleting the document from the database
214
+ * @memberof Fireproof
215
+ * @instance
216
+ */
217
+ async del (docOrId) {
218
+ let id
219
+ let clock = null
220
+ if (docOrId._id) {
221
+ id = docOrId._id
222
+ clock = docOrId._clock
223
+ } else {
224
+ id = docOrId
225
+ }
226
+ await this.runValidation({ _id: id, _deleted: true })
227
+ return await this.putToProllyTree({ key: id, del: true }, clock) // not working at prolly tree layer?
228
+ // this tombstone is temporary until we can get the prolly tree to delete
229
+ // return await this.putToProllyTree({ key: id, value: null }, clock)
230
+ }
231
+
232
+ /**
233
+ * Updates the underlying storage with the specified event.
234
+ * @private
235
+ * @param {{del?: true, key : string, value?: any}} decodedEvent - the event to add
236
+ * @returns {Promise<{ proof:{}, id: string, clock: CID[] }>} - The result of adding the event to storage
237
+ */
238
+ async putToProllyTree (decodedEvent, clock = null) {
239
+ const event = encodeEvent(decodedEvent)
240
+ if (clock && JSON.stringify(clock) !== JSON.stringify(this.clockToJSON())) {
241
+ // we need to check and see what version of the document exists at the clock specified
242
+ // if it is the same as the one we are trying to put, then we can proceed
243
+ const resp = await eventsSince(this.blocks, this.clock, event.value._clock)
244
+ const missedChange = resp.result.find(({ key }) => key === event.key)
245
+ if (missedChange) {
246
+ throw new Error('MVCC conflict, document is changed, please reload the document and try again.')
247
+ }
248
+ }
249
+ const result = await doTransaction(
250
+ 'putToProllyTree',
251
+ this.blocks,
252
+ async (blocks) => await put(blocks, this.clock, event)
253
+ )
254
+ if (!result) {
255
+ console.error('failed', event)
256
+ throw new Error('failed to put at storage layer')
257
+ }
258
+ // console.log('new clock head', this.instanceId, result.head.toString())
259
+ this.clock = result.head // do we want to do this as a finally block
260
+ await this.notifyListeners([decodedEvent]) // this type is odd
261
+ return {
262
+ id: decodedEvent.key,
263
+ clock: this.clockToJSON(),
264
+ proof: { data: await cidsToProof(result.cids), clock: await cidsToProof(result.clockCIDs) }
265
+ }
266
+ // todo should include additions (or split clock)
267
+ }
268
+
269
+ // /**
270
+ // * Advances the clock to the specified event and updates the root CID
271
+ // * Will be used by replication
272
+ // */
273
+ // async advance (event) {
274
+ // this.clock = await advance(this.blocks, this.clock, event)
275
+ // this.rootCid = await root(this.blocks, this.clock)
276
+ // return this.clock
277
+ // }
278
+
279
+ async * vis () {
280
+ return yield * vis(this.blocks, this.clock)
281
+ }
282
+
283
+ async visTree () {
284
+ return await visMerkleTree(this.blocks, this.clock)
285
+ }
286
+
287
+ async visClock () {
288
+ return await visMerkleClock(this.blocks, this.clock)
289
+ }
290
+
291
+ /**
292
+ * Registers a Listener to be called when the Fireproof instance's clock is updated.
293
+ * Recieves live changes from the database after they are committed.
294
+ * @param {Function} listener - The listener to be called when the clock is updated.
295
+ * @returns {Function} - A function that can be called to unregister the listener.
296
+ * @memberof Fireproof
297
+ */
298
+ registerListener (listener) {
299
+ this.listeners.add(listener)
300
+ return () => {
301
+ this.listeners.delete(listener)
302
+ }
303
+ }
304
+
305
+ async notifyListeners (changes) {
306
+ // await sleep(10)
307
+ await this.maybeSaveClock()
308
+ for (const listener of this.listeners) {
309
+ await listener(changes)
310
+ }
311
+ }
312
+
313
+ setCarUploader (carUploaderFn) {
314
+ // console.log('registering car uploader')
315
+ // https://en.wikipedia.org/wiki/Law_of_Demeter - this is a violation of the law of demeter
316
+ this.blocks.valet.uploadFunction = carUploaderFn
317
+ }
318
+
319
+ setRemoteBlockReader (remoteBlockReaderFn) {
320
+ this.blocks.remoteBlockFunction = remoteBlockReaderFn
321
+ }
322
+ }
323
+
324
+ export async function cidsToProof (cids) {
325
+ if (!cids || !cids.all) return []
326
+ const all = await cids.all()
327
+ return [...all].map((cid) => cid.toString())
328
+ }
329
+
330
+ function decodeEvent (event) {
331
+ const decodedKey = charwise.decode(event.key)
332
+ return { ...event, key: decodedKey }
333
+ }
334
+
335
+ function encodeEvent (event) {
336
+ if (!(event && event.key)) return
337
+ const encodedKey = charwise.encode(event.key)
338
+ return { ...event, key: encodedKey }
339
+ }
package/src/db-index.js CHANGED
@@ -9,7 +9,7 @@ import { nocache as cache } from 'prolly-trees/cache'
9
9
  import { bf, simpleCompare } from 'prolly-trees/utils'
10
10
  import { makeGetBlock } from './prolly.js'
11
11
  // eslint-disable-next-line no-unused-vars
12
- import { Fireproof, cidsToProof } from './fireproof.js'
12
+ import { Database, cidsToProof } from './database.js'
13
13
 
14
14
  import * as codec from '@ipld/dag-cbor'
15
15
  // import { create as createBlock } from 'multiformats/block'
@@ -88,7 +88,7 @@ const indexEntriesForChanges = (changes, mapFn) => {
88
88
  * @class DbIndex
89
89
  * @classdesc An DbIndex can be used to order and filter the documents in a Fireproof database.
90
90
  *
91
- * @param {Fireproof} database - The Fireproof database instance to DbIndex.
91
+ * @param {Database} database - The Fireproof database instance to DbIndex.
92
92
  * @param {Function} mapFn - The map function to apply to each entry in the database.
93
93
  *
94
94
  */
@@ -96,7 +96,7 @@ export class DbIndex {
96
96
  constructor (database, mapFn, clock, opts = {}) {
97
97
  this.database = database
98
98
  if (!database.indexBlocks) {
99
- database.indexBlocks = new TransactionBlockstore(database.name + '.indexes', database.blocks.valet.getKeyMaterial())
99
+ database.indexBlocks = new TransactionBlockstore(database?.name + '.indexes', database.blocks.valet?.getKeyMaterial())
100
100
  }
101
101
  /**
102
102
  * The map function to apply to each entry in the database.