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