@atproto/repo 0.1.0 → 0.3.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.
Files changed (49) hide show
  1. package/dist/block-map.d.ts +2 -0
  2. package/dist/data-diff.d.ts +12 -10
  3. package/dist/index.d.ts +1 -1
  4. package/dist/index.js +12388 -4431
  5. package/dist/index.js.map +4 -4
  6. package/dist/mst/mst.d.ts +19 -16
  7. package/dist/readable-repo.d.ts +4 -3
  8. package/dist/repo.d.ts +3 -2
  9. package/dist/storage/index.d.ts +0 -1
  10. package/dist/storage/memory-blockstore.d.ts +6 -10
  11. package/dist/storage/types.d.ts +29 -0
  12. package/dist/sync/consumer.d.ts +13 -16
  13. package/dist/sync/provider.d.ts +2 -6
  14. package/dist/types.d.ts +236 -48
  15. package/dist/util.d.ts +9 -7
  16. package/jest.bench.config.js +2 -1
  17. package/package.json +12 -7
  18. package/src/block-map.ts +8 -0
  19. package/src/data-diff.ts +47 -49
  20. package/src/index.ts +1 -1
  21. package/src/mst/diff.ts +14 -36
  22. package/src/mst/mst.ts +15 -14
  23. package/src/readable-repo.ts +5 -5
  24. package/src/repo.ts +50 -40
  25. package/src/storage/index.ts +0 -1
  26. package/src/storage/memory-blockstore.ts +19 -59
  27. package/src/storage/types.ts +30 -0
  28. package/src/sync/consumer.ts +170 -113
  29. package/src/sync/provider.ts +6 -44
  30. package/src/types.ts +49 -25
  31. package/src/util.ts +57 -91
  32. package/tests/_util.ts +38 -67
  33. package/tests/mst.test.ts +4 -1
  34. package/tests/{sync/narrow.test.ts → proofs.test.ts} +14 -21
  35. package/tests/repo.test.ts +5 -4
  36. package/tests/sync.test.ts +97 -0
  37. package/tests/util.test.ts +21 -0
  38. package/tsconfig.build.tsbuildinfo +1 -1
  39. package/tsconfig.json +1 -1
  40. package/dist/blockstore/index.d.ts +0 -2
  41. package/dist/blockstore/ipld-store.d.ts +0 -27
  42. package/dist/blockstore/memory-blockstore.d.ts +0 -13
  43. package/dist/storage/repo-storage.d.ts +0 -18
  44. package/dist/sync.d.ts +0 -9
  45. package/dist/verify.d.ts +0 -27
  46. package/src/storage/repo-storage.ts +0 -42
  47. package/src/verify.ts +0 -227
  48. package/tests/sync/checkout.test.ts +0 -57
  49. package/tests/sync/diff.test.ts +0 -87
@@ -1,14 +1,15 @@
1
1
  import { CID } from 'multiformats/cid'
2
- import { CommitData, def } from '../types'
2
+ import { CommitData } from '../types'
3
3
  import BlockMap from '../block-map'
4
- import { MST } from '../mst'
5
- import DataDiff from '../data-diff'
6
- import { MissingCommitBlocksError } from '../error'
7
- import RepoStorage from './repo-storage'
4
+ import ReadableBlockstore from './readable-blockstore'
5
+ import { RepoStorage } from './types'
8
6
 
9
- export class MemoryBlockstore extends RepoStorage {
7
+ export class MemoryBlockstore
8
+ extends ReadableBlockstore
9
+ implements RepoStorage
10
+ {
10
11
  blocks: BlockMap
11
- head: CID | null = null
12
+ root: CID | null = null
12
13
 
13
14
  constructor(blocks?: BlockMap) {
14
15
  super()
@@ -18,8 +19,8 @@ export class MemoryBlockstore extends RepoStorage {
18
19
  }
19
20
  }
20
21
 
21
- async getHead(): Promise<CID | null> {
22
- return this.head
22
+ async getRoot(): Promise<CID | null> {
23
+ return this.root
23
24
  }
24
25
 
25
26
  async getBytes(cid: CID): Promise<Uint8Array | null> {
@@ -42,60 +43,19 @@ export class MemoryBlockstore extends RepoStorage {
42
43
  this.blocks.addMap(blocks)
43
44
  }
44
45
 
45
- async indexCommits(commits: CommitData[]): Promise<void> {
46
- commits.forEach((commit) => {
47
- this.blocks.addMap(commit.blocks)
48
- })
49
- }
50
-
51
- async updateHead(cid: CID, _prev: CID | null): Promise<void> {
52
- this.head = cid
46
+ async updateRoot(cid: CID): Promise<void> {
47
+ this.root = cid
53
48
  }
54
49
 
55
50
  async applyCommit(commit: CommitData): Promise<void> {
56
- this.blocks.addMap(commit.blocks)
57
- this.head = commit.commit
58
- }
59
-
60
- async getCommitPath(
61
- latest: CID,
62
- earliest: CID | null,
63
- ): Promise<CID[] | null> {
64
- let curr: CID | null = latest
65
- const path: CID[] = []
66
- while (curr !== null) {
67
- path.push(curr)
68
- const commit = await this.readObj(curr, def.commit)
69
- if (!earliest && commit.prev === null) {
70
- return path.reverse()
71
- } else if (earliest && commit.prev.equals(earliest)) {
72
- return path.reverse()
73
- }
74
- curr = commit.prev
51
+ this.root = commit.cid
52
+ const rmCids = commit.removedCids.toList()
53
+ for (const cid of rmCids) {
54
+ this.blocks.delete(cid)
75
55
  }
76
- return null
77
- }
78
-
79
- async getBlocksForCommits(
80
- commits: CID[],
81
- ): Promise<{ [commit: string]: BlockMap }> {
82
- const commitData: { [commit: string]: BlockMap } = {}
83
- let prevData: MST | null = null
84
- for (const commitCid of commits) {
85
- const commit = await this.readObj(commitCid, def.commit)
86
- const data = await MST.load(this, commit.data)
87
- const diff = await DataDiff.of(data, prevData)
88
- const { blocks, missing } = await this.getBlocks([
89
- commitCid,
90
- ...diff.newCidList(),
91
- ])
92
- if (missing.length > 0) {
93
- throw new MissingCommitBlocksError(commitCid, missing)
94
- }
95
- commitData[commitCid.toString()] = blocks
96
- prevData = data
97
- }
98
- return commitData
56
+ commit.newBlocks.forEach((bytes, cid) => {
57
+ this.blocks.set(cid, bytes)
58
+ })
99
59
  }
100
60
 
101
61
  async sizeInBytes(): Promise<number> {
@@ -1,5 +1,34 @@
1
1
  import stream from 'stream'
2
2
  import { CID } from 'multiformats/cid'
3
+ import { RepoRecord } from '@atproto/lexicon'
4
+ import { check } from '@atproto/common'
5
+ import BlockMap from '../block-map'
6
+ import { CommitData } from '../types'
7
+
8
+ export interface RepoStorage {
9
+ // Writable
10
+ getRoot(): Promise<CID | null>
11
+ putBlock(cid: CID, block: Uint8Array, rev: string): Promise<void>
12
+ putMany(blocks: BlockMap, rev: string): Promise<void>
13
+ updateRoot(cid: CID): Promise<void>
14
+ applyCommit(commit: CommitData)
15
+
16
+ // Readable
17
+ getBytes(cid: CID): Promise<Uint8Array | null>
18
+ has(cid: CID): Promise<boolean>
19
+ getBlocks(cids: CID[]): Promise<{ blocks: BlockMap; missing: CID[] }>
20
+ attemptRead<T>(
21
+ cid: CID,
22
+ def: check.Def<T>,
23
+ ): Promise<{ obj: T; bytes: Uint8Array } | null>
24
+ readObjAndBytes<T>(
25
+ cid: CID,
26
+ def: check.Def<T>,
27
+ ): Promise<{ obj: T; bytes: Uint8Array }>
28
+ readObj<T>(cid: CID, def: check.Def<T>): Promise<T>
29
+ attemptReadRecord(cid: CID): Promise<RepoRecord | null>
30
+ readRecord(cid: CID): Promise<RepoRecord>
31
+ }
3
32
 
4
33
  export interface BlobStore {
5
34
  putTemp(bytes: Uint8Array | stream.Readable): Promise<string>
@@ -9,6 +38,7 @@ export interface BlobStore {
9
38
  unquarantine(cid: CID): Promise<void>
10
39
  getBytes(cid: CID): Promise<Uint8Array>
11
40
  getStream(cid: CID): Promise<stream.Readable>
41
+ hasStored(cid: CID): Promise<boolean>
12
42
  delete(cid: CID): Promise<void>
13
43
  }
14
44
 
@@ -1,137 +1,194 @@
1
1
  import { CID } from 'multiformats/cid'
2
- import { MemoryBlockstore, RepoStorage } from '../storage'
3
- import Repo from '../repo'
4
- import * as verify from '../verify'
2
+ import { MemoryBlockstore, ReadableBlockstore, SyncStorage } from '../storage'
3
+ import DataDiff from '../data-diff'
4
+ import ReadableRepo from '../readable-repo'
5
5
  import * as util from '../util'
6
- import { CommitData, RepoContents, WriteLog } from '../types'
7
- import CidSet from '../cid-set'
8
- import { MissingBlocksError } from '../error'
9
-
10
- // Checkouts
11
- // -------------
12
-
13
- export const loadCheckout = async (
14
- storage: RepoStorage,
15
- repoCar: Uint8Array,
16
- did: string,
17
- signingKey: string,
18
- ): Promise<{ root: CID; contents: RepoContents }> => {
19
- const { root, blocks } = await util.readCarWithRoot(repoCar)
20
- const updateStorage = new MemoryBlockstore(blocks)
21
- const checkout = await verify.verifyCheckout(
22
- updateStorage,
23
- root,
24
- did,
25
- signingKey,
26
- )
27
-
28
- const checkoutBlocks = await updateStorage.getBlocks(
29
- checkout.newCids.toList(),
30
- )
31
- if (checkoutBlocks.missing.length > 0) {
32
- throw new MissingBlocksError('sync', checkoutBlocks.missing)
33
- }
34
- await Promise.all([
35
- storage.putMany(checkoutBlocks.blocks),
36
- storage.updateHead(root, null),
37
- ])
6
+ import { RecordClaim, VerifiedDiff, VerifiedRepo } from '../types'
7
+ import { def } from '../types'
8
+ import { MST } from '../mst'
9
+ import { cidForCbor } from '@atproto/common'
10
+ import BlockMap from '../block-map'
11
+
12
+ export const verifyRepoCar = async (
13
+ carBytes: Uint8Array,
14
+ did?: string,
15
+ signingKey?: string,
16
+ ): Promise<VerifiedRepo> => {
17
+ const car = await util.readCarWithRoot(carBytes)
18
+ return verifyRepo(car.blocks, car.root, did, signingKey)
19
+ }
38
20
 
21
+ export const verifyRepo = async (
22
+ blocks: BlockMap,
23
+ head: CID,
24
+ did?: string,
25
+ signingKey?: string,
26
+ ): Promise<VerifiedRepo> => {
27
+ const diff = await verifyDiff(null, blocks, head, did, signingKey)
28
+ const creates = util.ensureCreates(diff.writes)
39
29
  return {
40
- root,
41
- contents: checkout.contents,
30
+ creates,
31
+ commit: diff.commit,
42
32
  }
43
33
  }
44
34
 
45
- // Diffs
46
- // -------------
35
+ export const verifyDiffCar = async (
36
+ repo: ReadableRepo | null,
37
+ carBytes: Uint8Array,
38
+ did?: string,
39
+ signingKey?: string,
40
+ ): Promise<VerifiedDiff> => {
41
+ const car = await util.readCarWithRoot(carBytes)
42
+ return verifyDiff(repo, car.blocks, car.root, did, signingKey)
43
+ }
47
44
 
48
- export const loadFullRepo = async (
49
- storage: RepoStorage,
50
- repoCar: Uint8Array,
51
- did: string,
52
- signingKey: string,
53
- ): Promise<{ root: CID; writeLog: WriteLog }> => {
54
- const { root, blocks } = await util.readCarWithRoot(repoCar)
55
- const updateStorage = new MemoryBlockstore(blocks)
56
- const updates = await verify.verifyFullHistory(
45
+ export const verifyDiff = async (
46
+ repo: ReadableRepo | null,
47
+ updateBlocks: BlockMap,
48
+ updateRoot: CID,
49
+ did?: string,
50
+ signingKey?: string,
51
+ ): Promise<VerifiedDiff> => {
52
+ const stagedStorage = new MemoryBlockstore(updateBlocks)
53
+ const updateStorage = repo
54
+ ? new SyncStorage(stagedStorage, repo.storage)
55
+ : stagedStorage
56
+ const updated = await verifyRepoRoot(
57
57
  updateStorage,
58
- root,
58
+ updateRoot,
59
59
  did,
60
60
  signingKey,
61
61
  )
62
-
63
- const [writeLog] = await Promise.all([
64
- persistUpdates(storage, updateStorage, updates),
65
- storage.updateHead(root, null),
66
- ])
67
-
62
+ const diff = await DataDiff.of(updated.data, repo?.data ?? null)
63
+ const writes = await util.diffToWriteDescripts(diff, updateBlocks)
64
+ const newBlocks = diff.newMstBlocks
65
+ const leaves = updateBlocks.getMany(diff.newLeafCids.toList())
66
+ if (leaves.missing.length > 0) {
67
+ throw new Error(`missing leaf blocks: ${leaves.missing}`)
68
+ }
69
+ newBlocks.addMap(leaves.blocks)
70
+ const removedCids = diff.removedCids
71
+ const commitCid = await newBlocks.add(updated.commit)
72
+ // ensure the commit cid actually changed
73
+ if (repo) {
74
+ if (commitCid.equals(repo.cid)) {
75
+ newBlocks.delete(commitCid)
76
+ } else {
77
+ removedCids.add(repo.cid)
78
+ }
79
+ }
68
80
  return {
69
- root,
70
- writeLog,
81
+ writes,
82
+ commit: {
83
+ cid: updated.cid,
84
+ rev: updated.commit.rev,
85
+ prev: repo?.cid ?? null,
86
+ since: repo?.commit.rev ?? null,
87
+ newBlocks,
88
+ removedCids,
89
+ },
71
90
  }
72
91
  }
73
92
 
74
- export const loadDiff = async (
75
- repo: Repo,
76
- diffCar: Uint8Array,
77
- did: string,
78
- signingKey: string,
79
- ): Promise<{ root: CID; writeLog: WriteLog }> => {
80
- const { root, blocks } = await util.readCarWithRoot(diffCar)
81
- const updateStorage = new MemoryBlockstore(blocks)
82
- const updates = await verify.verifyUpdates(
83
- repo,
84
- updateStorage,
85
- root,
86
- did,
87
- signingKey,
88
- )
89
-
90
- const [writeLog] = await Promise.all([
91
- persistUpdates(repo.storage, updateStorage, updates),
92
- repo.storage.updateHead(root, repo.cid),
93
- ])
94
-
95
- return {
96
- root,
97
- writeLog,
93
+ // @NOTE only verifies the root, not the repo contents
94
+ const verifyRepoRoot = async (
95
+ storage: ReadableBlockstore,
96
+ head: CID,
97
+ did?: string,
98
+ signingKey?: string,
99
+ ): Promise<ReadableRepo> => {
100
+ const repo = await ReadableRepo.load(storage, head)
101
+ if (did !== undefined && repo.did !== did) {
102
+ throw new RepoVerificationError(`Invalid repo did: ${repo.did}`)
98
103
  }
104
+ if (signingKey !== undefined) {
105
+ const validSig = await util.verifyCommitSig(repo.commit, signingKey)
106
+ if (!validSig) {
107
+ throw new RepoVerificationError(
108
+ `Invalid signature on commit: ${repo.cid.toString()}`,
109
+ )
110
+ }
111
+ }
112
+ return repo
99
113
  }
100
114
 
101
- // Helpers
102
- // -------------
103
-
104
- export const persistUpdates = async (
105
- storage: RepoStorage,
106
- updateStorage: RepoStorage,
107
- updates: verify.VerifiedUpdate[],
108
- ): Promise<WriteLog> => {
109
- const newCids = new CidSet()
110
- for (const update of updates) {
111
- newCids.addSet(update.newCids)
115
+ export const verifyProofs = async (
116
+ proofs: Uint8Array,
117
+ claims: RecordClaim[],
118
+ did: string,
119
+ didKey: string,
120
+ ): Promise<{ verified: RecordClaim[]; unverified: RecordClaim[] }> => {
121
+ const car = await util.readCarWithRoot(proofs)
122
+ const blockstore = new MemoryBlockstore(car.blocks)
123
+ const commit = await blockstore.readObj(car.root, def.commit)
124
+ if (commit.did !== did) {
125
+ throw new RepoVerificationError(`Invalid repo did: ${commit.did}`)
112
126
  }
113
-
114
- const diffBlocks = await updateStorage.getBlocks(newCids.toList())
115
- if (diffBlocks.missing.length > 0) {
116
- throw new MissingBlocksError('sync', diffBlocks.missing)
127
+ const validSig = await util.verifyCommitSig(commit, didKey)
128
+ if (!validSig) {
129
+ throw new RepoVerificationError(
130
+ `Invalid signature on commit: ${car.root.toString()}`,
131
+ )
117
132
  }
118
- const commits: CommitData[] = updates.map((update) => {
119
- const forCommit = diffBlocks.blocks.getMany(update.newCids.toList())
120
- if (forCommit.missing.length > 0) {
121
- throw new MissingBlocksError('sync', forCommit.missing)
122
- }
123
- return {
124
- commit: update.commit,
125
- prev: update.prev,
126
- blocks: forCommit.blocks,
133
+ const mst = MST.load(blockstore, commit.data)
134
+ const verified: RecordClaim[] = []
135
+ const unverified: RecordClaim[] = []
136
+ for (const claim of claims) {
137
+ const found = await mst.get(
138
+ util.formatDataKey(claim.collection, claim.rkey),
139
+ )
140
+ const record = found ? await blockstore.readObj(found, def.map) : null
141
+ if (claim.record === null) {
142
+ if (record === null) {
143
+ verified.push(claim)
144
+ } else {
145
+ unverified.push(claim)
146
+ }
147
+ } else {
148
+ const expected = await cidForCbor(claim.record)
149
+ if (expected.equals(found)) {
150
+ verified.push(claim)
151
+ } else {
152
+ unverified.push(claim)
153
+ }
127
154
  }
128
- })
129
-
130
- await storage.indexCommits(commits)
155
+ }
156
+ return { verified, unverified }
157
+ }
131
158
 
132
- return Promise.all(
133
- updates.map((upd) =>
134
- util.diffToWriteDescripts(upd.diff, diffBlocks.blocks),
135
- ),
136
- )
159
+ export const verifyRecords = async (
160
+ proofs: Uint8Array,
161
+ did: string,
162
+ signingKey: string,
163
+ ): Promise<RecordClaim[]> => {
164
+ const car = await util.readCarWithRoot(proofs)
165
+ const blockstore = new MemoryBlockstore(car.blocks)
166
+ const commit = await blockstore.readObj(car.root, def.commit)
167
+ if (commit.did !== did) {
168
+ throw new RepoVerificationError(`Invalid repo did: ${commit.did}`)
169
+ }
170
+ const validSig = await util.verifyCommitSig(commit, signingKey)
171
+ if (!validSig) {
172
+ throw new RepoVerificationError(
173
+ `Invalid signature on commit: ${car.root.toString()}`,
174
+ )
175
+ }
176
+ const mst = MST.load(blockstore, commit.data)
177
+
178
+ const records: RecordClaim[] = []
179
+ const leaves = await mst.reachableLeaves()
180
+ for (const leaf of leaves) {
181
+ const { collection, rkey } = util.parseDataKey(leaf.key)
182
+ const record = await blockstore.attemptReadRecord(leaf.value)
183
+ if (record) {
184
+ records.push({
185
+ collection,
186
+ rkey,
187
+ record,
188
+ })
189
+ }
190
+ }
191
+ return records
137
192
  }
193
+
194
+ export class RepoVerificationError extends Error {}
@@ -1,4 +1,4 @@
1
- import { Commit, def, RecordPath } from '../types'
1
+ import { def, RecordPath } from '../types'
2
2
  import { BlockWriter } from '@ipld/car/writer'
3
3
  import { CID } from 'multiformats/cid'
4
4
  import CidSet from '../cid-set'
@@ -7,13 +7,13 @@ import { RepoStorage } from '../storage'
7
7
  import * as util from '../util'
8
8
  import { MST } from '../mst'
9
9
 
10
- // Checkouts
10
+ // Full Repo
11
11
  // -------------
12
12
 
13
- export const getCheckout = async (
13
+ export const getFullRepo = (
14
14
  storage: RepoStorage,
15
15
  commitCid: CID,
16
- ): Promise<Uint8Array> => {
16
+ ): AsyncIterable<Uint8Array> => {
17
17
  return util.writeCar(commitCid, async (car: BlockWriter) => {
18
18
  const commit = await storage.readObjAndBytes(commitCid, def.commit)
19
19
  await car.put({ cid: commitCid, bytes: commit.bytes })
@@ -22,52 +22,14 @@ export const getCheckout = async (
22
22
  })
23
23
  }
24
24
 
25
- // Diffs
26
- // -------------
27
-
28
- export const getDiff = async (
29
- storage: RepoStorage,
30
- latest: CID,
31
- earliest: CID | null,
32
- ): Promise<Uint8Array> => {
33
- return util.writeCar(latest, (car: BlockWriter) => {
34
- return writeCommitsToCarStream(storage, car, latest, earliest)
35
- })
36
- }
37
-
38
- export const getFullRepo = async (
39
- storage: RepoStorage,
40
- cid: CID,
41
- ): Promise<Uint8Array> => {
42
- return getDiff(storage, cid, null)
43
- }
44
-
45
- export const writeCommitsToCarStream = async (
46
- storage: RepoStorage,
47
- car: BlockWriter,
48
- latest: CID,
49
- earliest: CID | null,
50
- ): Promise<void> => {
51
- const commits = await storage.getCommits(latest, earliest)
52
- if (commits === null) {
53
- throw new Error('Could not find shared history')
54
- }
55
- if (commits.length === 0) return
56
- for (const commit of commits) {
57
- for (const entry of commit.blocks.entries()) {
58
- await car.put(entry)
59
- }
60
- }
61
- }
62
-
63
25
  // Narrow slices
64
26
  // -------------
65
27
 
66
- export const getRecords = async (
28
+ export const getRecords = (
67
29
  storage: RepoStorage,
68
30
  commitCid: CID,
69
31
  paths: RecordPath[],
70
- ): Promise<Uint8Array> => {
32
+ ): AsyncIterable<Uint8Array> => {
71
33
  return util.writeCar(commitCid, async (car: BlockWriter) => {
72
34
  const commit = await storage.readObjAndBytes(commitCid, def.commit)
73
35
  await car.put({ cid: commitCid, bytes: commit.bytes })
package/src/types.ts CHANGED
@@ -1,33 +1,54 @@
1
1
  import { z } from 'zod'
2
- import { BlockWriter } from '@ipld/car/writer'
3
2
  import { schema as common, def as commonDef } from '@atproto/common'
4
3
  import { CID } from 'multiformats'
5
4
  import BlockMap from './block-map'
6
5
  import { RepoRecord } from '@atproto/lexicon'
6
+ import CidSet from './cid-set'
7
7
 
8
8
  // Repo nodes
9
9
  // ---------------
10
10
 
11
11
  const unsignedCommit = z.object({
12
12
  did: z.string(),
13
- version: z.number(),
14
- prev: common.cid.nullable(),
13
+ version: z.literal(3),
15
14
  data: common.cid,
15
+ rev: z.string(),
16
+ // `prev` added for backwards compatibility with v2, no requirement of keeping around history
17
+ prev: common.cid.nullable().optional(),
16
18
  })
17
19
  export type UnsignedCommit = z.infer<typeof unsignedCommit> & { sig?: never }
18
20
 
19
21
  const commit = z.object({
20
22
  did: z.string(),
21
- version: z.number(),
22
- prev: common.cid.nullable(),
23
+ version: z.literal(3),
23
24
  data: common.cid,
25
+ rev: z.string(),
26
+ prev: common.cid.nullable().optional(),
24
27
  sig: common.bytes,
25
28
  })
26
29
  export type Commit = z.infer<typeof commit>
27
30
 
31
+ const legacyV2Commit = z.object({
32
+ did: z.string(),
33
+ version: z.literal(2),
34
+ data: common.cid,
35
+ rev: z.string().optional(),
36
+ prev: common.cid.nullable(),
37
+ sig: common.bytes,
38
+ })
39
+ export type LegacyV2Commit = z.infer<typeof legacyV2Commit>
40
+
41
+ const versionedCommit = z.discriminatedUnion('version', [
42
+ commit,
43
+ legacyV2Commit,
44
+ ])
45
+ export type VersionedCommit = z.infer<typeof versionedCommit>
46
+
28
47
  export const schema = {
29
48
  ...common,
30
49
  commit,
50
+ legacyV2Commit,
51
+ versionedCommit,
31
52
  }
32
53
 
33
54
  export const def = {
@@ -36,6 +57,10 @@ export const def = {
36
57
  name: 'commit',
37
58
  schema: schema.commit,
38
59
  },
60
+ versionedCommit: {
61
+ name: 'versioned_commit',
62
+ schema: schema.versionedCommit,
63
+ },
39
64
  }
40
65
 
41
66
  // Repo Operations
@@ -92,13 +117,13 @@ export type WriteLog = RecordWriteDescript[][]
92
117
  // Updates/Commits
93
118
  // ---------------
94
119
 
95
- export type CommitBlockData = {
96
- commit: CID
97
- blocks: BlockMap
98
- }
99
-
100
- export type CommitData = CommitBlockData & {
120
+ export type CommitData = {
121
+ cid: CID
122
+ rev: string
123
+ since: string | null
101
124
  prev: CID | null
125
+ newBlocks: BlockMap
126
+ removedCids: CidSet
102
127
  }
103
128
 
104
129
  export type RepoUpdate = CommitData & {
@@ -108,6 +133,12 @@ export type RepoUpdate = CommitData & {
108
133
  export type CollectionContents = Record<string, RepoRecord>
109
134
  export type RepoContents = Record<string, CollectionContents>
110
135
 
136
+ export type RepoRecordWithCid = { cid: CID; value: RepoRecord }
137
+ export type CollectionContentsWithCids = Record<string, RepoRecordWithCid>
138
+ export type RepoContentsWithCids = Record<string, CollectionContentsWithCids>
139
+
140
+ export type DatastoreContents = Record<string, CID>
141
+
111
142
  export type RecordPath = {
112
143
  collection: string
113
144
  rkey: string
@@ -119,22 +150,15 @@ export type RecordClaim = {
119
150
  record: RepoRecord | null
120
151
  }
121
152
 
122
- // DataStores
153
+ // Sync
123
154
  // ---------------
124
155
 
125
- export type DataValue = {
126
- key: string
127
- value: CID
156
+ export type VerifiedDiff = {
157
+ writes: RecordWriteDescript[]
158
+ commit: CommitData
128
159
  }
129
160
 
130
- export interface DataStore {
131
- add(key: string, value: CID): Promise<DataStore>
132
- update(key: string, value: CID): Promise<DataStore>
133
- delete(key: string): Promise<DataStore>
134
- get(key: string): Promise<CID | null>
135
- list(count?: number, after?: string, before?: string): Promise<DataValue[]>
136
- listWithPrefix(prefix: string, count?: number): Promise<DataValue[]>
137
- getUnstoredBlocks(): Promise<{ root: CID; blocks: BlockMap }>
138
- writeToCarStream(car: BlockWriter): Promise<void>
139
- cidsForPath(key: string): Promise<CID[]>
161
+ export type VerifiedRepo = {
162
+ creates: RecordCreateDescript[]
163
+ commit: CommitData
140
164
  }