@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.
- package/bench/mst.bench.ts +7 -4
- package/bench/repo.bench.ts +25 -16
- package/dist/block-map.d.ts +27 -0
- package/dist/data-diff.d.ts +36 -0
- package/dist/error.d.ts +20 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +22870 -12456
- package/dist/index.js.map +4 -4
- package/dist/mst/diff.d.ts +4 -33
- package/dist/mst/mst.d.ts +73 -31
- package/dist/mst/util.d.ts +13 -5
- package/dist/parse.d.ts +16 -0
- package/dist/readable-repo.d.ts +23 -0
- package/dist/repo.d.ts +19 -31
- package/dist/src/block-map.d.ts +23 -0
- package/dist/src/blockstore/persistent-blockstore.d.ts +12 -0
- package/dist/src/cid-set.d.ts +14 -0
- package/dist/src/collection.d.ts +22 -0
- package/dist/src/data-diff.d.ts +34 -0
- package/dist/src/error.d.ts +21 -0
- package/dist/src/index.d.ts +7 -0
- package/dist/src/logger.d.ts +2 -0
- package/dist/src/mst/diff.d.ts +33 -0
- package/dist/src/mst/index.d.ts +4 -0
- package/dist/src/mst/mst.d.ts +106 -0
- package/dist/src/mst/util.d.ts +9 -0
- package/dist/src/mst/walker.d.ts +22 -0
- package/dist/src/parse.d.ts +11 -0
- package/dist/src/readable-repo.d.ts +25 -0
- package/dist/src/repo.d.ts +39 -0
- package/dist/src/storage/error.d.ts +22 -0
- package/dist/src/storage/index.d.ts +1 -0
- package/dist/src/storage/memory-blobstore.d.ts +1 -0
- package/dist/src/storage/memory-blockstore.d.ts +28 -0
- package/dist/src/storage/readable-blockstore.d.ts +21 -0
- package/dist/src/storage/repo-storage.d.ts +18 -0
- package/dist/src/storage/sync-storage.d.ts +15 -0
- package/dist/src/storage/types.d.ts +12 -0
- package/dist/src/storage/util.d.ts +17 -0
- package/dist/src/structure.d.ts +39 -0
- package/dist/src/sync/consumer.d.ts +19 -0
- package/dist/src/sync/index.d.ts +2 -0
- package/dist/src/sync/producer.d.ts +13 -0
- package/dist/src/sync/provider.d.ts +11 -0
- package/dist/src/types.d.ts +368 -0
- package/dist/src/util.d.ts +13 -0
- package/dist/src/verify.d.ts +5 -0
- package/dist/storage/index.d.ts +4 -0
- package/dist/storage/memory-blockstore.d.ts +29 -0
- package/dist/storage/readable-blockstore.d.ts +24 -0
- package/dist/storage/repo-storage.d.ts +19 -0
- package/dist/storage/sync-storage.d.ts +15 -0
- package/dist/storage/types.d.ts +4 -0
- package/dist/sync/consumer.d.ts +19 -0
- package/dist/sync/index.d.ts +2 -0
- package/dist/sync/provider.d.ts +9 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/dist/types.d.ts +137 -331
- package/dist/util.d.ts +35 -12
- package/dist/verify.d.ts +31 -4
- package/jest.bench.config.js +2 -1
- package/package.json +13 -6
- package/src/block-map.ts +103 -0
- package/src/cid-set.ts +1 -2
- package/src/data-diff.ts +117 -0
- package/src/error.ts +31 -0
- package/src/index.ts +4 -1
- package/src/mst/diff.ts +120 -90
- package/src/mst/mst.ts +179 -187
- package/src/mst/util.ts +54 -31
- package/src/parse.ts +44 -0
- package/src/readable-repo.ts +75 -0
- package/src/repo.ts +145 -244
- package/src/storage/index.ts +4 -0
- package/src/storage/memory-blockstore.ts +133 -0
- package/src/storage/readable-blockstore.ts +56 -0
- package/src/storage/repo-storage.ts +43 -0
- package/src/storage/sync-storage.ts +35 -0
- package/src/storage/types.ts +4 -0
- package/src/sync/consumer.ts +140 -0
- package/src/sync/index.ts +2 -0
- package/src/sync/provider.ts +91 -0
- package/src/types.ts +110 -73
- package/src/util.ts +258 -56
- package/src/verify.ts +248 -42
- package/tests/_util.ts +132 -97
- package/tests/mst.test.ts +269 -122
- package/tests/rebase.test.ts +37 -0
- package/tests/repo.test.ts +48 -50
- package/tests/sync/checkout.test.ts +75 -0
- package/tests/sync/diff.test.ts +92 -0
- package/tests/sync/narrow.test.ts +149 -0
- package/tests/util.test.ts +21 -0
- package/tsconfig.build.tsbuildinfo +1 -1
- package/tsconfig.json +2 -1
- package/src/blockstore/index.ts +0 -2
- package/src/blockstore/ipld-store.ts +0 -103
- package/src/blockstore/memory-blockstore.ts +0 -49
- package/src/sync.ts +0 -38
- package/tests/sync.test.ts +0 -129
- /package/dist/{blockstore → src/blockstore}/index.d.ts +0 -0
- /package/dist/{blockstore → src/blockstore}/ipld-store.d.ts +0 -0
- /package/dist/{blockstore → src/blockstore}/memory-blockstore.d.ts +0 -0
- /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
|
|
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 {
|
|
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
|
-
|
|
22
|
-
data:
|
|
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
|
-
|
|
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
|
-
|
|
41
|
-
this.
|
|
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
|
|
50
|
-
|
|
35
|
+
static async formatInitCommit(
|
|
36
|
+
storage: RepoStorage,
|
|
51
37
|
did: string,
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
): Promise<
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
-
|
|
80
|
-
|
|
64
|
+
return {
|
|
65
|
+
commit: commitCid,
|
|
81
66
|
prev: null,
|
|
82
|
-
|
|
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
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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(
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
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
|
-
|
|
103
|
+
storage,
|
|
116
104
|
data,
|
|
117
105
|
commit,
|
|
118
|
-
|
|
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
|
-
|
|
138
|
-
|
|
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
|
|
161
|
-
if (write.action ===
|
|
162
|
-
const cid = await
|
|
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 ===
|
|
166
|
-
const cid = await
|
|
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 ===
|
|
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
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
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
|
-
|
|
203
|
-
await this.blockstore.saveStaged()
|
|
147
|
+
commitBlocks.addMap(fromStorage.blocks)
|
|
204
148
|
}
|
|
205
149
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
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
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
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
|
|
238
|
-
|
|
239
|
-
|
|
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
|
|
244
|
-
|
|
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
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
const
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
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
|
|
260
|
-
|
|
261
|
-
|
|
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
|
|
272
|
-
|
|
273
|
-
|
|
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
|
|