@enbox/api
Version:
SDK for accessing the features and capabilities of Web5
909 lines • 61.7 kB
JavaScript
"use strict";
/**
* NOTE: Added reference types here to avoid a `pnpm` bug during build.
* https://github.com/TBD54566975/web5-js/pull/507
*/
/// <reference types="@enbox/dwn-sdk-js" />
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
var __values = (this && this.__values) || function(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
if (o && typeof o.length === "number") return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Record = void 0;
var agent_1 = require("@enbox/agent");
var common_1 = require("@enbox/common");
var utils_js_1 = require("./utils.js");
/**
* The `Record` class encapsulates a single record's data and metadata, providing a more
* developer-friendly interface for working with Decentralized Web Node (DWN) records.
*
* Methods are provided to read, update, and manage the record's lifecycle, including writing to
* remote DWNs.
*
* Note: The `messageTimestamp` of the most recent RecordsWrite message is
* logically equivalent to the date/time at which a Record was most
* recently modified. Since this Record class implementation is
* intended to simplify the developer experience of working with
* logical records (and not individual DWN messages) the
* `messageTimestamp` is mapped to `dateModified`.
*
* @beta
*/
var Record = exports.Record = /** @class */ (function () {
function Record(agent, options, permissionsApi) {
this._agent = agent;
// Store the author DID that originally signed the message as a convenience for developers, so
// that they don't have to decode the signer's DID from the JWS.
this._author = options.author;
// The creator is the author of the initial write, or the author of the record if there is no initial write.
this._creator = options.initialWrite ? (0, agent_1.getRecordAuthor)(options.initialWrite) : options.author;
// Store the `connectedDid`, and optionally the `delegateDid` and `permissionsApi` in order to be able
// to perform operations on the record (update, delete, data) as a delegate of the connected DID.
this._connectedDid = options.connectedDid;
this._delegateDid = options.delegateDid;
this._permissionsApi = permissionsApi !== null && permissionsApi !== void 0 ? permissionsApi : new agent_1.AgentPermissionsApi({ agent: agent });
// If the record was queried or read from a remote DWN, the `remoteOrigin` DID will be
// defined. This value is used to send subsequent read requests to the same remote DWN in the
// event the record's data payload was too large to be returned in query results. or must be
// read again (e.g., if the data stream is consumed).
this._remoteOrigin = options.remoteOrigin;
// RecordsWriteMessage properties.
this._attestation = options.attestation;
this._authorization = options.authorization;
this._contextId = options.contextId;
this._descriptor = options.descriptor;
this._encryption = options.encryption;
this._initialWrite = options.initialWrite;
this._recordId = this.isRecordsDeleteDescriptor(options.descriptor) ? options.descriptor.recordId : options.recordId;
this._protocolRole = options.protocolRole;
if (options.encodedData) {
// If `encodedData` is set, then it is expected that:
// type is Blob if the Record object was instantiated by dwn.records.create()/write().
// type is Base64 URL encoded string if the Record object was instantiated by dwn.records.query().
// If it is a string, we need to Base64 URL decode to bytes and instantiate a Blob.
this._encodedData = (typeof options.encodedData === 'string') ?
new Blob([common_1.Convert.base64Url(options.encodedData).toUint8Array()], { type: this.dataFormat }) :
options.encodedData;
}
if (options.data) {
// If the record was created from a RecordsRead reply then it will have a `data` property.
// If the `data` property is a web ReadableStream, convert it to a Node.js Readable.
this._readableStream = common_1.Stream.isReadableStream(options.data) ?
common_1.NodeStream.fromWebReadable({ readableStream: options.data }) :
options.data;
}
}
Object.defineProperty(Record.prototype, "_recordsWriteDescriptor", {
/** The `RecordsWriteMessage` descriptor unless the record is in a deleted state */
get: function () {
if ((0, agent_1.isDwnMessage)(agent_1.DwnInterface.RecordsWrite, this.rawMessage)) {
return this._descriptor;
}
return undefined; // returns undefined if the descriptor does not represent a RecordsWrite message.
},
enumerable: false,
configurable: true
});
Object.defineProperty(Record.prototype, "_immutableProperties", {
/** The `RecordsWrite` descriptor from the current record or the initial write if the record is in a delete state. */
get: function () {
return this._recordsWriteDescriptor || this._initialWrite.descriptor;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Record.prototype, "id", {
// Getters for immutable Record properties.
/** Record's ID */
get: function () { return this._recordId; },
enumerable: false,
configurable: true
});
Object.defineProperty(Record.prototype, "contextId", {
/** Record's context ID. If the record is deleted, the context Id comes from the initial write */
get: function () { return this.deleted ? this._initialWrite.contextId : this._contextId; },
enumerable: false,
configurable: true
});
Object.defineProperty(Record.prototype, "dateCreated", {
/** Record's creation date */
get: function () { return this._immutableProperties.dateCreated; },
enumerable: false,
configurable: true
});
Object.defineProperty(Record.prototype, "parentId", {
/** Record's parent ID */
get: function () { return this._immutableProperties.parentId; },
enumerable: false,
configurable: true
});
Object.defineProperty(Record.prototype, "protocol", {
/** Record's protocol */
get: function () { return this._immutableProperties.protocol; },
enumerable: false,
configurable: true
});
Object.defineProperty(Record.prototype, "protocolPath", {
/** Record's protocol path */
get: function () { return this._immutableProperties.protocolPath; },
enumerable: false,
configurable: true
});
Object.defineProperty(Record.prototype, "recipient", {
/** Record's recipient */
get: function () { return this._immutableProperties.recipient; },
enumerable: false,
configurable: true
});
Object.defineProperty(Record.prototype, "schema", {
/** Record's schema */
get: function () { return this._immutableProperties.schema; },
enumerable: false,
configurable: true
});
Object.defineProperty(Record.prototype, "dataFormat", {
// Getters for mutable DWN RecordsWrite properties that may be undefined in a deleted state.
/** Record's data format */
get: function () { var _a; return (_a = this._recordsWriteDescriptor) === null || _a === void 0 ? void 0 : _a.dataFormat; },
enumerable: false,
configurable: true
});
Object.defineProperty(Record.prototype, "dataCid", {
/** Record's CID */
get: function () { var _a; return (_a = this._recordsWriteDescriptor) === null || _a === void 0 ? void 0 : _a.dataCid; },
enumerable: false,
configurable: true
});
Object.defineProperty(Record.prototype, "dataSize", {
/** Record's data size */
get: function () { var _a; return (_a = this._recordsWriteDescriptor) === null || _a === void 0 ? void 0 : _a.dataSize; },
enumerable: false,
configurable: true
});
Object.defineProperty(Record.prototype, "datePublished", {
/** Record's published date */
get: function () { var _a; return (_a = this._recordsWriteDescriptor) === null || _a === void 0 ? void 0 : _a.datePublished; },
enumerable: false,
configurable: true
});
Object.defineProperty(Record.prototype, "published", {
/** Record's published status (true/false) */
get: function () { var _a; return (_a = this._recordsWriteDescriptor) === null || _a === void 0 ? void 0 : _a.published; },
enumerable: false,
configurable: true
});
Object.defineProperty(Record.prototype, "tags", {
/** Tags of the record */
get: function () { var _a; return (_a = this._recordsWriteDescriptor) === null || _a === void 0 ? void 0 : _a.tags; },
enumerable: false,
configurable: true
});
Object.defineProperty(Record.prototype, "author", {
// Getters for for properties that depend on the current state of the Record.
/** DID that is the logical author of the Record. */
get: function () { return this._author; },
enumerable: false,
configurable: true
});
Object.defineProperty(Record.prototype, "creator", {
/** DID that is the original creator of the Record. */
get: function () { return this._creator; },
enumerable: false,
configurable: true
});
Object.defineProperty(Record.prototype, "dateModified", {
/** Record's modified date */
get: function () { return this._descriptor.messageTimestamp; },
enumerable: false,
configurable: true
});
Object.defineProperty(Record.prototype, "encryption", {
/** Record's encryption */
get: function () { return this._encryption; },
enumerable: false,
configurable: true
});
Object.defineProperty(Record.prototype, "authorization", {
/** Record's signatures attestation */
get: function () { return this._authorization; },
enumerable: false,
configurable: true
});
Object.defineProperty(Record.prototype, "attestation", {
/** Record's signatures attestation */
get: function () { return this._attestation; },
enumerable: false,
configurable: true
});
Object.defineProperty(Record.prototype, "protocolRole", {
/** Role under which the author is writing the record */
get: function () { return this._protocolRole; },
enumerable: false,
configurable: true
});
Object.defineProperty(Record.prototype, "deleted", {
/** Record's deleted state (true/false) */
get: function () { return (0, agent_1.isDwnMessage)(agent_1.DwnInterface.RecordsDelete, this.rawMessage); },
enumerable: false,
configurable: true
});
Object.defineProperty(Record.prototype, "initialWrite", {
/** Record's initial write if the record has been updated */
get: function () { return this._initialWrite; },
enumerable: false,
configurable: true
});
Object.defineProperty(Record.prototype, "rawMessage", {
/**
* Returns a copy of the raw `RecordsWriteMessage` that was used to create the current `Record` instance.
*/
get: function () {
var messageType = this._descriptor.interface + this._descriptor.method;
var message;
if (messageType === agent_1.DwnInterface.RecordsWrite) {
message = JSON.parse(JSON.stringify({
contextId: this._contextId,
recordId: this._recordId,
descriptor: this._descriptor,
attestation: this._attestation,
authorization: this._authorization,
encryption: this._encryption,
}));
}
else {
message = JSON.parse(JSON.stringify({
descriptor: this._descriptor,
authorization: this._authorization,
}));
}
(0, common_1.removeUndefinedProperties)(message);
return message;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Record.prototype, "data", {
/**
* Returns the data of the current record.
* If the record data is not available, it attempts to fetch the data from the DWN.
* @returns a data stream with convenience methods such as `blob()`, `json()`, `text()`, and `stream()`, similar to the fetch API response
* @throws `Error` if the record has already been deleted.
*
* @beta
*/
get: function () {
var self = this; // Capture the context of the `Record` instance.
var dataObj = {
/**
* Returns the data of the current record as a `Blob`.
*
* @returns A promise that resolves to a Blob containing the record's data.
* @throws If the record data is not available or cannot be converted to a `Blob`.
*
* @beta
*/
blob: function () {
return __awaiter(this, void 0, void 0, function () {
var _a, _b, _c;
var _d;
return __generator(this, function (_e) {
switch (_e.label) {
case 0:
_a = Blob.bind;
_c = (_b = common_1.NodeStream).consumeToBytes;
_d = {};
return [4 /*yield*/, this.stream()];
case 1: return [4 /*yield*/, _c.apply(_b, [(_d.readable = _e.sent(), _d)])];
case 2: return [2 /*return*/, new (_a.apply(Blob, [void 0, [_e.sent()], { type: self.dataFormat }]))()];
}
});
});
},
/**
* Returns the data of the current record as a `Uint8Array`.
*
* @returns A Promise that resolves to a `Uint8Array` containing the record's data bytes.
* @throws If the record data is not available or cannot be converted to a byte array.
*
* @beta
*/
bytes: function () {
return __awaiter(this, void 0, void 0, function () {
var _a, _b;
var _c;
return __generator(this, function (_d) {
switch (_d.label) {
case 0:
_b = (_a = common_1.NodeStream).consumeToBytes;
_c = {};
return [4 /*yield*/, this.stream()];
case 1: return [4 /*yield*/, _b.apply(_a, [(_c.readable = _d.sent(), _c)])];
case 2: return [2 /*return*/, _d.sent()];
}
});
});
},
/**
* Parses the data of the current record as JSON and returns it as a JavaScript object.
*
* @returns A Promise that resolves to a JavaScript object parsed from the record's JSON data.
* @throws If the record data is not available, not in JSON format, or cannot be parsed.
*
* @beta
*/
json: function () {
return __awaiter(this, void 0, void 0, function () {
var _a, _b;
var _c;
return __generator(this, function (_d) {
switch (_d.label) {
case 0:
_b = (_a = common_1.NodeStream).consumeToJson;
_c = {};
return [4 /*yield*/, this.stream()];
case 1: return [4 /*yield*/, _b.apply(_a, [(_c.readable = _d.sent(), _c)])];
case 2: return [2 /*return*/, _d.sent()];
}
});
});
},
/**
* Returns the data of the current record as a `string`.
*
* @returns A promise that resolves to a `string` containing the record's text data.
* @throws If the record data is not available or cannot be converted to text.
*
* @beta
*/
text: function () {
return __awaiter(this, void 0, void 0, function () {
var _a, _b;
var _c;
return __generator(this, function (_d) {
switch (_d.label) {
case 0:
_b = (_a = common_1.NodeStream).consumeToText;
_c = {};
return [4 /*yield*/, this.stream()];
case 1: return [4 /*yield*/, _b.apply(_a, [(_c.readable = _d.sent(), _c)])];
case 2: return [2 /*return*/, _d.sent()];
}
});
});
},
/**
* Provides a `Readable` stream containing the record's data.
*
* @returns A promise that resolves to a Node.js `Readable` stream of the record's data.
* @throws If the record data is not available in-memory and cannot be fetched.
*
* @beta
*/
stream: function () {
return __awaiter(this, void 0, void 0, function () {
var _a, _b;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
if (!self._encodedData) return [3 /*break*/, 1];
/** If `encodedData` is set, it indicates that the Record was instantiated by
* `dwn.records.create()`/`dwn.records.write()` or the record's data payload was small
* enough to be returned in `dwn.records.query()` results. In either case, the data is
* already available in-memory and can be returned as a Node.js `Readable` stream. */
self._readableStream = common_1.NodeStream.fromWebReadable({ readableStream: self._encodedData.stream() });
return [3 /*break*/, 6];
case 1:
if (!!common_1.NodeStream.isReadable({ readable: self._readableStream })) return [3 /*break*/, 6];
/** If the data stream for this `Record` instance has already been partially or fully
* consumed, then the data must be fetched again from either: */
_a = self;
if (!self._remoteOrigin) return [3 /*break*/, 3];
// A. ...a remote DWN if the record was originally queried from a remote DWN.
return [4 /*yield*/, self.readRecordData({ target: self._remoteOrigin, isRemote: true })];
case 2:
// A. ...a remote DWN if the record was originally queried from a remote DWN.
_b = _c.sent();
return [3 /*break*/, 5];
case 3:
// B. ...a local DWN if the record was originally queried from the local DWN.
return [4 /*yield*/, self.readRecordData({ target: self._connectedDid, isRemote: false })];
case 4:
// B. ...a local DWN if the record was originally queried from the local DWN.
_b = _c.sent();
_c.label = 5;
case 5:
/** If the data stream for this `Record` instance has already been partially or fully
* consumed, then the data must be fetched again from either: */
_a._readableStream = _b;
_c.label = 6;
case 6:
if (!self._readableStream) {
throw new Error('Record data is not available.');
}
return [2 /*return*/, self._readableStream];
}
});
});
},
/**
* Attaches callbacks for the resolution and/or rejection of the `Promise` returned by
* `stream()`.
*
* This method is a proxy to the `then` method of the `Promise` returned by `stream()`,
* allowing for a seamless integration with promise-based workflows.
* @param onFulfilled - A function to asynchronously execute when the `stream()` promise
* becomes fulfilled.
* @param onRejected - A function to asynchronously execute when the `stream()` promise
* becomes rejected.
* @returns A `Promise` for the completion of which ever callback is executed.
*/
then: function (onFulfilled, onRejected) {
return this.stream().then(onFulfilled, onRejected);
},
/**
* Attaches a rejection handler callback to the `Promise` returned by the `stream()` method.
* This method is a shorthand for `.then(undefined, onRejected)`, specifically designed for handling
* rejection cases in the promise chain initiated by accessing the record's data. It ensures that
* errors during data retrieval or processing can be caught and handled appropriately.
*
* @param onRejected - A function to asynchronously execute when the `stream()` promise
* becomes rejected.
* @returns A `Promise` that resolves to the value of the callback if it is called, or to its
* original fulfillment value if the promise is instead fulfilled.
*/
catch: function (onRejected) {
return this.stream().catch(onRejected);
}
};
return dataObj;
},
enumerable: false,
configurable: true
});
/**
* Stores the current record state as well as any initial write to the owner's DWN.
*
* @param importRecord - if true, the record will signed by the owner before storing it to the owner's DWN. Defaults to false.
* @returns the status of the store request
*
* @beta
*/
Record.prototype.store = function (importRecord) {
if (importRecord === void 0) { importRecord = false; }
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
// if we are importing the record we sign it as the owner
return [2 /*return*/, this.processRecord({ signAsOwner: importRecord, store: true })];
});
});
};
/**
* Signs the current record state as well as any initial write and optionally stores it to the owner's DWN.
* This is useful when importing a record that was signed by someone else into your own DWN.
*
* @param store - if true, the record will be stored to the owner's DWN after signing. Defaults to true.
* @returns the status of the import request
*
* @beta
*/
Record.prototype.import = function (store) {
if (store === void 0) { store = true; }
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
return [2 /*return*/, this.processRecord({ store: store, signAsOwner: true })];
});
});
};
/**
* Send the current record to a remote DWN by specifying their DID
* If no DID is specified, the target is assumed to be the owner (connectedDID).
*
* If an initial write is present and the Record class send cache has no awareness of it, the initial write is sent first
* (vs waiting for the regular DWN sync)
*
* @param target - the optional DID to send the record to, if none is set it is sent to the connectedDid
* @returns the status of the send record request
* @throws `Error` if the record has already been deleted.
*
* @beta
*/
Record.prototype.send = function (target) {
return __awaiter(this, void 0, void 0, function () {
var initialWrite, rawMessage, sendRequestOptions, reply;
var _a;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
initialWrite = this._initialWrite;
target !== null && target !== void 0 ? target : (target = this._connectedDid);
if (!(initialWrite && !Record._sendCache.check(this._recordId, target))) return [3 /*break*/, 2];
rawMessage = __assign({}, initialWrite);
(0, common_1.removeUndefinedProperties)(rawMessage);
// Send the initial write to the target.
return [4 /*yield*/, this._agent.sendDwnRequest({
messageType: agent_1.DwnInterface.RecordsWrite,
author: this._connectedDid,
target: target,
rawMessage: rawMessage
})];
case 1:
// Send the initial write to the target.
_b.sent();
// Set the cache to maintain awareness that we don't need to send the initial write next time.
Record._sendCache.set(this._recordId, target);
_b.label = 2;
case 2:
if (!this.deleted) return [3 /*break*/, 3];
sendRequestOptions = {
messageType: agent_1.DwnInterface.RecordsDelete,
author: this._connectedDid,
target: target,
rawMessage: __assign({}, this.rawMessage)
};
return [3 /*break*/, 5];
case 3:
_a = {
messageType: agent_1.DwnInterface.RecordsWrite,
author: this._connectedDid,
target: target
};
return [4 /*yield*/, this.data.blob()];
case 4:
sendRequestOptions = (_a.dataStream = _b.sent(),
_a.rawMessage = __assign({}, this.rawMessage),
_a);
_b.label = 5;
case 5: return [4 /*yield*/, this._agent.sendDwnRequest(sendRequestOptions)];
case 6:
reply = (_b.sent()).reply;
return [2 /*return*/, reply];
}
});
});
};
/**
* Returns a JSON representation of the Record instance.
* It's called by `JSON.stringify(...)` automatically.
*/
Record.prototype.toJSON = function () {
return {
attestation: this.attestation,
author: this.author,
authorization: this.authorization,
contextId: this.contextId,
dataCid: this.dataCid,
dataFormat: this.dataFormat,
dataSize: this.dataSize,
dateCreated: this.dateCreated,
messageTimestamp: this.dateModified,
datePublished: this.datePublished,
encryption: this.encryption,
parentId: this.parentId,
protocol: this.protocol,
protocolPath: this.protocolPath,
protocolRole: this.protocolRole,
published: this.published,
recipient: this.recipient,
recordId: this.id,
schema: this.schema,
tags: this.tags,
};
};
/**
* Convenience method to return the string representation of the Record instance.
* Called automatically in string concatenation, String() type conversion, and template literals.
*/
Record.prototype.toString = function () {
var str = "Record: {\n";
str += " ID: ".concat(this.id, "\n");
str += this.contextId ? " Context ID: ".concat(this.contextId, "\n") : '';
str += this.protocol ? " Protocol: ".concat(this.protocol, "\n") : '';
str += this.schema ? " Schema: ".concat(this.schema, "\n") : '';
// Only display data properties if the record has not been deleted.
if (!this.deleted) {
str += " Data CID: ".concat(this.dataCid, "\n");
str += " Data Format: ".concat(this.dataFormat, "\n");
str += " Data Size: ".concat(this.dataSize, "\n");
}
str += " Deleted: ".concat(this.deleted, "\n");
str += " Created: ".concat(this.dateCreated, "\n");
str += " Modified: ".concat(this.dateModified, "\n");
str += "}";
return str;
};
/**
* Returns a pagination cursor for the current record given a sort order.
*
* @param sort the sort order to use for the pagination cursor.
* @returns A promise that resolves to a pagination cursor for the current record.
*/
Record.prototype.paginationCursor = function (sort) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
return [2 /*return*/, (0, agent_1.isDwnMessage)(agent_1.DwnInterface.RecordsWrite, this.rawMessage) ? (0, agent_1.getPaginationCursor)(this.rawMessage, sort) : undefined];
});
});
};
/**
* Update the current record on the DWN.
* @param params - Parameters to update the record.
* @returns the status of the update request
* @throws `Error` if the record has already been deleted.
*
* @beta
*/
Record.prototype.update = function (_a) {
var _b;
var dateModified = _a.dateModified, data = _a.data, protocolRole = _a.protocolRole, store = (_b = _a.store, _b === void 0 ? true : _b), params = __rest(_a, ["dateModified", "data", "protocolRole", "store"]);
return __awaiter(this, void 0, void 0, function () {
var _c, parentId, descriptor, parentContextId, updateMessage, dataBlob, mutableDescriptorProperties, requestOptions, delegatedGrant, agentResponse, message, status, responseMessage;
var _this = this;
return __generator(this, function (_d) {
switch (_d.label) {
case 0:
if (this.deleted) {
throw new Error('Record: Cannot revive a deleted record.');
}
_c = this._recordsWriteDescriptor, parentId = _c.parentId, descriptor = __rest(_c, ["parentId"]);
parentContextId = parentId ? this._contextId.split('/').slice(0, -1).join('/') : undefined;
updateMessage = __assign(__assign(__assign({}, descriptor), params), { parentContextId: parentContextId, protocolRole: protocolRole !== null && protocolRole !== void 0 ? protocolRole : this._protocolRole, messageTimestamp: dateModified, recordId: this._recordId });
// NOTE: The original Record's tags are copied to the update message, so that the tags are not lost.
// However if a user passes new tags in the `RecordUpdateParams` object, they will overwrite the original tags.
// If the updated tag object is empty or set to null, we remove the tags property to avoid schema validation errors in the DWN SDK.
if ((0, common_1.isEmptyObject)(updateMessage.tags) || updateMessage.tags === null) {
delete updateMessage.tags;
}
if (data !== undefined) {
// If `data` is being updated then `dataCid` and `dataSize` must be undefined and the `data`
// value must be converted to a Blob and later passed as a top-level property to
// `agent.processDwnRequest()`.
delete updateMessage.dataCid;
delete updateMessage.dataSize;
(dataBlob = (0, utils_js_1.dataToBlob)(data, updateMessage.dataFormat).dataBlob);
}
mutableDescriptorProperties = new Set(['data', 'dataCid', 'dataFormat', 'dataSize', 'datePublished', 'messageTimestamp', 'published', 'tags']);
Record.verifyPermittedMutation(Object.keys(params), mutableDescriptorProperties);
// If `published` is set to false, ensure that `datePublished` is undefined. Otherwise, DWN SDK's schema validation
// will throw an error if `published` is false but `datePublished` is set.
if (params.published === false && updateMessage.datePublished !== undefined) {
delete updateMessage.datePublished;
}
requestOptions = {
author: this._connectedDid,
dataStream: dataBlob,
messageParams: __assign({}, updateMessage),
messageType: agent_1.DwnInterface.RecordsWrite,
target: this._connectedDid,
store: store
};
if (!this._delegateDid) return [3 /*break*/, 2];
return [4 /*yield*/, this._permissionsApi.getPermissionForRequest({
connectedDid: this._connectedDid,
delegateDid: this._delegateDid,
protocol: this.protocol,
delegate: true,
cached: true,
messageType: requestOptions.messageType
})];
case 1:
delegatedGrant = (_d.sent()).message;
requestOptions.messageParams.delegatedGrant = delegatedGrant;
requestOptions.granteeDid = this._delegateDid;
_d.label = 2;
case 2: return [4 /*yield*/, this._agent.processDwnRequest(requestOptions)];
case 3:
agentResponse = _d.sent();
message = agentResponse.message, status = agentResponse.reply.status;
responseMessage = message;
if (200 <= status.code && status.code <= 299) {
// copy the original raw message to the initial write before we update the values.
if (!this._initialWrite) {
// If there is no initial write, we need to create one from the current record state.
// We checked in the beginning of the function that the rawMessage is a RecordsWrite message.
this._initialWrite = __assign({}, this.rawMessage);
}
// Only update the local Record instance mutable properties if the record was successfully (over)written.
this._authorization = responseMessage.authorization;
this._protocolRole = updateMessage.protocolRole;
mutableDescriptorProperties.forEach(function (property) {
_this._descriptor[property] = responseMessage.descriptor[property];
});
// Cache data.
if (data !== undefined) {
this._encodedData = dataBlob;
}
}
return [2 /*return*/, { status: status }];
}
});
});
};
/**
* Delete the current record on the DWN.
* @param params - Parameters to delete the record.
* @returns the status of the delete request
*/
Record.prototype.delete = function (deleteParams) {
var _a;
return __awaiter(this, void 0, void 0, function () {
var store, signAsOwner, dateModified, prune, signAsOwnerValue, signAsOwnerDelegate, deleteOptions, differentRole, delegatedGrant, agentResponse, message, status;
var _b, _c, _d;
return __generator(this, function (_e) {
switch (_e.label) {
case 0:
store = (_b = deleteParams || {}, _c = _b.store, _c === void 0 ? true : _c), signAsOwner = _b.signAsOwner, dateModified = _b.dateModified, prune = (_d = _b.prune, _d === void 0 ? false : _d);
signAsOwnerValue = signAsOwner && this._delegateDid === undefined;
signAsOwnerDelegate = signAsOwner && this._delegateDid !== undefined;
if (this.deleted && !this._initialWrite) {
throw new Error('Record: Record is in an invalid state, initial write is missing.');
}
if (!this._initialWrite) {
// If there is no initial write, we need to create one from the current record state.
// We checked in the beginning of the function that the initialWrite is not set if the rawMessage is a RecordsDelete message.
// So we can safely assume that the rawMessage is a RecordsWrite message.
this._initialWrite = __assign({}, this.rawMessage);
}
return [4 /*yield*/, this.processInitialWriteIfNeeded({ store: store, signAsOwner: signAsOwner })];
case 1:
_e.sent();
deleteOptions = {
messageType: agent_1.DwnInterface.RecordsDelete,
author: this._connectedDid,
target: this._connectedDid,
signAsOwner: signAsOwnerValue,
signAsOwnerDelegate: signAsOwnerDelegate,
store: store
};
differentRole = (deleteParams === null || deleteParams === void 0 ? void 0 : deleteParams.protocolRole) ? (0, agent_1.getRecordProtocolRole)(this.rawMessage) !== deleteParams.protocolRole : false;
// If the record is already in a deleted state but the protocolRole is different, we need to construct a delete message with the new protocolRole
// otherwise we can just use the existing delete message.
if (this.deleted && !differentRole) {
deleteOptions.rawMessage = this.rawMessage;
}
else {
// otherwise we construct a delete message given the `RecordDeleteParams`
deleteOptions.messageParams = {
prune: prune,
recordId: this._recordId,
messageTimestamp: dateModified,
protocolRole: (_a = deleteParams === null || deleteParams === void 0 ? void 0 : deleteParams.protocolRole) !== null && _a !== void 0 ? _a : this._protocolRole // if no protocolRole is provided, use the current protocolRole
};
}
if (!this._delegateDid) return [3 /*break*/, 3];
return [4 /*yield*/, this._permissionsApi.getPermissionForRequest({
connectedDid: this._connectedDid,
delegateDid: this._delegateDid,
protocol: this.protocol,
delegate: true,
cached: true,
messageType: deleteOptions.messageType
})];
case 2:
delegatedGrant = (_e.sent()).message;
deleteOptions.messageParams = __assign(__assign({}, deleteOptions.messageParams), { delegatedGrant: delegatedGrant });
deleteOptions.granteeDid = this._delegateDid;
_e.label = 3;
case 3: return [4 /*yield*/, this._agent.processDwnRequest(deleteOptions)];
case 4:
agentResponse = _e.sent();
message = agentResponse.message, status = agentResponse.reply.status;
if (status.code !== 202) {
// If the delete was not successful, return the status.
return [2 /*return*/, { status: status }];
}
// If the delete was successful, update the Record author to the author of the delete message.
this._author = (0, agent_1.getRecordAuthor)(message);
this._descriptor = message.descriptor;
this._authorization = message.authorization;
// clear out properties that are not relevant for a deleted record
this._encodedData = undefined;
this._encryption = undefined;
this._attestation = undefined;
this._contextId = undefined;
return [2 /*return*/, { status: status }];
}
});
});
};
/**
* Process the initial write, if it hasn't already been processed, with the options set for storing and/or signing as the owner.
*/
Record.prototype.processInitialWriteIfNeeded = function (_a) {
var store = _a.store, signAsOwner = _a.signAsOwner;
return __awaiter(this, void 0, void 0, function () {
var signAsOwnerValue, signAsOwnerDelegate, initialWriteRequest, delegatedGrant, agentResponse, message, status_1, responseMessage;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
if (!(this.initialWrite && ((signAsOwner && !this._initialWriteSigned) || (store && !this._initialWriteStored)))) return [3 /*break*/, 4];
signAsOwnerValue = signAsOwner && this._delegateDid === undefined;
signAsOwnerDelegate = signAsOwner && this._delegateDid !== undefined;
initialWriteRequest = {
messageType: agent_1.DwnInterface.RecordsWrite,
rawMessage: this.initialWrite,
author: this._connectedDid,
target: this._connectedDid,
signAsOwner: signAsOwnerValue,
signAsOwnerDelegate: signAsOwnerDelegate,
store: store,
};
if (!this._delegateDid) return [3 /*break*/, 2];
return [4 /*yield*/, this._permissionsApi.getPermissionForRequest({
connectedDid: this._connectedDid,
delegateDid: this._delegateDid,
protocol: this.protocol,
delegate: true,
cached: true,
messageType: initialWriteRequest.messageType
})];
case 1:
delegatedGrant = (_b.sent()).message;
initialWriteRequest.messageParams = __assign(__assign({}, initialWriteRequest.messageParams), { delegatedGrant: delegatedGrant });
initialWriteRequest.granteeDid = this._delegateDid;
_b.label = 2;
case 2: return [4