@fireproof/core 0.0.2 → 0.0.4
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/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/block.js.html +280 -0
- package/coverage/blockstore.js.html +916 -0
- package/coverage/clock.js.html +1141 -0
- package/coverage/db-index.js.html +694 -0
- package/coverage/favicon.png +0 -0
- package/coverage/fireproof.js.html +856 -0
- package/coverage/index.html +221 -0
- package/coverage/listener.js.html +421 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/prolly.js.html +883 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +196 -0
- package/coverage/tmp/coverage-42191-1678146904346-0.json +1 -0
- package/coverage/tmp/coverage-42193-1678146903521-0.json +1 -0
- package/coverage/tmp/coverage-42196-1678146904322-0.json +1 -0
- package/coverage/tmp/coverage-42197-1678146904292-0.json +1 -0
- package/coverage/valet.js.html +589 -0
- package/hooks/use-fireproof.md +149 -0
- package/hooks/use-fireproof.ts +112 -0
- package/package.json +7 -4
- package/src/block.js +0 -10
- package/src/blockstore.js +53 -22
- package/src/db-index.js +71 -46
- package/src/fireproof.js +90 -44
- package/src/listener.js +23 -20
- package/src/prolly.js +53 -22
- package/src/valet.js +119 -93
- package/test/clock.test.js +60 -12
- package/test/db-index.test.js +3 -0
- package/test/listener.test.js +2 -3
- package/test/valet.test.js +59 -0
package/src/fireproof.js
CHANGED
@@ -1,28 +1,34 @@
|
|
1
|
-
// import { vis } from './clock.js'
|
2
1
|
import { put, get, getAll, eventsSince } from './prolly.js'
|
3
2
|
import Blockstore, { doTransaction } from './blockstore.js'
|
4
3
|
|
5
4
|
// const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
|
6
5
|
|
7
6
|
/**
|
8
|
-
*
|
7
|
+
* @class Fireproof
|
8
|
+
* @classdesc Fireproof stores data in IndexedDB and provides a Merkle clock.
|
9
|
+
* This is the main class for saving and loading JSON and other documents with the database. You can find additional examples and
|
10
|
+
* usage guides in the repository README.
|
9
11
|
*
|
10
|
-
* @
|
11
|
-
* @
|
12
|
-
*
|
13
|
-
* @param {Blockstore} blocks - The block storage instance to use for the underlying ProllyDB instance.
|
14
|
-
* @param {import('../clock').EventLink<import('../crdt').EventData>[]} clock - The Merkle clock head to use for the Fireproof instance.
|
12
|
+
* @param {Blockstore} blocks - The block storage instance to use documents and indexes
|
13
|
+
* @param {CID[]} clock - The Merkle clock head to use for the Fireproof instance.
|
15
14
|
* @param {object} [config] - Optional configuration options for the Fireproof instance.
|
16
15
|
* @param {object} [authCtx] - Optional authorization context object to use for any authentication checks.
|
17
16
|
*
|
18
17
|
*/
|
19
|
-
|
20
18
|
export default class Fireproof {
|
19
|
+
#listeners = new Set()
|
20
|
+
|
21
21
|
/**
|
22
|
-
* @
|
23
|
-
* @
|
22
|
+
* @function storage
|
23
|
+
* @memberof Fireproof
|
24
|
+
* Creates a new Fireproof instance with default storage settings
|
25
|
+
* Most apps should use this and not worry about the details.
|
26
|
+
* @static
|
27
|
+
* @returns {Fireproof} - a new Fireproof instance
|
24
28
|
*/
|
25
|
-
|
29
|
+
static storage = () => {
|
30
|
+
return new Fireproof(new Blockstore(), [])
|
31
|
+
}
|
26
32
|
|
27
33
|
constructor (blocks, clock, config = {}, authCtx = {}) {
|
28
34
|
this.blocks = blocks
|
@@ -33,12 +39,13 @@ export default class Fireproof {
|
|
33
39
|
}
|
34
40
|
|
35
41
|
/**
|
36
|
-
* Returns a snapshot of the current Fireproof instance.
|
37
|
-
*
|
38
|
-
* @param {
|
39
|
-
* Clock to use for the snapshot.
|
42
|
+
* Returns a snapshot of the current Fireproof instance as a new instance.
|
43
|
+
* @function snapshot
|
44
|
+
* @param {CID[]} clock - The Merkle clock head to use for the snapshot.
|
40
45
|
* @returns {Fireproof}
|
41
46
|
* A new Fireproof instance representing the snapshot.
|
47
|
+
* @memberof Fireproof
|
48
|
+
* @instance
|
42
49
|
*/
|
43
50
|
snapshot (clock) {
|
44
51
|
// how to handle listeners, views, and config?
|
@@ -47,14 +54,26 @@ export default class Fireproof {
|
|
47
54
|
}
|
48
55
|
|
49
56
|
/**
|
50
|
-
* This triggers a notification to all listeners
|
57
|
+
* Move the current instance to a new point in time. This triggers a notification to all listeners
|
58
|
+
* of the Fireproof instance so they can repaint UI, etc.
|
59
|
+
* @param {CID[] } clock
|
60
|
+
* Clock to use for the snapshot.
|
61
|
+
* @returns {Promise<void>}
|
62
|
+
* @memberof Fireproof
|
63
|
+
* @instance
|
51
64
|
*/
|
52
65
|
async setClock (clock) {
|
53
66
|
// console.log('setClock', this.instanceId, clock)
|
54
|
-
this.clock = clock.map((item) => item['/'] ? item['/'] : item)
|
67
|
+
this.clock = clock.map((item) => (item['/'] ? item['/'] : item))
|
55
68
|
await this.#notifyListeners({ reset: true, clock })
|
56
69
|
}
|
57
70
|
|
71
|
+
/**
|
72
|
+
* Renders the Fireproof instance as a JSON object.
|
73
|
+
* @returns {Object} - The JSON representation of the Fireproof instance. Includes clock heads for the database and its indexes.
|
74
|
+
* @memberof Fireproof
|
75
|
+
* @instance
|
76
|
+
*/
|
58
77
|
toJSON () {
|
59
78
|
// todo this also needs to return the index roots...
|
60
79
|
return { clock: this.clock }
|
@@ -62,13 +81,11 @@ export default class Fireproof {
|
|
62
81
|
|
63
82
|
/**
|
64
83
|
* Returns the changes made to the Fireproof instance since the specified event.
|
65
|
-
*
|
66
|
-
* @param {
|
67
|
-
*
|
68
|
-
* @
|
69
|
-
*
|
70
|
-
* head: import('../clock').EventLink<import('../crdt').EventData>[]
|
71
|
-
* }>} - An object `{rows : [...{key, value, del}], head}` containing the rows and the head of the instance's clock.
|
84
|
+
* @function changesSince
|
85
|
+
* @param {CID[]} [event] - The clock head to retrieve changes since. If null or undefined, retrieves all changes.
|
86
|
+
* @returns {Object<{rows : Object[], clock: CID[]}>} An object containing the rows and the head of the instance's clock.
|
87
|
+
* @memberof Fireproof
|
88
|
+
* @instance
|
72
89
|
*/
|
73
90
|
async changesSince (event) {
|
74
91
|
// console.log('changesSince', this.instanceId, event, this.clock)
|
@@ -97,6 +114,7 @@ export default class Fireproof {
|
|
97
114
|
* Recieves live changes from the database after they are committed.
|
98
115
|
* @param {Function} listener - The listener to be called when the clock is updated.
|
99
116
|
* @returns {Function} - A function that can be called to unregister the listener.
|
117
|
+
* @memberof Fireproof
|
100
118
|
*/
|
101
119
|
registerListener (listener) {
|
102
120
|
this.#listeners.add(listener)
|
@@ -107,15 +125,21 @@ export default class Fireproof {
|
|
107
125
|
|
108
126
|
async #notifyListeners (changes) {
|
109
127
|
// await sleep(0)
|
110
|
-
this.#listeners
|
128
|
+
for (const listener of this.#listeners) {
|
129
|
+
await listener(changes)
|
130
|
+
}
|
111
131
|
}
|
112
132
|
|
113
133
|
/**
|
114
|
-
* Runs validation on the specified document using the Fireproof instance's configuration.
|
134
|
+
* Runs validation on the specified document using the Fireproof instance's configuration. Throws an error if the document is invalid.
|
115
135
|
*
|
116
136
|
* @param {Object} doc - The document to validate.
|
137
|
+
* @returns {Promise<void>}
|
138
|
+
* @throws {Error} - Throws an error if the document is invalid.
|
139
|
+
* @memberof Fireproof
|
140
|
+
* @instance
|
117
141
|
*/
|
118
|
-
async runValidation (doc) {
|
142
|
+
async #runValidation (doc) {
|
119
143
|
if (this.config && this.config.validateChange) {
|
120
144
|
const oldDoc = await this.get(doc._id)
|
121
145
|
.then((doc) => doc)
|
@@ -125,35 +149,50 @@ export default class Fireproof {
|
|
125
149
|
}
|
126
150
|
|
127
151
|
/**
|
128
|
-
* Adds a new document to the database, or updates an existing document.
|
152
|
+
* Adds a new document to the database, or updates an existing document. Returns the ID of the document and the new clock head.
|
129
153
|
*
|
130
154
|
* @param {Object} doc - the document to be added
|
131
155
|
* @param {string} doc._id - the document ID. If not provided, a random ID will be generated.
|
132
156
|
* @param {Object} doc.* - the document data to be added
|
133
|
-
* @returns {
|
157
|
+
* @returns {Object<{ id: string, clock: CID[] }>} - The result of adding the document to the database
|
158
|
+
* @memberof Fireproof
|
159
|
+
* @instance
|
134
160
|
*/
|
135
161
|
async put ({ _id, ...doc }) {
|
136
162
|
const id = _id || 'f' + Math.random().toString(36).slice(2)
|
137
|
-
await this
|
138
|
-
return await this
|
163
|
+
await this.#runValidation({ _id: id, ...doc })
|
164
|
+
return await this.#putToProllyTree({ key: id, value: doc })
|
139
165
|
}
|
140
166
|
|
141
167
|
/**
|
142
168
|
* Deletes a document from the database
|
143
169
|
* @param {string} id - the document ID
|
144
|
-
* @returns {
|
170
|
+
* @returns {Object<{ id: string, clock: CID[] }>} - The result of deleting the document from the database
|
171
|
+
* @memberof Fireproof
|
172
|
+
* @instance
|
145
173
|
*/
|
146
174
|
async del (id) {
|
147
|
-
await this
|
148
|
-
// return await this
|
175
|
+
await this.#runValidation({ _id: id, _deleted: true })
|
176
|
+
// return await this.#putToProllyTree({ key: id, del: true }) // not working at prolly tree layer?
|
149
177
|
// this tombstone is temporary until we can get the prolly tree to delete
|
150
|
-
return await this
|
178
|
+
return await this.#putToProllyTree({ key: id, value: null })
|
151
179
|
}
|
152
180
|
|
153
|
-
|
154
|
-
|
181
|
+
/**
|
182
|
+
* Updates the underlying storage with the specified event.
|
183
|
+
* @private
|
184
|
+
* @param {CID[]} event - the event to add
|
185
|
+
* @returns {Object<{ id: string, clock: CID[] }>} - The result of adding the event to storage
|
186
|
+
*/
|
187
|
+
async #putToProllyTree (event) {
|
188
|
+
const result = await doTransaction(
|
189
|
+
'#putToProllyTree',
|
190
|
+
this.blocks,
|
191
|
+
async (blocks) => await put(blocks, this.clock, event)
|
192
|
+
)
|
155
193
|
if (!result) {
|
156
|
-
console.
|
194
|
+
console.error('failed', event)
|
195
|
+
throw new Error('failed to put at storage layer')
|
157
196
|
}
|
158
197
|
this.clock = result.head // do we want to do this as a finally block
|
159
198
|
result.id = event.key
|
@@ -164,8 +203,6 @@ export default class Fireproof {
|
|
164
203
|
// /**
|
165
204
|
// * Advances the clock to the specified event and updates the root CID
|
166
205
|
// * Will be used by replication
|
167
|
-
// * @param {import('../clock').EventLink<import('../crdt').EventData>} event - the event to advance to
|
168
|
-
// * @returns {import('../clock').EventLink<import('../crdt').EventData>[]} - the new clock after advancing
|
169
206
|
// */
|
170
207
|
// async advance (event) {
|
171
208
|
// this.clock = await advance(this.blocks, this.clock, event)
|
@@ -191,7 +228,9 @@ export default class Fireproof {
|
|
191
228
|
* Retrieves the document with the specified ID from the database
|
192
229
|
*
|
193
230
|
* @param {string} key - the ID of the document to retrieve
|
194
|
-
* @returns {
|
231
|
+
* @returns {Object<{_id: string, ...doc: Object}>} - the document with the specified ID
|
232
|
+
* @memberof Fireproof
|
233
|
+
* @instance
|
195
234
|
*/
|
196
235
|
async get (key) {
|
197
236
|
const got = await get(this.blocks, this.clock, key)
|
@@ -202,8 +241,15 @@ export default class Fireproof {
|
|
202
241
|
got._id = key
|
203
242
|
return got
|
204
243
|
}
|
205
|
-
}
|
206
244
|
|
207
|
-
|
208
|
-
|
245
|
+
setCarUploader (carUploaderFn) {
|
246
|
+
console.log('registering car uploader')
|
247
|
+
// https://en.wikipedia.org/wiki/Law_of_Demeter - this is a violation of the law of demeter
|
248
|
+
this.blocks.valet.uploadFunction = carUploaderFn
|
249
|
+
}
|
250
|
+
|
251
|
+
setRemoteBlockReader (remoteBlockReaderFn) {
|
252
|
+
// console.log('registering remote block reader')
|
253
|
+
this.blocks.valet.remoteBlockFunction = remoteBlockReaderFn
|
254
|
+
}
|
209
255
|
}
|
package/src/listener.js
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
/**
|
2
2
|
* A Fireproof database Listener allows you to react to events in the database.
|
3
3
|
*
|
4
|
-
* @class
|
5
|
-
* @classdesc An listener
|
6
|
-
*
|
7
|
-
* @param {import('./fireproof').Fireproof} database - The Fireproof database instance to index.
|
8
|
-
* @param {Function} eventFun - The map function to apply to each entry in the database.
|
4
|
+
* @class Listener
|
5
|
+
* @classdesc An listener attaches to a Fireproof database and runs a routing function on each change, sending the results to subscribers.
|
9
6
|
*
|
7
|
+
* @param {Fireproof} database - The Fireproof database instance to index.
|
8
|
+
* @param {Function} routingFn - The routing function to apply to each entry in the database.
|
10
9
|
*/
|
10
|
+
// import { ChangeEvent } from './db-index'
|
11
|
+
|
11
12
|
export default class Listener {
|
12
13
|
#subcribers = new Map()
|
13
14
|
|
@@ -18,15 +19,10 @@ export default class Listener {
|
|
18
19
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakRef
|
19
20
|
#doStopListening = null
|
20
21
|
|
21
|
-
|
22
|
-
|
23
|
-
* @param {import('./fireproof').Fireproof} database - The Fireproof database instance to index.
|
24
|
-
* @param {Function} eventFun - The event function to apply to each current change to the database.
|
25
|
-
*/
|
26
|
-
constructor (database, eventFun) {
|
27
|
-
/** eventFun
|
22
|
+
constructor (database, routingFn) {
|
23
|
+
/** routingFn
|
28
24
|
* The database instance to index.
|
29
|
-
* @type {
|
25
|
+
* @type {Fireproof}
|
30
26
|
*/
|
31
27
|
this.database = database
|
32
28
|
this.#doStopListening = database.registerListener((changes) => this.#onChanges(changes))
|
@@ -34,7 +30,11 @@ export default class Listener {
|
|
34
30
|
* The map function to apply to each entry in the database.
|
35
31
|
* @type {Function}
|
36
32
|
*/
|
37
|
-
this.
|
33
|
+
this.routingFn =
|
34
|
+
routingFn ||
|
35
|
+
function (_, emit) {
|
36
|
+
emit('*')
|
37
|
+
}
|
38
38
|
this.dbHead = null
|
39
39
|
}
|
40
40
|
|
@@ -43,13 +43,15 @@ export default class Listener {
|
|
43
43
|
* @param {string} topic - The topic to subscribe to.
|
44
44
|
* @param {Function} subscriber - The function to call when the topic is emitted.
|
45
45
|
* @returns {Function} A function to unsubscribe from the topic.
|
46
|
+
* @memberof Listener
|
47
|
+
* @instance
|
46
48
|
*/
|
47
49
|
on (topic, subscriber, since) {
|
48
50
|
const listOfTopicSubscribers = getTopicList(this.#subcribers, topic)
|
49
51
|
listOfTopicSubscribers.push(subscriber)
|
50
52
|
if (typeof since !== 'undefined') {
|
51
53
|
this.database.changesSince(since).then(({ rows: changes }) => {
|
52
|
-
const keys = topicsForChanges(changes, this.
|
54
|
+
const keys = topicsForChanges(changes, this.routingFn).get(topic)
|
53
55
|
if (keys) keys.forEach((key) => subscriber(key))
|
54
56
|
})
|
55
57
|
}
|
@@ -61,7 +63,7 @@ export default class Listener {
|
|
61
63
|
|
62
64
|
#onChanges (changes) {
|
63
65
|
if (Array.isArray(changes)) {
|
64
|
-
const seenTopics = topicsForChanges(changes, this.
|
66
|
+
const seenTopics = topicsForChanges(changes, this.routingFn)
|
65
67
|
for (const [topic, keys] of seenTopics) {
|
66
68
|
const listOfTopicSubscribers = getTopicList(this.#subcribers, topic)
|
67
69
|
listOfTopicSubscribers.forEach((subscriber) => keys.forEach((key) => subscriber(key)))
|
@@ -94,15 +96,16 @@ const makeDoc = ({ key, value }) => ({ _id: key, ...value })
|
|
94
96
|
/**
|
95
97
|
* Transforms a set of changes to events using an emitter function.
|
96
98
|
*
|
97
|
-
* @param {
|
98
|
-
* @param {Function}
|
99
|
+
* @param {ChangeEvent[]} changes
|
100
|
+
* @param {Function} routingFn
|
99
101
|
* @returns {Array<string>} The topics emmitted by the event function.
|
102
|
+
* @private
|
100
103
|
*/
|
101
|
-
const topicsForChanges = (changes,
|
104
|
+
const topicsForChanges = (changes, routingFn) => {
|
102
105
|
const seenTopics = new Map()
|
103
106
|
changes.forEach(({ key, value, del }) => {
|
104
107
|
if (del || !value) value = { _deleted: true }
|
105
|
-
|
108
|
+
routingFn(makeDoc({ key, value }), (t) => {
|
106
109
|
const topicList = getTopicList(seenTopics, t)
|
107
110
|
topicList.push(key)
|
108
111
|
})
|
package/src/prolly.js
CHANGED
@@ -1,4 +1,10 @@
|
|
1
|
-
import {
|
1
|
+
import {
|
2
|
+
advance,
|
3
|
+
EventFetcher,
|
4
|
+
EventBlock,
|
5
|
+
findCommonAncestorWithSortedEvents,
|
6
|
+
findUnknownSortedEvents
|
7
|
+
} from './clock.js'
|
2
8
|
import { create, load } from 'prolly-trees/map'
|
3
9
|
import * as codec from '@ipld/dag-cbor'
|
4
10
|
import { sha256 as hasher } from 'multiformats/hashes/sha2'
|
@@ -21,7 +27,36 @@ const makeGetBlock = (blocks) => async (address) => {
|
|
21
27
|
return createBlock({ cid, bytes, hasher, codec })
|
22
28
|
}
|
23
29
|
|
24
|
-
|
30
|
+
/**
|
31
|
+
* Creates and saves a new event.
|
32
|
+
* @param {import('./blockstore.js').Blockstore} inBlocks - A persistent blockstore.
|
33
|
+
* @param {MemoryBlockstore} mblocks - A temporary blockstore.
|
34
|
+
* @param {Function} getBlock - A function that gets a block.
|
35
|
+
* @param {Function} bigPut - A function that puts a block.
|
36
|
+
* @param {import('prolly-trees/map').Root} root - The root node.
|
37
|
+
* @param {Object<{ key: string, value: any, del: boolean }>} event - The update event.
|
38
|
+
* @param {CID[]} head - The head of the event chain.
|
39
|
+
* @param {Array<import('multiformats/block').Block>} additions - A array of additions.
|
40
|
+
* @param {Array<mport('multiformats/block').Block>>} removals - An array of removals.
|
41
|
+
* @returns {Promise<{
|
42
|
+
* root: import('prolly-trees/map').Root,
|
43
|
+
* additions: Map<string, import('multiformats/block').Block>,
|
44
|
+
* removals: Array<string>,
|
45
|
+
* head: CID[],
|
46
|
+
* event: CID[]
|
47
|
+
* }>}
|
48
|
+
*/
|
49
|
+
async function createAndSaveNewEvent (
|
50
|
+
inBlocks,
|
51
|
+
mblocks,
|
52
|
+
getBlock,
|
53
|
+
bigPut,
|
54
|
+
root,
|
55
|
+
{ key, value, del },
|
56
|
+
head,
|
57
|
+
additions,
|
58
|
+
removals = []
|
59
|
+
) {
|
25
60
|
const data = {
|
26
61
|
type: 'put',
|
27
62
|
root: {
|
@@ -100,7 +135,7 @@ const prollyRootFromAncestor = async (events, ancestor, getBlock) => {
|
|
100
135
|
* @param {import('./block').BlockFetcher} blocks Bucket block storage.
|
101
136
|
* @param {import('./clock').EventLink<EventData>[]} head Merkle clock head.
|
102
137
|
* @param {string} key The key of the value to put.
|
103
|
-
* @param {
|
138
|
+
* @param {CID} value The value to put.
|
104
139
|
* @param {object} [options]
|
105
140
|
* @returns {Promise<Result>}
|
106
141
|
*/
|
@@ -132,8 +167,16 @@ export async function put (inBlocks, head, event, options) {
|
|
132
167
|
bigPut(nb, additions)
|
133
168
|
}
|
134
169
|
|
135
|
-
return createAndSaveNewEvent(
|
136
|
-
|
170
|
+
return createAndSaveNewEvent(
|
171
|
+
inBlocks,
|
172
|
+
mblocks,
|
173
|
+
getBlock,
|
174
|
+
bigPut,
|
175
|
+
prollyRootBlock,
|
176
|
+
event,
|
177
|
+
head,
|
178
|
+
Array.from(additions.values()) /*, Array.from(removals.values()) */
|
179
|
+
)
|
137
180
|
}
|
138
181
|
|
139
182
|
/**
|
@@ -180,8 +223,11 @@ export async function eventsSince (blocks, head, since) {
|
|
180
223
|
throw new Error('no head')
|
181
224
|
}
|
182
225
|
const sinceHead = [...since, ...head]
|
183
|
-
const unknownSorted3 = await findUnknownSortedEvents(
|
184
|
-
|
226
|
+
const unknownSorted3 = await findUnknownSortedEvents(
|
227
|
+
blocks,
|
228
|
+
sinceHead,
|
229
|
+
await findCommonAncestorWithSortedEvents(blocks, sinceHead)
|
230
|
+
)
|
185
231
|
return unknownSorted3.map(({ value: { data } }) => data)
|
186
232
|
}
|
187
233
|
|
@@ -218,18 +264,3 @@ export async function get (blocks, head, key) {
|
|
218
264
|
const { result } = await prollyRootNode.get(key)
|
219
265
|
return result
|
220
266
|
}
|
221
|
-
|
222
|
-
/**
|
223
|
-
* @typedef {{
|
224
|
-
* type: 'put'|'del'
|
225
|
-
* key: string
|
226
|
-
* value: import('./link').AnyLink
|
227
|
-
* root: import('./shard').ShardLink
|
228
|
-
* }} EventData
|
229
|
-
*
|
230
|
-
* @typedef {{
|
231
|
-
* root: import('./shard').ShardLink
|
232
|
-
* head: import('./clock').EventLink<EventData>[]
|
233
|
-
* event: import('./clock').EventBlockView<EventData>
|
234
|
-
* } & import('./db-index').ShardDiff} Result
|
235
|
-
*/
|