@atcute/car 3.0.5 → 3.1.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/README.md +78 -7
- package/dist/v3/atproto-repo.d.ts +1 -0
- package/dist/v3/atproto-repo.js +2 -0
- package/dist/v3/atproto-repo.js.map +1 -0
- package/dist/v3/index.js.map +1 -0
- package/dist/v3/reader.d.ts +1 -0
- package/dist/v3/reader.js +2 -0
- package/dist/v3/reader.js.map +1 -0
- package/dist/v4/car-reader/index.d.ts +3 -0
- package/dist/v4/car-reader/index.js +4 -0
- package/dist/v4/car-reader/index.js.map +1 -0
- package/dist/v4/car-reader/stream-car-reader.d.ts +11 -0
- package/dist/v4/car-reader/stream-car-reader.js +178 -0
- package/dist/v4/car-reader/stream-car-reader.js.map +1 -0
- package/dist/v4/car-reader/sync-car-reader.d.ts +10 -0
- package/dist/{utilities → v4/car-reader}/sync-car-reader.js +63 -31
- package/dist/v4/car-reader/sync-car-reader.js.map +1 -0
- package/dist/{utilities/car.js → v4/car-reader/types.js} +1 -1
- package/dist/v4/car-reader/types.js.map +1 -0
- package/dist/v4/index.d.ts +2 -0
- package/dist/v4/index.js +3 -0
- package/dist/v4/index.js.map +1 -0
- package/dist/v4/repo-reader/index.d.ts +5 -0
- package/dist/v4/repo-reader/index.js +6 -0
- package/dist/v4/repo-reader/index.js.map +1 -0
- package/dist/v4/repo-reader/mst.d.ts +47 -0
- package/dist/v4/repo-reader/mst.js +62 -0
- package/dist/v4/repo-reader/mst.js.map +1 -0
- package/dist/v4/repo-reader/stream-repo-reader.d.ts +24 -0
- package/dist/v4/repo-reader/stream-repo-reader.js +143 -0
- package/dist/v4/repo-reader/stream-repo-reader.js.map +1 -0
- package/dist/v4/repo-reader/sync-blockmap.d.ts +29 -0
- package/dist/v4/repo-reader/sync-blockmap.js +58 -0
- package/dist/v4/repo-reader/sync-blockmap.js.map +1 -0
- package/dist/v4/repo-reader/sync-repo-reader.d.ts +2 -0
- package/dist/v4/repo-reader/sync-repo-reader.js +20 -0
- package/dist/v4/repo-reader/sync-repo-reader.js.map +1 -0
- package/dist/v4/repo-reader/types.d.ts +20 -0
- package/dist/v4/repo-reader/types.js +37 -0
- package/dist/v4/repo-reader/types.js.map +1 -0
- package/dist/v4/utils.d.ts +3 -0
- package/dist/v4/utils.js +6 -0
- package/dist/v4/utils.js.map +1 -0
- package/lib/v3/atproto-repo.ts +15 -0
- package/lib/v3/reader.ts +9 -0
- package/lib/v4/car-reader/index.ts +4 -0
- package/lib/v4/car-reader/stream-car-reader.ts +240 -0
- package/lib/{utilities → v4/car-reader}/sync-car-reader.ts +90 -40
- package/lib/v4/index.ts +2 -0
- package/lib/v4/repo-reader/index.ts +6 -0
- package/lib/v4/repo-reader/mst.ts +110 -0
- package/lib/v4/repo-reader/stream-repo-reader.ts +209 -0
- package/lib/v4/repo-reader/sync-blockmap.ts +85 -0
- package/lib/v4/repo-reader/sync-repo-reader.ts +27 -0
- package/lib/v4/repo-reader/types.ts +32 -0
- package/lib/v4/utils.ts +7 -0
- package/package.json +7 -2
- package/dist/atproto-repo.d.ts +0 -104
- package/dist/atproto-repo.js +0 -171
- package/dist/atproto-repo.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/reader.d.ts +0 -4
- package/dist/reader.js +0 -7
- package/dist/reader.js.map +0 -1
- package/dist/utilities/car.js.map +0 -1
- package/dist/utilities/sync-byte-reader.d.ts +0 -7
- package/dist/utilities/sync-byte-reader.js +0 -28
- package/dist/utilities/sync-byte-reader.js.map +0 -1
- package/dist/utilities/sync-car-reader.d.ts +0 -7
- package/dist/utilities/sync-car-reader.js.map +0 -1
- package/lib/atproto-repo.ts +0 -248
- package/lib/reader.ts +0 -10
- package/lib/utilities/sync-byte-reader.ts +0 -39
- /package/dist/{index.d.ts → v3/index.d.ts} +0 -0
- /package/dist/{index.js → v3/index.js} +0 -0
- /package/dist/{utilities/car.d.ts → v4/car-reader/types.d.ts} +0 -0
- /package/lib/{index.ts → v3/index.ts} +0 -0
- /package/lib/{utilities/car.ts → v4/car-reader/types.ts} +0 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import Queue from 'yocto-queue';
|
|
2
|
+
import * as CBOR from '@atcute/cbor';
|
|
3
|
+
import * as CID from '@atcute/cid';
|
|
4
|
+
import { decodeUtf8From } from '@atcute/uint8array';
|
|
5
|
+
import * as CarReader from '../car-reader/index.js';
|
|
6
|
+
import { assert } from '../utils.js';
|
|
7
|
+
import { isCommit, isMstNode } from './mst.js';
|
|
8
|
+
import { RepoEntry } from './types.js';
|
|
9
|
+
export const repoEntryTransform = () => {
|
|
10
|
+
const transform = new TransformStream();
|
|
11
|
+
let repo;
|
|
12
|
+
return {
|
|
13
|
+
readable: new ReadableStream({
|
|
14
|
+
async start(controller) {
|
|
15
|
+
repo = fromStream(transform.readable);
|
|
16
|
+
try {
|
|
17
|
+
for await (const entry of repo) {
|
|
18
|
+
controller.enqueue(entry);
|
|
19
|
+
}
|
|
20
|
+
await repo.dispose();
|
|
21
|
+
controller.close();
|
|
22
|
+
}
|
|
23
|
+
catch (err) {
|
|
24
|
+
controller.error(err);
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
async cancel() {
|
|
28
|
+
if (repo !== undefined) {
|
|
29
|
+
await repo.dispose();
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
}),
|
|
33
|
+
writable: transform.writable,
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
export const fromStream = (stream) => {
|
|
37
|
+
let missingBlocks = [];
|
|
38
|
+
return {
|
|
39
|
+
get missingBlocks() {
|
|
40
|
+
return missingBlocks;
|
|
41
|
+
},
|
|
42
|
+
async dispose() {
|
|
43
|
+
// does nothing for now
|
|
44
|
+
},
|
|
45
|
+
[Symbol.asyncDispose]() {
|
|
46
|
+
return this.dispose();
|
|
47
|
+
},
|
|
48
|
+
async *[Symbol.asyncIterator]() {
|
|
49
|
+
// await using car = CarReader.fromStream(stream);
|
|
50
|
+
const car = CarReader.fromStream(stream);
|
|
51
|
+
try {
|
|
52
|
+
const pending = new Map();
|
|
53
|
+
const strays = new Map();
|
|
54
|
+
const queue = new Queue();
|
|
55
|
+
const request = (cid, meta) => {
|
|
56
|
+
const entry = strays.get(cid);
|
|
57
|
+
if (entry !== undefined) {
|
|
58
|
+
strays.delete(cid);
|
|
59
|
+
queue.enqueue({ c: cid, e: entry, m: meta });
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
pending.set(cid, meta);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
{
|
|
66
|
+
const roots = await car.roots();
|
|
67
|
+
assert(roots.length === 1, `expected only 1 root in the car archive; got=${roots.length}`);
|
|
68
|
+
const rootCid = roots[0].$link;
|
|
69
|
+
request(rootCid, { t: 0 });
|
|
70
|
+
}
|
|
71
|
+
for await (const entry of car) {
|
|
72
|
+
const cid = CID.toString(entry.cid);
|
|
73
|
+
{
|
|
74
|
+
const meta = pending.get(cid);
|
|
75
|
+
if (meta !== undefined) {
|
|
76
|
+
pending.delete(cid);
|
|
77
|
+
queue.enqueue({ c: cid, e: entry, m: meta });
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
strays.set(cid, entry);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
let task;
|
|
84
|
+
while ((task = queue.dequeue())) {
|
|
85
|
+
const { c: cid, e: entry, m: meta } = task;
|
|
86
|
+
switch (meta.t) {
|
|
87
|
+
case 0: {
|
|
88
|
+
const commit = CBOR.decode(entry.bytes);
|
|
89
|
+
assert(isCommit(commit), `expected commit block; cid=${cid}`);
|
|
90
|
+
request(commit.data.$link, { t: 1 });
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
case 1: {
|
|
94
|
+
const node = CBOR.decode(entry.bytes);
|
|
95
|
+
assert(isMstNode(node), `expected mst node block; cid=${cid}`);
|
|
96
|
+
const entries = node.e;
|
|
97
|
+
const left = node.l;
|
|
98
|
+
let lastKey = '';
|
|
99
|
+
if (left !== null) {
|
|
100
|
+
request(left.$link, meta);
|
|
101
|
+
}
|
|
102
|
+
for (let i = 0, il = entries.length; i < il; i++) {
|
|
103
|
+
const entry = entries[i];
|
|
104
|
+
const next = entry.t;
|
|
105
|
+
const key_str = decodeUtf8From(CBOR.fromBytes(entry.k));
|
|
106
|
+
const key = lastKey.slice(0, entry.p) + key_str;
|
|
107
|
+
lastKey = key;
|
|
108
|
+
request(entry.v.$link, { t: 2, k: key });
|
|
109
|
+
if (next !== null) {
|
|
110
|
+
request(next.$link, { t: 1 });
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
case 2: {
|
|
116
|
+
const [collection, rkey] = meta.k.split('/');
|
|
117
|
+
yield new RepoEntry(collection, rkey, CID.toCidLink(entry.cid), entry);
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
missingBlocks = Array.from(pending, ([cid, meta]) => {
|
|
124
|
+
switch (meta.t) {
|
|
125
|
+
case 0: {
|
|
126
|
+
return { cid, type: 'commit' };
|
|
127
|
+
}
|
|
128
|
+
case 1: {
|
|
129
|
+
return { cid, type: 'mst-node' };
|
|
130
|
+
}
|
|
131
|
+
case 2: {
|
|
132
|
+
return { cid, type: 'record', key: meta.k };
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
finally {
|
|
138
|
+
await car.dispose();
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
};
|
|
143
|
+
//# sourceMappingURL=stream-repo-reader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream-repo-reader.js","sourceRoot":"","sources":["../../../lib/v4/repo-reader/stream-repo-reader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as CID from '@atcute/cid';
|
|
2
|
+
import * as CarReader from '../car-reader/index.js';
|
|
3
|
+
export type BlockMap = Map<string, CarReader.CarEntry>;
|
|
4
|
+
/**
|
|
5
|
+
* collects entries from a CAR archive into a mapping of CID string -> actual bytes
|
|
6
|
+
* @param iterator a generator that yields objects with a `cid` and `bytes` property
|
|
7
|
+
* @returns a mapping of CID string -> actual bytes
|
|
8
|
+
*/
|
|
9
|
+
export declare const collectBlock: (iterator: Iterable<CarReader.CarEntry>) => BlockMap;
|
|
10
|
+
/**
|
|
11
|
+
* reads a block from the blockmap and validates it against the provided validation function
|
|
12
|
+
* @param map a mapping of CID string -> actual bytes
|
|
13
|
+
* @param link a CID link to read
|
|
14
|
+
* @param validate a validation function to validate the decoded data
|
|
15
|
+
* @returns the decoded and validated data
|
|
16
|
+
*/
|
|
17
|
+
export declare const readBlock: <T>(map: BlockMap, link: CID.CidLink, validate: (value: unknown) => value is T) => T;
|
|
18
|
+
/** node entry object */
|
|
19
|
+
export interface NodeEntry {
|
|
20
|
+
key: string;
|
|
21
|
+
cid: CID.CidLink;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* walks the entries of a Merkle Sorted Tree (MST) in a depth-first manner
|
|
25
|
+
* @param map a mapping of CID string -> actual bytes
|
|
26
|
+
* @param pointer a CID link to the root of the MST
|
|
27
|
+
* @returns a generator that yields the entries of the MST
|
|
28
|
+
*/
|
|
29
|
+
export declare function walkMstEntries(map: BlockMap, pointer: CID.CidLink): Generator<NodeEntry>;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import * as CBOR from '@atcute/cbor';
|
|
2
|
+
import * as CID from '@atcute/cid';
|
|
3
|
+
import { decodeUtf8From } from '@atcute/uint8array';
|
|
4
|
+
import * as CarReader from '../car-reader/index.js';
|
|
5
|
+
import { assert } from '../utils.js';
|
|
6
|
+
import { isMstNode } from './mst.js';
|
|
7
|
+
/**
|
|
8
|
+
* collects entries from a CAR archive into a mapping of CID string -> actual bytes
|
|
9
|
+
* @param iterator a generator that yields objects with a `cid` and `bytes` property
|
|
10
|
+
* @returns a mapping of CID string -> actual bytes
|
|
11
|
+
*/
|
|
12
|
+
export const collectBlock = (iterator) => {
|
|
13
|
+
const blockmap = new Map();
|
|
14
|
+
for (const entry of iterator) {
|
|
15
|
+
blockmap.set(CID.toString(entry.cid), entry);
|
|
16
|
+
}
|
|
17
|
+
return blockmap;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* reads a block from the blockmap and validates it against the provided validation function
|
|
21
|
+
* @param map a mapping of CID string -> actual bytes
|
|
22
|
+
* @param link a CID link to read
|
|
23
|
+
* @param validate a validation function to validate the decoded data
|
|
24
|
+
* @returns the decoded and validated data
|
|
25
|
+
*/
|
|
26
|
+
export const readBlock = (map, link, validate) => {
|
|
27
|
+
const cid = link.$link;
|
|
28
|
+
const entry = map.get(cid);
|
|
29
|
+
assert(entry != null, `cid not found in blockmap; cid=${cid}`);
|
|
30
|
+
const data = CBOR.decode(entry.bytes);
|
|
31
|
+
assert(validate(data), `validation failed for cid=${cid}`);
|
|
32
|
+
return data;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* walks the entries of a Merkle Sorted Tree (MST) in a depth-first manner
|
|
36
|
+
* @param map a mapping of CID string -> actual bytes
|
|
37
|
+
* @param pointer a CID link to the root of the MST
|
|
38
|
+
* @returns a generator that yields the entries of the MST
|
|
39
|
+
*/
|
|
40
|
+
export function* walkMstEntries(map, pointer) {
|
|
41
|
+
const data = readBlock(map, pointer, isMstNode);
|
|
42
|
+
const entries = data.e;
|
|
43
|
+
let lastKey = '';
|
|
44
|
+
if (data.l !== null) {
|
|
45
|
+
yield* walkMstEntries(map, data.l);
|
|
46
|
+
}
|
|
47
|
+
for (let i = 0, il = entries.length; i < il; i++) {
|
|
48
|
+
const entry = entries[i];
|
|
49
|
+
const key_str = decodeUtf8From(CBOR.fromBytes(entry.k));
|
|
50
|
+
const key = lastKey.slice(0, entry.p) + key_str;
|
|
51
|
+
lastKey = key;
|
|
52
|
+
yield { key: key, cid: entry.v };
|
|
53
|
+
if (entry.t !== null) {
|
|
54
|
+
yield* walkMstEntries(map, entry.t);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=sync-blockmap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-blockmap.js","sourceRoot":"","sources":["../../../lib/v4/repo-reader/sync-blockmap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,cAAc,CAAC;AACrC,OAAO,KAAK,GAAG,MAAM,aAAa,CAAC;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,OAAO,KAAK,SAAS,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAIrC;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,QAAsC,EAAY,EAAE;IAChF,MAAM,QAAQ,GAAa,IAAI,GAAG,EAAE,CAAC;IACrC,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;QAC9B,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;IAC9C,CAAC;IAED,OAAO,QAAQ,CAAC;AACjB,CAAC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CACxB,GAAa,EACb,IAAiB,EACjB,QAAwC,EACpC,EAAE;IACN,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC;IAEvB,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC3B,MAAM,CAAC,KAAK,IAAI,IAAI,EAAE,kCAAkC,GAAG,EAAE,CAAC,CAAC;IAE/D,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACtC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,6BAA6B,GAAG,EAAE,CAAC,CAAC;IAE3D,OAAO,IAAI,CAAC;AACb,CAAC,CAAC;AAQF;;;;;GAKG;AACH,MAAM,SAAS,CAAC,CAAC,cAAc,CAAC,GAAa,EAAE,OAAoB;IAClE,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC;IAEvB,IAAI,OAAO,GAAG,EAAE,CAAC;IAEjB,IAAI,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACrB,KAAK,CAAC,CAAC,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IACpC,CAAC;IAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;QAClD,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QAEzB,MAAM,OAAO,GAAG,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACxD,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;QAEhD,OAAO,GAAG,GAAG,CAAC;QAEd,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC;QAEjC,IAAI,KAAK,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YACtB,KAAK,CAAC,CAAC,cAAc,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;QACrC,CAAC;IACF,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as CarReader from '../car-reader/index.js';
|
|
2
|
+
import { assert } from '../utils.js';
|
|
3
|
+
import { isCommit } from './mst.js';
|
|
4
|
+
import { collectBlock, readBlock, walkMstEntries } from './sync-blockmap.js';
|
|
5
|
+
import { RepoEntry } from './types.js';
|
|
6
|
+
export function* fromUint8Array(buf) {
|
|
7
|
+
const car = CarReader.fromUint8Array(buf);
|
|
8
|
+
const roots = car.roots;
|
|
9
|
+
assert(roots.length === 1, `expected only 1 root in the car archive; got=${roots.length}`);
|
|
10
|
+
const blockmap = collectBlock(car);
|
|
11
|
+
assert(blockmap.size > 0, `expected at least 1 block in the archive; got=${blockmap.size}`);
|
|
12
|
+
const commit = readBlock(blockmap, roots[0], isCommit);
|
|
13
|
+
for (const { key, cid } of walkMstEntries(blockmap, commit.data)) {
|
|
14
|
+
const [collection, rkey] = key.split('/');
|
|
15
|
+
const carEntry = blockmap.get(cid.$link);
|
|
16
|
+
assert(carEntry != null, `cid not found in blockmap; cid=${cid}`);
|
|
17
|
+
yield new RepoEntry(collection, rkey, cid, carEntry);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=sync-repo-reader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-repo-reader.js","sourceRoot":"","sources":["../../../lib/v4/repo-reader/sync-repo-reader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAC7E,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC,MAAM,SAAS,CAAC,CAAC,cAAc,CAAC,GAAe;IAC9C,MAAM,GAAG,GAAG,SAAS,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;IAC1C,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC;IAExB,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,gDAAgD,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IAE3F,MAAM,QAAQ,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;IACnC,MAAM,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,EAAE,iDAAiD,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IAE5F,MAAM,MAAM,GAAG,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IAEvD,KAAK,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,cAAc,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;QAClE,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAE1C,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACzC,MAAM,CAAC,QAAQ,IAAI,IAAI,EAAE,kCAAkC,GAAG,EAAE,CAAC,CAAC;QAElE,MAAM,IAAI,SAAS,CAAC,UAAU,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;IACtD,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as CID from '@atcute/cid';
|
|
2
|
+
import { type CarEntry } from '../car-reader/index.js';
|
|
3
|
+
export declare class RepoEntry {
|
|
4
|
+
/** the collection this record belongs to */
|
|
5
|
+
readonly collection: string;
|
|
6
|
+
/** record key */
|
|
7
|
+
readonly rkey: string;
|
|
8
|
+
/** CID of this record */
|
|
9
|
+
readonly cid: CID.CidLink;
|
|
10
|
+
/** the associated CarEntry for this record */
|
|
11
|
+
readonly carEntry: CarEntry;
|
|
12
|
+
/**
|
|
13
|
+
* raw contents of this record
|
|
14
|
+
*/
|
|
15
|
+
get bytes(): Uint8Array;
|
|
16
|
+
/**
|
|
17
|
+
* decoded contents of this record
|
|
18
|
+
*/
|
|
19
|
+
get record(): unknown;
|
|
20
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import * as CBOR from '@atcute/cbor';
|
|
2
|
+
import * as CID from '@atcute/cid';
|
|
3
|
+
import {} from '../car-reader/index.js';
|
|
4
|
+
export class RepoEntry {
|
|
5
|
+
collection;
|
|
6
|
+
rkey;
|
|
7
|
+
cid;
|
|
8
|
+
carEntry;
|
|
9
|
+
/** @internal */
|
|
10
|
+
constructor(
|
|
11
|
+
/** the collection this record belongs to */
|
|
12
|
+
collection,
|
|
13
|
+
/** record key */
|
|
14
|
+
rkey,
|
|
15
|
+
/** CID of this record */
|
|
16
|
+
cid,
|
|
17
|
+
/** the associated CarEntry for this record */
|
|
18
|
+
carEntry) {
|
|
19
|
+
this.collection = collection;
|
|
20
|
+
this.rkey = rkey;
|
|
21
|
+
this.cid = cid;
|
|
22
|
+
this.carEntry = carEntry;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* raw contents of this record
|
|
26
|
+
*/
|
|
27
|
+
get bytes() {
|
|
28
|
+
return this.carEntry.bytes;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* decoded contents of this record
|
|
32
|
+
*/
|
|
33
|
+
get record() {
|
|
34
|
+
return CBOR.decode(this.bytes);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../lib/v4/repo-reader/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,cAAc,CAAC;AACrC,OAAO,KAAK,GAAG,MAAM,aAAa,CAAC;AAEnC,OAAO,EAAiB,MAAM,wBAAwB,CAAC;AAEvD,MAAM,OAAO,SAAS;IAIJ;IAEA;IAEA;IAEA;IATjB,gBAAgB;IAChB;IACC,4CAA4C;IAC5B,UAAkB;IAClC,iBAAiB;IACD,IAAY;IAC5B,yBAAyB;IACT,GAAgB;IAChC,8CAA8C;IAC9B,QAAkB;QANlB,eAAU,GAAV,UAAU,CAAQ;QAElB,SAAI,GAAJ,IAAI,CAAQ;QAEZ,QAAG,GAAH,GAAG,CAAa;QAEhB,aAAQ,GAAR,QAAQ,CAAU;IAChC,CAAC;IAEJ;;OAEG;IACH,IAAI,KAAK;QACR,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;IAC5B,CAAC;IAED;;OAEG;IACH,IAAI,MAAM;QACT,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC;CACD"}
|
package/dist/v4/utils.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../lib/v4/utils.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,MAAM,GAEf,CAAC,SAAS,EAAE,OAAO,EAAE,EAAE;IAC1B,IAAI,CAAC,SAAS,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;IAC1B,CAAC;AACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export {
|
|
2
|
+
collectBlock,
|
|
3
|
+
isCommit,
|
|
4
|
+
isMstNode,
|
|
5
|
+
isTreeEntry,
|
|
6
|
+
fromUint8Array as iterateAtpRepo,
|
|
7
|
+
readBlock,
|
|
8
|
+
RepoEntry,
|
|
9
|
+
walkMstEntries,
|
|
10
|
+
type BlockMap,
|
|
11
|
+
type Commit,
|
|
12
|
+
type MstNode,
|
|
13
|
+
type NodeEntry,
|
|
14
|
+
type TreeEntry,
|
|
15
|
+
} from '../v4/repo-reader/index.js';
|
package/lib/v3/reader.ts
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import * as CBOR from '@atcute/cbor';
|
|
2
|
+
import * as CID from '@atcute/cid';
|
|
3
|
+
import { concat } from '@atcute/uint8array';
|
|
4
|
+
|
|
5
|
+
import { isCarV1Header, type CarEntry, type CarHeader } from './types.js';
|
|
6
|
+
|
|
7
|
+
export interface StreamedCarReader {
|
|
8
|
+
header(): Promise<CarHeader>;
|
|
9
|
+
roots(): Promise<CBOR.CidLink[]>;
|
|
10
|
+
|
|
11
|
+
dispose(): Promise<void>;
|
|
12
|
+
|
|
13
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
14
|
+
[Symbol.asyncIterator](): AsyncIterator<CarEntry>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const carEntryTransform = (): ReadableWritablePair<CarEntry, Uint8Array> => {
|
|
18
|
+
const transform = new TransformStream<Uint8Array, Uint8Array>();
|
|
19
|
+
let car: StreamedCarReader | undefined;
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
readable: new ReadableStream({
|
|
23
|
+
async start(controller) {
|
|
24
|
+
car = fromStream(transform.readable);
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
for await (const entry of car) {
|
|
28
|
+
controller.enqueue(entry);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
await car.dispose();
|
|
32
|
+
|
|
33
|
+
controller.close();
|
|
34
|
+
} catch (err) {
|
|
35
|
+
controller.error(err);
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
async cancel() {
|
|
39
|
+
if (car !== undefined) {
|
|
40
|
+
await car.dispose();
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
}),
|
|
44
|
+
writable: transform.writable,
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export const fromStream = (stream: ReadableStream<Uint8Array>): StreamedCarReader => {
|
|
49
|
+
let chunk = new Uint8Array(0) as Uint8Array; // annoying!
|
|
50
|
+
let offset = 0;
|
|
51
|
+
|
|
52
|
+
let _header: CarHeader | undefined;
|
|
53
|
+
|
|
54
|
+
const reader = stream.getReader();
|
|
55
|
+
|
|
56
|
+
const readVarint = async (): Promise<number> => {
|
|
57
|
+
let value = 0;
|
|
58
|
+
let shift = 0;
|
|
59
|
+
|
|
60
|
+
const MSB = 0x80;
|
|
61
|
+
const REST = 0x7f;
|
|
62
|
+
|
|
63
|
+
while (true) {
|
|
64
|
+
if (chunk.length === 0) {
|
|
65
|
+
const { value, done } = await reader.read();
|
|
66
|
+
if (done) {
|
|
67
|
+
throw new Error(`unexpected eof while decoding varint`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
chunk = value;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const byte = chunk[0];
|
|
74
|
+
chunk = chunk.subarray(1);
|
|
75
|
+
|
|
76
|
+
value += shift < 28 ? (byte & REST) << shift : (byte & REST) * 2 ** shift;
|
|
77
|
+
shift += 7;
|
|
78
|
+
|
|
79
|
+
offset++;
|
|
80
|
+
|
|
81
|
+
if ((byte & MSB) === 0) {
|
|
82
|
+
return value;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const readExact = async (n: number): Promise<Uint8Array> => {
|
|
88
|
+
const buffer = new Uint8Array(n);
|
|
89
|
+
let written = 0;
|
|
90
|
+
|
|
91
|
+
while (written < n) {
|
|
92
|
+
if (chunk.length === 0) {
|
|
93
|
+
const { value, done } = await reader.read();
|
|
94
|
+
|
|
95
|
+
if (done) {
|
|
96
|
+
throw new Error('unexpected eof while reading data');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
chunk = value;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const taken = Math.min(n - written, chunk.length);
|
|
103
|
+
buffer.set(chunk.subarray(0, taken), written);
|
|
104
|
+
|
|
105
|
+
written += taken;
|
|
106
|
+
chunk = chunk.subarray(taken);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
offset += n;
|
|
110
|
+
return buffer;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const readCid = async (): Promise<CID.Cid> => {
|
|
114
|
+
const head = await readExact(4);
|
|
115
|
+
|
|
116
|
+
const version = head[0];
|
|
117
|
+
const codec = head[1];
|
|
118
|
+
const digestType = head[2];
|
|
119
|
+
const digestSize = head[3];
|
|
120
|
+
|
|
121
|
+
if (version !== CID.CID_VERSION) {
|
|
122
|
+
throw new RangeError(`incorrect cid version (got v${version})`);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (codec !== CID.CODEC_DCBOR && codec !== CID.CODEC_RAW) {
|
|
126
|
+
throw new RangeError(`incorrect cid codec (got 0x${codec.toString(16)})`);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (digestType !== CID.HASH_SHA256) {
|
|
130
|
+
throw new RangeError(`incorrect cid digest type (got 0x${digestType.toString(16)})`);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (digestSize !== 32 && digestSize !== 0) {
|
|
134
|
+
throw new RangeError(`incorrect cid digest size (got ${digestSize})`);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// concatenate and have digest refer back to this buffer
|
|
138
|
+
const bytes = concat([head, await readExact(digestSize)]);
|
|
139
|
+
const digest = bytes.subarray(4, 4 + digestSize);
|
|
140
|
+
|
|
141
|
+
const cid: CID.Cid = {
|
|
142
|
+
version: version,
|
|
143
|
+
codec: codec,
|
|
144
|
+
digest: {
|
|
145
|
+
codec: digestType,
|
|
146
|
+
contents: digest,
|
|
147
|
+
},
|
|
148
|
+
bytes: bytes,
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
return cid;
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
return {
|
|
155
|
+
[Symbol.asyncDispose]() {
|
|
156
|
+
return this.dispose();
|
|
157
|
+
},
|
|
158
|
+
|
|
159
|
+
async dispose() {
|
|
160
|
+
await reader.cancel();
|
|
161
|
+
},
|
|
162
|
+
|
|
163
|
+
async header(): Promise<CarHeader> {
|
|
164
|
+
if (_header !== undefined) {
|
|
165
|
+
return _header;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const headerStart = offset;
|
|
169
|
+
|
|
170
|
+
const headerSize = await readVarint();
|
|
171
|
+
if (headerSize === 0) {
|
|
172
|
+
throw new RangeError(`invalid car header; length=0`);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const dataStart = offset;
|
|
176
|
+
|
|
177
|
+
const raw = await readExact(headerSize);
|
|
178
|
+
const data = CBOR.decode(raw);
|
|
179
|
+
if (!isCarV1Header(data)) {
|
|
180
|
+
throw new TypeError(`expected a car v1 archive`);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const dataEnd = offset;
|
|
184
|
+
const headerEnd = offset;
|
|
185
|
+
|
|
186
|
+
return (_header = { data, headerStart, headerEnd, dataStart, dataEnd });
|
|
187
|
+
},
|
|
188
|
+
|
|
189
|
+
async roots(): Promise<CBOR.CidLink[]> {
|
|
190
|
+
const header = await this.header();
|
|
191
|
+
|
|
192
|
+
return header.data.roots;
|
|
193
|
+
},
|
|
194
|
+
|
|
195
|
+
async *[Symbol.asyncIterator](): AsyncGenerator<CarEntry> {
|
|
196
|
+
// ensure the header is read first
|
|
197
|
+
if (_header === undefined) {
|
|
198
|
+
await this.header();
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
while (true) {
|
|
202
|
+
if (chunk.length === 0) {
|
|
203
|
+
const { value, done } = await reader.read();
|
|
204
|
+
|
|
205
|
+
if (done) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
chunk = value;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const entryStart = offset;
|
|
213
|
+
const entrySize = await readVarint();
|
|
214
|
+
|
|
215
|
+
const cidStart = offset;
|
|
216
|
+
const cid = await readCid();
|
|
217
|
+
|
|
218
|
+
const bytesStart = offset;
|
|
219
|
+
const bytesSize = entrySize - (bytesStart - cidStart);
|
|
220
|
+
const bytes = await readExact(bytesSize);
|
|
221
|
+
|
|
222
|
+
const cidEnd = bytesStart;
|
|
223
|
+
const bytesEnd = offset;
|
|
224
|
+
const entryEnd = bytesEnd;
|
|
225
|
+
|
|
226
|
+
yield {
|
|
227
|
+
cid,
|
|
228
|
+
bytes,
|
|
229
|
+
|
|
230
|
+
entryStart,
|
|
231
|
+
entryEnd,
|
|
232
|
+
cidStart,
|
|
233
|
+
cidEnd,
|
|
234
|
+
bytesStart,
|
|
235
|
+
bytesEnd,
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
};
|
|
240
|
+
};
|