@atproto/repo 0.8.12 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/LICENSE.txt +1 -1
- package/dist/block-map.d.ts +15 -16
- package/dist/block-map.d.ts.map +1 -1
- package/dist/block-map.js +9 -44
- package/dist/block-map.js.map +1 -1
- package/dist/car.d.ts +8 -8
- package/dist/car.d.ts.map +1 -1
- package/dist/car.js +107 -37
- package/dist/car.js.map +1 -1
- package/dist/cid-set.d.ts +8 -7
- package/dist/cid-set.d.ts.map +1 -1
- package/dist/cid-set.js +11 -4
- package/dist/cid-set.js.map +1 -1
- package/dist/data-diff.d.ts +10 -10
- package/dist/data-diff.d.ts.map +1 -1
- package/dist/data-diff.js.map +1 -1
- package/dist/error.d.ts +10 -10
- package/dist/error.d.ts.map +1 -1
- package/dist/error.js.map +1 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +1 -0
- package/dist/logger.js.map +1 -1
- package/dist/mst/mst.d.ts +29 -29
- package/dist/mst/mst.d.ts.map +1 -1
- package/dist/mst/mst.js +12 -13
- package/dist/mst/mst.js.map +1 -1
- package/dist/mst/util.d.ts +2 -2
- package/dist/mst/util.d.ts.map +1 -1
- package/dist/mst/util.js +19 -40
- package/dist/mst/util.js.map +1 -1
- package/dist/parse.d.ts +6 -7
- package/dist/parse.d.ts.map +1 -1
- package/dist/parse.js +2 -3
- package/dist/parse.js.map +1 -1
- package/dist/readable-repo.d.ts +6 -7
- package/dist/readable-repo.d.ts.map +1 -1
- package/dist/readable-repo.js +0 -1
- package/dist/readable-repo.js.map +1 -1
- package/dist/repo.d.ts +4 -4
- package/dist/repo.d.ts.map +1 -1
- package/dist/repo.js +11 -10
- package/dist/repo.js.map +1 -1
- package/dist/storage/memory-blockstore.d.ts +9 -9
- package/dist/storage/memory-blockstore.d.ts.map +1 -1
- package/dist/storage/memory-blockstore.js.map +1 -1
- package/dist/storage/readable-blockstore.d.ts +11 -12
- package/dist/storage/readable-blockstore.d.ts.map +1 -1
- package/dist/storage/readable-blockstore.js +2 -36
- package/dist/storage/readable-blockstore.js.map +1 -1
- package/dist/storage/sync-storage.d.ts +5 -5
- package/dist/storage/sync-storage.d.ts.map +1 -1
- package/dist/storage/sync-storage.js.map +1 -1
- package/dist/storage/types.d.ts +25 -26
- package/dist/storage/types.d.ts.map +1 -1
- package/dist/storage/types.js +0 -1
- package/dist/storage/types.js.map +1 -1
- package/dist/sync/consumer.d.ts +3 -3
- package/dist/sync/consumer.d.ts.map +1 -1
- package/dist/sync/consumer.js +1 -1
- package/dist/sync/consumer.js.map +1 -1
- package/dist/sync/provider.d.ts +3 -3
- package/dist/sync/provider.d.ts.map +1 -1
- package/dist/sync/provider.js.map +1 -1
- package/dist/types.d.ts +127 -100
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +53 -13
- package/dist/types.js.map +1 -1
- package/dist/util.d.ts +8 -3
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +33 -17
- package/dist/util.js.map +1 -1
- package/package.json +6 -7
- package/src/block-map.ts +31 -28
- package/src/car.ts +124 -46
- package/src/cid-set.ts +16 -10
- package/src/data-diff.ts +10 -10
- package/src/error.ts +6 -6
- package/src/logger.ts +1 -0
- package/src/mst/mst.ts +24 -28
- package/src/mst/util.ts +24 -11
- package/src/parse.ts +8 -10
- package/src/readable-repo.ts +6 -9
- package/src/repo.ts +13 -12
- package/src/storage/memory-blockstore.ts +8 -8
- package/src/storage/readable-blockstore.ts +12 -15
- package/src/storage/sync-storage.ts +4 -4
- package/src/storage/types.ts +25 -27
- package/src/sync/consumer.ts +5 -5
- package/src/sync/provider.ts +10 -7
- package/src/types.ts +82 -43
- package/src/util.ts +31 -16
- package/tests/_keys.ts +156 -156
- package/tests/_util.ts +28 -14
- package/tests/car.test.ts +31 -13
- package/tests/commit-proof-fixtures.json +79 -57
- package/tests/commit-proofs.test.ts +3 -3
- package/tests/covering-proofs.test.ts +6 -6
- package/tests/mst.test.ts +18 -19
- package/tests/proofs.test.ts +8 -8
- package/tests/repo.test.ts +1 -1
- package/tests/sync.test.ts +3 -6
- package/bench/mst.bench.ts +0 -165
- package/bench/repo.bench.ts +0 -48
- package/tsconfig.tests.tsbuildinfo +0 -1
package/src/data-diff.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Cid } from '@atproto/lex-data'
|
|
2
2
|
import { BlockMap } from './block-map'
|
|
3
3
|
import { CidSet } from './cid-set'
|
|
4
4
|
import { MST, NodeEntry, mstDiff } from './mst'
|
|
@@ -37,7 +37,7 @@ export class DataDiff {
|
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
leafAdd(key: string, cid:
|
|
40
|
+
leafAdd(key: string, cid: Cid) {
|
|
41
41
|
this.adds[key] = { key, cid }
|
|
42
42
|
if (this.removedCids.has(cid)) {
|
|
43
43
|
this.removedCids.delete(cid)
|
|
@@ -46,14 +46,14 @@ export class DataDiff {
|
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
leafUpdate(key: string, prev:
|
|
49
|
+
leafUpdate(key: string, prev: Cid, cid: Cid) {
|
|
50
50
|
if (prev.equals(cid)) return
|
|
51
51
|
this.updates[key] = { key, prev, cid }
|
|
52
52
|
this.removedCids.add(prev)
|
|
53
53
|
this.newLeafCids.add(cid)
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
leafDelete(key: string, cid:
|
|
56
|
+
leafDelete(key: string, cid: Cid) {
|
|
57
57
|
this.deletes[key] = { key, cid }
|
|
58
58
|
if (this.newLeafCids.has(cid)) {
|
|
59
59
|
this.newLeafCids.delete(cid)
|
|
@@ -62,7 +62,7 @@ export class DataDiff {
|
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
treeAdd(cid:
|
|
65
|
+
treeAdd(cid: Cid, bytes: Uint8Array) {
|
|
66
66
|
if (this.removedCids.has(cid)) {
|
|
67
67
|
this.removedCids.delete(cid)
|
|
68
68
|
} else {
|
|
@@ -70,7 +70,7 @@ export class DataDiff {
|
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
treeDelete(cid:
|
|
73
|
+
treeDelete(cid: Cid) {
|
|
74
74
|
if (this.newMstBlocks.has(cid)) {
|
|
75
75
|
this.newMstBlocks.delete(cid)
|
|
76
76
|
} else {
|
|
@@ -102,16 +102,16 @@ export class DataDiff {
|
|
|
102
102
|
|
|
103
103
|
export type DataAdd = {
|
|
104
104
|
key: string
|
|
105
|
-
cid:
|
|
105
|
+
cid: Cid
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
export type DataUpdate = {
|
|
109
109
|
key: string
|
|
110
|
-
prev:
|
|
111
|
-
cid:
|
|
110
|
+
prev: Cid
|
|
111
|
+
cid: Cid
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
export type DataDelete = {
|
|
115
115
|
key: string
|
|
116
|
-
cid:
|
|
116
|
+
cid: Cid
|
|
117
117
|
}
|
package/src/error.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Cid } from '@atproto/lex-data'
|
|
2
2
|
|
|
3
3
|
export class MissingBlockError extends Error {
|
|
4
4
|
constructor(
|
|
5
|
-
public cid:
|
|
5
|
+
public cid: Cid,
|
|
6
6
|
def?: string,
|
|
7
7
|
) {
|
|
8
8
|
let msg = `block not found: ${cid.toString()}`
|
|
@@ -16,7 +16,7 @@ export class MissingBlockError extends Error {
|
|
|
16
16
|
export class MissingBlocksError extends Error {
|
|
17
17
|
constructor(
|
|
18
18
|
public context: string,
|
|
19
|
-
public cids:
|
|
19
|
+
public cids: Cid[],
|
|
20
20
|
) {
|
|
21
21
|
const cidStr = cids.map((c) => c.toString())
|
|
22
22
|
super(`missing ${context} blocks: ${cidStr}`)
|
|
@@ -25,8 +25,8 @@ export class MissingBlocksError extends Error {
|
|
|
25
25
|
|
|
26
26
|
export class MissingCommitBlocksError extends Error {
|
|
27
27
|
constructor(
|
|
28
|
-
public commit:
|
|
29
|
-
public cids:
|
|
28
|
+
public commit: Cid,
|
|
29
|
+
public cids: Cid[],
|
|
30
30
|
) {
|
|
31
31
|
const cidStr = cids.map((c) => c.toString())
|
|
32
32
|
super(`missing blocks for commit ${commit.toString()}: ${cidStr}`)
|
|
@@ -35,7 +35,7 @@ export class MissingCommitBlocksError extends Error {
|
|
|
35
35
|
|
|
36
36
|
export class UnexpectedObjectError extends Error {
|
|
37
37
|
constructor(
|
|
38
|
-
public cid:
|
|
38
|
+
public cid: Cid,
|
|
39
39
|
public def: string,
|
|
40
40
|
) {
|
|
41
41
|
super(`unexpected object at ${cid.toString()}, expected: ${def}`)
|
package/src/logger.ts
CHANGED
package/src/mst/mst.ts
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
|
-
/* eslint-disable import/no-deprecated */
|
|
2
|
-
|
|
3
|
-
import { CID } from 'multiformats'
|
|
4
1
|
import { z } from 'zod'
|
|
5
|
-
import {
|
|
2
|
+
import { cidForLex, encode } from '@atproto/lex-cbor'
|
|
3
|
+
import { Cid, cidForCbor } from '@atproto/lex-data'
|
|
6
4
|
import { BlockMap } from '../block-map'
|
|
7
5
|
import { CidSet } from '../cid-set'
|
|
8
6
|
import { MissingBlockError, MissingBlocksError } from '../error'
|
|
9
7
|
import * as parse from '../parse'
|
|
10
8
|
import { ReadableBlockstore } from '../storage'
|
|
11
|
-
import { CarBlock } from '../types'
|
|
9
|
+
import { CarBlock, schema } from '../types'
|
|
12
10
|
import * as util from './util'
|
|
13
11
|
|
|
14
12
|
/**
|
|
@@ -18,7 +16,7 @@ import * as util from './util'
|
|
|
18
16
|
* Keys are laid out in alphabetic order.
|
|
19
17
|
* The key insight of an MST is that each key is hashed and starting 0s are counted
|
|
20
18
|
* to determine which layer it falls on (5 zeros for ~32 fanout).
|
|
21
|
-
* This is a merkle tree, so each subtree is referred to by it's hash (
|
|
19
|
+
* This is a merkle tree, so each subtree is referred to by it's hash (Cid).
|
|
22
20
|
* When a leaf is changed, ever tree on the path to that leaf is changed as well,
|
|
23
21
|
* thereby updating the root hash.
|
|
24
22
|
*
|
|
@@ -44,11 +42,11 @@ import * as util from './util'
|
|
|
44
42
|
* Then the first will be described as `prefix: 0, key: 'bsky/posts/abcdefg'`,
|
|
45
43
|
* and the second will be described as `prefix: 16, key: 'hi'.`
|
|
46
44
|
*/
|
|
47
|
-
const subTreePointer = z.nullable(
|
|
45
|
+
const subTreePointer = z.nullable(schema.cid)
|
|
48
46
|
const treeEntry = z.object({
|
|
49
47
|
p: z.number(), // prefix count of ascii chars that this key shares with the prev key
|
|
50
|
-
k:
|
|
51
|
-
v:
|
|
48
|
+
k: schema.bytes, // the rest of the key outside the shared prefix
|
|
49
|
+
v: schema.cid, // value
|
|
52
50
|
t: subTreePointer, // next subtree (to the right of leaf)
|
|
53
51
|
})
|
|
54
52
|
const nodeData = z.object({
|
|
@@ -72,12 +70,12 @@ export class MST {
|
|
|
72
70
|
storage: ReadableBlockstore
|
|
73
71
|
entries: NodeEntry[] | null
|
|
74
72
|
layer: number | null
|
|
75
|
-
pointer:
|
|
73
|
+
pointer: Cid
|
|
76
74
|
outdatedPointer = false
|
|
77
75
|
|
|
78
76
|
constructor(
|
|
79
77
|
storage: ReadableBlockstore,
|
|
80
|
-
pointer:
|
|
78
|
+
pointer: Cid,
|
|
81
79
|
entries: NodeEntry[] | null,
|
|
82
80
|
layer: number | null,
|
|
83
81
|
) {
|
|
@@ -104,14 +102,14 @@ export class MST {
|
|
|
104
102
|
): Promise<MST> {
|
|
105
103
|
const { layer = null } = opts || {}
|
|
106
104
|
const entries = await util.deserializeNodeData(storage, data, opts)
|
|
107
|
-
const pointer = await
|
|
105
|
+
const pointer = await cidForLex(data)
|
|
108
106
|
return new MST(storage, pointer, entries, layer)
|
|
109
107
|
}
|
|
110
108
|
|
|
111
109
|
// this is really a *lazy* load, doesn't actually touch storage
|
|
112
110
|
static load(
|
|
113
111
|
storage: ReadableBlockstore,
|
|
114
|
-
cid:
|
|
112
|
+
cid: Cid,
|
|
115
113
|
opts?: Partial<MstOpts>,
|
|
116
114
|
): MST {
|
|
117
115
|
const { layer = null } = opts || {}
|
|
@@ -147,12 +145,12 @@ export class MST {
|
|
|
147
145
|
|
|
148
146
|
return this.entries
|
|
149
147
|
}
|
|
150
|
-
throw new Error('No entries or
|
|
148
|
+
throw new Error('No entries or Cid provided')
|
|
151
149
|
}
|
|
152
150
|
|
|
153
151
|
// We don't hash the node on every mutation for performance reasons
|
|
154
152
|
// Instead we keep track of whether the pointer is outdated and only (recursively) calculate when needed
|
|
155
|
-
async getPointer(): Promise<
|
|
153
|
+
async getPointer(): Promise<Cid> {
|
|
156
154
|
if (!this.outdatedPointer) return this.pointer
|
|
157
155
|
const { cid } = await this.serialize()
|
|
158
156
|
this.pointer = cid
|
|
@@ -160,7 +158,7 @@ export class MST {
|
|
|
160
158
|
return this.pointer
|
|
161
159
|
}
|
|
162
160
|
|
|
163
|
-
async serialize(): Promise<{ cid:
|
|
161
|
+
async serialize(): Promise<{ cid: Cid; bytes: Uint8Array }> {
|
|
164
162
|
let entries = await this.getEntries()
|
|
165
163
|
const outdated = entries.filter(
|
|
166
164
|
(e) => e.isTree() && e.outdatedPointer,
|
|
@@ -170,11 +168,9 @@ export class MST {
|
|
|
170
168
|
entries = await this.getEntries()
|
|
171
169
|
}
|
|
172
170
|
const data = util.serializeNodeData(entries)
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
bytes: block.bytes,
|
|
177
|
-
}
|
|
171
|
+
const bytes = encode(data)
|
|
172
|
+
const cid = await cidForCbor(bytes)
|
|
173
|
+
return { cid, bytes }
|
|
178
174
|
}
|
|
179
175
|
|
|
180
176
|
// In most cases, we get the layer of a node from a hint on creation
|
|
@@ -210,7 +206,7 @@ export class MST {
|
|
|
210
206
|
// -------------------
|
|
211
207
|
|
|
212
208
|
// Return the necessary blocks to persist the MST to repo storage
|
|
213
|
-
async getUnstoredBlocks(): Promise<{ root:
|
|
209
|
+
async getUnstoredBlocks(): Promise<{ root: Cid; blocks: BlockMap }> {
|
|
214
210
|
const blocks = new BlockMap()
|
|
215
211
|
const pointer = await this.getPointer()
|
|
216
212
|
const alreadyHas = await this.storage.has(pointer)
|
|
@@ -229,7 +225,7 @@ export class MST {
|
|
|
229
225
|
|
|
230
226
|
// Adds a new leaf for the given key/value pair
|
|
231
227
|
// Throws if a leaf with that key already exists
|
|
232
|
-
async add(key: string, value:
|
|
228
|
+
async add(key: string, value: Cid, knownZeros?: number): Promise<MST> {
|
|
233
229
|
util.ensureValidMstKey(key)
|
|
234
230
|
const keyZeros = knownZeros ?? (await util.leadingZerosOnHash(key))
|
|
235
231
|
const layer = await this.getLayer()
|
|
@@ -299,7 +295,7 @@ export class MST {
|
|
|
299
295
|
}
|
|
300
296
|
|
|
301
297
|
// Gets the value at the given key
|
|
302
|
-
async get(key: string): Promise<
|
|
298
|
+
async get(key: string): Promise<Cid | null> {
|
|
303
299
|
const index = await this.findGtOrEqualLeafIndex(key)
|
|
304
300
|
const found = await this.atIndex(index)
|
|
305
301
|
if (found && found.isLeaf() && found.key === key) {
|
|
@@ -314,7 +310,7 @@ export class MST {
|
|
|
314
310
|
|
|
315
311
|
// Edits the value at the given key
|
|
316
312
|
// Throws if the given key does not exist
|
|
317
|
-
async update(key: string, value:
|
|
313
|
+
async update(key: string, value: Cid): Promise<MST> {
|
|
318
314
|
util.ensureValidMstKey(key)
|
|
319
315
|
const index = await this.findGtOrEqualLeafIndex(key)
|
|
320
316
|
const found = await this.atIndex(index)
|
|
@@ -767,8 +763,8 @@ export class MST {
|
|
|
767
763
|
}
|
|
768
764
|
}
|
|
769
765
|
|
|
770
|
-
async cidsForPath(key: string): Promise<
|
|
771
|
-
const cids:
|
|
766
|
+
async cidsForPath(key: string): Promise<Cid[]> {
|
|
767
|
+
const cids: Cid[] = [await this.getPointer()]
|
|
772
768
|
const index = await this.findGtOrEqualLeafIndex(key)
|
|
773
769
|
const found = await this.atIndex(index)
|
|
774
770
|
if (found && found.isLeaf() && found.key === key) {
|
|
@@ -875,7 +871,7 @@ export class MST {
|
|
|
875
871
|
export class Leaf {
|
|
876
872
|
constructor(
|
|
877
873
|
public key: string,
|
|
878
|
-
public value:
|
|
874
|
+
public value: Cid,
|
|
879
875
|
) {}
|
|
880
876
|
|
|
881
877
|
isTree(): this is MST {
|
package/src/mst/util.ts
CHANGED
|
@@ -1,12 +1,25 @@
|
|
|
1
|
-
/* eslint-disable import/no-deprecated */
|
|
2
|
-
|
|
3
|
-
import { CID } from 'multiformats'
|
|
4
|
-
import * as uint8arrays from 'uint8arrays'
|
|
5
|
-
import { cidForCbor } from '@atproto/common'
|
|
6
1
|
import { sha256 } from '@atproto/crypto'
|
|
2
|
+
import { cidForLex } from '@atproto/lex-cbor'
|
|
3
|
+
import { Cid } from '@atproto/lex-data'
|
|
7
4
|
import { ReadableBlockstore } from '../storage'
|
|
8
5
|
import { Leaf, MST, MstOpts, NodeData, NodeEntry } from './mst'
|
|
9
6
|
|
|
7
|
+
function toAscii(bytes: Uint8Array): string {
|
|
8
|
+
let string = ''
|
|
9
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
10
|
+
string += String.fromCharCode(bytes[i])
|
|
11
|
+
}
|
|
12
|
+
return string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function fromAscii(str: string): Uint8Array {
|
|
16
|
+
const bytes = new Uint8Array(str.length)
|
|
17
|
+
for (let i = 0; i < str.length; i++) {
|
|
18
|
+
bytes[i] = str.charCodeAt(i)
|
|
19
|
+
}
|
|
20
|
+
return bytes
|
|
21
|
+
}
|
|
22
|
+
|
|
10
23
|
export const leadingZerosOnHash = async (key: string | Uint8Array) => {
|
|
11
24
|
const hash = await sha256(key)
|
|
12
25
|
let leadingZeros = 0
|
|
@@ -48,8 +61,8 @@ export const deserializeNodeData = async (
|
|
|
48
61
|
}
|
|
49
62
|
let lastKey = ''
|
|
50
63
|
for (const entry of data.e) {
|
|
51
|
-
const keyStr =
|
|
52
|
-
const key = lastKey.slice(0, entry.p)
|
|
64
|
+
const keyStr = toAscii(entry.k)
|
|
65
|
+
const key = `${lastKey.slice(0, entry.p)}${keyStr}`
|
|
53
66
|
ensureValidMstKey(key)
|
|
54
67
|
entries.push(new Leaf(key, entry.v))
|
|
55
68
|
lastKey = key
|
|
@@ -82,7 +95,7 @@ export const serializeNodeData = (entries: NodeEntry[]): NodeData => {
|
|
|
82
95
|
throw new Error('Not a valid node: two subtrees next to each other')
|
|
83
96
|
}
|
|
84
97
|
i++
|
|
85
|
-
let subtree:
|
|
98
|
+
let subtree: Cid | null = null
|
|
86
99
|
if (next?.isTree()) {
|
|
87
100
|
subtree = next.pointer
|
|
88
101
|
i++
|
|
@@ -91,7 +104,7 @@ export const serializeNodeData = (entries: NodeEntry[]): NodeData => {
|
|
|
91
104
|
const prefixLen = countPrefixLen(lastKey, leaf.key)
|
|
92
105
|
data.e.push({
|
|
93
106
|
p: prefixLen,
|
|
94
|
-
k:
|
|
107
|
+
k: fromAscii(leaf.key.slice(prefixLen)),
|
|
95
108
|
v: leaf.value,
|
|
96
109
|
t: subtree,
|
|
97
110
|
})
|
|
@@ -111,9 +124,9 @@ export const countPrefixLen = (a: string, b: string): number => {
|
|
|
111
124
|
return i
|
|
112
125
|
}
|
|
113
126
|
|
|
114
|
-
export const cidForEntries = async (entries: NodeEntry[]): Promise<
|
|
127
|
+
export const cidForEntries = async (entries: NodeEntry[]): Promise<Cid> => {
|
|
115
128
|
const data = serializeNodeData(entries)
|
|
116
|
-
return
|
|
129
|
+
return cidForLex(data)
|
|
117
130
|
}
|
|
118
131
|
|
|
119
132
|
export const isValidMstKey = (str: string): boolean => {
|
package/src/parse.ts
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
import { cborDecode, check } from '@atproto/common'
|
|
5
|
-
import { RepoRecord } from '@atproto/lexicon'
|
|
1
|
+
import { check } from '@atproto/common-web'
|
|
2
|
+
import { decode } from '@atproto/lex-cbor'
|
|
3
|
+
import { Cid, LexMap } from '@atproto/lex-data'
|
|
6
4
|
import { BlockMap } from './block-map'
|
|
7
5
|
import { MissingBlockError, UnexpectedObjectError } from './error'
|
|
8
6
|
import { cborToLexRecord } from './util'
|
|
9
7
|
|
|
10
8
|
export const getAndParseRecord = async (
|
|
11
9
|
blocks: BlockMap,
|
|
12
|
-
cid:
|
|
13
|
-
): Promise<{ record:
|
|
10
|
+
cid: Cid,
|
|
11
|
+
): Promise<{ record: LexMap; bytes: Uint8Array }> => {
|
|
14
12
|
const bytes = blocks.get(cid)
|
|
15
13
|
if (!bytes) {
|
|
16
14
|
throw new MissingBlockError(cid, 'record')
|
|
@@ -21,7 +19,7 @@ export const getAndParseRecord = async (
|
|
|
21
19
|
|
|
22
20
|
export const getAndParseByDef = async <T>(
|
|
23
21
|
blocks: BlockMap,
|
|
24
|
-
cid:
|
|
22
|
+
cid: Cid,
|
|
25
23
|
def: check.Def<T>,
|
|
26
24
|
): Promise<{ obj: T; bytes: Uint8Array }> => {
|
|
27
25
|
const bytes = blocks.get(cid)
|
|
@@ -33,10 +31,10 @@ export const getAndParseByDef = async <T>(
|
|
|
33
31
|
|
|
34
32
|
export const parseObjByDef = <T>(
|
|
35
33
|
bytes: Uint8Array,
|
|
36
|
-
cid:
|
|
34
|
+
cid: Cid,
|
|
37
35
|
def: check.Def<T>,
|
|
38
36
|
): { obj: T; bytes: Uint8Array } => {
|
|
39
|
-
const obj =
|
|
37
|
+
const obj = decode(bytes)
|
|
40
38
|
const res = def.schema.safeParse(obj)
|
|
41
39
|
if (res.success) {
|
|
42
40
|
return { obj: res.data, bytes }
|
package/src/readable-repo.ts
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { CID } from 'multiformats/cid'
|
|
4
|
-
import { RepoRecord } from '@atproto/lexicon'
|
|
1
|
+
import { Cid, LexMap } from '@atproto/lex-data'
|
|
5
2
|
import { MissingBlocksError } from './error'
|
|
6
3
|
import log from './logger'
|
|
7
4
|
import { MST } from './mst'
|
|
@@ -14,14 +11,14 @@ type Params = {
|
|
|
14
11
|
storage: ReadableBlockstore
|
|
15
12
|
data: MST
|
|
16
13
|
commit: Commit
|
|
17
|
-
cid:
|
|
14
|
+
cid: Cid
|
|
18
15
|
}
|
|
19
16
|
|
|
20
17
|
export class ReadableRepo {
|
|
21
18
|
storage: ReadableBlockstore
|
|
22
19
|
data: MST
|
|
23
20
|
commit: Commit
|
|
24
|
-
cid:
|
|
21
|
+
cid: Cid
|
|
25
22
|
|
|
26
23
|
constructor(params: Params) {
|
|
27
24
|
this.storage = params.storage
|
|
@@ -30,7 +27,7 @@ export class ReadableRepo {
|
|
|
30
27
|
this.cid = params.cid
|
|
31
28
|
}
|
|
32
29
|
|
|
33
|
-
static async load(storage: ReadableBlockstore, commitCid:
|
|
30
|
+
static async load(storage: ReadableBlockstore, commitCid: Cid) {
|
|
34
31
|
const commit = await storage.readObj(commitCid, def.versionedCommit)
|
|
35
32
|
const data = await MST.load(storage, commit.data)
|
|
36
33
|
log.info({ did: commit.did }, 'loaded repo for')
|
|
@@ -53,8 +50,8 @@ export class ReadableRepo {
|
|
|
53
50
|
async *walkRecords(from?: string): AsyncIterable<{
|
|
54
51
|
collection: string
|
|
55
52
|
rkey: string
|
|
56
|
-
cid:
|
|
57
|
-
record:
|
|
53
|
+
cid: Cid
|
|
54
|
+
record: LexMap
|
|
58
55
|
}> {
|
|
59
56
|
for await (const leaf of this.data.walkLeavesFrom(from ?? '')) {
|
|
60
57
|
const { collection, rkey } = util.parseDataKey(leaf.key)
|
package/src/repo.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { CID } from 'multiformats/cid'
|
|
4
|
-
import { TID, dataToCborBlock } from '@atproto/common'
|
|
1
|
+
import { TID } from '@atproto/common-web'
|
|
5
2
|
import * as crypto from '@atproto/crypto'
|
|
6
|
-
import {
|
|
3
|
+
import { encode } from '@atproto/lex-cbor'
|
|
4
|
+
import { Cid, cidForCbor } from '@atproto/lex-data'
|
|
7
5
|
import { BlockMap } from './block-map'
|
|
8
6
|
import { CidSet } from './cid-set'
|
|
9
7
|
import { DataDiff } from './data-diff'
|
|
@@ -25,7 +23,7 @@ type Params = {
|
|
|
25
23
|
storage: RepoStorage
|
|
26
24
|
data: MST
|
|
27
25
|
commit: Commit
|
|
28
|
-
cid:
|
|
26
|
+
cid: Cid
|
|
29
27
|
}
|
|
30
28
|
|
|
31
29
|
export class Repo extends ReadableRepo {
|
|
@@ -101,7 +99,7 @@ export class Repo extends ReadableRepo {
|
|
|
101
99
|
return Repo.createFromCommit(storage, commit)
|
|
102
100
|
}
|
|
103
101
|
|
|
104
|
-
static async load(storage: RepoStorage, cid?:
|
|
102
|
+
static async load(storage: RepoStorage, cid?: Cid) {
|
|
105
103
|
const commitCid = cid || (await storage.getRoot())
|
|
106
104
|
if (!commitCid) {
|
|
107
105
|
throw new Error('No cid provided and none in storage')
|
|
@@ -171,15 +169,18 @@ export class Repo extends ReadableRepo {
|
|
|
171
169
|
},
|
|
172
170
|
keypair,
|
|
173
171
|
)
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
172
|
+
|
|
173
|
+
const commitBytes = encode(commit)
|
|
174
|
+
const commitCid = await cidForCbor(commitBytes)
|
|
175
|
+
|
|
176
|
+
if (!commitCid.equals(this.cid)) {
|
|
177
|
+
newBlocks.set(commitCid, commitBytes)
|
|
178
|
+
relevantBlocks.set(commitCid, commitBytes)
|
|
178
179
|
removedCids.add(this.cid)
|
|
179
180
|
}
|
|
180
181
|
|
|
181
182
|
return {
|
|
182
|
-
cid:
|
|
183
|
+
cid: commitCid,
|
|
183
184
|
rev,
|
|
184
185
|
since: this.commit.rev,
|
|
185
186
|
prev: this.cid,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Cid } from '@atproto/lex-data'
|
|
2
2
|
import { BlockMap } from '../block-map'
|
|
3
3
|
import { CommitData } from '../types'
|
|
4
4
|
import { ReadableBlockstore } from './readable-blockstore'
|
|
@@ -9,7 +9,7 @@ export class MemoryBlockstore
|
|
|
9
9
|
implements RepoStorage
|
|
10
10
|
{
|
|
11
11
|
blocks: BlockMap
|
|
12
|
-
root:
|
|
12
|
+
root: Cid | null = null
|
|
13
13
|
rev: string | null = null
|
|
14
14
|
|
|
15
15
|
constructor(blocks?: BlockMap) {
|
|
@@ -20,23 +20,23 @@ export class MemoryBlockstore
|
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
async getRoot(): Promise<
|
|
23
|
+
async getRoot(): Promise<Cid | null> {
|
|
24
24
|
return this.root
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
async getBytes(cid:
|
|
27
|
+
async getBytes(cid: Cid): Promise<Uint8Array | null> {
|
|
28
28
|
return this.blocks.get(cid) || null
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
async has(cid:
|
|
31
|
+
async has(cid: Cid): Promise<boolean> {
|
|
32
32
|
return this.blocks.has(cid)
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
async getBlocks(cids:
|
|
35
|
+
async getBlocks(cids: Cid[]): Promise<{ blocks: BlockMap; missing: Cid[] }> {
|
|
36
36
|
return this.blocks.getMany(cids)
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
async putBlock(cid:
|
|
39
|
+
async putBlock(cid: Cid, block: Uint8Array): Promise<void> {
|
|
40
40
|
this.blocks.set(cid, block)
|
|
41
41
|
}
|
|
42
42
|
|
|
@@ -44,7 +44,7 @@ export class MemoryBlockstore
|
|
|
44
44
|
this.blocks.addMap(blocks)
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
async updateRoot(cid:
|
|
47
|
+
async updateRoot(cid: Cid, rev: string): Promise<void> {
|
|
48
48
|
this.root = cid
|
|
49
49
|
this.rev = rev
|
|
50
50
|
}
|
|
@@ -1,29 +1,26 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { CID } from 'multiformats/cid'
|
|
4
|
-
import { check } from '@atproto/common'
|
|
5
|
-
import { RepoRecord } from '@atproto/lexicon'
|
|
1
|
+
import { check } from '@atproto/common-web'
|
|
2
|
+
import { Cid, LexMap } from '@atproto/lex-data'
|
|
6
3
|
import { BlockMap } from '../block-map'
|
|
7
4
|
import { MissingBlockError } from '../error'
|
|
8
|
-
import
|
|
5
|
+
import { parseObjByDef } from '../parse'
|
|
9
6
|
import { cborToLexRecord } from '../util'
|
|
10
7
|
|
|
11
8
|
export abstract class ReadableBlockstore {
|
|
12
|
-
abstract getBytes(cid:
|
|
13
|
-
abstract has(cid:
|
|
14
|
-
abstract getBlocks(cids:
|
|
9
|
+
abstract getBytes(cid: Cid): Promise<Uint8Array | null>
|
|
10
|
+
abstract has(cid: Cid): Promise<boolean>
|
|
11
|
+
abstract getBlocks(cids: Cid[]): Promise<{ blocks: BlockMap; missing: Cid[] }>
|
|
15
12
|
|
|
16
13
|
async attemptRead<T>(
|
|
17
|
-
cid:
|
|
14
|
+
cid: Cid,
|
|
18
15
|
def: check.Def<T>,
|
|
19
16
|
): Promise<{ obj: T; bytes: Uint8Array } | null> {
|
|
20
17
|
const bytes = await this.getBytes(cid)
|
|
21
18
|
if (!bytes) return null
|
|
22
|
-
return
|
|
19
|
+
return parseObjByDef(bytes, cid, def)
|
|
23
20
|
}
|
|
24
21
|
|
|
25
22
|
async readObjAndBytes<T>(
|
|
26
|
-
cid:
|
|
23
|
+
cid: Cid,
|
|
27
24
|
def: check.Def<T>,
|
|
28
25
|
): Promise<{ obj: T; bytes: Uint8Array }> {
|
|
29
26
|
const read = await this.attemptRead(cid, def)
|
|
@@ -33,12 +30,12 @@ export abstract class ReadableBlockstore {
|
|
|
33
30
|
return read
|
|
34
31
|
}
|
|
35
32
|
|
|
36
|
-
async readObj<T>(cid:
|
|
33
|
+
async readObj<T>(cid: Cid, def: check.Def<T>): Promise<T> {
|
|
37
34
|
const obj = await this.readObjAndBytes(cid, def)
|
|
38
35
|
return obj.obj
|
|
39
36
|
}
|
|
40
37
|
|
|
41
|
-
async attemptReadRecord(cid:
|
|
38
|
+
async attemptReadRecord(cid: Cid): Promise<LexMap | null> {
|
|
42
39
|
try {
|
|
43
40
|
return await this.readRecord(cid)
|
|
44
41
|
} catch {
|
|
@@ -46,7 +43,7 @@ export abstract class ReadableBlockstore {
|
|
|
46
43
|
}
|
|
47
44
|
}
|
|
48
45
|
|
|
49
|
-
async readRecord(cid:
|
|
46
|
+
async readRecord(cid: Cid): Promise<LexMap> {
|
|
50
47
|
const bytes = await this.getBytes(cid)
|
|
51
48
|
if (!bytes) {
|
|
52
49
|
throw new MissingBlockError(cid)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Cid } from '@atproto/lex-data'
|
|
2
2
|
import { BlockMap } from '../block-map'
|
|
3
3
|
import { ReadableBlockstore } from './readable-blockstore'
|
|
4
4
|
|
|
@@ -10,13 +10,13 @@ export class SyncStorage extends ReadableBlockstore {
|
|
|
10
10
|
super()
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
async getBytes(cid:
|
|
13
|
+
async getBytes(cid: Cid): Promise<Uint8Array | null> {
|
|
14
14
|
const got = await this.staged.getBytes(cid)
|
|
15
15
|
if (got) return got
|
|
16
16
|
return this.saved.getBytes(cid)
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
async getBlocks(cids:
|
|
19
|
+
async getBlocks(cids: Cid[]): Promise<{ blocks: BlockMap; missing: Cid[] }> {
|
|
20
20
|
const fromStaged = await this.staged.getBlocks(cids)
|
|
21
21
|
const fromSaved = await this.saved.getBlocks(fromStaged.missing)
|
|
22
22
|
const blocks = fromStaged.blocks
|
|
@@ -27,7 +27,7 @@ export class SyncStorage extends ReadableBlockstore {
|
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
async has(cid:
|
|
30
|
+
async has(cid: Cid): Promise<boolean> {
|
|
31
31
|
return (await this.staged.has(cid)) || (await this.saved.has(cid))
|
|
32
32
|
}
|
|
33
33
|
}
|