UNPKG

@x5e/gink

Version:

an eventually consistent database

114 lines 4.73 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Bundler = void 0; const builders_1 = require("./builders"); const utils_1 = require("./utils"); class Bundler { constructor(pendingComment, preAssignedMedallion) { this.pendingComment = pendingComment; this.preAssignedMedallion = preAssignedMedallion; // note: this class is unit tested as part of Store.test.ts this.bundleInfo = undefined; this.bundleBytes = undefined; this.bundleBuilder = new builders_1.BundleBuilder(); this.countItems = 0; } requireNotSealed() { if (this.bundleInfo) throw new Error("This Bundler has already been sealed."); } get info() { return (0, utils_1.ensure)(this.bundleInfo, "not yet sealed"); } get bytes() { return (0, utils_1.ensure)(this.bundleBytes, "not yet sealed!"); } get builder() { if (!this.bundleInfo) throw new Error("Bundle not yet sealed."); return this.bundleBuilder; } set comment(value) { this.requireNotSealed(); this.pendingComment = value; } get comment() { var _a; return this.pendingComment || ((_a = this.bundleInfo) === null || _a === void 0 ? void 0 : _a.comment); } get medallion() { var _a; return this.preAssignedMedallion || ((_a = this.bundleInfo) === null || _a === void 0 ? void 0 : _a.medallion); } get timestamp() { var _a; return (_a = this.bundleInfo) === null || _a === void 0 ? void 0 : _a.timestamp; } addEntry(entryBuilder) { return this.addChange(new builders_1.ChangeBuilder().setEntry(entryBuilder)); } addContainer(containerBuilder) { return this.addChange(new builders_1.ChangeBuilder().setContainer(containerBuilder)); } /** * * @param changeBuilder a protobuf Change ready to be serialized * @returns an Address who's offset is immediately available and whose medallion and * timestamp become defined when this Bundle is sealed. */ addChange(changeBuilder) { this.requireNotSealed(); const offset = ++this.countItems; this.bundleBuilder.getChangesList().push(changeBuilder); // Using an anonymous class here because I only need the interface of Address, // but I need some non-trivial behavior: the timestamp and possibly medallion // are undefined until the associated bundle is finalized, then all the // components of the address become well-defined. return new (class { constructor(bundler, offset) { this.bundler = bundler; this.offset = offset; } get medallion() { return this.bundler.medallion; } get timestamp() { return this.bundler.timestamp; } })(this, offset); } /** * Intended to be called by a Database to finalize a bundle. * @param bundleInfo the bundle metadata to add when serializing * @returns serialized */ seal(bundleInfo, keyPair, priorHash, identity) { this.requireNotSealed(); if (this.preAssignedMedallion && this.preAssignedMedallion !== bundleInfo.medallion) { throw new Error("specified bundleInfo doesn't match pre-assigned medallion"); } this.bundleInfo = Object.assign({}, bundleInfo); this.bundleInfo.comment = this.pendingComment; this.bundleBuilder.setComment(this.pendingComment); this.bundleBuilder.setTimestamp(bundleInfo.timestamp); this.bundleBuilder.setPrevious(bundleInfo.priorTime); this.bundleBuilder.setChainStart(bundleInfo.chainStart); this.bundleBuilder.setMedallion(bundleInfo.medallion); this.bundleBuilder.setComment(this.bundleInfo.comment); if (bundleInfo.chainStart === bundleInfo.timestamp) { (0, utils_1.ensure)(identity, "identity required for chain-start bundles"); this.bundleBuilder.setIdentity(identity); this.bundleBuilder.setVerifyKey(keyPair.publicKey); } else { (0, utils_1.ensure)(priorHash && priorHash.length == 32, "need prior_hash"); (0, utils_1.ensure)(!identity, "identity not allowed for non-chain-start bundles"); this.bundleBuilder.setPriorHash(priorHash); } this.bundleBytes = (0, utils_1.signBundle)(this.bundleBuilder.serializeBinary(), keyPair.secretKey); this.bundleInfo.hashCode = (0, utils_1.digest)(this.bundleBytes); } } exports.Bundler = Bundler; //# sourceMappingURL=Bundler.js.map