@fireproof/core 0.8.0 → 0.10.1-dev
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +5 -184
- package/dist/fireproof.browser.js +18879 -0
- package/dist/fireproof.browser.js.map +7 -0
- package/dist/fireproof.cjs.js +9305 -0
- package/dist/fireproof.cjs.js.map +7 -0
- package/dist/fireproof.esm.js +9295 -0
- package/dist/fireproof.esm.js.map +7 -0
- package/package.json +57 -105
- package/dist/blockstore.js +0 -268
- package/dist/clock.js +0 -459
- package/dist/crypto.js +0 -63
- package/dist/database.js +0 -434
- package/dist/db-index.js +0 -403
- package/dist/encrypted-block.js +0 -48
- package/dist/fireproof.js +0 -84
- package/dist/import.js +0 -29
- package/dist/listener.js +0 -111
- package/dist/loader.js +0 -13
- package/dist/prolly.js +0 -405
- package/dist/remote.js +0 -102
- package/dist/sha1.js +0 -74
- package/dist/src/fireproof.d.ts +0 -472
- package/dist/src/fireproof.js +0 -81191
- package/dist/src/fireproof.js.map +0 -1
- package/dist/src/fireproof.mjs +0 -81186
- package/dist/src/fireproof.mjs.map +0 -1
- package/dist/storage/base.js +0 -426
- package/dist/storage/blocksToEncryptedCarBlock.js +0 -144
- package/dist/storage/browser.js +0 -62
- package/dist/storage/filesystem.js +0 -67
- package/dist/storage/rest.js +0 -57
- package/dist/storage/ucan.js +0 -0
- package/dist/storage/utils.js +0 -144
- package/dist/sync.js +0 -218
- package/dist/utils.js +0 -16
- package/dist/valet.js +0 -102
- package/src/blockstore.js +0 -283
- package/src/clock.js +0 -486
- package/src/crypto.js +0 -70
- package/src/database.js +0 -469
- package/src/db-index.js +0 -426
- package/src/encrypted-block.js +0 -57
- package/src/fireproof.js +0 -98
- package/src/import.js +0 -34
- package/src/link.d.ts +0 -3
- package/src/loader.js +0 -16
- package/src/prolly.js +0 -445
- package/src/remote.js +0 -113
- package/src/sha1.js +0 -83
- package/src/storage/base.js +0 -463
- package/src/storage/browser.js +0 -67
- package/src/storage/filesystem.js +0 -73
- package/src/storage/rest.js +0 -59
- package/src/storage/ucan.js +0 -0
- package/src/storage/utils.js +0 -152
- package/src/sync.js +0 -237
- package/src/valet.js +0 -105
package/src/clock.js
DELETED
@@ -1,486 +0,0 @@
|
|
1
|
-
import { Block, encode, decode } from 'multiformats/block'
|
2
|
-
import { sha256 } from 'multiformats/hashes/sha2'
|
3
|
-
import * as cbor from '@ipld/dag-cbor'
|
4
|
-
// @ts-ignore
|
5
|
-
import { CIDCounter } from 'prolly-trees/utils'
|
6
|
-
|
7
|
-
/**
|
8
|
-
* @template T
|
9
|
-
* @typedef {{ parents: EventLink<T>[], data: T }} EventView
|
10
|
-
*/
|
11
|
-
|
12
|
-
/**
|
13
|
-
* @template T
|
14
|
-
* @typedef {import('multiformats').BlockView<EventView<T>>} EventBlockView
|
15
|
-
*/
|
16
|
-
|
17
|
-
/**
|
18
|
-
* @template T
|
19
|
-
* @typedef {import('multiformats').Link<EventView<T>>} EventLink
|
20
|
-
*/
|
21
|
-
|
22
|
-
/**
|
23
|
-
* @typedef {{
|
24
|
-
* type: 'put'|'del'
|
25
|
-
* key: string
|
26
|
-
* value: import('./link').AnyLink
|
27
|
-
* root: import('./link').AnyLink
|
28
|
-
* }} EventData
|
29
|
-
* @typedef {{
|
30
|
-
* root: import('./link').AnyLink
|
31
|
-
* head: import('./clock').EventLink<EventData>[]
|
32
|
-
* event: import('./clock').EventBlockView<EventData>
|
33
|
-
* }} Result
|
34
|
-
*/
|
35
|
-
|
36
|
-
/**
|
37
|
-
* Advance the clock by adding an event.
|
38
|
-
*
|
39
|
-
* @template T
|
40
|
-
* @param {import('./blockstore').TransactionBlockstore} blocks Block storage.
|
41
|
-
* @param {EventLink<T>[]} head The head of the clock.
|
42
|
-
* @param {EventLink<T>} event The event to add.
|
43
|
-
* @returns {Promise<{head:EventLink<T>[], cids:any[]}>} The new head of the clock.
|
44
|
-
*/
|
45
|
-
export async function advance (blocks, head, event) {
|
46
|
-
/** @type {EventFetcher<T>} */
|
47
|
-
const events = new EventFetcher(blocks)
|
48
|
-
const headmap = new Map(head.map(cid => [cid.toString(), cid]))
|
49
|
-
|
50
|
-
// Check if the headmap already includes the event, return head if it does
|
51
|
-
if (headmap.has(event.toString())) return { head, cids: await events.all() }
|
52
|
-
|
53
|
-
// Does event contain the clock?
|
54
|
-
let changed = false
|
55
|
-
for (const cid of head) {
|
56
|
-
if (await contains(events, event, cid)) {
|
57
|
-
headmap.delete(cid.toString())
|
58
|
-
headmap.set(event.toString(), event)
|
59
|
-
changed = true
|
60
|
-
}
|
61
|
-
}
|
62
|
-
|
63
|
-
// If the headmap has been changed, return the new headmap values
|
64
|
-
if (changed) {
|
65
|
-
return { head: [...headmap.values()], cids: await events.all() }
|
66
|
-
}
|
67
|
-
|
68
|
-
// Does clock contain the event?
|
69
|
-
for (const p of head) {
|
70
|
-
if (await contains(events, p, event)) {
|
71
|
-
return { head, cids: await events.all() }
|
72
|
-
}
|
73
|
-
}
|
74
|
-
|
75
|
-
// Return the head concatenated with the new event if it passes both checks
|
76
|
-
return { head: head.concat(event), cids: await events.all() }
|
77
|
-
}
|
78
|
-
|
79
|
-
/**
|
80
|
-
* @template T
|
81
|
-
* @implements {EventBlockView<T>}
|
82
|
-
*/
|
83
|
-
export class EventBlock extends Block {
|
84
|
-
/**
|
85
|
-
* @param {object} config
|
86
|
-
* @param {EventLink<T>} config.cid
|
87
|
-
* @param {Event} config.value
|
88
|
-
* @param {Uint8Array} config.bytes
|
89
|
-
*/
|
90
|
-
constructor ({ cid, value, bytes }) {
|
91
|
-
// @ts-ignore
|
92
|
-
super({ cid, value, bytes })
|
93
|
-
}
|
94
|
-
|
95
|
-
/**
|
96
|
-
* @template T
|
97
|
-
* @param {T} data
|
98
|
-
* @param {EventLink<T>[]} [parents]
|
99
|
-
*/
|
100
|
-
static create (data, parents) {
|
101
|
-
return encodeEventBlock({ data, parents: parents ?? [] })
|
102
|
-
}
|
103
|
-
}
|
104
|
-
|
105
|
-
/** @template T */
|
106
|
-
export class EventFetcher {
|
107
|
-
/** @param {import('./blockstore').TransactionBlockstore} blocks */
|
108
|
-
constructor (blocks) {
|
109
|
-
/** @private */
|
110
|
-
this._blocks = blocks
|
111
|
-
this._cids = new CIDCounter()
|
112
|
-
this._cache = new Map()
|
113
|
-
}
|
114
|
-
|
115
|
-
/**
|
116
|
-
* @param {EventLink<T>} link
|
117
|
-
* @returns {Promise<EventBlockView<T>>}
|
118
|
-
*/
|
119
|
-
async get (link) {
|
120
|
-
const slink = link.toString()
|
121
|
-
// console.log('get', link.toString())
|
122
|
-
if (this._cache.has(slink)) return this._cache.get(slink)
|
123
|
-
const block = await this._blocks.get(link)
|
124
|
-
this._cids.add({ address: link })
|
125
|
-
if (!block) throw new Error(`missing block: ${link}`)
|
126
|
-
const got = decodeEventBlock(block.bytes)
|
127
|
-
this._cache.set(slink, got)
|
128
|
-
return got
|
129
|
-
}
|
130
|
-
|
131
|
-
async all () {
|
132
|
-
// await Promise.all([...this._cids])
|
133
|
-
return this._cids.all()
|
134
|
-
}
|
135
|
-
}
|
136
|
-
|
137
|
-
/**
|
138
|
-
* @template T
|
139
|
-
* @param {EventView<T>} value
|
140
|
-
* @returns {Promise<EventBlockView<T>>}
|
141
|
-
*/
|
142
|
-
export async function encodeEventBlock (value) {
|
143
|
-
// TODO: sort parents
|
144
|
-
const { cid, bytes } = await encode({ value, codec: cbor, hasher: sha256 })
|
145
|
-
// @ts-ignore
|
146
|
-
return new Block({ cid, value, bytes })
|
147
|
-
}
|
148
|
-
|
149
|
-
/**
|
150
|
-
* @template T
|
151
|
-
* @param {Uint8Array} bytes
|
152
|
-
* @returns {Promise<EventBlockView<T>>}
|
153
|
-
*/
|
154
|
-
export async function decodeEventBlock (bytes) {
|
155
|
-
const { cid, value } = await decode({ bytes, codec: cbor, hasher: sha256 })
|
156
|
-
// @ts-ignore
|
157
|
-
return new Block({ cid, value, bytes })
|
158
|
-
}
|
159
|
-
|
160
|
-
/**
|
161
|
-
* Returns true if event "a" contains event "b". Breadth first search.
|
162
|
-
* @template T
|
163
|
-
* @param {EventFetcher} events
|
164
|
-
* @param {EventLink<T>} a
|
165
|
-
* @param {EventLink<T>} b
|
166
|
-
*/
|
167
|
-
async function contains (events, a, b) {
|
168
|
-
if (a.toString() === b.toString()) return true
|
169
|
-
const [{ value: aevent }, { value: bevent }] = await Promise.all([events.get(a), events.get(b)])
|
170
|
-
// const links = [...aevent.parents]
|
171
|
-
// console.log('aevent', aevent.parents)
|
172
|
-
const links = [...(aevent.parents || [])]
|
173
|
-
while (links.length) {
|
174
|
-
const link = links.shift()
|
175
|
-
if (!link) break
|
176
|
-
if (link.toString() === b.toString()) return true
|
177
|
-
// if any of b's parents are this link, then b cannot exist in any of the
|
178
|
-
// tree below, since that would create a cycle.
|
179
|
-
if (bevent.parents.some(p => link.toString() === p.toString())) continue
|
180
|
-
const { value: event } = await events.get(link)
|
181
|
-
links.push(...event.parents)
|
182
|
-
}
|
183
|
-
return false
|
184
|
-
}
|
185
|
-
|
186
|
-
/**
|
187
|
-
* @template T
|
188
|
-
* @param {import('./blockstore').TransactionBlockstore} blocks Block storage.
|
189
|
-
* @param {EventLink<T>[]} head
|
190
|
-
* @param {object} [options]
|
191
|
-
* @param {(b: EventBlockView<T>) => string} [options.renderNodeLabel]
|
192
|
-
*/
|
193
|
-
export async function * vis (blocks, head, options = {}) {
|
194
|
-
// @ts-ignore
|
195
|
-
const renderNodeLabel =
|
196
|
-
options.renderNodeLabel ??
|
197
|
-
(b => {
|
198
|
-
// @ts-ignore
|
199
|
-
const { key, root, type } = b.value.data
|
200
|
-
return (
|
201
|
-
b.cid.toString() + '\n' + JSON.stringify({ key, root: root.cid.toString(), type }, null, 2).replace(/"/g, "'")
|
202
|
-
)
|
203
|
-
})
|
204
|
-
const events = new EventFetcher(blocks)
|
205
|
-
yield 'digraph clock {'
|
206
|
-
yield ' node [shape=point fontname="Courier"]; head;'
|
207
|
-
const hevents = await Promise.all(head.map(link => events.get(link)))
|
208
|
-
const links = []
|
209
|
-
const nodes = new Set()
|
210
|
-
for (const e of hevents) {
|
211
|
-
nodes.add(e.cid.toString())
|
212
|
-
yield ` node [shape=oval fontname="Courier"]; ${e.cid} [label="${renderNodeLabel(e)}"];`
|
213
|
-
yield ` head -> ${e.cid};`
|
214
|
-
for (const p of e.value.parents) {
|
215
|
-
yield ` ${e.cid} -> ${p};`
|
216
|
-
}
|
217
|
-
links.push(...e.value.parents)
|
218
|
-
}
|
219
|
-
while (links.length) {
|
220
|
-
const link = links.shift()
|
221
|
-
if (!link) break
|
222
|
-
if (nodes.has(link.toString())) continue
|
223
|
-
nodes.add(link.toString())
|
224
|
-
const block = await events.get(link)
|
225
|
-
yield ` node [shape=oval]; ${link} [label="${renderNodeLabel(block)}" fontname="Courier"];`
|
226
|
-
for (const p of block.value.parents) {
|
227
|
-
yield ` ${link} -> ${p};`
|
228
|
-
}
|
229
|
-
links.push(...block.value.parents)
|
230
|
-
}
|
231
|
-
yield '}'
|
232
|
-
}
|
233
|
-
|
234
|
-
export async function findEventsToSync (blocks, head) {
|
235
|
-
// const callTag = Math.random().toString(36).substring(7)
|
236
|
-
const events = new EventFetcher(blocks)
|
237
|
-
// console.time(callTag + '.findCommonAncestorWithSortedEvents')
|
238
|
-
const { ancestor, sorted } = await findCommonAncestorWithSortedEvents(events, head)
|
239
|
-
// console.timeEnd(callTag + '.findCommonAncestorWithSortedEvents')
|
240
|
-
// console.log('sorted', !!ancestor, sorted)
|
241
|
-
// console.time(callTag + '.contains')
|
242
|
-
|
243
|
-
const toSync = ancestor ? await asyncFilter(sorted, async uks => !(await contains(events, ancestor, uks.cid))) : sorted
|
244
|
-
// console.timeEnd(callTag + '.contains')
|
245
|
-
const sortDifference = sorted.length - toSync.length
|
246
|
-
if (sortDifference / sorted.length > 0.6) console.log('optimize sorted', !!ancestor, sortDifference)
|
247
|
-
|
248
|
-
return { cids: events, events: toSync }
|
249
|
-
}
|
250
|
-
|
251
|
-
const asyncFilter = async (arr, predicate) =>
|
252
|
-
Promise.all(arr.map(predicate)).then(results => arr.filter((_v, index) => results[index]))
|
253
|
-
|
254
|
-
export async function findCommonAncestorWithSortedEvents (events, children, doFull = false) {
|
255
|
-
// console.trace('findCommonAncestorWithSortedEvents')
|
256
|
-
// const callTag = Math.random().toString(36).substring(7)
|
257
|
-
// console.log(callTag + '.children', children.map((c) => c.toString()))
|
258
|
-
// console.time(callTag + '.findCommonAncestor')
|
259
|
-
const ancestor = await findCommonAncestor(events, children)
|
260
|
-
// console.timeEnd(callTag + '.findCommonAncestor')
|
261
|
-
// console.log('ancestor', ancestor.toString())
|
262
|
-
if (!ancestor) {
|
263
|
-
console.log('no common ancestor', children)
|
264
|
-
// throw new Error('no common ancestor')
|
265
|
-
const sorted = await findSortedEvents(events, children, children, doFull)
|
266
|
-
return { ancestor: null, sorted }
|
267
|
-
}
|
268
|
-
// console.time(callTag + '.findSortedEvents')
|
269
|
-
const sorted = await findSortedEvents(events, children, [ancestor], doFull)
|
270
|
-
// console.timeEnd(callTag + '.findSortedEvents')
|
271
|
-
// console.log('sorted', sorted.length)
|
272
|
-
// console.log('ancestor', JSON.stringify(ancestor, null, 2))
|
273
|
-
return { ancestor, sorted }
|
274
|
-
}
|
275
|
-
|
276
|
-
/**
|
277
|
-
* Find the common ancestor event of the passed children. A common ancestor is
|
278
|
-
* the first single event in the DAG that _all_ paths from children lead to.
|
279
|
-
*
|
280
|
-
* @param {import('./clock').EventFetcher} events
|
281
|
-
* @param {import('./clock').EventLink<EventData>[]} children
|
282
|
-
*/
|
283
|
-
// async function NEWfindCommonAncestor (events, children) {
|
284
|
-
// if (!children.length) return
|
285
|
-
// if (children.length === 1) return children[0]
|
286
|
-
|
287
|
-
// const candidates = children.map(c => [c])
|
288
|
-
// const visited = new Set()
|
289
|
-
|
290
|
-
// while (true) {
|
291
|
-
// let changed = false
|
292
|
-
// for (const c of candidates) {
|
293
|
-
// const candidate = await findAncestorCandidate(events, c[c.length - 1])
|
294
|
-
|
295
|
-
// if (!candidate) continue
|
296
|
-
|
297
|
-
// if (visited.has(candidate)) {
|
298
|
-
// return candidate // Common ancestor found
|
299
|
-
// }
|
300
|
-
|
301
|
-
// visited.add(candidate)
|
302
|
-
// changed = true
|
303
|
-
// c.push(candidate)
|
304
|
-
// }
|
305
|
-
|
306
|
-
// if (!changed) {
|
307
|
-
// // No common ancestor found, exhausted candidates
|
308
|
-
// return null
|
309
|
-
// }
|
310
|
-
// }
|
311
|
-
// }
|
312
|
-
|
313
|
-
async function findCommonAncestor (events, children) {
|
314
|
-
if (!children.length) return
|
315
|
-
children = [...new Set(children)]
|
316
|
-
if (children.length === 1) return children[0]
|
317
|
-
const candidates = children.map((c) => [c])
|
318
|
-
// console.log(
|
319
|
-
// 'og candidates',
|
320
|
-
// candidates.map((c) => c.toString())
|
321
|
-
// )
|
322
|
-
while (true) {
|
323
|
-
let changed = false
|
324
|
-
for (const c of candidates) {
|
325
|
-
const candidate = await findAncestorCandidate(events, c[c.length - 1])
|
326
|
-
if (!candidate) continue
|
327
|
-
|
328
|
-
// Check if the candidate is already in the list, and if so, skip it.
|
329
|
-
if (c.includes(candidate)) continue
|
330
|
-
|
331
|
-
// if set size is all cids, then no common ancestor
|
332
|
-
changed = true
|
333
|
-
c.push(candidate) // make set?
|
334
|
-
// console.log('candidate', candidates.map((c) => c.toString()))
|
335
|
-
const ancestor = findCommonString(candidates)
|
336
|
-
if (ancestor) return ancestor
|
337
|
-
}
|
338
|
-
if (!changed) return
|
339
|
-
}
|
340
|
-
}
|
341
|
-
|
342
|
-
// async function OGfindCommonAncestor (events, children) {
|
343
|
-
// if (!children.length) return
|
344
|
-
// if (children.length === 1) return children[0]
|
345
|
-
// const candidates = children.map(c => [c])
|
346
|
-
// console.log(
|
347
|
-
// 'og candidates',
|
348
|
-
// candidates.map(c => c.toString())
|
349
|
-
// )
|
350
|
-
// while (true) {
|
351
|
-
// let changed = false
|
352
|
-
// for (const c of candidates) {
|
353
|
-
// const candidate = await findAncestorCandidate(events, c[c.length - 1])
|
354
|
-
// if (!candidate) continue
|
355
|
-
// // if set size is all cids, then no common ancestor
|
356
|
-
// changed = true
|
357
|
-
// c.push(candidate) // make set?
|
358
|
-
// console.log(
|
359
|
-
// 'candidate',
|
360
|
-
// candidates.map(c => c.toString())
|
361
|
-
// )
|
362
|
-
// const ancestor = findCommonString(candidates)
|
363
|
-
// if (ancestor) return ancestor
|
364
|
-
// }
|
365
|
-
// if (!changed) return
|
366
|
-
// }
|
367
|
-
// }
|
368
|
-
|
369
|
-
/**
|
370
|
-
* @param {import('./clock').EventFetcher} events
|
371
|
-
* @param {import('./clock').EventLink<EventData>} root
|
372
|
-
*/
|
373
|
-
async function findAncestorCandidate (events, root) {
|
374
|
-
const { value: event } = await events.get(root) // .catch(() => ({ value: { parents: [] } }))
|
375
|
-
// console.log(
|
376
|
-
// 'findAncestorCandidate',
|
377
|
-
// root.toString(),
|
378
|
-
// 'parents',
|
379
|
-
// event.parents.map(p => p.toString())
|
380
|
-
// )
|
381
|
-
if (!event.parents.length) return root
|
382
|
-
return event.parents.length === 1 ? event.parents[0] : findCommonAncestor(events, event.parents)
|
383
|
-
}
|
384
|
-
|
385
|
-
/**
|
386
|
-
* @template {{ toString: () => string }} T
|
387
|
-
* @param {Array<T[]>} arrays
|
388
|
-
*/
|
389
|
-
function findCommonString (arrays) {
|
390
|
-
// console.log('findCommonString', arrays.map((a) => a.map((i) => String(i))))
|
391
|
-
arrays = arrays.map(a => [...a])
|
392
|
-
for (const arr of arrays) {
|
393
|
-
for (const item of arr) {
|
394
|
-
let matched = true
|
395
|
-
for (const other of arrays) {
|
396
|
-
if (arr === other) continue
|
397
|
-
matched = other.some(i => String(i) === String(item))
|
398
|
-
if (!matched) break
|
399
|
-
}
|
400
|
-
if (matched) return item
|
401
|
-
}
|
402
|
-
}
|
403
|
-
}
|
404
|
-
|
405
|
-
/**
|
406
|
-
* Find and sort events between the head(s) and the tail.
|
407
|
-
* @param {import('./clock').EventFetcher} events
|
408
|
-
* @param {any[]} head
|
409
|
-
* @param {import('./clock').EventLink<EventData>[]} tails
|
410
|
-
*/
|
411
|
-
async function findSortedEvents (events, head, tails, doFull) {
|
412
|
-
// const callTag = Math.random().toString(36).substring(7)
|
413
|
-
// get weighted events - heavier events happened first
|
414
|
-
// const callTag = Math.random().toString(36).substring(7)
|
415
|
-
|
416
|
-
/** @type {Map<string, { event: import('./clock').EventBlockView<EventData>, weight: number }>} */
|
417
|
-
const weights = new Map()
|
418
|
-
head = [...new Set([...head.map(h => h.toString())])]
|
419
|
-
// console.log(callTag + '.head', head.length)
|
420
|
-
|
421
|
-
const allEvents = new Set([tails.map((t) => t.toString()).toString(), ...head])
|
422
|
-
if (!doFull && allEvents.size === 1) {
|
423
|
-
// console.log('head contains tail', tail.toString())
|
424
|
-
return []
|
425
|
-
// const event = await events.get(tail)
|
426
|
-
// return [event]
|
427
|
-
}
|
428
|
-
|
429
|
-
// console.log('finding events')
|
430
|
-
// console.log(callTag + '.head', head.length, [...head.map((h) => h.toString())], tail.toString())
|
431
|
-
|
432
|
-
// console.time(callTag + '.findEvents')
|
433
|
-
const all = await (await Promise.all(tails.map((t) => Promise.all(head.map(h => findEvents(events, h, t)))))).flat()
|
434
|
-
// console.log('all', all.length)
|
435
|
-
// console.timeEnd(callTag + '.findEvents')
|
436
|
-
for (const arr of all) {
|
437
|
-
for (const { event, depth } of arr) {
|
438
|
-
// console.log('event value', event.value.data.value)
|
439
|
-
const info = weights.get(event.cid.toString())
|
440
|
-
if (info) {
|
441
|
-
info.weight += depth
|
442
|
-
} else {
|
443
|
-
weights.set(event.cid.toString(), { event, weight: depth })
|
444
|
-
}
|
445
|
-
}
|
446
|
-
}
|
447
|
-
|
448
|
-
// group events into buckets by weight
|
449
|
-
/** @type {Map<number, import('./clock').EventBlockView<EventData>[]>} */
|
450
|
-
const buckets = new Map()
|
451
|
-
for (const { event, weight } of weights.values()) {
|
452
|
-
const bucket = buckets.get(weight)
|
453
|
-
if (bucket) {
|
454
|
-
bucket.push(event)
|
455
|
-
} else {
|
456
|
-
buckets.set(weight, [event])
|
457
|
-
}
|
458
|
-
}
|
459
|
-
|
460
|
-
// sort by weight, and by CID within weight
|
461
|
-
const sorted = Array.from(buckets)
|
462
|
-
.sort((a, b) => b[0] - a[0])
|
463
|
-
.flatMap(([, es]) => es.sort((a, b) => (String(a.cid) < String(b.cid) ? -1 : 1)))
|
464
|
-
// console.log('sorted', sorted.map(s => s.cid))
|
465
|
-
|
466
|
-
return sorted
|
467
|
-
}
|
468
|
-
|
469
|
-
/**
|
470
|
-
* @param {EventFetcher} events
|
471
|
-
* @param {EventLink<EventData>} start
|
472
|
-
* @param {EventLink<EventData>} end
|
473
|
-
* @returns {Promise<Array<{ event: EventBlockView<EventData>, depth: number }>>}
|
474
|
-
*/
|
475
|
-
async function findEvents (events, start, end, depth = 0) {
|
476
|
-
// console.log('findEvents', start.toString(), end.toString(), depth)
|
477
|
-
const event = await events.get(start)
|
478
|
-
const send = String(end)
|
479
|
-
const acc = [{ event, depth }]
|
480
|
-
const { parents } = event.value
|
481
|
-
// if (parents.length === 1 && String(parents[0]) === send) return acc
|
482
|
-
if (parents.findIndex(p => String(p) === send) !== -1) return acc
|
483
|
-
// if (parents.length === 1) return acc
|
484
|
-
const rest = await Promise.all(parents.map(p => findEvents(events, p, end, depth + 1)))
|
485
|
-
return acc.concat(...rest)
|
486
|
-
}
|
package/src/crypto.js
DELETED
@@ -1,70 +0,0 @@
|
|
1
|
-
// @ts-nocheck
|
2
|
-
import * as codec from './encrypted-block.js'
|
3
|
-
import {
|
4
|
-
create,
|
5
|
-
load
|
6
|
-
} from 'prolly-trees/cid-set'
|
7
|
-
import { CID } from 'multiformats'
|
8
|
-
import { encode, decode, create as mfCreate } from 'multiformats/block'
|
9
|
-
import * as dagcbor from '@ipld/dag-cbor'
|
10
|
-
import { sha256 as hasher } from 'multiformats/hashes/sha2'
|
11
|
-
|
12
|
-
const createBlock = (bytes, cid) => mfCreate({ cid, bytes, hasher, codec })
|
13
|
-
|
14
|
-
const encrypt = async function * ({ get, cids, hasher, key, cache, chunker, root }) {
|
15
|
-
const set = new Set()
|
16
|
-
let eroot
|
17
|
-
for (const string of cids) {
|
18
|
-
const cid = CID.parse(string)
|
19
|
-
let unencrypted = await get(cid)
|
20
|
-
if (!unencrypted.cid) {
|
21
|
-
unencrypted = { cid, bytes: unencrypted }
|
22
|
-
}
|
23
|
-
// console.log('unencrypted', unencrypted)
|
24
|
-
const block = await encode({ ...await codec.encrypt({ ...unencrypted, key }), codec, hasher })
|
25
|
-
// console.log(`encrypting ${string} as ${block.cid}`)
|
26
|
-
yield block
|
27
|
-
set.add(block.cid.toString())
|
28
|
-
if (unencrypted.cid.equals(root)) eroot = block.cid
|
29
|
-
}
|
30
|
-
if (!eroot) throw new Error('cids does not include root')
|
31
|
-
const list = [...set].map(s => CID.parse(s))
|
32
|
-
let last
|
33
|
-
for await (const node of create({ list, get, cache, chunker, hasher, codec: dagcbor })) {
|
34
|
-
const block = await node.block
|
35
|
-
yield block
|
36
|
-
last = block
|
37
|
-
}
|
38
|
-
const head = [eroot, last.cid]
|
39
|
-
const block = await encode({ value: head, codec: dagcbor, hasher })
|
40
|
-
yield block
|
41
|
-
}
|
42
|
-
|
43
|
-
const decrypt = async function * ({ root, get, key, cache, chunker, hasher }) {
|
44
|
-
const o = { ...await get(root), codec: dagcbor, hasher }
|
45
|
-
const decodedRoot = await decode(o)
|
46
|
-
// console.log('decodedRoot', decodedRoot)
|
47
|
-
const { value: [eroot, tree] } = decodedRoot
|
48
|
-
const rootBlock = await get(eroot) // should I decrypt?
|
49
|
-
const cidset = await load({ cid: tree, get, cache, chunker, codec, hasher })
|
50
|
-
const { result: nodes } = await cidset.getAllEntries()
|
51
|
-
const unwrap = async (eblock) => {
|
52
|
-
const { bytes, cid } = await codec.decrypt({ ...eblock, key }).catch(e => {
|
53
|
-
// console.log('ekey', e)
|
54
|
-
throw new Error('bad key: ' + key.toString('hex'))
|
55
|
-
})
|
56
|
-
const block = await createBlock(bytes, cid)
|
57
|
-
return block
|
58
|
-
}
|
59
|
-
const promises = []
|
60
|
-
for (const { cid } of nodes) {
|
61
|
-
if (!rootBlock.cid.equals(cid)) promises.push(get(cid).then(unwrap))
|
62
|
-
}
|
63
|
-
yield * promises
|
64
|
-
yield unwrap(rootBlock)
|
65
|
-
}
|
66
|
-
|
67
|
-
export {
|
68
|
-
encrypt,
|
69
|
-
decrypt
|
70
|
-
}
|