matrix-js-sdk
Version:
Matrix Client-Server SDK for Javascript
214 lines (194 loc) • 8.23 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.MSC3089Branch = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _event = require("../@types/event");
var _eventTimeline = require("./event-timeline");
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
/**
* Represents a [MSC3089](https://github.com/matrix-org/matrix-doc/pull/3089) branch - a reference
* to a file (leaf) in the tree. Note that this is UNSTABLE and subject to breaking changes
* without notice.
*/
class MSC3089Branch {
constructor(client, indexEvent, directory) {
this.client = client;
this.indexEvent = indexEvent;
this.directory = directory;
} // Nothing to do
/**
* The file ID.
*/
get id() {
const stateKey = this.indexEvent.getStateKey();
if (!stateKey) {
throw new Error("State key not found for branch");
}
return stateKey;
}
/**
* Whether this branch is active/valid.
*/
get isActive() {
return this.indexEvent.getContent()["active"] === true;
}
/**
* Version for the file, one-indexed.
*/
get version() {
var _this$indexEvent$getC;
return (_this$indexEvent$getC = this.indexEvent.getContent()["version"]) !== null && _this$indexEvent$getC !== void 0 ? _this$indexEvent$getC : 1;
}
get roomId() {
return this.indexEvent.getRoomId();
}
/**
* Deletes the file from the tree, including all prior edits/versions.
* @returns Promise which resolves when complete.
*/
async delete() {
await this.client.sendStateEvent(this.roomId, _event.UNSTABLE_MSC3089_BRANCH.name, {}, this.id);
await this.client.redactEvent(this.roomId, this.id);
const nextVersion = (await this.getVersionHistory())[1]; // [0] will be us
if (nextVersion) await nextVersion.delete(); // implicit recursion
}
/**
* Gets the name for this file.
* @returns The name, or "Unnamed File" if unknown.
*/
getName() {
return this.indexEvent.getContent()["name"] || "Unnamed File";
}
/**
* Sets the name for this file.
* @param name - The new name for this file.
* @returns Promise which resolves when complete.
*/
async setName(name) {
await this.client.sendStateEvent(this.roomId, _event.UNSTABLE_MSC3089_BRANCH.name, _objectSpread(_objectSpread({}, this.indexEvent.getContent()), {}, {
name: name
}), this.id);
}
/**
* Gets whether or not a file is locked.
* @returns True if locked, false otherwise.
*/
isLocked() {
return this.indexEvent.getContent()["locked"] || false;
}
/**
* Sets a file as locked or unlocked.
* @param locked - True to lock the file, false otherwise.
* @returns Promise which resolves when complete.
*/
async setLocked(locked) {
await this.client.sendStateEvent(this.roomId, _event.UNSTABLE_MSC3089_BRANCH.name, _objectSpread(_objectSpread({}, this.indexEvent.getContent()), {}, {
locked: locked
}), this.id);
}
/**
* Gets information about the file needed to download it.
* @returns Information about the file.
*/
async getFileInfo() {
const event = await this.getFileEvent();
const file = event.getOriginalContent()["file"];
const httpUrl = this.client.mxcUrlToHttp(file["url"]);
if (!httpUrl) {
throw new Error(`No HTTP URL available for ${file["url"]}`);
}
return {
info: file,
httpUrl: httpUrl
};
}
/**
* Gets the event the file points to.
* @returns Promise which resolves to the file's event.
*/
async getFileEvent() {
const room = this.client.getRoom(this.roomId);
if (!room) throw new Error("Unknown room");
let event = room.getUnfilteredTimelineSet().findEventById(this.id);
// keep scrolling back if needed until we find the event or reach the start of the room:
while (!event && room.getLiveTimeline().getState(_eventTimeline.EventTimeline.BACKWARDS).paginationToken) {
await this.client.scrollback(room, 100);
event = room.getUnfilteredTimelineSet().findEventById(this.id);
}
if (!event) throw new Error("Failed to find event");
// Sometimes the event isn't decrypted for us, so do that. We specifically set `emit: true`
// to ensure that the relations system in the sdk will function.
await this.client.decryptEventIfNeeded(event, {
emit: true,
isRetry: true
});
return event;
}
/**
* Creates a new version of this file with contents in a type that is compatible with MatrixClient.uploadContent().
* @param name - The name of the file.
* @param encryptedContents - The encrypted contents.
* @param info - The encrypted file information.
* @param additionalContent - Optional event content fields to include in the message.
* @returns Promise which resolves to the file event's sent response.
*/
async createNewVersion(name, encryptedContents, info, additionalContent) {
const fileEventResponse = await this.directory.createFile(name, encryptedContents, info, _objectSpread(_objectSpread({}, additionalContent !== null && additionalContent !== void 0 ? additionalContent : {}), {}, {
"m.new_content": true,
"m.relates_to": {
rel_type: _event.RelationType.Replace,
event_id: this.id
}
}));
// Update the version of the new event
await this.client.sendStateEvent(this.roomId, _event.UNSTABLE_MSC3089_BRANCH.name, {
active: true,
name: name,
version: this.version + 1
}, fileEventResponse["event_id"]);
// Deprecate ourselves
await this.client.sendStateEvent(this.roomId, _event.UNSTABLE_MSC3089_BRANCH.name, _objectSpread(_objectSpread({}, this.indexEvent.getContent()), {}, {
active: false
}), this.id);
return fileEventResponse;
}
/**
* Gets the file's version history, starting at this file.
* @returns Promise which resolves to the file's version history, with the
* first element being the current version and the last element being the first version.
*/
async getVersionHistory() {
const fileHistory = [];
fileHistory.push(this); // start with ourselves
const room = this.client.getRoom(this.roomId);
if (!room) throw new Error("Invalid or unknown room");
// Clone the timeline to reverse it, getting most-recent-first ordering, hopefully
// shortening the awful loop below. Without the clone, we can unintentionally mutate
// the timeline.
const timelineEvents = [...room.getLiveTimeline().getEvents()].reverse();
// XXX: This is a very inefficient search, but it's the best we can do with the
// relations structure we have in the SDK. As of writing, it is not worth the
// investment in improving the structure.
let childEvent;
let parentEvent = await this.getFileEvent();
do {
childEvent = timelineEvents.find(e => e.replacingEventId() === parentEvent.getId());
if (childEvent) {
const branch = this.directory.getFile(childEvent.getId());
if (branch) {
fileHistory.push(branch);
parentEvent = childEvent;
} else {
break; // prevent infinite loop
}
}
} while (childEvent);
return fileHistory;
}
}
exports.MSC3089Branch = MSC3089Branch;
//# sourceMappingURL=MSC3089Branch.js.map