@atproto/repo 0.8.13 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/dist/block-map.d.ts +15 -16
- package/dist/block-map.d.ts.map +1 -1
- package/dist/block-map.js +9 -43
- 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 +18 -15
- 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 -12
- 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 -39
- 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 -2
- 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.map +1 -1
- package/dist/repo.d.ts +4 -4
- package/dist/repo.d.ts.map +1 -1
- package/dist/repo.js +11 -9
- 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 -35
- 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.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 -12
- 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 -16
- package/dist/util.js.map +1 -1
- package/package.json +6 -7
- package/src/block-map.ts +31 -26
- package/src/car.ts +23 -28
- 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 -26
- package/src/mst/util.ts +24 -9
- package/src/parse.ts +8 -8
- package/src/readable-repo.ts +6 -7
- package/src/repo.ts +13 -10
- package/src/storage/memory-blockstore.ts +8 -8
- package/src/storage/readable-blockstore.ts +12 -13
- package/src/storage/sync-storage.ts +4 -4
- package/src/storage/types.ts +25 -25
- package/src/sync/consumer.ts +5 -5
- package/src/sync/provider.ts +10 -7
- package/src/types.ts +82 -41
- package/src/util.ts +31 -14
- package/tests/_util.ts +28 -12
- package/tests/car.test.ts +31 -11
- 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 -6
- 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/src/sync/provider.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Cid } from '@atproto/lex-data'
|
|
2
2
|
import { writeCarStream } from '../car'
|
|
3
3
|
import { CidSet } from '../cid-set'
|
|
4
4
|
import { MissingBlocksError } from '../error'
|
|
5
5
|
import { MST } from '../mst'
|
|
6
6
|
import { ReadableBlockstore, RepoStorage } from '../storage'
|
|
7
|
-
import { RecordPath, def } from '../types'
|
|
7
|
+
import { CarBlock, RecordPath, def } from '../types'
|
|
8
8
|
import * as util from '../util'
|
|
9
9
|
|
|
10
10
|
// Full Repo
|
|
@@ -12,12 +12,15 @@ import * as util from '../util'
|
|
|
12
12
|
|
|
13
13
|
export const getFullRepo = (
|
|
14
14
|
storage: RepoStorage,
|
|
15
|
-
commitCid:
|
|
15
|
+
commitCid: Cid,
|
|
16
16
|
): AsyncIterable<Uint8Array> => {
|
|
17
17
|
return writeCarStream(commitCid, iterateFullRepo(storage, commitCid))
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
async function* iterateFullRepo(
|
|
20
|
+
async function* iterateFullRepo(
|
|
21
|
+
storage: RepoStorage,
|
|
22
|
+
commitCid: Cid,
|
|
23
|
+
): AsyncGenerator<CarBlock> {
|
|
21
24
|
const commit = await storage.readObjAndBytes(commitCid, def.commit)
|
|
22
25
|
yield { cid: commitCid, bytes: commit.bytes }
|
|
23
26
|
const mst = MST.load(storage, commit.obj.data)
|
|
@@ -31,7 +34,7 @@ async function* iterateFullRepo(storage: RepoStorage, commitCid: CID) {
|
|
|
31
34
|
|
|
32
35
|
export const getRecords = (
|
|
33
36
|
storage: ReadableBlockstore,
|
|
34
|
-
commitCid:
|
|
37
|
+
commitCid: Cid,
|
|
35
38
|
paths: RecordPath[],
|
|
36
39
|
): AsyncIterable<Uint8Array> => {
|
|
37
40
|
return writeCarStream(
|
|
@@ -42,9 +45,9 @@ export const getRecords = (
|
|
|
42
45
|
|
|
43
46
|
async function* iterateRecordBlocks(
|
|
44
47
|
storage: ReadableBlockstore,
|
|
45
|
-
commitCid:
|
|
48
|
+
commitCid: Cid,
|
|
46
49
|
paths: RecordPath[],
|
|
47
|
-
) {
|
|
50
|
+
): AsyncGenerator<CarBlock> {
|
|
48
51
|
const commit = await storage.readObjAndBytes(commitCid, def.commit)
|
|
49
52
|
yield { cid: commitCid, bytes: commit.bytes }
|
|
50
53
|
const mst = MST.load(storage, commit.obj.data)
|
package/src/types.ts
CHANGED
|
@@ -1,41 +1,50 @@
|
|
|
1
|
-
import { CID } from 'multiformats'
|
|
2
1
|
import { z } from 'zod'
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { RepoRecord } from '@atproto/lexicon'
|
|
2
|
+
import { Cid, LexMap, ifCid } from '@atproto/lex-data'
|
|
3
|
+
import { NsidString, RecordKeyString } from '@atproto/syntax'
|
|
6
4
|
import { BlockMap } from './block-map'
|
|
7
5
|
import { CidSet } from './cid-set'
|
|
8
6
|
|
|
9
7
|
// Repo nodes
|
|
10
8
|
// ---------------
|
|
11
9
|
|
|
10
|
+
const cidSchema = z.unknown().transform((input, ctx): Cid => {
|
|
11
|
+
const cid = ifCid(input)
|
|
12
|
+
if (cid) return cid
|
|
13
|
+
|
|
14
|
+
ctx.addIssue({
|
|
15
|
+
code: z.ZodIssueCode.custom,
|
|
16
|
+
message: 'Not a valid CID',
|
|
17
|
+
})
|
|
18
|
+
return z.NEVER
|
|
19
|
+
})
|
|
20
|
+
|
|
12
21
|
const unsignedCommit = z.object({
|
|
13
22
|
did: z.string(),
|
|
14
23
|
version: z.literal(3),
|
|
15
|
-
data:
|
|
24
|
+
data: cidSchema,
|
|
16
25
|
rev: z.string(),
|
|
17
26
|
// `prev` added for backwards compatibility with v2, no requirement of keeping around history
|
|
18
|
-
prev:
|
|
27
|
+
prev: cidSchema.nullable(),
|
|
19
28
|
})
|
|
20
29
|
export type UnsignedCommit = z.infer<typeof unsignedCommit> & { sig?: never }
|
|
21
30
|
|
|
22
31
|
const commit = z.object({
|
|
23
32
|
did: z.string(),
|
|
24
33
|
version: z.literal(3),
|
|
25
|
-
data:
|
|
34
|
+
data: cidSchema,
|
|
26
35
|
rev: z.string(),
|
|
27
|
-
prev:
|
|
28
|
-
sig:
|
|
36
|
+
prev: cidSchema.nullable(),
|
|
37
|
+
sig: z.instanceof(Uint8Array),
|
|
29
38
|
})
|
|
30
39
|
export type Commit = z.infer<typeof commit>
|
|
31
40
|
|
|
32
41
|
const legacyV2Commit = z.object({
|
|
33
42
|
did: z.string(),
|
|
34
43
|
version: z.literal(2),
|
|
35
|
-
data:
|
|
44
|
+
data: cidSchema,
|
|
36
45
|
rev: z.string().optional(),
|
|
37
|
-
prev:
|
|
38
|
-
sig:
|
|
46
|
+
prev: cidSchema.nullable(),
|
|
47
|
+
sig: z.instanceof(Uint8Array),
|
|
39
48
|
})
|
|
40
49
|
export type LegacyV2Commit = z.infer<typeof legacyV2Commit>
|
|
41
50
|
|
|
@@ -46,14 +55,46 @@ const versionedCommit = z.discriminatedUnion('version', [
|
|
|
46
55
|
export type VersionedCommit = z.infer<typeof versionedCommit>
|
|
47
56
|
|
|
48
57
|
export const schema = {
|
|
49
|
-
|
|
58
|
+
cid: cidSchema,
|
|
59
|
+
carHeader: z.object({
|
|
60
|
+
version: z.literal(1),
|
|
61
|
+
roots: z.array(cidSchema),
|
|
62
|
+
}),
|
|
63
|
+
bytes: z.instanceof(Uint8Array),
|
|
64
|
+
string: z.string(),
|
|
65
|
+
array: z.array(z.unknown()),
|
|
66
|
+
map: z.record(z.string(), z.unknown()),
|
|
67
|
+
unknown: z.unknown(),
|
|
50
68
|
commit,
|
|
51
69
|
legacyV2Commit,
|
|
52
70
|
versionedCommit,
|
|
53
71
|
}
|
|
54
72
|
|
|
55
73
|
export const def = {
|
|
56
|
-
|
|
74
|
+
cid: {
|
|
75
|
+
name: 'cid',
|
|
76
|
+
schema: schema.cid,
|
|
77
|
+
},
|
|
78
|
+
carHeader: {
|
|
79
|
+
name: 'CAR header',
|
|
80
|
+
schema: schema.carHeader,
|
|
81
|
+
},
|
|
82
|
+
bytes: {
|
|
83
|
+
name: 'bytes',
|
|
84
|
+
schema: schema.bytes,
|
|
85
|
+
},
|
|
86
|
+
string: {
|
|
87
|
+
name: 'string',
|
|
88
|
+
schema: schema.string,
|
|
89
|
+
},
|
|
90
|
+
map: {
|
|
91
|
+
name: 'map',
|
|
92
|
+
schema: schema.map,
|
|
93
|
+
},
|
|
94
|
+
unknown: {
|
|
95
|
+
name: 'unknown',
|
|
96
|
+
schema: schema.unknown,
|
|
97
|
+
},
|
|
57
98
|
commit: {
|
|
58
99
|
name: 'commit',
|
|
59
100
|
schema: schema.commit,
|
|
@@ -75,46 +116,46 @@ export enum WriteOpAction {
|
|
|
75
116
|
|
|
76
117
|
export type RecordCreateOp = {
|
|
77
118
|
action: WriteOpAction.Create
|
|
78
|
-
collection:
|
|
79
|
-
rkey:
|
|
80
|
-
record:
|
|
119
|
+
collection: NsidString
|
|
120
|
+
rkey: RecordKeyString
|
|
121
|
+
record: LexMap
|
|
81
122
|
}
|
|
82
123
|
|
|
83
124
|
export type RecordUpdateOp = {
|
|
84
125
|
action: WriteOpAction.Update
|
|
85
|
-
collection:
|
|
86
|
-
rkey:
|
|
87
|
-
record:
|
|
126
|
+
collection: NsidString
|
|
127
|
+
rkey: RecordKeyString
|
|
128
|
+
record: LexMap
|
|
88
129
|
}
|
|
89
130
|
|
|
90
131
|
export type RecordDeleteOp = {
|
|
91
132
|
action: WriteOpAction.Delete
|
|
92
|
-
collection:
|
|
93
|
-
rkey:
|
|
133
|
+
collection: NsidString
|
|
134
|
+
rkey: RecordKeyString
|
|
94
135
|
}
|
|
95
136
|
|
|
96
137
|
export type RecordWriteOp = RecordCreateOp | RecordUpdateOp | RecordDeleteOp
|
|
97
138
|
|
|
98
139
|
export type RecordCreateDescript = {
|
|
99
140
|
action: WriteOpAction.Create
|
|
100
|
-
collection:
|
|
101
|
-
rkey:
|
|
102
|
-
cid:
|
|
141
|
+
collection: NsidString
|
|
142
|
+
rkey: RecordKeyString
|
|
143
|
+
cid: Cid
|
|
103
144
|
}
|
|
104
145
|
|
|
105
146
|
export type RecordUpdateDescript = {
|
|
106
147
|
action: WriteOpAction.Update
|
|
107
|
-
collection:
|
|
108
|
-
rkey:
|
|
109
|
-
prev:
|
|
110
|
-
cid:
|
|
148
|
+
collection: NsidString
|
|
149
|
+
rkey: RecordKeyString
|
|
150
|
+
prev: Cid
|
|
151
|
+
cid: Cid
|
|
111
152
|
}
|
|
112
153
|
|
|
113
154
|
export type RecordDeleteDescript = {
|
|
114
155
|
action: WriteOpAction.Delete
|
|
115
|
-
collection:
|
|
116
|
-
rkey:
|
|
117
|
-
cid:
|
|
156
|
+
collection: NsidString
|
|
157
|
+
rkey: RecordKeyString
|
|
158
|
+
cid: Cid
|
|
118
159
|
}
|
|
119
160
|
|
|
120
161
|
export type RecordWriteDescript =
|
|
@@ -128,10 +169,10 @@ export type WriteLog = RecordWriteDescript[][]
|
|
|
128
169
|
// ---------------
|
|
129
170
|
|
|
130
171
|
export type CommitData = {
|
|
131
|
-
cid:
|
|
172
|
+
cid: Cid
|
|
132
173
|
rev: string
|
|
133
174
|
since: string | null
|
|
134
|
-
prev:
|
|
175
|
+
prev: Cid | null
|
|
135
176
|
newBlocks: BlockMap
|
|
136
177
|
relevantBlocks: BlockMap
|
|
137
178
|
removedCids: CidSet
|
|
@@ -141,14 +182,14 @@ export type RepoUpdate = CommitData & {
|
|
|
141
182
|
ops: RecordWriteOp[]
|
|
142
183
|
}
|
|
143
184
|
|
|
144
|
-
export type CollectionContents = Record<string,
|
|
145
|
-
export type RepoContents = Record<
|
|
185
|
+
export type CollectionContents = Record<string, LexMap>
|
|
186
|
+
export type RepoContents = Record<NsidString, CollectionContents>
|
|
146
187
|
|
|
147
|
-
export type RepoRecordWithCid = { cid:
|
|
188
|
+
export type RepoRecordWithCid = { cid: Cid; value: LexMap }
|
|
148
189
|
export type CollectionContentsWithCids = Record<string, RepoRecordWithCid>
|
|
149
190
|
export type RepoContentsWithCids = Record<string, CollectionContentsWithCids>
|
|
150
191
|
|
|
151
|
-
export type DatastoreContents = Record<string,
|
|
192
|
+
export type DatastoreContents = Record<string, Cid>
|
|
152
193
|
|
|
153
194
|
export type RecordPath = {
|
|
154
195
|
collection: string
|
|
@@ -158,13 +199,13 @@ export type RecordPath = {
|
|
|
158
199
|
export type RecordCidClaim = {
|
|
159
200
|
collection: string
|
|
160
201
|
rkey: string
|
|
161
|
-
cid:
|
|
202
|
+
cid: Cid | null
|
|
162
203
|
}
|
|
163
204
|
|
|
164
205
|
export type RecordClaim = {
|
|
165
206
|
collection: string
|
|
166
207
|
rkey: string
|
|
167
|
-
record:
|
|
208
|
+
record: LexMap | null
|
|
168
209
|
}
|
|
169
210
|
|
|
170
211
|
// Sync
|
|
@@ -181,6 +222,6 @@ export type VerifiedRepo = {
|
|
|
181
222
|
}
|
|
182
223
|
|
|
183
224
|
export type CarBlock = {
|
|
184
|
-
cid:
|
|
225
|
+
cid: Cid
|
|
185
226
|
bytes: Uint8Array
|
|
186
227
|
}
|
package/src/util.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { TID, cborDecode, check, cidForCbor, schema } from '@atproto/common'
|
|
1
|
+
import { TID } from '@atproto/common-web'
|
|
3
2
|
import * as crypto from '@atproto/crypto'
|
|
4
3
|
import { Keypair } from '@atproto/crypto'
|
|
5
|
-
import
|
|
4
|
+
import * as cbor from '@atproto/lex-cbor'
|
|
5
|
+
import { Cid, LexMap, LexValue, isPlainObject } from '@atproto/lex-data'
|
|
6
6
|
import { DataDiff } from './data-diff'
|
|
7
7
|
import {
|
|
8
8
|
Commit,
|
|
@@ -66,9 +66,9 @@ export const ensureCreates = (
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
export const parseDataKey = (key: string): RecordPath => {
|
|
69
|
-
const
|
|
70
|
-
if (
|
|
71
|
-
return { collection
|
|
69
|
+
const { length, 0: collection, 1: rkey } = key.split('/')
|
|
70
|
+
if (length !== 2) throw new Error(`Invalid record key: ${key}`)
|
|
71
|
+
return { collection, rkey }
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
export const formatDataKey = (collection: string, rkey: string): string => {
|
|
@@ -100,21 +100,17 @@ export const verifyCommitSig = async (
|
|
|
100
100
|
return crypto.verifySignature(didKey, encoded, sig)
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
-
export const cborToLex
|
|
104
|
-
return ipldToLex(cborDecode(val))
|
|
105
|
-
}
|
|
103
|
+
export const cborToLex: (val: Uint8Array) => LexValue = cbor.decode
|
|
106
104
|
|
|
107
|
-
export const cborToLexRecord = (val: Uint8Array):
|
|
105
|
+
export const cborToLexRecord = (val: Uint8Array): LexMap => {
|
|
108
106
|
const parsed = cborToLex(val)
|
|
109
|
-
if (!
|
|
107
|
+
if (!isPlainObject(parsed)) {
|
|
110
108
|
throw new Error('lexicon records be a json object')
|
|
111
109
|
}
|
|
112
110
|
return parsed
|
|
113
111
|
}
|
|
114
112
|
|
|
115
|
-
export const cidForRecord
|
|
116
|
-
return cidForCbor(lexToIpld(val))
|
|
117
|
-
}
|
|
113
|
+
export const cidForRecord: (val: LexValue) => Promise<Cid> = cbor.cidForLex
|
|
118
114
|
|
|
119
115
|
export const ensureV3Commit = (commit: LegacyV2Commit | Commit): Commit => {
|
|
120
116
|
if (commit.version === 3) {
|
|
@@ -127,3 +123,24 @@ export const ensureV3Commit = (commit: LegacyV2Commit | Commit): Commit => {
|
|
|
127
123
|
}
|
|
128
124
|
}
|
|
129
125
|
}
|
|
126
|
+
|
|
127
|
+
export async function concatBytesAsync(iterable: AsyncIterable<Uint8Array>) {
|
|
128
|
+
const chunks: Uint8Array[] = []
|
|
129
|
+
for await (const chunk of iterable) chunks.push(chunk)
|
|
130
|
+
return concatBytes(chunks)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* This is the same as {@link Buffer.concat}, without the `totalLength` argument.
|
|
135
|
+
*/
|
|
136
|
+
export function concatBytes(chunks: readonly Uint8Array[]): Uint8Array {
|
|
137
|
+
let totalLength = 0
|
|
138
|
+
for (const chunk of chunks) totalLength += chunk.byteLength
|
|
139
|
+
const result = new Uint8Array(totalLength)
|
|
140
|
+
let offset = 0
|
|
141
|
+
for (const chunk of chunks) {
|
|
142
|
+
result.set(chunk, offset)
|
|
143
|
+
offset += chunk.byteLength
|
|
144
|
+
}
|
|
145
|
+
return result
|
|
146
|
+
}
|
package/tests/_util.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import fs from 'node:fs'
|
|
2
|
-
import {
|
|
3
|
-
import { TID, dataToCborBlock } from '@atproto/common'
|
|
2
|
+
import { TID } from '@atproto/common-web'
|
|
4
3
|
import * as crypto from '@atproto/crypto'
|
|
5
4
|
import { Keypair, randomBytes } from '@atproto/crypto'
|
|
5
|
+
import * as cbor from '@atproto/lex-cbor'
|
|
6
|
+
import { Cid, cidForCbor, parseCid } from '@atproto/lex-data'
|
|
7
|
+
import { NsidString } from '@atproto/syntax'
|
|
6
8
|
import {
|
|
7
9
|
BlockMap,
|
|
8
10
|
CollectionContents,
|
|
@@ -18,15 +20,16 @@ import { MST } from '../src/mst'
|
|
|
18
20
|
import { Repo } from '../src/repo'
|
|
19
21
|
import { RepoStorage } from '../src/storage'
|
|
20
22
|
|
|
21
|
-
type IdMapping = Record<string,
|
|
23
|
+
type IdMapping = Record<string, Cid>
|
|
22
24
|
|
|
23
|
-
export const randomCid = async (storage?: RepoStorage): Promise<
|
|
24
|
-
const
|
|
25
|
+
export const randomCid = async (storage?: RepoStorage): Promise<Cid> => {
|
|
26
|
+
const bytes = cbor.encode({ test: randomStr(50) })
|
|
27
|
+
const cid = await cidForCbor(bytes)
|
|
25
28
|
if (storage) {
|
|
26
29
|
// @ts-expect-error FIXME remove this comment (and fix the TS error)
|
|
27
|
-
await storage.putBlock(
|
|
30
|
+
await storage.putBlock(cid, bytes)
|
|
28
31
|
}
|
|
29
|
-
return
|
|
32
|
+
return cid
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
export const generateBulkDataKeys = async (
|
|
@@ -78,7 +81,10 @@ export const generateObject = (): Record<string, string> => {
|
|
|
78
81
|
// Mass repo mutations & checking
|
|
79
82
|
// -------------------------------
|
|
80
83
|
|
|
81
|
-
export const testCollections = [
|
|
84
|
+
export const testCollections: NsidString[] = [
|
|
85
|
+
'com.example.posts',
|
|
86
|
+
'com.example.likes',
|
|
87
|
+
]
|
|
82
88
|
|
|
83
89
|
export const fillRepo = async (
|
|
84
90
|
repo: Repo,
|
|
@@ -173,7 +179,7 @@ export const formatEdit = async (
|
|
|
173
179
|
export const pathsForOps = (ops: RecordWriteOp[]): RecordPath[] =>
|
|
174
180
|
ops.map((op) => ({ collection: op.collection, rkey: op.rkey }))
|
|
175
181
|
|
|
176
|
-
export const saveMst = async (storage: RepoStorage, mst: MST): Promise<
|
|
182
|
+
export const saveMst = async (storage: RepoStorage, mst: MST): Promise<Cid> => {
|
|
177
183
|
const diff = await mst.getUnstoredBlocks()
|
|
178
184
|
// @ts-expect-error FIXME remove this comment (and fix the TS error)
|
|
179
185
|
await storage.putMany(diff.blocks)
|
|
@@ -237,13 +243,23 @@ export const writeMstLog = async (filename: string, tree: MST) => {
|
|
|
237
243
|
fs.writeFileSync(filename, log)
|
|
238
244
|
}
|
|
239
245
|
|
|
240
|
-
export const saveMstEntries = (filename: string, entries: [string,
|
|
246
|
+
export const saveMstEntries = (filename: string, entries: [string, Cid][]) => {
|
|
241
247
|
const writable = entries.map(([key, val]) => [key, val.toString()])
|
|
242
248
|
fs.writeFileSync(filename, JSON.stringify(writable))
|
|
243
249
|
}
|
|
244
250
|
|
|
245
|
-
export const loadMstEntries = (filename: string): [string,
|
|
251
|
+
export const loadMstEntries = (filename: string): [string, Cid][] => {
|
|
246
252
|
const contents = fs.readFileSync(filename)
|
|
247
253
|
const parsed = JSON.parse(contents.toString())
|
|
248
|
-
return parsed.map(([key, value]) => [key,
|
|
254
|
+
return parsed.map(([key, value]) => [key, parseCid(value)])
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
export async function toBuffer(
|
|
258
|
+
stream: AsyncIterable<Uint8Array> | Iterable<Uint8Array>,
|
|
259
|
+
): Promise<Buffer> {
|
|
260
|
+
const chunks: Uint8Array[] = []
|
|
261
|
+
for await (const chunk of stream) {
|
|
262
|
+
chunks.push(chunk)
|
|
263
|
+
}
|
|
264
|
+
return Buffer.concat(chunks)
|
|
249
265
|
}
|
package/tests/car.test.ts
CHANGED
|
@@ -1,28 +1,48 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
1
|
+
import { wait } from '@atproto/common-web'
|
|
2
|
+
import { encode } from '@atproto/lex-cbor'
|
|
3
|
+
import {
|
|
4
|
+
Cid,
|
|
5
|
+
LexValue,
|
|
6
|
+
cidForCbor,
|
|
7
|
+
fromBase64,
|
|
8
|
+
parseCid,
|
|
9
|
+
toBase64,
|
|
10
|
+
} from '@atproto/lex-data'
|
|
4
11
|
import { CarBlock, readCarStream, writeCarStream } from '../src'
|
|
5
12
|
import fixtures from './car-file-fixtures.json'
|
|
6
13
|
|
|
14
|
+
async function dataToCborBlock(data: LexValue): Promise<{
|
|
15
|
+
cid: Cid
|
|
16
|
+
bytes: Uint8Array
|
|
17
|
+
}> {
|
|
18
|
+
const bytes = encode(data)
|
|
19
|
+
const cid = await cidForCbor(bytes)
|
|
20
|
+
return { cid, bytes }
|
|
21
|
+
}
|
|
22
|
+
|
|
7
23
|
describe('car', () => {
|
|
8
24
|
for (const fixture of fixtures) {
|
|
9
25
|
it('correctly writes car files', async () => {
|
|
10
|
-
const root =
|
|
26
|
+
const root = parseCid(fixture.root)
|
|
11
27
|
async function* blockIter() {
|
|
12
28
|
for (const block of fixture.blocks) {
|
|
13
|
-
const cid =
|
|
14
|
-
const bytes =
|
|
29
|
+
const cid = parseCid(block.cid)
|
|
30
|
+
const bytes = fromBase64(block.bytes, 'base64')
|
|
15
31
|
yield { cid, bytes }
|
|
16
32
|
}
|
|
17
33
|
}
|
|
18
34
|
const carStream = writeCarStream(root, blockIter())
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
|
|
35
|
+
const chunks: Uint8Array[] = []
|
|
36
|
+
for await (const chunk of carStream) {
|
|
37
|
+
chunks.push(chunk)
|
|
38
|
+
}
|
|
39
|
+
const car = Buffer.concat(chunks)
|
|
40
|
+
// @NOTE Not using car.toString('base64') because of padding differences
|
|
41
|
+
expect(toBase64(car)).toEqual(fixture.car)
|
|
22
42
|
})
|
|
23
43
|
|
|
24
44
|
it('correctly reads carfiles', async () => {
|
|
25
|
-
const carStream = [
|
|
45
|
+
const carStream = [fromBase64(fixture.car, 'base64')]
|
|
26
46
|
const { roots, blocks } = await readCarStream(carStream)
|
|
27
47
|
expect(roots.length).toBe(1)
|
|
28
48
|
expect(roots[0].toString()).toEqual(fixture.root)
|
|
@@ -33,7 +53,7 @@ describe('car', () => {
|
|
|
33
53
|
expect(carBlocks.length).toEqual(fixture.blocks.length)
|
|
34
54
|
for (let i = 0; i < carBlocks.length; i++) {
|
|
35
55
|
expect(carBlocks[i].cid.toString()).toEqual(fixture.blocks[i].cid)
|
|
36
|
-
expect(
|
|
56
|
+
expect(toBase64(carBlocks[i].bytes, 'base64')).toEqual(
|
|
37
57
|
fixture.blocks[i].bytes,
|
|
38
58
|
)
|
|
39
59
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { parseCid } from '@atproto/lex-data'
|
|
2
2
|
import { BlockMap } from '../src'
|
|
3
3
|
import { MST } from '../src/mst'
|
|
4
4
|
import { MemoryBlockstore } from '../src/storage'
|
|
@@ -8,7 +8,7 @@ describe('commit proofs', () => {
|
|
|
8
8
|
for (const fixture of fixtures) {
|
|
9
9
|
it(fixture.comment, async () => {
|
|
10
10
|
const { leafValue, keys, adds, dels } = fixture
|
|
11
|
-
const leaf =
|
|
11
|
+
const leaf = parseCid(leafValue)
|
|
12
12
|
|
|
13
13
|
const storage = new MemoryBlockstore()
|
|
14
14
|
let mst = await MST.create(storage)
|
|
@@ -31,7 +31,7 @@ describe('commit proofs', () => {
|
|
|
31
31
|
[...adds, ...dels].map((key) => mst.getCoveringProof(key)),
|
|
32
32
|
)
|
|
33
33
|
const proof = proofs.reduce((acc, cur) => acc.addMap(cur), new BlockMap())
|
|
34
|
-
const blocksInProof = fixture.blocksInProof.map(
|
|
34
|
+
const blocksInProof = fixture.blocksInProof.map(parseCid)
|
|
35
35
|
for (const cid of blocksInProof) {
|
|
36
36
|
expect(proof.has(cid)).toBe(true)
|
|
37
37
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { parseCid } from '@atproto/lex-data'
|
|
2
2
|
import { BlockMap } from '../src'
|
|
3
3
|
import { MST } from '../src/mst'
|
|
4
4
|
import { MemoryBlockstore } from '../src/storage'
|
|
@@ -25,7 +25,7 @@ describe('covering proofs', () => {
|
|
|
25
25
|
*/
|
|
26
26
|
it('two deep split ', async () => {
|
|
27
27
|
const storage = new MemoryBlockstore()
|
|
28
|
-
const cid =
|
|
28
|
+
const cid = parseCid(
|
|
29
29
|
'bafyreie5cvv4h45feadgeuwhbcutmh6t2ceseocckahdoe6uat64zmz454',
|
|
30
30
|
)
|
|
31
31
|
|
|
@@ -65,7 +65,7 @@ describe('covering proofs', () => {
|
|
|
65
65
|
*/
|
|
66
66
|
it('two deep leafless splits ', async () => {
|
|
67
67
|
const storage = new MemoryBlockstore()
|
|
68
|
-
const cid =
|
|
68
|
+
const cid = parseCid(
|
|
69
69
|
'bafyreie5cvv4h45feadgeuwhbcutmh6t2ceseocckahdoe6uat64zmz454',
|
|
70
70
|
)
|
|
71
71
|
|
|
@@ -103,7 +103,7 @@ describe('covering proofs', () => {
|
|
|
103
103
|
*/
|
|
104
104
|
it('add on edge with neighbor two layers down', async () => {
|
|
105
105
|
const storage = new MemoryBlockstore()
|
|
106
|
-
const cid =
|
|
106
|
+
const cid = parseCid(
|
|
107
107
|
'bafyreie5cvv4h45feadgeuwhbcutmh6t2ceseocckahdoe6uat64zmz454',
|
|
108
108
|
)
|
|
109
109
|
|
|
@@ -140,7 +140,7 @@ describe('covering proofs', () => {
|
|
|
140
140
|
*/
|
|
141
141
|
it('merge and split in multi op commit', async () => {
|
|
142
142
|
const storage = new MemoryBlockstore()
|
|
143
|
-
const cid =
|
|
143
|
+
const cid = parseCid(
|
|
144
144
|
'bafyreie5cvv4h45feadgeuwhbcutmh6t2ceseocckahdoe6uat64zmz454',
|
|
145
145
|
)
|
|
146
146
|
|
|
@@ -206,7 +206,7 @@ describe('covering proofs', () => {
|
|
|
206
206
|
*/
|
|
207
207
|
it('complex multi-op commit', async () => {
|
|
208
208
|
const storage = new MemoryBlockstore()
|
|
209
|
-
const cid =
|
|
209
|
+
const cid = parseCid(
|
|
210
210
|
'bafyreie5cvv4h45feadgeuwhbcutmh6t2ceseocckahdoe6uat64zmz454',
|
|
211
211
|
)
|
|
212
212
|
|