UNPKG

@atproto/repo

Version:

atproto repo and MST implementation

207 lines 8.27 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Repo = void 0; const common_1 = require("@atproto/common"); const lexicon_1 = require("@atproto/lexicon"); const block_map_1 = require("./block-map"); const cid_set_1 = require("./cid-set"); const data_diff_1 = require("./data-diff"); const logger_1 = __importDefault(require("./logger")); const mst_1 = require("./mst"); const readable_repo_1 = require("./readable-repo"); const types_1 = require("./types"); const util = __importStar(require("./util")); class Repo extends readable_repo_1.ReadableRepo { constructor(params) { super(params); Object.defineProperty(this, "storage", { enumerable: true, configurable: true, writable: true, value: void 0 }); this.storage = params.storage; } static async formatInitCommit(storage, did, keypair, initialWrites = [], revOverride) { const newBlocks = new block_map_1.BlockMap(); let data = await mst_1.MST.create(storage); for (const record of initialWrites) { const cid = await newBlocks.add(record.record); const dataKey = util.formatDataKey(record.collection, record.rkey); data = await data.add(dataKey, cid); } const dataCid = await data.getPointer(); const diff = await data_diff_1.DataDiff.of(data, null); newBlocks.addMap(diff.newMstBlocks); const rev = revOverride ?? common_1.TID.nextStr(); const commit = await util.signCommit({ did, version: 3, rev, prev: null, // added for backwards compatibility with v2 data: dataCid, }, keypair); const commitCid = await newBlocks.add(commit); return { cid: commitCid, rev, since: null, prev: null, newBlocks, relevantBlocks: newBlocks, removedCids: diff.removedCids, }; } static async createFromCommit(storage, commit) { await storage.applyCommit(commit); return Repo.load(storage, commit.cid); } static async create(storage, did, keypair, initialWrites = []) { const commit = await Repo.formatInitCommit(storage, did, keypair, initialWrites); return Repo.createFromCommit(storage, commit); } static async load(storage, cid) { const commitCid = cid || (await storage.getRoot()); if (!commitCid) { throw new Error('No cid provided and none in storage'); } const commit = await storage.readObj(commitCid, types_1.def.versionedCommit); const data = await mst_1.MST.load(storage, commit.data); logger_1.default.info({ did: commit.did }, 'loaded repo for'); return new Repo({ storage, data, commit: util.ensureV3Commit(commit), cid: commitCid, }); } async formatCommit(toWrite, keypair) { const writes = Array.isArray(toWrite) ? toWrite : [toWrite]; const leaves = new block_map_1.BlockMap(); let data = this.data; for (const write of writes) { if (write.action === types_1.WriteOpAction.Create) { const cid = await leaves.add(write.record); const dataKey = write.collection + '/' + write.rkey; data = await data.add(dataKey, cid); } else if (write.action === types_1.WriteOpAction.Update) { const cid = await leaves.add(write.record); const dataKey = write.collection + '/' + write.rkey; data = await data.update(dataKey, cid); } else if (write.action === types_1.WriteOpAction.Delete) { const dataKey = write.collection + '/' + write.rkey; data = await data.delete(dataKey); } } const dataCid = await data.getPointer(); const diff = await data_diff_1.DataDiff.of(data, this.data); const newBlocks = diff.newMstBlocks; const removedCids = diff.removedCids; const proofs = await Promise.all(writes.map((op) => data.getCoveringProof(util.formatDataKey(op.collection, op.rkey)))); const relevantBlocks = proofs.reduce((acc, cur) => { return acc.addMap(cur); }, new block_map_1.BlockMap()); const addedLeaves = leaves.getMany(diff.newLeafCids.toList()); if (addedLeaves.missing.length > 0) { throw new Error(`Missing leaf blocks: ${addedLeaves.missing}`); } newBlocks.addMap(addedLeaves.blocks); relevantBlocks.addMap(addedLeaves.blocks); const rev = common_1.TID.nextStr(this.commit.rev); const commit = await util.signCommit({ did: this.did, version: 3, rev, prev: null, // added for backwards compatibility with v2 data: dataCid, }, keypair); const commitBlock = await (0, common_1.dataToCborBlock)((0, lexicon_1.lexToIpld)(commit)); if (!commitBlock.cid.equals(this.cid)) { newBlocks.set(commitBlock.cid, commitBlock.bytes); relevantBlocks.set(commitBlock.cid, commitBlock.bytes); removedCids.add(this.cid); } return { cid: commitBlock.cid, rev, since: this.commit.rev, prev: this.cid, newBlocks, relevantBlocks, removedCids, }; } async applyCommit(commitData) { await this.storage.applyCommit(commitData); return Repo.load(this.storage, commitData.cid); } async applyWrites(toWrite, keypair) { const commit = await this.formatCommit(toWrite, keypair); return this.applyCommit(commit); } async formatResignCommit(rev, keypair) { const commit = await util.signCommit({ did: this.did, version: 3, rev, prev: null, // added for backwards compatibility with v2 data: this.commit.data, }, keypair); const newBlocks = new block_map_1.BlockMap(); const commitCid = await newBlocks.add(commit); return { cid: commitCid, rev, since: null, prev: null, newBlocks, relevantBlocks: newBlocks, removedCids: new cid_set_1.CidSet([this.cid]), }; } async resignCommit(rev, keypair) { const formatted = await this.formatResignCommit(rev, keypair); return this.applyCommit(formatted); } } exports.Repo = Repo; exports.default = Repo; //# sourceMappingURL=repo.js.map