@atproto/repo 0.8.13 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/dist/block-map.d.ts +15 -16
- package/dist/block-map.d.ts.map +1 -1
- package/dist/block-map.js +9 -43
- package/dist/block-map.js.map +1 -1
- package/dist/car.d.ts +8 -8
- package/dist/car.d.ts.map +1 -1
- package/dist/car.js +18 -15
- package/dist/car.js.map +1 -1
- package/dist/cid-set.d.ts +8 -7
- package/dist/cid-set.d.ts.map +1 -1
- package/dist/cid-set.js +11 -4
- package/dist/cid-set.js.map +1 -1
- package/dist/data-diff.d.ts +10 -10
- package/dist/data-diff.d.ts.map +1 -1
- package/dist/data-diff.js.map +1 -1
- package/dist/error.d.ts +10 -10
- package/dist/error.d.ts.map +1 -1
- package/dist/error.js.map +1 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +1 -0
- package/dist/logger.js.map +1 -1
- package/dist/mst/mst.d.ts +29 -29
- package/dist/mst/mst.d.ts.map +1 -1
- package/dist/mst/mst.js +12 -12
- package/dist/mst/mst.js.map +1 -1
- package/dist/mst/util.d.ts +2 -2
- package/dist/mst/util.d.ts.map +1 -1
- package/dist/mst/util.js +19 -39
- package/dist/mst/util.js.map +1 -1
- package/dist/parse.d.ts +6 -7
- package/dist/parse.d.ts.map +1 -1
- package/dist/parse.js +2 -2
- package/dist/parse.js.map +1 -1
- package/dist/readable-repo.d.ts +6 -7
- package/dist/readable-repo.d.ts.map +1 -1
- package/dist/readable-repo.js.map +1 -1
- package/dist/repo.d.ts +4 -4
- package/dist/repo.d.ts.map +1 -1
- package/dist/repo.js +11 -9
- package/dist/repo.js.map +1 -1
- package/dist/storage/memory-blockstore.d.ts +9 -9
- package/dist/storage/memory-blockstore.d.ts.map +1 -1
- package/dist/storage/memory-blockstore.js.map +1 -1
- package/dist/storage/readable-blockstore.d.ts +11 -12
- package/dist/storage/readable-blockstore.d.ts.map +1 -1
- package/dist/storage/readable-blockstore.js +2 -35
- package/dist/storage/readable-blockstore.js.map +1 -1
- package/dist/storage/sync-storage.d.ts +5 -5
- package/dist/storage/sync-storage.d.ts.map +1 -1
- package/dist/storage/sync-storage.js.map +1 -1
- package/dist/storage/types.d.ts +25 -26
- package/dist/storage/types.d.ts.map +1 -1
- package/dist/storage/types.js.map +1 -1
- package/dist/sync/consumer.d.ts +3 -3
- package/dist/sync/consumer.d.ts.map +1 -1
- package/dist/sync/consumer.js +1 -1
- package/dist/sync/consumer.js.map +1 -1
- package/dist/sync/provider.d.ts +3 -3
- package/dist/sync/provider.d.ts.map +1 -1
- package/dist/sync/provider.js.map +1 -1
- package/dist/types.d.ts +127 -100
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +53 -12
- package/dist/types.js.map +1 -1
- package/dist/util.d.ts +8 -3
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +33 -16
- package/dist/util.js.map +1 -1
- package/package.json +6 -7
- package/src/block-map.ts +31 -26
- package/src/car.ts +23 -28
- package/src/cid-set.ts +16 -10
- package/src/data-diff.ts +10 -10
- package/src/error.ts +6 -6
- package/src/logger.ts +1 -0
- package/src/mst/mst.ts +24 -26
- package/src/mst/util.ts +24 -9
- package/src/parse.ts +8 -8
- package/src/readable-repo.ts +6 -7
- package/src/repo.ts +13 -10
- package/src/storage/memory-blockstore.ts +8 -8
- package/src/storage/readable-blockstore.ts +12 -13
- package/src/storage/sync-storage.ts +4 -4
- package/src/storage/types.ts +25 -25
- package/src/sync/consumer.ts +5 -5
- package/src/sync/provider.ts +10 -7
- package/src/types.ts +82 -41
- package/src/util.ts +31 -14
- package/tests/_util.ts +28 -12
- package/tests/car.test.ts +31 -11
- package/tests/commit-proofs.test.ts +3 -3
- package/tests/covering-proofs.test.ts +6 -6
- package/tests/mst.test.ts +18 -19
- package/tests/proofs.test.ts +8 -6
- package/tests/repo.test.ts +1 -1
- package/tests/sync.test.ts +3 -6
- package/bench/mst.bench.ts +0 -165
- package/bench/repo.bench.ts +0 -48
package/dist/util.js
CHANGED
|
@@ -34,10 +34,12 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.ensureV3Commit = exports.cidForRecord = exports.cborToLexRecord = exports.cborToLex = exports.verifyCommitSig = exports.signCommit = exports.metaEqual = exports.formatDataKey = exports.parseDataKey = exports.ensureCreates = exports.diffToWriteDescripts = void 0;
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
exports.concatBytesAsync = concatBytesAsync;
|
|
38
|
+
exports.concatBytes = concatBytes;
|
|
39
|
+
const common_web_1 = require("@atproto/common-web");
|
|
39
40
|
const crypto = __importStar(require("@atproto/crypto"));
|
|
40
|
-
const
|
|
41
|
+
const cbor = __importStar(require("@atproto/lex-cbor"));
|
|
42
|
+
const lex_data_1 = require("@atproto/lex-data");
|
|
41
43
|
const types_1 = require("./types");
|
|
42
44
|
const diffToWriteDescripts = (diff) => {
|
|
43
45
|
return Promise.all([
|
|
@@ -86,10 +88,10 @@ const ensureCreates = (descripts) => {
|
|
|
86
88
|
};
|
|
87
89
|
exports.ensureCreates = ensureCreates;
|
|
88
90
|
const parseDataKey = (key) => {
|
|
89
|
-
const
|
|
90
|
-
if (
|
|
91
|
+
const { length, 0: collection, 1: rkey } = key.split('/');
|
|
92
|
+
if (length !== 2)
|
|
91
93
|
throw new Error(`Invalid record key: ${key}`);
|
|
92
|
-
return { collection
|
|
94
|
+
return { collection, rkey };
|
|
93
95
|
};
|
|
94
96
|
exports.parseDataKey = parseDataKey;
|
|
95
97
|
const formatDataKey = (collection, rkey) => {
|
|
@@ -115,22 +117,16 @@ const verifyCommitSig = async (commit, didKey) => {
|
|
|
115
117
|
return crypto.verifySignature(didKey, encoded, sig);
|
|
116
118
|
};
|
|
117
119
|
exports.verifyCommitSig = verifyCommitSig;
|
|
118
|
-
|
|
119
|
-
return (0, lexicon_1.ipldToLex)((0, common_1.cborDecode)(val));
|
|
120
|
-
};
|
|
121
|
-
exports.cborToLex = cborToLex;
|
|
120
|
+
exports.cborToLex = cbor.decode;
|
|
122
121
|
const cborToLexRecord = (val) => {
|
|
123
122
|
const parsed = (0, exports.cborToLex)(val);
|
|
124
|
-
if (!
|
|
123
|
+
if (!(0, lex_data_1.isPlainObject)(parsed)) {
|
|
125
124
|
throw new Error('lexicon records be a json object');
|
|
126
125
|
}
|
|
127
126
|
return parsed;
|
|
128
127
|
};
|
|
129
128
|
exports.cborToLexRecord = cborToLexRecord;
|
|
130
|
-
|
|
131
|
-
return (0, common_1.cidForCbor)((0, lexicon_1.lexToIpld)(val));
|
|
132
|
-
};
|
|
133
|
-
exports.cidForRecord = cidForRecord;
|
|
129
|
+
exports.cidForRecord = cbor.cidForLex;
|
|
134
130
|
const ensureV3Commit = (commit) => {
|
|
135
131
|
if (commit.version === 3) {
|
|
136
132
|
return commit;
|
|
@@ -139,9 +135,30 @@ const ensureV3Commit = (commit) => {
|
|
|
139
135
|
return {
|
|
140
136
|
...commit,
|
|
141
137
|
version: 3,
|
|
142
|
-
rev: commit.rev ??
|
|
138
|
+
rev: commit.rev ?? common_web_1.TID.nextStr(),
|
|
143
139
|
};
|
|
144
140
|
}
|
|
145
141
|
};
|
|
146
142
|
exports.ensureV3Commit = ensureV3Commit;
|
|
143
|
+
async function concatBytesAsync(iterable) {
|
|
144
|
+
const chunks = [];
|
|
145
|
+
for await (const chunk of iterable)
|
|
146
|
+
chunks.push(chunk);
|
|
147
|
+
return concatBytes(chunks);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* This is the same as {@link Buffer.concat}, without the `totalLength` argument.
|
|
151
|
+
*/
|
|
152
|
+
function concatBytes(chunks) {
|
|
153
|
+
let totalLength = 0;
|
|
154
|
+
for (const chunk of chunks)
|
|
155
|
+
totalLength += chunk.byteLength;
|
|
156
|
+
const result = new Uint8Array(totalLength);
|
|
157
|
+
let offset = 0;
|
|
158
|
+
for (const chunk of chunks) {
|
|
159
|
+
result.set(chunk, offset);
|
|
160
|
+
offset += chunk.byteLength;
|
|
161
|
+
}
|
|
162
|
+
return result;
|
|
163
|
+
}
|
|
147
164
|
//# sourceMappingURL=util.js.map
|
package/dist/util.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8HA,4CAIC;AAKD,kCAUC;AAjJD,oDAAyC;AACzC,wDAAyC;AAEzC,wDAAyC;AACzC,gDAAwE;AAExE,mCAUgB;AAET,MAAM,oBAAoB,GAAG,CAClC,IAAc,EACkB,EAAE;IAClC,OAAO,OAAO,CAAC,GAAG,CAAC;QACjB,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;YAClC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,IAAA,oBAAY,EAAC,GAAG,CAAC,GAAG,CAAC,CAAA;YAClD,OAAO;gBACL,MAAM,EAAE,qBAAa,CAAC,MAAM;gBAC5B,UAAU;gBACV,IAAI;gBACJ,GAAG,EAAE,GAAG,CAAC,GAAG;aACW,CAAA;QAC3B,CAAC,CAAC;QACF,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;YACrC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,IAAA,oBAAY,EAAC,GAAG,CAAC,GAAG,CAAC,CAAA;YAClD,OAAO;gBACL,MAAM,EAAE,qBAAa,CAAC,MAAM;gBAC5B,UAAU;gBACV,IAAI;gBACJ,GAAG,EAAE,GAAG,CAAC,GAAG;gBACZ,IAAI,EAAE,GAAG,CAAC,IAAI;aACS,CAAA;QAC3B,CAAC,CAAC;QACF,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;YAC/B,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,IAAA,oBAAY,EAAC,GAAG,CAAC,GAAG,CAAC,CAAA;YAClD,OAAO;gBACL,MAAM,EAAE,qBAAa,CAAC,MAAM;gBAC5B,UAAU;gBACV,IAAI;gBACJ,GAAG,EAAE,GAAG,CAAC,GAAG;aACW,CAAA;QAC3B,CAAC,CAAC;KACH,CAAC,CAAA;AACJ,CAAC,CAAA;AAjCY,QAAA,oBAAoB,wBAiChC;AAEM,MAAM,aAAa,GAAG,CAC3B,SAAgC,EACR,EAAE;IAC1B,MAAM,OAAO,GAA2B,EAAE,CAAA;IAC1C,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,IAAI,QAAQ,CAAC,MAAM,KAAK,qBAAa,CAAC,MAAM,EAAE,CAAC;YAC7C,MAAM,IAAI,KAAK,CAAC,sBAAsB,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAA;QAC1D,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QACxB,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC,CAAA;AAZY,QAAA,aAAa,iBAYzB;AAEM,MAAM,YAAY,GAAG,CAAC,GAAW,EAAc,EAAE;IACtD,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,IAAI,EAAE,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IACzD,IAAI,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,GAAG,EAAE,CAAC,CAAA;IAC/D,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,CAAA;AAC7B,CAAC,CAAA;AAJY,QAAA,YAAY,gBAIxB;AAEM,MAAM,aAAa,GAAG,CAAC,UAAkB,EAAE,IAAY,EAAU,EAAE;IACxE,OAAO,UAAU,GAAG,GAAG,GAAG,IAAI,CAAA;AAChC,CAAC,CAAA;AAFY,QAAA,aAAa,iBAEzB;AAEM,MAAM,SAAS,GAAG,CAAC,CAAS,EAAE,CAAS,EAAW,EAAE;IACzD,OAAO,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,OAAO,CAAA;AACnD,CAAC,CAAA;AAFY,QAAA,SAAS,aAErB;AAEM,MAAM,UAAU,GAAG,KAAK,EAC7B,QAAwB,EACxB,OAAgB,EACC,EAAE;IACnB,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;IACrC,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACvC,OAAO;QACL,GAAG,QAAQ;QACX,GAAG;KACJ,CAAA;AACH,CAAC,CAAA;AAVY,QAAA,UAAU,cAUtB;AAEM,MAAM,eAAe,GAAG,KAAK,EAClC,MAAc,EACd,MAAc,EACI,EAAE;IACpB,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,MAAM,CAAA;IAC/B,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IACjC,OAAO,MAAM,CAAC,eAAe,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,CAAC,CAAA;AACrD,CAAC,CAAA;AAPY,QAAA,eAAe,mBAO3B;AAEY,QAAA,SAAS,GAAkC,IAAI,CAAC,MAAM,CAAA;AAE5D,MAAM,eAAe,GAAG,CAAC,GAAe,EAAU,EAAE;IACzD,MAAM,MAAM,GAAG,IAAA,iBAAS,EAAC,GAAG,CAAC,CAAA;IAC7B,IAAI,CAAC,IAAA,wBAAa,EAAC,MAAM,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAA;IACrD,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC,CAAA;AANY,QAAA,eAAe,mBAM3B;AAEY,QAAA,YAAY,GAAoC,IAAI,CAAC,SAAS,CAAA;AAEpE,MAAM,cAAc,GAAG,CAAC,MAA+B,EAAU,EAAE;IACxE,IAAI,MAAM,CAAC,OAAO,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,MAAM,CAAA;IACf,CAAC;SAAM,CAAC;QACN,OAAO;YACL,GAAG,MAAM;YACT,OAAO,EAAE,CAAC;YACV,GAAG,EAAE,MAAM,CAAC,GAAG,IAAI,gBAAG,CAAC,OAAO,EAAE;SACjC,CAAA;IACH,CAAC;AACH,CAAC,CAAA;AAVY,QAAA,cAAc,kBAU1B;AAEM,KAAK,UAAU,gBAAgB,CAAC,QAAmC;IACxE,MAAM,MAAM,GAAiB,EAAE,CAAA;IAC/B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,QAAQ;QAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACtD,OAAO,WAAW,CAAC,MAAM,CAAC,CAAA;AAC5B,CAAC;AAED;;GAEG;AACH,SAAgB,WAAW,CAAC,MAA6B;IACvD,IAAI,WAAW,GAAG,CAAC,CAAA;IACnB,KAAK,MAAM,KAAK,IAAI,MAAM;QAAE,WAAW,IAAI,KAAK,CAAC,UAAU,CAAA;IAC3D,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,WAAW,CAAC,CAAA;IAC1C,IAAI,MAAM,GAAG,CAAC,CAAA;IACd,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;QACzB,MAAM,IAAI,KAAK,CAAC,UAAU,CAAA;IAC5B,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC","sourcesContent":["import { TID } from '@atproto/common-web'\nimport * as crypto from '@atproto/crypto'\nimport { Keypair } from '@atproto/crypto'\nimport * as cbor from '@atproto/lex-cbor'\nimport { Cid, LexMap, LexValue, isPlainObject } from '@atproto/lex-data'\nimport { DataDiff } from './data-diff'\nimport {\n Commit,\n LegacyV2Commit,\n RecordCreateDescript,\n RecordDeleteDescript,\n RecordPath,\n RecordUpdateDescript,\n RecordWriteDescript,\n UnsignedCommit,\n WriteOpAction,\n} from './types'\n\nexport const diffToWriteDescripts = (\n diff: DataDiff,\n): Promise<RecordWriteDescript[]> => {\n return Promise.all([\n ...diff.addList().map(async (add) => {\n const { collection, rkey } = parseDataKey(add.key)\n return {\n action: WriteOpAction.Create,\n collection,\n rkey,\n cid: add.cid,\n } as RecordCreateDescript\n }),\n ...diff.updateList().map(async (upd) => {\n const { collection, rkey } = parseDataKey(upd.key)\n return {\n action: WriteOpAction.Update,\n collection,\n rkey,\n cid: upd.cid,\n prev: upd.prev,\n } as RecordUpdateDescript\n }),\n ...diff.deleteList().map((del) => {\n const { collection, rkey } = parseDataKey(del.key)\n return {\n action: WriteOpAction.Delete,\n collection,\n rkey,\n cid: del.cid,\n } as RecordDeleteDescript\n }),\n ])\n}\n\nexport const ensureCreates = (\n descripts: RecordWriteDescript[],\n): RecordCreateDescript[] => {\n const creates: RecordCreateDescript[] = []\n for (const descript of descripts) {\n if (descript.action !== WriteOpAction.Create) {\n throw new Error(`Unexpected action: ${descript.action}`)\n } else {\n creates.push(descript)\n }\n }\n return creates\n}\n\nexport const parseDataKey = (key: string): RecordPath => {\n const { length, 0: collection, 1: rkey } = key.split('/')\n if (length !== 2) throw new Error(`Invalid record key: ${key}`)\n return { collection, rkey }\n}\n\nexport const formatDataKey = (collection: string, rkey: string): string => {\n return collection + '/' + rkey\n}\n\nexport const metaEqual = (a: Commit, b: Commit): boolean => {\n return a.did === b.did && a.version === b.version\n}\n\nexport const signCommit = async (\n unsigned: UnsignedCommit,\n keypair: Keypair,\n): Promise<Commit> => {\n const encoded = cbor.encode(unsigned)\n const sig = await keypair.sign(encoded)\n return {\n ...unsigned,\n sig,\n }\n}\n\nexport const verifyCommitSig = async (\n commit: Commit,\n didKey: string,\n): Promise<boolean> => {\n const { sig, ...rest } = commit\n const encoded = cbor.encode(rest)\n return crypto.verifySignature(didKey, encoded, sig)\n}\n\nexport const cborToLex: (val: Uint8Array) => LexValue = cbor.decode\n\nexport const cborToLexRecord = (val: Uint8Array): LexMap => {\n const parsed = cborToLex(val)\n if (!isPlainObject(parsed)) {\n throw new Error('lexicon records be a json object')\n }\n return parsed\n}\n\nexport const cidForRecord: (val: LexValue) => Promise<Cid> = cbor.cidForLex\n\nexport const ensureV3Commit = (commit: LegacyV2Commit | Commit): Commit => {\n if (commit.version === 3) {\n return commit\n } else {\n return {\n ...commit,\n version: 3,\n rev: commit.rev ?? TID.nextStr(),\n }\n }\n}\n\nexport async function concatBytesAsync(iterable: AsyncIterable<Uint8Array>) {\n const chunks: Uint8Array[] = []\n for await (const chunk of iterable) chunks.push(chunk)\n return concatBytes(chunks)\n}\n\n/**\n * This is the same as {@link Buffer.concat}, without the `totalLength` argument.\n */\nexport function concatBytes(chunks: readonly Uint8Array[]): Uint8Array {\n let totalLength = 0\n for (const chunk of chunks) totalLength += chunk.byteLength\n const result = new Uint8Array(totalLength)\n let offset = 0\n for (const chunk of chunks) {\n result.set(chunk, offset)\n offset += chunk.byteLength\n }\n return result\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atproto/repo",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "atproto repo and MST implementation",
|
|
6
6
|
"keywords": [
|
|
@@ -19,15 +19,14 @@
|
|
|
19
19
|
"main": "dist/index.js",
|
|
20
20
|
"types": "dist/index.d.ts",
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@ipld/dag-cbor": "^7.0.0",
|
|
23
|
-
"multiformats": "^9.9.0",
|
|
24
|
-
"uint8arrays": "3.0.0",
|
|
25
22
|
"varint": "^6.0.0",
|
|
26
23
|
"zod": "^3.23.8",
|
|
27
|
-
"@atproto/common": "^0.5.
|
|
28
|
-
"@atproto/common-web": "^0.4.
|
|
24
|
+
"@atproto/common": "^0.5.16",
|
|
25
|
+
"@atproto/common-web": "^0.4.20",
|
|
29
26
|
"@atproto/crypto": "^0.4.5",
|
|
30
|
-
"@atproto/
|
|
27
|
+
"@atproto/lex-cbor": "^0.0.16",
|
|
28
|
+
"@atproto/lex-data": "^0.0.15",
|
|
29
|
+
"@atproto/syntax": "^0.5.3"
|
|
31
30
|
},
|
|
32
31
|
"devDependencies": {
|
|
33
32
|
"jest": "^28.1.2",
|
package/src/block-map.ts
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import { encode } from '@atproto/lex-cbor'
|
|
2
|
+
import {
|
|
3
|
+
Cid,
|
|
4
|
+
LexValue,
|
|
5
|
+
cidForCbor,
|
|
6
|
+
parseCid,
|
|
7
|
+
ui8Equals,
|
|
8
|
+
} from '@atproto/lex-data'
|
|
9
|
+
|
|
10
|
+
export class BlockMap implements Iterable<[cid: Cid, bytes: Uint8Array]> {
|
|
7
11
|
private map: Map<string, Uint8Array> = new Map()
|
|
8
12
|
|
|
9
|
-
constructor(entries?: Iterable<readonly [cid:
|
|
13
|
+
constructor(entries?: Iterable<readonly [cid: Cid, bytes: Uint8Array]>) {
|
|
10
14
|
if (entries) {
|
|
11
15
|
for (const [cid, bytes] of entries) {
|
|
12
16
|
this.set(cid, bytes)
|
|
@@ -14,28 +18,29 @@ export class BlockMap implements Iterable<[cid: CID, bytes: Uint8Array]> {
|
|
|
14
18
|
}
|
|
15
19
|
}
|
|
16
20
|
|
|
17
|
-
async add(value: LexValue): Promise<
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
async add(value: LexValue): Promise<Cid> {
|
|
22
|
+
const bytes = encode(value)
|
|
23
|
+
const cid = await cidForCbor(bytes)
|
|
24
|
+
this.set(cid, bytes)
|
|
25
|
+
return cid
|
|
21
26
|
}
|
|
22
27
|
|
|
23
|
-
set(cid:
|
|
28
|
+
set(cid: Cid, bytes: Uint8Array): BlockMap {
|
|
24
29
|
this.map.set(cid.toString(), bytes)
|
|
25
30
|
return this
|
|
26
31
|
}
|
|
27
32
|
|
|
28
|
-
get(cid:
|
|
33
|
+
get(cid: Cid): Uint8Array | undefined {
|
|
29
34
|
return this.map.get(cid.toString())
|
|
30
35
|
}
|
|
31
36
|
|
|
32
|
-
delete(cid:
|
|
37
|
+
delete(cid: Cid): BlockMap {
|
|
33
38
|
this.map.delete(cid.toString())
|
|
34
39
|
return this
|
|
35
40
|
}
|
|
36
41
|
|
|
37
|
-
getMany(cids:
|
|
38
|
-
const missing:
|
|
42
|
+
getMany(cids: Cid[]): { blocks: BlockMap; missing: Cid[] } {
|
|
43
|
+
const missing: Cid[] = []
|
|
39
44
|
const blocks = new BlockMap()
|
|
40
45
|
for (const cid of cids) {
|
|
41
46
|
const got = this.map.get(cid.toString())
|
|
@@ -48,7 +53,7 @@ export class BlockMap implements Iterable<[cid: CID, bytes: Uint8Array]> {
|
|
|
48
53
|
return { blocks, missing }
|
|
49
54
|
}
|
|
50
55
|
|
|
51
|
-
has(cid:
|
|
56
|
+
has(cid: Cid): boolean {
|
|
52
57
|
return this.map.has(cid.toString())
|
|
53
58
|
}
|
|
54
59
|
|
|
@@ -56,7 +61,7 @@ export class BlockMap implements Iterable<[cid: CID, bytes: Uint8Array]> {
|
|
|
56
61
|
this.map.clear()
|
|
57
62
|
}
|
|
58
63
|
|
|
59
|
-
forEach(cb: (bytes: Uint8Array, cid:
|
|
64
|
+
forEach(cb: (bytes: Uint8Array, cid: Cid) => void): void {
|
|
60
65
|
for (const [cid, bytes] of this) cb(bytes, cid)
|
|
61
66
|
}
|
|
62
67
|
|
|
@@ -64,7 +69,7 @@ export class BlockMap implements Iterable<[cid: CID, bytes: Uint8Array]> {
|
|
|
64
69
|
return Array.from(this, toEntry)
|
|
65
70
|
}
|
|
66
71
|
|
|
67
|
-
cids():
|
|
72
|
+
cids(): Cid[] {
|
|
68
73
|
return Array.from(this.keys())
|
|
69
74
|
}
|
|
70
75
|
|
|
@@ -90,16 +95,16 @@ export class BlockMap implements Iterable<[cid: CID, bytes: Uint8Array]> {
|
|
|
90
95
|
for (const [cid, bytes] of this) {
|
|
91
96
|
const otherBytes = other.get(cid)
|
|
92
97
|
if (!otherBytes) return false
|
|
93
|
-
if (!
|
|
98
|
+
if (!ui8Equals(bytes, otherBytes)) {
|
|
94
99
|
return false
|
|
95
100
|
}
|
|
96
101
|
}
|
|
97
102
|
return true
|
|
98
103
|
}
|
|
99
104
|
|
|
100
|
-
*keys(): Generator<
|
|
105
|
+
*keys(): Generator<Cid, void, unknown> {
|
|
101
106
|
for (const key of this.map.keys()) {
|
|
102
|
-
yield
|
|
107
|
+
yield parseCid(key)
|
|
103
108
|
}
|
|
104
109
|
}
|
|
105
110
|
|
|
@@ -107,19 +112,19 @@ export class BlockMap implements Iterable<[cid: CID, bytes: Uint8Array]> {
|
|
|
107
112
|
yield* this.map.values()
|
|
108
113
|
}
|
|
109
114
|
|
|
110
|
-
*[Symbol.iterator](): Generator<[
|
|
115
|
+
*[Symbol.iterator](): Generator<[Cid, Uint8Array], void, unknown> {
|
|
111
116
|
for (const [key, value] of this.map) {
|
|
112
|
-
yield [
|
|
117
|
+
yield [parseCid(key), value]
|
|
113
118
|
}
|
|
114
119
|
}
|
|
115
120
|
}
|
|
116
121
|
|
|
117
|
-
function toEntry([cid, bytes]: readonly [
|
|
122
|
+
function toEntry([cid, bytes]: readonly [Cid, Uint8Array]): Entry {
|
|
118
123
|
return { cid, bytes }
|
|
119
124
|
}
|
|
120
125
|
|
|
121
126
|
type Entry = {
|
|
122
|
-
cid:
|
|
127
|
+
cid: Cid
|
|
123
128
|
bytes: Uint8Array
|
|
124
129
|
}
|
|
125
130
|
|
package/src/car.ts
CHANGED
|
@@ -1,20 +1,13 @@
|
|
|
1
1
|
import { setImmediate } from 'node:timers/promises'
|
|
2
|
-
import * as cbor from '@ipld/dag-cbor'
|
|
3
|
-
import { CID } from 'multiformats/cid'
|
|
4
|
-
import * as ui8 from 'uint8arrays'
|
|
5
2
|
import * as varint from 'varint'
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
parseCidFromBytes,
|
|
9
|
-
schema,
|
|
10
|
-
streamToBuffer,
|
|
11
|
-
verifyCidForBytes,
|
|
12
|
-
} from '@atproto/common'
|
|
3
|
+
import * as cbor from '@atproto/lex-cbor'
|
|
4
|
+
import { Cid, decodeCid, isCidForBytes } from '@atproto/lex-data'
|
|
13
5
|
import { BlockMap } from './block-map'
|
|
14
|
-
import { CarBlock } from './types'
|
|
6
|
+
import { CarBlock, schema } from './types'
|
|
7
|
+
import { concatBytesAsync } from './util'
|
|
15
8
|
|
|
16
9
|
export async function* writeCarStream(
|
|
17
|
-
root:
|
|
10
|
+
root: Cid | null,
|
|
18
11
|
blocks: AsyncIterable<CarBlock>,
|
|
19
12
|
): AsyncIterable<Uint8Array> {
|
|
20
13
|
const header = new Uint8Array(
|
|
@@ -34,16 +27,15 @@ export async function* writeCarStream(
|
|
|
34
27
|
}
|
|
35
28
|
}
|
|
36
29
|
|
|
37
|
-
export
|
|
38
|
-
root:
|
|
30
|
+
export async function blocksToCarFile(
|
|
31
|
+
root: Cid | null,
|
|
39
32
|
blocks: BlockMap,
|
|
40
|
-
): Promise<Uint8Array>
|
|
41
|
-
|
|
42
|
-
return streamToBuffer(carStream)
|
|
33
|
+
): Promise<Uint8Array> {
|
|
34
|
+
return concatBytesAsync(blocksToCarStream(root, blocks))
|
|
43
35
|
}
|
|
44
36
|
|
|
45
37
|
export const blocksToCarStream = (
|
|
46
|
-
root:
|
|
38
|
+
root: Cid | null,
|
|
47
39
|
blocks: BlockMap,
|
|
48
40
|
): AsyncIterable<Uint8Array> => {
|
|
49
41
|
return writeCarStream(root, iterateBlocks(blocks))
|
|
@@ -65,7 +57,7 @@ export type ReadCarOptions = {
|
|
|
65
57
|
export const readCar = async (
|
|
66
58
|
bytes: Uint8Array,
|
|
67
59
|
opts?: ReadCarOptions,
|
|
68
|
-
): Promise<{ roots:
|
|
60
|
+
): Promise<{ roots: Cid[]; blocks: BlockMap }> => {
|
|
69
61
|
const { roots, blocks } = await readCarReader(new Ui8Reader(bytes), opts)
|
|
70
62
|
const blockMap = new BlockMap()
|
|
71
63
|
for await (const block of blocks) {
|
|
@@ -77,7 +69,7 @@ export const readCar = async (
|
|
|
77
69
|
export const readCarWithRoot = async (
|
|
78
70
|
bytes: Uint8Array,
|
|
79
71
|
opts?: ReadCarOptions,
|
|
80
|
-
): Promise<{ root:
|
|
72
|
+
): Promise<{ root: Cid; blocks: BlockMap }> => {
|
|
81
73
|
const { roots, blocks } = await readCar(bytes, opts)
|
|
82
74
|
if (roots.length !== 1) {
|
|
83
75
|
throw new Error(`Expected one root, got ${roots.length}`)
|
|
@@ -96,7 +88,7 @@ export const readCarStream = async (
|
|
|
96
88
|
car: Iterable<Uint8Array> | AsyncIterable<Uint8Array>,
|
|
97
89
|
opts?: ReadCarOptions,
|
|
98
90
|
): Promise<{
|
|
99
|
-
roots:
|
|
91
|
+
roots: Cid[]
|
|
100
92
|
blocks: CarBlockIterable
|
|
101
93
|
}> => {
|
|
102
94
|
return readCarReader(new BufferedReader(car), opts)
|
|
@@ -106,7 +98,7 @@ export const readCarReader = async (
|
|
|
106
98
|
reader: BytesReader,
|
|
107
99
|
opts?: ReadCarOptions,
|
|
108
100
|
): Promise<{
|
|
109
|
-
roots:
|
|
101
|
+
roots: Cid[]
|
|
110
102
|
blocks: CarBlockIterable
|
|
111
103
|
}> => {
|
|
112
104
|
try {
|
|
@@ -116,11 +108,12 @@ export const readCarReader = async (
|
|
|
116
108
|
}
|
|
117
109
|
const headerBytes = await reader.read(headerSize)
|
|
118
110
|
const header = cbor.decode(headerBytes)
|
|
119
|
-
|
|
120
|
-
|
|
111
|
+
const result = schema.carHeader.safeParse(header)
|
|
112
|
+
if (!result.success) {
|
|
113
|
+
throw new Error('Could not parse CAR header', { cause: result.error })
|
|
121
114
|
}
|
|
122
115
|
return {
|
|
123
|
-
roots:
|
|
116
|
+
roots: result.data.roots,
|
|
124
117
|
blocks: readCarBlocksIter(reader, opts),
|
|
125
118
|
}
|
|
126
119
|
} catch (err) {
|
|
@@ -163,7 +156,7 @@ async function* readCarBlocksIterGenerator(
|
|
|
163
156
|
break
|
|
164
157
|
}
|
|
165
158
|
const blockBytes = await reader.read(blockSize)
|
|
166
|
-
const cid =
|
|
159
|
+
const cid = decodeCid(blockBytes.subarray(0, 36))
|
|
167
160
|
const bytes = blockBytes.subarray(36)
|
|
168
161
|
yield { cid, bytes }
|
|
169
162
|
|
|
@@ -183,7 +176,9 @@ export async function* verifyIncomingCarBlocks(
|
|
|
183
176
|
car: AsyncIterable<CarBlock>,
|
|
184
177
|
): AsyncGenerator<CarBlock, void, unknown> {
|
|
185
178
|
for await (const block of car) {
|
|
186
|
-
await
|
|
179
|
+
if (!(await isCidForBytes(block.cid, block.bytes))) {
|
|
180
|
+
throw new Error(`Not a valid CID for bytes (${block.cid.toString()})`)
|
|
181
|
+
}
|
|
187
182
|
yield block
|
|
188
183
|
}
|
|
189
184
|
}
|
|
@@ -205,7 +200,7 @@ const readVarint = async (reader: BytesReader): Promise<number | null> => {
|
|
|
205
200
|
done = true
|
|
206
201
|
}
|
|
207
202
|
}
|
|
208
|
-
const concatted =
|
|
203
|
+
const concatted = Buffer.concat(bytes)
|
|
209
204
|
return varint.decode(concatted)
|
|
210
205
|
}
|
|
211
206
|
|
package/src/cid-set.ts
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Cid, parseCid } from '@atproto/lex-data'
|
|
2
2
|
|
|
3
|
-
export class CidSet {
|
|
3
|
+
export class CidSet implements Iterable<Cid> {
|
|
4
4
|
private set: Set<string>
|
|
5
5
|
|
|
6
|
-
constructor(arr:
|
|
6
|
+
constructor(arr: Cid[] = []) {
|
|
7
7
|
const strArr = arr.map((c) => c.toString())
|
|
8
8
|
this.set = new Set(strArr)
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
add(cid:
|
|
11
|
+
add(cid: Cid): CidSet {
|
|
12
12
|
this.set.add(cid.toString())
|
|
13
13
|
return this
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
addSet(toMerge: CidSet): CidSet {
|
|
17
|
-
toMerge.
|
|
17
|
+
for (const c of toMerge.set) this.set.add(c)
|
|
18
18
|
return this
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
subtractSet(toSubtract: CidSet): CidSet {
|
|
22
|
-
toSubtract.
|
|
22
|
+
for (const c of toSubtract.set) this.set.delete(c)
|
|
23
23
|
return this
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
delete(cid:
|
|
26
|
+
delete(cid: Cid) {
|
|
27
27
|
this.set.delete(cid.toString())
|
|
28
28
|
return this
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
has(cid:
|
|
31
|
+
has(cid: Cid): boolean {
|
|
32
32
|
return this.set.has(cid.toString())
|
|
33
33
|
}
|
|
34
34
|
|
|
@@ -41,8 +41,14 @@ export class CidSet {
|
|
|
41
41
|
return this
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
toList():
|
|
45
|
-
return
|
|
44
|
+
toList(): Cid[] {
|
|
45
|
+
return Array.from(this)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
*[Symbol.iterator](): Generator<Cid, void, unknown> {
|
|
49
|
+
for (const c of this.set) {
|
|
50
|
+
yield parseCid(c)
|
|
51
|
+
}
|
|
46
52
|
}
|
|
47
53
|
}
|
|
48
54
|
|
package/src/data-diff.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Cid } from '@atproto/lex-data'
|
|
2
2
|
import { BlockMap } from './block-map'
|
|
3
3
|
import { CidSet } from './cid-set'
|
|
4
4
|
import { MST, NodeEntry, mstDiff } from './mst'
|
|
@@ -37,7 +37,7 @@ export class DataDiff {
|
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
leafAdd(key: string, cid:
|
|
40
|
+
leafAdd(key: string, cid: Cid) {
|
|
41
41
|
this.adds[key] = { key, cid }
|
|
42
42
|
if (this.removedCids.has(cid)) {
|
|
43
43
|
this.removedCids.delete(cid)
|
|
@@ -46,14 +46,14 @@ export class DataDiff {
|
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
leafUpdate(key: string, prev:
|
|
49
|
+
leafUpdate(key: string, prev: Cid, cid: Cid) {
|
|
50
50
|
if (prev.equals(cid)) return
|
|
51
51
|
this.updates[key] = { key, prev, cid }
|
|
52
52
|
this.removedCids.add(prev)
|
|
53
53
|
this.newLeafCids.add(cid)
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
leafDelete(key: string, cid:
|
|
56
|
+
leafDelete(key: string, cid: Cid) {
|
|
57
57
|
this.deletes[key] = { key, cid }
|
|
58
58
|
if (this.newLeafCids.has(cid)) {
|
|
59
59
|
this.newLeafCids.delete(cid)
|
|
@@ -62,7 +62,7 @@ export class DataDiff {
|
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
treeAdd(cid:
|
|
65
|
+
treeAdd(cid: Cid, bytes: Uint8Array) {
|
|
66
66
|
if (this.removedCids.has(cid)) {
|
|
67
67
|
this.removedCids.delete(cid)
|
|
68
68
|
} else {
|
|
@@ -70,7 +70,7 @@ export class DataDiff {
|
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
treeDelete(cid:
|
|
73
|
+
treeDelete(cid: Cid) {
|
|
74
74
|
if (this.newMstBlocks.has(cid)) {
|
|
75
75
|
this.newMstBlocks.delete(cid)
|
|
76
76
|
} else {
|
|
@@ -102,16 +102,16 @@ export class DataDiff {
|
|
|
102
102
|
|
|
103
103
|
export type DataAdd = {
|
|
104
104
|
key: string
|
|
105
|
-
cid:
|
|
105
|
+
cid: Cid
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
export type DataUpdate = {
|
|
109
109
|
key: string
|
|
110
|
-
prev:
|
|
111
|
-
cid:
|
|
110
|
+
prev: Cid
|
|
111
|
+
cid: Cid
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
export type DataDelete = {
|
|
115
115
|
key: string
|
|
116
|
-
cid:
|
|
116
|
+
cid: Cid
|
|
117
117
|
}
|
package/src/error.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Cid } from '@atproto/lex-data'
|
|
2
2
|
|
|
3
3
|
export class MissingBlockError extends Error {
|
|
4
4
|
constructor(
|
|
5
|
-
public cid:
|
|
5
|
+
public cid: Cid,
|
|
6
6
|
def?: string,
|
|
7
7
|
) {
|
|
8
8
|
let msg = `block not found: ${cid.toString()}`
|
|
@@ -16,7 +16,7 @@ export class MissingBlockError extends Error {
|
|
|
16
16
|
export class MissingBlocksError extends Error {
|
|
17
17
|
constructor(
|
|
18
18
|
public context: string,
|
|
19
|
-
public cids:
|
|
19
|
+
public cids: Cid[],
|
|
20
20
|
) {
|
|
21
21
|
const cidStr = cids.map((c) => c.toString())
|
|
22
22
|
super(`missing ${context} blocks: ${cidStr}`)
|
|
@@ -25,8 +25,8 @@ export class MissingBlocksError extends Error {
|
|
|
25
25
|
|
|
26
26
|
export class MissingCommitBlocksError extends Error {
|
|
27
27
|
constructor(
|
|
28
|
-
public commit:
|
|
29
|
-
public cids:
|
|
28
|
+
public commit: Cid,
|
|
29
|
+
public cids: Cid[],
|
|
30
30
|
) {
|
|
31
31
|
const cidStr = cids.map((c) => c.toString())
|
|
32
32
|
super(`missing blocks for commit ${commit.toString()}: ${cidStr}`)
|
|
@@ -35,7 +35,7 @@ export class MissingCommitBlocksError extends Error {
|
|
|
35
35
|
|
|
36
36
|
export class UnexpectedObjectError extends Error {
|
|
37
37
|
constructor(
|
|
38
|
-
public cid:
|
|
38
|
+
public cid: Cid,
|
|
39
39
|
public def: string,
|
|
40
40
|
) {
|
|
41
41
|
super(`unexpected object at ${cid.toString()}, expected: ${def}`)
|
package/src/logger.ts
CHANGED