@atproto/repo 0.0.1 → 0.2.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 (104) hide show
  1. package/bench/mst.bench.ts +7 -4
  2. package/bench/repo.bench.ts +25 -16
  3. package/dist/block-map.d.ts +27 -0
  4. package/dist/data-diff.d.ts +36 -0
  5. package/dist/error.d.ts +20 -0
  6. package/dist/index.d.ts +4 -1
  7. package/dist/index.js +22870 -12456
  8. package/dist/index.js.map +4 -4
  9. package/dist/mst/diff.d.ts +4 -33
  10. package/dist/mst/mst.d.ts +73 -31
  11. package/dist/mst/util.d.ts +13 -5
  12. package/dist/parse.d.ts +16 -0
  13. package/dist/readable-repo.d.ts +23 -0
  14. package/dist/repo.d.ts +19 -31
  15. package/dist/src/block-map.d.ts +23 -0
  16. package/dist/src/blockstore/persistent-blockstore.d.ts +12 -0
  17. package/dist/src/cid-set.d.ts +14 -0
  18. package/dist/src/collection.d.ts +22 -0
  19. package/dist/src/data-diff.d.ts +34 -0
  20. package/dist/src/error.d.ts +21 -0
  21. package/dist/src/index.d.ts +7 -0
  22. package/dist/src/logger.d.ts +2 -0
  23. package/dist/src/mst/diff.d.ts +33 -0
  24. package/dist/src/mst/index.d.ts +4 -0
  25. package/dist/src/mst/mst.d.ts +106 -0
  26. package/dist/src/mst/util.d.ts +9 -0
  27. package/dist/src/mst/walker.d.ts +22 -0
  28. package/dist/src/parse.d.ts +11 -0
  29. package/dist/src/readable-repo.d.ts +25 -0
  30. package/dist/src/repo.d.ts +39 -0
  31. package/dist/src/storage/error.d.ts +22 -0
  32. package/dist/src/storage/index.d.ts +1 -0
  33. package/dist/src/storage/memory-blobstore.d.ts +1 -0
  34. package/dist/src/storage/memory-blockstore.d.ts +28 -0
  35. package/dist/src/storage/readable-blockstore.d.ts +21 -0
  36. package/dist/src/storage/repo-storage.d.ts +18 -0
  37. package/dist/src/storage/sync-storage.d.ts +15 -0
  38. package/dist/src/storage/types.d.ts +12 -0
  39. package/dist/src/storage/util.d.ts +17 -0
  40. package/dist/src/structure.d.ts +39 -0
  41. package/dist/src/sync/consumer.d.ts +19 -0
  42. package/dist/src/sync/index.d.ts +2 -0
  43. package/dist/src/sync/producer.d.ts +13 -0
  44. package/dist/src/sync/provider.d.ts +11 -0
  45. package/dist/src/types.d.ts +368 -0
  46. package/dist/src/util.d.ts +13 -0
  47. package/dist/src/verify.d.ts +5 -0
  48. package/dist/storage/index.d.ts +4 -0
  49. package/dist/storage/memory-blockstore.d.ts +29 -0
  50. package/dist/storage/readable-blockstore.d.ts +24 -0
  51. package/dist/storage/repo-storage.d.ts +19 -0
  52. package/dist/storage/sync-storage.d.ts +15 -0
  53. package/dist/storage/types.d.ts +4 -0
  54. package/dist/sync/consumer.d.ts +19 -0
  55. package/dist/sync/index.d.ts +2 -0
  56. package/dist/sync/provider.d.ts +9 -0
  57. package/dist/tsconfig.build.tsbuildinfo +1 -0
  58. package/dist/types.d.ts +137 -331
  59. package/dist/util.d.ts +35 -12
  60. package/dist/verify.d.ts +31 -4
  61. package/jest.bench.config.js +2 -1
  62. package/package.json +13 -6
  63. package/src/block-map.ts +103 -0
  64. package/src/cid-set.ts +1 -2
  65. package/src/data-diff.ts +117 -0
  66. package/src/error.ts +31 -0
  67. package/src/index.ts +4 -1
  68. package/src/mst/diff.ts +120 -90
  69. package/src/mst/mst.ts +179 -187
  70. package/src/mst/util.ts +54 -31
  71. package/src/parse.ts +44 -0
  72. package/src/readable-repo.ts +75 -0
  73. package/src/repo.ts +145 -244
  74. package/src/storage/index.ts +4 -0
  75. package/src/storage/memory-blockstore.ts +133 -0
  76. package/src/storage/readable-blockstore.ts +56 -0
  77. package/src/storage/repo-storage.ts +43 -0
  78. package/src/storage/sync-storage.ts +35 -0
  79. package/src/storage/types.ts +4 -0
  80. package/src/sync/consumer.ts +140 -0
  81. package/src/sync/index.ts +2 -0
  82. package/src/sync/provider.ts +91 -0
  83. package/src/types.ts +110 -73
  84. package/src/util.ts +258 -56
  85. package/src/verify.ts +248 -42
  86. package/tests/_util.ts +132 -97
  87. package/tests/mst.test.ts +269 -122
  88. package/tests/rebase.test.ts +37 -0
  89. package/tests/repo.test.ts +48 -50
  90. package/tests/sync/checkout.test.ts +75 -0
  91. package/tests/sync/diff.test.ts +92 -0
  92. package/tests/sync/narrow.test.ts +149 -0
  93. package/tests/util.test.ts +21 -0
  94. package/tsconfig.build.tsbuildinfo +1 -1
  95. package/tsconfig.json +2 -1
  96. package/src/blockstore/index.ts +0 -2
  97. package/src/blockstore/ipld-store.ts +0 -103
  98. package/src/blockstore/memory-blockstore.ts +0 -49
  99. package/src/sync.ts +0 -38
  100. package/tests/sync.test.ts +0 -129
  101. /package/dist/{blockstore → src/blockstore}/index.d.ts +0 -0
  102. /package/dist/{blockstore → src/blockstore}/ipld-store.d.ts +0 -0
  103. /package/dist/{blockstore → src/blockstore}/memory-blockstore.d.ts +0 -0
  104. /package/dist/{sync.d.ts → src/sync.d.ts} +0 -0
package/src/parse.ts ADDED
@@ -0,0 +1,44 @@
1
+ import { check, cborDecode } from '@atproto/common'
2
+ import { RepoRecord } from '@atproto/lexicon'
3
+ import { CID } from 'multiformats/cid'
4
+ import BlockMap from './block-map'
5
+ import { MissingBlockError, UnexpectedObjectError } from './error'
6
+ import { cborToLexRecord } from './util'
7
+
8
+ export const getAndParseRecord = async (
9
+ blocks: BlockMap,
10
+ cid: CID,
11
+ ): Promise<{ record: RepoRecord; bytes: Uint8Array }> => {
12
+ const bytes = blocks.get(cid)
13
+ if (!bytes) {
14
+ throw new MissingBlockError(cid, 'record')
15
+ }
16
+ const record = await cborToLexRecord(bytes)
17
+ return { record, bytes }
18
+ }
19
+
20
+ export const getAndParseByDef = async <T>(
21
+ blocks: BlockMap,
22
+ cid: CID,
23
+ def: check.Def<T>,
24
+ ): Promise<{ obj: T; bytes: Uint8Array }> => {
25
+ const bytes = blocks.get(cid)
26
+ if (!bytes) {
27
+ throw new MissingBlockError(cid, def.name)
28
+ }
29
+ return parseObjByDef(bytes, cid, def)
30
+ }
31
+
32
+ export const parseObjByDef = <T>(
33
+ bytes: Uint8Array,
34
+ cid: CID,
35
+ def: check.Def<T>,
36
+ ): { obj: T; bytes: Uint8Array } => {
37
+ const obj = cborDecode(bytes)
38
+ const res = def.schema.safeParse(obj)
39
+ if (res.success) {
40
+ return { obj: res.data, bytes }
41
+ } else {
42
+ throw new UnexpectedObjectError(cid, def.name)
43
+ }
44
+ }
@@ -0,0 +1,75 @@
1
+ import { CID } from 'multiformats/cid'
2
+ import { Commit, def, RepoContents } from './types'
3
+ import { ReadableBlockstore } from './storage'
4
+ import { MST } from './mst'
5
+ import log from './logger'
6
+ import * as util from './util'
7
+ import * as parse from './parse'
8
+ import { MissingBlocksError } from './error'
9
+
10
+ type Params = {
11
+ storage: ReadableBlockstore
12
+ data: MST
13
+ commit: Commit
14
+ cid: CID
15
+ }
16
+
17
+ export class ReadableRepo {
18
+ storage: ReadableBlockstore
19
+ data: MST
20
+ commit: Commit
21
+ cid: CID
22
+
23
+ constructor(params: Params) {
24
+ this.storage = params.storage
25
+ this.data = params.data
26
+ this.commit = params.commit
27
+ this.cid = params.cid
28
+ }
29
+
30
+ static async load(storage: ReadableBlockstore, commitCid: CID) {
31
+ const commit = await storage.readObj(commitCid, def.commit)
32
+ const data = await MST.load(storage, commit.data)
33
+ log.info({ did: commit.did }, 'loaded repo for')
34
+ return new ReadableRepo({
35
+ storage,
36
+ data,
37
+ commit,
38
+ cid: commitCid,
39
+ })
40
+ }
41
+
42
+ get did(): string {
43
+ return this.commit.did
44
+ }
45
+
46
+ get version(): number {
47
+ return this.commit.version
48
+ }
49
+
50
+ async getRecord(collection: string, rkey: string): Promise<unknown | null> {
51
+ const dataKey = collection + '/' + rkey
52
+ const cid = await this.data.get(dataKey)
53
+ if (!cid) return null
54
+ return this.storage.readObj(cid, def.unknown)
55
+ }
56
+
57
+ async getContents(): Promise<RepoContents> {
58
+ const entries = await this.data.list()
59
+ const cids = entries.map((e) => e.value)
60
+ const { blocks, missing } = await this.storage.getBlocks(cids)
61
+ if (missing.length > 0) {
62
+ throw new MissingBlocksError('getContents record', missing)
63
+ }
64
+ const contents: RepoContents = {}
65
+ for (const entry of entries) {
66
+ const { collection, rkey } = util.parseDataKey(entry.key)
67
+ contents[collection] ??= {}
68
+ const parsed = await parse.getAndParseRecord(blocks, entry.value)
69
+ contents[collection][rkey] = parsed.record
70
+ }
71
+ return contents
72
+ }
73
+ }
74
+
75
+ export default ReadableRepo
package/src/repo.ts CHANGED
@@ -1,311 +1,212 @@
1
1
  import { CID } from 'multiformats/cid'
2
- import { CarWriter } from '@ipld/car'
3
- import { BlockWriter } from '@ipld/car/writer'
2
+ import * as crypto from '@atproto/crypto'
4
3
  import {
5
- RepoRoot,
6
4
  Commit,
7
5
  def,
8
- DataStore,
9
- RepoMeta,
10
6
  RecordCreateOp,
11
7
  RecordWriteOp,
8
+ CommitData,
9
+ WriteOpAction,
10
+ RebaseData,
12
11
  } from './types'
13
- import { streamToArray } from '@atproto/common'
14
- import IpldStore from './blockstore/ipld-store'
15
- import * as auth from '@atproto/auth'
12
+ import { RepoStorage } from './storage'
16
13
  import { MST } from './mst'
14
+ import DataDiff from './data-diff'
17
15
  import log from './logger'
16
+ import BlockMap from './block-map'
17
+ import { ReadableRepo } from './readable-repo'
18
18
  import * as util from './util'
19
19
 
20
20
  type Params = {
21
- blockstore: IpldStore
22
- data: DataStore
21
+ storage: RepoStorage
22
+ data: MST
23
23
  commit: Commit
24
- root: RepoRoot
25
- meta: RepoMeta
26
24
  cid: CID
27
- stagedWrites: RecordWriteOp[]
28
25
  }
29
26
 
30
- export class Repo {
31
- blockstore: IpldStore
32
- data: DataStore
33
- commit: Commit
34
- root: RepoRoot
35
- meta: RepoMeta
36
- cid: CID
37
- stagedWrites: RecordWriteOp[]
27
+ export class Repo extends ReadableRepo {
28
+ storage: RepoStorage
38
29
 
39
30
  constructor(params: Params) {
40
- this.blockstore = params.blockstore
41
- this.data = params.data
42
- this.commit = params.commit
43
- this.root = params.root
44
- this.meta = params.meta
45
- this.cid = params.cid
46
- this.stagedWrites = params.stagedWrites
31
+ super(params)
32
+ this.storage = params.storage
47
33
  }
48
34
 
49
- static async create(
50
- blockstore: IpldStore,
35
+ static async formatInitCommit(
36
+ storage: RepoStorage,
51
37
  did: string,
52
- authStore: auth.AuthStore,
53
- initialRecords: RecordCreateOp[] = [],
54
- ): Promise<Repo> {
55
- let tokenCid: CID | null = null
56
- if (!(await authStore.canSignForDid(did))) {
57
- const foundUcan = await authStore.findUcan(auth.maintenanceCap(did))
58
- if (foundUcan === null) {
59
- throw new Error(`No valid Ucan for creating repo`)
60
- }
61
- tokenCid = await blockstore.stage(auth.encodeUcan(foundUcan))
62
- }
63
-
64
- let data = await MST.create(blockstore)
65
- for (const write of initialRecords) {
66
- const cid = await blockstore.stage(write.value)
67
- const dataKey = write.collection + '/' + write.rkey
38
+ keypair: crypto.Keypair,
39
+ initialWrites: RecordCreateOp[] = [],
40
+ ): Promise<CommitData> {
41
+ const newBlocks = new BlockMap()
42
+
43
+ let data = await MST.create(storage)
44
+ for (const record of initialWrites) {
45
+ const cid = await newBlocks.add(record.record)
46
+ const dataKey = util.formatDataKey(record.collection, record.rkey)
68
47
  data = await data.add(dataKey, cid)
69
48
  }
70
- const dataCid = await data.stage()
71
49
 
72
- const meta: RepoMeta = {
73
- did,
74
- version: 1,
75
- datastore: 'mst',
76
- }
77
- const metaCid = await blockstore.stage(meta)
50
+ const unstoredData = await data.getUnstoredBlocks()
51
+ newBlocks.addMap(unstoredData.blocks)
52
+
53
+ const commit = await util.signCommit(
54
+ {
55
+ did,
56
+ version: 2,
57
+ prev: null,
58
+ data: unstoredData.root,
59
+ },
60
+ keypair,
61
+ )
62
+ const commitCid = await newBlocks.add(commit)
78
63
 
79
- const root: RepoRoot = {
80
- meta: metaCid,
64
+ return {
65
+ commit: commitCid,
81
66
  prev: null,
82
- auth_token: tokenCid,
83
- data: dataCid,
84
- }
85
-
86
- const rootCid = await blockstore.stage(root)
87
- const commit: Commit = {
88
- root: rootCid,
89
- sig: await authStore.sign(rootCid.bytes),
67
+ blocks: newBlocks,
90
68
  }
69
+ }
91
70
 
92
- const cid = await blockstore.stage(commit)
93
-
94
- await blockstore.saveStaged()
71
+ static async createFromCommit(
72
+ storage: RepoStorage,
73
+ commit: CommitData,
74
+ ): Promise<Repo> {
75
+ await storage.applyCommit(commit)
76
+ return Repo.load(storage, commit.commit)
77
+ }
95
78
 
96
- log.info({ did }, `created repo`)
97
- return new Repo({
98
- blockstore,
99
- data,
100
- commit,
101
- root,
102
- meta,
103
- cid,
104
- stagedWrites: [],
105
- })
79
+ static async create(
80
+ storage: RepoStorage,
81
+ did: string,
82
+ keypair: crypto.Keypair,
83
+ initialWrites: RecordCreateOp[] = [],
84
+ ): Promise<Repo> {
85
+ const commit = await Repo.formatInitCommit(
86
+ storage,
87
+ did,
88
+ keypair,
89
+ initialWrites,
90
+ )
91
+ return Repo.createFromCommit(storage, commit)
106
92
  }
107
93
 
108
- static async load(blockstore: IpldStore, cid: CID) {
109
- const commit = await blockstore.get(cid, def.commit)
110
- const root = await blockstore.get(commit.root, def.repoRoot)
111
- const meta = await blockstore.get(root.meta, def.repoMeta)
112
- const data = await MST.load(blockstore, root.data)
113
- log.info({ did: meta.did }, 'loaded repo for')
94
+ static async load(storage: RepoStorage, cid?: CID) {
95
+ const commitCid = cid || (await storage.getHead())
96
+ if (!commitCid) {
97
+ throw new Error('No cid provided and none in storage')
98
+ }
99
+ const commit = await storage.readObj(commitCid, def.commit)
100
+ const data = await MST.load(storage, commit.data)
101
+ log.info({ did: commit.did }, 'loaded repo for')
114
102
  return new Repo({
115
- blockstore,
103
+ storage,
116
104
  data,
117
105
  commit,
118
- root,
119
- meta,
120
- cid,
121
- stagedWrites: [],
122
- })
123
- }
124
-
125
- private updateRepo(params: Partial<Params>): Repo {
126
- return new Repo({
127
- blockstore: params.blockstore || this.blockstore,
128
- data: params.data || this.data,
129
- commit: params.commit || this.commit,
130
- root: params.root || this.root,
131
- meta: params.meta || this.meta,
132
- cid: params.cid || this.cid,
133
- stagedWrites: params.stagedWrites || this.stagedWrites,
106
+ cid: commitCid,
134
107
  })
135
108
  }
136
109
 
137
- get did(): string {
138
- return this.meta.did
139
- }
110
+ async formatCommit(
111
+ toWrite: RecordWriteOp | RecordWriteOp[],
112
+ keypair: crypto.Keypair,
113
+ ): Promise<CommitData> {
114
+ const writes = Array.isArray(toWrite) ? toWrite : [toWrite]
115
+ const commitBlocks = new BlockMap()
140
116
 
141
- async getRecord(collection: string, rkey: string): Promise<unknown | null> {
142
- const dataKey = collection + '/' + rkey
143
- const cid = await this.data.get(dataKey)
144
- if (!cid) return null
145
- return this.blockstore.getUnchecked(cid)
146
- }
147
-
148
- stageUpdate(write: RecordWriteOp | RecordWriteOp[]): Repo {
149
- const writeArr = Array.isArray(write) ? write : [write]
150
- return this.updateRepo({
151
- stagedWrites: [...this.stagedWrites, ...writeArr],
152
- })
153
- }
154
-
155
- async createCommit(
156
- authStore: auth.AuthStore,
157
- performUpdate?: (prev: CID, curr: CID) => Promise<CID | null>,
158
- ): Promise<Repo> {
159
117
  let data = this.data
160
- for (const write of this.stagedWrites) {
161
- if (write.action === 'create') {
162
- const cid = await this.blockstore.stage(write.value)
118
+ for (const write of writes) {
119
+ if (write.action === WriteOpAction.Create) {
120
+ const cid = await commitBlocks.add(write.record)
163
121
  const dataKey = write.collection + '/' + write.rkey
164
122
  data = await data.add(dataKey, cid)
165
- } else if (write.action === 'update') {
166
- const cid = await this.blockstore.stage(write.value)
123
+ } else if (write.action === WriteOpAction.Update) {
124
+ const cid = await commitBlocks.add(write.record)
167
125
  const dataKey = write.collection + '/' + write.rkey
168
126
  data = await data.update(dataKey, cid)
169
- } else if (write.action === 'delete') {
127
+ } else if (write.action === WriteOpAction.Delete) {
170
128
  const dataKey = write.collection + '/' + write.rkey
171
129
  data = await data.delete(dataKey)
172
130
  }
173
131
  }
174
- const token = (await authStore.canSignForDid(this.did))
175
- ? null
176
- : await util.ucanForOperation(this.data, data, this.did, authStore)
177
- const tokenCid = token ? await this.blockstore.stage(token) : null
178
-
179
- const dataCid = await data.stage()
180
- const root: RepoRoot = {
181
- meta: this.root.meta,
182
- prev: this.cid,
183
- auth_token: tokenCid,
184
- data: dataCid,
185
- }
186
- const rootCid = await this.blockstore.stage(root)
187
- const commit: Commit = {
188
- root: rootCid,
189
- sig: await authStore.sign(rootCid.bytes),
190
- }
191
- const commitCid = await this.blockstore.stage(commit)
192
132
 
193
- if (performUpdate) {
194
- const rebaseOn = await performUpdate(this.cid, commitCid)
195
- if (rebaseOn) {
196
- await this.blockstore.clearStaged()
197
- const rebaseRepo = await Repo.load(this.blockstore, rebaseOn)
198
- return rebaseRepo.createCommit(authStore, performUpdate)
199
- } else {
200
- await this.blockstore.saveStaged()
133
+ const unstoredData = await data.getUnstoredBlocks()
134
+ commitBlocks.addMap(unstoredData.blocks)
135
+
136
+ // ensure we're not missing any blocks that were removed and then readded in this commit
137
+ const diff = await DataDiff.of(data, this.data)
138
+ const found = commitBlocks.getMany(diff.newCidList())
139
+ if (found.missing.length > 0) {
140
+ const fromStorage = await this.storage.getBlocks(found.missing)
141
+ if (fromStorage.missing.length > 0) {
142
+ // this shouldn't ever happen
143
+ throw new Error(
144
+ 'Could not find block for commit in Datastore or storage',
145
+ )
201
146
  }
202
- } else {
203
- await this.blockstore.saveStaged()
147
+ commitBlocks.addMap(fromStorage.blocks)
204
148
  }
205
149
 
206
- return this.updateRepo({
207
- cid: commitCid,
208
- root,
209
- commit,
210
- data,
211
- stagedWrites: [],
212
- })
213
- }
150
+ const commit = await util.signCommit(
151
+ {
152
+ did: this.did,
153
+ version: 2,
154
+ prev: this.cid,
155
+ data: unstoredData.root,
156
+ },
157
+ keypair,
158
+ )
159
+ const commitCid = await commitBlocks.add(commit)
214
160
 
215
- async revert(count: number): Promise<Repo> {
216
- let revertTo = this.cid
217
- for (let i = 0; i < count; i++) {
218
- const commit = await this.blockstore.get(revertTo, def.commit)
219
- const root = await this.blockstore.get(commit.root, def.repoRoot)
220
- if (root.prev === null) {
221
- throw new Error(`Could not revert ${count} commits`)
222
- }
223
- revertTo = root.prev
161
+ return {
162
+ commit: commitCid,
163
+ prev: this.cid,
164
+ blocks: commitBlocks,
224
165
  }
225
- return Repo.load(this.blockstore, revertTo)
226
- }
227
-
228
- // CAR FILES
229
- // -----------
230
-
231
- async getCarNoHistory(): Promise<Uint8Array> {
232
- return this.openCar((car: BlockWriter) => {
233
- return this.writeCheckoutToCarStream(car)
234
- })
235
166
  }
236
167
 
237
- async getDiffCar(to: CID | null): Promise<Uint8Array> {
238
- return this.openCar((car: BlockWriter) => {
239
- return this.writeCommitsToCarStream(car, to, this.cid)
240
- })
168
+ async applyCommit(commitData: CommitData): Promise<Repo> {
169
+ await this.storage.applyCommit(commitData)
170
+ return Repo.load(this.storage, commitData.commit)
241
171
  }
242
172
 
243
- async getFullHistory(): Promise<Uint8Array> {
244
- return this.getDiffCar(null)
173
+ async applyWrites(
174
+ toWrite: RecordWriteOp | RecordWriteOp[],
175
+ keypair: crypto.Keypair,
176
+ ): Promise<Repo> {
177
+ const commit = await this.formatCommit(toWrite, keypair)
178
+ return this.applyCommit(commit)
245
179
  }
246
180
 
247
- private async openCar(
248
- fn: (car: BlockWriter) => Promise<void>,
249
- ): Promise<Uint8Array> {
250
- const { writer, out } = CarWriter.create([this.cid])
251
- try {
252
- await fn(writer)
253
- } finally {
254
- writer.close()
181
+ async formatRebase(keypair: crypto.Keypair): Promise<RebaseData> {
182
+ const preservedCids = await this.data.allCids()
183
+ const blocks = new BlockMap()
184
+ const commit = await util.signCommit(
185
+ {
186
+ did: this.did,
187
+ version: 2,
188
+ prev: null,
189
+ data: this.commit.data,
190
+ },
191
+ keypair,
192
+ )
193
+ const commitCid = await blocks.add(commit)
194
+ return {
195
+ commit: commitCid,
196
+ rebased: this.cid,
197
+ blocks,
198
+ preservedCids: preservedCids.toList(),
255
199
  }
256
- return streamToArray(out)
257
200
  }
258
201
 
259
- async writeCheckoutToCarStream(car: BlockWriter): Promise<void> {
260
- const commit = await this.blockstore.get(this.cid, def.commit)
261
- const root = await this.blockstore.get(commit.root, def.repoRoot)
262
- await this.blockstore.addToCar(car, this.cid)
263
- await this.blockstore.addToCar(car, commit.root)
264
- await this.blockstore.addToCar(car, root.meta)
265
- if (root.auth_token) {
266
- await this.blockstore.addToCar(car, root.auth_token)
267
- }
268
- await this.data.writeToCarStream(car)
202
+ async applyRebase(rebase: RebaseData): Promise<Repo> {
203
+ await this.storage.applyRebase(rebase)
204
+ return Repo.load(this.storage, rebase.commit)
269
205
  }
270
206
 
271
- async writeCommitsToCarStream(
272
- car: BlockWriter,
273
- oldestCommit: CID | null,
274
- recentCommit: CID,
275
- ): Promise<void> {
276
- const commitPath = await util.getCommitPath(
277
- this.blockstore,
278
- oldestCommit,
279
- recentCommit,
280
- )
281
- if (commitPath === null) {
282
- throw new Error('Could not find shared history')
283
- }
284
- if (commitPath.length === 0) return
285
- const firstHeadInPath = await Repo.load(this.blockstore, commitPath[0])
286
- // handle the first commit
287
- let prevHead: Repo | null =
288
- firstHeadInPath.root.prev !== null
289
- ? await Repo.load(this.blockstore, firstHeadInPath.root.prev)
290
- : null
291
- for (const commit of commitPath) {
292
- const nextHead = await Repo.load(this.blockstore, commit)
293
- await this.blockstore.addToCar(car, nextHead.cid)
294
- await this.blockstore.addToCar(car, nextHead.commit.root)
295
- await this.blockstore.addToCar(car, nextHead.root.meta)
296
- if (nextHead.root.auth_token) {
297
- await this.blockstore.addToCar(car, nextHead.root.auth_token)
298
- }
299
- if (prevHead === null) {
300
- await nextHead.data.writeToCarStream(car)
301
- } else {
302
- const diff = await prevHead.data.diff(nextHead.data)
303
- await Promise.all(
304
- diff.newCidList().map((cid) => this.blockstore.addToCar(car, cid)),
305
- )
306
- }
307
- prevHead = nextHead
308
- }
207
+ async rebase(keypair: crypto.Keypair): Promise<Repo> {
208
+ const rebaseData = await this.formatRebase(keypair)
209
+ return this.applyRebase(rebaseData)
309
210
  }
310
211
  }
311
212
 
@@ -1 +1,5 @@
1
+ export * from './readable-blockstore'
2
+ export * from './repo-storage'
3
+ export * from './memory-blockstore'
4
+ export * from './sync-storage'
1
5
  export * from './types'